aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/tile/tilegx.c
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2013-08-01 11:36:42 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-01 17:35:50 -0400
commit5e7a54a2a78d59d8c6e0f71711a3eafa4ab969af (patch)
tree0337e2ae87443c788ec4469f0c9e5f206e960069 /drivers/net/ethernet/tile/tilegx.c
parentad0181855a48641e812454e64c62c07e015b6a97 (diff)
tile: fix panic bug in napi support for tilegx network driver
The code used to call napi_disable() in an interrupt handler (from smp_call_function), which in turn could call msleep(). Unfortunately you can't sleep in an interrupt context. Luckily it turns out all the NAPI support functions are just operating on data structures and not on any deeply per-cpu data, so we can arrange to set up and tear down all the NAPI state on the core driving the process, and just do the IRQ enable/disable as a smp_call_function thing. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/tile/tilegx.c')
-rw-r--r--drivers/net/ethernet/tile/tilegx.c65
1 files changed, 33 insertions, 32 deletions
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
index e9eba2bf6aae..17bcf3361874 100644
--- a/drivers/net/ethernet/tile/tilegx.c
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -650,37 +650,13 @@ static enum hrtimer_restart tile_net_handle_egress_timer(struct hrtimer *t)
650 return HRTIMER_NORESTART; 650 return HRTIMER_NORESTART;
651} 651}
652 652
653/* Helper function for "tile_net_update()". 653/* Helper function for "tile_net_update()". */
654 * "dev" (i.e. arg) is the device being brought up or down, 654static void manage_ingress_irq(void *enable)
655 * or NULL if all devices are now down.
656 */
657static void tile_net_update_cpu(void *arg)
658{ 655{
659 struct tile_net_info *info = &__get_cpu_var(per_cpu_info); 656 if (enable)
660 struct net_device *dev = arg;
661
662 if (!info->has_iqueue)
663 return;
664
665 if (dev != NULL) {
666 if (!info->napi_added) {
667 netif_napi_add(dev, &info->napi,
668 tile_net_poll, TILE_NET_WEIGHT);
669 info->napi_added = true;
670 }
671 if (!info->napi_enabled) {
672 napi_enable(&info->napi);
673 info->napi_enabled = true;
674 }
675 enable_percpu_irq(ingress_irq, 0); 657 enable_percpu_irq(ingress_irq, 0);
676 } else { 658 else
677 disable_percpu_irq(ingress_irq); 659 disable_percpu_irq(ingress_irq);
678 if (info->napi_enabled) {
679 napi_disable(&info->napi);
680 info->napi_enabled = false;
681 }
682 /* FIXME: Drain the iqueue. */
683 }
684} 660}
685 661
686/* Helper function for tile_net_open() and tile_net_stop(). 662/* Helper function for tile_net_open() and tile_net_stop().
@@ -717,10 +693,35 @@ static int tile_net_update(struct net_device *dev)
717 return -EIO; 693 return -EIO;
718 } 694 }
719 695
720 /* Update all cpus, sequentially (to protect "netif_napi_add()"). */ 696 /* Update all cpus, sequentially (to protect "netif_napi_add()").
721 for_each_online_cpu(cpu) 697 * We use on_each_cpu to handle the IPI mask or unmask.
722 smp_call_function_single(cpu, tile_net_update_cpu, 698 */
723 (saw_channel ? dev : NULL), 1); 699 if (!saw_channel)
700 on_each_cpu(manage_ingress_irq, (void *)0, 1);
701 for_each_online_cpu(cpu) {
702 struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
703 if (!info->has_iqueue)
704 continue;
705 if (saw_channel) {
706 if (!info->napi_added) {
707 netif_napi_add(dev, &info->napi,
708 tile_net_poll, TILE_NET_WEIGHT);
709 info->napi_added = true;
710 }
711 if (!info->napi_enabled) {
712 napi_enable(&info->napi);
713 info->napi_enabled = true;
714 }
715 } else {
716 if (info->napi_enabled) {
717 napi_disable(&info->napi);
718 info->napi_enabled = false;
719 }
720 /* FIXME: Drain the iqueue. */
721 }
722 }
723 if (saw_channel)
724 on_each_cpu(manage_ingress_irq, (void *)1, 1);
724 725
725 /* HACK: Allow packets to flow in the simulator. */ 726 /* HACK: Allow packets to flow in the simulator. */
726 if (saw_channel) 727 if (saw_channel)