Message ID | 20190523162209.9543-4-mimu@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | s390: virtio: support protected virtualization | expand |
On Thu, 23 May 2019, Michael Mueller wrote: > static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch) > { > struct ccw_device *cdev; > + struct gen_pool *dma_pool; > > cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); > - if (cdev) { > - cdev->private = kzalloc(sizeof(struct ccw_device_private), > - GFP_KERNEL | GFP_DMA); > - if (cdev->private) > - return cdev; > - } > + if (!cdev) > + goto err_cdev; > + cdev->private = kzalloc(sizeof(struct ccw_device_private), > + GFP_KERNEL | GFP_DMA); > + if (!cdev->private) > + goto err_priv; > + cdev->dev.coherent_dma_mask = sch->dev.coherent_dma_mask; > + cdev->dev.dma_mask = &cdev->dev.coherent_dma_mask; > + dma_pool = cio_gp_dma_create(&cdev->dev, 1); This can return NULL. gen_pool_alloc will panic in this case. [...] > +err_dma_area: > + kfree(io_priv); Indentation. > +err_priv: > + put_device(&sch->dev); > + return ERR_PTR(-ENOMEM); > } [...] > void ccw_device_update_sense_data(struct ccw_device *cdev) > { > memset(&cdev->id, 0, sizeof(cdev->id)); > - cdev->id.cu_type = cdev->private->senseid.cu_type; > - cdev->id.cu_model = cdev->private->senseid.cu_model; > - cdev->id.dev_type = cdev->private->senseid.dev_type; > - cdev->id.dev_model = cdev->private->senseid.dev_model; > + cdev->id.cu_type = > + cdev->private->dma_area->senseid.cu_type; > + cdev->id.cu_model = > + cdev->private->dma_area->senseid.cu_model; > + cdev->id.dev_type = > + cdev->private->dma_area->senseid.dev_type; > + cdev->id.dev_model = > + cdev->private->dma_area->senseid.dev_model; These fit into one line. > +/** > + * Allocate zeroed dma coherent 31 bit addressable memory using > + * the subchannels dma pool. Maximal size of allocation supported > + * is PAGE_SIZE. > + */ drivers/s390/cio/device_ops.c:708: warning: Function parameter or member 'cdev' not described in 'ccw_device_dma_zalloc' drivers/s390/cio/device_ops.c:708: warning: Function parameter or member 'size' not described in 'ccw_device_dma_zalloc' Reviewed-by: Sebastian Ott <sebott@linux.ibm.com>
On Thu, 23 May 2019 18:22:04 +0200 Michael Mueller <mimu@linux.ibm.com> wrote: > From: Halil Pasic <pasic@linux.ibm.com> > > As virtio-ccw devices are channel devices, we need to use the dma area > for any communication with the hypervisor. > > It handles neither QDIO in the common code, nor any device type specific > stuff (like channel programs constructed by the DASD driver). > > An interesting side effect is that virtio structures are now going to > get allocated in 31 bit addressable storage. > > Signed-off-by: Halil Pasic <pasic@linux.ibm.com> [Side note: you really should add your s-o-b if you send someone else's patches... if Halil ends up committing them, it's fine, though.] > --- > arch/s390/include/asm/ccwdev.h | 4 +++ > drivers/s390/cio/ccwreq.c | 9 +++--- > drivers/s390/cio/device.c | 64 +++++++++++++++++++++++++++++++++------- > drivers/s390/cio/device_fsm.c | 53 ++++++++++++++++++++------------- > drivers/s390/cio/device_id.c | 20 +++++++------ > drivers/s390/cio/device_ops.c | 21 +++++++++++-- > drivers/s390/cio/device_pgid.c | 22 +++++++------- > drivers/s390/cio/device_status.c | 24 +++++++-------- > drivers/s390/cio/io_sch.h | 20 +++++++++---- > drivers/s390/virtio/virtio_ccw.c | 10 ------- > 10 files changed, 164 insertions(+), 83 deletions(-) > (...) > @@ -1593,20 +1622,31 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) > return ERR_CAST(sch); > > io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); > - if (!io_priv) { > - put_device(&sch->dev); > - return ERR_PTR(-ENOMEM); > - } > + if (!io_priv) > + goto err_priv; > + io_priv->dma_area = dma_alloc_coherent(&sch->dev, > + sizeof(*io_priv->dma_area), > + &io_priv->dma_area_dma, GFP_KERNEL); Even though we'll only end up here for 3215 or 3270 consoles, this sent me looking. This code is invoked via console_init(). A few lines down in start_kernel(), we have /* * This needs to be called before any devices perform DMA * operations that might use the SWIOTLB bounce buffers. It will * mark the bounce buffers as decrypted so that their usage will * not cause "plain-text" data to be decrypted when accessed. */ mem_encrypt_init(); So, I'm wondering if creating the console device interacts in any way with the memory encryption interface? [Does basic recognition work if you start a protected virt guest with a 3270 console? I realize that the console is unlikely to work, but that should at least exercise this code path.] > + if (!io_priv->dma_area) > + goto err_dma_area; > set_io_private(sch, io_priv); > cdev = io_subchannel_create_ccwdev(sch); > if (IS_ERR(cdev)) { > put_device(&sch->dev); > + dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), > + io_priv->dma_area, io_priv->dma_area_dma); > kfree(io_priv); > return cdev; > } > cdev->drv = drv; > ccw_device_set_int_class(cdev); > return cdev; > + > +err_dma_area: > + kfree(io_priv); > +err_priv: > + put_device(&sch->dev); > + return ERR_PTR(-ENOMEM); > } > > void __init ccw_device_destroy_console(struct ccw_device *cdev)
On 27.05.19 12:38, Cornelia Huck wrote: > On Thu, 23 May 2019 18:22:04 +0200 > Michael Mueller <mimu@linux.ibm.com> wrote: > >> From: Halil Pasic <pasic@linux.ibm.com> >> >> As virtio-ccw devices are channel devices, we need to use the dma area >> for any communication with the hypervisor. >> >> It handles neither QDIO in the common code, nor any device type specific >> stuff (like channel programs constructed by the DASD driver). >> >> An interesting side effect is that virtio structures are now going to >> get allocated in 31 bit addressable storage. >> >> Signed-off-by: Halil Pasic <pasic@linux.ibm.com> > > [Side note: you really should add your s-o-b if you send someone else's > patches... if Halil ends up committing them, it's fine, though.] My real problem here is that Halil is writing comments and patches after I have prepared all my changes. ;) And now this contnues... Michael > >> --- >> arch/s390/include/asm/ccwdev.h | 4 +++ >> drivers/s390/cio/ccwreq.c | 9 +++--- >> drivers/s390/cio/device.c | 64 +++++++++++++++++++++++++++++++++------- >> drivers/s390/cio/device_fsm.c | 53 ++++++++++++++++++++------------- >> drivers/s390/cio/device_id.c | 20 +++++++------ >> drivers/s390/cio/device_ops.c | 21 +++++++++++-- >> drivers/s390/cio/device_pgid.c | 22 +++++++------- >> drivers/s390/cio/device_status.c | 24 +++++++-------- >> drivers/s390/cio/io_sch.h | 20 +++++++++---- >> drivers/s390/virtio/virtio_ccw.c | 10 ------- >> 10 files changed, 164 insertions(+), 83 deletions(-) >> > > (...) > >> @@ -1593,20 +1622,31 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) >> return ERR_CAST(sch); >> >> io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); >> - if (!io_priv) { >> - put_device(&sch->dev); >> - return ERR_PTR(-ENOMEM); >> - } >> + if (!io_priv) >> + goto err_priv; >> + io_priv->dma_area = dma_alloc_coherent(&sch->dev, >> + sizeof(*io_priv->dma_area), >> + &io_priv->dma_area_dma, GFP_KERNEL); > > Even though we'll only end up here for 3215 or 3270 consoles, this sent > me looking. > > This code is invoked via console_init(). A few lines down in > start_kernel(), we have > > /* > * This needs to be called before any devices perform DMA > * operations that might use the SWIOTLB bounce buffers. It will > * mark the bounce buffers as decrypted so that their usage will > * not cause "plain-text" data to be decrypted when accessed. > */ > mem_encrypt_init(); > > So, I'm wondering if creating the console device interacts in any way > with the memory encryption interface? > > [Does basic recognition work if you start a protected virt guest with a > 3270 console? I realize that the console is unlikely to work, but that > should at least exercise this code path.] > >> + if (!io_priv->dma_area) >> + goto err_dma_area; >> set_io_private(sch, io_priv); >> cdev = io_subchannel_create_ccwdev(sch); >> if (IS_ERR(cdev)) { >> put_device(&sch->dev); >> + dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), >> + io_priv->dma_area, io_priv->dma_area_dma); >> kfree(io_priv); >> return cdev; >> } >> cdev->drv = drv; >> ccw_device_set_int_class(cdev); >> return cdev; >> + >> +err_dma_area: >> + kfree(io_priv); >> +err_priv: >> + put_device(&sch->dev); >> + return ERR_PTR(-ENOMEM); >> } >> >> void __init ccw_device_destroy_console(struct ccw_device *cdev) >
On Mon, 27 May 2019 12:38:02 +0200 Cornelia Huck <cohuck@redhat.com> wrote: > On Thu, 23 May 2019 18:22:04 +0200 > Michael Mueller <mimu@linux.ibm.com> wrote: > > > From: Halil Pasic <pasic@linux.ibm.com> > > > > As virtio-ccw devices are channel devices, we need to use the dma area > > for any communication with the hypervisor. > > > > It handles neither QDIO in the common code, nor any device type specific > > stuff (like channel programs constructed by the DASD driver). > > > > An interesting side effect is that virtio structures are now going to > > get allocated in 31 bit addressable storage. > > > > Signed-off-by: Halil Pasic <pasic@linux.ibm.com> > > [Side note: you really should add your s-o-b if you send someone else's > patches... if Halil ends up committing them, it's fine, though.] > > > --- > > arch/s390/include/asm/ccwdev.h | 4 +++ > > drivers/s390/cio/ccwreq.c | 9 +++--- > > drivers/s390/cio/device.c | 64 +++++++++++++++++++++++++++++++++------- > > drivers/s390/cio/device_fsm.c | 53 ++++++++++++++++++++------------- > > drivers/s390/cio/device_id.c | 20 +++++++------ > > drivers/s390/cio/device_ops.c | 21 +++++++++++-- > > drivers/s390/cio/device_pgid.c | 22 +++++++------- > > drivers/s390/cio/device_status.c | 24 +++++++-------- > > drivers/s390/cio/io_sch.h | 20 +++++++++---- > > drivers/s390/virtio/virtio_ccw.c | 10 ------- > > 10 files changed, 164 insertions(+), 83 deletions(-) > > > > (...) > > > @@ -1593,20 +1622,31 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) > > return ERR_CAST(sch); > > > > io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); > > - if (!io_priv) { > > - put_device(&sch->dev); > > - return ERR_PTR(-ENOMEM); > > - } > > + if (!io_priv) > > + goto err_priv; > > + io_priv->dma_area = dma_alloc_coherent(&sch->dev, > > + sizeof(*io_priv->dma_area), > > + &io_priv->dma_area_dma, GFP_KERNEL); > > Even though we'll only end up here for 3215 or 3270 consoles, this sent > me looking. > > This code is invoked via console_init(). A few lines down in > start_kernel(), we have > > /* > * This needs to be called before any devices perform DMA > * operations that might use the SWIOTLB bounce buffers. It will > * mark the bounce buffers as decrypted so that their usage will > * not cause "plain-text" data to be decrypted when accessed. > */ > mem_encrypt_init(); > > So, I'm wondering if creating the console device interacts in any way > with the memory encryption interface? I do things a bit different than x86: the SWIOTLB stuff is set up in mem_init(). So I think we should be fine. If there is a down-side to calling swiotlb_update_mem_attributes() earlier, honestly I'm not sure. > > [Does basic recognition work if you start a protected virt guest with a > 3270 console? I realize that the console is unlikely to work, but that > should at least exercise this code path.] I've already had some thoughts along these lines and slapped -device x-terminal3270,chardev=char_0,devno=fe.0.000a,id=terminal_0 \ on my qemu command line. The ccw device does show up in the guest... Device Subchan. DevType CU Type Use PIM PAM POM CHPIDs ---------------------------------------------------------------------- 0.0.0000 0.0.0000 0000/00 3832/01 yes 80 80 ff 00000000 00000000 0.0.000a 0.0.0001 0000/00 3270/00 80 80 ff 01000000 00000000 0.0.0002 0.0.0002 0000/00 3832/09 yes 80 80 ff 00000000 00000000 0.0.0300 0.0.0003 0000/00 3832/02 yes 80 80 ff 00000000 00000000 0.0.0301 0.0.0004 0000/00 3832/02 yes 80 80 ff 00000000 00000000 But I would not call it a comprehensive test... Mimu, do we have something more elaborate with regards to this? Regards, Halil
On Mon, 27 May 2019 14:30:14 +0200 Halil Pasic <pasic@linux.ibm.com> wrote: > On Mon, 27 May 2019 12:38:02 +0200 > Cornelia Huck <cohuck@redhat.com> wrote: > > > On Thu, 23 May 2019 18:22:04 +0200 > > Michael Mueller <mimu@linux.ibm.com> wrote: > > > > > From: Halil Pasic <pasic@linux.ibm.com> > > > > > > As virtio-ccw devices are channel devices, we need to use the dma area > > > for any communication with the hypervisor. > > > > > > It handles neither QDIO in the common code, nor any device type specific > > > stuff (like channel programs constructed by the DASD driver). > > > > > > An interesting side effect is that virtio structures are now going to > > > get allocated in 31 bit addressable storage. > > > > > > Signed-off-by: Halil Pasic <pasic@linux.ibm.com> > > > > [Side note: you really should add your s-o-b if you send someone else's > > patches... if Halil ends up committing them, it's fine, though.] > > > > > --- > > > arch/s390/include/asm/ccwdev.h | 4 +++ > > > drivers/s390/cio/ccwreq.c | 9 +++--- > > > drivers/s390/cio/device.c | 64 +++++++++++++++++++++++++++++++++------- > > > drivers/s390/cio/device_fsm.c | 53 ++++++++++++++++++++------------- > > > drivers/s390/cio/device_id.c | 20 +++++++------ > > > drivers/s390/cio/device_ops.c | 21 +++++++++++-- > > > drivers/s390/cio/device_pgid.c | 22 +++++++------- > > > drivers/s390/cio/device_status.c | 24 +++++++-------- > > > drivers/s390/cio/io_sch.h | 20 +++++++++---- > > > drivers/s390/virtio/virtio_ccw.c | 10 ------- > > > 10 files changed, 164 insertions(+), 83 deletions(-) > > > > > > > (...) > > > > > @@ -1593,20 +1622,31 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) > > > return ERR_CAST(sch); > > > > > > io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); > > > - if (!io_priv) { > > > - put_device(&sch->dev); > > > - return ERR_PTR(-ENOMEM); > > > - } > > > + if (!io_priv) > > > + goto err_priv; > > > + io_priv->dma_area = dma_alloc_coherent(&sch->dev, > > > + sizeof(*io_priv->dma_area), > > > + &io_priv->dma_area_dma, GFP_KERNEL); > > > > Even though we'll only end up here for 3215 or 3270 consoles, this sent > > me looking. > > > > This code is invoked via console_init(). A few lines down in > > start_kernel(), we have > > > > /* > > * This needs to be called before any devices perform DMA > > * operations that might use the SWIOTLB bounce buffers. It will > > * mark the bounce buffers as decrypted so that their usage will > > * not cause "plain-text" data to be decrypted when accessed. > > */ > > mem_encrypt_init(); > > > > So, I'm wondering if creating the console device interacts in any way > > with the memory encryption interface? > > I do things a bit different than x86: the SWIOTLB stuff is set up in > mem_init(). So I think we should be fine. If there is a down-side to > calling swiotlb_update_mem_attributes() earlier, honestly I'm > not sure. Neither am I; do any of the folks who looked at the swiotlb patch have an idea? > > > > > [Does basic recognition work if you start a protected virt guest with a > > 3270 console? I realize that the console is unlikely to work, but that > > should at least exercise this code path.] > > I've already had some thoughts along these lines and slapped > -device x-terminal3270,chardev=char_0,devno=fe.0.000a,id=terminal_0 \ > on my qemu command line. The ccw device does show up in the guest... > > Device Subchan. DevType CU Type Use PIM PAM POM CHPIDs > ---------------------------------------------------------------------- > 0.0.0000 0.0.0000 0000/00 3832/01 yes 80 80 ff 00000000 00000000 > 0.0.000a 0.0.0001 0000/00 3270/00 80 80 ff 01000000 00000000 > 0.0.0002 0.0.0002 0000/00 3832/09 yes 80 80 ff 00000000 00000000 > 0.0.0300 0.0.0003 0000/00 3832/02 yes 80 80 ff 00000000 00000000 > 0.0.0301 0.0.0004 0000/00 3832/02 yes 80 80 ff 00000000 00000000 > > But I would not call it a comprehensive test... If you only add the device, it will show up as a normal ccw device in the guest; i.e. device recognition is done at the same time as for the other ccw devices. Still good to see that nothing breaks there :) To actually make the guest use the 3270 as its console, I guess you need to explicitly force it (see https://wiki.qemu.org/Features/3270#Using_3270_as_the_console)... actually starting the console will almost certainly fail; but you can at least check whether device recognition in the console path works. > > Mimu, do we have something more elaborate with regards to this? I don't think we need extensive testing here; just checking that the sequence is not fundamentally broken.
On 25.05.19 11:44, Sebastian Ott wrote: > > On Thu, 23 May 2019, Michael Mueller wrote: >> static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch) >> { >> struct ccw_device *cdev; >> + struct gen_pool *dma_pool; >> >> cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); >> - if (cdev) { >> - cdev->private = kzalloc(sizeof(struct ccw_device_private), >> - GFP_KERNEL | GFP_DMA); >> - if (cdev->private) >> - return cdev; >> - } >> + if (!cdev) >> + goto err_cdev; >> + cdev->private = kzalloc(sizeof(struct ccw_device_private), >> + GFP_KERNEL | GFP_DMA); >> + if (!cdev->private) >> + goto err_priv; >> + cdev->dev.coherent_dma_mask = sch->dev.coherent_dma_mask; >> + cdev->dev.dma_mask = &cdev->dev.coherent_dma_mask; >> + dma_pool = cio_gp_dma_create(&cdev->dev, 1); > > This can return NULL. gen_pool_alloc will panic in this case. > [...] yep, will handled in next version > >> +err_dma_area: >> + kfree(io_priv); one tab gone > > Indentation. > >> +err_priv: >> + put_device(&sch->dev); >> + return ERR_PTR(-ENOMEM); >> } > [...] >> void ccw_device_update_sense_data(struct ccw_device *cdev) >> { >> memset(&cdev->id, 0, sizeof(cdev->id)); >> - cdev->id.cu_type = cdev->private->senseid.cu_type; >> - cdev->id.cu_model = cdev->private->senseid.cu_model; >> - cdev->id.dev_type = cdev->private->senseid.dev_type; >> - cdev->id.dev_model = cdev->private->senseid.dev_model; >> + cdev->id.cu_type = >> + cdev->private->dma_area->senseid.cu_type; >> + cdev->id.cu_model = >> + cdev->private->dma_area->senseid.cu_model; >> + cdev->id.dev_type = >> + cdev->private->dma_area->senseid.dev_type; >> + cdev->id.dev_model = >> + cdev->private->dma_area->senseid.dev_model; > > These fit into one line. yep, surprisingly below 80 characters > >> +/** >> + * Allocate zeroed dma coherent 31 bit addressable memory using >> + * the subchannels dma pool. Maximal size of allocation supported >> + * is PAGE_SIZE. >> + */ > drivers/s390/cio/device_ops.c:708: warning: Function parameter or member 'cdev' not described in 'ccw_device_dma_zalloc' > drivers/s390/cio/device_ops.c:708: warning: Function parameter or member 'size' not described in 'ccw_device_dma_zalloc' changing comment open token > > > Reviewed-by: Sebastian Ott <sebott@linux.ibm.com> > Thanks! Michael
On 27.05.19 15:31, Cornelia Huck wrote: > On Mon, 27 May 2019 14:30:14 +0200 > Halil Pasic <pasic@linux.ibm.com> wrote: > >> On Mon, 27 May 2019 12:38:02 +0200 >> Cornelia Huck <cohuck@redhat.com> wrote: >> >>> On Thu, 23 May 2019 18:22:04 +0200 >>> Michael Mueller <mimu@linux.ibm.com> wrote: >>> >>>> From: Halil Pasic <pasic@linux.ibm.com> >>>> >>>> As virtio-ccw devices are channel devices, we need to use the dma area >>>> for any communication with the hypervisor. >>>> >>>> It handles neither QDIO in the common code, nor any device type specific >>>> stuff (like channel programs constructed by the DASD driver). >>>> >>>> An interesting side effect is that virtio structures are now going to >>>> get allocated in 31 bit addressable storage. >>>> >>>> Signed-off-by: Halil Pasic <pasic@linux.ibm.com> >>> >>> [Side note: you really should add your s-o-b if you send someone else's >>> patches... if Halil ends up committing them, it's fine, though.] >>> >>>> --- >>>> arch/s390/include/asm/ccwdev.h | 4 +++ >>>> drivers/s390/cio/ccwreq.c | 9 +++--- >>>> drivers/s390/cio/device.c | 64 +++++++++++++++++++++++++++++++++------- >>>> drivers/s390/cio/device_fsm.c | 53 ++++++++++++++++++++------------- >>>> drivers/s390/cio/device_id.c | 20 +++++++------ >>>> drivers/s390/cio/device_ops.c | 21 +++++++++++-- >>>> drivers/s390/cio/device_pgid.c | 22 +++++++------- >>>> drivers/s390/cio/device_status.c | 24 +++++++-------- >>>> drivers/s390/cio/io_sch.h | 20 +++++++++---- >>>> drivers/s390/virtio/virtio_ccw.c | 10 ------- >>>> 10 files changed, 164 insertions(+), 83 deletions(-) >>>> >>> >>> (...) >>> >>>> @@ -1593,20 +1622,31 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) >>>> return ERR_CAST(sch); >>>> >>>> io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); >>>> - if (!io_priv) { >>>> - put_device(&sch->dev); >>>> - return ERR_PTR(-ENOMEM); >>>> - } >>>> + if (!io_priv) >>>> + goto err_priv; >>>> + io_priv->dma_area = dma_alloc_coherent(&sch->dev, >>>> + sizeof(*io_priv->dma_area), >>>> + &io_priv->dma_area_dma, GFP_KERNEL); >>> >>> Even though we'll only end up here for 3215 or 3270 consoles, this sent >>> me looking. >>> >>> This code is invoked via console_init(). A few lines down in >>> start_kernel(), we have >>> >>> /* >>> * This needs to be called before any devices perform DMA >>> * operations that might use the SWIOTLB bounce buffers. It will >>> * mark the bounce buffers as decrypted so that their usage will >>> * not cause "plain-text" data to be decrypted when accessed. >>> */ >>> mem_encrypt_init(); >>> >>> So, I'm wondering if creating the console device interacts in any way >>> with the memory encryption interface? >> >> I do things a bit different than x86: the SWIOTLB stuff is set up in >> mem_init(). So I think we should be fine. If there is a down-side to >> calling swiotlb_update_mem_attributes() earlier, honestly I'm >> not sure. > > Neither am I; do any of the folks who looked at the swiotlb patch have > an idea? > >> >>> >>> [Does basic recognition work if you start a protected virt guest with a >>> 3270 console? I realize that the console is unlikely to work, but that >>> should at least exercise this code path.] >> >> I've already had some thoughts along these lines and slapped >> -device x-terminal3270,chardev=char_0,devno=fe.0.000a,id=terminal_0 \ >> on my qemu command line. The ccw device does show up in the guest... >> >> Device Subchan. DevType CU Type Use PIM PAM POM CHPIDs >> ---------------------------------------------------------------------- >> 0.0.0000 0.0.0000 0000/00 3832/01 yes 80 80 ff 00000000 00000000 >> 0.0.000a 0.0.0001 0000/00 3270/00 80 80 ff 01000000 00000000 >> 0.0.0002 0.0.0002 0000/00 3832/09 yes 80 80 ff 00000000 00000000 >> 0.0.0300 0.0.0003 0000/00 3832/02 yes 80 80 ff 00000000 00000000 >> 0.0.0301 0.0.0004 0000/00 3832/02 yes 80 80 ff 00000000 00000000 >> >> But I would not call it a comprehensive test... > > If you only add the device, it will show up as a normal ccw device in > the guest; i.e. device recognition is done at the same time as for the > other ccw devices. Still good to see that nothing breaks there :) > > To actually make the guest use the 3270 as its console, I guess you > need to explicitly force it (see > https://wiki.qemu.org/Features/3270#Using_3270_as_the_console)... > actually starting the console will almost certainly fail; but you can > at least check whether device recognition in the console path works. > >> >> Mimu, do we have something more elaborate with regards to this? I ran that with success [root@ap01 ~]# lscss | grep 3270 0.0.002a 0.0.0008 0000/00 3270/00 yes 80 80 ff 01000000 00000000 and was able to connect and login. Michael > > I don't think we need extensive testing here; just checking that the > sequence is not fundamentally broken. >
On Wed, 29 May 2019 14:24:39 +0200 Michael Mueller <mimu@linux.ibm.com> wrote: > On 27.05.19 15:31, Cornelia Huck wrote: > > To actually make the guest use the 3270 as its console, I guess you > > need to explicitly force it (see > > https://wiki.qemu.org/Features/3270#Using_3270_as_the_console)... > > actually starting the console will almost certainly fail; but you can > > at least check whether device recognition in the console path works. > > > >> > >> Mimu, do we have something more elaborate with regards to this? > > I ran that with success > > [root@ap01 ~]# lscss | grep 3270 > 0.0.002a 0.0.0008 0000/00 3270/00 yes 80 80 ff 01000000 00000000 > > and was able to connect and login. Oh, cool. I'm actually a bit surprised this works without additional changes to the 3270 code :)
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index a29dd430fb40..865ce1cb86d5 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h @@ -226,6 +226,10 @@ extern int ccw_device_enable_console(struct ccw_device *); extern void ccw_device_wait_idle(struct ccw_device *); extern int ccw_device_force_console(struct ccw_device *); +extern void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size); +extern void ccw_device_dma_free(struct ccw_device *cdev, + void *cpu_addr, size_t size); + int ccw_device_siosl(struct ccw_device *); extern void ccw_device_get_schid(struct ccw_device *, struct subchannel_id *); diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c index 603268a33ea1..73582a0a2622 100644 --- a/drivers/s390/cio/ccwreq.c +++ b/drivers/s390/cio/ccwreq.c @@ -63,7 +63,7 @@ static void ccwreq_stop(struct ccw_device *cdev, int rc) return; req->done = 1; ccw_device_set_timeout(cdev, 0); - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); if (rc && rc != -ENODEV && req->drc) rc = req->drc; req->callback(cdev, req->data, rc); @@ -86,7 +86,7 @@ static void ccwreq_do(struct ccw_device *cdev) continue; } /* Perform start function. */ - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); rc = cio_start(sch, cp, (u8) req->mask); if (rc == 0) { /* I/O started successfully. */ @@ -169,7 +169,7 @@ int ccw_request_cancel(struct ccw_device *cdev) */ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) { - struct irb *irb = &cdev->private->irb; + struct irb *irb = &cdev->private->dma_area->irb; struct cmd_scsw *scsw = &irb->scsw.cmd; enum uc_todo todo; @@ -187,7 +187,8 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) CIO_TRACE_EVENT(2, "sensedata"); CIO_HEX_EVENT(2, &cdev->private->dev_id, sizeof(struct ccw_dev_id)); - CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT); + CIO_HEX_EVENT(2, &cdev->private->dma_area->irb.ecw, + SENSE_MAX_COUNT); /* Check for command reject. */ if (irb->ecw[0] & SNS0_CMD_REJECT) return IO_REJECTED; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 1540229a37bb..a9ee03c20d7e 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -24,6 +24,7 @@ #include <linux/timer.h> #include <linux/kernel_stat.h> #include <linux/sched/signal.h> +#include <linux/dma-mapping.h> #include <asm/ccwdev.h> #include <asm/cio.h> @@ -687,6 +688,9 @@ ccw_device_release(struct device *dev) struct ccw_device *cdev; cdev = to_ccwdev(dev); + cio_gp_dma_free(cdev->private->dma_pool, cdev->private->dma_area, + sizeof(*cdev->private->dma_area)); + cio_gp_dma_destroy(cdev->private->dma_pool, &cdev->dev); /* Release reference of parent subchannel. */ put_device(cdev->dev.parent); kfree(cdev->private); @@ -696,15 +700,30 @@ ccw_device_release(struct device *dev) static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch) { struct ccw_device *cdev; + struct gen_pool *dma_pool; cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (cdev) { - cdev->private = kzalloc(sizeof(struct ccw_device_private), - GFP_KERNEL | GFP_DMA); - if (cdev->private) - return cdev; - } + if (!cdev) + goto err_cdev; + cdev->private = kzalloc(sizeof(struct ccw_device_private), + GFP_KERNEL | GFP_DMA); + if (!cdev->private) + goto err_priv; + cdev->dev.coherent_dma_mask = sch->dev.coherent_dma_mask; + cdev->dev.dma_mask = &cdev->dev.coherent_dma_mask; + dma_pool = cio_gp_dma_create(&cdev->dev, 1); + cdev->private->dma_pool = dma_pool; + cdev->private->dma_area = cio_gp_dma_zalloc(dma_pool, &cdev->dev, + sizeof(*cdev->private->dma_area)); + if (!cdev->private->dma_area) + goto err_dma_area; + return cdev; +err_dma_area: + cio_gp_dma_destroy(dma_pool, &cdev->dev); + kfree(cdev->private); +err_priv: kfree(cdev); +err_cdev: return ERR_PTR(-ENOMEM); } @@ -884,7 +903,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) wake_up(&ccw_device_init_wq); break; case DEV_STATE_OFFLINE: - /* + /* * We can't register the device in interrupt context so * we schedule a work item. */ @@ -1062,6 +1081,14 @@ static int io_subchannel_probe(struct subchannel *sch) if (!io_priv) goto out_schedule; + io_priv->dma_area = dma_alloc_coherent(&sch->dev, + sizeof(*io_priv->dma_area), + &io_priv->dma_area_dma, GFP_KERNEL); + if (!io_priv->dma_area) { + kfree(io_priv); + goto out_schedule; + } + set_io_private(sch, io_priv); css_schedule_eval(sch->schid); return 0; @@ -1088,6 +1115,8 @@ static int io_subchannel_remove(struct subchannel *sch) set_io_private(sch, NULL); spin_unlock_irq(sch->lock); out_free: + dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), + io_priv->dma_area, io_priv->dma_area_dma); kfree(io_priv); sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); return 0; @@ -1593,20 +1622,31 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) return ERR_CAST(sch); io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); - if (!io_priv) { - put_device(&sch->dev); - return ERR_PTR(-ENOMEM); - } + if (!io_priv) + goto err_priv; + io_priv->dma_area = dma_alloc_coherent(&sch->dev, + sizeof(*io_priv->dma_area), + &io_priv->dma_area_dma, GFP_KERNEL); + if (!io_priv->dma_area) + goto err_dma_area; set_io_private(sch, io_priv); cdev = io_subchannel_create_ccwdev(sch); if (IS_ERR(cdev)) { put_device(&sch->dev); + dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), + io_priv->dma_area, io_priv->dma_area_dma); kfree(io_priv); return cdev; } cdev->drv = drv; ccw_device_set_int_class(cdev); return cdev; + +err_dma_area: + kfree(io_priv); +err_priv: + put_device(&sch->dev); + return ERR_PTR(-ENOMEM); } void __init ccw_device_destroy_console(struct ccw_device *cdev) @@ -1617,6 +1657,8 @@ void __init ccw_device_destroy_console(struct ccw_device *cdev) set_io_private(sch, NULL); put_device(&sch->dev); put_device(&cdev->dev); + dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), + io_priv->dma_area, io_priv->dma_area_dma); kfree(io_priv); } diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 9169af7dbb43..96326dbc64ce 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -67,8 +67,10 @@ static void ccw_timeout_log(struct ccw_device *cdev) sizeof(struct tcw), 0); } else { printk(KERN_WARNING "cio: orb indicates command mode\n"); - if ((void *)(addr_t)orb->cmd.cpa == &private->sense_ccw || - (void *)(addr_t)orb->cmd.cpa == cdev->private->iccws) + if ((void *)(addr_t)orb->cmd.cpa == + &private->dma_area->sense_ccw || + (void *)(addr_t)orb->cmd.cpa == + cdev->private->dma_area->iccws) printk(KERN_WARNING "cio: last channel program " "(intern):\n"); else @@ -143,18 +145,26 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) void ccw_device_update_sense_data(struct ccw_device *cdev) { memset(&cdev->id, 0, sizeof(cdev->id)); - cdev->id.cu_type = cdev->private->senseid.cu_type; - cdev->id.cu_model = cdev->private->senseid.cu_model; - cdev->id.dev_type = cdev->private->senseid.dev_type; - cdev->id.dev_model = cdev->private->senseid.dev_model; + cdev->id.cu_type = + cdev->private->dma_area->senseid.cu_type; + cdev->id.cu_model = + cdev->private->dma_area->senseid.cu_model; + cdev->id.dev_type = + cdev->private->dma_area->senseid.dev_type; + cdev->id.dev_model = + cdev->private->dma_area->senseid.dev_model; } int ccw_device_test_sense_data(struct ccw_device *cdev) { - return cdev->id.cu_type == cdev->private->senseid.cu_type && - cdev->id.cu_model == cdev->private->senseid.cu_model && - cdev->id.dev_type == cdev->private->senseid.dev_type && - cdev->id.dev_model == cdev->private->senseid.dev_model; + return cdev->id.cu_type == + cdev->private->dma_area->senseid.cu_type && + cdev->id.cu_model == + cdev->private->dma_area->senseid.cu_model && + cdev->id.dev_type == + cdev->private->dma_area->senseid.dev_type && + cdev->id.dev_model == + cdev->private->dma_area->senseid.dev_model; } /* @@ -342,7 +352,7 @@ ccw_device_done(struct ccw_device *cdev, int state) cio_disable_subchannel(sch); /* Reset device status. */ - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); cdev->private->state = state; @@ -509,13 +519,14 @@ void ccw_device_verify_done(struct ccw_device *cdev, int err) ccw_device_done(cdev, DEV_STATE_ONLINE); /* Deliver fake irb to device driver, if needed. */ if (cdev->private->flags.fake_irb) { - create_fake_irb(&cdev->private->irb, + create_fake_irb(&cdev->private->dma_area->irb, cdev->private->flags.fake_irb); cdev->private->flags.fake_irb = 0; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - &cdev->private->irb); - memset(&cdev->private->irb, 0, sizeof(struct irb)); + &cdev->private->dma_area->irb); + memset(&cdev->private->dma_area->irb, 0, + sizeof(struct irb)); } ccw_device_report_path_events(cdev); ccw_device_handle_broken_paths(cdev); @@ -672,7 +683,8 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) if (scsw_actl(&sch->schib.scsw) != 0 || (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) || - (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) { + (scsw_stctl(&cdev->private->dma_area->irb.scsw) & + SCSW_STCTL_STATUS_PEND)) { /* * No final status yet or final status not yet delivered * to the device driver. Can't do path verification now, @@ -719,7 +731,7 @@ static int ccw_device_call_handler(struct ccw_device *cdev) * - fast notification was requested (primary status) * - unsolicited interrupts */ - stctl = scsw_stctl(&cdev->private->irb.scsw); + stctl = scsw_stctl(&cdev->private->dma_area->irb.scsw); ending_status = (stctl & SCSW_STCTL_SEC_STATUS) || (stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) || (stctl == SCSW_STCTL_STATUS_PEND); @@ -735,9 +747,9 @@ static int ccw_device_call_handler(struct ccw_device *cdev) if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - &cdev->private->irb); + &cdev->private->dma_area->irb); - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); return 1; } @@ -759,7 +771,8 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) /* Unit check but no sense data. Need basic sense. */ if (ccw_device_do_sense(cdev, irb) != 0) goto call_handler_unsol; - memcpy(&cdev->private->irb, irb, sizeof(struct irb)); + memcpy(&cdev->private->dma_area->irb, irb, + sizeof(struct irb)); cdev->private->state = DEV_STATE_W4SENSE; cdev->private->intparm = 0; return; @@ -842,7 +855,7 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) if (scsw_fctl(&irb->scsw) & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { cdev->private->flags.dosense = 0; - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); ccw_device_accumulate_irb(cdev, irb); goto call_handler; } diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index f6df83a9dfbb..740996d0dc8c 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -99,7 +99,7 @@ static int diag210_to_senseid(struct senseid *senseid, struct diag210 *diag) static int diag210_get_dev_info(struct ccw_device *cdev) { struct ccw_dev_id *dev_id = &cdev->private->dev_id; - struct senseid *senseid = &cdev->private->senseid; + struct senseid *senseid = &cdev->private->dma_area->senseid; struct diag210 diag_data; int rc; @@ -134,8 +134,10 @@ static int diag210_get_dev_info(struct ccw_device *cdev) static void snsid_init(struct ccw_device *cdev) { cdev->private->flags.esid = 0; - memset(&cdev->private->senseid, 0, sizeof(cdev->private->senseid)); - cdev->private->senseid.cu_type = 0xffff; + + memset(&cdev->private->dma_area->senseid, 0, + sizeof(cdev->private->dma_area->senseid)); + cdev->private->dma_area->senseid.cu_type = 0xffff; } /* @@ -143,16 +145,16 @@ static void snsid_init(struct ccw_device *cdev) */ static int snsid_check(struct ccw_device *cdev, void *data) { - struct cmd_scsw *scsw = &cdev->private->irb.scsw.cmd; + struct cmd_scsw *scsw = &cdev->private->dma_area->irb.scsw.cmd; int len = sizeof(struct senseid) - scsw->count; /* Check for incomplete SENSE ID data. */ if (len < SENSE_ID_MIN_LEN) goto out_restart; - if (cdev->private->senseid.cu_type == 0xffff) + if (cdev->private->dma_area->senseid.cu_type == 0xffff) goto out_restart; /* Check for incompatible SENSE ID data. */ - if (cdev->private->senseid.reserved != 0xff) + if (cdev->private->dma_area->senseid.reserved != 0xff) return -EOPNOTSUPP; /* Check for extended-identification information. */ if (len > SENSE_ID_BASIC_LEN) @@ -170,7 +172,7 @@ static int snsid_check(struct ccw_device *cdev, void *data) static void snsid_callback(struct ccw_device *cdev, void *data, int rc) { struct ccw_dev_id *id = &cdev->private->dev_id; - struct senseid *senseid = &cdev->private->senseid; + struct senseid *senseid = &cdev->private->dma_area->senseid; int vm = 0; if (rc && MACHINE_IS_VM) { @@ -200,7 +202,7 @@ void ccw_device_sense_id_start(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; CIO_TRACE_EVENT(4, "snsid"); CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); @@ -208,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->senseid; + cp->cda = (u32) (addr_t) &cdev->private->dma_area->senseid; cp->count = sizeof(struct senseid); cp->flags = CCW_FLAG_SLI; /* Request setup. */ diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 4435ae0b3027..be4acfa9265a 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -429,8 +429,8 @@ struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) if (cdev->private->flags.esid == 0) return NULL; for (ciw_cnt = 0; ciw_cnt < MAX_CIWS; ciw_cnt++) - if (cdev->private->senseid.ciw[ciw_cnt].ct == ct) - return cdev->private->senseid.ciw + ciw_cnt; + if (cdev->private->dma_area->senseid.ciw[ciw_cnt].ct == ct) + return cdev->private->dma_area->senseid.ciw + ciw_cnt; return NULL; } @@ -699,6 +699,23 @@ void ccw_device_get_schid(struct ccw_device *cdev, struct subchannel_id *schid) } EXPORT_SYMBOL_GPL(ccw_device_get_schid); +/** + * Allocate zeroed dma coherent 31 bit addressable memory using + * the subchannels dma pool. Maximal size of allocation supported + * is PAGE_SIZE. + */ +void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size) +{ + return cio_gp_dma_zalloc(cdev->private->dma_pool, &cdev->dev, size); +} +EXPORT_SYMBOL(ccw_device_dma_zalloc); + +void ccw_device_dma_free(struct ccw_device *cdev, void *cpu_addr, size_t size) +{ + cio_gp_dma_free(cdev->private->dma_pool, cpu_addr, size); +} +EXPORT_SYMBOL(ccw_device_dma_free); + EXPORT_SYMBOL(ccw_device_set_options_mask); EXPORT_SYMBOL(ccw_device_set_options); EXPORT_SYMBOL(ccw_device_clear_options); diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index d30a3babf176..767a85635a0f 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -57,7 +57,7 @@ static void verify_done(struct ccw_device *cdev, int rc) static void nop_build_cp(struct ccw_device *cdev) { struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; cp->cmd_code = CCW_CMD_NOOP; cp->cda = 0; @@ -134,9 +134,9 @@ static void nop_callback(struct ccw_device *cdev, void *data, int rc) static void spid_build_cp(struct ccw_device *cdev, u8 fn) { struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; int i = pathmask_to_pos(req->lpm); - struct pgid *pgid = &cdev->private->pgid[i]; + struct pgid *pgid = &cdev->private->dma_area->pgid[i]; pgid->inf.fc = fn; cp->cmd_code = CCW_CMD_SET_PGID; @@ -300,7 +300,7 @@ static int pgid_cmp(struct pgid *p1, struct pgid *p2) static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, int *mismatch, u8 *reserved, u8 *reset) { - struct pgid *pgid = &cdev->private->pgid[0]; + struct pgid *pgid = &cdev->private->dma_area->pgid[0]; struct pgid *first = NULL; int lpm; int i; @@ -342,7 +342,7 @@ static u8 pgid_to_donepm(struct ccw_device *cdev) lpm = 0x80 >> i; if ((cdev->private->pgid_valid_mask & lpm) == 0) continue; - pgid = &cdev->private->pgid[i]; + pgid = &cdev->private->dma_area->pgid[i]; if (sch->opm & lpm) { if (pgid->inf.ps.state1 != SNID_STATE1_GROUPED) continue; @@ -368,7 +368,8 @@ static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid) int i; for (i = 0; i < 8; i++) - memcpy(&cdev->private->pgid[i], pgid, sizeof(struct pgid)); + memcpy(&cdev->private->dma_area->pgid[i], pgid, + sizeof(struct pgid)); } /* @@ -435,12 +436,12 @@ static void snid_done(struct ccw_device *cdev, int rc) static void snid_build_cp(struct ccw_device *cdev) { struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; int i = pathmask_to_pos(req->lpm); /* Channel program setup. */ cp->cmd_code = CCW_CMD_SENSE_PGID; - cp->cda = (u32) (addr_t) &cdev->private->pgid[i]; + cp->cda = (u32) (addr_t) &cdev->private->dma_area->pgid[i]; cp->count = sizeof(struct pgid); cp->flags = CCW_FLAG_SLI; req->cp = cp; @@ -516,7 +517,8 @@ static void verify_start(struct ccw_device *cdev) sch->lpm = sch->schib.pmcw.pam; /* Initialize PGID data. */ - memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid)); + memset(cdev->private->dma_area->pgid, 0, + sizeof(cdev->private->dma_area->pgid)); cdev->private->pgid_valid_mask = 0; cdev->private->pgid_todo_mask = sch->schib.pmcw.pam; cdev->private->path_notoper_mask = 0; @@ -626,7 +628,7 @@ struct stlck_data { static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2) { struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; cp[0].cmd_code = CCW_CMD_STLCK; cp[0].cda = (u32) (addr_t) buf1; diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 7d5c7892b2c4..0bd8f2642732 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -79,15 +79,15 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) * are condition that have to be met for the extended control * bit to have meaning. Sick. */ - cdev->private->irb.scsw.cmd.ectl = 0; + cdev->private->dma_area->irb.scsw.cmd.ectl = 0; if ((irb->scsw.cmd.stctl & SCSW_STCTL_ALERT_STATUS) && !(irb->scsw.cmd.stctl & SCSW_STCTL_INTER_STATUS)) - cdev->private->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl; + cdev->private->dma_area->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl; /* Check if extended control word is valid. */ - if (!cdev->private->irb.scsw.cmd.ectl) + if (!cdev->private->dma_area->irb.scsw.cmd.ectl) return; /* Copy concurrent sense / model dependent information. */ - memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw)); + memcpy(&cdev->private->dma_area->irb.ecw, irb->ecw, sizeof(irb->ecw)); } /* @@ -118,7 +118,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) if (!ccw_device_accumulate_esw_valid(irb)) return; - cdev_irb = &cdev->private->irb; + cdev_irb = &cdev->private->dma_area->irb; /* Copy last path used mask. */ cdev_irb->esw.esw1.lpum = irb->esw.esw1.lpum; @@ -210,7 +210,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) ccw_device_path_notoper(cdev); /* No irb accumulation for transport mode irbs. */ if (scsw_is_tm(&irb->scsw)) { - memcpy(&cdev->private->irb, irb, sizeof(struct irb)); + memcpy(&cdev->private->dma_area->irb, irb, sizeof(struct irb)); return; } /* @@ -219,7 +219,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) if (!scsw_is_solicited(&irb->scsw)) return; - cdev_irb = &cdev->private->irb; + cdev_irb = &cdev->private->dma_area->irb; /* * If the clear function had been performed, all formerly pending @@ -227,7 +227,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) * intermediate accumulated status to the device driver. */ if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); /* Copy bits which are valid only for the start function. */ if (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) { @@ -329,9 +329,9 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) /* * We have ending status but no sense information. Do a basic sense. */ - sense_ccw = &to_io_private(sch)->sense_ccw; + 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->irb.ecw); + sense_ccw->cda = (__u32) __pa(cdev->private->dma_area->irb.ecw); sense_ccw->count = SENSE_MAX_COUNT; sense_ccw->flags = CCW_FLAG_SLI; @@ -364,7 +364,7 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb) if (!(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && (irb->scsw.cmd.dstat & DEV_STAT_CHN_END)) { - cdev->private->irb.esw.esw0.erw.cons = 1; + cdev->private->dma_area->irb.esw.esw0.erw.cons = 1; cdev->private->flags.dosense = 0; } /* Check if path verification is required. */ @@ -386,7 +386,7 @@ ccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb) /* Check for basic sense. */ if (cdev->private->flags.dosense && !(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) { - cdev->private->irb.esw.esw0.erw.cons = 1; + cdev->private->dma_area->irb.esw.esw0.erw.cons = 1; cdev->private->flags.dosense = 0; return 0; } diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index 90e4e3a7841b..c03b4a19974e 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -9,15 +9,20 @@ #include "css.h" #include "orb.h" +struct io_subchannel_dma_area { + struct ccw1 sense_ccw; /* static ccw for sense command */ +}; + struct io_subchannel_private { union orb orb; /* operation request block */ - struct ccw1 sense_ccw; /* static ccw for sense command */ struct ccw_device *cdev;/* pointer to the child ccw device */ struct { unsigned int suspend:1; /* allow suspend */ unsigned int prefetch:1;/* deny prefetch */ unsigned int inter:1; /* suppress intermediate interrupts */ } __packed options; + struct io_subchannel_dma_area *dma_area; + dma_addr_t dma_area_dma; } __aligned(8); #define to_io_private(n) ((struct io_subchannel_private *) \ @@ -115,6 +120,13 @@ enum cdev_todo { #define FAKE_CMD_IRB 1 #define FAKE_TM_IRB 2 +struct ccw_device_dma_area { + struct senseid senseid; /* SenseID info */ + struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ + struct irb irb; /* device status */ + struct pgid pgid[8]; /* path group IDs per chpid*/ +}; + struct ccw_device_private { struct ccw_device *cdev; struct subchannel *sch; @@ -156,11 +168,7 @@ struct ccw_device_private { } __attribute__((packed)) flags; unsigned long intparm; /* user interruption parameter */ struct qdio_irq *qdio_data; - struct irb irb; /* device status */ int async_kill_io_rc; - struct senseid senseid; /* SenseID info */ - struct pgid pgid[8]; /* path group IDs per chpid*/ - struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ struct work_struct todo_work; enum cdev_todo todo; wait_queue_head_t wait_q; @@ -169,6 +177,8 @@ struct ccw_device_private { struct list_head cmb_list; /* list of measured devices */ u64 cmb_start_time; /* clock value of cmb reset */ void *cmb_wait; /* deferred cmb enable/disable */ + struct gen_pool *dma_pool; + struct ccw_device_dma_area *dma_area; enum interruption_class int_class; }; diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 6a3076881321..f995798bb025 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -66,7 +66,6 @@ struct virtio_ccw_device { bool device_lost; unsigned int config_ready; void *airq_info; - u64 dma_mask; }; struct vq_info_block_legacy { @@ -1255,16 +1254,7 @@ static int virtio_ccw_online(struct ccw_device *cdev) ret = -ENOMEM; goto out_free; } - vcdev->vdev.dev.parent = &cdev->dev; - cdev->dev.dma_mask = &vcdev->dma_mask; - /* we are fine with common virtio infrastructure using 64 bit DMA */ - ret = dma_set_mask_and_coherent(&cdev->dev, DMA_BIT_MASK(64)); - if (ret) { - dev_warn(&cdev->dev, "Failed to enable 64-bit DMA.\n"); - goto out_free; - } - vcdev->config_block = kzalloc(sizeof(*vcdev->config_block), GFP_DMA | GFP_KERNEL); if (!vcdev->config_block) {