Commit 5c2e5a0c authored by Alexander Gordeev's avatar Alexander Gordeev
Browse files

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: default avatarPeter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
parent 1143f6f5
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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);
+7 −7
Original line number Diff line number Diff line
@@ -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:
+1 −1
Original line number Diff line number Diff line
@@ -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. */
+7 −6
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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. */
Loading