s390/cio: sort out physical vs virtual pointers usage
authorAlexander Gordeev <agordeev@linux.ibm.com>
Fri, 18 Jun 2021 06:39:12 +0000 (08:39 +0200)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Thu, 1 Dec 2022 09:58:04 +0000 (10:58 +0100)
This does not fix a real bug, since virtual addresses
are currently indentical to physical ones.

Use virt_to_phys() for intparm interrupt parameter to
convert a 64-bit virtual address to the 32-bit physical
address, which is expected to be below 2GB.

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/cio.c
drivers/s390/cio/device.c
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_id.c
drivers/s390/cio/device_pgid.c
drivers/s390/cio/device_status.c
drivers/s390/cio/eadm_sch.c
drivers/s390/cio/fcx.c
drivers/s390/cio/itcw.c

index 962dfa25a310842633e818a002d4c9be520c359a..180ab899289c55e01af3e73c0085c7ea83889025 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/compat.h>
 #include <linux/device.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
@@ -85,7 +86,7 @@ static int chsc_subchannel_probe(struct subchannel *sch)
        if (!private)
                return -ENOMEM;
        dev_set_drvdata(&sch->dev, private);
-       ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+       ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
        if (ret) {
                CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n",
                         sch->schid.ssid, sch->schid.sch_no, ret);
index 923f5ca4f5e6b6584b902c42fc5984956ab56589..6127add746d18116df27dc9a2f97e4faa9b9dd52 100644 (file)
@@ -134,7 +134,7 @@ cio_start_key (struct subchannel *sch,      /* subchannel structure */
 
        memset(orb, 0, sizeof(union orb));
        /* sch is always under 2G. */
-       orb->cmd.intparm = (u32)(addr_t)sch;
+       orb->cmd.intparm = (u32)virt_to_phys(sch);
        orb->cmd.fmt = 1;
 
        orb->cmd.pfch = priv->options.prefetch == 0;
@@ -148,7 +148,7 @@ cio_start_key (struct subchannel *sch,      /* subchannel structure */
        orb->cmd.i2k = 0;
        orb->cmd.key = key >> 4;
        /* issue "Start Subchannel" */
-       orb->cmd.cpa = (__u32) __pa(cpa);
+       orb->cmd.cpa = (u32)virt_to_phys(cpa);
        ccode = ssch(sch->schid, orb);
 
        /* process condition code */
@@ -539,13 +539,13 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
        tpi_info = &get_irq_regs()->tpi_info;
        trace_s390_cio_interrupt(tpi_info);
        irb = this_cpu_ptr(&cio_irb);
-       sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
-       if (!sch) {
+       if (!tpi_info->intparm) {
                /* Clear pending interrupt condition. */
                inc_irq_stat(IRQIO_CIO);
                tsch(tpi_info->schid, irb);
                return IRQ_HANDLED;
        }
+       sch = phys_to_virt(tpi_info->intparm);
        spin_lock(sch->lock);
        /* Store interrupt response block to lowcore. */
        if (tsch(tpi_info->schid, irb) == 0) {
@@ -666,7 +666,7 @@ struct subchannel *cio_probe_console(void)
        lockdep_set_class(sch->lock, &console_sch_key);
        isc_register(CONSOLE_ISC);
        sch->config.isc = CONSOLE_ISC;
-       sch->config.intparm = (u32)(addr_t)sch;
+       sch->config.intparm = (u32)virt_to_phys(sch);
        ret = cio_commit_config(sch);
        if (ret) {
                isc_unregister(CONSOLE_ISC);
@@ -713,11 +713,11 @@ int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key)
        union orb *orb = &to_io_private(sch)->orb;
 
        memset(orb, 0, sizeof(union orb));
-       orb->tm.intparm = (u32) (addr_t) sch;
+       orb->tm.intparm = (u32)virt_to_phys(sch);
        orb->tm.key = key >> 4;
        orb->tm.b = 1;
        orb->tm.lpm = lpm ? lpm : sch->lpm;
-       orb->tm.tcw = (u32) (addr_t) tcw;
+       orb->tm.tcw = (u32)virt_to_phys(tcw);
        cc = ssch(sch->schid, orb);
        switch (cc) {
        case 0:
index 3b1cd0c96a74b85d53f218ec517fc3eb525b0524..9e0cf44ff9d4b2abc2134d933e0b25883f78e765 100644 (file)
@@ -936,7 +936,7 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev,
                if (old_enabled) {
                        /* Try to reenable the old subchannel. */
                        spin_lock_irq(old_sch->lock);
-                       cio_enable_subchannel(old_sch, (u32)(addr_t)old_sch);
+                       cio_enable_subchannel(old_sch, (u32)virt_to_phys(old_sch));
                        spin_unlock_irq(old_sch->lock);
                }
                /* Release child reference for new parent. */
index 6d63b968309a8dba95b806718952ff504651641c..2b2058427a2b120576ea551b6eb2430db4e8456b 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/jiffies.h>
 #include <linux/string.h>
 
@@ -63,7 +64,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
                printk(KERN_WARNING "cio: orb indicates transport mode\n");
                printk(KERN_WARNING "cio: last tcw:\n");
                print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-                              (void *)(addr_t)orb->tm.tcw,
+                              phys_to_virt(orb->tm.tcw),
                               sizeof(struct tcw), 0);
        } else {
                printk(KERN_WARNING "cio: orb indicates command mode\n");
@@ -77,7 +78,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
                        printk(KERN_WARNING "cio: last channel program:\n");
 
                print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-                              (void *)(addr_t)orb->cmd.cpa,
+                              phys_to_virt(orb->cmd.cpa),
                               sizeof(struct ccw1), 0);
        }
        printk(KERN_WARNING "cio: ccw device state: %d\n",
@@ -397,7 +398,7 @@ void ccw_device_recognition(struct ccw_device *cdev)
         */
        cdev->private->flags.recog_done = 0;
        cdev->private->state = DEV_STATE_SENSE_ID;
-       if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) {
+       if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch))) {
                ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
                return;
        }
