]> err.no Git - linux-2.6/blobdiff - drivers/net/s2io.c
[PATCH] S2io: Timer based slowpath handling
[linux-2.6] / drivers / net / s2io.c
index 28d6d3746c8073de9387754eb437929082cd1437..ee498d248d38eafd9c72ab8768fc14af413b424a 100644 (file)
@@ -168,6 +168,12 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
 #define S2IO_TEST_LEN  sizeof(s2io_gstrings) / ETH_GSTRING_LEN
 #define S2IO_STRINGS_LEN       S2IO_TEST_LEN * ETH_GSTRING_LEN
 
+#define S2IO_TIMER_CONF(timer, handle, arg, exp)               \
+                       init_timer(&timer);                     \
+                       timer.function = handle;                \
+                       timer.data = (unsigned long) arg;       \
+                       mod_timer(&timer, (jiffies + exp))      \
+
 /*
  * Constants to be programmed into the Xena's registers, to configure
  * the XAUI.
@@ -2741,6 +2747,7 @@ int s2io_open(struct net_device *dev)
 setting_mac_address_failed:
        free_irq(sp->pdev->irq, dev);
 isr_registration_failed:
+       del_timer_sync(&sp->alarm_timer);
        s2io_reset(sp);
 hw_init_failed:
        return err;
@@ -2849,6 +2856,7 @@ int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        txdp->Control_2 |= config->tx_intr_type;
+
        txdp->Control_1 |= (TXD_BUFFER0_SIZE(frg_len) |
                            TXD_GATHER_CODE_FIRST);
        txdp->Control_1 |= TXD_LIST_OWN_XENA;
@@ -2897,6 +2905,15 @@ int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
+static void
+s2io_alarm_handle(unsigned long data)
+{
+       nic_t *sp = (nic_t *)data;
+
+       alarm_intr_handler(sp);
+       mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
+}
+
 /**
  *  s2io_isr - ISR handler of the device .
  *  @irq: the irq of the device.
@@ -2941,9 +2958,6 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
                return IRQ_NONE;
        }
 
-       if (reason & (GEN_ERROR_INTR))
-               alarm_intr_handler(sp);
-
 #ifdef CONFIG_S2IO_NAPI
        if (reason & GEN_INTR_RXTRAFFIC) {
                if (netif_rx_schedule_prep(dev)) {
@@ -4246,14 +4260,6 @@ int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 int s2io_change_mtu(struct net_device *dev, int new_mtu)
 {
        nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
-       register u64 val64;
-
-       if (netif_running(dev)) {
-               DBG_PRINT(ERR_DBG, "%s: Must be stopped to ", dev->name);
-               DBG_PRINT(ERR_DBG, "change its MTU\n");
-               return -EBUSY;
-       }
 
        if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
                DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
@@ -4261,11 +4267,22 @@ int s2io_change_mtu(struct net_device *dev, int new_mtu)
                return -EPERM;
        }
 
-       /* Set the new MTU into the PYLD register of the NIC */
-       val64 = new_mtu;
-       writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
-
        dev->mtu = new_mtu;
+       if (netif_running(dev)) {
+               s2io_card_down(sp);
+               netif_stop_queue(dev);
+               if (s2io_card_up(sp)) {
+                       DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
+                                 __FUNCTION__);
+               }
+               if (netif_queue_stopped(dev))
+                       netif_wake_queue(dev);
+       } else { /* Device is down */
+               XENA_dev_config_t __iomem *bar0 = sp->bar0;
+               u64 val64 = new_mtu;
+
+               writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
+       }
 
        return 0;
 }
@@ -4390,6 +4407,7 @@ static void s2io_card_down(nic_t * sp)
        unsigned long flags;
        register u64 val64 = 0;
 
+       del_timer_sync(&sp->alarm_timer);
        /* If s2io_set_link task is executing, wait till it completes. */
        while (test_and_set_bit(0, &(sp->link_state))) {
                msleep(50);
@@ -4492,6 +4510,8 @@ static int s2io_card_up(nic_t * sp)
                return -ENODEV;
        }
 
+       S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
+
        atomic_set(&sp->card_state, CARD_UP);
        return 0;
 }