Patchwork [3/3] ehea: Improve driver behaviour in low mem conditions

login
register
mail settings
Submitter Thomas Klein
Date Jan. 21, 2009, 2:49 p.m.
Message ID <200901211549.41352.tklein@de.ibm.com>
Download mbox | patch
Permalink /patch/19669/
State Not Applicable
Headers show

Comments

Thomas Klein - Jan. 21, 2009, 2:49 p.m.
Reworked receive queue fill policies to make the driver more tolerant
in low memory conditions.

Signed-off-by: Thomas Klein <tklein@de.ibm.com>

---
David Miller - Jan. 21, 2009, 10:47 p.m.
From: Thomas Klein <tklein@de.ibm.com>
Date: Wed, 21 Jan 2009 15:49:41 +0100

> Reworked receive queue fill policies to make the driver more tolerant
> in low memory conditions.
> 
> Signed-off-by: Thomas Klein <tklein@de.ibm.com>

Applied, but there is an even better way to handle this.

You should be allocating replacement RX skbs at receive time.  And if
the RX allocation fails, you simply give the RX skb back to the chip
and do not pass it up into the stack.

This is what many ethernet drivers do to ensure that the chip never
can reach a situation where the free RX packet queue becomes empty.

Patch

diff -Nurp -X dontdiff linux-2.6.29-rc2/drivers/net/ehea/ehea_main.c patched_kernel/drivers/net/ehea/ehea_main.c
--- linux-2.6.29-rc2/drivers/net/ehea/ehea_main.c	2009-01-20 17:03:17.000000000 +0100
+++ patched_kernel/drivers/net/ehea/ehea_main.c	2009-01-20 17:03:57.000000000 +0100
@@ -370,8 +370,6 @@  static void ehea_refill_rq1(struct ehea_
 							      EHEA_L_PKT_SIZE);
 			if (!skb_arr_rq1[index]) {
 				pr->rq1_skba.os_skbs = fill_wqes - i;
-				ehea_error("%s: no mem for skb/%d wqes filled",
-					   dev->name, i);
 				break;
 			}
 		}
@@ -387,26 +385,19 @@  static void ehea_refill_rq1(struct ehea_
 	ehea_update_rq1a(pr->qp, adder);
 }
 
-static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
+static void ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
 {
-	int ret = 0;
 	struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
 	struct net_device *dev = pr->port->netdev;
 	int i;
 
 	for (i = 0; i < pr->rq1_skba.len; i++) {
 		skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE);
-		if (!skb_arr_rq1[i]) {
-			ehea_error("%s: no mem for skb/%d wqes filled",
-				   dev->name, i);
-			ret = -ENOMEM;
-			goto out;
-		}
+		if (!skb_arr_rq1[i])
+			break;
 	}
 	/* Ring doorbell */
 	ehea_update_rq1a(pr->qp, nr_rq1a);
-out:
-	return ret;
 }
 
 static int ehea_refill_rq_def(struct ehea_port_res *pr,
@@ -435,10 +426,12 @@  static int ehea_refill_rq_def(struct ehe
 		u64 tmp_addr;
 		struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
 		if (!skb) {
-			ehea_error("%s: no mem for skb/%d wqes filled",
-				   pr->port->netdev->name, i);
 			q_skba->os_skbs = fill_wqes - i;
-			ret = -ENOMEM;
+			if (q_skba->os_skbs == q_skba->len - 2) {
+				ehea_info("%s: rq%i ran dry - no mem for skb",
+					  pr->port->netdev->name, rq_nr);
+				ret = -ENOMEM;
+			}
 			break;
 		}
 		skb_reserve(skb, NET_IP_ALIGN);
@@ -1201,11 +1194,11 @@  static int ehea_fill_port_res(struct ehe
 	int ret;
 	struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr;
 
-	ret = ehea_init_fill_rq1(pr, init_attr->act_nr_rwqes_rq1
-				     - init_attr->act_nr_rwqes_rq2
-				     - init_attr->act_nr_rwqes_rq3 - 1);
+	ehea_init_fill_rq1(pr, init_attr->act_nr_rwqes_rq1
+			       - init_attr->act_nr_rwqes_rq2
+			       - init_attr->act_nr_rwqes_rq3 - 1);
 
-	ret |= ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2 - 1);
+	ret = ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2 - 1);
 
 	ret |= ehea_refill_rq3(pr, init_attr->act_nr_rwqes_rq3 - 1);