Commit 2fb717ec3ec76b0ca4cee9c4d802ce551750413d
Committed by
Linus Torvalds
1 parent
005842efd1
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
rapidio/rionet: rework to support multiple RIO master ports
Make RIONET driver multi-net safe/capable by introducing per-net lists of RapidIO network peers. Rework registration of network adapters to support all available RIO master port devices. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Li Yang <leoli@freescale.com> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 70 additions and 63 deletions Side-by-side Diff
drivers/net/rionet.c
... | ... | @@ -26,7 +26,7 @@ |
26 | 26 | #include <linux/ethtool.h> |
27 | 27 | |
28 | 28 | #define DRV_NAME "rionet" |
29 | -#define DRV_VERSION "0.2" | |
29 | +#define DRV_VERSION "0.3" | |
30 | 30 | #define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>" |
31 | 31 | #define DRV_DESC "Ethernet over RapidIO" |
32 | 32 | |
33 | 33 | |
... | ... | @@ -47,9 +47,8 @@ |
47 | 47 | |
48 | 48 | #define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE |
49 | 49 | #define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE |
50 | +#define RIONET_MAX_NETS 8 | |
50 | 51 | |
51 | -static LIST_HEAD(rionet_peers); | |
52 | - | |
53 | 52 | struct rionet_private { |
54 | 53 | struct rio_mport *mport; |
55 | 54 | struct sk_buff *rx_skb[RIONET_RX_RING_SIZE]; |
56 | 55 | |
... | ... | @@ -69,17 +68,14 @@ |
69 | 68 | struct resource *res; |
70 | 69 | }; |
71 | 70 | |
72 | -static int rionet_check = 0; | |
73 | -static int rionet_capable = 1; | |
71 | +struct rionet_net { | |
72 | + struct net_device *ndev; | |
73 | + struct list_head peers; | |
74 | + struct rio_dev **active; | |
75 | + int nact; /* number of active peers */ | |
76 | +}; | |
74 | 77 | |
75 | -/* | |
76 | - * This is a fast lookup table 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; | |
82 | -static int nact; /* total number of active rionet peers */ | |
78 | +static struct rionet_net nets[RIONET_MAX_NETS]; | |
83 | 79 | |
84 | 80 | #define is_rionet_capable(src_ops, dst_ops) \ |
85 | 81 | ((src_ops & RIO_SRC_OPS_DATA_MSG) && \ |
... | ... | @@ -185,7 +181,7 @@ |
185 | 181 | } |
186 | 182 | |
187 | 183 | if (is_multicast_ether_addr(eth->h_dest)) |
188 | - add_num = nact; | |
184 | + add_num = nets[rnet->mport->id].nact; | |
189 | 185 | |
190 | 186 | if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) { |
191 | 187 | netif_stop_queue(ndev); |
192 | 188 | |
193 | 189 | |
194 | 190 | |
... | ... | @@ -197,19 +193,21 @@ |
197 | 193 | |
198 | 194 | if (is_multicast_ether_addr(eth->h_dest)) { |
199 | 195 | int count = 0; |
196 | + | |
200 | 197 | for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size); |
201 | 198 | i++) |
202 | - if (rionet_active[i]) { | |
199 | + if (nets[rnet->mport->id].active[i]) { | |
203 | 200 | rionet_queue_tx_msg(skb, ndev, |
204 | - rionet_active[i]); | |
201 | + nets[rnet->mport->id].active[i]); | |
205 | 202 | if (count) |
206 | 203 | atomic_inc(&skb->users); |
207 | 204 | count++; |
208 | 205 | } |
209 | 206 | } else if (RIONET_MAC_MATCH(eth->h_dest)) { |
210 | 207 | destid = RIONET_GET_DESTID(eth->h_dest); |
211 | - if (rionet_active[destid]) | |
212 | - rionet_queue_tx_msg(skb, ndev, rionet_active[destid]); | |
208 | + if (nets[rnet->mport->id].active[destid]) | |
209 | + rionet_queue_tx_msg(skb, ndev, | |
210 | + nets[rnet->mport->id].active[destid]); | |
213 | 211 | } |
214 | 212 | |
215 | 213 | spin_unlock_irqrestore(&rnet->tx_lock, flags); |
216 | 214 | |
217 | 215 | |
... | ... | @@ -228,19 +226,21 @@ |
228 | 226 | printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", |
229 | 227 | DRV_NAME, sid, tid, info); |
230 | 228 | if (info == RIONET_DOORBELL_JOIN) { |
231 | - if (!rionet_active[sid]) { | |
232 | - list_for_each_entry(peer, &rionet_peers, node) { | |
229 | + if (!nets[rnet->mport->id].active[sid]) { | |
230 | + list_for_each_entry(peer, | |
231 | + &nets[rnet->mport->id].peers, node) { | |
233 | 232 | if (peer->rdev->destid == sid) { |
234 | - rionet_active[sid] = peer->rdev; | |
235 | - nact++; | |
233 | + nets[rnet->mport->id].active[sid] = | |
234 | + peer->rdev; | |
235 | + nets[rnet->mport->id].nact++; | |
236 | 236 | } |
237 | 237 | } |
238 | 238 | rio_mport_send_doorbell(mport, sid, |
239 | 239 | RIONET_DOORBELL_JOIN); |
240 | 240 | } |
241 | 241 | } else if (info == RIONET_DOORBELL_LEAVE) { |
242 | - rionet_active[sid] = NULL; | |
243 | - nact--; | |
242 | + nets[rnet->mport->id].active[sid] = NULL; | |
243 | + nets[rnet->mport->id].nact--; | |
244 | 244 | } else { |
245 | 245 | if (netif_msg_intr(rnet)) |
246 | 246 | printk(KERN_WARNING "%s: unhandled doorbell\n", |
... | ... | @@ -334,7 +334,8 @@ |
334 | 334 | netif_carrier_on(ndev); |
335 | 335 | netif_start_queue(ndev); |
336 | 336 | |
337 | - list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { | |
337 | + list_for_each_entry_safe(peer, tmp, | |
338 | + &nets[rnet->mport->id].peers, node) { | |
338 | 339 | if (!(peer->res = rio_request_outb_dbell(peer->rdev, |
339 | 340 | RIONET_DOORBELL_JOIN, |
340 | 341 | RIONET_DOORBELL_LEAVE))) |
... | ... | @@ -359,7 +360,7 @@ |
359 | 360 | int i; |
360 | 361 | |
361 | 362 | if (netif_msg_ifup(rnet)) |
362 | - printk(KERN_INFO "%s: close\n", DRV_NAME); | |
363 | + printk(KERN_INFO "%s: close %s\n", DRV_NAME, ndev->name); | |
363 | 364 | |
364 | 365 | netif_stop_queue(ndev); |
365 | 366 | netif_carrier_off(ndev); |
366 | 367 | |
... | ... | @@ -367,10 +368,11 @@ |
367 | 368 | for (i = 0; i < RIONET_RX_RING_SIZE; i++) |
368 | 369 | kfree_skb(rnet->rx_skb[i]); |
369 | 370 | |
370 | - list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { | |
371 | - if (rionet_active[peer->rdev->destid]) { | |
371 | + list_for_each_entry_safe(peer, tmp, | |
372 | + &nets[rnet->mport->id].peers, node) { | |
373 | + if (nets[rnet->mport->id].active[peer->rdev->destid]) { | |
372 | 374 | rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); |
373 | - rionet_active[peer->rdev->destid] = NULL; | |
375 | + nets[rnet->mport->id].active[peer->rdev->destid] = NULL; | |
374 | 376 | } |
375 | 377 | rio_release_outb_dbell(peer->rdev, peer->res); |
376 | 378 | } |
377 | 379 | |
378 | 380 | |
379 | 381 | |
380 | 382 | |
... | ... | @@ -386,17 +388,21 @@ |
386 | 388 | static void rionet_remove(struct rio_dev *rdev) |
387 | 389 | { |
388 | 390 | struct net_device *ndev = rio_get_drvdata(rdev); |
391 | + unsigned char netid = rdev->net->hport->id; | |
389 | 392 | struct rionet_peer *peer, *tmp; |
390 | 393 | |
391 | - free_pages((unsigned long)rionet_active, get_order(sizeof(void *) * | |
392 | - RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size))); | |
393 | 394 | unregister_netdev(ndev); |
394 | - free_netdev(ndev); | |
395 | 395 | |
396 | - list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { | |
396 | + free_pages((unsigned long)nets[netid].active, get_order(sizeof(void *) * | |
397 | + RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size))); | |
398 | + nets[netid].active = NULL; | |
399 | + | |
400 | + list_for_each_entry_safe(peer, tmp, &nets[netid].peers, node) { | |
397 | 401 | list_del(&peer->node); |
398 | 402 | kfree(peer); |
399 | 403 | } |
404 | + | |
405 | + free_netdev(ndev); | |
400 | 406 | } |
401 | 407 | |
402 | 408 | static void rionet_get_drvinfo(struct net_device *ndev, |
403 | 409 | |
... | ... | @@ -448,13 +454,13 @@ |
448 | 454 | const size_t rionet_active_bytes = sizeof(void *) * |
449 | 455 | RIO_MAX_ROUTE_ENTRIES(mport->sys_size); |
450 | 456 | |
451 | - rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, | |
452 | - get_order(rionet_active_bytes)); | |
453 | - if (!rionet_active) { | |
457 | + nets[mport->id].active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, | |
458 | + get_order(rionet_active_bytes)); | |
459 | + if (!nets[mport->id].active) { | |
454 | 460 | rc = -ENOMEM; |
455 | 461 | goto out; |
456 | 462 | } |
457 | - memset((void *)rionet_active, 0, rionet_active_bytes); | |
463 | + memset((void *)nets[mport->id].active, 0, rionet_active_bytes); | |
458 | 464 | |
459 | 465 | /* Set up private area */ |
460 | 466 | rnet = netdev_priv(ndev); |
461 | 467 | |
462 | 468 | |
463 | 469 | |
464 | 470 | |
465 | 471 | |
466 | 472 | |
467 | 473 | |
468 | 474 | |
469 | 475 | |
470 | 476 | |
... | ... | @@ -483,61 +489,62 @@ |
483 | 489 | if (rc != 0) |
484 | 490 | goto out; |
485 | 491 | |
486 | - printk("%s: %s %s Version %s, MAC %pM\n", | |
492 | + printk(KERN_INFO "%s: %s %s Version %s, MAC %pM, %s\n", | |
487 | 493 | ndev->name, |
488 | 494 | DRV_NAME, |
489 | 495 | DRV_DESC, |
490 | 496 | DRV_VERSION, |
491 | - ndev->dev_addr); | |
497 | + ndev->dev_addr, | |
498 | + mport->name); | |
492 | 499 | |
493 | 500 | out: |
494 | 501 | return rc; |
495 | 502 | } |
496 | 503 | |
497 | -/* | |
498 | - * XXX Make multi-net safe | |
499 | - */ | |
504 | +static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1]; | |
505 | + | |
500 | 506 | static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) |
501 | 507 | { |
502 | 508 | int rc = -ENODEV; |
503 | 509 | u32 lsrc_ops, ldst_ops; |
504 | 510 | struct rionet_peer *peer; |
505 | 511 | struct net_device *ndev = NULL; |
512 | + unsigned char netid = rdev->net->hport->id; | |
513 | + int oldnet; | |
506 | 514 | |
507 | - /* If local device is not rionet capable, give up quickly */ | |
508 | - if (!rionet_capable) | |
509 | - goto out; | |
515 | + if (netid >= RIONET_MAX_NETS) | |
516 | + return rc; | |
510 | 517 | |
511 | - /* Allocate our net_device structure */ | |
512 | - ndev = alloc_etherdev(sizeof(struct rionet_private)); | |
513 | - if (ndev == NULL) { | |
514 | - rc = -ENOMEM; | |
515 | - goto out; | |
516 | - } | |
518 | + oldnet = test_and_set_bit(netid, net_table); | |
517 | 519 | |
518 | 520 | /* |
519 | 521 | * First time through, make sure local device is rionet |
520 | - * capable, setup netdev, and set flags so this is skipped | |
521 | - * on later probes | |
522 | + * capable, setup netdev (will be skipped on later probes) | |
522 | 523 | */ |
523 | - if (!rionet_check) { | |
524 | + if (!oldnet) { | |
524 | 525 | rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, |
525 | 526 | &lsrc_ops); |
526 | 527 | rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, |
527 | 528 | &ldst_ops); |
528 | 529 | if (!is_rionet_capable(lsrc_ops, ldst_ops)) { |
529 | 530 | printk(KERN_ERR |
530 | - "%s: local device is not network capable\n", | |
531 | - DRV_NAME); | |
532 | - rionet_check = 1; | |
533 | - rionet_capable = 0; | |
531 | + "%s: local device %s is not network capable\n", | |
532 | + DRV_NAME, rdev->net->hport->name); | |
534 | 533 | goto out; |
535 | 534 | } |
536 | 535 | |
536 | + /* Allocate our net_device structure */ | |
537 | + ndev = alloc_etherdev(sizeof(struct rionet_private)); | |
538 | + if (ndev == NULL) { | |
539 | + rc = -ENOMEM; | |
540 | + goto out; | |
541 | + } | |
542 | + nets[netid].ndev = ndev; | |
537 | 543 | rc = rionet_setup_netdev(rdev->net->hport, ndev); |
538 | - rionet_check = 1; | |
539 | - nact = 0; | |
540 | - } | |
544 | + INIT_LIST_HEAD(&nets[netid].peers); | |
545 | + nets[netid].nact = 0; | |
546 | + } else if (nets[netid].ndev == NULL) | |
547 | + goto out; | |
541 | 548 | |
542 | 549 | /* |
543 | 550 | * If the remote device has mailbox/doorbell capabilities, |
544 | 551 | |
... | ... | @@ -549,10 +556,10 @@ |
549 | 556 | goto out; |
550 | 557 | } |
551 | 558 | peer->rdev = rdev; |
552 | - list_add_tail(&peer->node, &rionet_peers); | |
559 | + list_add_tail(&peer->node, &nets[netid].peers); | |
553 | 560 | } |
554 | 561 | |
555 | - rio_set_drvdata(rdev, ndev); | |
562 | + rio_set_drvdata(rdev, nets[netid].ndev); | |
556 | 563 | |
557 | 564 | out: |
558 | 565 | return rc; |