aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ixp2000/enp2611.c
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2005-11-11 12:23:13 -0500
committerJeff Garzik <jgarzik@pobox.com>2005-11-18 13:32:22 -0500
commit15d014d13149aedd76cbff1b5c3bbfe839391457 (patch)
tree748af38a44021cf286016b179e58190b685c1630 /drivers/net/ixp2000/enp2611.c
parent7f7f53168dbee6d6a462acea666fddd18aad4f08 (diff)
[PATCH] intel ixp2000 network driver
The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net/ixp2000/enp2611.c')
-rw-r--r--drivers/net/ixp2000/enp2611.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ixp2000/enp2611.c
new file mode 100644
index 000000000000..3262e70ede61
--- /dev/null
+++ b/drivers/net/ixp2000/enp2611.c
@@ -0,0 +1,238 @@
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/config.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/netdevice.h>
16#include <linux/etherdevice.h>
17#include <linux/init.h>
18#include <linux/moduleparam.h>
19#include <asm/arch/uengine.h>
20#include <asm/mach-types.h>
21#include <asm/io.h>
22#include "ixpdev.h"
23#include "caleb.h"
24#include "ixp2400-msf.h"
25#include "pm3386.h"
26
27/***********************************************************************
28 * The Radisys ENP2611 is a PCI form factor board with three SFP GBIC
29 * slots, connected via two PMC/Sierra 3386s and an SPI-3 bridge FPGA
30 * to the IXP2400.
31 *
32 * +-------------+
33 * SFP GBIC #0 ---+ | +---------+
34 * | PM3386 #0 +-------+ |
35 * SFP GBIC #1 ---+ | | "Caleb" | +---------+
36 * +-------------+ | | | |
37 * | SPI-3 +---------+ IXP2400 |
38 * +-------------+ | bridge | | |
39 * SFP GBIC #2 ---+ | | FPGA | +---------+
40 * | PM3386 #1 +-------+ |
41 * | | +---------+
42 * +-------------+
43 * ^ ^ ^
44 * | 1.25Gbaud | 104MHz | 104MHz
45 * | SERDES ea. | SPI-3 ea. | SPI-3
46 *
47 ***********************************************************************/
48static struct ixp2400_msf_parameters enp2611_msf_parameters =
49{
50 .rx_mode = IXP2400_RX_MODE_UTOPIA_POS |
51 IXP2400_RX_MODE_1x32 |
52 IXP2400_RX_MODE_MPHY |
53 IXP2400_RX_MODE_MPHY_32 |
54 IXP2400_RX_MODE_MPHY_POLLED_STATUS |
55 IXP2400_RX_MODE_MPHY_LEVEL3 |
56 IXP2400_RX_MODE_RBUF_SIZE_64,
57
58 .rxclk01_multiplier = IXP2400_PLL_MULTIPLIER_16,
59
60 .rx_poll_ports = 3,
61
62 .rx_channel_mode = {
63 IXP2400_PORT_RX_MODE_MASTER |
64 IXP2400_PORT_RX_MODE_POS_PHY |
65 IXP2400_PORT_RX_MODE_POS_PHY_L3 |
66 IXP2400_PORT_RX_MODE_ODD_PARITY |
67 IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
68
69 IXP2400_PORT_RX_MODE_MASTER |
70 IXP2400_PORT_RX_MODE_POS_PHY |
71 IXP2400_PORT_RX_MODE_POS_PHY_L3 |
72 IXP2400_PORT_RX_MODE_ODD_PARITY |
73 IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
74
75 IXP2400_PORT_RX_MODE_MASTER |
76 IXP2400_PORT_RX_MODE_POS_PHY |
77 IXP2400_PORT_RX_MODE_POS_PHY_L3 |
78 IXP2400_PORT_RX_MODE_ODD_PARITY |
79 IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
80
81 IXP2400_PORT_RX_MODE_MASTER |
82 IXP2400_PORT_RX_MODE_POS_PHY |
83 IXP2400_PORT_RX_MODE_POS_PHY_L3 |
84 IXP2400_PORT_RX_MODE_ODD_PARITY |
85 IXP2400_PORT_RX_MODE_2_CYCLE_DECODE
86 },
87
88 .tx_mode = IXP2400_TX_MODE_UTOPIA_POS |
89 IXP2400_TX_MODE_1x32 |
90 IXP2400_TX_MODE_MPHY |
91 IXP2400_TX_MODE_MPHY_32 |
92 IXP2400_TX_MODE_MPHY_POLLED_STATUS |
93 IXP2400_TX_MODE_MPHY_LEVEL3 |
94 IXP2400_TX_MODE_TBUF_SIZE_64,
95
96 .txclk01_multiplier = IXP2400_PLL_MULTIPLIER_16,
97
98 .tx_poll_ports = 3,
99
100 .tx_channel_mode = {
101 IXP2400_PORT_TX_MODE_MASTER |
102 IXP2400_PORT_TX_MODE_POS_PHY |
103 IXP2400_PORT_TX_MODE_ODD_PARITY |
104 IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
105
106 IXP2400_PORT_TX_MODE_MASTER |
107 IXP2400_PORT_TX_MODE_POS_PHY |
108 IXP2400_PORT_TX_MODE_ODD_PARITY |
109 IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
110
111 IXP2400_PORT_TX_MODE_MASTER |
112 IXP2400_PORT_TX_MODE_POS_PHY |
113 IXP2400_PORT_TX_MODE_ODD_PARITY |
114 IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
115
116 IXP2400_PORT_TX_MODE_MASTER |
117 IXP2400_PORT_TX_MODE_POS_PHY |
118 IXP2400_PORT_TX_MODE_ODD_PARITY |
119 IXP2400_PORT_TX_MODE_2_CYCLE_DECODE
120 }
121};
122
123struct enp2611_ixpdev_priv
124{
125 struct ixpdev_priv ixpdev_priv;
126 struct net_device_stats stats;
127};
128
129static struct net_device *nds[3];
130static struct timer_list link_check_timer;
131
132static struct net_device_stats *enp2611_get_stats(struct net_device *dev)
133{
134 struct enp2611_ixpdev_priv *ip = netdev_priv(dev);
135
136 pm3386_get_stats(ip->ixpdev_priv.channel, &(ip->stats));
137
138 return &(ip->stats);
139}
140
141/* @@@ Poll the SFP moddef0 line too. */
142/* @@@ Try to use the pm3386 DOOL interrupt as well. */
143static void enp2611_check_link_status(unsigned long __dummy)
144{
145 int i;
146
147 for (i = 0; i < 3; i++) {
148 struct net_device *dev;
149 int status;
150
151 if (!netif_running(nds[i]))
152 continue;
153
154 dev = nds[i];
155
156 status = pm3386_is_link_up(i);
157 if (status && !netif_carrier_ok(nds[i])) {
158 pm3386_enable_tx(i);
159 caleb_enable_tx(i);
160 netif_carrier_on(nds[i]);
161 } else if (!status && netif_carrier_ok(nds[i])) {
162 netif_carrier_off(nds[i]);
163 caleb_disable_tx(i);
164 pm3386_disable_tx(i);
165 }
166 }
167
168 link_check_timer.expires = jiffies + HZ / 10;
169 add_timer(&link_check_timer);
170}
171
172static void enp2611_set_port_admin_status(int port, int up)
173{
174 if (up) {
175 caleb_enable_rx(port);
176 pm3386_enable_rx(port);
177 } else {
178 caleb_disable_tx(port);
179 pm3386_disable_tx(port);
180 pm3386_disable_rx(port);
181 caleb_disable_rx(port);
182 }
183}
184
185static int __init enp2611_init_module(void)
186{
187 int i;
188
189 if (!machine_is_enp2611())
190 return -ENODEV;
191
192 caleb_reset();
193 pm3386_reset();
194
195 for (i = 0; i < 3; i++) {
196 nds[i] = ixpdev_alloc(i, sizeof(struct enp2611_ixpdev_priv));
197 if (nds[i] == NULL) {
198 while (--i >= 0)
199 free_netdev(nds[i]);
200 return -ENOMEM;
201 }
202
203 SET_MODULE_OWNER(nds[i]);
204 nds[i]->get_stats = enp2611_get_stats;
205 pm3386_init_port(i);
206 pm3386_get_mac(i, nds[i]->dev_addr);
207 }
208
209 ixp2400_msf_init(&enp2611_msf_parameters);
210
211 if (ixpdev_init(3, nds, enp2611_set_port_admin_status)) {
212 for (i = 0; i < 3; i++)
213 free_netdev(nds[i]);
214 return -EINVAL;
215 }
216
217 init_timer(&link_check_timer);
218 link_check_timer.function = enp2611_check_link_status;
219 link_check_timer.expires = jiffies;
220 add_timer(&link_check_timer);
221
222 return 0;
223}
224
225static void __exit enp2611_cleanup_module(void)
226{
227 int i;
228
229 del_timer_sync(&link_check_timer);
230
231 ixpdev_deinit();
232 for (i = 0; i < 3; i++)
233 free_netdev(nds[i]);
234}
235
236module_init(enp2611_init_module);
237module_exit(enp2611_cleanup_module);
238MODULE_LICENSE("GPL");