@@ -548,7 +549,7 @@ ccw_device_online(struct ccw_device *cdev)
            (cdev->private->state != DEV_STATE_BOXED))
                return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
-       ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
+       ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
        if (ret != 0) {
                /* Couldn't enable the subchannel for i/o. Sick device. */
                if (ret == -ENODEV)
@@ -691,7 +692,7 @@ static void ccw_device_boxed_verify(struct ccw_device *cdev,
        struct subchannel *sch = to_subchannel(cdev->dev.parent);
 
        if (cdev->online) {
-               if (cio_enable_subchannel(sch, (u32) (addr_t) sch))
+               if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch)))
                        ccw_device_done(cdev, DEV_STATE_NOT_OPER);
                else
                        ccw_device_online_verify(cdev, dev_event);
@@ -922,7 +923,7 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
        struct subchannel *sch;
 
        sch = to_subchannel(cdev->dev.parent);
-       if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0)
+       if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch)) != 0)
                /* Couldn't enable the subchannel for i/o. Sick device. */
                return;
        cdev->private->state = DEV_STATE_DISCONNECTED_SENSE_ID;
index 7835a87a60b560325214007393264de480363b63..ce99ee2457e6e8669346fdee588cd05e0783b93f 100644 (file)
@@ -210,7 +210,7 @@ void ccw_device_sense_id_start(struct ccw_device *cdev)
        snsid_init(cdev);
        /* Channel program setup. */
        cp->cmd_code    = CCW_CMD_SENSE_ID;
-       cp->cda         = (u32) (addr_t) &cdev->private->dma_area->senseid;
+       cp->cda         = (u32)virt_to_phys(&cdev->private->dma_area->senseid);
        cp->count       = sizeof(struct senseid);
        cp->flags       = CCW_FLAG_SLI;
        /* Request setup. */
index 767a85635a0f7e545e59431070a593ff1e87dc1a..3862961697eb6ab67b7a7ecef264bf72f0dfa41c 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
 
@@ -140,7 +141,7 @@ static void spid_build_cp(struct ccw_device *cdev, u8 fn)
 
        pgid->inf.fc    = fn;
        cp->cmd_code    = CCW_CMD_SET_PGID;
