Commit f89efd523b25cc1702e074dafdcac283da657002
Committed by
Jeff Garzik
1 parent
43ec6e95e4
Exists in
master
and in
7 other branches
[PATCH] Add rapidio net driver
Adds an "Ethernet" driver which sends Ethernet packets over the standard RapidIO messaging. This depends on the core RIO patch for mailbox/doorbell access. Signed-off-by: Matt Porter <mporter@kernel.crashing.org> Cc: Jeff Garzik <jgarzik@pobox.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Showing 3 changed files with 589 additions and 0 deletions Side-by-side Diff
drivers/net/Kconfig
... | ... | @@ -2235,6 +2235,20 @@ |
2235 | 2235 | tristate "iSeries Virtual Ethernet driver support" |
2236 | 2236 | depends on PPC_ISERIES |
2237 | 2237 | |
2238 | +config RIONET | |
2239 | + tristate "RapidIO Ethernet over messaging driver support" | |
2240 | + depends on NETDEVICES && RAPIDIO | |
2241 | + | |
2242 | +config RIONET_TX_SIZE | |
2243 | + int "Number of outbound queue entries" | |
2244 | + depends on RIONET | |
2245 | + default "128" | |
2246 | + | |
2247 | +config RIONET_RX_SIZE | |
2248 | + int "Number of inbound queue entries" | |
2249 | + depends on RIONET | |
2250 | + default "128" | |
2251 | + | |
2238 | 2252 | config FDDI |
2239 | 2253 | bool "FDDI driver support" |
2240 | 2254 | depends on (PCI || EISA) |
drivers/net/Makefile
drivers/net/rionet.c
1 | +/* | |
2 | + * rionet - Ethernet driver over RapidIO messaging services | |
3 | + * | |
4 | + * Copyright 2005 MontaVista Software, Inc. | |
5 | + * Matt Porter <mporter@kernel.crashing.org> | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or modify it | |
8 | + * under the terms of the GNU General Public License as published by the | |
9 | + * Free Software Foundation; either version 2 of the License, or (at your | |
10 | + * option) any later version. | |
11 | + */ | |
12 | + | |
13 | +#include <linux/module.h> | |
14 | +#include <linux/kernel.h> | |
15 | +#include <linux/dma-mapping.h> | |
16 | +#include <linux/delay.h> | |
17 | +#include <linux/rio.h> | |
18 | +#include <linux/rio_drv.h> | |
19 | +#include <linux/rio_ids.h> | |
20 | + | |
21 | +#include <linux/netdevice.h> | |
22 | +#include <linux/etherdevice.h> | |
23 | +#include <linux/skbuff.h> | |
24 | +#include <linux/crc32.h> | |
25 | +#include <linux/ethtool.h> | |
26 | + | |
27 | +#define DRV_NAME "rionet" | |
28 | +#define DRV_VERSION "0.2" | |
29 | +#define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>" | |
30 | +#define DRV_DESC "Ethernet over RapidIO" | |
31 | + | |
32 | +MODULE_AUTHOR(DRV_AUTHOR); | |
33 | +MODULE_DESCRIPTION(DRV_DESC); | |
34 | +MODULE_LICENSE("GPL"); | |
35 | + | |
36 | +#define RIONET_DEFAULT_MSGLEVEL \ | |
37 | + (NETIF_MSG_DRV | \ | |
38 | + NETIF_MSG_LINK | \ | |
39 | + NETIF_MSG_RX_ERR | \ | |
40 | + NETIF_MSG_TX_ERR) | |
41 | + | |
42 | +#define RIONET_DOORBELL_JOIN 0x1000 | |
43 | +#define RIONET_DOORBELL_LEAVE 0x1001 | |
44 | + | |
45 | +#define RIONET_MAILBOX 0 | |
46 | + | |
47 | +#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE | |
48 | +#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE | |
49 | + | |
50 | +static LIST_HEAD(rionet_peers); | |
51 | + | |
52 | +struct rionet_private { | |
53 | + struct rio_mport *mport; | |
54 | + struct sk_buff *rx_skb[RIONET_RX_RING_SIZE]; | |
55 | + struct sk_buff *tx_skb[RIONET_TX_RING_SIZE]; | |
56 | + struct net_device_stats stats; | |
57 | + int rx_slot; | |
58 | + int tx_slot; | |
59 | + int tx_cnt; | |
60 | + int ack_slot; | |
61 | + spinlock_t lock; | |
62 | + spinlock_t tx_lock; | |
63 | + u32 msg_enable; | |
64 | +}; | |
65 | + | |
66 | +struct rionet_peer { | |
67 | + struct list_head node; | |
68 | + struct rio_dev *rdev; | |
69 | + struct resource *res; | |
70 | +}; | |
71 | + | |
72 | +static int rionet_check = 0; | |
73 | +static int rionet_capable = 1; | |
74 | + | |
75 | +/* | |
76 | + * This is a fast lookup table for for translating TX | |
77 | + * Ethernet packets into a destination RIO device. It | |
78 | + * could be made into a hash table to save memory depending | |
79 | + * on system trade-offs. | |
80 | + */ | |
81 | +static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES]; | |
82 | + | |
83 | +#define is_rionet_capable(pef, src_ops, dst_ops) \ | |
84 | + ((pef & RIO_PEF_INB_MBOX) && \ | |
85 | + (pef & RIO_PEF_INB_DOORBELL) && \ | |
86 | + (src_ops & RIO_SRC_OPS_DOORBELL) && \ | |
87 | + (dst_ops & RIO_DST_OPS_DOORBELL)) | |
88 | +#define dev_rionet_capable(dev) \ | |
89 | + is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops) | |
90 | + | |
91 | +#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001) | |
92 | +#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4)) | |
93 | + | |
94 | +static struct net_device_stats *rionet_stats(struct net_device *ndev) | |
95 | +{ | |
96 | + struct rionet_private *rnet = ndev->priv; | |
97 | + return &rnet->stats; | |
98 | +} | |
99 | + | |
100 | +static int rionet_rx_clean(struct net_device *ndev) | |
101 | +{ | |
102 | + int i; | |
103 | + int error = 0; | |
104 | + struct rionet_private *rnet = ndev->priv; | |
105 | + void *data; | |
106 | + | |
107 | + i = rnet->rx_slot; | |
108 | + | |
109 | + do { | |
110 | + if (!rnet->rx_skb[i]) | |
111 | + continue; | |
112 | + | |
113 | + if (!(data = rio_get_inb_message(rnet->mport, RIONET_MAILBOX))) | |
114 | + break; | |
115 | + | |
116 | + rnet->rx_skb[i]->data = data; | |
117 | + skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE); | |
118 | + rnet->rx_skb[i]->dev = ndev; | |
119 | + rnet->rx_skb[i]->protocol = | |
120 | + eth_type_trans(rnet->rx_skb[i], ndev); | |
121 | + error = netif_rx(rnet->rx_skb[i]); | |
122 | + | |
123 | + if (error == NET_RX_DROP) { | |
124 | + rnet->stats.rx_dropped++; | |
125 | + } else if (error == NET_RX_BAD) { | |
126 | + if (netif_msg_rx_err(rnet)) | |
127 | + printk(KERN_WARNING "%s: bad rx packet\n", | |
128 | + DRV_NAME); | |
129 | + rnet->stats.rx_errors++; | |
130 | + } else { | |
131 | + rnet->stats.rx_packets++; | |
132 | + rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE; | |
133 | + } | |
134 | + | |
135 | + } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot); | |
136 | + | |
137 | + return i; | |
138 | +} | |
139 | + | |
140 | +static void rionet_rx_fill(struct net_device *ndev, int end) | |
141 | +{ | |
142 | + int i; | |
143 | + struct rionet_private *rnet = ndev->priv; | |
144 | + | |
145 | + i = rnet->rx_slot; | |
146 | + do { | |
147 | + rnet->rx_skb[i] = dev_alloc_skb(RIO_MAX_MSG_SIZE); | |
148 | + | |
149 | + if (!rnet->rx_skb[i]) | |
150 | + break; | |
151 | + | |
152 | + rio_add_inb_buffer(rnet->mport, RIONET_MAILBOX, | |
153 | + rnet->rx_skb[i]->data); | |
154 | + } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != end); | |
155 | + | |
156 | + rnet->rx_slot = i; | |
157 | +} | |
158 | + | |
159 | +static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, | |
160 | + struct rio_dev *rdev) | |
161 | +{ | |
162 | + struct rionet_private *rnet = ndev->priv; | |
163 | + | |
164 | + rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len); | |
165 | + rnet->tx_skb[rnet->tx_slot] = skb; | |
166 | + | |
167 | + rnet->stats.tx_packets++; | |
168 | + rnet->stats.tx_bytes += skb->len; | |
169 | + | |
170 | + if (++rnet->tx_cnt == RIONET_TX_RING_SIZE) | |
171 | + netif_stop_queue(ndev); | |
172 | + | |
173 | + ++rnet->tx_slot; | |
174 | + rnet->tx_slot &= (RIONET_TX_RING_SIZE - 1); | |
175 | + | |
176 | + if (netif_msg_tx_queued(rnet)) | |
177 | + printk(KERN_INFO "%s: queued skb %8.8x len %8.8x\n", DRV_NAME, | |
178 | + (u32) skb, skb->len); | |
179 | + | |
180 | + return 0; | |
181 | +} | |
182 | + | |
183 | +static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |
184 | +{ | |
185 | + int i; | |
186 | + struct rionet_private *rnet = ndev->priv; | |
187 | + struct ethhdr *eth = (struct ethhdr *)skb->data; | |
188 | + u16 destid; | |
189 | + unsigned long flags; | |
190 | + | |
191 | + local_irq_save(flags); | |
192 | + if (!spin_trylock(&rnet->tx_lock)) { | |
193 | + local_irq_restore(flags); | |
194 | + return NETDEV_TX_LOCKED; | |
195 | + } | |
196 | + | |
197 | + if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) { | |
198 | + netif_stop_queue(ndev); | |
199 | + spin_unlock_irqrestore(&rnet->tx_lock, flags); | |
200 | + printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", | |
201 | + ndev->name); | |
202 | + return NETDEV_TX_BUSY; | |
203 | + } | |
204 | + | |
205 | + if (eth->h_dest[0] & 0x01) { | |
206 | + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) | |
207 | + if (rionet_active[i]) | |
208 | + rionet_queue_tx_msg(skb, ndev, | |
209 | + rionet_active[i]); | |
210 | + } else if (RIONET_MAC_MATCH(eth->h_dest)) { | |
211 | + destid = RIONET_GET_DESTID(eth->h_dest); | |
212 | + if (rionet_active[destid]) | |
213 | + rionet_queue_tx_msg(skb, ndev, rionet_active[destid]); | |
214 | + } | |
215 | + | |
216 | + spin_unlock_irqrestore(&rnet->tx_lock, flags); | |
217 | + | |
218 | + return 0; | |
219 | +} | |
220 | + | |
221 | +static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid, | |
222 | + u16 info) | |
223 | +{ | |
224 | + struct net_device *ndev = dev_id; | |
225 | + struct rionet_private *rnet = ndev->priv; | |
226 | + struct rionet_peer *peer; | |
227 | + | |
228 | + if (netif_msg_intr(rnet)) | |
229 | + printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", | |
230 | + DRV_NAME, sid, tid, info); | |
231 | + if (info == RIONET_DOORBELL_JOIN) { | |
232 | + if (!rionet_active[sid]) { | |
233 | + list_for_each_entry(peer, &rionet_peers, node) { | |
234 | + if (peer->rdev->destid == sid) | |
235 | + rionet_active[sid] = peer->rdev; | |
236 | + } | |
237 | + rio_mport_send_doorbell(mport, sid, | |
238 | + RIONET_DOORBELL_JOIN); | |
239 | + } | |
240 | + } else if (info == RIONET_DOORBELL_LEAVE) { | |
241 | + rionet_active[sid] = NULL; | |
242 | + } else { | |
243 | + if (netif_msg_intr(rnet)) | |
244 | + printk(KERN_WARNING "%s: unhandled doorbell\n", | |
245 | + DRV_NAME); | |
246 | + } | |
247 | +} | |
248 | + | |
249 | +static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) | |
250 | +{ | |
251 | + int n; | |
252 | + struct net_device *ndev = dev_id; | |
253 | + struct rionet_private *rnet = (struct rionet_private *)ndev->priv; | |
254 | + | |
255 | + if (netif_msg_intr(rnet)) | |
256 | + printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n", | |
257 | + DRV_NAME, mbox, slot); | |
258 | + | |
259 | + spin_lock(&rnet->lock); | |
260 | + if ((n = rionet_rx_clean(ndev)) != rnet->rx_slot) | |
261 | + rionet_rx_fill(ndev, n); | |
262 | + spin_unlock(&rnet->lock); | |
263 | +} | |
264 | + | |
265 | +static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) | |
266 | +{ | |
267 | + struct net_device *ndev = dev_id; | |
268 | + struct rionet_private *rnet = ndev->priv; | |
269 | + | |
270 | + spin_lock(&rnet->lock); | |
271 | + | |
272 | + if (netif_msg_intr(rnet)) | |
273 | + printk(KERN_INFO | |
274 | + "%s: outbound message event, mbox %d slot %d\n", | |
275 | + DRV_NAME, mbox, slot); | |
276 | + | |
277 | + while (rnet->tx_cnt && (rnet->ack_slot != slot)) { | |
278 | + /* dma unmap single */ | |
279 | + dev_kfree_skb_irq(rnet->tx_skb[rnet->ack_slot]); | |
280 | + rnet->tx_skb[rnet->ack_slot] = NULL; | |
281 | + ++rnet->ack_slot; | |
282 | + rnet->ack_slot &= (RIONET_TX_RING_SIZE - 1); | |
283 | + rnet->tx_cnt--; | |
284 | + } | |
285 | + | |
286 | + if (rnet->tx_cnt < RIONET_TX_RING_SIZE) | |
287 | + netif_wake_queue(ndev); | |
288 | + | |
289 | + spin_unlock(&rnet->lock); | |
290 | +} | |
291 | + | |
292 | +static int rionet_open(struct net_device *ndev) | |
293 | +{ | |
294 | + int i, rc = 0; | |
295 | + struct rionet_peer *peer, *tmp; | |
296 | + u32 pwdcsr; | |
297 | + struct rionet_private *rnet = ndev->priv; | |
298 | + | |
299 | + if (netif_msg_ifup(rnet)) | |
300 | + printk(KERN_INFO "%s: open\n", DRV_NAME); | |
301 | + | |
302 | + if ((rc = rio_request_inb_dbell(rnet->mport, | |
303 | + (void *)ndev, | |
304 | + RIONET_DOORBELL_JOIN, | |
305 | + RIONET_DOORBELL_LEAVE, | |
306 | + rionet_dbell_event)) < 0) | |
307 | + goto out; | |
308 | + | |
309 | + if ((rc = rio_request_inb_mbox(rnet->mport, | |
310 | + (void *)ndev, | |
311 | + RIONET_MAILBOX, | |
312 | + RIONET_RX_RING_SIZE, | |
313 | + rionet_inb_msg_event)) < 0) | |
314 | + goto out; | |
315 | + | |
316 | + if ((rc = rio_request_outb_mbox(rnet->mport, | |
317 | + (void *)ndev, | |
318 | + RIONET_MAILBOX, | |
319 | + RIONET_TX_RING_SIZE, | |
320 | + rionet_outb_msg_event)) < 0) | |
321 | + goto out; | |
322 | + | |
323 | + /* Initialize inbound message ring */ | |
324 | + for (i = 0; i < RIONET_RX_RING_SIZE; i++) | |
325 | + rnet->rx_skb[i] = NULL; | |
326 | + rnet->rx_slot = 0; | |
327 | + rionet_rx_fill(ndev, 0); | |
328 | + | |
329 | + rnet->tx_slot = 0; | |
330 | + rnet->tx_cnt = 0; | |
331 | + rnet->ack_slot = 0; | |
332 | + | |
333 | + netif_carrier_on(ndev); | |
334 | + netif_start_queue(ndev); | |
335 | + | |
336 | + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { | |
337 | + if (!(peer->res = rio_request_outb_dbell(peer->rdev, | |
338 | + RIONET_DOORBELL_JOIN, | |
339 | + RIONET_DOORBELL_LEAVE))) | |
340 | + { | |
341 | + printk(KERN_ERR "%s: error requesting doorbells\n", | |
342 | + DRV_NAME); | |
343 | + continue; | |
344 | + } | |
345 | + | |
346 | + /* | |
347 | + * If device has initialized inbound doorbells, | |
348 | + * send a join message | |
349 | + */ | |
350 | + rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr); | |
351 | + if (pwdcsr & RIO_DOORBELL_AVAIL) | |
352 | + rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN); | |
353 | + } | |
354 | + | |
355 | + out: | |
356 | + return rc; | |
357 | +} | |
358 | + | |
359 | +static int rionet_close(struct net_device *ndev) | |
360 | +{ | |
361 | + struct rionet_private *rnet = (struct rionet_private *)ndev->priv; | |
362 | + struct rionet_peer *peer, *tmp; | |
363 | + int i; | |
364 | + | |
365 | + if (netif_msg_ifup(rnet)) | |
366 | + printk(KERN_INFO "%s: close\n", DRV_NAME); | |
367 | + | |
368 | + netif_stop_queue(ndev); | |
369 | + netif_carrier_off(ndev); | |
370 | + | |
371 | + for (i = 0; i < RIONET_RX_RING_SIZE; i++) | |
372 | + if (rnet->rx_skb[i]) | |
373 | + kfree_skb(rnet->rx_skb[i]); | |
374 | + | |
375 | + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { | |
376 | + if (rionet_active[peer->rdev->destid]) { | |
377 | + rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); | |
378 | + rionet_active[peer->rdev->destid] = NULL; | |
379 | + } | |
380 | + rio_release_outb_dbell(peer->rdev, peer->res); | |
381 | + } | |
382 | + | |
383 | + rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN, | |
384 | + RIONET_DOORBELL_LEAVE); | |
385 | + rio_release_inb_mbox(rnet->mport, RIONET_MAILBOX); | |
386 | + rio_release_outb_mbox(rnet->mport, RIONET_MAILBOX); | |
387 | + | |
388 | + return 0; | |
389 | +} | |
390 | + | |
391 | +static void rionet_remove(struct rio_dev *rdev) | |
392 | +{ | |
393 | + struct net_device *ndev = NULL; | |
394 | + struct rionet_peer *peer, *tmp; | |
395 | + | |
396 | + unregister_netdev(ndev); | |
397 | + kfree(ndev); | |
398 | + | |
399 | + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { | |
400 | + list_del(&peer->node); | |
401 | + kfree(peer); | |
402 | + } | |
403 | +} | |
404 | + | |
405 | +static void rionet_get_drvinfo(struct net_device *ndev, | |
406 | + struct ethtool_drvinfo *info) | |
407 | +{ | |
408 | + struct rionet_private *rnet = ndev->priv; | |
409 | + | |
410 | + strcpy(info->driver, DRV_NAME); | |
411 | + strcpy(info->version, DRV_VERSION); | |
412 | + strcpy(info->fw_version, "n/a"); | |
413 | + strcpy(info->bus_info, rnet->mport->name); | |
414 | +} | |
415 | + | |
416 | +static u32 rionet_get_msglevel(struct net_device *ndev) | |
417 | +{ | |
418 | + struct rionet_private *rnet = ndev->priv; | |
419 | + | |
420 | + return rnet->msg_enable; | |
421 | +} | |
422 | + | |
423 | +static void rionet_set_msglevel(struct net_device *ndev, u32 value) | |
424 | +{ | |
425 | + struct rionet_private *rnet = ndev->priv; | |
426 | + | |
427 | + rnet->msg_enable = value; | |
428 | +} | |
429 | + | |
430 | +static struct ethtool_ops rionet_ethtool_ops = { | |
431 | + .get_drvinfo = rionet_get_drvinfo, | |
432 | + .get_msglevel = rionet_get_msglevel, | |
433 | + .set_msglevel = rionet_set_msglevel, | |
434 | + .get_link = ethtool_op_get_link, | |
435 | +}; | |
436 | + | |
437 | +static int rionet_setup_netdev(struct rio_mport *mport) | |
438 | +{ | |
439 | + int rc = 0; | |
440 | + struct net_device *ndev = NULL; | |
441 | + struct rionet_private *rnet; | |
442 | + u16 device_id; | |
443 | + | |
444 | + /* Allocate our net_device structure */ | |
445 | + ndev = alloc_etherdev(sizeof(struct rionet_private)); | |
446 | + if (ndev == NULL) { | |
447 | + printk(KERN_INFO "%s: could not allocate ethernet device.\n", | |
448 | + DRV_NAME); | |
449 | + rc = -ENOMEM; | |
450 | + goto out; | |
451 | + } | |
452 | + | |
453 | + /* Set up private area */ | |
454 | + rnet = (struct rionet_private *)ndev->priv; | |
455 | + rnet->mport = mport; | |
456 | + | |
457 | + /* Set the default MAC address */ | |
458 | + device_id = rio_local_get_device_id(mport); | |
459 | + ndev->dev_addr[0] = 0x00; | |
460 | + ndev->dev_addr[1] = 0x01; | |
461 | + ndev->dev_addr[2] = 0x00; | |
462 | + ndev->dev_addr[3] = 0x01; | |
463 | + ndev->dev_addr[4] = device_id >> 8; | |
464 | + ndev->dev_addr[5] = device_id & 0xff; | |
465 | + | |
466 | + /* Fill in the driver function table */ | |
467 | + ndev->open = &rionet_open; | |
468 | + ndev->hard_start_xmit = &rionet_start_xmit; | |
469 | + ndev->stop = &rionet_close; | |
470 | + ndev->get_stats = &rionet_stats; | |
471 | + ndev->mtu = RIO_MAX_MSG_SIZE - 14; | |
472 | + ndev->features = NETIF_F_LLTX; | |
473 | + SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); | |
474 | + | |
475 | + SET_MODULE_OWNER(ndev); | |
476 | + | |
477 | + spin_lock_init(&rnet->lock); | |
478 | + spin_lock_init(&rnet->tx_lock); | |
479 | + | |
480 | + rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL; | |
481 | + | |
482 | + rc = register_netdev(ndev); | |
483 | + if (rc != 0) | |
484 | + goto out; | |
485 | + | |
486 | + printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", | |
487 | + ndev->name, | |
488 | + DRV_NAME, | |
489 | + DRV_DESC, | |
490 | + DRV_VERSION, | |
491 | + ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], | |
492 | + ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); | |
493 | + | |
494 | + out: | |
495 | + return rc; | |
496 | +} | |
497 | + | |
498 | +/* | |
499 | + * XXX Make multi-net safe | |
500 | + */ | |
501 | +static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) | |
502 | +{ | |
503 | + int rc = -ENODEV; | |
504 | + u32 lpef, lsrc_ops, ldst_ops; | |
505 | + struct rionet_peer *peer; | |
506 | + | |
507 | + /* If local device is not rionet capable, give up quickly */ | |
508 | + if (!rionet_capable) | |
509 | + goto out; | |
510 | + | |
511 | + /* | |
512 | + * First time through, make sure local device is rionet | |
513 | + * capable, setup netdev, and set flags so this is skipped | |
514 | + * on later probes | |
515 | + */ | |
516 | + if (!rionet_check) { | |
517 | + rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef); | |
518 | + rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, | |
519 | + &lsrc_ops); | |
520 | + rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, | |
521 | + &ldst_ops); | |
522 | + if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) { | |
523 | + printk(KERN_ERR | |
524 | + "%s: local device is not network capable\n", | |
525 | + DRV_NAME); | |
526 | + rionet_check = 1; | |
527 | + rionet_capable = 0; | |
528 | + goto out; | |
529 | + } | |
530 | + | |
531 | + rc = rionet_setup_netdev(rdev->net->hport); | |
532 | + rionet_check = 1; | |
533 | + } | |
534 | + | |
535 | + /* | |
536 | + * If the remote device has mailbox/doorbell capabilities, | |
537 | + * add it to the peer list. | |
538 | + */ | |
539 | + if (dev_rionet_capable(rdev)) { | |
540 | + if (!(peer = kmalloc(sizeof(struct rionet_peer), GFP_KERNEL))) { | |
541 | + rc = -ENOMEM; | |
542 | + goto out; | |
543 | + } | |
544 | + peer->rdev = rdev; | |
545 | + list_add_tail(&peer->node, &rionet_peers); | |
546 | + } | |
547 | + | |
548 | + out: | |
549 | + return rc; | |
550 | +} | |
551 | + | |
552 | +static struct rio_device_id rionet_id_table[] = { | |
553 | + {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)} | |
554 | +}; | |
555 | + | |
556 | +static struct rio_driver rionet_driver = { | |
557 | + .name = "rionet", | |
558 | + .id_table = rionet_id_table, | |
559 | + .probe = rionet_probe, | |
560 | + .remove = rionet_remove, | |
561 | +}; | |
562 | + | |
563 | +static int __init rionet_init(void) | |
564 | +{ | |
565 | + return rio_register_driver(&rionet_driver); | |
566 | +} | |
567 | + | |
568 | +static void __exit rionet_exit(void) | |
569 | +{ | |
570 | + rio_unregister_driver(&rionet_driver); | |
571 | +} | |
572 | + | |
573 | +module_init(rionet_init); | |
574 | +module_exit(rionet_exit); |