diff options
author | Maciej Sosnowski <maciej.sosnowski@intel.com> | 2010-11-24 12:29:38 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2011-01-16 16:23:34 -0500 |
commit | ea623455b736d82f476460647e8b5fe5dc36f4f2 (patch) | |
tree | c1e2343adc9b2e8f7e11d58dc561370905d60bb8 /drivers/infiniband/hw/nes | |
parent | 2a4c97ead4b375a64063523210939b87ad225b85 (diff) |
RDMA/nes: Generate IB_EVENT_PORT_ERR/PORT_ACTIVE events
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>
Diffstat (limited to 'drivers/infiniband/hw/nes')
-rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.c | 14 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.h | 6 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_nic.c | 35 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_verbs.c | 37 |
4 files changed, 83 insertions, 9 deletions
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 1980a461c49..2b89b06ca7c 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c | |||
@@ -2608,6 +2608,13 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) | |||
2608 | netif_start_queue(nesvnic->netdev); | 2608 | netif_start_queue(nesvnic->netdev); |
2609 | nesvnic->linkup = 1; | 2609 | nesvnic->linkup = 1; |
2610 | netif_carrier_on(nesvnic->netdev); | 2610 | netif_carrier_on(nesvnic->netdev); |
2611 | |||
2612 | spin_lock(&nesvnic->port_ibevent_lock); | ||
2613 | if (nesdev->iw_status == 0) { | ||
2614 | nesdev->iw_status = 1; | ||
2615 | nes_port_ibevent(nesvnic); | ||
2616 | } | ||
2617 | spin_unlock(&nesvnic->port_ibevent_lock); | ||
2611 | } | 2618 | } |
2612 | } | 2619 | } |
2613 | } else { | 2620 | } else { |
@@ -2633,6 +2640,13 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) | |||
2633 | netif_stop_queue(nesvnic->netdev); | 2640 | netif_stop_queue(nesvnic->netdev); |
2634 | nesvnic->linkup = 0; | 2641 | nesvnic->linkup = 0; |
2635 | netif_carrier_off(nesvnic->netdev); | 2642 | netif_carrier_off(nesvnic->netdev); |
2643 | |||
2644 | spin_lock(&nesvnic->port_ibevent_lock); | ||
2645 | if (nesdev->iw_status == 1) { | ||
2646 | nesdev->iw_status = 0; | ||
2647 | nes_port_ibevent(nesvnic); | ||
2648 | } | ||
2649 | spin_unlock(&nesvnic->port_ibevent_lock); | ||
2636 | } | 2650 | } |
2637 | } | 2651 | } |
2638 | } | 2652 | } |
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 1204c3432b6..8a9ea9a4dc5 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h | |||
@@ -1193,6 +1193,8 @@ struct nes_listener { | |||
1193 | 1193 | ||
1194 | struct nes_ib_device; | 1194 | struct nes_ib_device; |
1195 | 1195 | ||
1196 | #define NES_EVENT_DELAY msecs_to_jiffies(100) | ||
1197 | |||
1196 | struct nes_vnic { | 1198 | struct nes_vnic { |
1197 | struct nes_ib_device *nesibdev; | 1199 | struct nes_ib_device *nesibdev; |
1198 | u64 sq_full; | 1200 | u64 sq_full; |
@@ -1247,6 +1249,10 @@ struct nes_vnic { | |||
1247 | u32 lro_max_aggr; | 1249 | u32 lro_max_aggr; |
1248 | struct net_lro_mgr lro_mgr; | 1250 | struct net_lro_mgr lro_mgr; |
1249 | struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; | 1251 | struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; |
1252 | struct timer_list event_timer; | ||
1253 | enum ib_event_type delayed_event; | ||
1254 | enum ib_event_type last_dispatched_event; | ||
1255 | spinlock_t port_ibevent_lock; | ||
1250 | }; | 1256 | }; |
1251 | 1257 | ||
1252 | struct nes_ib_device { | 1258 | struct nes_ib_device { |
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 5a4c3648472..81052fbcd9b 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c | |||
@@ -144,6 +144,7 @@ static int nes_netdev_open(struct net_device *netdev) | |||
144 | u32 nic_active_bit; | 144 | u32 nic_active_bit; |
145 | u32 nic_active; | 145 | u32 nic_active; |
146 | struct list_head *list_pos, *list_temp; | 146 | struct list_head *list_pos, *list_temp; |
147 | unsigned long flags; | ||
147 | 148 | ||
148 | assert(nesdev != NULL); | 149 | assert(nesdev != NULL); |
149 | 150 | ||
@@ -233,18 +234,27 @@ static int nes_netdev_open(struct net_device *netdev) | |||
233 | first_nesvnic = nesvnic; | 234 | first_nesvnic = nesvnic; |
234 | } | 235 | } |
235 | 236 | ||
236 | if (nesvnic->of_device_registered) { | ||
237 | nesdev->iw_status = 1; | ||
238 | nesdev->nesadapter->send_term_ok = 1; | ||
239 | nes_port_ibevent(nesvnic); | ||
240 | } | ||
241 | |||
242 | if (first_nesvnic->linkup) { | 237 | if (first_nesvnic->linkup) { |
243 | /* Enable network packets */ | 238 | /* Enable network packets */ |
244 | nesvnic->linkup = 1; | 239 | nesvnic->linkup = 1; |
245 | netif_start_queue(netdev); | 240 | netif_start_queue(netdev); |
246 | netif_carrier_on(netdev); | 241 | netif_carrier_on(netdev); |
247 | } | 242 | } |
243 | |||
244 | spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags); | ||
245 | if (nesvnic->of_device_registered) { | ||
246 | nesdev->nesadapter->send_term_ok = 1; | ||
247 | if (nesvnic->linkup == 1) { | ||
248 | if (nesdev->iw_status == 0) { | ||
249 | nesdev->iw_status = 1; | ||
250 | nes_port_ibevent(nesvnic); | ||
251 | } | ||
252 | } else { | ||
253 | nesdev->iw_status = 0; | ||
254 | } | ||
255 | } | ||
256 | spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags); | ||
257 | |||
248 | napi_enable(&nesvnic->napi); | 258 | napi_enable(&nesvnic->napi); |
249 | nesvnic->netdev_open = 1; | 259 | nesvnic->netdev_open = 1; |
250 | 260 | ||
@@ -263,6 +273,7 @@ static int nes_netdev_stop(struct net_device *netdev) | |||
263 | u32 nic_active; | 273 | u32 nic_active; |
264 | struct nes_vnic *first_nesvnic = NULL; | 274 | struct nes_vnic *first_nesvnic = NULL; |
265 | struct list_head *list_pos, *list_temp; | 275 | struct list_head *list_pos, *list_temp; |
276 | unsigned long flags; | ||
266 | 277 | ||
267 | nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n", | 278 | nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n", |
268 | nesvnic, nesdev, netdev, netdev->name); | 279 | nesvnic, nesdev, netdev, netdev->name); |
@@ -315,12 +326,17 @@ static int nes_netdev_stop(struct net_device *netdev) | |||
315 | nic_active &= nic_active_mask; | 326 | nic_active &= nic_active_mask; |
316 | nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active); | 327 | nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active); |
317 | 328 | ||
318 | 329 | spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags); | |
319 | if (nesvnic->of_device_registered) { | 330 | if (nesvnic->of_device_registered) { |
320 | nesdev->nesadapter->send_term_ok = 0; | 331 | nesdev->nesadapter->send_term_ok = 0; |
321 | nesdev->iw_status = 0; | 332 | nesdev->iw_status = 0; |
322 | nes_port_ibevent(nesvnic); | 333 | if (nesvnic->linkup == 1) |
334 | nes_port_ibevent(nesvnic); | ||
323 | } | 335 | } |
336 | del_timer_sync(&nesvnic->event_timer); | ||
337 | nesvnic->event_timer.function = NULL; | ||
338 | spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags); | ||
339 | |||
324 | nes_destroy_nic_qp(nesvnic); | 340 | nes_destroy_nic_qp(nesvnic); |
325 | 341 | ||
326 | nesvnic->netdev_open = 0; | 342 | nesvnic->netdev_open = 0; |
@@ -1750,7 +1766,10 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, | |||
1750 | nesvnic->rdma_enabled = 0; | 1766 | nesvnic->rdma_enabled = 0; |
1751 | } | 1767 | } |
1752 | nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id; | 1768 | nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id; |
1769 | init_timer(&nesvnic->event_timer); | ||
1770 | nesvnic->event_timer.function = NULL; | ||
1753 | spin_lock_init(&nesvnic->tx_lock); | 1771 | spin_lock_init(&nesvnic->tx_lock); |
1772 | spin_lock_init(&nesvnic->port_ibevent_lock); | ||
1754 | nesdev->netdev[nesdev->netdev_count] = netdev; | 1773 | nesdev->netdev[nesdev->netdev_count] = netdev; |
1755 | 1774 | ||
1756 | nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n", | 1775 | nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n", |
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 99933e4e48f..26d8018c0a7 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c | |||
@@ -3936,6 +3936,30 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev) | |||
3936 | return nesibdev; | 3936 | return nesibdev; |
3937 | } | 3937 | } |
3938 | 3938 | ||
3939 | |||
3940 | /** | ||
3941 | * nes_handle_delayed_event | ||
3942 | */ | ||
3943 | static void nes_handle_delayed_event(unsigned long data) | ||
3944 | { | ||
3945 | struct nes_vnic *nesvnic = (void *) data; | ||
3946 | |||
3947 | if (nesvnic->delayed_event != nesvnic->last_dispatched_event) { | ||
3948 | struct ib_event event; | ||
3949 | |||
3950 | event.device = &nesvnic->nesibdev->ibdev; | ||
3951 | if (!event.device) | ||
3952 | goto stop_timer; | ||
3953 | event.event = nesvnic->delayed_event; | ||
3954 | event.element.port_num = nesvnic->logical_port + 1; | ||
3955 | ib_dispatch_event(&event); | ||
3956 | } | ||
3957 | |||
3958 | stop_timer: | ||
3959 | nesvnic->event_timer.function = NULL; | ||
3960 | } | ||
3961 | |||
3962 | |||
3939 | void nes_port_ibevent(struct nes_vnic *nesvnic) | 3963 | void nes_port_ibevent(struct nes_vnic *nesvnic) |
3940 | { | 3964 | { |
3941 | struct nes_ib_device *nesibdev = nesvnic->nesibdev; | 3965 | struct nes_ib_device *nesibdev = nesvnic->nesibdev; |
@@ -3944,7 +3968,18 @@ void nes_port_ibevent(struct nes_vnic *nesvnic) | |||
3944 | event.device = &nesibdev->ibdev; | 3968 | event.device = &nesibdev->ibdev; |
3945 | event.element.port_num = nesvnic->logical_port + 1; | 3969 | event.element.port_num = nesvnic->logical_port + 1; |
3946 | event.event = nesdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; | 3970 | event.event = nesdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; |
3947 | ib_dispatch_event(&event); | 3971 | |
3972 | if (!nesvnic->event_timer.function) { | ||
3973 | ib_dispatch_event(&event); | ||
3974 | nesvnic->last_dispatched_event = event.event; | ||
3975 | nesvnic->event_timer.function = nes_handle_delayed_event; | ||
3976 | nesvnic->event_timer.data = (unsigned long) nesvnic; | ||
3977 | nesvnic->event_timer.expires = jiffies + NES_EVENT_DELAY; | ||
3978 | add_timer(&nesvnic->event_timer); | ||
3979 | } else { | ||
3980 | mod_timer(&nesvnic->event_timer, jiffies + NES_EVENT_DELAY); | ||
3981 | } | ||
3982 | nesvnic->delayed_event = event.event; | ||
3948 | } | 3983 | } |
3949 | 3984 | ||
3950 | 3985 | ||