-       cp->cda         = (u32) (addr_t) pgid;
+       cp->cda         = (u32)virt_to_phys(pgid);
        cp->count       = sizeof(*pgid);
        cp->flags       = CCW_FLAG_SLI;
        req->cp         = cp;
@@ -441,7 +442,7 @@ static void snid_build_cp(struct ccw_device *cdev)
 
        /* Channel program setup. */
        cp->cmd_code    = CCW_CMD_SENSE_PGID;
-       cp->cda         = (u32) (addr_t) &cdev->private->dma_area->pgid[i];
+       cp->cda         = (u32)virt_to_phys(&cdev->private->dma_area->pgid[i]);
        cp->count       = sizeof(struct pgid);
        cp->flags       = CCW_FLAG_SLI;
        req->cp         = cp;
@@ -631,11 +632,11 @@ static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2)
        struct ccw1 *cp = cdev->private->dma_area->iccws;
 
        cp[0].cmd_code = CCW_CMD_STLCK;
-       cp[0].cda = (u32) (addr_t) buf1;
+       cp[0].cda = (u32)virt_to_phys(buf1);
        cp[0].count = 32;
        cp[0].flags = CCW_FLAG_CC;
        cp[1].cmd_code = CCW_CMD_RELEASE;
-       cp[1].cda = (u32) (addr_t) buf2;
+       cp[1].cda = (u32)virt_to_phys(buf2);
        cp[1].count = 32;
        cp[1].flags = 0;
        req->cp = cp;
@@ -698,7 +699,7 @@ int ccw_device_stlck(struct ccw_device *cdev)
        init_completion(&data.done);
        data.rc = -EIO;
        spin_lock_irq(sch->lock);
-       rc = cio_enable_subchannel(sch, (u32) (addr_t) sch);
+       rc = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
        if (rc)
                goto out_unlock;
        /* Perform operation. */
index 0bd8f2642732f1e9cedf8d4664a8e902fc221f95..6c2e35065fec3e9376a08e5375cd583420321b09 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
@@ -331,7 +332,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
         */
        sense_ccw = &to_io_private(sch)->dma_area->sense_ccw;
        sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
-       sense_ccw->cda = (__u32) __pa(cdev->private->dma_area->irb.ecw);
+       sense_ccw->cda = virt_to_phys(cdev->private->dma_area->irb.ecw);
        sense_ccw->count = SENSE_MAX_COUNT;
        sense_ccw->flags = CCW_FLAG_SLI;
 
index ab6a7495180a40c37e7ec53377887e91f652c1e4..826364d2facd856e81dfa70f5ead8c42adb99cb7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/timer.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/io.h>
 
 #include <asm/css_chars.h>
 #include <asm/debug.h>
@@ -62,8 +63,8 @@ static int eadm_subchannel_start(struct subchannel *sch, struct aob *aob)
        int cc;
 
        orb_init(orb);
-       orb->eadm.aob = (u32)__pa(aob);
-       orb->eadm.intparm = (u32)(addr_t)sch;
+       orb->eadm.aob = (u32)virt_to_phys(aob);
+       orb->eadm.intparm = (u32)virt_to_phys(sch);
        orb->eadm.key = PAGE_DEFAULT_KEY >> 4;
 
        EADM_LOG(6, "start");
@@ -146,7 +147,7 @@ static void eadm_subchannel_irq(struct subchannel *sch)
                css_sched_sch_todo(sch, SCH_TODO_EVAL);
                return;
        }
-       scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error);
+       scm_irq_handler(phys_to_virt(scsw->aob), error);
        private->state = EADM_IDLE;
 
        if (private->completion)
@@ -225,7 +226,7 @@ static int eadm_subchannel_probe(struct subchannel *sch)
        private->state = EADM_IDLE;
        private->sch = sch;
        sch->isc = EADM_SCH_ISC;
