diff options
Diffstat (limited to 'drivers/net/rionet.c')
-rw-r--r-- | drivers/net/rionet.c | 152 |
1 files changed, 102 insertions, 50 deletions
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index f994fa1fde2f..c15d9581dd56 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c | |||
@@ -63,6 +63,7 @@ struct rionet_private { | |||
63 | spinlock_t lock; | 63 | spinlock_t lock; |
64 | spinlock_t tx_lock; | 64 | spinlock_t tx_lock; |
65 | u32 msg_enable; | 65 | u32 msg_enable; |
66 | bool open; | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | struct rionet_peer { | 69 | struct rionet_peer { |
@@ -74,6 +75,7 @@ struct rionet_peer { | |||
74 | struct rionet_net { | 75 | struct rionet_net { |
75 | struct net_device *ndev; | 76 | struct net_device *ndev; |
76 | struct list_head peers; | 77 | struct list_head peers; |
78 | spinlock_t lock; /* net info access lock */ | ||
77 | struct rio_dev **active; | 79 | struct rio_dev **active; |
78 | int nact; /* number of active peers */ | 80 | int nact; /* number of active peers */ |
79 | }; | 81 | }; |
@@ -235,26 +237,32 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u | |||
235 | struct net_device *ndev = dev_id; | 237 | struct net_device *ndev = dev_id; |
236 | struct rionet_private *rnet = netdev_priv(ndev); | 238 | struct rionet_private *rnet = netdev_priv(ndev); |
237 | struct rionet_peer *peer; | 239 | struct rionet_peer *peer; |
240 | unsigned char netid = rnet->mport->id; | ||
238 | 241 | ||
239 | if (netif_msg_intr(rnet)) | 242 | if (netif_msg_intr(rnet)) |
240 | printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", | 243 | printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", |
241 | DRV_NAME, sid, tid, info); | 244 | DRV_NAME, sid, tid, info); |
242 | if (info == RIONET_DOORBELL_JOIN) { | 245 | if (info == RIONET_DOORBELL_JOIN) { |
243 | if (!nets[rnet->mport->id].active[sid]) { | 246 | if (!nets[netid].active[sid]) { |
244 | list_for_each_entry(peer, | 247 | spin_lock(&nets[netid].lock); |
245 | &nets[rnet->mport->id].peers, node) { | 248 | list_for_each_entry(peer, &nets[netid].peers, node) { |
246 | if (peer->rdev->destid == sid) { | 249 | if (peer->rdev->destid == sid) { |
247 | nets[rnet->mport->id].active[sid] = | 250 | nets[netid].active[sid] = peer->rdev; |
248 | peer->rdev; | 251 | nets[netid].nact++; |
249 | nets[rnet->mport->id].nact++; | ||
250 | } | 252 | } |
251 | } | 253 | } |
254 | spin_unlock(&nets[netid].lock); | ||
255 | |||
252 | rio_mport_send_doorbell(mport, sid, | 256 | rio_mport_send_doorbell(mport, sid, |
253 | RIONET_DOORBELL_JOIN); | 257 | RIONET_DOORBELL_JOIN); |
254 | } | 258 | } |
255 | } else if (info == RIONET_DOORBELL_LEAVE) { | 259 | } else if (info == RIONET_DOORBELL_LEAVE) { |
256 | nets[rnet->mport->id].active[sid] = NULL; | 260 | spin_lock(&nets[netid].lock); |
257 | nets[rnet->mport->id].nact--; | 261 | if (nets[netid].active[sid]) { |
262 | nets[netid].active[sid] = NULL; | ||
263 | nets[netid].nact--; | ||
264 | } | ||
265 | spin_unlock(&nets[netid].lock); | ||
258 | } else { | 266 | } else { |
259 | if (netif_msg_intr(rnet)) | 267 | if (netif_msg_intr(rnet)) |
260 | printk(KERN_WARNING "%s: unhandled doorbell\n", | 268 | printk(KERN_WARNING "%s: unhandled doorbell\n", |
@@ -308,8 +316,10 @@ static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbo | |||
308 | static int rionet_open(struct net_device *ndev) | 316 | static int rionet_open(struct net_device *ndev) |
309 | { | 317 | { |
310 | int i, rc = 0; | 318 | int i, rc = 0; |
311 | struct rionet_peer *peer, *tmp; | 319 | struct rionet_peer *peer; |
312 | struct rionet_private *rnet = netdev_priv(ndev); | 320 | struct rionet_private *rnet = netdev_priv(ndev); |
321 | unsigned char netid = rnet->mport->id; | ||
322 | unsigned long flags; | ||
313 | 323 | ||
314 | if (netif_msg_ifup(rnet)) | 324 | if (netif_msg_ifup(rnet)) |
315 | printk(KERN_INFO "%s: open\n", DRV_NAME); | 325 | printk(KERN_INFO "%s: open\n", DRV_NAME); |
@@ -348,20 +358,13 @@ static int rionet_open(struct net_device *ndev) | |||
348 | netif_carrier_on(ndev); | 358 | netif_carrier_on(ndev); |
349 | netif_start_queue(ndev); | 359 | netif_start_queue(ndev); |
350 | 360 | ||
351 | list_for_each_entry_safe(peer, tmp, | 361 | spin_lock_irqsave(&nets[netid].lock, flags); |
352 | &nets[rnet->mport->id].peers, node) { | 362 | list_for_each_entry(peer, &nets[netid].peers, node) { |
353 | if (!(peer->res = rio_request_outb_dbell(peer->rdev, | ||
354 | RIONET_DOORBELL_JOIN, | ||
355 | RIONET_DOORBELL_LEAVE))) | ||
356 | { | ||
357 | printk(KERN_ERR "%s: error requesting doorbells\n", | ||
358 | DRV_NAME); | ||
359 | continue; | ||
360 | } | ||
361 | |||
362 | /* Send a join message */ | 363 | /* Send a join message */ |
363 | rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN); | 364 | rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN); |
364 | } | 365 | } |
366 | spin_unlock_irqrestore(&nets[netid].lock, flags); | ||
367 | rnet->open = true; | ||
365 | 368 | ||
366 | out: | 369 | out: |
367 | return rc; | 370 | return rc; |
@@ -370,7 +373,9 @@ static int rionet_open(struct net_device *ndev) | |||
370 | static int rionet_close(struct net_device *ndev) | 373 | static int rionet_close(struct net_device *ndev) |
371 | { | 374 | { |
372 | struct rionet_private *rnet = netdev_priv(ndev); | 375 | struct rionet_private *rnet = netdev_priv(ndev); |
373 | struct rionet_peer *peer, *tmp; | 376 | struct rionet_peer *peer; |
377 | unsigned char netid = rnet->mport->id; | ||
378 | unsigned long flags; | ||
374 | int i; | 379 | int i; |
375 | 380 | ||
376 | if (netif_msg_ifup(rnet)) | 381 | if (netif_msg_ifup(rnet)) |
@@ -378,18 +383,21 @@ static int rionet_close(struct net_device *ndev) | |||
378 | 383 | ||
379 | netif_stop_queue(ndev); | 384 | netif_stop_queue(ndev); |
380 | netif_carrier_off(ndev); | 385 | netif_carrier_off(ndev); |
386 | rnet->open = false; | ||
381 | 387 | ||
382 | for (i = 0; i < RIONET_RX_RING_SIZE; i++) | 388 | for (i = 0; i < RIONET_RX_RING_SIZE; i++) |
383 | kfree_skb(rnet->rx_skb[i]); | 389 | kfree_skb(rnet->rx_skb[i]); |
384 | 390 | ||
385 | list_for_each_entry_safe(peer, tmp, | 391 | spin_lock_irqsave(&nets[netid].lock, flags); |
386 | &nets[rnet->mport->id].peers, node) { | 392 | list_for_each_entry(peer, &nets[netid].peers, node) { |
387 | if (nets[rnet->mport->id].active[peer->rdev->destid]) { | 393 | if (nets[netid].active[peer->rdev->destid]) { |
388 | rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); | 394 | rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); |
389 | nets[rnet->mport->id].active[peer->rdev->destid] = NULL; | 395 | nets[netid].active[peer->rdev->destid] = NULL; |
390 | } | 396 | } |
391 | rio_release_outb_dbell(peer->rdev, peer->res); | 397 | if (peer->res) |
398 | rio_release_outb_dbell(peer->rdev, peer->res); | ||
392 | } | 399 | } |
400 | spin_unlock_irqrestore(&nets[netid].lock, flags); | ||
393 | 401 | ||
394 | rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN, | 402 | rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN, |
395 | RIONET_DOORBELL_LEAVE); | 403 | RIONET_DOORBELL_LEAVE); |
@@ -403,22 +411,38 @@ static void rionet_remove_dev(struct device *dev, struct subsys_interface *sif) | |||
403 | { | 411 | { |
404 | struct rio_dev *rdev = to_rio_dev(dev); | 412 | struct rio_dev *rdev = to_rio_dev(dev); |
405 | unsigned char netid = rdev->net->hport->id; | 413 | unsigned char netid = rdev->net->hport->id; |
406 | struct rionet_peer *peer, *tmp; | 414 | struct rionet_peer *peer; |
415 | int state, found = 0; | ||
416 | unsigned long flags; | ||
407 | 417 | ||
408 | if (dev_rionet_capable(rdev)) { | 418 | if (!dev_rionet_capable(rdev)) |
409 | list_for_each_entry_safe(peer, tmp, &nets[netid].peers, node) { | 419 | return; |
410 | if (peer->rdev == rdev) { | 420 | |
411 | if (nets[netid].active[rdev->destid]) { | 421 | spin_lock_irqsave(&nets[netid].lock, flags); |
412 | nets[netid].active[rdev->destid] = NULL; | 422 | list_for_each_entry(peer, &nets[netid].peers, node) { |
413 | nets[netid].nact--; | 423 | if (peer->rdev == rdev) { |
424 | list_del(&peer->node); | ||
425 | if (nets[netid].active[rdev->destid]) { | ||
426 | state = atomic_read(&rdev->state); | ||
427 | if (state != RIO_DEVICE_GONE && | ||
428 | state != RIO_DEVICE_INITIALIZING) { | ||
429 | rio_send_doorbell(rdev, | ||
430 | RIONET_DOORBELL_LEAVE); | ||
414 | } | 431 | } |
415 | 432 | nets[netid].active[rdev->destid] = NULL; | |
416 | list_del(&peer->node); | 433 | nets[netid].nact--; |
417 | kfree(peer); | ||
418 | break; | ||
419 | } | 434 | } |
435 | found = 1; | ||
436 | break; | ||
420 | } | 437 | } |
421 | } | 438 | } |
439 | spin_unlock_irqrestore(&nets[netid].lock, flags); | ||
440 | |||
441 | if (found) { | ||
442 | if (peer->res) | ||
443 | rio_release_outb_dbell(rdev, peer->res); | ||
444 | kfree(peer); | ||
445 | } | ||
422 | } | 446 | } |
423 | 447 | ||
424 | static void rionet_get_drvinfo(struct net_device *ndev, | 448 | static void rionet_get_drvinfo(struct net_device *ndev, |
@@ -492,6 +516,7 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) | |||
492 | /* Set up private area */ | 516 | /* Set up private area */ |
493 | rnet = netdev_priv(ndev); | 517 | rnet = netdev_priv(ndev); |
494 | rnet->mport = mport; | 518 | rnet->mport = mport; |
519 | rnet->open = false; | ||
495 | 520 | ||
496 | /* Set the default MAC address */ | 521 | /* Set the default MAC address */ |
497 | device_id = rio_local_get_device_id(mport); | 522 | device_id = rio_local_get_device_id(mport); |
@@ -514,8 +539,11 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) | |||
514 | rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL; | 539 | rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL; |
515 | 540 | ||
516 | rc = register_netdev(ndev); | 541 | rc = register_netdev(ndev); |
517 | if (rc != 0) | 542 | if (rc != 0) { |
543 | free_pages((unsigned long)nets[mport->id].active, | ||
544 | get_order(rionet_active_bytes)); | ||
518 | goto out; | 545 | goto out; |
546 | } | ||
519 | 547 | ||
520 | printk(KERN_INFO "%s: %s %s Version %s, MAC %pM, %s\n", | 548 | printk(KERN_INFO "%s: %s %s Version %s, MAC %pM, %s\n", |
521 | ndev->name, | 549 | ndev->name, |
@@ -529,8 +557,6 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) | |||
529 | return rc; | 557 | return rc; |
530 | } | 558 | } |
531 | 559 | ||
532 | static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1]; | ||
533 | |||
534 | static int rionet_add_dev(struct device *dev, struct subsys_interface *sif) | 560 | static int rionet_add_dev(struct device *dev, struct subsys_interface *sif) |
535 | { | 561 | { |
536 | int rc = -ENODEV; | 562 | int rc = -ENODEV; |
@@ -539,19 +565,16 @@ static int rionet_add_dev(struct device *dev, struct subsys_interface *sif) | |||
539 | struct net_device *ndev = NULL; | 565 | struct net_device *ndev = NULL; |
540 | struct rio_dev *rdev = to_rio_dev(dev); | 566 | struct rio_dev *rdev = to_rio_dev(dev); |
541 | unsigned char netid = rdev->net->hport->id; | 567 | unsigned char netid = rdev->net->hport->id; |
542 | int oldnet; | ||
543 | 568 | ||
544 | if (netid >= RIONET_MAX_NETS) | 569 | if (netid >= RIONET_MAX_NETS) |
545 | return rc; | 570 | return rc; |
546 | 571 | ||
547 | oldnet = test_and_set_bit(netid, net_table); | ||
548 | |||
549 | /* | 572 | /* |
550 | * If first time through this net, make sure local device is rionet | 573 | * If first time through this net, make sure local device is rionet |
551 | * capable and setup netdev (this step will be skipped in later probes | 574 | * capable and setup netdev (this step will be skipped in later probes |
552 | * on the same net). | 575 | * on the same net). |
553 | */ | 576 | */ |
554 | if (!oldnet) { | 577 | if (!nets[netid].ndev) { |
555 | rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, | 578 | rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, |
556 | &lsrc_ops); | 579 | &lsrc_ops); |
557 | rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, | 580 | rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, |
@@ -569,30 +592,56 @@ static int rionet_add_dev(struct device *dev, struct subsys_interface *sif) | |||
569 | rc = -ENOMEM; | 592 | rc = -ENOMEM; |
570 | goto out; | 593 | goto out; |
571 | } | 594 | } |
572 | nets[netid].ndev = ndev; | 595 | |
573 | rc = rionet_setup_netdev(rdev->net->hport, ndev); | 596 | rc = rionet_setup_netdev(rdev->net->hport, ndev); |
574 | if (rc) { | 597 | if (rc) { |
575 | printk(KERN_ERR "%s: failed to setup netdev (rc=%d)\n", | 598 | printk(KERN_ERR "%s: failed to setup netdev (rc=%d)\n", |
576 | DRV_NAME, rc); | 599 | DRV_NAME, rc); |
600 | free_netdev(ndev); | ||
577 | goto out; | 601 | goto out; |
578 | } | 602 | } |
579 | 603 | ||
580 | INIT_LIST_HEAD(&nets[netid].peers); | 604 | INIT_LIST_HEAD(&nets[netid].peers); |
605 | spin_lock_init(&nets[netid].lock); | ||
581 | nets[netid].nact = 0; | 606 | nets[netid].nact = 0; |
582 | } else if (nets[netid].ndev == NULL) | 607 | nets[netid].ndev = ndev; |
583 | goto out; | 608 | } |
584 | 609 | ||
585 | /* | 610 | /* |
586 | * If the remote device has mailbox/doorbell capabilities, | 611 | * If the remote device has mailbox/doorbell capabilities, |
587 | * add it to the peer list. | 612 | * add it to the peer list. |
588 | */ | 613 | */ |
589 | if (dev_rionet_capable(rdev)) { | 614 | if (dev_rionet_capable(rdev)) { |
590 | if (!(peer = kmalloc(sizeof(struct rionet_peer), GFP_KERNEL))) { | 615 | struct rionet_private *rnet; |
616 | unsigned long flags; | ||
617 | |||
618 | rnet = netdev_priv(nets[netid].ndev); | ||
619 | |||
620 | peer = kzalloc(sizeof(*peer), GFP_KERNEL); | ||
621 | if (!peer) { | ||
591 | rc = -ENOMEM; | 622 | rc = -ENOMEM; |
592 | goto out; | 623 | goto out; |
593 | } | 624 | } |
594 | peer->rdev = rdev; | 625 | peer->rdev = rdev; |
626 | peer->res = rio_request_outb_dbell(peer->rdev, | ||
627 | RIONET_DOORBELL_JOIN, | ||
628 | RIONET_DOORBELL_LEAVE); | ||
629 | if (!peer->res) { | ||
630 | pr_err("%s: error requesting doorbells\n", DRV_NAME); | ||
631 | kfree(peer); | ||
632 | rc = -ENOMEM; | ||
633 | goto out; | ||
634 | } | ||
635 | |||
636 | spin_lock_irqsave(&nets[netid].lock, flags); | ||
595 | list_add_tail(&peer->node, &nets[netid].peers); | 637 | list_add_tail(&peer->node, &nets[netid].peers); |
638 | spin_unlock_irqrestore(&nets[netid].lock, flags); | ||
639 | pr_debug("%s: %s add peer %s\n", | ||
640 | DRV_NAME, __func__, rio_name(rdev)); | ||
641 | |||
642 | /* If netdev is already opened, send join request to new peer */ | ||
643 | if (rnet->open) | ||
644 | rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN); | ||
596 | } | 645 | } |
597 | 646 | ||
598 | return 0; | 647 | return 0; |
@@ -603,7 +652,8 @@ out: | |||
603 | static int rionet_shutdown(struct notifier_block *nb, unsigned long code, | 652 | static int rionet_shutdown(struct notifier_block *nb, unsigned long code, |
604 | void *unused) | 653 | void *unused) |
605 | { | 654 | { |
606 | struct rionet_peer *peer, *tmp; | 655 | struct rionet_peer *peer; |
656 | unsigned long flags; | ||
607 | int i; | 657 | int i; |
608 | 658 | ||
609 | pr_debug("%s: %s\n", DRV_NAME, __func__); | 659 | pr_debug("%s: %s\n", DRV_NAME, __func__); |
@@ -612,13 +662,15 @@ static int rionet_shutdown(struct notifier_block *nb, unsigned long code, | |||
612 | if (!nets[i].ndev) | 662 | if (!nets[i].ndev) |
613 | continue; | 663 | continue; |
614 | 664 | ||
615 | list_for_each_entry_safe(peer, tmp, &nets[i].peers, node) { | 665 | spin_lock_irqsave(&nets[i].lock, flags); |
666 | list_for_each_entry(peer, &nets[i].peers, node) { | ||
616 | if (nets[i].active[peer->rdev->destid]) { | 667 | if (nets[i].active[peer->rdev->destid]) { |
617 | rio_send_doorbell(peer->rdev, | 668 | rio_send_doorbell(peer->rdev, |
618 | RIONET_DOORBELL_LEAVE); | 669 | RIONET_DOORBELL_LEAVE); |
619 | nets[i].active[peer->rdev->destid] = NULL; | 670 | nets[i].active[peer->rdev->destid] = NULL; |
620 | } | 671 | } |
621 | } | 672 | } |
673 | spin_unlock_irqrestore(&nets[i].lock, flags); | ||
622 | } | 674 | } |
623 | 675 | ||
624 | return NOTIFY_DONE; | 676 | return NOTIFY_DONE; |