Blob Blame History Raw
From: Julian Wiedmann <jwi@linux.ibm.com>
Date: Tue, 24 Aug 2021 09:37:06 +0300
Subject: s390/qdio: avoid allocating the qdio_irq with GFP_DMA
Git-commit: 718ce9e10171f70f2d00c3c89ceb7e406a892bb6
Patch-mainline: v5.17-rc1
References: jsc#PED-588 bsc#1203836 LTC#198623

The qdio_irq contains only two fields that are directly exposed to the
HW (ccw and qib). And only the ccw needs to reside in 31-bit memory. So
allocate it separately, and remove the GFP_DMA constraint from the
qdio_irq allocation.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/s390/cio/qdio.h       |    2 +-
 drivers/s390/cio/qdio_main.c  |   34 ++++++++++++++++++++++------------
 drivers/s390/cio/qdio_setup.c |    1 -
 3 files changed, 23 insertions(+), 14 deletions(-)

--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -236,7 +236,7 @@ struct qdio_irq {
 	int nr_input_qs;
 	int nr_output_qs;
 
-	struct ccw1 ccw;
+	struct ccw1 *ccw;
 
 	struct qdio_ssqd_desc ssqd_desc;
 	void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *);
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/kmemleak.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
 #include <linux/io.h>
@@ -874,6 +875,7 @@ int qdio_free(struct ccw_device *cdev)
 	qdio_free_queues(irq_ptr);
 	free_page((unsigned long) irq_ptr->qdr);
 	free_page(irq_ptr->chsc_page);
+	kfree(irq_ptr->ccw);
 	free_page((unsigned long) irq_ptr);
 	return 0;
 }
@@ -899,11 +901,17 @@ int qdio_allocate(struct ccw_device *cde
 	    no_output_qs > QDIO_MAX_QUEUES_PER_IRQ)
 		return -EINVAL;
 
-	/* irq_ptr must be in GFP_DMA since it contains ccw1.cda */
-	irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	irq_ptr = (void *) get_zeroed_page(GFP_KERNEL);
 	if (!irq_ptr)
 		return -ENOMEM;
 
+	irq_ptr->ccw = kmalloc(sizeof(*irq_ptr->ccw), GFP_KERNEL | GFP_DMA);
+	if (!irq_ptr->ccw)
+		goto err_ccw;
+
+	/* kmemleak doesn't scan the page-allocated irq_ptr: */
+	kmemleak_not_leak(irq_ptr->ccw);
+
 	irq_ptr->cdev = cdev;
 	mutex_init(&irq_ptr->setup_mutex);
 	if (qdio_allocate_dbf(irq_ptr))
@@ -941,6 +949,8 @@ err_qdr:
 	free_page(irq_ptr->chsc_page);
 err_chsc:
 err_dbf:
+	kfree(irq_ptr->ccw);
+err_ccw:
 	free_page((unsigned long) irq_ptr);
 	return rc;
 }
@@ -1012,15 +1022,15 @@ int qdio_establish(struct ccw_device *cd
 		goto err_thinint;
 
 	/* establish q */
-	irq_ptr->ccw.cmd_code = ciw->cmd;
-	irq_ptr->ccw.flags = CCW_FLAG_SLI;
-	irq_ptr->ccw.count = ciw->count;
-	irq_ptr->ccw.cda = (u32) virt_to_phys(irq_ptr->qdr);
+	irq_ptr->ccw->cmd_code = ciw->cmd;
+	irq_ptr->ccw->flags = CCW_FLAG_SLI;
+	irq_ptr->ccw->count = ciw->count;
+	irq_ptr->ccw->cda = (u32) virt_to_phys(irq_ptr->qdr);
 
 	spin_lock_irq(get_ccwdev_lock(cdev));
 	ccw_device_set_options_mask(cdev, 0);
 
-	rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ESTABLISH, 0, 0);
+	rc = ccw_device_start(cdev, irq_ptr->ccw, QDIO_DOING_ESTABLISH, 0, 0);
 	spin_unlock_irq(get_ccwdev_lock(cdev));
 	if (rc) {
 		DBF_ERROR("%4x est IO ERR", irq_ptr->schid.sch_no);
@@ -1093,15 +1103,15 @@ int qdio_activate(struct ccw_device *cde
 		goto out;
 	}
 
-	irq_ptr->ccw.cmd_code = ciw->cmd;
-	irq_ptr->ccw.flags = CCW_FLAG_SLI;
-	irq_ptr->ccw.count = ciw->count;
-	irq_ptr->ccw.cda = 0;
+	irq_ptr->ccw->cmd_code = ciw->cmd;
+	irq_ptr->ccw->flags = CCW_FLAG_SLI;
+	irq_ptr->ccw->count = ciw->count;
+	irq_ptr->ccw->cda = 0;
 
 	spin_lock_irq(get_ccwdev_lock(cdev));
 	ccw_device_set_options(cdev, CCWDEV_REPORT_ALL);
 
-	rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ACTIVATE,
+	rc = ccw_device_start(cdev, irq_ptr->ccw, QDIO_DOING_ACTIVATE,
 			      0, DOIO_DENY_PREFETCH);
 	spin_unlock_irq(get_ccwdev_lock(cdev));
 	if (rc) {
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -369,7 +369,6 @@ void qdio_setup_irq(struct qdio_irq *irq
 	struct ccw_device *cdev = irq_ptr->cdev;
 
 	irq_ptr->qdioac1 = 0;
-	memset(&irq_ptr->ccw, 0, sizeof(irq_ptr->ccw));
 	memset(&irq_ptr->ssqd_desc, 0, sizeof(irq_ptr->ssqd_desc));
 	memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));