diff options
Diffstat (limited to 'drivers/net/rionet.c')
-rw-r--r-- | drivers/net/rionet.c | 141 |
1 files changed, 81 insertions, 60 deletions
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 91d25888a1b9..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,16 +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 | 79 | ||
83 | #define is_rionet_capable(src_ops, dst_ops) \ | 80 | #define is_rionet_capable(src_ops, dst_ops) \ |
84 | ((src_ops & RIO_SRC_OPS_DATA_MSG) && \ | 81 | ((src_ops & RIO_SRC_OPS_DATA_MSG) && \ |
@@ -175,6 +172,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
175 | struct ethhdr *eth = (struct ethhdr *)skb->data; | 172 | struct ethhdr *eth = (struct ethhdr *)skb->data; |
176 | u16 destid; | 173 | u16 destid; |
177 | unsigned long flags; | 174 | unsigned long flags; |
175 | int add_num = 1; | ||
178 | 176 | ||
179 | local_irq_save(flags); | 177 | local_irq_save(flags); |
180 | if (!spin_trylock(&rnet->tx_lock)) { | 178 | if (!spin_trylock(&rnet->tx_lock)) { |
@@ -182,7 +180,10 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
182 | return NETDEV_TX_LOCKED; | 180 | return NETDEV_TX_LOCKED; |
183 | } | 181 | } |
184 | 182 | ||
185 | if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) { | 183 | if (is_multicast_ether_addr(eth->h_dest)) |
184 | add_num = nets[rnet->mport->id].nact; | ||
185 | |||
186 | if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) { | ||
186 | netif_stop_queue(ndev); | 187 | netif_stop_queue(ndev); |
187 | spin_unlock_irqrestore(&rnet->tx_lock, flags); | 188 | spin_unlock_irqrestore(&rnet->tx_lock, flags); |
188 | printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", | 189 | printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", |
@@ -191,15 +192,22 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
191 | } | 192 | } |
192 | 193 | ||
193 | if (is_multicast_ether_addr(eth->h_dest)) { | 194 | if (is_multicast_ether_addr(eth->h_dest)) { |
195 | int count = 0; | ||
196 | |||
194 | 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); |
195 | i++) | 198 | i++) |
196 | if (rionet_active[i]) | 199 | if (nets[rnet->mport->id].active[i]) { |
197 | rionet_queue_tx_msg(skb, ndev, | 200 | rionet_queue_tx_msg(skb, ndev, |
198 | rionet_active[i]); | 201 | nets[rnet->mport->id].active[i]); |
202 | if (count) | ||
203 | atomic_inc(&skb->users); | ||
204 | count++; | ||
205 | } | ||
199 | } else if (RIONET_MAC_MATCH(eth->h_dest)) { | 206 | } else if (RIONET_MAC_MATCH(eth->h_dest)) { |
200 | destid = RIONET_GET_DESTID(eth->h_dest); | 207 | destid = RIONET_GET_DESTID(eth->h_dest); |
201 | if (rionet_active[destid]) | 208 | if (nets[rnet->mport->id].active[destid]) |
202 | rionet_queue_tx_msg(skb, ndev, rionet_active[destid]); | 209 | rionet_queue_tx_msg(skb, ndev, |
210 | nets[rnet->mport->id].active[destid]); | ||
203 | } | 211 | } |
204 | 212 | ||
205 | spin_unlock_irqrestore(&rnet->tx_lock, flags); | 213 | spin_unlock_irqrestore(&rnet->tx_lock, flags); |
@@ -218,16 +226,21 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u | |||
218 | 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", |
219 | DRV_NAME, sid, tid, info); | 227 | DRV_NAME, sid, tid, info); |
220 | if (info == RIONET_DOORBELL_JOIN) { | 228 | if (info == RIONET_DOORBELL_JOIN) { |
221 | if (!rionet_active[sid]) { | 229 | if (!nets[rnet->mport->id].active[sid]) { |
222 | list_for_each_entry(peer, &rionet_peers, node) { | 230 | list_for_each_entry(peer, |
223 | if (peer->rdev->destid == sid) | 231 | &nets[rnet->mport->id].peers, node) { |
224 | rionet_active[sid] = peer->rdev; | 232 | if (peer->rdev->destid == sid) { |
233 | nets[rnet->mport->id].active[sid] = | ||
234 | peer->rdev; | ||
235 | nets[rnet->mport->id].nact++; | ||
236 | } | ||
225 | } | 237 | } |
226 | rio_mport_send_doorbell(mport, sid, | 238 | rio_mport_send_doorbell(mport, sid, |
227 | RIONET_DOORBELL_JOIN); | 239 | RIONET_DOORBELL_JOIN); |
228 | } | 240 | } |
229 | } else if (info == RIONET_DOORBELL_LEAVE) { | 241 | } else if (info == RIONET_DOORBELL_LEAVE) { |
230 | rionet_active[sid] = NULL; | 242 | nets[rnet->mport->id].active[sid] = NULL; |
243 | nets[rnet->mport->id].nact--; | ||
231 | } else { | 244 | } else { |
232 | if (netif_msg_intr(rnet)) | 245 | if (netif_msg_intr(rnet)) |
233 | printk(KERN_WARNING "%s: unhandled doorbell\n", | 246 | printk(KERN_WARNING "%s: unhandled doorbell\n", |
@@ -321,7 +334,8 @@ static int rionet_open(struct net_device *ndev) | |||
321 | netif_carrier_on(ndev); | 334 | netif_carrier_on(ndev); |
322 | netif_start_queue(ndev); | 335 | netif_start_queue(ndev); |
323 | 336 | ||
324 | 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) { | ||
325 | if (!(peer->res = rio_request_outb_dbell(peer->rdev, | 339 | if (!(peer->res = rio_request_outb_dbell(peer->rdev, |
326 | RIONET_DOORBELL_JOIN, | 340 | RIONET_DOORBELL_JOIN, |
327 | RIONET_DOORBELL_LEAVE))) | 341 | RIONET_DOORBELL_LEAVE))) |
@@ -346,7 +360,7 @@ static int rionet_close(struct net_device *ndev) | |||
346 | int i; | 360 | int i; |
347 | 361 | ||
348 | if (netif_msg_ifup(rnet)) | 362 | if (netif_msg_ifup(rnet)) |
349 | printk(KERN_INFO "%s: close\n", DRV_NAME); | 363 | printk(KERN_INFO "%s: close %s\n", DRV_NAME, ndev->name); |
350 | 364 | ||
351 | netif_stop_queue(ndev); | 365 | netif_stop_queue(ndev); |
352 | netif_carrier_off(ndev); | 366 | netif_carrier_off(ndev); |
@@ -354,10 +368,11 @@ static int rionet_close(struct net_device *ndev) | |||
354 | for (i = 0; i < RIONET_RX_RING_SIZE; i++) | 368 | for (i = 0; i < RIONET_RX_RING_SIZE; i++) |
355 | kfree_skb(rnet->rx_skb[i]); | 369 | kfree_skb(rnet->rx_skb[i]); |
356 | 370 | ||
357 | list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { | 371 | list_for_each_entry_safe(peer, tmp, |
358 | if (rionet_active[peer->rdev->destid]) { | 372 | &nets[rnet->mport->id].peers, node) { |
373 | if (nets[rnet->mport->id].active[peer->rdev->destid]) { | ||
359 | rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); | 374 | rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); |
360 | rionet_active[peer->rdev->destid] = NULL; | 375 | nets[rnet->mport->id].active[peer->rdev->destid] = NULL; |
361 | } | 376 | } |
362 | rio_release_outb_dbell(peer->rdev, peer->res); | 377 | rio_release_outb_dbell(peer->rdev, peer->res); |
363 | } | 378 | } |
@@ -373,17 +388,21 @@ static int rionet_close(struct net_device *ndev) | |||
373 | static void rionet_remove(struct rio_dev *rdev) | 388 | static void rionet_remove(struct rio_dev *rdev) |
374 | { | 389 | { |
375 | 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; | ||
376 | struct rionet_peer *peer, *tmp; | 392 | struct rionet_peer *peer, *tmp; |
377 | 393 | ||
378 | free_pages((unsigned long)rionet_active, get_order(sizeof(void *) * | ||
379 | RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size))); | ||
380 | unregister_netdev(ndev); | 394 | unregister_netdev(ndev); |
381 | free_netdev(ndev); | ||
382 | 395 | ||
383 | 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) { | ||
384 | list_del(&peer->node); | 401 | list_del(&peer->node); |
385 | kfree(peer); | 402 | kfree(peer); |
386 | } | 403 | } |
404 | |||
405 | free_netdev(ndev); | ||
387 | } | 406 | } |
388 | 407 | ||
389 | static void rionet_get_drvinfo(struct net_device *ndev, | 408 | static void rionet_get_drvinfo(struct net_device *ndev, |
@@ -435,13 +454,13 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) | |||
435 | const size_t rionet_active_bytes = sizeof(void *) * | 454 | const size_t rionet_active_bytes = sizeof(void *) * |
436 | RIO_MAX_ROUTE_ENTRIES(mport->sys_size); | 455 | RIO_MAX_ROUTE_ENTRIES(mport->sys_size); |
437 | 456 | ||
438 | rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, | 457 | nets[mport->id].active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, |
439 | get_order(rionet_active_bytes)); | 458 | get_order(rionet_active_bytes)); |
440 | if (!rionet_active) { | 459 | if (!nets[mport->id].active) { |
441 | rc = -ENOMEM; | 460 | rc = -ENOMEM; |
442 | goto out; | 461 | goto out; |
443 | } | 462 | } |
444 | memset((void *)rionet_active, 0, rionet_active_bytes); | 463 | memset((void *)nets[mport->id].active, 0, rionet_active_bytes); |
445 | 464 | ||
446 | /* Set up private area */ | 465 | /* Set up private area */ |
447 | rnet = netdev_priv(ndev); | 466 | rnet = netdev_priv(ndev); |
@@ -470,60 +489,62 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) | |||
470 | if (rc != 0) | 489 | if (rc != 0) |
471 | goto out; | 490 | goto out; |
472 | 491 | ||
473 | printk("%s: %s %s Version %s, MAC %pM\n", | 492 | printk(KERN_INFO "%s: %s %s Version %s, MAC %pM, %s\n", |
474 | ndev->name, | 493 | ndev->name, |
475 | DRV_NAME, | 494 | DRV_NAME, |
476 | DRV_DESC, | 495 | DRV_DESC, |
477 | DRV_VERSION, | 496 | DRV_VERSION, |
478 | ndev->dev_addr); | 497 | ndev->dev_addr, |
498 | mport->name); | ||
479 | 499 | ||
480 | out: | 500 | out: |
481 | return rc; | 501 | return rc; |
482 | } | 502 | } |
483 | 503 | ||
484 | /* | 504 | static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1]; |
485 | * XXX Make multi-net safe | 505 | |
486 | */ | ||
487 | 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) |
488 | { | 507 | { |
489 | int rc = -ENODEV; | 508 | int rc = -ENODEV; |
490 | u32 lsrc_ops, ldst_ops; | 509 | u32 lsrc_ops, ldst_ops; |
491 | struct rionet_peer *peer; | 510 | struct rionet_peer *peer; |
492 | struct net_device *ndev = NULL; | 511 | struct net_device *ndev = NULL; |
512 | unsigned char netid = rdev->net->hport->id; | ||
513 | int oldnet; | ||
493 | 514 | ||
494 | /* If local device is not rionet capable, give up quickly */ | 515 | if (netid >= RIONET_MAX_NETS) |
495 | if (!rionet_capable) | 516 | return rc; |
496 | goto out; | ||
497 | 517 | ||
498 | /* Allocate our net_device structure */ | 518 | oldnet = test_and_set_bit(netid, net_table); |
499 | ndev = alloc_etherdev(sizeof(struct rionet_private)); | ||
500 | if (ndev == NULL) { | ||
501 | rc = -ENOMEM; | ||
502 | goto out; | ||
503 | } | ||
504 | 519 | ||
505 | /* | 520 | /* |
506 | * First time through, make sure local device is rionet | 521 | * First time through, make sure local device is rionet |
507 | * capable, setup netdev, and set flags so this is skipped | 522 | * capable, setup netdev (will be skipped on later probes) |
508 | * on later probes | ||
509 | */ | 523 | */ |
510 | if (!rionet_check) { | 524 | if (!oldnet) { |
511 | 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, |
512 | &lsrc_ops); | 526 | &lsrc_ops); |
513 | 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, |
514 | &ldst_ops); | 528 | &ldst_ops); |
515 | if (!is_rionet_capable(lsrc_ops, ldst_ops)) { | 529 | if (!is_rionet_capable(lsrc_ops, ldst_ops)) { |
516 | printk(KERN_ERR | 530 | printk(KERN_ERR |
517 | "%s: local device is not network capable\n", | 531 | "%s: local device %s is not network capable\n", |
518 | DRV_NAME); | 532 | DRV_NAME, rdev->net->hport->name); |
519 | rionet_check = 1; | ||
520 | rionet_capable = 0; | ||
521 | goto out; | 533 | goto out; |
522 | } | 534 | } |
523 | 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; | ||
524 | rc = rionet_setup_netdev(rdev->net->hport, ndev); | 543 | rc = rionet_setup_netdev(rdev->net->hport, ndev); |
525 | rionet_check = 1; | 544 | INIT_LIST_HEAD(&nets[netid].peers); |
526 | } | 545 | nets[netid].nact = 0; |
546 | } else if (nets[netid].ndev == NULL) | ||
547 | goto out; | ||
527 | 548 | ||
528 | /* | 549 | /* |
529 | * If the remote device has mailbox/doorbell capabilities, | 550 | * If the remote device has mailbox/doorbell capabilities, |
@@ -535,10 +556,10 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) | |||
535 | goto out; | 556 | goto out; |
536 | } | 557 | } |
537 | peer->rdev = rdev; | 558 | peer->rdev = rdev; |
538 | list_add_tail(&peer->node, &rionet_peers); | 559 | list_add_tail(&peer->node, &nets[netid].peers); |
539 | } | 560 | } |
540 | 561 | ||
541 | rio_set_drvdata(rdev, ndev); | 562 | rio_set_drvdata(rdev, nets[netid].ndev); |
542 | 563 | ||
543 | out: | 564 | out: |
544 | return rc; | 565 | return rc; |