From b087dfab4d3902681550fd1f5ff9c3e942059478 Mon Sep 17 00:00:00 2001 From: Patrick Steuer Date: Thu, 4 Nov 2021 15:58:51 +0100 Subject: s390/crypto: add SIMD implementation for ChaCha20 Add an implementation of the ChaCha20 stream cipher (see e.g. RFC 7539) that makes use of z13's vector instruction set extension. The original implementation is by Andy Polyakov which is adapted for kernel use. Four to six blocks are processed in parallel resulting in a performance gain for inputs >= 256 bytes. chacha20-generic 1 operation in 622 cycles (256 bytes) 1 operation in 2346 cycles (1024 bytes) chacha20-s390 1 operation in 218 cycles (256 bytes) 1 operation in 647 cycles (1024 bytes) Cc: Andy Polyakov Reviewed-by: Harald Freudenberger Signed-off-by: Patrick Steuer Signed-off-by: Heiko Carstens --- drivers/crypto/Kconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 51690e73153a..4f705674f94f 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -213,6 +213,18 @@ config CRYPTO_AES_S390 key sizes and XTS mode is hardware accelerated for 256 and 512 bit keys. +config CRYPTO_CHACHA_S390 + tristate "ChaCha20 stream cipher" + depends on S390 + select CRYPTO_ALGAPI + select CRYPTO_SKCIPHER + select CRYPTO_CHACHA20 + help + This is the s390 SIMD implementation of the ChaCha20 stream + cipher (RFC 7539). + + It is available as of z13. + config S390_PRNG tristate "Pseudo random number generator device driver" depends on S390 -- cgit v1.2.3-59-g8ed1b From a84d1c5006b56166dac477e922643ede01cdbb92 Mon Sep 17 00:00:00 2001 From: Vineeth Vijayan Date: Tue, 29 Jun 2021 09:38:22 +0200 Subject: s390/cio: remove uevent suppress from cio driver commit fa1a8c23eb7d ("s390: cio: Delay uevents for subchannels") introduced suppression of uevents for a subchannel until after it is clear that the subchannel would not be unregistered again immediately. This was done to avoid uevents being generated for I/O subchannels with no valid device, which can happen on LPAR. However, this also has some drawbacks: All subchannel drivers need to manually remove the uevent suppression and generate an ADD uevent as soon as they are sure that the subchannel will stay around. This misses out on all uevents that are not the initial ADD uevent that would be generated while uevents are suppressed; for example, all subchannels were missing the BIND uevent. As uevents being generated even for I/O subchannels without an operational device turned out to be not as bad as missing uevents and complicating the code flow, let's remove uevent suppression for subchannels. Signed-off-by: Vineeth Vijayan [cohuck@redhat.com: modified changelog] Reviewed-by: Cornelia Huck Reviewed-by: Peter Oberparleiter Link: https://lore.kernel.org/r/20211122103756.352463-2-vneethv@linux.ibm.com Signed-off-by: Heiko Carstens --- drivers/s390/cio/chsc_sch.c | 5 ----- drivers/s390/cio/css.c | 19 ------------------- drivers/s390/cio/device.c | 20 +++----------------- drivers/s390/cio/eadm_sch.c | 5 ----- drivers/s390/cio/vfio_ccw_drv.c | 5 ----- 5 files changed, 3 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 684348d82f08..962dfa25a310 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -91,11 +91,6 @@ static int chsc_subchannel_probe(struct subchannel *sch) sch->schid.ssid, sch->schid.sch_no, ret); dev_set_drvdata(&sch->dev, NULL); kfree(private); - } else { - if (dev_get_uevent_suppress(&sch->dev)) { - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } } return ret; } diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index ce9e7517430f..fa8293335077 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -470,16 +470,6 @@ int css_register_subchannel(struct subchannel *sch) if (sch->st == SUBCHANNEL_TYPE_IO) sch->dev.type = &io_subchannel_type; - /* - * We don't want to generate uevents for I/O subchannels that don't - * have a working ccw device behind them since they will be - * unregistered before they can be used anyway, so we delay the add - * uevent until after device recognition was successful. - * Note that we suppress the uevent for all subchannel types; - * the subchannel driver can decide itself when it wants to inform - * userspace of its existence. - */ - dev_set_uevent_suppress(&sch->dev, 1); css_update_ssd_info(sch); /* make it known to the system */ ret = css_sch_device_register(sch); @@ -488,15 +478,6 @@ int css_register_subchannel(struct subchannel *sch) sch->schid.ssid, sch->schid.sch_no, ret); return ret; } - if (!sch->driver) { - /* - * No driver matched. Generate the uevent now so that - * a fitting driver module may be loaded based on the - * modalias. - */ - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } return ret; } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 07a17613fab5..cd938a26b76c 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -838,14 +838,6 @@ static void io_subchannel_register(struct ccw_device *cdev) adjust_init_count = 0; goto out; } - /* - * Now we know this subchannel will stay, we can throw - * our delayed uevent. - */ - if (dev_get_uevent_suppress(&sch->dev)) { - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } /* make it known to the system */ ret = device_add(&cdev->dev); if (ret) { @@ -1036,15 +1028,9 @@ static int io_subchannel_probe(struct subchannel *sch) "0.%x.%04x (rc=%d)\n", sch->schid.ssid, sch->schid.sch_no, rc); /* - * The console subchannel already has an associated ccw_device. - * Throw the delayed uevent for the subchannel, register - * the ccw_device and exit. - */ - if (dev_get_uevent_suppress(&sch->dev)) { - /* should always be the case for the console */ - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } + * The console subchannel already has an associated ccw_device. + * Register it and exit. + */ cdev = sch_get_cdev(sch); rc = device_add(&cdev->dev); if (rc) { diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index 15bdae5981ca..8b463681a149 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c @@ -243,11 +243,6 @@ static int eadm_subchannel_probe(struct subchannel *sch) spin_lock_irq(&list_lock); list_add(&private->head, &eadm_list); spin_unlock_irq(&list_lock); - - if (dev_get_uevent_suppress(&sch->dev)) { - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } out: return ret; } diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index 040742777095..ee182cfb467d 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -244,11 +244,6 @@ static int vfio_ccw_sch_probe(struct subchannel *sch) if (ret) goto out_disable; - if (dev_get_uevent_suppress(&sch->dev)) { - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } - VFIO_CCW_MSG_EVENT(4, "bound to subchannel %x.%x.%04x\n", sch->schid.cssid, sch->schid.ssid, sch->schid.sch_no); -- cgit v1.2.3-59-g8ed1b From bd3a025dd22c500d33960b0a1fcf92e27514332c Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 8 Jul 2021 08:49:28 +0200 Subject: s390/qdio: improve handling of CIWs Fetch the individual CIWs when we actually need them, rather than fetching both of them in qdio_setup_irq() and then needing to cache them inside the qdio_irq. Also deal with the error when a CIW is not available, instead of silently dropping this error condition in qdio_setup_irq()'s caller. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Heiko Carstens --- drivers/s390/cio/qdio.h | 4 +--- drivers/s390/cio/qdio_main.c | 22 ++++++++++++++++++---- drivers/s390/cio/qdio_setup.c | 20 +------------------- 3 files changed, 20 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 99c2212dc6a6..5f43e2b0c855 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -237,8 +237,6 @@ struct qdio_irq { int nr_output_qs; struct ccw1 ccw; - struct ciw equeue; - struct ciw aqueue; struct qdio_ssqd_desc ssqd_desc; void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *); @@ -338,7 +336,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, struct subchannel_id *schid, struct qdio_ssqd_desc *data); -int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data); +void qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data); void qdio_shutdown_irq(struct qdio_irq *irq); void qdio_print_subchannel_info(struct qdio_irq *irq_ptr); void qdio_free_queues(struct qdio_irq *irq_ptr); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 45e810c6ea3b..c42ce1933b2e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -972,6 +972,7 @@ int qdio_establish(struct ccw_device *cdev, { struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct subchannel_id schid; + struct ciw *ciw; long timeout; int rc; @@ -996,6 +997,12 @@ int qdio_establish(struct ccw_device *cdev, if (!init_data->irq_poll) return -EINVAL; + ciw = ccw_device_get_ciw(cdev, CIW_TYPE_EQUEUE); + if (!ciw) { + DBF_ERROR("%4x NO EQ", schid.sch_no); + return -EIO; + } + mutex_lock(&irq_ptr->setup_mutex); qdio_trace_init_data(irq_ptr, init_data); qdio_setup_irq(irq_ptr, init_data); @@ -1005,9 +1012,9 @@ int qdio_establish(struct ccw_device *cdev, goto err_thinint; /* establish q */ - irq_ptr->ccw.cmd_code = irq_ptr->equeue.cmd; + irq_ptr->ccw.cmd_code = ciw->cmd; irq_ptr->ccw.flags = CCW_FLAG_SLI; - irq_ptr->ccw.count = irq_ptr->equeue.count; + irq_ptr->ccw.count = ciw->count; irq_ptr->ccw.cda = (u32) virt_to_phys(irq_ptr->qdr); spin_lock_irq(get_ccwdev_lock(cdev)); @@ -1065,6 +1072,7 @@ int qdio_activate(struct ccw_device *cdev) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct subchannel_id schid; + struct ciw *ciw; int rc; ccw_device_get_schid(cdev, &schid); @@ -1073,15 +1081,21 @@ int qdio_activate(struct ccw_device *cdev) if (!irq_ptr) return -ENODEV; + ciw = ccw_device_get_ciw(cdev, CIW_TYPE_AQUEUE); + if (!ciw) { + DBF_ERROR("%4x NO AQ", schid.sch_no); + return -EIO; + } + mutex_lock(&irq_ptr->setup_mutex); if (irq_ptr->state == QDIO_IRQ_STATE_INACTIVE) { rc = -EBUSY; goto out; } - irq_ptr->ccw.cmd_code = irq_ptr->aqueue.cmd; + irq_ptr->ccw.cmd_code = ciw->cmd; irq_ptr->ccw.flags = CCW_FLAG_SLI; - irq_ptr->ccw.count = irq_ptr->aqueue.count; + irq_ptr->ccw.count = ciw->count; irq_ptr->ccw.cda = 0; spin_lock_irq(get_ccwdev_lock(cdev)); diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index efbb5e5eca05..766f1e849fae 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -351,10 +351,9 @@ static void setup_qib(struct qdio_irq *irq_ptr, sizeof(irq_ptr->qib.parm)); } -int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) +void qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) { struct ccw_device *cdev = irq_ptr->cdev; - struct ciw *ciw; irq_ptr->qdioac1 = 0; memset(&irq_ptr->ccw, 0, sizeof(irq_ptr->ccw)); @@ -386,23 +385,6 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) irq_ptr->orig_handler = cdev->handler; cdev->handler = qdio_int_handler; spin_unlock_irq(get_ccwdev_lock(cdev)); - - /* get qdio commands */ - ciw = ccw_device_get_ciw(cdev, CIW_TYPE_EQUEUE); - if (!ciw) { - DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no); - return -EINVAL; - } - irq_ptr->equeue = *ciw; - - ciw = ccw_device_get_ciw(cdev, CIW_TYPE_AQUEUE); - if (!ciw) { - DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no); - return -EINVAL; - } - irq_ptr->aqueue = *ciw; - - return 0; } void qdio_shutdown_irq(struct qdio_irq *irq) -- cgit v1.2.3-59-g8ed1b From 718ce9e10171f70f2d00c3c89ceb7e406a892bb6 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 24 Aug 2021 09:37:06 +0300 Subject: s390/qdio: avoid allocating the qdio_irq with GFP_DMA 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 Reviewed-by: Benjamin Block Signed-off-by: Heiko Carstens --- 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(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 5f43e2b0c855..152c032e74d4 100644 --- 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 *); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index c42ce1933b2e..9b48573db93d 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -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 *cdev, unsigned int no_input_qs, 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 *cdev, 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 *cdev) 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) { diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 766f1e849fae..fd663922d7d5 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -356,7 +356,6 @@ void qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) 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)); -- cgit v1.2.3-59-g8ed1b From 0a86cdcb4ce297f543d13d0bbd4f0c86f00626e5 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 15 Nov 2021 08:21:38 +0100 Subject: s390/qdio: clean up access to queue in qdio_handle_activate_check() qdio_handle_activate_check() re-uses a queue-specific handler to report that the ACTIVATE ccw has been terminated. It uses either the first input or output queue, so we can hard-code q->nr as 0. Also don't access the q->irq_ptr parent pointer, we already have a pointer to the qdio_irq. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Heiko Carstens --- drivers/s390/cio/qdio_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 9b48573db93d..3e586e460f91 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -669,8 +669,8 @@ static void qdio_handle_activate_check(struct qdio_irq *irq_ptr, goto no_handler; } - q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE, - q->nr, q->first_to_check, 0, irq_ptr->int_parm); + q->handler(irq_ptr->cdev, QDIO_ERROR_ACTIVATE, 0, q->first_to_check, + 0, irq_ptr->int_parm); no_handler: qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); /* -- cgit v1.2.3-59-g8ed1b From 513251fe25d304d1ca628c581bd0cc0422de150a Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 15 Nov 2021 08:28:08 +0100 Subject: s390/qdio: clarify handler logic for qdio_handle_activate_check() qdio_handle_activate_check() tries to re-use one of the queue-specific handlers to report that the ACTIVATE ccw has been terminated. But the logic to select that handler is overly complex - in practice both qdio drivers have at least one Input Queue, so we never take the other paths. Make things more obvious by removing this unused code, and clearly spelling out that we re-use the Input Handler for generic error reporting. This also paves the way for a world without queue-specific error handlers. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Heiko Carstens --- arch/s390/include/asm/qdio.h | 2 +- drivers/s390/cio/qdio.h | 1 + drivers/s390/cio/qdio_main.c | 25 +++++++++++-------------- drivers/s390/cio/qdio_setup.c | 1 + 4 files changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index c5a5b454f8dc..97356ec27d37 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -312,7 +312,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, * @qib_rflags: rflags to set * @no_input_qs: number of input queues * @no_output_qs: number of output queues - * @input_handler: handler to be called for input queues + * @input_handler: handler to be called for input queues, and device-wide errors * @output_handler: handler to be called for output queues * @irq_poll: Data IRQ polling handler * @scan_threshold: # of in-use buffers that triggers scan on output queue diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 152c032e74d4..5ea6249d8180 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -240,6 +240,7 @@ struct qdio_irq { struct qdio_ssqd_desc ssqd_desc; void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *); + qdio_handler_t (*error_handler); int perf_stat_enabled; diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 3e586e460f91..35a32240b4ce 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -654,24 +654,18 @@ static void qdio_handle_activate_check(struct qdio_irq *irq_ptr, unsigned long intparm, int cstat, int dstat) { - struct qdio_q *q; + unsigned int first_to_check = 0; DBF_ERROR("%4x ACT CHECK", irq_ptr->schid.sch_no); DBF_ERROR("intp :%lx", intparm); DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); - if (irq_ptr->nr_input_qs) { - q = irq_ptr->input_qs[0]; - } else if (irq_ptr->nr_output_qs) { - q = irq_ptr->output_qs[0]; - } else { - dump_stack(); - goto no_handler; - } + /* zfcp wants this: */ + if (irq_ptr->nr_input_qs) + first_to_check = irq_ptr->input_qs[0]->first_to_check; - q->handler(irq_ptr->cdev, QDIO_ERROR_ACTIVATE, 0, q->first_to_check, - 0, irq_ptr->int_parm); -no_handler: + irq_ptr->error_handler(irq_ptr->cdev, QDIO_ERROR_ACTIVATE, 0, + first_to_check, 0, irq_ptr->int_parm); qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); /* * In case of z/VM LGR (Live Guest Migration) QDIO recovery will happen. @@ -996,8 +990,11 @@ int qdio_establish(struct ccw_device *cdev, init_data->no_output_qs > irq_ptr->max_output_qs) return -EINVAL; - if ((init_data->no_input_qs && !init_data->input_handler) || - (init_data->no_output_qs && !init_data->output_handler)) + /* Needed as error_handler: */ + if (!init_data->input_handler) + return -EINVAL; + + if (init_data->no_output_qs && !init_data->output_handler) return -EINVAL; if (!init_data->input_sbal_addr_array || diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index fd663922d7d5..714878e2acc4 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -362,6 +362,7 @@ void qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) irq_ptr->debugfs_dev = NULL; irq_ptr->sch_token = irq_ptr->perf_stat_enabled = 0; irq_ptr->state = QDIO_IRQ_STATE_INACTIVE; + irq_ptr->error_handler = init_data->input_handler; irq_ptr->int_parm = init_data->int_parm; irq_ptr->nr_input_qs = init_data->no_input_qs; -- cgit v1.2.3-59-g8ed1b From b44995e515227e68af8a337c0538e17b05ae560f Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 23 Jul 2021 09:16:10 +0200 Subject: s390/qdio: split qdio_inspect_queue() The callers know what type of queue they want to inspect. Introduce type-specific variants to inspect an {Input,Output} queue, so that we can avoid one function parameter and some conditional branches in the hot paths. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Heiko Carstens --- arch/s390/include/asm/qdio.h | 7 ++-- drivers/s390/cio/qdio_main.c | 84 +++++++++++++++++++++++---------------- drivers/s390/net/qeth_core_main.c | 16 ++++---- drivers/s390/scsi/zfcp_qdio.c | 4 +- 4 files changed, 64 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 97356ec27d37..5eb431f59ede 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -352,9 +352,10 @@ extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, int q_nr, unsigned int bufnr, unsigned int count, struct qaob *aob); extern int qdio_start_irq(struct ccw_device *cdev); extern int qdio_stop_irq(struct ccw_device *cdev); -extern int qdio_inspect_queue(struct ccw_device *cdev, unsigned int nr, - bool is_input, unsigned int *bufnr, - unsigned int *error); +extern int qdio_inspect_input_queue(struct ccw_device *cdev, unsigned int nr, + unsigned int *bufnr, unsigned int *error); +extern int qdio_inspect_output_queue(struct ccw_device *cdev, unsigned int nr, + unsigned int *bufnr, unsigned int *error); extern int qdio_shutdown(struct ccw_device *, int); extern int qdio_free(struct ccw_device *); extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 35a32240b4ce..3f047faf59f0 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -500,6 +500,31 @@ static int get_inbound_buffer_frontier(struct qdio_q *q, unsigned int start, } } +int qdio_inspect_input_queue(struct ccw_device *cdev, unsigned int nr, + unsigned int *bufnr, unsigned int *error) +{ + struct qdio_irq *irq = cdev->private->qdio_data; + unsigned int start; + struct qdio_q *q; + int count; + + if (!irq) + return -ENODEV; + + q = irq->input_qs[nr]; + start = q->first_to_check; + *error = 0; + + count = get_inbound_buffer_frontier(q, start, error); + if (count == 0) + return 0; + + *bufnr = start; + q->first_to_check = add_buf(start, count); + return count; +} +EXPORT_SYMBOL_GPL(qdio_inspect_input_queue); + static inline int qdio_inbound_q_done(struct qdio_q *q, unsigned int start) { unsigned char state = 0; @@ -579,6 +604,31 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start, } } +int qdio_inspect_output_queue(struct ccw_device *cdev, unsigned int nr, + unsigned int *bufnr, unsigned int *error) +{ + struct qdio_irq *irq = cdev->private->qdio_data; + unsigned int start; + struct qdio_q *q; + int count; + + if (!irq) + return -ENODEV; + + q = irq->output_qs[nr]; + start = q->first_to_check; + *error = 0; + + count = get_outbound_buffer_frontier(q, start, error); + if (count == 0) + return 0; + + *bufnr = start; + q->first_to_check = add_buf(start, count); + return count; +} +EXPORT_SYMBOL_GPL(qdio_inspect_output_queue); + static int qdio_kick_outbound_q(struct qdio_q *q, unsigned int count, unsigned long aob) { @@ -1284,40 +1334,6 @@ rescan: } EXPORT_SYMBOL(qdio_start_irq); -static int __qdio_inspect_queue(struct qdio_q *q, unsigned int *bufnr, - unsigned int *error) -{ - unsigned int start = q->first_to_check; - int count; - - *error = 0; - count = q->is_input_q ? get_inbound_buffer_frontier(q, start, error) : - get_outbound_buffer_frontier(q, start, error); - if (count == 0) - return 0; - - *bufnr = start; - - /* for the next time */ - q->first_to_check = add_buf(start, count); - - return count; -} - -int qdio_inspect_queue(struct ccw_device *cdev, unsigned int nr, bool is_input, - unsigned int *bufnr, unsigned int *error) -{ - struct qdio_irq *irq_ptr = cdev->private->qdio_data; - struct qdio_q *q; - - if (!irq_ptr) - return -ENODEV; - q = is_input ? irq_ptr->input_qs[nr] : irq_ptr->output_qs[nr]; - - return __qdio_inspect_queue(q, bufnr, error); -} -EXPORT_SYMBOL_GPL(qdio_inspect_queue); - /** * qdio_stop_irq - disable interrupt processing for the device * @cdev: associated ccw_device for the qdio subchannel diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 26c55f67289f..8cfbcb6aec07 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5850,10 +5850,10 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget) /* Fetch completed RX buffers: */ if (!card->rx.b_count) { card->rx.qdio_err = 0; - card->rx.b_count = qdio_inspect_queue(CARD_DDEV(card), - 0, true, - &card->rx.b_index, - &card->rx.qdio_err); + card->rx.b_count = + qdio_inspect_input_queue(CARD_DDEV(card), 0, + &card->rx.b_index, + &card->rx.qdio_err); if (card->rx.b_count <= 0) { card->rx.b_count = 0; break; @@ -5900,8 +5900,8 @@ static void qeth_cq_poll(struct qeth_card *card) unsigned int start, error; int completed; - completed = qdio_inspect_queue(CARD_DDEV(card), 1, true, &start, - &error); + completed = qdio_inspect_input_queue(CARD_DDEV(card), 1, &start, + &error); if (completed <= 0) return; @@ -6038,8 +6038,8 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget) return 0; } - completed = qdio_inspect_queue(CARD_DDEV(card), queue_no, false, - &start, &error); + completed = qdio_inspect_output_queue(CARD_DDEV(card), queue_no, + &start, &error); if (completed <= 0) { /* Ensure we see TX completion for pending work: */ if (napi_complete_done(napi, 0) && diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 6a2720105138..728945c70621 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -79,7 +79,7 @@ static void zfcp_qdio_request_tasklet(struct tasklet_struct *tasklet) unsigned int start, error; int completed; - completed = qdio_inspect_queue(cdev, 0, false, &start, &error); + completed = qdio_inspect_output_queue(cdev, 0, &start, &error); if (completed > 0) { if (error) { zfcp_qdio_handler_error(qdio, "qdreqt1", error); @@ -169,7 +169,7 @@ static void zfcp_qdio_irq_tasklet(struct tasklet_struct *tasklet) tasklet_schedule(&qdio->request_tasklet); /* Check the Response Queue: */ - completed = qdio_inspect_queue(cdev, 0, true, &start, &error); + completed = qdio_inspect_input_queue(cdev, 0, &start, &error); if (completed < 0) return; if (completed > 0) -- cgit v1.2.3-59-g8ed1b From a60bffe536f90834ddedc0ed4ddf81af943eb061 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 30 Aug 2021 15:28:36 +0300 Subject: s390/qdio: split do_QDIO() The callers know what type of queue they want to work with. Introduce type-specific variants to add buffers on an {Input,Output} queue, so that we can avoid some function parameters and the de-muxing into type-specific hot paths. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Heiko Carstens --- arch/s390/include/asm/qdio.h | 11 +++++---- drivers/s390/cio/qdio_main.c | 51 +++++++++++++++++++++++++++++---------- drivers/s390/net/qeth_core_main.c | 20 +++++++-------- drivers/s390/scsi/zfcp_qdio.c | 15 +++++++----- 4 files changed, 63 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 5eb431f59ede..c65652fa2dbd 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -336,9 +336,6 @@ struct qdio_initialize { struct qdio_buffer ***output_sbal_addr_array; }; -#define QDIO_FLAG_SYNC_INPUT 0x01 -#define QDIO_FLAG_SYNC_OUTPUT 0x02 - int qdio_alloc_buffers(struct qdio_buffer **buf, unsigned int count); void qdio_free_buffers(struct qdio_buffer **buf, unsigned int count); void qdio_reset_buffers(struct qdio_buffer **buf, unsigned int count); @@ -348,14 +345,18 @@ extern int qdio_allocate(struct ccw_device *cdev, unsigned int no_input_qs, extern int qdio_establish(struct ccw_device *cdev, struct qdio_initialize *init_data); extern int qdio_activate(struct ccw_device *); -extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, int q_nr, - unsigned int bufnr, unsigned int count, struct qaob *aob); extern int qdio_start_irq(struct ccw_device *cdev); extern int qdio_stop_irq(struct ccw_device *cdev); extern int qdio_inspect_input_queue(struct ccw_device *cdev, unsigned int nr, unsigned int *bufnr, unsigned int *error); extern int qdio_inspect_output_queue(struct ccw_device *cdev, unsigned int nr, unsigned int *bufnr, unsigned int *error); +extern int qdio_add_bufs_to_input_queue(struct ccw_device *cdev, + unsigned int q_nr, unsigned int bufnr, + unsigned int count); +extern int qdio_add_bufs_to_output_queue(struct ccw_device *cdev, + unsigned int q_nr, unsigned int bufnr, + unsigned int count, struct qaob *aob); extern int qdio_shutdown(struct ccw_device *, int); extern int qdio_free(struct ccw_device *); extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 3f047faf59f0..82c2383b0740 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1214,6 +1214,35 @@ static int handle_inbound(struct qdio_q *q, int bufnr, int count) return 0; } +/** + * qdio_add_bufs_to_input_queue - process buffers on an Input Queue + * @cdev: associated ccw_device for the qdio subchannel + * @q_nr: queue number + * @bufnr: buffer number + * @count: how many buffers to process + */ +int qdio_add_bufs_to_input_queue(struct ccw_device *cdev, unsigned int q_nr, + unsigned int bufnr, unsigned int count) +{ + struct qdio_irq *irq_ptr = cdev->private->qdio_data; + + if (bufnr >= QDIO_MAX_BUFFERS_PER_Q || count > QDIO_MAX_BUFFERS_PER_Q) + return -EINVAL; + + if (!irq_ptr) + return -ENODEV; + + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "addi b:%02x c:%02x", bufnr, count); + + if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) + return -EIO; + if (!count) + return 0; + + return handle_inbound(irq_ptr->input_qs[q_nr], bufnr, count); +} +EXPORT_SYMBOL_GPL(qdio_add_bufs_to_input_queue); + /** * handle_outbound - process filled outbound buffers * @q: queue containing the buffers @@ -1255,16 +1284,16 @@ static int handle_outbound(struct qdio_q *q, unsigned int bufnr, unsigned int co } /** - * do_QDIO - process input or output buffers + * qdio_add_bufs_to_output_queue - process buffers on an Output Queue * @cdev: associated ccw_device for the qdio subchannel - * @callflags: input or output and special flags from the program * @q_nr: queue number * @bufnr: buffer number * @count: how many buffers to process - * @aob: asynchronous operation block (outbound only) + * @aob: asynchronous operation block */ -int do_QDIO(struct ccw_device *cdev, unsigned int callflags, - int q_nr, unsigned int bufnr, unsigned int count, struct qaob *aob) +int qdio_add_bufs_to_output_queue(struct ccw_device *cdev, unsigned int q_nr, + unsigned int bufnr, unsigned int count, + struct qaob *aob) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; @@ -1274,20 +1303,16 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, if (!irq_ptr) return -ENODEV; - DBF_DEV_EVENT(DBF_INFO, irq_ptr, - "do%02x b:%02x c:%02x", callflags, bufnr, count); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "addo b:%02x c:%02x", bufnr, count); if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) return -EIO; if (!count) return 0; - if (callflags & QDIO_FLAG_SYNC_INPUT) - return handle_inbound(irq_ptr->input_qs[q_nr], bufnr, count); - else if (callflags & QDIO_FLAG_SYNC_OUTPUT) - return handle_outbound(irq_ptr->output_qs[q_nr], bufnr, count, aob); - return -EINVAL; + + return handle_outbound(irq_ptr->output_qs[q_nr], bufnr, count, aob); } -EXPORT_SYMBOL_GPL(do_QDIO); +EXPORT_SYMBOL_GPL(qdio_add_bufs_to_output_queue); /** * qdio_start_irq - enable interrupt processing for the device diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 8cfbcb6aec07..fe2c4c699d37 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -355,8 +355,8 @@ static int qeth_cq_init(struct qeth_card *card) qdio_reset_buffers(card->qdio.c_q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q); card->qdio.c_q->next_buf_to_init = 127; - rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 1, 0, 127, - NULL); + + rc = qdio_add_bufs_to_input_queue(CARD_DDEV(card), 1, 0, 127); if (rc) { QETH_CARD_TEXT_(card, 2, "1err%d", rc); goto out; @@ -2926,8 +2926,7 @@ static int qeth_init_qdio_queues(struct qeth_card *card) } card->qdio.in_q->next_buf_to_init = QDIO_BUFNR(rx_bufs); - rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0, rx_bufs, - NULL); + rc = qdio_add_bufs_to_input_queue(CARD_DDEV(card), 0, 0, rx_bufs); if (rc) { QETH_CARD_TEXT_(card, 2, "1err%d", rc); return rc; @@ -3415,8 +3414,9 @@ static unsigned int qeth_rx_refill_queue(struct qeth_card *card, return 0; } - rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, - queue->next_buf_to_init, count, NULL); + rc = qdio_add_bufs_to_input_queue(CARD_DDEV(card), 0, + queue->next_buf_to_init, + count); if (rc) { QETH_CARD_TEXT(card, 2, "qinberr"); } @@ -3588,8 +3588,8 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, } QETH_TXQ_STAT_INC(queue, doorbell); - rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_OUTPUT, queue->queue_no, - index, count, aob); + rc = qdio_add_bufs_to_output_queue(CARD_DDEV(card), queue->queue_no, + index, count, aob); switch (rc) { case 0: @@ -3739,8 +3739,8 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err, } qeth_scrub_qdio_buffer(buffer, QDIO_MAX_ELEMENTS_PER_BUFFER); } - rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, queue, - cq->next_buf_to_init, count, NULL); + rc = qdio_add_bufs_to_input_queue(CARD_DDEV(card), queue, + cq->next_buf_to_init, count); if (rc) { dev_warn(&card->gdev->dev, "QDIO reported an error, rc=%i\n", rc); diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 728945c70621..f54f506b02d6 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -154,7 +154,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, /* * put SBALs back to response queue */ - if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count, NULL)) + if (qdio_add_bufs_to_input_queue(cdev, 0, idx, count)) zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2"); } @@ -326,8 +326,9 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) atomic_sub(sbal_number, &qdio->req_q_free); - retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, - q_req->sbal_first, sbal_number, NULL); + retval = qdio_add_bufs_to_output_queue(qdio->adapter->ccw_device, 0, + q_req->sbal_first, sbal_number, + NULL); if (unlikely(retval)) { /* Failed to submit the IO, roll back our modifications. */ @@ -395,7 +396,10 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return; - /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ + /* + * Clear QDIOUP flag, thus qdio_add_bufs_to_output_queue() is not called + * during qdio_shutdown(). + */ spin_lock_irq(&qdio->req_q_lock); atomic_andnot(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); spin_unlock_irq(&qdio->req_q_lock); @@ -498,8 +502,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) sbale->addr = 0; } - if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q, - NULL)) + if (qdio_add_bufs_to_input_queue(cdev, 0, 0, QDIO_MAX_BUFFERS_PER_Q)) goto failed_qdio; /* set index of first available SBALS / number of available SBALS */ -- cgit v1.2.3-59-g8ed1b From 97aa7468f697383e0ed5babd1168aaed8a660dc0 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 25 Nov 2021 19:30:07 +0100 Subject: s390/vmcp: use page_to_virt instead of page_to_phys Fix wrong usage of page_to_phys/phys_to_page. Note: this currently doesn't fix a real bug, since virtual addresses are indentical to physical ones. Acked-by: Thomas Richter Signed-off-by: Heiko Carstens --- drivers/s390/char/vmcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 9e066281e2d0..4cebfaaa22b4 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -72,7 +72,7 @@ static void vmcp_response_alloc(struct vmcp_session *session) if (order > 2) page = cma_alloc(vmcp_cma, nr_pages, 0, false); if (page) { - session->response = (char *)page_to_phys(page); + session->response = (char *)page_to_virt(page); session->cma_alloc = 1; return; } @@ -89,7 +89,7 @@ static void vmcp_response_free(struct vmcp_session *session) order = get_order(session->bufsize); nr_pages = ALIGN(session->bufsize, PAGE_SIZE) >> PAGE_SHIFT; if (session->cma_alloc) { - page = phys_to_page((unsigned long)session->response); + page = virt_to_page((unsigned long)session->response); cma_release(vmcp_cma, page, nr_pages); session->cma_alloc = 0; } else { -- cgit v1.2.3-59-g8ed1b From 568de506e31749ae9140c1a804f3b1d1ab47b4c2 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 25 Nov 2021 16:46:00 +0100 Subject: s390/pci: use physical addresses in DMA tables The entries in the DMA translation tables for our IOMMU must specify physical addresses of either the next level table or the final page to be mapped for DMA. Currently however the code simply passes the virtual addresses of both. On the other hand we still need to walk the tables via their virtual addresses so we need to do a phys_to_virt() when setting the entries and a virt_to_phys() when getting them. Similarly when passing the I/O translation anchor to the hardware we must also specify its physical address. As the DMA and IOMMU APIs we are implementing already use the correct phys_addr_t type for the address to be mapped let's also thread this through instead of treating it as just an unsigned long. Note: this currently doesn't fix a real bug, since virtual addresses are indentical to physical ones. Reviewed-by: Pierre Morel Signed-off-by: Niklas Schnelle Signed-off-by: Heiko Carstens --- arch/s390/include/asm/pci_dma.h | 29 ++++++++++++++++------------- arch/s390/pci/pci.c | 2 +- arch/s390/pci/pci_dma.c | 26 +++++++++++++------------- drivers/iommu/s390-iommu.c | 10 +++++----- 4 files changed, 35 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/arch/s390/include/asm/pci_dma.h b/arch/s390/include/asm/pci_dma.h index 3b8e89d4578a..91e63426bdc5 100644 --- a/arch/s390/include/asm/pci_dma.h +++ b/arch/s390/include/asm/pci_dma.h @@ -97,23 +97,23 @@ static inline unsigned int calc_px(dma_addr_t ptr) return ((unsigned long) ptr >> PAGE_SHIFT) & ZPCI_PT_MASK; } -static inline void set_pt_pfaa(unsigned long *entry, void *pfaa) +static inline void set_pt_pfaa(unsigned long *entry, phys_addr_t pfaa) { *entry &= ZPCI_PTE_FLAG_MASK; - *entry |= ((unsigned long) pfaa & ZPCI_PTE_ADDR_MASK); + *entry |= (pfaa & ZPCI_PTE_ADDR_MASK); } -static inline void set_rt_sto(unsigned long *entry, void *sto) +static inline void set_rt_sto(unsigned long *entry, phys_addr_t sto) { *entry &= ZPCI_RTE_FLAG_MASK; - *entry |= ((unsigned long) sto & ZPCI_RTE_ADDR_MASK); + *entry |= (sto & ZPCI_RTE_ADDR_MASK); *entry |= ZPCI_TABLE_TYPE_RTX; } -static inline void set_st_pto(unsigned long *entry, void *pto) +static inline void set_st_pto(unsigned long *entry, phys_addr_t pto) { *entry &= ZPCI_STE_FLAG_MASK; - *entry |= ((unsigned long) pto & ZPCI_STE_ADDR_MASK); + *entry |= (pto & ZPCI_STE_ADDR_MASK); *entry |= ZPCI_TABLE_TYPE_SX; } @@ -169,16 +169,19 @@ static inline int pt_entry_isvalid(unsigned long entry) static inline unsigned long *get_rt_sto(unsigned long entry) { - return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX) - ? (unsigned long *) (entry & ZPCI_RTE_ADDR_MASK) - : NULL; + if ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX) + return phys_to_virt(entry & ZPCI_RTE_ADDR_MASK); + else + return NULL; + } static inline unsigned long *get_st_pto(unsigned long entry) { - return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_SX) - ? (unsigned long *) (entry & ZPCI_STE_ADDR_MASK) - : NULL; + if ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_SX) + return phys_to_virt(entry & ZPCI_STE_ADDR_MASK); + else + return NULL; } /* Prototypes */ @@ -186,7 +189,7 @@ void dma_free_seg_table(unsigned long); unsigned long *dma_alloc_cpu_table(void); void dma_cleanup_tables(unsigned long *); unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr); -void dma_update_cpu_trans(unsigned long *entry, void *page_addr, int flags); +void dma_update_cpu_trans(unsigned long *entry, phys_addr_t page_addr, int flags); extern const struct dma_map_ops s390_pci_dma_ops; diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 2f9b78fa82a5..792f8e0f2178 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -771,7 +771,7 @@ int zpci_hot_reset_device(struct zpci_dev *zdev) if (zdev->dma_table) rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, - (u64)zdev->dma_table); + virt_to_phys(zdev->dma_table)); else rc = zpci_dma_init_device(zdev); if (rc) { diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index 1f4540d6bd2d..f46833a25526 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c @@ -74,7 +74,7 @@ static unsigned long *dma_get_seg_table_origin(unsigned long *entry) if (!sto) return NULL; - set_rt_sto(entry, sto); + set_rt_sto(entry, virt_to_phys(sto)); validate_rt_entry(entry); entry_clr_protected(entry); } @@ -91,7 +91,7 @@ static unsigned long *dma_get_page_table_origin(unsigned long *entry) pto = dma_alloc_page_table(); if (!pto) return NULL; - set_st_pto(entry, pto); + set_st_pto(entry, virt_to_phys(pto)); validate_st_entry(entry); entry_clr_protected(entry); } @@ -117,7 +117,7 @@ unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr) return &pto[px]; } -void dma_update_cpu_trans(unsigned long *entry, void *page_addr, int flags) +void dma_update_cpu_trans(unsigned long *entry, phys_addr_t page_addr, int flags) { if (flags & ZPCI_PTE_INVALID) { invalidate_pt_entry(entry); @@ -132,11 +132,11 @@ void dma_update_cpu_trans(unsigned long *entry, void *page_addr, int flags) entry_clr_protected(entry); } -static int __dma_update_trans(struct zpci_dev *zdev, unsigned long pa, +static int __dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa, dma_addr_t dma_addr, size_t size, int flags) { unsigned int nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; - u8 *page_addr = (u8 *) (pa & PAGE_MASK); + phys_addr_t page_addr = (pa & PAGE_MASK); unsigned long irq_flags; unsigned long *entry; int i, rc = 0; @@ -217,7 +217,7 @@ out: return ret; } -static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa, +static int dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa, dma_addr_t dma_addr, size_t size, int flags) { int rc; @@ -400,7 +400,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size, { struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); struct page *page; - unsigned long pa; + phys_addr_t pa; dma_addr_t map; size = PAGE_ALIGN(size); @@ -411,18 +411,18 @@ static void *s390_dma_alloc(struct device *dev, size_t size, pa = page_to_phys(page); map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, 0); if (dma_mapping_error(dev, map)) { - free_pages(pa, get_order(size)); + __free_pages(page, get_order(size)); return NULL; } atomic64_add(size / PAGE_SIZE, &zdev->allocated_pages); if (dma_handle) *dma_handle = map; - return (void *) pa; + return phys_to_virt(pa); } static void s390_dma_free(struct device *dev, size_t size, - void *pa, dma_addr_t dma_handle, + void *vaddr, dma_addr_t dma_handle, unsigned long attrs) { struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); @@ -430,7 +430,7 @@ static void s390_dma_free(struct device *dev, size_t size, size = PAGE_ALIGN(size); atomic64_sub(size / PAGE_SIZE, &zdev->allocated_pages); s390_dma_unmap_pages(dev, dma_handle, size, DMA_BIDIRECTIONAL, 0); - free_pages((unsigned long) pa, get_order(size)); + free_pages((unsigned long)vaddr, get_order(size)); } /* Map a segment into a contiguous dma address area */ @@ -443,7 +443,7 @@ static int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg, dma_addr_t dma_addr_base, dma_addr; int flags = ZPCI_PTE_VALID; struct scatterlist *s; - unsigned long pa = 0; + phys_addr_t pa = 0; int ret; dma_addr_base = dma_alloc_address(dev, nr_pages); @@ -598,7 +598,7 @@ int zpci_dma_init_device(struct zpci_dev *zdev) } if (zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, - (u64)zdev->dma_table)) { + virt_to_phys(zdev->dma_table))) { rc = -EIO; goto free_bitmap; } diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index 83df387e70a3..50860ebdd087 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -109,7 +109,7 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, zdev->dma_table = s390_domain->dma_table; cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, - (u64) zdev->dma_table); + virt_to_phys(zdev->dma_table)); if (cc) { rc = -EIO; goto out_restore; @@ -205,11 +205,11 @@ static void s390_iommu_release_device(struct device *dev) } static int s390_iommu_update_trans(struct s390_domain *s390_domain, - unsigned long pa, dma_addr_t dma_addr, + phys_addr_t pa, dma_addr_t dma_addr, size_t size, int flags) { struct s390_domain_device *domain_device; - u8 *page_addr = (u8 *) (pa & PAGE_MASK); + phys_addr_t page_addr = pa & PAGE_MASK; dma_addr_t start_dma_addr = dma_addr; unsigned long irq_flags, nr_pages, i; unsigned long *entry; @@ -274,7 +274,7 @@ static int s390_iommu_map(struct iommu_domain *domain, unsigned long iova, if (!(prot & IOMMU_WRITE)) flags |= ZPCI_TABLE_PROTECTED; - rc = s390_iommu_update_trans(s390_domain, (unsigned long) paddr, iova, + rc = s390_iommu_update_trans(s390_domain, paddr, iova, size, flags); return rc; @@ -324,7 +324,7 @@ static size_t s390_iommu_unmap(struct iommu_domain *domain, if (!paddr) return 0; - rc = s390_iommu_update_trans(s390_domain, (unsigned long) paddr, iova, + rc = s390_iommu_update_trans(s390_domain, paddr, iova, size, flags); if (rc) return 0; -- cgit v1.2.3-59-g8ed1b From e628f28793033ff760c82e04a73abe415b10a66c Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 24 Nov 2021 10:16:53 +0100 Subject: s390/qdio: remove unneeded sanity check in qdio_do_sqbs() All callers of set_buf_states() are already making sure that 'count' is not 0. So don't check it an additional time. Note that our own code also doesn't _require_ the count to be sane (ie. we can't overrun an array or similar). So worst case HW would simply reject the SQBS operation and report an error. Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Heiko Carstens --- drivers/s390/cio/qdio_main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 82c2383b0740..9cde55730b65 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -170,8 +170,6 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, int tmp_count = count, tmp_start = start; int nr = q->nr; - if (!count) - return 0; qperf_inc(q, sqbs); if (!q->is_input_q) -- cgit v1.2.3-59-g8ed1b From f139862b92cf85bd25cbe7c8683d63c037e6562c Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Wed, 27 Oct 2021 11:20:14 -0400 Subject: s390/vfio-ap: add status attribute to AP queue device's sysfs dir This patch adds a sysfs 'status' attribute to a queue device when it is bound to the vfio_ap device driver. The field displays a string indicating the status of the queue device: Status String: Indicates: ------------- --------- "assigned" the queue is assigned to an mdev, but is not in use by a KVM guest. "in use" the queue is assigned to an mdev and is in use by a KVM guest. "unassigned" the queue is not assigned to an mdev. The status string will be displayed by the 'lszcrypt' command if the queue device is bound to the vfio_ap device driver. Signed-off-by: Harald Freudenberger [akrowiak@linux.ibm.com: added check for queue in use by guest] Signed-off-by: Tony Krowiak Signed-off-by: Heiko Carstens --- drivers/s390/crypto/vfio_ap_drv.c | 79 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c index 03311a476366..e043ae236630 100644 --- a/drivers/s390/crypto/vfio_ap_drv.c +++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -17,6 +17,9 @@ #define VFIO_AP_ROOT_NAME "vfio_ap" #define VFIO_AP_DEV_NAME "matrix" +#define AP_QUEUE_ASSIGNED "assigned" +#define AP_QUEUE_UNASSIGNED "unassigned" +#define AP_QUEUE_IN_USE "in use" MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018"); @@ -41,26 +44,95 @@ static struct ap_device_id ap_queue_ids[] = { MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids); +static struct ap_matrix_mdev *vfio_ap_mdev_for_queue(struct vfio_ap_queue *q) +{ + struct ap_matrix_mdev *matrix_mdev; + unsigned long apid = AP_QID_CARD(q->apqn); + unsigned long apqi = AP_QID_QUEUE(q->apqn); + + list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) { + if (test_bit_inv(apid, matrix_mdev->matrix.apm) && + test_bit_inv(apqi, matrix_mdev->matrix.aqm)) + return matrix_mdev; + } + + return NULL; +} + +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t nchars = 0; + struct vfio_ap_queue *q; + struct ap_matrix_mdev *matrix_mdev; + struct ap_device *apdev = to_ap_dev(dev); + + mutex_lock(&matrix_dev->lock); + q = dev_get_drvdata(&apdev->device); + matrix_mdev = vfio_ap_mdev_for_queue(q); + + if (matrix_mdev) { + if (matrix_mdev->kvm) + nchars = scnprintf(buf, PAGE_SIZE, "%s\n", + AP_QUEUE_IN_USE); + else + nchars = scnprintf(buf, PAGE_SIZE, "%s\n", + AP_QUEUE_ASSIGNED); + } else { + nchars = scnprintf(buf, PAGE_SIZE, "%s\n", + AP_QUEUE_UNASSIGNED); + } + + mutex_unlock(&matrix_dev->lock); + + return nchars; +} + +static DEVICE_ATTR_RO(status); + +static struct attribute *vfio_queue_attrs[] = { + &dev_attr_status.attr, + NULL, +}; + +static const struct attribute_group vfio_queue_attr_group = { + .attrs = vfio_queue_attrs, +}; + /** * vfio_ap_queue_dev_probe: Allocate a vfio_ap_queue structure and associate it * with the device as driver_data. * * @apdev: the AP device being probed * - * Return: returns 0 if the probe succeeded; otherwise, returns -ENOMEM if - * storage could not be allocated for a vfio_ap_queue object. + * Return: returns 0 if the probe succeeded; otherwise, returns an error if + * storage could not be allocated for a vfio_ap_queue object or the + * sysfs 'status' attribute could not be created for the queue device. */ static int vfio_ap_queue_dev_probe(struct ap_device *apdev) { + int ret; struct vfio_ap_queue *q; q = kzalloc(sizeof(*q), GFP_KERNEL); if (!q) return -ENOMEM; + + mutex_lock(&matrix_dev->lock); dev_set_drvdata(&apdev->device, q); q->apqn = to_ap_queue(&apdev->device)->qid; q->saved_isc = VFIO_AP_ISC_INVALID; - return 0; + + ret = sysfs_create_group(&apdev->device.kobj, &vfio_queue_attr_group); + if (ret) { + dev_set_drvdata(&apdev->device, NULL); + kfree(q); + } + + mutex_unlock(&matrix_dev->lock); + + return ret; } /** @@ -75,6 +147,7 @@ static void vfio_ap_queue_dev_remove(struct ap_device *apdev) struct vfio_ap_queue *q; mutex_lock(&matrix_dev->lock); + sysfs_remove_group(&apdev->device.kobj, &vfio_queue_attr_group); q = dev_get_drvdata(&apdev->device); vfio_ap_mdev_reset_queue(q, 1); dev_set_drvdata(&apdev->device, NULL); -- cgit v1.2.3-59-g8ed1b From b6b486ecef02916af8a430397ccd5a68c5b967b1 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 13 Dec 2021 18:59:02 +0100 Subject: s390/sclp: fix memblock_phys_free() vs memblock_free() confusion memblock_phys_free() is used on a virtual address. Fix this by using memblock_free(). Note: this doesn't fix a bug currently, since virtual and physical addresses are identical. Reviewed-by: Alexander Gordeev Signed-off-by: Heiko Carstens --- drivers/s390/char/sclp_early.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index b64feab62caa..e9943a86c361 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -139,7 +139,7 @@ int __init sclp_early_get_core_info(struct sclp_core_info *info) } sclp_fill_core_info(info, sccb); out: - memblock_phys_free((unsigned long)sccb, length); + memblock_free(sccb, length); return rc; } -- cgit v1.2.3-59-g8ed1b From cff2d3abc8da078a0447d785736204d8a0ad49b0 Mon Sep 17 00:00:00 2001 From: Juergen Christ Date: Mon, 22 Nov 2021 14:01:34 +0100 Subject: s390/zcrypt: CCA control CPRB sending When sending a CCA CPRB to a control domain, the CPRB has to be sent via a usage domain. Previous code used the default domain to route this message. If the default domain is not online and ready to send the CPRB, the ioctl will fail even if other usage domains could be used to send the CPRB. To improve this, instead of using the default domain, switch to auto-select of the domain. Signed-off-by: Juergen Christ Reviewed-by: Harald Freudenberger Signed-off-by: Heiko Carstens --- drivers/s390/crypto/zcrypt_api.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 4c3dcc435e83..9811ab81f3c4 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -878,14 +878,13 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, /* * If a valid target domain is set and this domain is NOT a usage - * domain but a control only domain, use the default domain as target. + * domain but a control only domain, autoselect target domain. */ tdom = *domain; if (tdom < AP_DOMAINS && !ap_test_config_usage_domain(tdom) && - ap_test_config_ctrl_domain(tdom) && - ap_domain_index >= 0) - tdom = ap_domain_index; + ap_test_config_ctrl_domain(tdom)) + tdom = AUTOSEL_DOM; pref_zc = NULL; pref_zq = NULL; -- cgit v1.2.3-59-g8ed1b From 1350f36d3825e8f9563bbffb047d6ee634949667 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 6 Jan 2022 10:52:52 +0100 Subject: s390/sclp_sd: use default_groups in kobj_type There are currently 2 ways to create a set of sysfs files for a kobj_type, through the default_attrs field, and the default_groups field. Move the sclp_sd sysfs code to use default_groups field which has been the preferred way since commit aa30f47cf666 ("kobject: Add support for default attribute groups to kobj_type") so that we can soon get rid of the obsolete default_attrs field. Cc: Vasily Gorbik Cc: Christian Borntraeger Cc: Alexander Gordeev Cc: Peter Oberparleiter Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20220106095252.3273905-1-gregkh@linuxfoundation.org Signed-off-by: Heiko Carstens --- drivers/s390/char/sclp_sd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_sd.c b/drivers/s390/char/sclp_sd.c index 25c2d760f6e6..f9e164be7568 100644 --- a/drivers/s390/char/sclp_sd.c +++ b/drivers/s390/char/sclp_sd.c @@ -438,11 +438,12 @@ static struct attribute *sclp_sd_file_default_attrs[] = { &reload_attr.attr, NULL, }; +ATTRIBUTE_GROUPS(sclp_sd_file_default); static struct kobj_type sclp_sd_file_ktype = { .sysfs_ops = &kobj_sysfs_ops, .release = sclp_sd_file_release, - .default_attrs = sclp_sd_file_default_attrs, + .default_groups = sclp_sd_file_default_groups, }; /** -- cgit v1.2.3-59-g8ed1b From 0704a8586f75663cf30a283bbeeca09eb4e60a07 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 6 Jan 2022 10:54:01 +0100 Subject: s390/dasd: use default_groups in kobj_type There are currently 2 ways to create a set of sysfs files for a kobj_type, through the default_attrs field, and the default_groups field. Move the s390 dasd sysfs code to use default_groups field which has been the preferred way since commit aa30f47cf666 ("kobject: Add support for default attribute groups to kobj_type") so that we can soon get rid of the obsolete default_attrs field. Cc: Stefan Haberland Cc: Jan Hoeppner Cc: Vasily Gorbik Cc: Christian Borntraeger Cc: Alexander Gordeev Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20220106095401.3274637-1-gregkh@linuxfoundation.org Signed-off-by: Heiko Carstens --- drivers/s390/block/dasd_devmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 6043c832d09e..811e79c9f59c 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1824,10 +1824,11 @@ static struct attribute *paths_info_attrs[] = { &path_fcs_attribute.attr, NULL, }; +ATTRIBUTE_GROUPS(paths_info); static struct kobj_type path_attr_type = { .release = dasd_path_release, - .default_attrs = paths_info_attrs, + .default_groups = paths_info_groups, .sysfs_ops = &kobj_sysfs_ops, }; -- cgit v1.2.3-59-g8ed1b