s390/cio: sort out physical vs virtual pointers usage

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>
This commit is contained in:
Alexander Gordeev 2021-06-18 08:39:12 +02:00
parent 1143f6f55d
commit 5c2e5a0cf5
10 changed files with 45 additions and 38 deletions

View 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);

View 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:

View 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. */

View 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;

View 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. */

View 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. */

View 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;

View 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);

View 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);

View 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. */