aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2016-03-22 17:26:29 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-22 18:36:02 -0400
commit34ed2ebb65b0aa6a82206686870aaaddc12b2271 (patch)
tree79b70c4c4f99b64d7a59ff1532595a7ed170f1b1
parentdd64f4fe6fe5e3924b36ec4bb4d4202af944a452 (diff)
rapidio/rionet: add locking into add/remove device
Add spinlock protection when handling list of connected peers and ability to handle new peer device addition after the RIONET device was open. Before his update RIONET was sending JOIN requests only when it have been opened, peer devices added later have been missing from this process. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Aurelien Jacquiot <a-jacquiot@ti.com> Cc: Andre van Herk <andre.van.herk@prodrive-technologies.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/net/rionet.c152
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
68struct rionet_peer { 69struct rionet_peer {
@@ -74,6 +75,7 @@ struct rionet_peer {
74struct rionet_net { 75struct 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
308static int rionet_open(struct net_device *ndev) 316static 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)
370static int rionet_close(struct net_device *ndev) 373static 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
424static void rionet_get_drvinfo(struct net_device *ndev, 448static 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
532static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1];
533
534static int rionet_add_dev(struct device *dev, struct subsys_interface *sif) 560static 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:
603static int rionet_shutdown(struct notifier_block *nb, unsigned long code, 652static 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;