-       ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+       ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
        if (ret) {
                set_eadm_private(sch, NULL);
                spin_unlock_irq(sch->lock);
index 99c900cc3e5b5323ee40f10733f6c95693e2c458..84f24a2f46e4a0ae48f34ac8ddbe664c5f396a8b 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/module.h>
@@ -24,7 +25,7 @@
  */
 struct tcw *tcw_get_intrg(struct tcw *tcw)
 {
-       return (struct tcw *) ((addr_t) tcw->intrg);
+       return phys_to_virt(tcw->intrg);
 }
 EXPORT_SYMBOL(tcw_get_intrg);
 
@@ -39,9 +40,9 @@ EXPORT_SYMBOL(tcw_get_intrg);
 void *tcw_get_data(struct tcw *tcw)
 {
        if (tcw->r)
-               return (void *) ((addr_t) tcw->input);
+               return phys_to_virt(tcw->input);
        if (tcw->w)
-               return (void *) ((addr_t) tcw->output);
+               return phys_to_virt(tcw->output);
        return NULL;
 }
 EXPORT_SYMBOL(tcw_get_data);
@@ -54,7 +55,7 @@ EXPORT_SYMBOL(tcw_get_data);
  */
 struct tccb *tcw_get_tccb(struct tcw *tcw)
 {
-       return (struct tccb *) ((addr_t) tcw->tccb);
+       return phys_to_virt(tcw->tccb);
 }
 EXPORT_SYMBOL(tcw_get_tccb);
 
@@ -66,7 +67,7 @@ EXPORT_SYMBOL(tcw_get_tccb);
  */
 struct tsb *tcw_get_tsb(struct tcw *tcw)
 {
-       return (struct tsb *) ((addr_t) tcw->tsb);
+       return phys_to_virt(tcw->tsb);
 }
 EXPORT_SYMBOL(tcw_get_tsb);
 
@@ -189,7 +190,7 @@ EXPORT_SYMBOL(tcw_finalize);
  */
 void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw)
 {
-       tcw->intrg = (u32) ((addr_t) intrg_tcw);
+       tcw->intrg = (u32)virt_to_phys(intrg_tcw);
 }
 EXPORT_SYMBOL(tcw_set_intrg);
 
@@ -207,11 +208,11 @@ EXPORT_SYMBOL(tcw_set_intrg);
 void tcw_set_data(struct tcw *tcw, void *data, int use_tidal)
 {
        if (tcw->r) {
-               tcw->input = (u64) ((addr_t) data);
+               tcw->input = virt_to_phys(data);
                if (use_tidal)
                        tcw->flags |= TCW_FLAGS_INPUT_TIDA;
        } else if (tcw->w) {
-               tcw->output = (u64) ((addr_t) data);
+               tcw->output = virt_to_phys(data);
                if (use_tidal)
                        tcw->flags |= TCW_FLAGS_OUTPUT_TIDA;
        }
@@ -227,7 +228,7 @@ EXPORT_SYMBOL(tcw_set_data);
  */
 void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb)
 {
-       tcw->tccb = (u64) ((addr_t) tccb);
+       tcw->tccb = virt_to_phys(tccb);
 }
 EXPORT_SYMBOL(tcw_set_tccb);
 
@@ -240,7 +241,7 @@ EXPORT_SYMBOL(tcw_set_tccb);
  */
 void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb)
 {
-       tcw->tsb = (u64) ((addr_t) tsb);
+       tcw->tsb = virt_to_phys(tsb);
 }
 EXPORT_SYMBOL(tcw_set_tsb);
 
@@ -345,7 +346,7 @@ struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags,
        memset(tidaw, 0, sizeof(struct tidaw));
        tidaw->flags = flags;
        tidaw->count = count;
-       tidaw->addr = (u64) ((addr_t) addr);
+       tidaw->addr = virt_to_phys(addr);
        return tidaw;
 }
 EXPORT_SYMBOL(tcw_add_tidaw);
index 19e46363348ccdbf62aa596c98ce1379e36a517b..dbd3099c520eabbb1828ba51835407cb5b318570 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/module.h>
@@ -187,7 +188,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
        /* Check for 2G limit. */
        start = (addr_t) buffer;
        end = start + size;
-       if (end > (1 << 31))
+       if ((virt_to_phys(buffer) + size) > (1 << 31))
                return ERR_PTR(-EINVAL);
        memset(buffer, 0, size);
        /* ITCW. */