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:
Родитель
1143f6f55d
Коммит
5c2e5a0cf5
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
Загрузка…
Ссылка в новой задаче