s390/zcrypt: Fixed attrition of AP adapters and domains

Currently the first eligible AP adapter respectively domain will be
selected to service requests. In case of sequential workload, the
very same adapter/domain will be used.

The adapter/domain selection algorithm now considers the completed
transactions per adaper/domain and therefore ensures a homogeneous
utilization.

Signed-off-by: Ingo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 54b17e1..4dc7c88 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -195,6 +195,7 @@
 	unsigned int functions;		/* AP device function bitfield. */
 	int queue_depth;		/* AP queue depth.*/
 	int id;				/* AP card number. */
+	atomic_t total_request_count;	/* # requests ever for this AP device.*/
 };
 
 #define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device)
@@ -211,7 +212,7 @@
 	enum ap_state state;		/* State of the AP device. */
 	int pendingq_count;		/* # requests on pendingq list. */
 	int requestq_count;		/* # requests on requestq list. */
-	int total_request_count;	/* # requests ever for this AP device. */
+	int total_request_count;	/* # requests ever for this AP device.*/
 	int request_timeout;		/* Request timout in jiffies. */
 	struct timer_list timeout;	/* Timer for request timeouts. */
 	struct list_head pendingq;	/* List of message sent to AP queue. */
diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c
index 731dc0d..0110d44 100644
--- a/drivers/s390/crypto/ap_card.c
+++ b/drivers/s390/crypto/ap_card.c
@@ -63,13 +63,11 @@
 				     char *buf)
 {
 	struct ap_card *ac = to_ap_card(dev);
-	struct ap_queue *aq;
 	unsigned int req_cnt;
 
 	req_cnt = 0;
 	spin_lock_bh(&ap_list_lock);
-	for_each_ap_queue(aq, ac)
-		req_cnt += aq->total_request_count;
+	req_cnt = atomic_read(&ac->total_request_count);
 	spin_unlock_bh(&ap_list_lock);
 	return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt);
 }
diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c
index 8f95a07..b58a917 100644
--- a/drivers/s390/crypto/ap_queue.c
+++ b/drivers/s390/crypto/ap_queue.c
@@ -625,6 +625,7 @@
 	list_add_tail(&ap_msg->list, &aq->requestq);
 	aq->requestq_count++;
 	aq->total_request_count++;
+	atomic_inc(&aq->card->total_request_count);
 	/* Send/receive as many request from the queue as possible. */
 	ap_wait(ap_sm_event_loop(aq, AP_EVENT_POLL));
 	spin_unlock_bh(&aq->lock);
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 403af9d..c7b5e70 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -188,6 +188,34 @@
 	module_put(mod);
 }
 
+static inline bool zcrypt_card_compare(struct zcrypt_card *zc,
+				       struct zcrypt_card *pref_zc,
+				       unsigned weight, unsigned pref_weight)
+{
+	if (!pref_zc)
+		return 0;
+	weight += atomic_read(&zc->load);
+	pref_weight += atomic_read(&pref_zc->load);
+	if (weight == pref_weight)
+		return atomic_read(&zc->card->total_request_count) >
+			atomic_read(&pref_zc->card->total_request_count);
+	return weight > pref_weight;
+}
+
+static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq,
+					struct zcrypt_queue *pref_zq,
+					unsigned weight, unsigned pref_weight)
+{
+	if (!pref_zq)
+		return 0;
+	weight += atomic_read(&zq->load);
+	pref_weight += atomic_read(&pref_zq->load);
+	if (weight == pref_weight)
+		return &zq->queue->total_request_count >
+			&pref_zq->queue->total_request_count;
+	return weight > pref_weight;
+}
+
 /*
  * zcrypt ioctls.
  */
@@ -225,15 +253,14 @@
 			continue;
 		/* get weight index of the card device	*/
 		weight = zc->speed_rating[func_code];
-		if (pref_zc && atomic_read(&zc->load) + weight >=
-		    atomic_read(&pref_zc->load) + pref_weight)
+		if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
 			continue;
 		for_each_zcrypt_queue(zq, zc) {
 			/* check if device is online and eligible */
 			if (!zq->online)
 				continue;
-			if (pref_zq && atomic_read(&zq->load) + weight >=
-			    atomic_read(&pref_zq->load) + pref_weight)
+			if (zcrypt_queue_compare(zq, pref_zq,
+						 weight, pref_weight))
 				continue;
 			pref_zc = zc;
 			pref_zq = zq;
@@ -289,15 +316,14 @@
 			continue;
 		/* get weight index of the card device	*/
 		weight = zc->speed_rating[func_code];
-		if (pref_zc && atomic_read(&zc->load) + weight >=
-		    atomic_read(&pref_zc->load) + pref_weight)
+		if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
 			continue;
 		for_each_zcrypt_queue(zq, zc) {
 			/* check if device is online and eligible */
 			if (!zq->online)
 				continue;
-			if (pref_zq && atomic_read(&zq->load) + weight >=
-			    atomic_read(&pref_zq->load) + pref_weight)
+			if (zcrypt_queue_compare(zq, pref_zq,
+						 weight, pref_weight))
 				continue;
 			pref_zc = zc;
 			pref_zq = zq;
@@ -346,8 +372,7 @@
 			continue;
 		/* get weight index of the card device	*/
 		weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY];
-		if (pref_zc && atomic_read(&zc->load) + weight >=
-		    atomic_read(&pref_zc->load) + pref_weight)
+		if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
 			continue;
 		for_each_zcrypt_queue(zq, zc) {
 			/* check if device is online and eligible */
@@ -355,8 +380,8 @@
 			    ((*domain != (unsigned short) AUTOSELECT) &&
 			     (*domain != AP_QID_QUEUE(zq->queue->qid))))
 				continue;
-			if (pref_zq && atomic_read(&zq->load) + weight >=
-			    atomic_read(&pref_zq->load) + pref_weight)
+			if (zcrypt_queue_compare(zq, pref_zq,
+						 weight, pref_weight))
 				continue;
 			pref_zc = zc;
 			pref_zq = zq;
@@ -450,8 +475,7 @@
 			continue;
 		/* get weight index of the card device	*/
 		weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY];
-		if (pref_zc && atomic_read(&zc->load) + weight >=
-		    atomic_read(&pref_zc->load) + pref_weight)
+		if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
 			continue;
 		for_each_zcrypt_queue(zq, zc) {
 			/* check if device is online and eligible */
@@ -460,8 +484,8 @@
 			     !is_desired_ep11_queue(zq->queue->qid,
 						    target_num, targets)))
 				continue;
-			if (pref_zq && atomic_read(&zq->load) + weight >=
-			    atomic_read(&pref_zq->load) + pref_weight)
+			if (zcrypt_queue_compare(zq, pref_zq,
+						 weight, pref_weight))
 				continue;
 			pref_zc = zc;
 			pref_zq = zq;
@@ -510,15 +534,14 @@
 			continue;
 		/* get weight index of the card device	*/
 		weight = zc->speed_rating[func_code];
-		if (pref_zc && atomic_read(&zc->load) + weight >=
-		    atomic_read(&pref_zc->load) + pref_weight)
+		if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
 			continue;
 		for_each_zcrypt_queue(zq, zc) {
 			/* check if device is online and eligible */
 			if (!zq->online)
 				continue;
-			if (pref_zq && atomic_read(&zq->load) + weight >=
-			    atomic_read(&pref_zq->load) + pref_weight)
+			if (zcrypt_queue_compare(zq, pref_zq,
+						 weight, pref_weight))
 				continue;
 			pref_zc = zc;
 			pref_zq = zq;