aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/xscale
diff options
context:
space:
mode:
authorJeff Kirsher <jeffrey.t.kirsher@intel.com>2011-07-15 01:13:23 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2011-08-11 19:29:28 -0400
commitb47da97728c045a8fd75f36e59ba08cddc8f2292 (patch)
tree71aa03f391344e9dcec4bee239f6d5c67a0fa361 /drivers/net/ethernet/xscale
parentd9fb9f384292d848ad9db386bcf97f1e06e60264 (diff)
xscale: Move the Intel XScale IXP drivers
Move the Intel XScale IXP drivers into drivers/net/ethernet/xscale/ and make the necessary Kconfig and Makefile changes. CC: Krzysztof Halasa <khc@pm.waw.pl> CC: Lennert Buytenhek <kernel@wantstofly.org> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/xscale')
-rw-r--r--drivers/net/ethernet/xscale/Kconfig31
-rw-r--r--drivers/net/ethernet/xscale/Makefile6
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/Kconfig6
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/Makefile3
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/caleb.c136
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/caleb.h22
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/enp2611.c232
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c212
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h115
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc408
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode130
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc272
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode98
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixpdev.c440
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixpdev.h29
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h57
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/pm3386.c351
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/pm3386.h29
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c1489
19 files changed, 4066 insertions, 0 deletions
diff --git a/drivers/net/ethernet/xscale/Kconfig b/drivers/net/ethernet/xscale/Kconfig
new file mode 100644
index 000000000000..6bbcc54d6ce7
--- /dev/null
+++ b/drivers/net/ethernet/xscale/Kconfig
@@ -0,0 +1,31 @@
1#
2# Intel XScale IXP device configuration
3#
4
5config NET_VENDOR_XSCALE
6 bool "Intel XScale IXP devices"
7 depends on NET_VENDOR_INTEL && ((ARM && ARCH_IXP4XX && \
8 IXP4XX_NPE && IXP4XX_QMGR) || ARCH_ENP2611)
9 ---help---
10 If you have a network (Ethernet) card belonging to this class, say Y
11 and read the Ethernet-HOWTO, available from
12 <http://www.tldp.org/docs.html#howto>.
13
14 Note that the answer to this question does not directly affect the
15 kernel: saying N will just cause the configurator to skip all
16 the questions about XSacle IXP devices. If you say Y, you will be
17 asked for your specific card in the following questions.
18
19if NET_VENDOR_XSCALE
20
21config IXP4XX_ETH
22 tristate "Intel IXP4xx Ethernet support"
23 depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
24 select PHYLIB
25 ---help---
26 Say Y here if you want to use built-in Ethernet ports
27 on IXP4xx processor.
28
29source "drivers/net/ethernet/xscale/ixp2000/Kconfig"
30
31endif # NET_VENDOR_XSCALE
diff --git a/drivers/net/ethernet/xscale/Makefile b/drivers/net/ethernet/xscale/Makefile
new file mode 100644
index 000000000000..b195b9d7fe81
--- /dev/null
+++ b/drivers/net/ethernet/xscale/Makefile
@@ -0,0 +1,6 @@
1#
2# Makefile for the Intel XScale IXP device drivers.
3#
4
5obj-$(CONFIG_ENP2611_MSF_NET) += ixp2000/
6obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o
diff --git a/drivers/net/ethernet/xscale/ixp2000/Kconfig b/drivers/net/ethernet/xscale/ixp2000/Kconfig
new file mode 100644
index 000000000000..58dbc5b876bc
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/Kconfig
@@ -0,0 +1,6 @@
1config ENP2611_MSF_NET
2 tristate "Radisys ENP2611 MSF network interface support"
3 depends on ARCH_ENP2611
4 ---help---
5 This is a driver for the MSF network interface unit in
6 the IXP2400 on the Radisys ENP2611 platform.
diff --git a/drivers/net/ethernet/xscale/ixp2000/Makefile b/drivers/net/ethernet/xscale/ixp2000/Makefile
new file mode 100644
index 000000000000..fd38351ceaa7
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/Makefile
@@ -0,0 +1,3 @@
1obj-$(CONFIG_ENP2611_MSF_NET) += enp2611_mod.o
2
3enp2611_mod-objs := caleb.o enp2611.o ixp2400-msf.o ixpdev.o pm3386.o
diff --git a/drivers/net/ethernet/xscale/ixp2000/caleb.c b/drivers/net/ethernet/xscale/ixp2000/caleb.c
new file mode 100644
index 000000000000..7dea5b95012c
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/caleb.c
@@ -0,0 +1,136 @@
1/*
2 * Helper functions for the SPI-3 bridge FPGA on the Radisys ENP2611
3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/delay.h>
14#include <asm/io.h>
15#include "caleb.h"
16
17#define CALEB_IDLO 0x00
18#define CALEB_IDHI 0x01
19#define CALEB_RID 0x02
20#define CALEB_RESET 0x03
21#define CALEB_INTREN0 0x04
22#define CALEB_INTREN1 0x05
23#define CALEB_INTRSTAT0 0x06
24#define CALEB_INTRSTAT1 0x07
25#define CALEB_PORTEN 0x08
26#define CALEB_BURST 0x09
27#define CALEB_PORTPAUS 0x0A
28#define CALEB_PORTPAUSD 0x0B
29#define CALEB_PHY0RX 0x10
30#define CALEB_PHY1RX 0x11
31#define CALEB_PHY0TX 0x12
32#define CALEB_PHY1TX 0x13
33#define CALEB_IXPRX_HI_CNTR 0x15
34#define CALEB_PHY0RX_HI_CNTR 0x16
35#define CALEB_PHY1RX_HI_CNTR 0x17
36#define CALEB_IXPRX_CNTR 0x18
37#define CALEB_PHY0RX_CNTR 0x19
38#define CALEB_PHY1RX_CNTR 0x1A
39#define CALEB_IXPTX_CNTR 0x1B
40#define CALEB_PHY0TX_CNTR 0x1C
41#define CALEB_PHY1TX_CNTR 0x1D
42#define CALEB_DEBUG0 0x1E
43#define CALEB_DEBUG1 0x1F
44
45
46static u8 caleb_reg_read(int reg)
47{
48 u8 value;
49
50 value = *((volatile u8 *)(ENP2611_CALEB_VIRT_BASE + reg));
51
52// printk(KERN_INFO "caleb_reg_read(%d) = %.2x\n", reg, value);
53
54 return value;
55}
56
57static void caleb_reg_write(int reg, u8 value)
58{
59 u8 dummy;
60
61// printk(KERN_INFO "caleb_reg_write(%d, %.2x)\n", reg, value);
62
63 *((volatile u8 *)(ENP2611_CALEB_VIRT_BASE + reg)) = value;
64
65 dummy = *((volatile u8 *)ENP2611_CALEB_VIRT_BASE);
66 __asm__ __volatile__("mov %0, %0" : "+r" (dummy));
67}
68
69
70void caleb_reset(void)
71{
72 /*
73 * Perform a chip reset.
74 */
75 caleb_reg_write(CALEB_RESET, 0x02);
76 udelay(1);
77
78 /*
79 * Enable all interrupt sources. This is needed to get
80 * meaningful results out of the status bits (register 6
81 * and 7.)
82 */
83 caleb_reg_write(CALEB_INTREN0, 0xff);
84 caleb_reg_write(CALEB_INTREN1, 0x07);
85
86 /*
87 * Set RX and TX FIFO thresholds to 1.5kb.
88 */
89 caleb_reg_write(CALEB_PHY0RX, 0x11);
90 caleb_reg_write(CALEB_PHY1RX, 0x11);
91 caleb_reg_write(CALEB_PHY0TX, 0x11);
92 caleb_reg_write(CALEB_PHY1TX, 0x11);
93
94 /*
95 * Program SPI-3 burst size.
96 */
97 caleb_reg_write(CALEB_BURST, 0); // 64-byte RBUF mpackets
98// caleb_reg_write(CALEB_BURST, 1); // 128-byte RBUF mpackets
99// caleb_reg_write(CALEB_BURST, 2); // 256-byte RBUF mpackets
100}
101
102void caleb_enable_rx(int port)
103{
104 u8 temp;
105
106 temp = caleb_reg_read(CALEB_PORTEN);
107 temp |= 1 << port;
108 caleb_reg_write(CALEB_PORTEN, temp);
109}
110
111void caleb_disable_rx(int port)
112{
113 u8 temp;
114
115 temp = caleb_reg_read(CALEB_PORTEN);
116 temp &= ~(1 << port);
117 caleb_reg_write(CALEB_PORTEN, temp);
118}
119
120void caleb_enable_tx(int port)
121{
122 u8 temp;
123
124 temp = caleb_reg_read(CALEB_PORTEN);
125 temp |= 1 << (port + 4);
126 caleb_reg_write(CALEB_PORTEN, temp);
127}
128
129void caleb_disable_tx(int port)
130{
131 u8 temp;
132
133 temp = caleb_reg_read(CALEB_PORTEN);
134 temp &= ~(1 << (port + 4));
135 caleb_reg_write(CALEB_PORTEN, temp);
136}
diff --git a/drivers/net/ethernet/xscale/ixp2000/caleb.h b/drivers/net/ethernet/xscale/ixp2000/caleb.h
new file mode 100644
index 000000000000..e93a1ef5b8a3
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/caleb.h
@@ -0,0 +1,22 @@
1/*
2 * Helper functions for the SPI-3 bridge FPGA on the Radisys ENP2611
3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#ifndef __CALEB_H
13#define __CALEB_H
14
15void caleb_reset(void);
16void caleb_enable_rx(int port);
17void caleb_disable_rx(int port);
18void caleb_enable_tx(int port);
19void caleb_disable_tx(int port);
20
21
22#endif
diff --git a/drivers/net/ethernet/xscale/ixp2000/enp2611.c b/drivers/net/ethernet/xscale/ixp2000/enp2611.c
new file mode 100644
index 000000000000..34a6cfd17930
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/enp2611.c
@@ -0,0 +1,232 @@
1/*
2 * IXP2400 MSF network device driver for the Radisys ENP2611
3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/netdevice.h>
15#include <linux/etherdevice.h>
16#include <linux/init.h>
17#include <linux/moduleparam.h>
18#include <asm/hardware/uengine.h>
19#include <asm/mach-types.h>
20#include <asm/io.h>
21#include "ixpdev.h"
22#include "caleb.h"
23#include "ixp2400-msf.h"
24#include "pm3386.h"
25
26/***********************************************************************
27 * The Radisys ENP2611 is a PCI form factor board with three SFP GBIC
28 * slots, connected via two PMC/Sierra 3386s and an SPI-3 bridge FPGA
29 * to the IXP2400.
30 *
31 * +-------------+
32 * SFP GBIC #0 ---+ | +---------+
33 * | PM3386 #0 +-------+ |
34 * SFP GBIC #1 ---+ | | "Caleb" | +---------+
35 * +-------------+ | | | |
36 * | SPI-3 +---------+ IXP2400 |
37 * +-------------+ | bridge | | |
38 * SFP GBIC #2 ---+ | | FPGA | +---------+
39 * | PM3386 #1 +-------+ |
40 * | | +---------+
41 * +-------------+
42 * ^ ^ ^
43 * | 1.25Gbaud | 104MHz | 104MHz
44 * | SERDES ea. | SPI-3 ea. | SPI-3
45 *
46 ***********************************************************************/
47static struct ixp2400_msf_parameters enp2611_msf_parameters =
48{
49 .rx_mode = IXP2400_RX_MODE_UTOPIA_POS |
50 IXP2400_RX_MODE_1x32 |
51 IXP2400_RX_MODE_MPHY |
52 IXP2400_RX_MODE_MPHY_32 |
53 IXP2400_RX_MODE_MPHY_POLLED_STATUS |
54 IXP2400_RX_MODE_MPHY_LEVEL3 |
55 IXP2400_RX_MODE_RBUF_SIZE_64,
56
57 .rxclk01_multiplier = IXP2400_PLL_MULTIPLIER_16,
58
59 .rx_poll_ports = 3,
60
61 .rx_channel_mode = {
62 IXP2400_PORT_RX_MODE_MASTER |
63 IXP2400_PORT_RX_MODE_POS_PHY |
64 IXP2400_PORT_RX_MODE_POS_PHY_L3 |
65 IXP2400_PORT_RX_MODE_ODD_PARITY |
66 IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
67
68 IXP2400_PORT_RX_MODE_MASTER |
69 IXP2400_PORT_RX_MODE_POS_PHY |
70 IXP2400_PORT_RX_MODE_POS_PHY_L3 |
71 IXP2400_PORT_RX_MODE_ODD_PARITY |
72 IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
73
74 IXP2400_PORT_RX_MODE_MASTER |
75 IXP2400_PORT_RX_MODE_POS_PHY |
76 IXP2400_PORT_RX_MODE_POS_PHY_L3 |
77 IXP2400_PORT_RX_MODE_ODD_PARITY |
78 IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
79
80 IXP2400_PORT_RX_MODE_MASTER |
81 IXP2400_PORT_RX_MODE_POS_PHY |
82 IXP2400_PORT_RX_MODE_POS_PHY_L3 |
83 IXP2400_PORT_RX_MODE_ODD_PARITY |
84 IXP2400_PORT_RX_MODE_2_CYCLE_DECODE
85 },
86
87 .tx_mode = IXP2400_TX_MODE_UTOPIA_POS |
88 IXP2400_TX_MODE_1x32 |
89 IXP2400_TX_MODE_MPHY |
90 IXP2400_TX_MODE_MPHY_32 |
91 IXP2400_TX_MODE_MPHY_POLLED_STATUS |
92 IXP2400_TX_MODE_MPHY_LEVEL3 |
93 IXP2400_TX_MODE_TBUF_SIZE_64,
94
95 .txclk01_multiplier = IXP2400_PLL_MULTIPLIER_16,
96
97 .tx_poll_ports = 3,
98
99 .tx_channel_mode = {
100 IXP2400_PORT_TX_MODE_MASTER |
101 IXP2400_PORT_TX_MODE_POS_PHY |
102 IXP2400_PORT_TX_MODE_ODD_PARITY |
103 IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
104
105 IXP2400_PORT_TX_MODE_MASTER |
106 IXP2400_PORT_TX_MODE_POS_PHY |
107 IXP2400_PORT_TX_MODE_ODD_PARITY |
108 IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
109
110 IXP2400_PORT_TX_MODE_MASTER |
111 IXP2400_PORT_TX_MODE_POS_PHY |
112 IXP2400_PORT_TX_MODE_ODD_PARITY |
113 IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
114
115 IXP2400_PORT_TX_MODE_MASTER |
116 IXP2400_PORT_TX_MODE_POS_PHY |
117 IXP2400_PORT_TX_MODE_ODD_PARITY |
118 IXP2400_PORT_TX_MODE_2_CYCLE_DECODE
119 }
120};
121
122static struct net_device *nds[3];
123static struct timer_list link_check_timer;
124
125/* @@@ Poll the SFP moddef0 line too. */
126/* @@@ Try to use the pm3386 DOOL interrupt as well. */
127static void enp2611_check_link_status(unsigned long __dummy)
128{
129 int i;
130
131 for (i = 0; i < 3; i++) {
132 struct net_device *dev;
133 int status;
134
135 dev = nds[i];
136 if (dev == NULL)
137 continue;
138
139 status = pm3386_is_link_up(i);
140 if (status && !netif_carrier_ok(dev)) {
141 /* @@@ Should report autonegotiation status. */
142 printk(KERN_INFO "%s: NIC Link is Up\n", dev->name);
143
144 pm3386_enable_tx(i);
145 caleb_enable_tx(i);
146 netif_carrier_on(dev);
147 } else if (!status && netif_carrier_ok(dev)) {
148 printk(KERN_INFO "%s: NIC Link is Down\n", dev->name);
149
150 netif_carrier_off(dev);
151 caleb_disable_tx(i);
152 pm3386_disable_tx(i);
153 }
154 }
155
156 link_check_timer.expires = jiffies + HZ / 10;
157 add_timer(&link_check_timer);
158}
159
160static void enp2611_set_port_admin_status(int port, int up)
161{
162 if (up) {
163 caleb_enable_rx(port);
164
165 pm3386_set_carrier(port, 1);
166 pm3386_enable_rx(port);
167 } else {
168 caleb_disable_tx(port);
169 pm3386_disable_tx(port);
170 /* @@@ Flush out pending packets. */
171 pm3386_set_carrier(port, 0);
172
173 pm3386_disable_rx(port);
174 caleb_disable_rx(port);
175 }
176}
177
178static int __init enp2611_init_module(void)
179{
180 int ports;
181 int i;
182
183 if (!machine_is_enp2611())
184 return -ENODEV;
185
186 caleb_reset();
187 pm3386_reset();
188
189 ports = pm3386_port_count();
190 for (i = 0; i < ports; i++) {
191 nds[i] = ixpdev_alloc(i, sizeof(struct ixpdev_priv));
192 if (nds[i] == NULL) {
193 while (--i >= 0)
194 free_netdev(nds[i]);
195 return -ENOMEM;
196 }
197
198 pm3386_init_port(i);
199 pm3386_get_mac(i, nds[i]->dev_addr);
200 }
201
202 ixp2400_msf_init(&enp2611_msf_parameters);
203
204 if (ixpdev_init(ports, nds, enp2611_set_port_admin_status)) {
205 for (i = 0; i < ports; i++)
206 if (nds[i])
207 free_netdev(nds[i]);
208 return -EINVAL;
209 }
210
211 init_timer(&link_check_timer);
212 link_check_timer.function = enp2611_check_link_status;
213 link_check_timer.expires = jiffies;
214 add_timer(&link_check_timer);
215
216 return 0;
217}
218
219static void __exit enp2611_cleanup_module(void)
220{
221 int i;
222
223 del_timer_sync(&link_check_timer);
224
225 ixpdev_deinit();
226 for (i = 0; i < 3; i++)
227 free_netdev(nds[i]);
228}
229
230module_init(enp2611_init_module);
231module_exit(enp2611_cleanup_module);
232MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c b/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c
new file mode 100644
index 000000000000..f5ffd7e05d26
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c
@@ -0,0 +1,212 @@
1/*
2 * Generic library functions for the MSF (Media and Switch Fabric) unit
3 * found on the Intel IXP2400 network processor.
4 *
5 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
6 * Dedicated to Marija Kulikova.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation; either version 2.1 of the
11 * License, or (at your option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <mach/hardware.h>
17#include <mach/ixp2000-regs.h>
18#include <asm/delay.h>
19#include <asm/io.h>
20#include "ixp2400-msf.h"
21
22/*
23 * This is the Intel recommended PLL init procedure as described on
24 * page 340 of the IXP2400/IXP2800 Programmer's Reference Manual.
25 */
26static void ixp2400_pll_init(struct ixp2400_msf_parameters *mp)
27{
28 int rx_dual_clock;
29 int tx_dual_clock;
30 u32 value;
31
32 /*
33 * If the RX mode is not 1x32, we have to enable both RX PLLs
34 * (#0 and #1.) The same thing for the TX direction.
35 */
36 rx_dual_clock = !!(mp->rx_mode & IXP2400_RX_MODE_WIDTH_MASK);
37 tx_dual_clock = !!(mp->tx_mode & IXP2400_TX_MODE_WIDTH_MASK);
38
39 /*
40 * Read initial value.
41 */
42 value = ixp2000_reg_read(IXP2000_MSF_CLK_CNTRL);
43
44 /*
45 * Put PLLs in powerdown and bypass mode.
46 */
47 value |= 0x0000f0f0;
48 ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
49
50 /*
51 * Set single or dual clock mode bits.
52 */
53 value &= ~0x03000000;
54 value |= (rx_dual_clock << 24) | (tx_dual_clock << 25);
55
56 /*
57 * Set multipliers.
58 */
59 value &= ~0x00ff0000;
60 value |= mp->rxclk01_multiplier << 16;
61 value |= mp->rxclk23_multiplier << 18;
62 value |= mp->txclk01_multiplier << 20;
63 value |= mp->txclk23_multiplier << 22;
64
65 /*
66 * And write value.
67 */
68 ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
69
70 /*
71 * Disable PLL bypass mode.
72 */
73 value &= ~(0x00005000 | rx_dual_clock << 13 | tx_dual_clock << 15);
74 ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
75
76 /*
77 * Turn on PLLs.
78 */
79 value &= ~(0x00000050 | rx_dual_clock << 5 | tx_dual_clock << 7);
80 ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
81
82 /*
83 * Wait for PLLs to lock. There are lock status bits, but IXP2400
84 * erratum #65 says that these lock bits should not be relied upon
85 * as they might not accurately reflect the true state of the PLLs.
86 */
87 udelay(100);
88}
89
90/*
91 * Needed according to p480 of Programmer's Reference Manual.
92 */
93static void ixp2400_msf_free_rbuf_entries(struct ixp2400_msf_parameters *mp)
94{
95 int size_bits;
96 int i;
97
98 /*
99 * Work around IXP2400 erratum #69 (silent RBUF-to-DRAM transfer
100 * corruption) in the Intel-recommended way: do not add the RBUF
101 * elements susceptible to corruption to the freelist.
102 */
103 size_bits = mp->rx_mode & IXP2400_RX_MODE_RBUF_SIZE_MASK;
104 if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_64) {
105 for (i = 1; i < 128; i++) {
106 if (i == 9 || i == 18 || i == 27)
107 continue;
108 ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
109 }
110 } else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_128) {
111 for (i = 1; i < 64; i++) {
112 if (i == 4 || i == 9 || i == 13)
113 continue;
114 ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
115 }
116 } else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_256) {
117 for (i = 1; i < 32; i++) {
118 if (i == 2 || i == 4 || i == 6)
119 continue;
120 ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
121 }
122 }
123}
124
125static u32 ixp2400_msf_valid_channels(u32 reg)
126{
127 u32 channels;
128
129 channels = 0;
130 switch (reg & IXP2400_RX_MODE_WIDTH_MASK) {
131 case IXP2400_RX_MODE_1x32:
132 channels = 0x1;
133 if (reg & IXP2400_RX_MODE_MPHY &&
134 !(reg & IXP2400_RX_MODE_MPHY_32))
135 channels = 0xf;
136 break;
137
138 case IXP2400_RX_MODE_2x16:
139 channels = 0x5;
140 break;
141
142 case IXP2400_RX_MODE_4x8:
143 channels = 0xf;
144 break;
145
146 case IXP2400_RX_MODE_1x16_2x8:
147 channels = 0xd;
148 break;
149 }
150
151 return channels;
152}
153
154static void ixp2400_msf_enable_rx(struct ixp2400_msf_parameters *mp)
155{
156 u32 value;
157
158 value = ixp2000_reg_read(IXP2000_MSF_RX_CONTROL) & 0x0fffffff;
159 value |= ixp2400_msf_valid_channels(mp->rx_mode) << 28;
160 ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, value);
161}
162
163static void ixp2400_msf_enable_tx(struct ixp2400_msf_parameters *mp)
164{
165 u32 value;
166
167 value = ixp2000_reg_read(IXP2000_MSF_TX_CONTROL) & 0x0fffffff;
168 value |= ixp2400_msf_valid_channels(mp->tx_mode) << 28;
169 ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, value);
170}
171
172
173void ixp2400_msf_init(struct ixp2400_msf_parameters *mp)
174{
175 u32 value;
176 int i;
177
178 /*
179 * Init the RX/TX PLLs based on the passed parameter block.
180 */
181 ixp2400_pll_init(mp);
182
183 /*
184 * Reset MSF. Bit 7 in IXP_RESET_0 resets the MSF.
185 */
186 value = ixp2000_reg_read(IXP2000_RESET0);
187 ixp2000_reg_write(IXP2000_RESET0, value | 0x80);
188 ixp2000_reg_write(IXP2000_RESET0, value & ~0x80);
189
190 /*
191 * Initialise the RX section.
192 */
193 ixp2000_reg_write(IXP2000_MSF_RX_MPHY_POLL_LIMIT, mp->rx_poll_ports - 1);
194 ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, mp->rx_mode);
195 for (i = 0; i < 4; i++) {
196 ixp2000_reg_write(IXP2000_MSF_RX_UP_CONTROL_0 + i,
197 mp->rx_channel_mode[i]);
198 }
199 ixp2400_msf_free_rbuf_entries(mp);
200 ixp2400_msf_enable_rx(mp);
201
202 /*
203 * Initialise the TX section.
204 */
205 ixp2000_reg_write(IXP2000_MSF_TX_MPHY_POLL_LIMIT, mp->tx_poll_ports - 1);
206 ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, mp->tx_mode);
207 for (i = 0; i < 4; i++) {
208 ixp2000_reg_write(IXP2000_MSF_TX_UP_CONTROL_0 + i,
209 mp->tx_channel_mode[i]);
210 }
211 ixp2400_msf_enable_tx(mp);
212}
diff --git a/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h b/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h
new file mode 100644
index 000000000000..3ac1af2771da
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h
@@ -0,0 +1,115 @@
1/*
2 * Generic library functions for the MSF (Media and Switch Fabric) unit
3 * found on the Intel IXP2400 network processor.
4 *
5 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
6 * Dedicated to Marija Kulikova.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation; either version 2.1 of the
11 * License, or (at your option) any later version.
12 */
13
14#ifndef __IXP2400_MSF_H
15#define __IXP2400_MSF_H
16
17struct ixp2400_msf_parameters
18{
19 u32 rx_mode;
20 unsigned rxclk01_multiplier:2;
21 unsigned rxclk23_multiplier:2;
22 unsigned rx_poll_ports:6;
23 u32 rx_channel_mode[4];
24
25 u32 tx_mode;
26 unsigned txclk01_multiplier:2;
27 unsigned txclk23_multiplier:2;
28 unsigned tx_poll_ports:6;
29 u32 tx_channel_mode[4];
30};
31
32void ixp2400_msf_init(struct ixp2400_msf_parameters *mp);
33
34#define IXP2400_PLL_MULTIPLIER_48 0x00
35#define IXP2400_PLL_MULTIPLIER_24 0x01
36#define IXP2400_PLL_MULTIPLIER_16 0x02
37#define IXP2400_PLL_MULTIPLIER_12 0x03
38
39#define IXP2400_RX_MODE_CSIX 0x00400000
40#define IXP2400_RX_MODE_UTOPIA_POS 0x00000000
41#define IXP2400_RX_MODE_WIDTH_MASK 0x00300000
42#define IXP2400_RX_MODE_1x16_2x8 0x00300000
43#define IXP2400_RX_MODE_4x8 0x00200000
44#define IXP2400_RX_MODE_2x16 0x00100000
45#define IXP2400_RX_MODE_1x32 0x00000000
46#define IXP2400_RX_MODE_MPHY 0x00080000
47#define IXP2400_RX_MODE_SPHY 0x00000000
48#define IXP2400_RX_MODE_MPHY_32 0x00040000
49#define IXP2400_RX_MODE_MPHY_4 0x00000000
50#define IXP2400_RX_MODE_MPHY_POLLED_STATUS 0x00020000
51#define IXP2400_RX_MODE_MPHY_DIRECT_STATUS 0x00000000
52#define IXP2400_RX_MODE_CBUS_FULL_DUPLEX 0x00010000
53#define IXP2400_RX_MODE_CBUS_SIMPLEX 0x00000000
54#define IXP2400_RX_MODE_MPHY_LEVEL2 0x00004000
55#define IXP2400_RX_MODE_MPHY_LEVEL3 0x00000000
56#define IXP2400_RX_MODE_CBUS_8BIT 0x00002000
57#define IXP2400_RX_MODE_CBUS_4BIT 0x00000000
58#define IXP2400_RX_MODE_CSIX_SINGLE_FREELIST 0x00000200
59#define IXP2400_RX_MODE_CSIX_SPLIT_FREELISTS 0x00000000
60#define IXP2400_RX_MODE_RBUF_SIZE_MASK 0x0000000c
61#define IXP2400_RX_MODE_RBUF_SIZE_256 0x00000008
62#define IXP2400_RX_MODE_RBUF_SIZE_128 0x00000004
63#define IXP2400_RX_MODE_RBUF_SIZE_64 0x00000000
64
65#define IXP2400_PORT_RX_MODE_SLAVE 0x00000040
66#define IXP2400_PORT_RX_MODE_MASTER 0x00000000
67#define IXP2400_PORT_RX_MODE_POS_PHY_L3 0x00000020
68#define IXP2400_PORT_RX_MODE_POS_PHY_L2 0x00000000
69#define IXP2400_PORT_RX_MODE_POS_PHY 0x00000010
70#define IXP2400_PORT_RX_MODE_UTOPIA 0x00000000
71#define IXP2400_PORT_RX_MODE_EVEN_PARITY 0x0000000c
72#define IXP2400_PORT_RX_MODE_ODD_PARITY 0x00000008
73#define IXP2400_PORT_RX_MODE_NO_PARITY 0x00000000
74#define IXP2400_PORT_RX_MODE_UTOPIA_BIG_CELLS 0x00000002
75#define IXP2400_PORT_RX_MODE_UTOPIA_NORMAL_CELLS 0x00000000
76#define IXP2400_PORT_RX_MODE_2_CYCLE_DECODE 0x00000001
77#define IXP2400_PORT_RX_MODE_1_CYCLE_DECODE 0x00000000
78
79#define IXP2400_TX_MODE_CSIX 0x00400000
80#define IXP2400_TX_MODE_UTOPIA_POS 0x00000000
81#define IXP2400_TX_MODE_WIDTH_MASK 0x00300000
82#define IXP2400_TX_MODE_1x16_2x8 0x00300000
83#define IXP2400_TX_MODE_4x8 0x00200000
84#define IXP2400_TX_MODE_2x16 0x00100000
85#define IXP2400_TX_MODE_1x32 0x00000000
86#define IXP2400_TX_MODE_MPHY 0x00080000
87#define IXP2400_TX_MODE_SPHY 0x00000000
88#define IXP2400_TX_MODE_MPHY_32 0x00040000
89#define IXP2400_TX_MODE_MPHY_4 0x00000000
90#define IXP2400_TX_MODE_MPHY_POLLED_STATUS 0x00020000
91#define IXP2400_TX_MODE_MPHY_DIRECT_STATUS 0x00000000
92#define IXP2400_TX_MODE_CBUS_FULL_DUPLEX 0x00010000
93#define IXP2400_TX_MODE_CBUS_SIMPLEX 0x00000000
94#define IXP2400_TX_MODE_MPHY_LEVEL2 0x00004000
95#define IXP2400_TX_MODE_MPHY_LEVEL3 0x00000000
96#define IXP2400_TX_MODE_CBUS_8BIT 0x00002000
97#define IXP2400_TX_MODE_CBUS_4BIT 0x00000000
98#define IXP2400_TX_MODE_TBUF_SIZE_MASK 0x0000000c
99#define IXP2400_TX_MODE_TBUF_SIZE_256 0x00000008
100#define IXP2400_TX_MODE_TBUF_SIZE_128 0x00000004
101#define IXP2400_TX_MODE_TBUF_SIZE_64 0x00000000
102
103#define IXP2400_PORT_TX_MODE_SLAVE 0x00000040
104#define IXP2400_PORT_TX_MODE_MASTER 0x00000000
105#define IXP2400_PORT_TX_MODE_POS_PHY 0x00000010
106#define IXP2400_PORT_TX_MODE_UTOPIA 0x00000000
107#define IXP2400_PORT_TX_MODE_EVEN_PARITY 0x0000000c
108#define IXP2400_PORT_TX_MODE_ODD_PARITY 0x00000008
109#define IXP2400_PORT_TX_MODE_NO_PARITY 0x00000000
110#define IXP2400_PORT_TX_MODE_UTOPIA_BIG_CELLS 0x00000002
111#define IXP2400_PORT_TX_MODE_2_CYCLE_DECODE 0x00000001
112#define IXP2400_PORT_TX_MODE_1_CYCLE_DECODE 0x00000000
113
114
115#endif
diff --git a/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc b/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc
new file mode 100644
index 000000000000..42a73e357afa
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc
@@ -0,0 +1,408 @@
1/*
2 * RX ucode for the Intel IXP2400 in POS-PHY mode.
3 * Copyright (C) 2004, 2005 Lennert Buytenhek
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Assumptions made in this code:
12 * - The IXP2400 MSF is configured for POS-PHY mode, in a mode where
13 * only one full element list is used. This includes, for example,
14 * 1x32 SPHY and 1x32 MPHY32, but not 4x8 SPHY or 1x32 MPHY4. (This
15 * is not an exhaustive list.)
16 * - The RBUF uses 64-byte mpackets.
17 * - RX descriptors reside in SRAM, and have the following format:
18 * struct rx_desc
19 * {
20 * // to uengine
21 * u32 buf_phys_addr;
22 * u32 buf_length;
23 *
24 * // from uengine
25 * u32 channel;
26 * u32 pkt_length;
27 * };
28 * - Packet data resides in DRAM.
29 * - Packet buffer addresses are 8-byte aligned.
30 * - Scratch ring 0 is rx_pending.
31 * - Scratch ring 1 is rx_done, and has status condition 'full'.
32 * - The host triggers rx_done flush and rx_pending refill on seeing INTA.
33 * - This code is run on all eight threads of the microengine it runs on.
34 *
35 * Local memory is used for per-channel RX state.
36 */
37
38#define RX_THREAD_FREELIST_0 0x0030
39#define RBUF_ELEMENT_DONE 0x0044
40
41#define CHANNEL_FLAGS *l$index0[0]
42#define CHANNEL_FLAG_RECEIVING 1
43#define PACKET_LENGTH *l$index0[1]
44#define PACKET_CHECKSUM *l$index0[2]
45#define BUFFER_HANDLE *l$index0[3]
46#define BUFFER_START *l$index0[4]
47#define BUFFER_LENGTH *l$index0[5]
48
49#define CHANNEL_STATE_SIZE 24 // in bytes
50#define CHANNEL_STATE_SHIFT 5 // ceil(log2(state size))
51
52
53 .sig volatile sig1
54 .sig volatile sig2
55 .sig volatile sig3
56
57 .sig mpacket_arrived
58 .reg add_to_rx_freelist
59 .reg read $rsw0, $rsw1
60 .xfer_order $rsw0 $rsw1
61
62 .reg zero
63
64 /*
65 * Initialise add_to_rx_freelist.
66 */
67 .begin
68 .reg temp
69 .reg temp2
70
71 immed[add_to_rx_freelist, RX_THREAD_FREELIST_0]
72 immed_w1[add_to_rx_freelist, (&$rsw0 | (&mpacket_arrived << 12))]
73
74 local_csr_rd[ACTIVE_CTX_STS]
75 immed[temp, 0]
76 alu[temp2, temp, and, 0x1f]
77 alu_shf[add_to_rx_freelist, add_to_rx_freelist, or, temp2, <<20]
78 alu[temp2, temp, and, 0x80]
79 alu_shf[add_to_rx_freelist, add_to_rx_freelist, or, temp2, <<18]
80 .end
81
82 immed[zero, 0]
83
84 /*
85 * Skip context 0 initialisation?
86 */
87 .begin
88 br!=ctx[0, mpacket_receive_loop#]
89 .end
90
91 /*
92 * Initialise local memory.
93 */
94 .begin
95 .reg addr
96 .reg temp
97
98 immed[temp, 0]
99 init_local_mem_loop#:
100 alu_shf[addr, --, b, temp, <<CHANNEL_STATE_SHIFT]
101 local_csr_wr[ACTIVE_LM_ADDR_0, addr]
102 nop
103 nop
104 nop
105
106 immed[CHANNEL_FLAGS, 0]
107
108 alu[temp, temp, +, 1]
109 alu[--, temp, and, 0x20]
110 beq[init_local_mem_loop#]
111 .end
112
113 /*
114 * Initialise signal pipeline.
115 */
116 .begin
117 local_csr_wr[SAME_ME_SIGNAL, (&sig1 << 3)]
118 .set_sig sig1
119
120 local_csr_wr[SAME_ME_SIGNAL, (&sig2 << 3)]
121 .set_sig sig2
122
123 local_csr_wr[SAME_ME_SIGNAL, (&sig3 << 3)]
124 .set_sig sig3
125 .end
126
127mpacket_receive_loop#:
128 /*
129 * Synchronise and wait for mpacket.
130 */
131 .begin
132 ctx_arb[sig1]
133 local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig1 << 3))]
134
135 msf[fast_wr, --, add_to_rx_freelist, 0]
136 .set_sig mpacket_arrived
137 ctx_arb[mpacket_arrived]
138 .set $rsw0 $rsw1
139 .end
140
141 /*
142 * We halt if we see {inbparerr,parerr,null,soperror}.
143 */
144 .begin
145 alu_shf[--, 0x1b, and, $rsw0, >>8]
146 bne[abort_rswerr#]
147 .end
148
149 /*
150 * Point local memory pointer to this channel's state area.
151 */
152 .begin
153 .reg chanaddr
154
155 alu[chanaddr, $rsw0, and, 0x1f]
156 alu_shf[chanaddr, --, b, chanaddr, <<CHANNEL_STATE_SHIFT]
157 local_csr_wr[ACTIVE_LM_ADDR_0, chanaddr]
158 nop
159 nop
160 nop
161 .end
162
163 /*
164 * Check whether we received a SOP mpacket while we were already
165 * working on a packet, or a non-SOP mpacket while there was no
166 * packet pending. (SOP == RECEIVING -> abort) If everything's
167 * okay, update the RECEIVING flag to reflect our new state.
168 */
169 .begin
170 .reg temp
171 .reg eop
172
173 #if CHANNEL_FLAG_RECEIVING != 1
174 #error CHANNEL_FLAG_RECEIVING is not 1
175 #endif
176
177 alu_shf[temp, 1, and, $rsw0, >>15]
178 alu[temp, temp, xor, CHANNEL_FLAGS]
179 alu[--, temp, and, CHANNEL_FLAG_RECEIVING]
180 beq[abort_proterr#]
181
182 alu_shf[eop, 1, and, $rsw0, >>14]
183 alu[CHANNEL_FLAGS, temp, xor, eop]
184 .end
185
186 /*
187 * Copy the mpacket into the right spot, and in case of EOP,
188 * write back the descriptor and pass the packet on.
189 */
190 .begin
191 .reg buffer_offset
192 .reg _packet_length
193 .reg _packet_checksum
194 .reg _buffer_handle
195 .reg _buffer_start
196 .reg _buffer_length
197
198 /*
199 * Determine buffer_offset, _packet_length and
200 * _packet_checksum.
201 */
202 .begin
203 .reg temp
204
205 alu[--, 1, and, $rsw0, >>15]
206 beq[not_sop#]
207
208 immed[PACKET_LENGTH, 0]
209 immed[PACKET_CHECKSUM, 0]
210
211 not_sop#:
212 alu[buffer_offset, --, b, PACKET_LENGTH]
213 alu_shf[temp, 0xff, and, $rsw0, >>16]
214 alu[_packet_length, buffer_offset, +, temp]
215 alu[PACKET_LENGTH, --, b, _packet_length]
216
217 immed[temp, 0xffff]
218 alu[temp, $rsw1, and, temp]
219 alu[_packet_checksum, PACKET_CHECKSUM, +, temp]
220 alu[PACKET_CHECKSUM, --, b, _packet_checksum]
221 .end
222
223 /*
224 * Allocate buffer in case of SOP.
225 */
226 .begin
227 .reg temp
228
229 alu[temp, 1, and, $rsw0, >>15]
230 beq[skip_buffer_alloc#]
231
232 .begin
233 .sig zzz
234 .reg read $stemp $stemp2
235 .xfer_order $stemp $stemp2
236
237 rx_nobufs#:
238 scratch[get, $stemp, zero, 0, 1], ctx_swap[zzz]
239 alu[_buffer_handle, --, b, $stemp]
240 beq[rx_nobufs#]
241
242 sram[read, $stemp, _buffer_handle, 0, 2],
243 ctx_swap[zzz]
244 alu[_buffer_start, --, b, $stemp]
245 alu[_buffer_length, --, b, $stemp2]
246 .end
247
248 skip_buffer_alloc#:
249 .end
250
251 /*
252 * Resynchronise.
253 */
254 .begin
255 ctx_arb[sig2]
256 local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig2 << 3))]
257 .end
258
259 /*
260 * Synchronise buffer state.
261 */
262 .begin
263 .reg temp
264
265 alu[temp, 1, and, $rsw0, >>15]
266 beq[copy_from_local_mem#]
267
268 alu[BUFFER_HANDLE, --, b, _buffer_handle]
269 alu[BUFFER_START, --, b, _buffer_start]
270 alu[BUFFER_LENGTH, --, b, _buffer_length]
271 br[sync_state_done#]
272
273 copy_from_local_mem#:
274 alu[_buffer_handle, --, b, BUFFER_HANDLE]
275 alu[_buffer_start, --, b, BUFFER_START]
276 alu[_buffer_length, --, b, BUFFER_LENGTH]
277
278 sync_state_done#:
279 .end
280
281#if 0
282 /*
283 * Debug buffer state management.
284 */
285 .begin
286 .reg temp
287
288 alu[temp, 1, and, $rsw0, >>14]
289 beq[no_poison#]
290 immed[BUFFER_HANDLE, 0xdead]
291 immed[BUFFER_START, 0xdead]
292 immed[BUFFER_LENGTH, 0xdead]
293 no_poison#:
294
295 immed[temp, 0xdead]
296 alu[--, _buffer_handle, -, temp]
297 beq[state_corrupted#]
298 alu[--, _buffer_start, -, temp]
299 beq[state_corrupted#]
300 alu[--, _buffer_length, -, temp]
301 beq[state_corrupted#]
302 .end
303#endif
304
305 /*
306 * Check buffer length.
307 */
308 .begin
309 alu[--, _buffer_length, -, _packet_length]
310 blo[buffer_overflow#]
311 .end
312
313 /*
314 * Copy the mpacket and give back the RBUF element.
315 */
316 .begin
317 .reg element
318 .reg xfer_size
319 .reg temp
320 .sig copy_sig
321
322 alu_shf[element, 0x7f, and, $rsw0, >>24]
323 alu_shf[xfer_size, 0xff, and, $rsw0, >>16]
324
325 alu[xfer_size, xfer_size, -, 1]
326 alu_shf[xfer_size, 0x10, or, xfer_size, >>3]
327 alu_shf[temp, 0x10, or, xfer_size, <<21]
328 alu_shf[temp, temp, or, element, <<11]
329 alu_shf[--, temp, or, 1, <<18]
330
331 dram[rbuf_rd, --, _buffer_start, buffer_offset, max_8],
332 indirect_ref, sig_done[copy_sig]
333 ctx_arb[copy_sig]
334
335 alu[temp, RBUF_ELEMENT_DONE, or, element, <<16]
336 msf[fast_wr, --, temp, 0]
337 .end
338
339 /*
340 * If EOP, write back the packet descriptor.
341 */
342 .begin
343 .reg write $stemp $stemp2
344 .xfer_order $stemp $stemp2
345 .sig zzz
346
347 alu_shf[--, 1, and, $rsw0, >>14]
348 beq[no_writeback#]
349
350 alu[$stemp, $rsw0, and, 0x1f]
351 alu[$stemp2, --, b, _packet_length]
352 sram[write, $stemp, _buffer_handle, 8, 2], ctx_swap[zzz]
353
354 no_writeback#:
355 .end
356
357 /*
358 * Resynchronise.
359 */
360 .begin
361 ctx_arb[sig3]
362 local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig3 << 3))]
363 .end
364
365 /*
366 * If EOP, put the buffer back onto the scratch ring.
367 */
368 .begin
369 .reg write $stemp
370 .sig zzz
371
372 br_inp_state[SCR_Ring1_Status, rx_done_ring_overflow#]
373
374 alu_shf[--, 1, and, $rsw0, >>14]
375 beq[mpacket_receive_loop#]
376
377 alu[--, 1, and, $rsw0, >>10]
378 bne[rxerr#]
379
380 alu[$stemp, --, b, _buffer_handle]
381 scratch[put, $stemp, zero, 4, 1], ctx_swap[zzz]
382 cap[fast_wr, 0, XSCALE_INT_A]
383 br[mpacket_receive_loop#]
384
385 rxerr#:
386 alu[$stemp, --, b, _buffer_handle]
387 scratch[put, $stemp, zero, 0, 1], ctx_swap[zzz]
388 br[mpacket_receive_loop#]
389 .end
390 .end
391
392
393abort_rswerr#:
394 halt
395
396abort_proterr#:
397 halt
398
399state_corrupted#:
400 halt
401
402buffer_overflow#:
403 halt
404
405rx_done_ring_overflow#:
406 halt
407
408
diff --git a/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode b/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode
new file mode 100644
index 000000000000..e8aee2f81aad
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode
@@ -0,0 +1,130 @@
1static struct ixp2000_uengine_code ixp2400_rx =
2{
3 .cpu_model_bitmask = 0x000003fe,
4 .cpu_min_revision = 0,
5 .cpu_max_revision = 255,
6
7 .uengine_parameters = IXP2000_UENGINE_8_CONTEXTS |
8 IXP2000_UENGINE_PRN_UPDATE_EVERY |
9 IXP2000_UENGINE_NN_FROM_PREVIOUS |
10 IXP2000_UENGINE_ASSERT_EMPTY_AT_0 |
11 IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT |
12 IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT,
13
14 .initial_reg_values = (struct ixp2000_reg_value []) {
15 { -1, -1 }
16 },
17
18 .num_insns = 109,
19 .insns = (u8 []) {
20 0xf0, 0x00, 0x0c, 0xc0, 0x05,
21 0xf4, 0x44, 0x0c, 0x00, 0x05,
22 0xfc, 0x04, 0x4c, 0x00, 0x00,
23 0xf0, 0x00, 0x00, 0x3b, 0x00,
24 0xb4, 0x40, 0xf0, 0x3b, 0x1f,
25 0x8a, 0xc0, 0x50, 0x3e, 0x05,
26 0xb4, 0x40, 0xf0, 0x3b, 0x80,
27 0x9a, 0xe0, 0x00, 0x3e, 0x05,
28 0xf0, 0x00, 0x00, 0x07, 0x00,
29 0xd8, 0x05, 0xc0, 0x00, 0x11,
30 0xf0, 0x00, 0x00, 0x0f, 0x00,
31 0x91, 0xb0, 0x20, 0x0e, 0x00,
32 0xfc, 0x06, 0x60, 0x0b, 0x00,
33 0xf0, 0x00, 0x0c, 0x03, 0x00,
34 0xf0, 0x00, 0x0c, 0x03, 0x00,
35 0xf0, 0x00, 0x0c, 0x03, 0x00,
36 0xf0, 0x00, 0x0c, 0x02, 0x00,
37 0xb0, 0xc0, 0x30, 0x0f, 0x01,
38 0xa4, 0x70, 0x00, 0x0f, 0x20,
39 0xd8, 0x02, 0xc0, 0x01, 0x00,
40 0xfc, 0x10, 0xac, 0x23, 0x08,
41 0xfc, 0x10, 0xac, 0x43, 0x10,
42 0xfc, 0x10, 0xac, 0x63, 0x18,
43 0xe0, 0x00, 0x00, 0x00, 0x02,
44 0xfc, 0x10, 0xae, 0x23, 0x88,
45 0x3d, 0x00, 0x04, 0x03, 0x20,
46 0xe0, 0x00, 0x00, 0x00, 0x10,
47 0x84, 0x82, 0x02, 0x01, 0x3b,
48 0xd8, 0x1a, 0x00, 0x01, 0x01,
49 0xb4, 0x00, 0x8c, 0x7d, 0x80,
50 0x91, 0xb0, 0x80, 0x22, 0x00,
51 0xfc, 0x06, 0x60, 0x23, 0x00,
52 0xf0, 0x00, 0x0c, 0x03, 0x00,
53 0xf0, 0x00, 0x0c, 0x03, 0x00,
54 0xf0, 0x00, 0x0c, 0x03, 0x00,
55 0x94, 0xf0, 0x92, 0x01, 0x21,
56 0xac, 0x40, 0x60, 0x26, 0x00,
57 0xa4, 0x30, 0x0c, 0x04, 0x06,
58 0xd8, 0x1a, 0x40, 0x01, 0x00,
59 0x94, 0xe0, 0xa2, 0x01, 0x21,
60 0xac, 0x20, 0x00, 0x28, 0x06,
61 0x84, 0xf2, 0x02, 0x01, 0x21,
62 0xd8, 0x0b, 0x40, 0x01, 0x00,
63 0xf0, 0x00, 0x0c, 0x02, 0x01,
64 0xf0, 0x00, 0x0c, 0x02, 0x02,
65 0xa0, 0x00, 0x08, 0x04, 0x00,
66 0x95, 0x00, 0xc6, 0x01, 0xff,
67 0xa0, 0x80, 0x10, 0x30, 0x00,
68 0xa0, 0x60, 0x1c, 0x00, 0x01,
69 0xf0, 0x0f, 0xf0, 0x33, 0xff,
70 0xb4, 0x00, 0xc0, 0x31, 0x81,
71 0xb0, 0x80, 0xb0, 0x32, 0x02,
72 0xa0, 0x20, 0x20, 0x2c, 0x00,
73 0x94, 0xf0, 0xd2, 0x01, 0x21,
74 0xd8, 0x0f, 0x40, 0x01, 0x00,
75 0x19, 0x40, 0x10, 0x04, 0x20,
76 0xa0, 0x00, 0x26, 0x04, 0x00,
77 0xd8, 0x0d, 0xc0, 0x01, 0x00,
78 0x00, 0x42, 0x10, 0x80, 0x02,
79 0xb0, 0x00, 0x46, 0x04, 0x00,
80 0xb0, 0x00, 0x56, 0x08, 0x00,
81 0xe0, 0x00, 0x00, 0x00, 0x04,
82 0xfc, 0x10, 0xae, 0x43, 0x90,
83 0x84, 0xf0, 0x32, 0x01, 0x21,
84 0xd8, 0x11, 0x40, 0x01, 0x00,
85 0xa0, 0x60, 0x3c, 0x00, 0x02,
86 0xa0, 0x20, 0x40, 0x10, 0x00,
87 0xa0, 0x20, 0x50, 0x14, 0x00,
88 0xd8, 0x12, 0x00, 0x00, 0x18,
89 0xa0, 0x00, 0x28, 0x0c, 0x00,
90 0xb0, 0x00, 0x48, 0x10, 0x00,
91 0xb0, 0x00, 0x58, 0x14, 0x00,
92 0xaa, 0xf0, 0x00, 0x14, 0x01,
93 0xd8, 0x1a, 0xc0, 0x01, 0x05,
94 0x85, 0x80, 0x42, 0x01, 0xff,
95 0x95, 0x00, 0x66, 0x01, 0xff,
96 0xba, 0xc0, 0x60, 0x1b, 0x01,
97 0x9a, 0x30, 0x60, 0x19, 0x30,
98 0x9a, 0xb0, 0x70, 0x1a, 0x30,
99 0x9b, 0x50, 0x78, 0x1e, 0x04,
100 0x8a, 0xe2, 0x08, 0x1e, 0x21,
101 0x6a, 0x4e, 0x00, 0x13, 0x00,
102 0xe0, 0x00, 0x00, 0x00, 0x30,
103 0x9b, 0x00, 0x7a, 0x92, 0x04,
104 0x3d, 0x00, 0x04, 0x1f, 0x20,
105 0x84, 0xe2, 0x02, 0x01, 0x21,
106 0xd8, 0x16, 0x80, 0x01, 0x00,
107 0xa4, 0x18, 0x0c, 0x7d, 0x80,
108 0xa0, 0x58, 0x1c, 0x00, 0x01,
109 0x01, 0x42, 0x00, 0xa0, 0x02,
110 0xe0, 0x00, 0x00, 0x00, 0x08,
111 0xfc, 0x10, 0xae, 0x63, 0x98,
112 0xd8, 0x1b, 0x00, 0xc2, 0x14,
113 0x84, 0xe2, 0x02, 0x01, 0x21,
114 0xd8, 0x05, 0xc0, 0x01, 0x00,
115 0x84, 0xa2, 0x02, 0x01, 0x21,
116 0xd8, 0x19, 0x40, 0x01, 0x01,
117 0xa0, 0x58, 0x0c, 0x00, 0x02,
118 0x1a, 0x40, 0x00, 0x04, 0x24,
119 0x33, 0x00, 0x01, 0x2f, 0x20,
120 0xd8, 0x05, 0xc0, 0x00, 0x18,
121 0xa0, 0x58, 0x0c, 0x00, 0x02,
122 0x1a, 0x40, 0x00, 0x04, 0x20,
123 0xd8, 0x05, 0xc0, 0x00, 0x18,
124 0xe0, 0x00, 0x02, 0x00, 0x00,
125 0xe0, 0x00, 0x02, 0x00, 0x00,
126 0xe0, 0x00, 0x02, 0x00, 0x00,
127 0xe0, 0x00, 0x02, 0x00, 0x00,
128 0xe0, 0x00, 0x02, 0x00, 0x00,
129 }
130};
diff --git a/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc b/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc
new file mode 100644
index 000000000000..d090d1884fb7
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc
@@ -0,0 +1,272 @@
1/*
2 * TX ucode for the Intel IXP2400 in POS-PHY mode.
3 * Copyright (C) 2004, 2005 Lennert Buytenhek
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Assumptions made in this code:
12 * - The IXP2400 MSF is configured for POS-PHY mode, in a mode where
13 * only one TBUF partition is used. This includes, for example,
14 * 1x32 SPHY and 1x32 MPHY32, but not 4x8 SPHY or 1x32 MPHY4. (This
15 * is not an exhaustive list.)
16 * - The TBUF uses 64-byte mpackets.
17 * - TX descriptors reside in SRAM, and have the following format:
18 * struct tx_desc
19 * {
20 * // to uengine
21 * u32 buf_phys_addr;
22 * u32 pkt_length;
23 * u32 channel;
24 * };
25 * - Packet data resides in DRAM.
26 * - Packet buffer addresses are 8-byte aligned.
27 * - Scratch ring 2 is tx_pending.
28 * - Scratch ring 3 is tx_done, and has status condition 'full'.
29 * - This code is run on all eight threads of the microengine it runs on.
30 */
31
32#define TX_SEQUENCE_0 0x0060
33#define TBUF_CTRL 0x1800
34
35#define PARTITION_SIZE 128
36#define PARTITION_THRESH 96
37
38
39 .sig volatile sig1
40 .sig volatile sig2
41 .sig volatile sig3
42
43 .reg @old_tx_seq_0
44 .reg @mpkts_in_flight
45 .reg @next_tbuf_mpacket
46
47 .reg @buffer_handle
48 .reg @buffer_start
49 .reg @packet_length
50 .reg @channel
51 .reg @packet_offset
52
53 .reg zero
54
55 immed[zero, 0]
56
57 /*
58 * Skip context 0 initialisation?
59 */
60 .begin
61 br!=ctx[0, mpacket_tx_loop#]
62 .end
63
64 /*
65 * Wait until all pending TBUF elements have been transmitted.
66 */
67 .begin
68 .reg read $tx
69 .sig zzz
70
71 loop_empty#:
72 msf[read, $tx, zero, TX_SEQUENCE_0, 1], ctx_swap[zzz]
73 alu_shf[--, --, b, $tx, >>31]
74 beq[loop_empty#]
75
76 alu[@old_tx_seq_0, --, b, $tx]
77 .end
78
79 immed[@mpkts_in_flight, 0]
80 alu[@next_tbuf_mpacket, @old_tx_seq_0, and, (PARTITION_SIZE - 1)]
81
82 immed[@buffer_handle, 0]
83
84 /*
85 * Initialise signal pipeline.
86 */
87 .begin
88 local_csr_wr[SAME_ME_SIGNAL, (&sig1 << 3)]
89 .set_sig sig1
90
91 local_csr_wr[SAME_ME_SIGNAL, (&sig2 << 3)]
92 .set_sig sig2
93
94 local_csr_wr[SAME_ME_SIGNAL, (&sig3 << 3)]
95 .set_sig sig3
96 .end
97
98mpacket_tx_loop#:
99 .begin
100 .reg tbuf_element_index
101 .reg buffer_handle
102 .reg sop_eop
103 .reg packet_data
104 .reg channel
105 .reg mpacket_size
106
107 /*
108 * If there is no packet currently being transmitted,
109 * dequeue the next TX descriptor, and fetch the buffer
110 * address, packet length and destination channel number.
111 */
112 .begin
113 .reg read $stemp $stemp2 $stemp3
114 .xfer_order $stemp $stemp2 $stemp3
115 .sig zzz
116
117 ctx_arb[sig1]
118
119 alu[--, --, b, @buffer_handle]
120 bne[already_got_packet#]
121
122 tx_nobufs#:
123 scratch[get, $stemp, zero, 8, 1], ctx_swap[zzz]
124 alu[@buffer_handle, --, b, $stemp]
125 beq[tx_nobufs#]
126
127 sram[read, $stemp, $stemp, 0, 3], ctx_swap[zzz]
128 alu[@buffer_start, --, b, $stemp]
129 alu[@packet_length, --, b, $stemp2]
130 beq[zero_byte_packet#]
131 alu[@channel, --, b, $stemp3]
132 immed[@packet_offset, 0]
133
134 already_got_packet#:
135 local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig1 << 3))]
136 .end
137
138 /*
139 * Determine tbuf element index, SOP/EOP flags, mpacket
140 * offset and mpacket size and cache buffer_handle and
141 * channel number.
142 */
143 .begin
144 alu[tbuf_element_index, --, b, @next_tbuf_mpacket]
145 alu[@next_tbuf_mpacket, @next_tbuf_mpacket, +, 1]
146 alu[@next_tbuf_mpacket, @next_tbuf_mpacket, and,
147 (PARTITION_SIZE - 1)]
148
149 alu[buffer_handle, --, b, @buffer_handle]
150 immed[@buffer_handle, 0]
151
152 immed[sop_eop, 1]
153
154 alu[packet_data, --, b, @packet_offset]
155 bne[no_sop#]
156 alu[sop_eop, sop_eop, or, 2]
157 no_sop#:
158 alu[packet_data, packet_data, +, @buffer_start]
159
160 alu[channel, --, b, @channel]
161
162 alu[mpacket_size, @packet_length, -, @packet_offset]
163 alu[--, 64, -, mpacket_size]
164 bhs[eop#]
165 alu[@buffer_handle, --, b, buffer_handle]
166 immed[mpacket_size, 64]
167 alu[sop_eop, sop_eop, and, 2]
168 eop#:
169
170 alu[@packet_offset, @packet_offset, +, mpacket_size]
171 .end
172
173 /*
174 * Wait until there's enough space in the TBUF.
175 */
176 .begin
177 .reg read $tx
178 .reg temp
179 .sig zzz
180
181 ctx_arb[sig2]
182
183 br[test_space#]
184
185 loop_space#:
186 msf[read, $tx, zero, TX_SEQUENCE_0, 1], ctx_swap[zzz]
187
188 alu[temp, $tx, -, @old_tx_seq_0]
189 alu[temp, temp, and, 0xff]
190 alu[@mpkts_in_flight, @mpkts_in_flight, -, temp]
191
192 alu[@old_tx_seq_0, --, b, $tx]
193
194 test_space#:
195 alu[--, PARTITION_THRESH, -, @mpkts_in_flight]
196 blo[loop_space#]
197
198 alu[@mpkts_in_flight, @mpkts_in_flight, +, 1]
199
200 local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig2 << 3))]
201 .end
202
203 /*
204 * Copy the packet data to the TBUF.
205 */
206 .begin
207 .reg temp
208 .sig copy_sig
209
210 alu[temp, mpacket_size, -, 1]
211 alu_shf[temp, 0x10, or, temp, >>3]
212 alu_shf[temp, 0x10, or, temp, <<21]
213 alu_shf[temp, temp, or, tbuf_element_index, <<11]
214 alu_shf[--, temp, or, 1, <<18]
215
216 dram[tbuf_wr, --, packet_data, 0, max_8],
217 indirect_ref, sig_done[copy_sig]
218 ctx_arb[copy_sig]
219 .end
220
221 /*
222 * Mark TBUF element as ready-to-be-transmitted.
223 */
224 .begin
225 .reg write $tsw $tsw2
226 .xfer_order $tsw $tsw2
227 .reg temp
228 .sig zzz
229
230 alu_shf[temp, channel, or, mpacket_size, <<24]
231 alu_shf[$tsw, temp, or, sop_eop, <<8]
232 immed[$tsw2, 0]
233
234 immed[temp, TBUF_CTRL]
235 alu_shf[temp, temp, or, tbuf_element_index, <<3]
236 msf[write, $tsw, temp, 0, 2], ctx_swap[zzz]
237 .end
238
239 /*
240 * Resynchronise.
241 */
242 .begin
243 ctx_arb[sig3]
244 local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig3 << 3))]
245 .end
246
247 /*
248 * If this was an EOP mpacket, recycle the TX buffer
249 * and signal the host.
250 */
251 .begin
252 .reg write $stemp
253 .sig zzz
254
255 alu[--, sop_eop, and, 1]
256 beq[mpacket_tx_loop#]
257
258 tx_done_ring_full#:
259 br_inp_state[SCR_Ring3_Status, tx_done_ring_full#]
260
261 alu[$stemp, --, b, buffer_handle]
262 scratch[put, $stemp, zero, 12, 1], ctx_swap[zzz]
263 cap[fast_wr, 0, XSCALE_INT_A]
264 br[mpacket_tx_loop#]
265 .end
266 .end
267
268
269zero_byte_packet#:
270 halt
271
272
diff --git a/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode b/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode
new file mode 100644
index 000000000000..a433e24b0a51
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode
@@ -0,0 +1,98 @@
1static struct ixp2000_uengine_code ixp2400_tx =
2{
3 .cpu_model_bitmask = 0x000003fe,
4 .cpu_min_revision = 0,
5 .cpu_max_revision = 255,
6
7 .uengine_parameters = IXP2000_UENGINE_8_CONTEXTS |
8 IXP2000_UENGINE_PRN_UPDATE_EVERY |
9 IXP2000_UENGINE_NN_FROM_PREVIOUS |
10 IXP2000_UENGINE_ASSERT_EMPTY_AT_0 |
11 IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT |
12 IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT,
13
14 .initial_reg_values = (struct ixp2000_reg_value []) {
15 { -1, -1 }
16 },
17
18 .num_insns = 77,
19 .insns = (u8 []) {
20 0xf0, 0x00, 0x00, 0x07, 0x00,
21 0xd8, 0x03, 0x00, 0x00, 0x11,
22 0x3c, 0x40, 0x00, 0x04, 0xe0,
23 0x81, 0xf2, 0x02, 0x01, 0x00,
24 0xd8, 0x00, 0x80, 0x01, 0x00,
25 0xb0, 0x08, 0x06, 0x00, 0x00,
26 0xf0, 0x00, 0x0c, 0x00, 0x80,
27 0xb4, 0x49, 0x02, 0x03, 0x7f,
28 0xf0, 0x00, 0x02, 0x83, 0x00,
29 0xfc, 0x10, 0xac, 0x23, 0x08,
30 0xfc, 0x10, 0xac, 0x43, 0x10,
31 0xfc, 0x10, 0xac, 0x63, 0x18,
32 0xe0, 0x00, 0x00, 0x00, 0x02,
33 0xa0, 0x30, 0x02, 0x80, 0x00,
34 0xd8, 0x06, 0x00, 0x01, 0x01,
35 0x19, 0x40, 0x00, 0x04, 0x28,
36 0xb0, 0x0a, 0x06, 0x00, 0x00,
37 0xd8, 0x03, 0xc0, 0x01, 0x00,
38 0x00, 0x44, 0x00, 0x80, 0x80,
39 0xa0, 0x09, 0x06, 0x00, 0x00,
40 0xb0, 0x0b, 0x06, 0x04, 0x00,
41 0xd8, 0x13, 0x00, 0x01, 0x00,
42 0xb0, 0x0c, 0x06, 0x08, 0x00,
43 0xf0, 0x00, 0x0c, 0x00, 0xa0,
44 0xfc, 0x10, 0xae, 0x23, 0x88,
45 0xa0, 0x00, 0x12, 0x40, 0x00,
46 0xb0, 0xc9, 0x02, 0x43, 0x01,
47 0xb4, 0x49, 0x02, 0x43, 0x7f,
48 0xb0, 0x00, 0x22, 0x80, 0x00,
49 0xf0, 0x00, 0x02, 0x83, 0x00,
50 0xf0, 0x00, 0x0c, 0x04, 0x02,
51 0xb0, 0x40, 0x6c, 0x00, 0xa0,
52 0xd8, 0x08, 0x80, 0x01, 0x01,
53 0xaa, 0x00, 0x2c, 0x08, 0x02,
54 0xa0, 0xc0, 0x30, 0x18, 0x90,
55 0xa0, 0x00, 0x43, 0x00, 0x00,
56 0xba, 0xc0, 0x32, 0xc0, 0xa0,
57 0xaa, 0xb0, 0x00, 0x0f, 0x40,
58 0xd8, 0x0a, 0x80, 0x01, 0x04,
59 0xb0, 0x0a, 0x00, 0x08, 0x00,
60 0xf0, 0x00, 0x00, 0x0f, 0x40,
61 0xa4, 0x00, 0x2c, 0x08, 0x02,
62 0xa0, 0x8a, 0x00, 0x0c, 0xa0,
63 0xe0, 0x00, 0x00, 0x00, 0x04,
64 0xd8, 0x0c, 0x80, 0x00, 0x18,
65 0x3c, 0x40, 0x00, 0x04, 0xe0,
66 0xba, 0x80, 0x42, 0x01, 0x80,
67 0xb4, 0x40, 0x40, 0x13, 0xff,
68 0xaa, 0x88, 0x00, 0x10, 0x80,
69 0xb0, 0x08, 0x06, 0x00, 0x00,
70 0xaa, 0xf0, 0x0d, 0x80, 0x80,
71 0xd8, 0x0b, 0x40, 0x01, 0x05,
72 0xa0, 0x88, 0x0c, 0x04, 0x80,
73 0xfc, 0x10, 0xae, 0x43, 0x90,
74 0xba, 0xc0, 0x50, 0x0f, 0x01,
75 0x9a, 0x30, 0x50, 0x15, 0x30,
76 0x9a, 0xb0, 0x50, 0x16, 0x30,
77 0x9b, 0x50, 0x58, 0x16, 0x01,
78 0x8a, 0xe2, 0x08, 0x16, 0x21,
79 0x6b, 0x4e, 0x00, 0x83, 0x03,
80 0xe0, 0x00, 0x00, 0x00, 0x30,
81 0x9a, 0x80, 0x70, 0x0e, 0x04,
82 0x8b, 0x88, 0x08, 0x1e, 0x02,
83 0xf0, 0x00, 0x0c, 0x01, 0x81,
84 0xf0, 0x01, 0x80, 0x1f, 0x00,
85 0x9b, 0xd0, 0x78, 0x1e, 0x01,
86 0x3d, 0x42, 0x00, 0x1c, 0x20,
87 0xe0, 0x00, 0x00, 0x00, 0x08,
88 0xfc, 0x10, 0xae, 0x63, 0x98,
89 0xa4, 0x30, 0x0c, 0x04, 0x02,
90 0xd8, 0x03, 0x00, 0x01, 0x00,
91 0xd8, 0x11, 0xc1, 0x42, 0x14,
92 0xa0, 0x18, 0x00, 0x08, 0x00,
93 0x1a, 0x40, 0x00, 0x04, 0x2c,
94 0x33, 0x00, 0x01, 0x2f, 0x20,
95 0xd8, 0x03, 0x00, 0x00, 0x18,
96 0xe0, 0x00, 0x02, 0x00, 0x00,
97 }
98};
diff --git a/drivers/net/ethernet/xscale/ixp2000/ixpdev.c b/drivers/net/ethernet/xscale/ixp2000/ixpdev.c
new file mode 100644
index 000000000000..e122493ab70e
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/ixpdev.c
@@ -0,0 +1,440 @@
1/*
2 * IXP2000 MSF network device driver
3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/netdevice.h>
15#include <linux/etherdevice.h>
16#include <linux/init.h>
17#include <linux/interrupt.h>
18#include <linux/moduleparam.h>
19#include <linux/gfp.h>
20#include <asm/hardware/uengine.h>
21#include <asm/io.h>
22#include "ixp2400_rx.ucode"
23#include "ixp2400_tx.ucode"
24#include "ixpdev_priv.h"
25#include "ixpdev.h"
26#include "pm3386.h"
27
28#define DRV_MODULE_VERSION "0.2"
29
30static int nds_count;
31static struct net_device **nds;
32static int nds_open;
33static void (*set_port_admin_status)(int port, int up);
34
35static struct ixpdev_rx_desc * const rx_desc =
36 (struct ixpdev_rx_desc *)(IXP2000_SRAM0_VIRT_BASE + RX_BUF_DESC_BASE);
37static struct ixpdev_tx_desc * const tx_desc =
38 (struct ixpdev_tx_desc *)(IXP2000_SRAM0_VIRT_BASE + TX_BUF_DESC_BASE);
39static int tx_pointer;
40
41
42static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
43{
44 struct ixpdev_priv *ip = netdev_priv(dev);
45 struct ixpdev_tx_desc *desc;
46 int entry;
47 unsigned long flags;
48
49 if (unlikely(skb->len > PAGE_SIZE)) {
50 /* @@@ Count drops. */
51 dev_kfree_skb(skb);
52 return NETDEV_TX_OK;
53 }
54
55 entry = tx_pointer;
56 tx_pointer = (tx_pointer + 1) % TX_BUF_COUNT;
57
58 desc = tx_desc + entry;
59 desc->pkt_length = skb->len;
60 desc->channel = ip->channel;
61
62 skb_copy_and_csum_dev(skb, phys_to_virt(desc->buf_addr));
63 dev_kfree_skb(skb);
64
65 ixp2000_reg_write(RING_TX_PENDING,
66 TX_BUF_DESC_BASE + (entry * sizeof(struct ixpdev_tx_desc)));
67
68 local_irq_save(flags);
69 ip->tx_queue_entries++;
70 if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN)
71 netif_stop_queue(dev);
72 local_irq_restore(flags);
73
74 return NETDEV_TX_OK;
75}
76
77
78static int ixpdev_rx(struct net_device *dev, int processed, int budget)
79{
80 while (processed < budget) {
81 struct ixpdev_rx_desc *desc;
82 struct sk_buff *skb;
83 void *buf;
84 u32 _desc;
85
86 _desc = ixp2000_reg_read(RING_RX_DONE);
87 if (_desc == 0)
88 return 0;
89
90 desc = rx_desc +
91 ((_desc - RX_BUF_DESC_BASE) / sizeof(struct ixpdev_rx_desc));
92 buf = phys_to_virt(desc->buf_addr);
93
94 if (desc->pkt_length < 4 || desc->pkt_length > PAGE_SIZE) {
95 printk(KERN_ERR "ixp2000: rx err, length %d\n",
96 desc->pkt_length);
97 goto err;
98 }
99
100 if (desc->channel < 0 || desc->channel >= nds_count) {
101 printk(KERN_ERR "ixp2000: rx err, channel %d\n",
102 desc->channel);
103 goto err;
104 }
105
106 /* @@@ Make FCS stripping configurable. */
107 desc->pkt_length -= 4;
108
109 if (unlikely(!netif_running(nds[desc->channel])))
110 goto err;
111
112 skb = netdev_alloc_skb_ip_align(dev, desc->pkt_length);
113 if (likely(skb != NULL)) {
114 skb_copy_to_linear_data(skb, buf, desc->pkt_length);
115 skb_put(skb, desc->pkt_length);
116 skb->protocol = eth_type_trans(skb, nds[desc->channel]);
117
118 netif_receive_skb(skb);
119 }
120
121err:
122 ixp2000_reg_write(RING_RX_PENDING, _desc);
123 processed++;
124 }
125
126 return processed;
127}
128
129/* dev always points to nds[0]. */
130static int ixpdev_poll(struct napi_struct *napi, int budget)
131{
132 struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi);
133 struct net_device *dev = ip->dev;
134 int rx;
135
136 rx = 0;
137 do {
138 ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff);
139
140 rx = ixpdev_rx(dev, rx, budget);
141 if (rx >= budget)
142 break;
143 } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff);
144
145 napi_complete(napi);
146 ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff);
147
148 return rx;
149}
150
151static void ixpdev_tx_complete(void)
152{
153 int channel;
154 u32 wake;
155
156 wake = 0;
157 while (1) {
158 struct ixpdev_priv *ip;
159 u32 desc;
160 int entry;
161
162 desc = ixp2000_reg_read(RING_TX_DONE);
163 if (desc == 0)
164 break;
165
166 /* @@@ Check whether entries come back in order. */
167 entry = (desc - TX_BUF_DESC_BASE) / sizeof(struct ixpdev_tx_desc);
168 channel = tx_desc[entry].channel;
169
170 if (channel < 0 || channel >= nds_count) {
171 printk(KERN_ERR "ixp2000: txcomp channel index "
172 "out of bounds (%d, %.8i, %d)\n",
173 channel, (unsigned int)desc, entry);
174 continue;
175 }
176
177 ip = netdev_priv(nds[channel]);
178 if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN)
179 wake |= 1 << channel;
180 ip->tx_queue_entries--;
181 }
182
183 for (channel = 0; wake != 0; channel++) {
184 if (wake & (1 << channel)) {
185 netif_wake_queue(nds[channel]);
186 wake &= ~(1 << channel);
187 }
188 }
189}
190
191static irqreturn_t ixpdev_interrupt(int irq, void *dev_id)
192{
193 u32 status;
194
195 status = ixp2000_reg_read(IXP2000_IRQ_THD_STATUS_A_0);
196 if (status == 0)
197 return IRQ_NONE;
198
199 /*
200 * Any of the eight receive units signaled RX?
201 */
202 if (status & 0x00ff) {
203 struct net_device *dev = nds[0];
204 struct ixpdev_priv *ip = netdev_priv(dev);
205
206 ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
207 if (likely(napi_schedule_prep(&ip->napi))) {
208 __napi_schedule(&ip->napi);
209 } else {
210 printk(KERN_CRIT "ixp2000: irq while polling!!\n");
211 }
212 }
213
214 /*
215 * Any of the eight transmit units signaled TXdone?
216 */
217 if (status & 0xff00) {
218 ixp2000_reg_wrb(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0xff00);
219 ixpdev_tx_complete();
220 }
221
222 return IRQ_HANDLED;
223}
224
225#ifdef CONFIG_NET_POLL_CONTROLLER
226static void ixpdev_poll_controller(struct net_device *dev)
227{
228 disable_irq(IRQ_IXP2000_THDA0);
229 ixpdev_interrupt(IRQ_IXP2000_THDA0, dev);
230 enable_irq(IRQ_IXP2000_THDA0);
231}
232#endif
233
234static int ixpdev_open(struct net_device *dev)
235{
236 struct ixpdev_priv *ip = netdev_priv(dev);
237 int err;
238
239 napi_enable(&ip->napi);
240 if (!nds_open++) {
241 err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt,
242 IRQF_SHARED, "ixp2000_eth", nds);
243 if (err) {
244 nds_open--;
245 napi_disable(&ip->napi);
246 return err;
247 }
248
249 ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0xffff);
250 }
251
252 set_port_admin_status(ip->channel, 1);
253 netif_start_queue(dev);
254
255 return 0;
256}
257
258static int ixpdev_close(struct net_device *dev)
259{
260 struct ixpdev_priv *ip = netdev_priv(dev);
261
262 netif_stop_queue(dev);
263 napi_disable(&ip->napi);
264 set_port_admin_status(ip->channel, 0);
265
266 if (!--nds_open) {
267 ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0xffff);
268 free_irq(IRQ_IXP2000_THDA0, nds);
269 }
270
271 return 0;
272}
273
274static struct net_device_stats *ixpdev_get_stats(struct net_device *dev)
275{
276 struct ixpdev_priv *ip = netdev_priv(dev);
277
278 pm3386_get_stats(ip->channel, &(dev->stats));
279
280 return &(dev->stats);
281}
282
283static const struct net_device_ops ixpdev_netdev_ops = {
284 .ndo_open = ixpdev_open,
285 .ndo_stop = ixpdev_close,
286 .ndo_start_xmit = ixpdev_xmit,
287 .ndo_change_mtu = eth_change_mtu,
288 .ndo_validate_addr = eth_validate_addr,
289 .ndo_set_mac_address = eth_mac_addr,
290 .ndo_get_stats = ixpdev_get_stats,
291#ifdef CONFIG_NET_POLL_CONTROLLER
292 .ndo_poll_controller = ixpdev_poll_controller,
293#endif
294};
295
296struct net_device *ixpdev_alloc(int channel, int sizeof_priv)
297{
298 struct net_device *dev;
299 struct ixpdev_priv *ip;
300
301 dev = alloc_etherdev(sizeof_priv);
302 if (dev == NULL)
303 return NULL;
304
305 dev->netdev_ops = &ixpdev_netdev_ops;
306
307 dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
308
309 ip = netdev_priv(dev);
310 ip->dev = dev;
311 netif_napi_add(dev, &ip->napi, ixpdev_poll, 64);
312 ip->channel = channel;
313 ip->tx_queue_entries = 0;
314
315 return dev;
316}
317
318int ixpdev_init(int __nds_count, struct net_device **__nds,
319 void (*__set_port_admin_status)(int port, int up))
320{
321 int i;
322 int err;
323
324 BUILD_BUG_ON(RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192);
325
326 printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION);
327
328 nds_count = __nds_count;
329 nds = __nds;
330 set_port_admin_status = __set_port_admin_status;
331
332 for (i = 0; i < RX_BUF_COUNT; i++) {
333 void *buf;
334
335 buf = (void *)get_zeroed_page(GFP_KERNEL);
336 if (buf == NULL) {
337 err = -ENOMEM;
338 while (--i >= 0)
339 free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
340 goto err_out;
341 }
342 rx_desc[i].buf_addr = virt_to_phys(buf);
343 rx_desc[i].buf_length = PAGE_SIZE;
344 }
345
346 /* @@@ Maybe we shouldn't be preallocating TX buffers. */
347 for (i = 0; i < TX_BUF_COUNT; i++) {
348 void *buf;
349
350 buf = (void *)get_zeroed_page(GFP_KERNEL);
351 if (buf == NULL) {
352 err = -ENOMEM;
353 while (--i >= 0)
354 free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
355 goto err_free_rx;
356 }
357 tx_desc[i].buf_addr = virt_to_phys(buf);
358 }
359
360 /* 256 entries, ring status set means 'empty', base address 0x0000. */
361 ixp2000_reg_write(RING_RX_PENDING_BASE, 0x44000000);
362 ixp2000_reg_write(RING_RX_PENDING_HEAD, 0x00000000);
363 ixp2000_reg_write(RING_RX_PENDING_TAIL, 0x00000000);
364
365 /* 256 entries, ring status set means 'full', base address 0x0400. */
366 ixp2000_reg_write(RING_RX_DONE_BASE, 0x40000400);
367 ixp2000_reg_write(RING_RX_DONE_HEAD, 0x00000000);
368 ixp2000_reg_write(RING_RX_DONE_TAIL, 0x00000000);
369
370 for (i = 0; i < RX_BUF_COUNT; i++) {
371 ixp2000_reg_write(RING_RX_PENDING,
372 RX_BUF_DESC_BASE + (i * sizeof(struct ixpdev_rx_desc)));
373 }
374
375 ixp2000_uengine_load(0, &ixp2400_rx);
376 ixp2000_uengine_start_contexts(0, 0xff);
377
378 /* 256 entries, ring status set means 'empty', base address 0x0800. */
379 ixp2000_reg_write(RING_TX_PENDING_BASE, 0x44000800);
380 ixp2000_reg_write(RING_TX_PENDING_HEAD, 0x00000000);
381 ixp2000_reg_write(RING_TX_PENDING_TAIL, 0x00000000);
382
383 /* 256 entries, ring status set means 'full', base address 0x0c00. */
384 ixp2000_reg_write(RING_TX_DONE_BASE, 0x40000c00);
385 ixp2000_reg_write(RING_TX_DONE_HEAD, 0x00000000);
386 ixp2000_reg_write(RING_TX_DONE_TAIL, 0x00000000);
387
388 ixp2000_uengine_load(1, &ixp2400_tx);
389 ixp2000_uengine_start_contexts(1, 0xff);
390
391 for (i = 0; i < nds_count; i++) {
392 err = register_netdev(nds[i]);
393 if (err) {
394 while (--i >= 0)
395 unregister_netdev(nds[i]);
396 goto err_free_tx;
397 }
398 }
399
400 for (i = 0; i < nds_count; i++) {
401 printk(KERN_INFO "%s: IXP2000 MSF ethernet (port %d), "
402 "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", nds[i]->name, i,
403 nds[i]->dev_addr[0], nds[i]->dev_addr[1],
404 nds[i]->dev_addr[2], nds[i]->dev_addr[3],
405 nds[i]->dev_addr[4], nds[i]->dev_addr[5]);
406 }
407
408 return 0;
409
410err_free_tx:
411 for (i = 0; i < TX_BUF_COUNT; i++)
412 free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
413
414err_free_rx:
415 for (i = 0; i < RX_BUF_COUNT; i++)
416 free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
417
418err_out:
419 return err;
420}
421
422void ixpdev_deinit(void)
423{
424 int i;
425
426 /* @@@ Flush out pending packets. */
427
428 for (i = 0; i < nds_count; i++)
429 unregister_netdev(nds[i]);
430
431 ixp2000_uengine_stop_contexts(1, 0xff);
432 ixp2000_uengine_stop_contexts(0, 0xff);
433 ixp2000_uengine_reset(0x3);
434
435 for (i = 0; i < TX_BUF_COUNT; i++)
436 free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
437
438 for (i = 0; i < RX_BUF_COUNT; i++)
439 free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
440}
diff --git a/drivers/net/ethernet/xscale/ixp2000/ixpdev.h b/drivers/net/ethernet/xscale/ixp2000/ixpdev.h
new file mode 100644
index 000000000000..391ece623243
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/ixpdev.h
@@ -0,0 +1,29 @@
1/*
2 * IXP2000 MSF network device driver
3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#ifndef __IXPDEV_H
13#define __IXPDEV_H
14
15struct ixpdev_priv
16{
17 struct net_device *dev;
18 struct napi_struct napi;
19 int channel;
20 int tx_queue_entries;
21};
22
23struct net_device *ixpdev_alloc(int channel, int sizeof_priv);
24int ixpdev_init(int num_ports, struct net_device **nds,
25 void (*set_port_admin_status)(int port, int up));
26void ixpdev_deinit(void);
27
28
29#endif
diff --git a/drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h b/drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h
new file mode 100644
index 000000000000..86aa08ea0c33
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h
@@ -0,0 +1,57 @@
1/*
2 * IXP2000 MSF network device driver
3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#ifndef __IXPDEV_PRIV_H
13#define __IXPDEV_PRIV_H
14
15#define RX_BUF_DESC_BASE 0x00001000
16#define RX_BUF_COUNT ((3 * PAGE_SIZE) / (4 * sizeof(struct ixpdev_rx_desc)))
17#define TX_BUF_DESC_BASE 0x00002000
18#define TX_BUF_COUNT ((3 * PAGE_SIZE) / (4 * sizeof(struct ixpdev_tx_desc)))
19#define TX_BUF_COUNT_PER_CHAN (TX_BUF_COUNT / 4)
20
21#define RING_RX_PENDING ((u32 *)IXP2000_SCRATCH_RING_VIRT_BASE)
22#define RING_RX_DONE ((u32 *)(IXP2000_SCRATCH_RING_VIRT_BASE + 4))
23#define RING_TX_PENDING ((u32 *)(IXP2000_SCRATCH_RING_VIRT_BASE + 8))
24#define RING_TX_DONE ((u32 *)(IXP2000_SCRATCH_RING_VIRT_BASE + 12))
25
26#define SCRATCH_REG(x) ((u32 *)(IXP2000_GLOBAL_REG_VIRT_BASE | 0x0800 | (x)))
27#define RING_RX_PENDING_BASE SCRATCH_REG(0x00)
28#define RING_RX_PENDING_HEAD SCRATCH_REG(0x04)
29#define RING_RX_PENDING_TAIL SCRATCH_REG(0x08)
30#define RING_RX_DONE_BASE SCRATCH_REG(0x10)
31#define RING_RX_DONE_HEAD SCRATCH_REG(0x14)
32#define RING_RX_DONE_TAIL SCRATCH_REG(0x18)
33#define RING_TX_PENDING_BASE SCRATCH_REG(0x20)
34#define RING_TX_PENDING_HEAD SCRATCH_REG(0x24)
35#define RING_TX_PENDING_TAIL SCRATCH_REG(0x28)
36#define RING_TX_DONE_BASE SCRATCH_REG(0x30)
37#define RING_TX_DONE_HEAD SCRATCH_REG(0x34)
38#define RING_TX_DONE_TAIL SCRATCH_REG(0x38)
39
40struct ixpdev_rx_desc
41{
42 u32 buf_addr;
43 u32 buf_length;
44 u32 channel;
45 u32 pkt_length;
46};
47
48struct ixpdev_tx_desc
49{
50 u32 buf_addr;
51 u32 pkt_length;
52 u32 channel;
53 u32 unused;
54};
55
56
57#endif
diff --git a/drivers/net/ethernet/xscale/ixp2000/pm3386.c b/drivers/net/ethernet/xscale/ixp2000/pm3386.c
new file mode 100644
index 000000000000..e08d3f9863b8
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/pm3386.c
@@ -0,0 +1,351 @@
1/*
2 * Helper functions for the PM3386s on the Radisys ENP2611
3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/delay.h>
14#include <linux/netdevice.h>
15#include <asm/io.h>
16#include "pm3386.h"
17
18/*
19 * Read from register 'reg' of PM3386 device 'pm'.
20 */
21static u16 pm3386_reg_read(int pm, int reg)
22{
23 void *_reg;
24 u16 value;
25
26 _reg = (void *)ENP2611_PM3386_0_VIRT_BASE;
27 if (pm == 1)
28 _reg = (void *)ENP2611_PM3386_1_VIRT_BASE;
29
30 value = *((volatile u16 *)(_reg + (reg << 1)));
31
32// printk(KERN_INFO "pm3386_reg_read(%d, %.3x) = %.8x\n", pm, reg, value);
33
34 return value;
35}
36
37/*
38 * Write to register 'reg' of PM3386 device 'pm', and perform
39 * a readback from the identification register.
40 */
41static void pm3386_reg_write(int pm, int reg, u16 value)
42{
43 void *_reg;
44 u16 dummy;
45
46// printk(KERN_INFO "pm3386_reg_write(%d, %.3x, %.8x)\n", pm, reg, value);
47
48 _reg = (void *)ENP2611_PM3386_0_VIRT_BASE;
49 if (pm == 1)
50 _reg = (void *)ENP2611_PM3386_1_VIRT_BASE;
51
52 *((volatile u16 *)(_reg + (reg << 1))) = value;
53
54 dummy = *((volatile u16 *)_reg);
55 __asm__ __volatile__("mov %0, %0" : "+r" (dummy));
56}
57
58/*
59 * Read from port 'port' register 'reg', where the registers
60 * for the different ports are 'spacing' registers apart.
61 */
62static u16 pm3386_port_reg_read(int port, int _reg, int spacing)
63{
64 int reg;
65
66 reg = _reg;
67 if (port & 1)
68 reg += spacing;
69
70 return pm3386_reg_read(port >> 1, reg);
71}
72
73/*
74 * Write to port 'port' register 'reg', where the registers
75 * for the different ports are 'spacing' registers apart.
76 */
77static void pm3386_port_reg_write(int port, int _reg, int spacing, u16 value)
78{
79 int reg;
80
81 reg = _reg;
82 if (port & 1)
83 reg += spacing;
84
85 pm3386_reg_write(port >> 1, reg, value);
86}
87
88int pm3386_secondary_present(void)
89{
90 return pm3386_reg_read(1, 0) == 0x3386;
91}
92
93void pm3386_reset(void)
94{
95 u8 mac[3][6];
96 int secondary;
97
98 secondary = pm3386_secondary_present();
99
100 /* Save programmed MAC addresses. */
101 pm3386_get_mac(0, mac[0]);
102 pm3386_get_mac(1, mac[1]);
103 if (secondary)
104 pm3386_get_mac(2, mac[2]);
105
106 /* Assert analog and digital reset. */
107 pm3386_reg_write(0, 0x002, 0x0060);
108 if (secondary)
109 pm3386_reg_write(1, 0x002, 0x0060);
110 mdelay(1);
111
112 /* Deassert analog reset. */
113 pm3386_reg_write(0, 0x002, 0x0062);
114 if (secondary)
115 pm3386_reg_write(1, 0x002, 0x0062);
116 mdelay(10);
117
118 /* Deassert digital reset. */
119 pm3386_reg_write(0, 0x002, 0x0063);
120 if (secondary)
121 pm3386_reg_write(1, 0x002, 0x0063);
122 mdelay(10);
123
124 /* Restore programmed MAC addresses. */
125 pm3386_set_mac(0, mac[0]);
126 pm3386_set_mac(1, mac[1]);
127 if (secondary)
128 pm3386_set_mac(2, mac[2]);
129
130 /* Disable carrier on all ports. */
131 pm3386_set_carrier(0, 0);
132 pm3386_set_carrier(1, 0);
133 if (secondary)
134 pm3386_set_carrier(2, 0);
135}
136
137static u16 swaph(u16 x)
138{
139 return ((x << 8) | (x >> 8)) & 0xffff;
140}
141
142int pm3386_port_count(void)
143{
144 return 2 + pm3386_secondary_present();
145}
146
147void pm3386_init_port(int port)
148{
149 int pm = port >> 1;
150
151 /*
152 * Work around ENP2611 bootloader programming MAC address
153 * in reverse.
154 */
155 if (pm3386_port_reg_read(port, 0x30a, 0x100) == 0x0000 &&
156 (pm3386_port_reg_read(port, 0x309, 0x100) & 0xff00) == 0x5000) {
157 u16 temp[3];
158
159 temp[0] = pm3386_port_reg_read(port, 0x308, 0x100);
160 temp[1] = pm3386_port_reg_read(port, 0x309, 0x100);
161 temp[2] = pm3386_port_reg_read(port, 0x30a, 0x100);
162 pm3386_port_reg_write(port, 0x308, 0x100, swaph(temp[2]));
163 pm3386_port_reg_write(port, 0x309, 0x100, swaph(temp[1]));
164 pm3386_port_reg_write(port, 0x30a, 0x100, swaph(temp[0]));
165 }
166
167 /*
168 * Initialise narrowbanding mode. See application note 2010486
169 * for more information. (@@@ We also need to issue a reset
170 * when ROOL or DOOL are detected.)
171 */
172 pm3386_port_reg_write(port, 0x708, 0x10, 0xd055);
173 udelay(500);
174 pm3386_port_reg_write(port, 0x708, 0x10, 0x5055);
175
176 /*
177 * SPI-3 ingress block. Set 64 bytes SPI-3 burst size
178 * towards SPI-3 bridge.
179 */
180 pm3386_port_reg_write(port, 0x122, 0x20, 0x0002);
181
182 /*
183 * Enable ingress protocol checking, and soft reset the
184 * SPI-3 ingress block.
185 */
186 pm3386_reg_write(pm, 0x103, 0x0003);
187 while (!(pm3386_reg_read(pm, 0x103) & 0x80))
188 ;
189
190 /*
191 * SPI-3 egress block. Gather 12288 bytes of the current
192 * packet in the TX fifo before initiating transmit on the
193 * SERDES interface. (Prevents TX underflows.)
194 */
195 pm3386_port_reg_write(port, 0x221, 0x20, 0x0007);
196
197 /*
198 * Enforce odd parity from the SPI-3 bridge, and soft reset
199 * the SPI-3 egress block.
200 */
201 pm3386_reg_write(pm, 0x203, 0x000d & ~(4 << (port & 1)));
202 while ((pm3386_reg_read(pm, 0x203) & 0x000c) != 0x000c)
203 ;
204
205 /*
206 * EGMAC block. Set this channels to reject long preambles,
207 * not send or transmit PAUSE frames, enable preamble checking,
208 * disable frame length checking, enable FCS appending, enable
209 * TX frame padding.
210 */
211 pm3386_port_reg_write(port, 0x302, 0x100, 0x0113);
212
213 /*
214 * Soft reset the EGMAC block.
215 */
216 pm3386_port_reg_write(port, 0x301, 0x100, 0x8000);
217 pm3386_port_reg_write(port, 0x301, 0x100, 0x0000);
218
219 /*
220 * Auto-sense autonegotiation status.
221 */
222 pm3386_port_reg_write(port, 0x306, 0x100, 0x0100);
223
224 /*
225 * Allow reception of jumbo frames.
226 */
227 pm3386_port_reg_write(port, 0x310, 0x100, 9018);
228
229 /*
230 * Allow transmission of jumbo frames.
231 */
232 pm3386_port_reg_write(port, 0x336, 0x100, 9018);
233
234 /* @@@ Should set 0x337/0x437 (RX forwarding threshold.) */
235
236 /*
237 * Set autonegotiation parameters to 'no PAUSE, full duplex.'
238 */
239 pm3386_port_reg_write(port, 0x31c, 0x100, 0x0020);
240
241 /*
242 * Enable and restart autonegotiation.
243 */
244 pm3386_port_reg_write(port, 0x318, 0x100, 0x0003);
245 pm3386_port_reg_write(port, 0x318, 0x100, 0x0002);
246}
247
248void pm3386_get_mac(int port, u8 *mac)
249{
250 u16 temp;
251
252 temp = pm3386_port_reg_read(port, 0x308, 0x100);
253 mac[0] = temp & 0xff;
254 mac[1] = (temp >> 8) & 0xff;
255
256 temp = pm3386_port_reg_read(port, 0x309, 0x100);
257 mac[2] = temp & 0xff;
258 mac[3] = (temp >> 8) & 0xff;
259
260 temp = pm3386_port_reg_read(port, 0x30a, 0x100);
261 mac[4] = temp & 0xff;
262 mac[5] = (temp >> 8) & 0xff;
263}
264
265void pm3386_set_mac(int port, u8 *mac)
266{
267 pm3386_port_reg_write(port, 0x308, 0x100, (mac[1] << 8) | mac[0]);
268 pm3386_port_reg_write(port, 0x309, 0x100, (mac[3] << 8) | mac[2]);
269 pm3386_port_reg_write(port, 0x30a, 0x100, (mac[5] << 8) | mac[4]);
270}
271
272static u32 pm3386_get_stat(int port, u16 base)
273{
274 u32 value;
275
276 value = pm3386_port_reg_read(port, base, 0x100);
277 value |= pm3386_port_reg_read(port, base + 1, 0x100) << 16;
278
279 return value;
280}
281
282void pm3386_get_stats(int port, struct net_device_stats *stats)
283{
284 /*
285 * Snapshot statistics counters.
286 */
287 pm3386_port_reg_write(port, 0x500, 0x100, 0x0001);
288 while (pm3386_port_reg_read(port, 0x500, 0x100) & 0x0001)
289 ;
290
291 memset(stats, 0, sizeof(*stats));
292
293 stats->rx_packets = pm3386_get_stat(port, 0x510);
294 stats->tx_packets = pm3386_get_stat(port, 0x590);
295 stats->rx_bytes = pm3386_get_stat(port, 0x514);
296 stats->tx_bytes = pm3386_get_stat(port, 0x594);
297 /* @@@ Add other stats. */
298}
299
300void pm3386_set_carrier(int port, int state)
301{
302 pm3386_port_reg_write(port, 0x703, 0x10, state ? 0x1001 : 0x0000);
303}
304
305int pm3386_is_link_up(int port)
306{
307 u16 temp;
308
309 temp = pm3386_port_reg_read(port, 0x31a, 0x100);
310 temp = pm3386_port_reg_read(port, 0x31a, 0x100);
311
312 return !!(temp & 0x0002);
313}
314
315void pm3386_enable_rx(int port)
316{
317 u16 temp;
318
319 temp = pm3386_port_reg_read(port, 0x303, 0x100);
320 temp |= 0x1000;
321 pm3386_port_reg_write(port, 0x303, 0x100, temp);
322}
323
324void pm3386_disable_rx(int port)
325{
326 u16 temp;
327
328 temp = pm3386_port_reg_read(port, 0x303, 0x100);
329 temp &= 0xefff;
330 pm3386_port_reg_write(port, 0x303, 0x100, temp);
331}
332
333void pm3386_enable_tx(int port)
334{
335 u16 temp;
336
337 temp = pm3386_port_reg_read(port, 0x303, 0x100);
338 temp |= 0x4000;
339 pm3386_port_reg_write(port, 0x303, 0x100, temp);
340}
341
342void pm3386_disable_tx(int port)
343{
344 u16 temp;
345
346 temp = pm3386_port_reg_read(port, 0x303, 0x100);
347 temp &= 0xbfff;
348 pm3386_port_reg_write(port, 0x303, 0x100, temp);
349}
350
351MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/xscale/ixp2000/pm3386.h b/drivers/net/ethernet/xscale/ixp2000/pm3386.h
new file mode 100644
index 000000000000..cc4183dca911
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp2000/pm3386.h
@@ -0,0 +1,29 @@
1/*
2 * Helper functions for the PM3386s on the Radisys ENP2611
3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#ifndef __PM3386_H
13#define __PM3386_H
14
15void pm3386_reset(void);
16int pm3386_port_count(void);
17void pm3386_init_port(int port);
18void pm3386_get_mac(int port, u8 *mac);
19void pm3386_set_mac(int port, u8 *mac);
20void pm3386_get_stats(int port, struct net_device_stats *stats);
21void pm3386_set_carrier(int port, int state);
22int pm3386_is_link_up(int port);
23void pm3386_enable_rx(int port);
24void pm3386_disable_rx(int port);
25void pm3386_enable_tx(int port);
26void pm3386_disable_tx(int port);
27
28
29#endif
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
new file mode 100644
index 000000000000..de51e8453c13
--- /dev/null
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -0,0 +1,1489 @@
1/*
2 * Intel IXP4xx Ethernet driver for Linux
3 *
4 * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of version 2 of the GNU General Public License
8 * as published by the Free Software Foundation.
9 *
10 * Ethernet port config (0x00 is not present on IXP42X):
11 *
12 * logical port 0x00 0x10 0x20
13 * NPE 0 (NPE-A) 1 (NPE-B) 2 (NPE-C)
14 * physical PortId 2 0 1
15 * TX queue 23 24 25
16 * RX-free queue 26 27 28
17 * TX-done queue is always 31, per-port RX and TX-ready queues are configurable
18 *
19 *
20 * Queue entries:
21 * bits 0 -> 1 - NPE ID (RX and TX-done)
22 * bits 0 -> 2 - priority (TX, per 802.1D)
23 * bits 3 -> 4 - port ID (user-set?)
24 * bits 5 -> 31 - physical descriptor address
25 */
26
27#include <linux/delay.h>
28#include <linux/dma-mapping.h>
29#include <linux/dmapool.h>
30#include <linux/etherdevice.h>
31#include <linux/io.h>
32#include <linux/kernel.h>
33#include <linux/net_tstamp.h>
34#include <linux/phy.h>
35#include <linux/platform_device.h>
36#include <linux/ptp_classify.h>
37#include <linux/slab.h>
38#include <mach/ixp46x_ts.h>
39#include <mach/npe.h>
40#include <mach/qmgr.h>
41
42#define DEBUG_DESC 0
43#define DEBUG_RX 0
44#define DEBUG_TX 0
45#define DEBUG_PKT_BYTES 0
46#define DEBUG_MDIO 0
47#define DEBUG_CLOSE 0
48
49#define DRV_NAME "ixp4xx_eth"
50
51#define MAX_NPES 3
52
53#define RX_DESCS 64 /* also length of all RX queues */
54#define TX_DESCS 16 /* also length of all TX queues */
55#define TXDONE_QUEUE_LEN 64 /* dwords */
56
57#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS))
58#define REGS_SIZE 0x1000
59#define MAX_MRU 1536 /* 0x600 */
60#define RX_BUFF_SIZE ALIGN((NET_IP_ALIGN) + MAX_MRU, 4)
61
62#define NAPI_WEIGHT 16
63#define MDIO_INTERVAL (3 * HZ)
64#define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */
65#define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */
66
67#define NPE_ID(port_id) ((port_id) >> 4)
68#define PHYSICAL_ID(port_id) ((NPE_ID(port_id) + 2) % 3)
69#define TX_QUEUE(port_id) (NPE_ID(port_id) + 23)
70#define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26)
71#define TXDONE_QUEUE 31
72
73#define PTP_SLAVE_MODE 1
74#define PTP_MASTER_MODE 2
75#define PORT2CHANNEL(p) NPE_ID(p->id)
76
77/* TX Control Registers */
78#define TX_CNTRL0_TX_EN 0x01
79#define TX_CNTRL0_HALFDUPLEX 0x02
80#define TX_CNTRL0_RETRY 0x04
81#define TX_CNTRL0_PAD_EN 0x08
82#define TX_CNTRL0_APPEND_FCS 0x10
83#define TX_CNTRL0_2DEFER 0x20
84#define TX_CNTRL0_RMII 0x40 /* reduced MII */
85#define TX_CNTRL1_RETRIES 0x0F /* 4 bits */
86
87/* RX Control Registers */
88#define RX_CNTRL0_RX_EN 0x01
89#define RX_CNTRL0_PADSTRIP_EN 0x02
90#define RX_CNTRL0_SEND_FCS 0x04
91#define RX_CNTRL0_PAUSE_EN 0x08
92#define RX_CNTRL0_LOOP_EN 0x10
93#define RX_CNTRL0_ADDR_FLTR_EN 0x20
94#define RX_CNTRL0_RX_RUNT_EN 0x40
95#define RX_CNTRL0_BCAST_DIS 0x80
96#define RX_CNTRL1_DEFER_EN 0x01
97
98/* Core Control Register */
99#define CORE_RESET 0x01
100#define CORE_RX_FIFO_FLUSH 0x02
101#define CORE_TX_FIFO_FLUSH 0x04
102#define CORE_SEND_JAM 0x08
103#define CORE_MDC_EN 0x10 /* MDIO using NPE-B ETH-0 only */
104
105#define DEFAULT_TX_CNTRL0 (TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY | \
106 TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
107 TX_CNTRL0_2DEFER)
108#define DEFAULT_RX_CNTRL0 RX_CNTRL0_RX_EN
109#define DEFAULT_CORE_CNTRL CORE_MDC_EN
110
111
112/* NPE message codes */
113#define NPE_GETSTATUS 0x00
114#define NPE_EDB_SETPORTADDRESS 0x01
115#define NPE_EDB_GETMACADDRESSDATABASE 0x02
116#define NPE_EDB_SETMACADDRESSSDATABASE 0x03
117#define NPE_GETSTATS 0x04
118#define NPE_RESETSTATS 0x05
119#define NPE_SETMAXFRAMELENGTHS 0x06
120#define NPE_VLAN_SETRXTAGMODE 0x07
121#define NPE_VLAN_SETDEFAULTRXVID 0x08
122#define NPE_VLAN_SETPORTVLANTABLEENTRY 0x09
123#define NPE_VLAN_SETPORTVLANTABLERANGE 0x0A
124#define NPE_VLAN_SETRXQOSENTRY 0x0B
125#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
126#define NPE_STP_SETBLOCKINGSTATE 0x0D
127#define NPE_FW_SETFIREWALLMODE 0x0E
128#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
129#define NPE_PC_SETAPMACTABLE 0x11
130#define NPE_SETLOOPBACK_MODE 0x12
131#define NPE_PC_SETBSSIDTABLE 0x13
132#define NPE_ADDRESS_FILTER_CONFIG 0x14
133#define NPE_APPENDFCSCONFIG 0x15
134#define NPE_NOTIFY_MAC_RECOVERY_DONE 0x16
135#define NPE_MAC_RECOVERY_START 0x17
136
137
138#ifdef __ARMEB__
139typedef struct sk_buff buffer_t;
140#define free_buffer dev_kfree_skb
141#define free_buffer_irq dev_kfree_skb_irq
142#else
143typedef void buffer_t;
144#define free_buffer kfree
145#define free_buffer_irq kfree
146#endif
147
148struct eth_regs {
149 u32 tx_control[2], __res1[2]; /* 000 */
150 u32 rx_control[2], __res2[2]; /* 010 */
151 u32 random_seed, __res3[3]; /* 020 */
152 u32 partial_empty_threshold, __res4; /* 030 */
153 u32 partial_full_threshold, __res5; /* 038 */
154 u32 tx_start_bytes, __res6[3]; /* 040 */
155 u32 tx_deferral, rx_deferral, __res7[2];/* 050 */
156 u32 tx_2part_deferral[2], __res8[2]; /* 060 */
157 u32 slot_time, __res9[3]; /* 070 */
158 u32 mdio_command[4]; /* 080 */
159 u32 mdio_status[4]; /* 090 */
160 u32 mcast_mask[6], __res10[2]; /* 0A0 */
161 u32 mcast_addr[6], __res11[2]; /* 0C0 */
162 u32 int_clock_threshold, __res12[3]; /* 0E0 */
163 u32 hw_addr[6], __res13[61]; /* 0F0 */
164 u32 core_control; /* 1FC */
165};
166
167struct port {
168 struct resource *mem_res;
169 struct eth_regs __iomem *regs;
170 struct npe *npe;
171 struct net_device *netdev;
172 struct napi_struct napi;
173 struct phy_device *phydev;
174 struct eth_plat_info *plat;
175 buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];
176 struct desc *desc_tab; /* coherent */
177 u32 desc_tab_phys;
178 int id; /* logical port ID */
179 int speed, duplex;
180 u8 firmware[4];
181 int hwts_tx_en;
182 int hwts_rx_en;
183};
184
185/* NPE message structure */
186struct msg {
187#ifdef __ARMEB__
188 u8 cmd, eth_id, byte2, byte3;
189 u8 byte4, byte5, byte6, byte7;
190#else
191 u8 byte3, byte2, eth_id, cmd;
192 u8 byte7, byte6, byte5, byte4;
193#endif
194};
195
196/* Ethernet packet descriptor */
197struct desc {
198 u32 next; /* pointer to next buffer, unused */
199
200#ifdef __ARMEB__
201 u16 buf_len; /* buffer length */
202 u16 pkt_len; /* packet length */
203 u32 data; /* pointer to data buffer in RAM */
204 u8 dest_id;
205 u8 src_id;
206 u16 flags;
207 u8 qos;
208 u8 padlen;
209 u16 vlan_tci;
210#else
211 u16 pkt_len; /* packet length */
212 u16 buf_len; /* buffer length */
213 u32 data; /* pointer to data buffer in RAM */
214 u16 flags;
215 u8 src_id;
216 u8 dest_id;
217 u16 vlan_tci;
218 u8 padlen;
219 u8 qos;
220#endif
221
222#ifdef __ARMEB__
223 u8 dst_mac_0, dst_mac_1, dst_mac_2, dst_mac_3;
224 u8 dst_mac_4, dst_mac_5, src_mac_0, src_mac_1;
225 u8 src_mac_2, src_mac_3, src_mac_4, src_mac_5;
226#else
227 u8 dst_mac_3, dst_mac_2, dst_mac_1, dst_mac_0;
228 u8 src_mac_1, src_mac_0, dst_mac_5, dst_mac_4;
229 u8 src_mac_5, src_mac_4, src_mac_3, src_mac_2;
230#endif
231};
232
233
234#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \
235 (n) * sizeof(struct desc))
236#define rx_desc_ptr(port, n) (&(port)->desc_tab[n])
237
238#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \
239 ((n) + RX_DESCS) * sizeof(struct desc))
240#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS])
241
242#ifndef __ARMEB__
243static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
244{
245 int i;
246 for (i = 0; i < cnt; i++)
247 dest[i] = swab32(src[i]);
248}
249#endif
250
251static spinlock_t mdio_lock;
252static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */
253static struct mii_bus *mdio_bus;
254static int ports_open;
255static struct port *npe_port_tab[MAX_NPES];
256static struct dma_pool *dma_pool;
257
258static struct sock_filter ptp_filter[] = {
259 PTP_FILTER
260};
261
262static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
263{
264 u8 *data = skb->data;
265 unsigned int offset;
266 u16 *hi, *id;
267 u32 lo;
268
269 if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)
270 return 0;
271
272 offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
273
274 if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
275 return 0;
276
277 hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
278 id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
279
280 memcpy(&lo, &hi[1], sizeof(lo));
281
282 return (uid_hi == ntohs(*hi) &&
283 uid_lo == ntohl(lo) &&
284 seqid == ntohs(*id));
285}
286
287static void ixp_rx_timestamp(struct port *port, struct sk_buff *skb)
288{
289 struct skb_shared_hwtstamps *shhwtstamps;
290 struct ixp46x_ts_regs *regs;
291 u64 ns;
292 u32 ch, hi, lo, val;
293 u16 uid, seq;
294
295 if (!port->hwts_rx_en)
296 return;
297
298 ch = PORT2CHANNEL(port);
299
300 regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
301
302 val = __raw_readl(&regs->channel[ch].ch_event);
303
304 if (!(val & RX_SNAPSHOT_LOCKED))
305 return;
306
307 lo = __raw_readl(&regs->channel[ch].src_uuid_lo);
308 hi = __raw_readl(&regs->channel[ch].src_uuid_hi);
309
310 uid = hi & 0xffff;
311 seq = (hi >> 16) & 0xffff;
312
313 if (!ixp_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
314 goto out;
315
316 lo = __raw_readl(&regs->channel[ch].rx_snap_lo);
317 hi = __raw_readl(&regs->channel[ch].rx_snap_hi);
318 ns = ((u64) hi) << 32;
319 ns |= lo;
320 ns <<= TICKS_NS_SHIFT;
321
322 shhwtstamps = skb_hwtstamps(skb);
323 memset(shhwtstamps, 0, sizeof(*shhwtstamps));
324 shhwtstamps->hwtstamp = ns_to_ktime(ns);
325out:
326 __raw_writel(RX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
327}
328
329static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb)
330{
331 struct skb_shared_hwtstamps shhwtstamps;
332 struct ixp46x_ts_regs *regs;
333 struct skb_shared_info *shtx;
334 u64 ns;
335 u32 ch, cnt, hi, lo, val;
336
337 shtx = skb_shinfo(skb);
338 if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && port->hwts_tx_en))
339 shtx->tx_flags |= SKBTX_IN_PROGRESS;
340 else
341 return;
342
343 ch = PORT2CHANNEL(port);
344
345 regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
346
347 /*
348 * This really stinks, but we have to poll for the Tx time stamp.
349 * Usually, the time stamp is ready after 4 to 6 microseconds.
350 */
351 for (cnt = 0; cnt < 100; cnt++) {
352 val = __raw_readl(&regs->channel[ch].ch_event);
353 if (val & TX_SNAPSHOT_LOCKED)
354 break;
355 udelay(1);
356 }
357 if (!(val & TX_SNAPSHOT_LOCKED)) {
358 shtx->tx_flags &= ~SKBTX_IN_PROGRESS;
359 return;
360 }
361
362 lo = __raw_readl(&regs->channel[ch].tx_snap_lo);
363 hi = __raw_readl(&regs->channel[ch].tx_snap_hi);
364 ns = ((u64) hi) << 32;
365 ns |= lo;
366 ns <<= TICKS_NS_SHIFT;
367
368 memset(&shhwtstamps, 0, sizeof(shhwtstamps));
369 shhwtstamps.hwtstamp = ns_to_ktime(ns);
370 skb_tstamp_tx(skb, &shhwtstamps);
371
372 __raw_writel(TX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
373}
374
375static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
376{
377 struct hwtstamp_config cfg;
378 struct ixp46x_ts_regs *regs;
379 struct port *port = netdev_priv(netdev);
380 int ch;
381
382 if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
383 return -EFAULT;
384
385 if (cfg.flags) /* reserved for future extensions */
386 return -EINVAL;
387
388 ch = PORT2CHANNEL(port);
389 regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
390
391 switch (cfg.tx_type) {
392 case HWTSTAMP_TX_OFF:
393 port->hwts_tx_en = 0;
394 break;
395 case HWTSTAMP_TX_ON:
396 port->hwts_tx_en = 1;
397 break;
398 default:
399 return -ERANGE;
400 }
401
402 switch (cfg.rx_filter) {
403 case HWTSTAMP_FILTER_NONE:
404 port->hwts_rx_en = 0;
405 break;
406 case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
407 port->hwts_rx_en = PTP_SLAVE_MODE;
408 __raw_writel(0, &regs->channel[ch].ch_control);
409 break;
410 case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
411 port->hwts_rx_en = PTP_MASTER_MODE;
412 __raw_writel(MASTER_MODE, &regs->channel[ch].ch_control);
413 break;
414 default:
415 return -ERANGE;
416 }
417
418 /* Clear out any old time stamps. */
419 __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED,
420 &regs->channel[ch].ch_event);
421
422 return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
423}
424
425static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location,
426 int write, u16 cmd)
427{
428 int cycles = 0;
429
430 if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
431 printk(KERN_ERR "%s: MII not ready to transmit\n", bus->name);
432 return -1;
433 }
434
435 if (write) {
436 __raw_writel(cmd & 0xFF, &mdio_regs->mdio_command[0]);
437 __raw_writel(cmd >> 8, &mdio_regs->mdio_command[1]);
438 }
439 __raw_writel(((phy_id << 5) | location) & 0xFF,
440 &mdio_regs->mdio_command[2]);
441 __raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
442 &mdio_regs->mdio_command[3]);
443
444 while ((cycles < MAX_MDIO_RETRIES) &&
445 (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
446 udelay(1);
447 cycles++;
448 }
449
450 if (cycles == MAX_MDIO_RETRIES) {
451 printk(KERN_ERR "%s #%i: MII write failed\n", bus->name,
452 phy_id);
453 return -1;
454 }
455
456#if DEBUG_MDIO
457 printk(KERN_DEBUG "%s #%i: mdio_%s() took %i cycles\n", bus->name,
458 phy_id, write ? "write" : "read", cycles);
459#endif
460
461 if (write)
462 return 0;
463
464 if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
465#if DEBUG_MDIO
466 printk(KERN_DEBUG "%s #%i: MII read failed\n", bus->name,
467 phy_id);
468#endif
469 return 0xFFFF; /* don't return error */
470 }
471
472 return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
473 ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8);
474}
475
476static int ixp4xx_mdio_read(struct mii_bus *bus, int phy_id, int location)
477{
478 unsigned long flags;
479 int ret;
480
481 spin_lock_irqsave(&mdio_lock, flags);
482 ret = ixp4xx_mdio_cmd(bus, phy_id, location, 0, 0);
483 spin_unlock_irqrestore(&mdio_lock, flags);
484#if DEBUG_MDIO
485 printk(KERN_DEBUG "%s #%i: MII read [%i] -> 0x%X\n", bus->name,
486 phy_id, location, ret);
487#endif
488 return ret;
489}
490
491static int ixp4xx_mdio_write(struct mii_bus *bus, int phy_id, int location,
492 u16 val)
493{
494 unsigned long flags;
495 int ret;
496
497 spin_lock_irqsave(&mdio_lock, flags);
498 ret = ixp4xx_mdio_cmd(bus, phy_id, location, 1, val);
499 spin_unlock_irqrestore(&mdio_lock, flags);
500#if DEBUG_MDIO
501 printk(KERN_DEBUG "%s #%i: MII write [%i] <- 0x%X, err = %i\n",
502 bus->name, phy_id, location, val, ret);
503#endif
504 return ret;
505}
506
507static int ixp4xx_mdio_register(void)
508{
509 int err;
510
511 if (!(mdio_bus = mdiobus_alloc()))
512 return -ENOMEM;
513
514 if (cpu_is_ixp43x()) {
515 /* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */
516 if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEC_ETH))
517 return -ENODEV;
518 mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT;
519 } else {
520 /* All MII PHY accesses use NPE-B Ethernet registers */
521 if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
522 return -ENODEV;
523 mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
524 }
525
526 __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
527 spin_lock_init(&mdio_lock);
528 mdio_bus->name = "IXP4xx MII Bus";
529 mdio_bus->read = &ixp4xx_mdio_read;
530 mdio_bus->write = &ixp4xx_mdio_write;
531 strcpy(mdio_bus->id, "0");
532
533 if ((err = mdiobus_register(mdio_bus)))
534 mdiobus_free(mdio_bus);
535 return err;
536}
537
538static void ixp4xx_mdio_remove(void)
539{
540 mdiobus_unregister(mdio_bus);
541 mdiobus_free(mdio_bus);
542}
543
544
545static void ixp4xx_adjust_link(struct net_device *dev)
546{
547 struct port *port = netdev_priv(dev);
548 struct phy_device *phydev = port->phydev;
549
550 if (!phydev->link) {
551 if (port->speed) {
552 port->speed = 0;
553 printk(KERN_INFO "%s: link down\n", dev->name);
554 }
555 return;
556 }
557
558 if (port->speed == phydev->speed && port->duplex == phydev->duplex)
559 return;
560
561 port->speed = phydev->speed;
562 port->duplex = phydev->duplex;
563
564 if (port->duplex)
565 __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
566 &port->regs->tx_control[0]);
567 else
568 __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
569 &port->regs->tx_control[0]);
570
571 printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n",
572 dev->name, port->speed, port->duplex ? "full" : "half");
573}
574
575
576static inline void debug_pkt(struct net_device *dev, const char *func,
577 u8 *data, int len)
578{
579#if DEBUG_PKT_BYTES
580 int i;
581
582 printk(KERN_DEBUG "%s: %s(%i) ", dev->name, func, len);
583 for (i = 0; i < len; i++) {
584 if (i >= DEBUG_PKT_BYTES)
585 break;
586 printk("%s%02X",
587 ((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
588 data[i]);
589 }
590 printk("\n");
591#endif
592}
593
594
595static inline void debug_desc(u32 phys, struct desc *desc)
596{
597#if DEBUG_DESC
598 printk(KERN_DEBUG "%X: %X %3X %3X %08X %2X < %2X %4X %X"
599 " %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
600 phys, desc->next, desc->buf_len, desc->pkt_len,
601 desc->data, desc->dest_id, desc->src_id, desc->flags,
602 desc->qos, desc->padlen, desc->vlan_tci,
603 desc->dst_mac_0, desc->dst_mac_1, desc->dst_mac_2,
604 desc->dst_mac_3, desc->dst_mac_4, desc->dst_mac_5,
605 desc->src_mac_0, desc->src_mac_1, desc->src_mac_2,
606 desc->src_mac_3, desc->src_mac_4, desc->src_mac_5);
607#endif
608}
609
610static inline int queue_get_desc(unsigned int queue, struct port *port,
611 int is_tx)
612{
613 u32 phys, tab_phys, n_desc;
614 struct desc *tab;
615
616 if (!(phys = qmgr_get_entry(queue)))
617 return -1;
618
619 phys &= ~0x1F; /* mask out non-address bits */
620 tab_phys = is_tx ? tx_desc_phys(port, 0) : rx_desc_phys(port, 0);
621 tab = is_tx ? tx_desc_ptr(port, 0) : rx_desc_ptr(port, 0);
622 n_desc = (phys - tab_phys) / sizeof(struct desc);
623 BUG_ON(n_desc >= (is_tx ? TX_DESCS : RX_DESCS));
624 debug_desc(phys, &tab[n_desc]);
625 BUG_ON(tab[n_desc].next);
626 return n_desc;
627}
628
629static inline void queue_put_desc(unsigned int queue, u32 phys,
630 struct desc *desc)
631{
632 debug_desc(phys, desc);
633 BUG_ON(phys & 0x1F);
634 qmgr_put_entry(queue, phys);
635 /* Don't check for queue overflow here, we've allocated sufficient
636 length and queues >= 32 don't support this check anyway. */
637}
638
639
640static inline void dma_unmap_tx(struct port *port, struct desc *desc)
641{
642#ifdef __ARMEB__
643 dma_unmap_single(&port->netdev->dev, desc->data,
644 desc->buf_len, DMA_TO_DEVICE);
645#else
646 dma_unmap_single(&port->netdev->dev, desc->data & ~3,
647 ALIGN((desc->data & 3) + desc->buf_len, 4),
648 DMA_TO_DEVICE);
649#endif
650}
651
652
653static void eth_rx_irq(void *pdev)
654{
655 struct net_device *dev = pdev;
656 struct port *port = netdev_priv(dev);
657
658#if DEBUG_RX
659 printk(KERN_DEBUG "%s: eth_rx_irq\n", dev->name);
660#endif
661 qmgr_disable_irq(port->plat->rxq);
662 napi_schedule(&port->napi);
663}
664
665static int eth_poll(struct napi_struct *napi, int budget)
666{
667 struct port *port = container_of(napi, struct port, napi);
668 struct net_device *dev = port->netdev;
669 unsigned int rxq = port->plat->rxq, rxfreeq = RXFREE_QUEUE(port->id);
670 int received = 0;
671
672#if DEBUG_RX
673 printk(KERN_DEBUG "%s: eth_poll\n", dev->name);
674#endif
675
676 while (received < budget) {
677 struct sk_buff *skb;
678 struct desc *desc;
679 int n;
680#ifdef __ARMEB__
681 struct sk_buff *temp;
682 u32 phys;
683#endif
684
685 if ((n = queue_get_desc(rxq, port, 0)) < 0) {
686#if DEBUG_RX
687 printk(KERN_DEBUG "%s: eth_poll napi_complete\n",
688 dev->name);
689#endif
690 napi_complete(napi);
691 qmgr_enable_irq(rxq);
692 if (!qmgr_stat_below_low_watermark(rxq) &&
693 napi_reschedule(napi)) { /* not empty again */
694#if DEBUG_RX
695 printk(KERN_DEBUG "%s: eth_poll"
696 " napi_reschedule successed\n",
697 dev->name);
698#endif
699 qmgr_disable_irq(rxq);
700 continue;
701 }
702#if DEBUG_RX
703 printk(KERN_DEBUG "%s: eth_poll all done\n",
704 dev->name);
705#endif
706 return received; /* all work done */
707 }
708
709 desc = rx_desc_ptr(port, n);
710
711#ifdef __ARMEB__
712 if ((skb = netdev_alloc_skb(dev, RX_BUFF_SIZE))) {
713 phys = dma_map_single(&dev->dev, skb->data,
714 RX_BUFF_SIZE, DMA_FROM_DEVICE);
715 if (dma_mapping_error(&dev->dev, phys)) {
716 dev_kfree_skb(skb);
717 skb = NULL;
718 }
719 }
720#else
721 skb = netdev_alloc_skb(dev,
722 ALIGN(NET_IP_ALIGN + desc->pkt_len, 4));
723#endif
724
725 if (!skb) {
726 dev->stats.rx_dropped++;
727 /* put the desc back on RX-ready queue */
728 desc->buf_len = MAX_MRU;
729 desc->pkt_len = 0;
730 queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
731 continue;
732 }
733
734 /* process received frame */
735#ifdef __ARMEB__
736 temp = skb;
737 skb = port->rx_buff_tab[n];
738 dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN,
739 RX_BUFF_SIZE, DMA_FROM_DEVICE);
740#else
741 dma_sync_single_for_cpu(&dev->dev, desc->data - NET_IP_ALIGN,
742 RX_BUFF_SIZE, DMA_FROM_DEVICE);
743 memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n],
744 ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4);
745#endif
746 skb_reserve(skb, NET_IP_ALIGN);
747 skb_put(skb, desc->pkt_len);
748
749 debug_pkt(dev, "eth_poll", skb->data, skb->len);
750
751 ixp_rx_timestamp(port, skb);
752 skb->protocol = eth_type_trans(skb, dev);
753 dev->stats.rx_packets++;
754 dev->stats.rx_bytes += skb->len;
755 netif_receive_skb(skb);
756
757 /* put the new buffer on RX-free queue */
758#ifdef __ARMEB__
759 port->rx_buff_tab[n] = temp;
760 desc->data = phys + NET_IP_ALIGN;
761#endif
762 desc->buf_len = MAX_MRU;
763 desc->pkt_len = 0;
764 queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
765 received++;
766 }
767
768#if DEBUG_RX
769 printk(KERN_DEBUG "eth_poll(): end, not all work done\n");
770#endif
771 return received; /* not all work done */
772}
773
774
775static void eth_txdone_irq(void *unused)
776{
777 u32 phys;
778
779#if DEBUG_TX
780 printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n");
781#endif
782 while ((phys = qmgr_get_entry(TXDONE_QUEUE)) != 0) {
783 u32 npe_id, n_desc;
784 struct port *port;
785 struct desc *desc;
786 int start;
787
788 npe_id = phys & 3;
789 BUG_ON(npe_id >= MAX_NPES);
790 port = npe_port_tab[npe_id];
791 BUG_ON(!port);
792 phys &= ~0x1F; /* mask out non-address bits */
793 n_desc = (phys - tx_desc_phys(port, 0)) / sizeof(struct desc);
794 BUG_ON(n_desc >= TX_DESCS);
795 desc = tx_desc_ptr(port, n_desc);
796 debug_desc(phys, desc);
797
798 if (port->tx_buff_tab[n_desc]) { /* not the draining packet */
799 port->netdev->stats.tx_packets++;
800 port->netdev->stats.tx_bytes += desc->pkt_len;
801
802 dma_unmap_tx(port, desc);
803#if DEBUG_TX
804 printk(KERN_DEBUG "%s: eth_txdone_irq free %p\n",
805 port->netdev->name, port->tx_buff_tab[n_desc]);
806#endif
807 free_buffer_irq(port->tx_buff_tab[n_desc]);
808 port->tx_buff_tab[n_desc] = NULL;
809 }
810
811 start = qmgr_stat_below_low_watermark(port->plat->txreadyq);
812 queue_put_desc(port->plat->txreadyq, phys, desc);
813 if (start) { /* TX-ready queue was empty */
814#if DEBUG_TX
815 printk(KERN_DEBUG "%s: eth_txdone_irq xmit ready\n",
816 port->netdev->name);
817#endif
818 netif_wake_queue(port->netdev);
819 }
820 }
821}
822
823static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
824{
825 struct port *port = netdev_priv(dev);
826 unsigned int txreadyq = port->plat->txreadyq;
827 int len, offset, bytes, n;
828 void *mem;
829 u32 phys;
830 struct desc *desc;
831
832#if DEBUG_TX
833 printk(KERN_DEBUG "%s: eth_xmit\n", dev->name);
834#endif
835
836 if (unlikely(skb->len > MAX_MRU)) {
837 dev_kfree_skb(skb);
838 dev->stats.tx_errors++;
839 return NETDEV_TX_OK;
840 }
841
842 debug_pkt(dev, "eth_xmit", skb->data, skb->len);
843
844 len = skb->len;
845#ifdef __ARMEB__
846 offset = 0; /* no need to keep alignment */
847 bytes = len;
848 mem = skb->data;
849#else
850 offset = (int)skb->data & 3; /* keep 32-bit alignment */
851 bytes = ALIGN(offset + len, 4);
852 if (!(mem = kmalloc(bytes, GFP_ATOMIC))) {
853 dev_kfree_skb(skb);
854 dev->stats.tx_dropped++;
855 return NETDEV_TX_OK;
856 }
857 memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
858#endif
859
860 phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
861 if (dma_mapping_error(&dev->dev, phys)) {
862 dev_kfree_skb(skb);
863#ifndef __ARMEB__
864 kfree(mem);
865#endif
866 dev->stats.tx_dropped++;
867 return NETDEV_TX_OK;
868 }
869
870 n = queue_get_desc(txreadyq, port, 1);
871 BUG_ON(n < 0);
872 desc = tx_desc_ptr(port, n);
873
874#ifdef __ARMEB__
875 port->tx_buff_tab[n] = skb;
876#else
877 port->tx_buff_tab[n] = mem;
878#endif
879 desc->data = phys + offset;
880 desc->buf_len = desc->pkt_len = len;
881
882 /* NPE firmware pads short frames with zeros internally */
883 wmb();
884 queue_put_desc(TX_QUEUE(port->id), tx_desc_phys(port, n), desc);
885
886 if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */
887#if DEBUG_TX
888 printk(KERN_DEBUG "%s: eth_xmit queue full\n", dev->name);
889#endif
890 netif_stop_queue(dev);
891 /* we could miss TX ready interrupt */
892 /* really empty in fact */
893 if (!qmgr_stat_below_low_watermark(txreadyq)) {
894#if DEBUG_TX
895 printk(KERN_DEBUG "%s: eth_xmit ready again\n",
896 dev->name);
897#endif
898 netif_wake_queue(dev);
899 }
900 }
901
902#if DEBUG_TX
903 printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name);
904#endif
905
906 ixp_tx_timestamp(port, skb);
907 skb_tx_timestamp(skb);
908
909#ifndef __ARMEB__
910 dev_kfree_skb(skb);
911#endif
912 return NETDEV_TX_OK;
913}
914
915
916static void eth_set_mcast_list(struct net_device *dev)
917{
918 struct port *port = netdev_priv(dev);
919 struct netdev_hw_addr *ha;
920 u8 diffs[ETH_ALEN], *addr;
921 int i;
922 static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
923
924 if (dev->flags & IFF_ALLMULTI) {
925 for (i = 0; i < ETH_ALEN; i++) {
926 __raw_writel(allmulti[i], &port->regs->mcast_addr[i]);
927 __raw_writel(allmulti[i], &port->regs->mcast_mask[i]);
928 }
929 __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN,
930 &port->regs->rx_control[0]);
931 return;
932 }
933
934 if ((dev->flags & IFF_PROMISC) || netdev_mc_empty(dev)) {
935 __raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN,
936 &port->regs->rx_control[0]);
937 return;
938 }
939
940 memset(diffs, 0, ETH_ALEN);
941
942 addr = NULL;
943 netdev_for_each_mc_addr(ha, dev) {
944 if (!addr)
945 addr = ha->addr; /* first MAC address */
946 for (i = 0; i < ETH_ALEN; i++)
947 diffs[i] |= addr[i] ^ ha->addr[i];
948 }
949
950 for (i = 0; i < ETH_ALEN; i++) {
951 __raw_writel(addr[i], &port->regs->mcast_addr[i]);
952 __raw_writel(~diffs[i], &port->regs->mcast_mask[i]);
953 }
954
955 __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN,
956 &port->regs->rx_control[0]);
957}
958
959
960static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
961{
962 struct port *port = netdev_priv(dev);
963
964 if (!netif_running(dev))
965 return -EINVAL;
966
967 if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP)
968 return hwtstamp_ioctl(dev, req, cmd);
969
970 return phy_mii_ioctl(port->phydev, req, cmd);
971}
972
973/* ethtool support */
974
975static void ixp4xx_get_drvinfo(struct net_device *dev,
976 struct ethtool_drvinfo *info)
977{
978 struct port *port = netdev_priv(dev);
979 strcpy(info->driver, DRV_NAME);
980 snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u",
981 port->firmware[0], port->firmware[1],
982 port->firmware[2], port->firmware[3]);
983 strcpy(info->bus_info, "internal");
984}
985
986static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
987{
988 struct port *port = netdev_priv(dev);
989 return phy_ethtool_gset(port->phydev, cmd);
990}
991
992static int ixp4xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
993{
994 struct port *port = netdev_priv(dev);
995 return phy_ethtool_sset(port->phydev, cmd);
996}
997
998static int ixp4xx_nway_reset(struct net_device *dev)
999{
1000 struct port *port = netdev_priv(dev);
1001 return phy_start_aneg(port->phydev);
1002}
1003
1004static const struct ethtool_ops ixp4xx_ethtool_ops = {
1005 .get_drvinfo = ixp4xx_get_drvinfo,
1006 .get_settings = ixp4xx_get_settings,
1007 .set_settings = ixp4xx_set_settings,
1008 .nway_reset = ixp4xx_nway_reset,
1009 .get_link = ethtool_op_get_link,
1010};
1011
1012
1013static int request_queues(struct port *port)
1014{
1015 int err;
1016
1017 err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0,
1018 "%s:RX-free", port->netdev->name);
1019 if (err)
1020 return err;
1021
1022 err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0,
1023 "%s:RX", port->netdev->name);
1024 if (err)
1025 goto rel_rxfree;
1026
1027 err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0,
1028 "%s:TX", port->netdev->name);
1029 if (err)
1030 goto rel_rx;
1031
1032 err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0,
1033 "%s:TX-ready", port->netdev->name);
1034 if (err)
1035 goto rel_tx;
1036
1037 /* TX-done queue handles skbs sent out by the NPEs */
1038 if (!ports_open) {
1039 err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
1040 "%s:TX-done", DRV_NAME);
1041 if (err)
1042 goto rel_txready;
1043 }
1044 return 0;
1045
1046rel_txready:
1047 qmgr_release_queue(port->plat->txreadyq);
1048rel_tx:
1049 qmgr_release_queue(TX_QUEUE(port->id));
1050rel_rx:
1051 qmgr_release_queue(port->plat->rxq);
1052rel_rxfree:
1053 qmgr_release_queue(RXFREE_QUEUE(port->id));
1054 printk(KERN_DEBUG "%s: unable to request hardware queues\n",
1055 port->netdev->name);
1056 return err;
1057}
1058
1059static void release_queues(struct port *port)
1060{
1061 qmgr_release_queue(RXFREE_QUEUE(port->id));
1062 qmgr_release_queue(port->plat->rxq);
1063 qmgr_release_queue(TX_QUEUE(port->id));
1064 qmgr_release_queue(port->plat->txreadyq);
1065
1066 if (!ports_open)
1067 qmgr_release_queue(TXDONE_QUEUE);
1068}
1069
1070static int init_queues(struct port *port)
1071{
1072 int i;
1073
1074 if (!ports_open)
1075 if (!(dma_pool = dma_pool_create(DRV_NAME, NULL,
1076 POOL_ALLOC_SIZE, 32, 0)))
1077 return -ENOMEM;
1078
1079 if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL,
1080 &port->desc_tab_phys)))
1081 return -ENOMEM;
1082 memset(port->desc_tab, 0, POOL_ALLOC_SIZE);
1083 memset(port->rx_buff_tab, 0, sizeof(port->rx_buff_tab)); /* tables */
1084 memset(port->tx_buff_tab, 0, sizeof(port->tx_buff_tab));
1085
1086 /* Setup RX buffers */
1087 for (i = 0; i < RX_DESCS; i++) {
1088 struct desc *desc = rx_desc_ptr(port, i);
1089 buffer_t *buff; /* skb or kmalloc()ated memory */
1090 void *data;
1091#ifdef __ARMEB__
1092 if (!(buff = netdev_alloc_skb(port->netdev, RX_BUFF_SIZE)))
1093 return -ENOMEM;
1094 data = buff->data;
1095#else
1096 if (!(buff = kmalloc(RX_BUFF_SIZE, GFP_KERNEL)))
1097 return -ENOMEM;
1098 data = buff;
1099#endif
1100 desc->buf_len = MAX_MRU;
1101 desc->data = dma_map_single(&port->netdev->dev, data,
1102 RX_BUFF_SIZE, DMA_FROM_DEVICE);
1103 if (dma_mapping_error(&port->netdev->dev, desc->data)) {
1104 free_buffer(buff);
1105 return -EIO;
1106 }
1107 desc->data += NET_IP_ALIGN;
1108 port->rx_buff_tab[i] = buff;
1109 }
1110
1111 return 0;
1112}
1113
1114static void destroy_queues(struct port *port)
1115{
1116 int i;
1117
1118 if (port->desc_tab) {
1119 for (i = 0; i < RX_DESCS; i++) {
1120 struct desc *desc = rx_desc_ptr(port, i);
1121 buffer_t *buff = port->rx_buff_tab[i];
1122 if (buff) {
1123 dma_unmap_single(&port->netdev->dev,
1124 desc->data - NET_IP_ALIGN,
1125 RX_BUFF_SIZE, DMA_FROM_DEVICE);
1126 free_buffer(buff);
1127 }
1128 }
1129 for (i = 0; i < TX_DESCS; i++) {
1130 struct desc *desc = tx_desc_ptr(port, i);
1131 buffer_t *buff = port->tx_buff_tab[i];
1132 if (buff) {
1133 dma_unmap_tx(port, desc);
1134 free_buffer(buff);
1135 }
1136 }
1137 dma_pool_free(dma_pool, port->desc_tab, port->desc_tab_phys);
1138 port->desc_tab = NULL;
1139 }
1140
1141 if (!ports_open && dma_pool) {
1142 dma_pool_destroy(dma_pool);
1143 dma_pool = NULL;
1144 }
1145}
1146
1147static int eth_open(struct net_device *dev)
1148{
1149 struct port *port = netdev_priv(dev);
1150 struct npe *npe = port->npe;
1151 struct msg msg;
1152 int i, err;
1153
1154 if (!npe_running(npe)) {
1155 err = npe_load_firmware(npe, npe_name(npe), &dev->dev);
1156 if (err)
1157 return err;
1158
1159 if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
1160 printk(KERN_ERR "%s: %s not responding\n", dev->name,
1161 npe_name(npe));
1162 return -EIO;
1163 }
1164 port->firmware[0] = msg.byte4;
1165 port->firmware[1] = msg.byte5;
1166 port->firmware[2] = msg.byte6;
1167 port->firmware[3] = msg.byte7;
1168 }
1169
1170 memset(&msg, 0, sizeof(msg));
1171 msg.cmd = NPE_VLAN_SETRXQOSENTRY;
1172 msg.eth_id = port->id;
1173 msg.byte5 = port->plat->rxq | 0x80;
1174 msg.byte7 = port->plat->rxq << 4;
1175 for (i = 0; i < 8; i++) {
1176 msg.byte3 = i;
1177 if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ"))
1178 return -EIO;
1179 }
1180
1181 msg.cmd = NPE_EDB_SETPORTADDRESS;
1182 msg.eth_id = PHYSICAL_ID(port->id);
1183 msg.byte2 = dev->dev_addr[0];
1184 msg.byte3 = dev->dev_addr[1];
1185 msg.byte4 = dev->dev_addr[2];
1186 msg.byte5 = dev->dev_addr[3];
1187 msg.byte6 = dev->dev_addr[4];
1188 msg.byte7 = dev->dev_addr[5];
1189 if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC"))
1190 return -EIO;
1191
1192 memset(&msg, 0, sizeof(msg));
1193 msg.cmd = NPE_FW_SETFIREWALLMODE;
1194 msg.eth_id = port->id;
1195 if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE"))
1196 return -EIO;
1197
1198 if ((err = request_queues(port)) != 0)
1199 return err;
1200
1201 if ((err = init_queues(port)) != 0) {
1202 destroy_queues(port);
1203 release_queues(port);
1204 return err;
1205 }
1206
1207 port->speed = 0; /* force "link up" message */
1208 phy_start(port->phydev);
1209
1210 for (i = 0; i < ETH_ALEN; i++)
1211 __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]);
1212 __raw_writel(0x08, &port->regs->random_seed);
1213 __raw_writel(0x12, &port->regs->partial_empty_threshold);
1214 __raw_writel(0x30, &port->regs->partial_full_threshold);
1215 __raw_writel(0x08, &port->regs->tx_start_bytes);
1216 __raw_writel(0x15, &port->regs->tx_deferral);
1217 __raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
1218 __raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
1219 __raw_writel(0x80, &port->regs->slot_time);
1220 __raw_writel(0x01, &port->regs->int_clock_threshold);
1221
1222 /* Populate queues with buffers, no failure after this point */
1223 for (i = 0; i < TX_DESCS; i++)
1224 queue_put_desc(port->plat->txreadyq,
1225 tx_desc_phys(port, i), tx_desc_ptr(port, i));
1226
1227 for (i = 0; i < RX_DESCS; i++)
1228 queue_put_desc(RXFREE_QUEUE(port->id),
1229 rx_desc_phys(port, i), rx_desc_ptr(port, i));
1230
1231 __raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
1232 __raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
1233 __raw_writel(0, &port->regs->rx_control[1]);
1234 __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
1235
1236 napi_enable(&port->napi);
1237 eth_set_mcast_list(dev);
1238 netif_start_queue(dev);
1239
1240 qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY,
1241 eth_rx_irq, dev);
1242 if (!ports_open) {
1243 qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
1244 eth_txdone_irq, NULL);
1245 qmgr_enable_irq(TXDONE_QUEUE);
1246 }
1247 ports_open++;
1248 /* we may already have RX data, enables IRQ */
1249 napi_schedule(&port->napi);
1250 return 0;
1251}
1252
1253static int eth_close(struct net_device *dev)
1254{
1255 struct port *port = netdev_priv(dev);
1256 struct msg msg;
1257 int buffs = RX_DESCS; /* allocated RX buffers */
1258 int i;
1259
1260 ports_open--;
1261 qmgr_disable_irq(port->plat->rxq);
1262 napi_disable(&port->napi);
1263 netif_stop_queue(dev);
1264
1265 while (queue_get_desc(RXFREE_QUEUE(port->id), port, 0) >= 0)
1266 buffs--;
1267
1268 memset(&msg, 0, sizeof(msg));
1269 msg.cmd = NPE_SETLOOPBACK_MODE;
1270 msg.eth_id = port->id;
1271 msg.byte3 = 1;
1272 if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
1273 printk(KERN_CRIT "%s: unable to enable loopback\n", dev->name);
1274
1275 i = 0;
1276 do { /* drain RX buffers */
1277 while (queue_get_desc(port->plat->rxq, port, 0) >= 0)
1278 buffs--;
1279 if (!buffs)
1280 break;
1281 if (qmgr_stat_empty(TX_QUEUE(port->id))) {
1282 /* we have to inject some packet */
1283 struct desc *desc;
1284 u32 phys;
1285 int n = queue_get_desc(port->plat->txreadyq, port, 1);
1286 BUG_ON(n < 0);
1287 desc = tx_desc_ptr(port, n);
1288 phys = tx_desc_phys(port, n);
1289 desc->buf_len = desc->pkt_len = 1;
1290 wmb();
1291 queue_put_desc(TX_QUEUE(port->id), phys, desc);
1292 }
1293 udelay(1);
1294 } while (++i < MAX_CLOSE_WAIT);
1295
1296 if (buffs)
1297 printk(KERN_CRIT "%s: unable to drain RX queue, %i buffer(s)"
1298 " left in NPE\n", dev->name, buffs);
1299#if DEBUG_CLOSE
1300 if (!buffs)
1301 printk(KERN_DEBUG "Draining RX queue took %i cycles\n", i);
1302#endif
1303
1304 buffs = TX_DESCS;
1305 while (queue_get_desc(TX_QUEUE(port->id), port, 1) >= 0)
1306 buffs--; /* cancel TX */
1307
1308 i = 0;
1309 do {
1310 while (queue_get_desc(port->plat->txreadyq, port, 1) >= 0)
1311 buffs--;
1312 if (!buffs)
1313 break;
1314 } while (++i < MAX_CLOSE_WAIT);
1315
1316 if (buffs)
1317 printk(KERN_CRIT "%s: unable to drain TX queue, %i buffer(s) "
1318 "left in NPE\n", dev->name, buffs);
1319#if DEBUG_CLOSE
1320 if (!buffs)
1321 printk(KERN_DEBUG "Draining TX queues took %i cycles\n", i);
1322#endif
1323
1324 msg.byte3 = 0;
1325 if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
1326 printk(KERN_CRIT "%s: unable to disable loopback\n",
1327 dev->name);
1328
1329 phy_stop(port->phydev);
1330
1331 if (!ports_open)
1332 qmgr_disable_irq(TXDONE_QUEUE);
1333 destroy_queues(port);
1334 release_queues(port);
1335 return 0;
1336}
1337
1338static const struct net_device_ops ixp4xx_netdev_ops = {
1339 .ndo_open = eth_open,
1340 .ndo_stop = eth_close,
1341 .ndo_start_xmit = eth_xmit,
1342 .ndo_set_multicast_list = eth_set_mcast_list,
1343 .ndo_do_ioctl = eth_ioctl,
1344 .ndo_change_mtu = eth_change_mtu,
1345 .ndo_set_mac_address = eth_mac_addr,
1346 .ndo_validate_addr = eth_validate_addr,
1347};
1348
1349static int __devinit eth_init_one(struct platform_device *pdev)
1350{
1351 struct port *port;
1352 struct net_device *dev;
1353 struct eth_plat_info *plat = pdev->dev.platform_data;
1354 u32 regs_phys;
1355 char phy_id[MII_BUS_ID_SIZE + 3];
1356 int err;
1357
1358 if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
1359 pr_err("ixp4xx_eth: bad ptp filter\n");
1360 return -EINVAL;
1361 }
1362
1363 if (!(dev = alloc_etherdev(sizeof(struct port))))
1364 return -ENOMEM;
1365
1366 SET_NETDEV_DEV(dev, &pdev->dev);
1367 port = netdev_priv(dev);
1368 port->netdev = dev;
1369 port->id = pdev->id;
1370
1371 switch (port->id) {
1372 case IXP4XX_ETH_NPEA:
1373 port->regs = (struct eth_regs __iomem *)IXP4XX_EthA_BASE_VIRT;
1374 regs_phys = IXP4XX_EthA_BASE_PHYS;
1375 break;
1376 case IXP4XX_ETH_NPEB:
1377 port->regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
1378 regs_phys = IXP4XX_EthB_BASE_PHYS;
1379 break;
1380 case IXP4XX_ETH_NPEC:
1381 port->regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT;
1382 regs_phys = IXP4XX_EthC_BASE_PHYS;
1383 break;
1384 default:
1385 err = -ENODEV;
1386 goto err_free;
1387 }
1388
1389 dev->netdev_ops = &ixp4xx_netdev_ops;
1390 dev->ethtool_ops = &ixp4xx_ethtool_ops;
1391 dev->tx_queue_len = 100;
1392
1393 netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT);
1394
1395 if (!(port->npe = npe_request(NPE_ID(port->id)))) {
1396 err = -EIO;
1397 goto err_free;
1398 }
1399
1400 port->mem_res = request_mem_region(regs_phys, REGS_SIZE, dev->name);
1401 if (!port->mem_res) {
1402 err = -EBUSY;
1403 goto err_npe_rel;
1404 }
1405
1406 port->plat = plat;
1407 npe_port_tab[NPE_ID(port->id)] = port;
1408 memcpy(dev->dev_addr, plat->hwaddr, ETH_ALEN);
1409
1410 platform_set_drvdata(pdev, dev);
1411
1412 __raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
1413 &port->regs->core_control);
1414 udelay(50);
1415 __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
1416 udelay(50);
1417
1418 snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, "0", plat->phy);
1419 port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
1420 PHY_INTERFACE_MODE_MII);
1421 if (IS_ERR(port->phydev)) {
1422 err = PTR_ERR(port->phydev);
1423 goto err_free_mem;
1424 }
1425
1426 port->phydev->irq = PHY_POLL;
1427
1428 if ((err = register_netdev(dev)))
1429 goto err_phy_dis;
1430
1431 printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
1432 npe_name(port->npe));
1433
1434 return 0;
1435
1436err_phy_dis:
1437 phy_disconnect(port->phydev);
1438err_free_mem:
1439 npe_port_tab[NPE_ID(port->id)] = NULL;
1440 platform_set_drvdata(pdev, NULL);
1441 release_resource(port->mem_res);
1442err_npe_rel:
1443 npe_release(port->npe);
1444err_free:
1445 free_netdev(dev);
1446 return err;
1447}
1448
1449static int __devexit eth_remove_one(struct platform_device *pdev)
1450{
1451 struct net_device *dev = platform_get_drvdata(pdev);
1452 struct port *port = netdev_priv(dev);
1453
1454 unregister_netdev(dev);
1455 phy_disconnect(port->phydev);
1456 npe_port_tab[NPE_ID(port->id)] = NULL;
1457 platform_set_drvdata(pdev, NULL);
1458 npe_release(port->npe);
1459 release_resource(port->mem_res);
1460 free_netdev(dev);
1461 return 0;
1462}
1463
1464static struct platform_driver ixp4xx_eth_driver = {
1465 .driver.name = DRV_NAME,
1466 .probe = eth_init_one,
1467 .remove = eth_remove_one,
1468};
1469
1470static int __init eth_init_module(void)
1471{
1472 int err;
1473 if ((err = ixp4xx_mdio_register()))
1474 return err;
1475 return platform_driver_register(&ixp4xx_eth_driver);
1476}
1477
1478static void __exit eth_cleanup_module(void)
1479{
1480 platform_driver_unregister(&ixp4xx_eth_driver);
1481 ixp4xx_mdio_remove();
1482}
1483
1484MODULE_AUTHOR("Krzysztof Halasa");
1485MODULE_DESCRIPTION("Intel IXP4xx Ethernet driver");
1486MODULE_LICENSE("GPL v2");
1487MODULE_ALIAS("platform:ixp4xx_eth");
1488module_init(eth_init_module);
1489module_exit(eth_cleanup_module);