s390x/css: ccw translation infrastructure
Implement a basic infrastructure of handling channel I/O instruction interception for passed through subchannels: 1. Branch the code path of instruction interception handling by SubChannel type. 2. For a passed-through subchannel, issue the ORB to kernel to do ccw translation and perform an I/O operation. 3. Assign different condition code based on the I/O result, or trigger a program check. Signed-off-by: Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> Signed-off-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> Message-Id: <20170517004813.58227-12-bjsdjshi@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
This commit is contained in:
		
							parent
							
								
									8ca2b376b4
								
							
						
					
					
						commit
						bab482d740
					
				| 
						 | 
				
			
			@ -524,7 +524,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
 | 
			
		|||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sch_handle_start_func(SubchDev *sch, ORB *orb)
 | 
			
		||||
static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    PMCW *p = &sch->curr_status.pmcw;
 | 
			
		||||
| 
						 | 
				
			
			@ -626,13 +626,58 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sch_handle_start_func_passthrough(SubchDev *sch, ORB *orb)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    PMCW *p = &sch->curr_status.pmcw;
 | 
			
		||||
    SCSW *s = &sch->curr_status.scsw;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (!(s->ctrl & SCSW_ACTL_SUSP)) {
 | 
			
		||||
        assert(orb != NULL);
 | 
			
		||||
        p->intparm = orb->intparm;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Only support prefetch enable mode.
 | 
			
		||||
     * Only support 64bit addressing idal.
 | 
			
		||||
     */
 | 
			
		||||
    if (!(orb->ctrl0 & ORB_CTRL0_MASK_PFCH) ||
 | 
			
		||||
        !(orb->ctrl0 & ORB_CTRL0_MASK_C64)) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = s390_ccw_cmd_request(orb, s, sch->driver_data);
 | 
			
		||||
    switch (ret) {
 | 
			
		||||
    /* Currently we don't update control block and just return the cc code. */
 | 
			
		||||
    case 0:
 | 
			
		||||
        break;
 | 
			
		||||
    case -EBUSY:
 | 
			
		||||
        break;
 | 
			
		||||
    case -ENODEV:
 | 
			
		||||
        break;
 | 
			
		||||
    case -EACCES:
 | 
			
		||||
        /* Let's reflect an inaccessible host device by cc 3. */
 | 
			
		||||
        ret = -ENODEV;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
       /*
 | 
			
		||||
        * All other return codes will trigger a program check,
 | 
			
		||||
        * or set cc to 1.
 | 
			
		||||
        */
 | 
			
		||||
       break;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * On real machines, this would run asynchronously to the main vcpus.
 | 
			
		||||
 * We might want to make some parts of the ssch handling (interpreting
 | 
			
		||||
 * read/writes) asynchronous later on if we start supporting more than
 | 
			
		||||
 * our current very simple devices.
 | 
			
		||||
 */
 | 
			
		||||
static void do_subchannel_work(SubchDev *sch, ORB *orb)
 | 
			
		||||
int do_subchannel_work_virtual(SubchDev *sch, ORB *orb)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    SCSW *s = &sch->curr_status.scsw;
 | 
			
		||||
| 
						 | 
				
			
			@ -643,12 +688,45 @@ static void do_subchannel_work(SubchDev *sch, ORB *orb)
 | 
			
		|||
        sch_handle_halt_func(sch);
 | 
			
		||||
    } else if (s->ctrl & SCSW_FCTL_START_FUNC) {
 | 
			
		||||
        /* Triggered by both ssch and rsch. */
 | 
			
		||||
        sch_handle_start_func(sch, orb);
 | 
			
		||||
        sch_handle_start_func_virtual(sch, orb);
 | 
			
		||||
    } else {
 | 
			
		||||
        /* Cannot happen. */
 | 
			
		||||
        return;
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    css_inject_io_interrupt(sch);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    SCSW *s = &sch->curr_status.scsw;
 | 
			
		||||
 | 
			
		||||
    if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) {
 | 
			
		||||
        /* TODO: Clear handling */
 | 
			
		||||
        sch_handle_clear_func(sch);
 | 
			
		||||
        ret = 0;
 | 
			
		||||
    } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) {
 | 
			
		||||
        /* TODO: Halt handling */
 | 
			
		||||
        sch_handle_halt_func(sch);
 | 
			
		||||
        ret = 0;
 | 
			
		||||
    } else if (s->ctrl & SCSW_FCTL_START_FUNC) {
 | 
			
		||||
        ret = sch_handle_start_func_passthrough(sch, orb);
 | 
			
		||||
    } else {
 | 
			
		||||
        /* Cannot happen. */
 | 
			
		||||
        return -ENODEV;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_subchannel_work(SubchDev *sch, ORB *orb)
 | 
			
		||||
{
 | 
			
		||||
    if (sch->do_subchannel_work) {
 | 
			
		||||
        return sch->do_subchannel_work(sch, orb);
 | 
			
		||||
    } else {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src)
 | 
			
		||||
| 
						 | 
				
			
			@ -967,8 +1045,7 @@ int css_do_ssch(SubchDev *sch, ORB *orb)
 | 
			
		|||
    s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
 | 
			
		||||
    s->flags &= ~SCSW_FLAGS_MASK_PNO;
 | 
			
		||||
 | 
			
		||||
    do_subchannel_work(sch, orb);
 | 
			
		||||
    ret = 0;
 | 
			
		||||
    ret = do_subchannel_work(sch, orb);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    return ret;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,17 @@
 | 
			
		|||
#include "hw/s390x/css-bridge.h"
 | 
			
		||||
#include "hw/s390x/s390-ccw.h"
 | 
			
		||||
 | 
			
		||||
int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data)
 | 
			
		||||
{
 | 
			
		||||
    S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(data);
 | 
			
		||||
 | 
			
		||||
    if (cdc->handle_request) {
 | 
			
		||||
        return cdc->handle_request(orb, scsw, data);
 | 
			
		||||
    } else {
 | 
			
		||||
        return -ENOSYS;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
 | 
			
		||||
                                  char *sysfsdev,
 | 
			
		||||
                                  Error **errp)
 | 
			
		||||
| 
						 | 
				
			
			@ -72,6 +83,7 @@ static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp)
 | 
			
		|||
        goto out_mdevid_free;
 | 
			
		||||
    }
 | 
			
		||||
    sch->driver_data = cdev;
 | 
			
		||||
    sch->do_subchannel_work = do_subchannel_work_passthrough;
 | 
			
		||||
 | 
			
		||||
    ccw_dev->sch = sch;
 | 
			
		||||
    ret = css_sch_build_schib(sch, &cdev->hostid);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -701,6 +701,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
 | 
			
		|||
    sch->disable_cb = virtio_sch_disable_cb;
 | 
			
		||||
    sch->id.reserved = 0xff;
 | 
			
		||||
    sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
 | 
			
		||||
    sch->do_subchannel_work = do_subchannel_work_virtual;
 | 
			
		||||
    ccw_dev->sch = sch;
 | 
			
		||||
    dev->indicators = NULL;
 | 
			
		||||
    dev->revision = -1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,6 +91,7 @@ struct SubchDev {
 | 
			
		|||
    /* transport-provided data: */
 | 
			
		||||
    int (*ccw_cb) (SubchDev *, CCW1);
 | 
			
		||||
    void (*disable_cb)(SubchDev *);
 | 
			
		||||
    int (*do_subchannel_work) (SubchDev *, ORB *);
 | 
			
		||||
    SenseId id;
 | 
			
		||||
    void *driver_data;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -148,6 +149,9 @@ void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
 | 
			
		|||
void css_generate_css_crws(uint8_t cssid);
 | 
			
		||||
void css_clear_sei_pending(void);
 | 
			
		||||
void css_adapter_interrupt(uint8_t isc);
 | 
			
		||||
int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data);
 | 
			
		||||
int do_subchannel_work_virtual(SubchDev *sub, ORB *orb);
 | 
			
		||||
int do_subchannel_work_passthrough(SubchDev *sub, ORB *orb);
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    CSS_IO_ADAPTER_VIRTIO = 0,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -244,6 +244,15 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
 | 
			
		|||
    case -EBUSY:
 | 
			
		||||
        cc = 2;
 | 
			
		||||
        break;
 | 
			
		||||
    case -EFAULT:
 | 
			
		||||
        /*
 | 
			
		||||
         * TODO:
 | 
			
		||||
         * I'm wondering whether there is something better
 | 
			
		||||
         * to do for us here (like setting some device or
 | 
			
		||||
         * subchannel status).
 | 
			
		||||
         */
 | 
			
		||||
        program_interrupt(env, PGM_ADDRESSING, 4);
 | 
			
		||||
        return;
 | 
			
		||||
    case 0:
 | 
			
		||||
        cc = 0;
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue