RDMA/nes: Generate IB_EVENT_PORT_ERR/PORT_ACTIVE events
authorMaciej Sosnowski <maciej.sosnowski@intel.com>
Wed, 24 Nov 2010 17:29:38 +0000 (17:29 +0000)
committerRoland Dreier <rolandd@cisco.com>
Sun, 16 Jan 2011 21:23:34 +0000 (13:23 -0800)
Depending on link state change, IB_EVENT_PORT_ERR or
IB_EVENT_PORT_ACTIVE should be generated when handling MAC interrupts.

Plugging in a cable happens to result in series of interrupts changing
driver's link state a number of times before finally staying at link
up (e.g. link up, link down, link up, link down, ..., link up).  To
prevent sending series of redundant IB_EVENT_PORT_ACTIVE and
IB_EVENT_PORT_ERR events, we use a timer to debounce them in
nes_port_ibevent().

Signed-off-by: Maciej Sosnowski <maciej.sosnowski@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/nes/nes_hw.h
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/hw/nes/nes_verbs.c

index 1980a461c49904e93102e02e655e5b033c5f92be..2b89b06ca7c315f0837b0d59c140a9f5934afcce 100644 (file)
@@ -2608,6 +2608,13 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                                                netif_start_queue(nesvnic->netdev);
                                        nesvnic->linkup = 1;
                                        netif_carrier_on(nesvnic->netdev);
+
+                                       spin_lock(&nesvnic->port_ibevent_lock);
+                                       if (nesdev->iw_status == 0) {
+                                               nesdev->iw_status = 1;
+                                               nes_port_ibevent(nesvnic);
+                                       }
+                                       spin_unlock(&nesvnic->port_ibevent_lock);
                                }
                        }
                } else {
@@ -2633,6 +2640,13 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                                                netif_stop_queue(nesvnic->netdev);
                                        nesvnic->linkup = 0;
                                        netif_carrier_off(nesvnic->netdev);
+
+                                       spin_lock(&nesvnic->port_ibevent_lock);
+                                       if (nesdev->iw_status == 1) {
+                                               nesdev->iw_status = 0;
+                                               nes_port_ibevent(nesvnic);
+                                       }
+                                       spin_unlock(&nesvnic->port_ibevent_lock);
                                }
                        }
                }
index 1204c3432b6322f23518c42d550746f19d9e4ce6..8a9ea9a4dc5d4288884aa7c33a60a1f23084e1d6 100644 (file)
@@ -1193,6 +1193,8 @@ struct nes_listener {
 
 struct nes_ib_device;
 
+#define NES_EVENT_DELAY msecs_to_jiffies(100)
+
 struct nes_vnic {
        struct nes_ib_device *nesibdev;
        u64 sq_full;
@@ -1247,6 +1249,10 @@ struct nes_vnic {
        u32 lro_max_aggr;
        struct net_lro_mgr lro_mgr;
        struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS];
+       struct timer_list event_timer;
+       enum ib_event_type delayed_event;
+       enum ib_event_type last_dispatched_event;
+       spinlock_t port_ibevent_lock;
 };
 
 struct nes_ib_device {
index 5a4c364847228f0d02499422c22b358d2fa9cd93..81052fbcd9baf12b610ef991e1f507f55729a019 100644 (file)
@@ -144,6 +144,7 @@ static int nes_netdev_open(struct net_device *netdev)
        u32 nic_active_bit;
        u32 nic_active;
        struct list_head *list_pos, *list_temp;
+       unsigned long flags;
 
        assert(nesdev != NULL);
 
@@ -233,18 +234,27 @@ static int nes_netdev_open(struct net_device *netdev)
                first_nesvnic = nesvnic;
        }
 
-       if (nesvnic->of_device_registered) {
-               nesdev->iw_status = 1;
-               nesdev->nesadapter->send_term_ok = 1;
-               nes_port_ibevent(nesvnic);
-       }
-
        if (first_nesvnic->linkup) {
                /* Enable network packets */
                nesvnic->linkup = 1;
                netif_start_queue(netdev);
                netif_carrier_on(netdev);
        }
+
+       spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags);
+       if (nesvnic->of_device_registered) {
+               nesdev->nesadapter->send_term_ok = 1;
+               if (nesvnic->linkup == 1) {
+                       if (nesdev->iw_status == 0) {
+                               nesdev->iw_status = 1;
+                               nes_port_ibevent(nesvnic);
+                       }
+               } else {
+                       nesdev->iw_status = 0;
+               }
+       }
+       spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags);
+
        napi_enable(&nesvnic->napi);
        nesvnic->netdev_open = 1;
 
@@ -263,6 +273,7 @@ static int nes_netdev_stop(struct net_device *netdev)
        u32 nic_active;
        struct nes_vnic *first_nesvnic = NULL;
        struct list_head *list_pos, *list_temp;
+       unsigned long flags;
 
        nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n",
                        nesvnic, nesdev, netdev, netdev->name);
@@ -315,12 +326,17 @@ static int nes_netdev_stop(struct net_device *netdev)
        nic_active &= nic_active_mask;
        nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
 
-
+       spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags);
        if (nesvnic->of_device_registered) {
                nesdev->nesadapter->send_term_ok = 0;
                nesdev->iw_status = 0;
-               nes_port_ibevent(nesvnic);
+               if (nesvnic->linkup == 1)
+                       nes_port_ibevent(nesvnic);
        }
+       del_timer_sync(&nesvnic->event_timer);
+       nesvnic->event_timer.function = NULL;
+       spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags);
+
        nes_destroy_nic_qp(nesvnic);
 
        nesvnic->netdev_open = 0;
@@ -1750,7 +1766,10 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
                nesvnic->rdma_enabled = 0;
        }
        nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id;
+       init_timer(&nesvnic->event_timer);
+       nesvnic->event_timer.function = NULL;
        spin_lock_init(&nesvnic->tx_lock);
+       spin_lock_init(&nesvnic->port_ibevent_lock);
        nesdev->netdev[nesdev->netdev_count] = netdev;
 
        nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n",
index 99933e4e48ff853da4a79f14ce899a1dea5afc67..26d8018c0a7c557d6eb2f4f8f69adf09d916c781 100644 (file)
@@ -3936,6 +3936,30 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
        return nesibdev;
 }
 
+
+/**
+ * nes_handle_delayed_event
+ */
+static void nes_handle_delayed_event(unsigned long data)
+{
+       struct nes_vnic *nesvnic = (void *) data;
+
+       if (nesvnic->delayed_event != nesvnic->last_dispatched_event) {
+               struct ib_event event;
+
+               event.device = &nesvnic->nesibdev->ibdev;
+               if (!event.device)
+                       goto stop_timer;
+               event.event = nesvnic->delayed_event;
+               event.element.port_num = nesvnic->logical_port + 1;
+               ib_dispatch_event(&event);
+       }
+
+stop_timer:
+       nesvnic->event_timer.function = NULL;
+}
+
+
 void  nes_port_ibevent(struct nes_vnic *nesvnic)
 {
        struct nes_ib_device *nesibdev = nesvnic->nesibdev;
@@ -3944,7 +3968,18 @@ void  nes_port_ibevent(struct nes_vnic *nesvnic)
        event.device = &nesibdev->ibdev;
        event.element.port_num = nesvnic->logical_port + 1;
        event.event = nesdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
-       ib_dispatch_event(&event);
+
+       if (!nesvnic->event_timer.function) {
+               ib_dispatch_event(&event);
+               nesvnic->last_dispatched_event = event.event;
+               nesvnic->event_timer.function = nes_handle_delayed_event;
+               nesvnic->event_timer.data = (unsigned long) nesvnic;
+               nesvnic->event_timer.expires = jiffies + NES_EVENT_DELAY;
+               add_timer(&nesvnic->event_timer);
+       } else {
+               mod_timer(&nesvnic->event_timer, jiffies + NES_EVENT_DELAY);
+       }
+       nesvnic->delayed_event = event.event;
 }