diff options
author | Alexandre Bounine <alexandre.bounine@idt.com> | 2012-10-04 20:16:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-05 14:05:23 -0400 |
commit | 2fb717ec3ec76b0ca4cee9c4d802ce551750413d (patch) | |
tree | e1641886b80194af8ad4c86b07e6be42fef5014b /drivers/net/rionet.c | |
parent | 005842efd1ac8ef455ebd28a8c713944863edc5a (diff) |
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>
Diffstat (limited to 'drivers/net/rionet.c')
-rw-r--r-- | drivers/net/rionet.c | 133 |
1 files changed, 70 insertions, 63 deletions
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 1470d3e86e3c..d8b9b1e8ee02 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/ethtool.h> | 26 | #include <linux/ethtool.h> |
27 | 27 | ||
28 | #define DRV_NAME "rionet" | 28 | #define DRV_NAME "rionet" |
29 | #define DRV_VERSION "0.2" | 29 | #define DRV_VERSION "0.3" |
30 | #define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>" | 30 | #define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>" |
31 | #define DRV_DESC "Ethernet over RapidIO" | 31 | #define DRV_DESC "Ethernet over RapidIO" |
32 | 32 | ||
@@ -47,8 +47,7 @@ MODULE_LICENSE("GPL"); | |||
47 | 47 | ||
48 | #define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE | 48 | #define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE |
49 | #define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE | 49 | #define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE |
50 | 50 | #define RIONET_MAX_NETS 8 | |
51 | static LIST_HEAD(rionet_peers); | ||
52 | 51 | ||
53 | struct rionet_private { | 52 | struct rionet_private { |
54 | struct rio_mport *mport; | 53 | struct rio_mport *mport; |
@@ -69,17 +68,14 @@ struct rionet_peer { | |||
69 | struct resource *res; | 68 | struct resource *res; |
70 | }; | 69 | }; |
71 | 70 | ||
72 | static int rionet_check = 0; | 71 | struct rionet_net { |
73 | static int rionet_capable = 1; | 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 | /* | 78 | static struct rionet_net nets[RIONET_MAX_NETS]; |
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 */ | ||
83 | 79 | ||
84 | #define is_rionet_capable(src_ops, dst_ops) \ | 80 | #define is_rionet_capable(src_ops, dst_ops) \ |
85 | ((src_ops & RIO_SRC_OPS_DATA_MSG) && \ | 81 | ((src_ops & RIO_SRC_OPS_DATA_MSG) && \ |
@@ -185,7 +181,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
185 | } | 181 | } |
186 | 182 | ||
187 | if (is_multicast_ether_addr(eth->h_dest)) | 183 | if (is_multicast_ether_addr(eth->h_dest)) |
188 | add_num = nact; | 184 | add_num = nets[rnet->mport->id].nact; |
189 | 185 | ||
190 | if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) { | 186 | if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) { |
191 | netif_stop_queue(ndev); | 187 | netif_stop_queue(ndev); |
@@ -197,19 +193,21 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
197 | 193 | ||
198 | if (is_multicast_ether_addr(eth->h_dest)) { | 194 | if (is_multicast_ether_addr(eth->h_dest)) { |
199 | int count = 0; | 195 | int count = 0; |
196 | |||
200 | for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size); | 197 | for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size); |
201 | i++) | 198 | i++) |
202 | if (rionet_active[i]) { | 199 | if (nets[rnet->mport->id].active[i]) { |
203 | rionet_queue_tx_msg(skb, ndev, | 200 | rionet_queue_tx_msg(skb, ndev, |
204 | rionet_active[i]); | 201 | nets[rnet->mport->id].active[i]); |
205 | if (count) | 202 | if (count) |
206 | atomic_inc(&skb->users); | 203 | atomic_inc(&skb->users); |
207 | count++; | 204 | count++; |
208 | } | 205 | } |
209 | } else if (RIONET_MAC_MATCH(eth->h_dest)) { | 206 | } else if (RIONET_MAC_MATCH(eth->h_dest)) { |
210 | destid = RIONET_GET_DESTID(eth->h_dest); | 207 | destid = RIONET_GET_DESTID(eth->h_dest); |
211 | if (rionet_active[destid]) | 208 | if (nets[rnet->mport->id].active[destid]) |
212 | rionet_queue_tx_msg(skb, ndev, rionet_active[destid]); | 209 | rionet_queue_tx_msg(skb, ndev, |
210 | nets[rnet->mport->id].active[destid]); | ||
213 | } | 211 | } |
214 | 212 | ||
215 | spin_unlock_irqrestore(&rnet->tx_lock, flags); | 213 | spin_unlock_irqrestore(&rnet->tx_lock, flags); |
@@ -228,19 +226,21 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u | |||
228 | printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", | 226 | printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", |
229 | DRV_NAME, sid, tid, info); | 227 | DRV_NAME, sid, tid, info); |
230 | if (info == RIONET_DOORBELL_JOIN) { | 228 | if (info == RIONET_DOORBELL_JOIN) { |
231 | if (!rionet_active[sid]) { | 229 | if (!nets[rnet->mport->id].active[sid]) { |
232 | list_for_each_entry(peer, &rionet_peers, node) { | 230 | list_for_each_entry(peer, |
231 | &nets[rnet->mport->id].peers, node) { | ||
233 | if (peer->rdev->destid == sid) { | 232 | if (peer->rdev->destid == sid) { |
234 | rionet_active[sid] = peer->rdev; | 233 | nets[rnet->mport->id].active[sid] = |
235 | nact++; | 234 | peer->rdev; |
235 | nets[rnet->mport->id].nact++; | ||
236 | } | 236 | } |
237 | } | 237 | } |
238 | rio_mport_send_doorbell(mport, sid, | 238 | rio_mport_send_doorbell(mport, sid, |
239 | RIONET_DOORBELL_JOIN); | 239 | RIONET_DOORBELL_JOIN); |
240 | } | 240 | } |
241 | } else if (info == RIONET_DOORBELL_LEAVE) { | 241 | } else if (info == RIONET_DOORBELL_LEAVE) { |
242 | rionet_active[sid] = NULL; | 242 | nets[rnet->mport->id].active[sid] = NULL; |
243 | nact--; | 243 | nets[rnet->mport->id].nact--; |
244 | } else { | 244 | } else { |
245 | if (netif_msg_intr(rnet)) | 245 | if (netif_msg_intr(rnet)) |
246 | printk(KERN_WARNING "%s: unhandled doorbell\n", | 246 | printk(KERN_WARNING "%s: unhandled doorbell\n", |
@@ -334,7 +334,8 @@ static int rionet_open(struct net_device *ndev) | |||
334 | netif_carrier_on(ndev); | 334 | netif_carrier_on(ndev); |
335 | netif_start_queue(ndev); | 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 | if (!(peer->res = rio_request_outb_dbell(peer->rdev, | 339 | if (!(peer->res = rio_request_outb_dbell(peer->rdev, |
339 | RIONET_DOORBELL_JOIN, | 340 | RIONET_DOORBELL_JOIN, |
340 | RIONET_DOORBELL_LEAVE))) | 341 | RIONET_DOORBELL_LEAVE))) |
@@ -359,7 +360,7 @@ static int rionet_close(struct net_device *ndev) | |||
359 | int i; | 360 | int i; |
360 | 361 | ||
361 | if (netif_msg_ifup(rnet)) | 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 | netif_stop_queue(ndev); | 365 | netif_stop_queue(ndev); |
365 | netif_carrier_off(ndev); | 366 | netif_carrier_off(ndev); |
@@ -367,10 +368,11 @@ static int rionet_close(struct net_device *ndev) | |||
367 | for (i = 0; i < RIONET_RX_RING_SIZE; i++) | 368 | for (i = 0; i < RIONET_RX_RING_SIZE; i++) |
368 | kfree_skb(rnet->rx_skb[i]); | 369 | kfree_skb(rnet->rx_skb[i]); |
369 | 370 | ||
370 | list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { | 371 | list_for_each_entry_safe(peer, tmp, |
371 | if (rionet_active[peer->rdev->destid]) { | 372 | &nets[rnet->mport->id].peers, node) { |
373 | if (nets[rnet->mport->id].active[peer->rdev->destid]) { | ||
372 | rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); | 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 | rio_release_outb_dbell(peer->rdev, peer->res); | 377 | rio_release_outb_dbell(peer->rdev, peer->res); |
376 | } | 378 | } |
@@ -386,17 +388,21 @@ static int rionet_close(struct net_device *ndev) | |||
386 | static void rionet_remove(struct rio_dev *rdev) | 388 | static void rionet_remove(struct rio_dev *rdev) |
387 | { | 389 | { |
388 | struct net_device *ndev = rio_get_drvdata(rdev); | 390 | struct net_device *ndev = rio_get_drvdata(rdev); |
391 | unsigned char netid = rdev->net->hport->id; | ||
389 | struct rionet_peer *peer, *tmp; | 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 | unregister_netdev(ndev); | 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 | list_del(&peer->node); | 401 | list_del(&peer->node); |
398 | kfree(peer); | 402 | kfree(peer); |
399 | } | 403 | } |
404 | |||
405 | free_netdev(ndev); | ||
400 | } | 406 | } |
401 | 407 | ||
402 | static void rionet_get_drvinfo(struct net_device *ndev, | 408 | static void rionet_get_drvinfo(struct net_device *ndev, |
@@ -448,13 +454,13 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) | |||
448 | const size_t rionet_active_bytes = sizeof(void *) * | 454 | const size_t rionet_active_bytes = sizeof(void *) * |
449 | RIO_MAX_ROUTE_ENTRIES(mport->sys_size); | 455 | RIO_MAX_ROUTE_ENTRIES(mport->sys_size); |
450 | 456 | ||
451 | rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, | 457 | nets[mport->id].active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, |
452 | get_order(rionet_active_bytes)); | 458 | get_order(rionet_active_bytes)); |
453 | if (!rionet_active) { | 459 | if (!nets[mport->id].active) { |
454 | rc = -ENOMEM; | 460 | rc = -ENOMEM; |
455 | goto out; | 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 | /* Set up private area */ | 465 | /* Set up private area */ |
460 | rnet = netdev_priv(ndev); | 466 | rnet = netdev_priv(ndev); |
@@ -483,61 +489,62 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) | |||
483 | if (rc != 0) | 489 | if (rc != 0) |
484 | goto out; | 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 | ndev->name, | 493 | ndev->name, |
488 | DRV_NAME, | 494 | DRV_NAME, |
489 | DRV_DESC, | 495 | DRV_DESC, |
490 | DRV_VERSION, | 496 | DRV_VERSION, |
491 | ndev->dev_addr); | 497 | ndev->dev_addr, |
498 | mport->name); | ||
492 | 499 | ||
493 | out: | 500 | out: |
494 | return rc; | 501 | return rc; |
495 | } | 502 | } |
496 | 503 | ||
497 | /* | 504 | static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1]; |
498 | * XXX Make multi-net safe | 505 | |
499 | */ | ||
500 | static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) | 506 | static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) |
501 | { | 507 | { |
502 | int rc = -ENODEV; | 508 | int rc = -ENODEV; |
503 | u32 lsrc_ops, ldst_ops; | 509 | u32 lsrc_ops, ldst_ops; |
504 | struct rionet_peer *peer; | 510 | struct rionet_peer *peer; |
505 | struct net_device *ndev = NULL; | 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 */ | 515 | if (netid >= RIONET_MAX_NETS) |
508 | if (!rionet_capable) | 516 | return rc; |
509 | goto out; | ||
510 | 517 | ||
511 | /* Allocate our net_device structure */ | 518 | oldnet = test_and_set_bit(netid, net_table); |
512 | ndev = alloc_etherdev(sizeof(struct rionet_private)); | ||
513 | if (ndev == NULL) { | ||
514 | rc = -ENOMEM; | ||
515 | goto out; | ||
516 | } | ||
517 | 519 | ||
518 | /* | 520 | /* |
519 | * First time through, make sure local device is rionet | 521 | * First time through, make sure local device is rionet |
520 | * capable, setup netdev, and set flags so this is skipped | 522 | * capable, setup netdev (will be skipped on later probes) |
521 | * on later probes | ||
522 | */ | 523 | */ |
523 | if (!rionet_check) { | 524 | if (!oldnet) { |
524 | rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, | 525 | rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, |
525 | &lsrc_ops); | 526 | &lsrc_ops); |
526 | rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, | 527 | rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, |
527 | &ldst_ops); | 528 | &ldst_ops); |
528 | if (!is_rionet_capable(lsrc_ops, ldst_ops)) { | 529 | if (!is_rionet_capable(lsrc_ops, ldst_ops)) { |
529 | printk(KERN_ERR | 530 | printk(KERN_ERR |
530 | "%s: local device is not network capable\n", | 531 | "%s: local device %s is not network capable\n", |
531 | DRV_NAME); | 532 | DRV_NAME, rdev->net->hport->name); |
532 | rionet_check = 1; | ||
533 | rionet_capable = 0; | ||
534 | goto out; | 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 | rc = rionet_setup_netdev(rdev->net->hport, ndev); | 543 | rc = rionet_setup_netdev(rdev->net->hport, ndev); |
538 | rionet_check = 1; | 544 | INIT_LIST_HEAD(&nets[netid].peers); |
539 | nact = 0; | 545 | nets[netid].nact = 0; |
540 | } | 546 | } else if (nets[netid].ndev == NULL) |
547 | goto out; | ||
541 | 548 | ||
542 | /* | 549 | /* |
543 | * If the remote device has mailbox/doorbell capabilities, | 550 | * If the remote device has mailbox/doorbell capabilities, |
@@ -549,10 +556,10 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) | |||
549 | goto out; | 556 | goto out; |
550 | } | 557 | } |
551 | peer->rdev = rdev; | 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 | out: | 564 | out: |
558 | return rc; | 565 | return rc; |