aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/iseries_veth.c75
1 files changed, 69 insertions, 6 deletions
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 7d6ba5114a1e..122d60db4ff7 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -132,6 +132,11 @@ struct veth_lpar_connection {
132 struct kobject kobject; 132 struct kobject kobject;
133 struct timer_list ack_timer; 133 struct timer_list ack_timer;
134 134
135 struct timer_list reset_timer;
136 unsigned int reset_timeout;
137 unsigned long last_contact;
138 int outstanding_tx;
139
135 spinlock_t lock; 140 spinlock_t lock;
136 unsigned long state; 141 unsigned long state;
137 HvLpInstanceId src_inst; 142 HvLpInstanceId src_inst;
@@ -171,8 +176,9 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev);
171static void veth_recycle_msg(struct veth_lpar_connection *, struct veth_msg *); 176static void veth_recycle_msg(struct veth_lpar_connection *, struct veth_msg *);
172static void veth_flush_pending(struct veth_lpar_connection *cnx); 177static void veth_flush_pending(struct veth_lpar_connection *cnx);
173static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *); 178static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *);
174static void veth_timed_ack(unsigned long connectionPtr);
175static void veth_release_connection(struct kobject *kobject); 179static void veth_release_connection(struct kobject *kobject);
180static void veth_timed_ack(unsigned long ptr);
181static void veth_timed_reset(unsigned long ptr);
176 182
177static struct kobj_type veth_lpar_connection_ktype = { 183static struct kobj_type veth_lpar_connection_ktype = {
178 .release = veth_release_connection 184 .release = veth_release_connection
@@ -360,7 +366,7 @@ static void veth_handle_int(struct VethLpEvent *event)
360 HvLpIndex rlp = event->base_event.xSourceLp; 366 HvLpIndex rlp = event->base_event.xSourceLp;
361 struct veth_lpar_connection *cnx = veth_cnx[rlp]; 367 struct veth_lpar_connection *cnx = veth_cnx[rlp];
362 unsigned long flags; 368 unsigned long flags;
363 int i; 369 int i, acked = 0;
364 370
365 BUG_ON(! cnx); 371 BUG_ON(! cnx);
366 372
@@ -374,13 +380,22 @@ static void veth_handle_int(struct VethLpEvent *event)
374 break; 380 break;
375 case VethEventTypeFramesAck: 381 case VethEventTypeFramesAck:
376 spin_lock_irqsave(&cnx->lock, flags); 382 spin_lock_irqsave(&cnx->lock, flags);
383
377 for (i = 0; i < VETH_MAX_ACKS_PER_MSG; ++i) { 384 for (i = 0; i < VETH_MAX_ACKS_PER_MSG; ++i) {
378 u16 msgnum = event->u.frames_ack_data.token[i]; 385 u16 msgnum = event->u.frames_ack_data.token[i];
379 386
380 if (msgnum < VETH_NUMBUFFERS) 387 if (msgnum < VETH_NUMBUFFERS) {
381 veth_recycle_msg(cnx, cnx->msgs + msgnum); 388 veth_recycle_msg(cnx, cnx->msgs + msgnum);
389 cnx->outstanding_tx--;
390 acked++;
391 }
382 } 392 }
393
394 if (acked > 0)
395 cnx->last_contact = jiffies;
396
383 spin_unlock_irqrestore(&cnx->lock, flags); 397 spin_unlock_irqrestore(&cnx->lock, flags);
398
384 veth_flush_pending(cnx); 399 veth_flush_pending(cnx);
385 break; 400 break;
386 case VethEventTypeFrames: 401 case VethEventTypeFrames:
@@ -454,8 +469,6 @@ static void veth_statemachine(void *p)
454 469
455 restart: 470 restart:
456 if (cnx->state & VETH_STATE_RESET) { 471 if (cnx->state & VETH_STATE_RESET) {
457 int i;
458
459 if (cnx->state & VETH_STATE_OPEN) 472 if (cnx->state & VETH_STATE_OPEN)
460 HvCallEvent_closeLpEventPath(cnx->remote_lp, 473 HvCallEvent_closeLpEventPath(cnx->remote_lp,
461 HvLpEvent_Type_VirtualLan); 474 HvLpEvent_Type_VirtualLan);
@@ -474,15 +487,20 @@ static void veth_statemachine(void *p)
474 | VETH_STATE_SENTCAPACK | VETH_STATE_READY); 487 | VETH_STATE_SENTCAPACK | VETH_STATE_READY);
475 488
476 /* Clean up any leftover messages */ 489 /* Clean up any leftover messages */
477 if (cnx->msgs) 490 if (cnx->msgs) {
491 int i;
478 for (i = 0; i < VETH_NUMBUFFERS; ++i) 492 for (i = 0; i < VETH_NUMBUFFERS; ++i)
479 veth_recycle_msg(cnx, cnx->msgs + i); 493 veth_recycle_msg(cnx, cnx->msgs + i);
494 }
495 cnx->outstanding_tx = 0;
480 496
481 /* Drop the lock so we can do stuff that might sleep or 497 /* Drop the lock so we can do stuff that might sleep or
482 * take other locks. */ 498 * take other locks. */
483 spin_unlock_irq(&cnx->lock); 499 spin_unlock_irq(&cnx->lock);
484 500
485 del_timer_sync(&cnx->ack_timer); 501 del_timer_sync(&cnx->ack_timer);
502 del_timer_sync(&cnx->reset_timer);
503
486 veth_flush_pending(cnx); 504 veth_flush_pending(cnx);
487 505
488 spin_lock_irq(&cnx->lock); 506 spin_lock_irq(&cnx->lock);
@@ -631,9 +649,16 @@ static int veth_init_connection(u8 rlp)
631 cnx->remote_lp = rlp; 649 cnx->remote_lp = rlp;
632 spin_lock_init(&cnx->lock); 650 spin_lock_init(&cnx->lock);
633 INIT_WORK(&cnx->statemachine_wq, veth_statemachine, cnx); 651 INIT_WORK(&cnx->statemachine_wq, veth_statemachine, cnx);
652
634 init_timer(&cnx->ack_timer); 653 init_timer(&cnx->ack_timer);
635 cnx->ack_timer.function = veth_timed_ack; 654 cnx->ack_timer.function = veth_timed_ack;
636 cnx->ack_timer.data = (unsigned long) cnx; 655 cnx->ack_timer.data = (unsigned long) cnx;
656
657 init_timer(&cnx->reset_timer);
658 cnx->reset_timer.function = veth_timed_reset;
659 cnx->reset_timer.data = (unsigned long) cnx;
660 cnx->reset_timeout = 5 * HZ * (VETH_ACKTIMEOUT / 1000000);
661
637 memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks)); 662 memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks));
638 663
639 veth_cnx[rlp] = cnx; 664 veth_cnx[rlp] = cnx;
@@ -948,6 +973,13 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp,
948 if (rc != HvLpEvent_Rc_Good) 973 if (rc != HvLpEvent_Rc_Good)
949 goto recycle_and_drop; 974 goto recycle_and_drop;
950 975
976 /* If the timer's not already running, start it now. */
977 if (0 == cnx->outstanding_tx)
978 mod_timer(&cnx->reset_timer, jiffies + cnx->reset_timeout);
979
980 cnx->last_contact = jiffies;
981 cnx->outstanding_tx++;
982
951 spin_unlock_irqrestore(&cnx->lock, flags); 983 spin_unlock_irqrestore(&cnx->lock, flags);
952 return 0; 984 return 0;
953 985
@@ -1093,6 +1125,37 @@ static void veth_flush_pending(struct veth_lpar_connection *cnx)
1093 } 1125 }
1094} 1126}
1095 1127
1128static void veth_timed_reset(unsigned long ptr)
1129{
1130 struct veth_lpar_connection *cnx = (struct veth_lpar_connection *)ptr;
1131 unsigned long trigger_time, flags;
1132
1133 /* FIXME is it possible this fires after veth_stop_connection()?
1134 * That would reschedule the statemachine for 5 seconds and probably
1135 * execute it after the module's been unloaded. Hmm. */
1136
1137 spin_lock_irqsave(&cnx->lock, flags);
1138
1139 if (cnx->outstanding_tx > 0) {
1140 trigger_time = cnx->last_contact + cnx->reset_timeout;
1141
1142 if (trigger_time < jiffies) {
1143 cnx->state |= VETH_STATE_RESET;
1144 veth_kick_statemachine(cnx);
1145 veth_error("%d packets not acked by LPAR %d within %d "
1146 "seconds, resetting.\n",
1147 cnx->outstanding_tx, cnx->remote_lp,
1148 cnx->reset_timeout / HZ);
1149 } else {
1150 /* Reschedule the timer */
1151 trigger_time = jiffies + cnx->reset_timeout;
1152 mod_timer(&cnx->reset_timer, trigger_time);
1153 }
1154 }
1155
1156 spin_unlock_irqrestore(&cnx->lock, flags);
1157}
1158
1096/* 1159/*
1097 * Rx path 1160 * Rx path
1098 */ 1161 */