Message ID | 1551466776-29123-11-git-send-email-jjherne@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | s390: vfio-ccw dasd ipl support | expand |
On Fri, 1 Mar 2019 13:59:30 -0500 "Jason J. Herne" <jjherne@linux.ibm.com> wrote: > Add struct for format-0 ccws. Support executing format-0 channel > programs and waiting for their completion before continuing execution. That sentence is a bit confusing. What about: "Introduce a library function for executing format-0 and format-1 channel programs..." > This will be used for real dasd ipl. But also for virtio in the follow-on patches, won't it? > > Add cu_type() to channel io library. This will be used to query control > unit type which is used to determine if we are booting a virtio device or a > real dasd device. > > Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com> > --- > pc-bios/s390-ccw/cio.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ > pc-bios/s390-ccw/cio.h | 127 ++++++++++++++++++++++++++++++++++++++- > pc-bios/s390-ccw/s390-ccw.h | 1 + > pc-bios/s390-ccw/start.S | 31 ++++++++++ > 4 files changed, 297 insertions(+), 3 deletions(-) > (...) > +/* > + * Handles executing ssch, tsch and returns the irb obtained from tsch. > + * Returns 0 on success, -1 if unexpected status pending and we need to retry, > + * otherwse returns condition code from ssch/tsch for error cases. s/otherwse/otherwise/ > + */ > +static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb) > +{ > + CmdOrb orb = {}; > + int rc; > + > + IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format"); > + > + /* ccw_addr must be <= 24 bits and point to at least one whole ccw. */ > + if (fmt == 0) { > + IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address"); > + } > + > + orb.fmt = fmt ; extra ' ' before ';' > + orb.pfch = 1; /* QEMU's cio implementation requires prefetch */ > + orb.c64 = 1; /* QEMU's cio implementation requires 64-bit idaws */ > + orb.lpm = 0xFF; /* All paths allowed */ > + orb.cpa = ccw_addr; > + > + rc = ssch(schid, &orb); > + if (rc == 1) { > + /* Status pending, not sure why. Eat status and ask for retry. */ > + tsch(schid, irb); > + return -1; > + } > + if (rc) { > + print_int("ssch failed with rc=", rc); Better 'cc' than 'rc' in the message? > + return rc; > + } > + > + consume_io_int(); > + > + /* collect status */ > + rc = tsch(schid, irb); > + if (rc) { > + print_int("tsch failed with rc=", rc); > + } Hm. The whole code flow relies on the fact that not only no more than one cpu is enabled for I/O interrupts, but also only one subchannel. Otherwise, you could get an interrupt for another subchannel, which would be the only way you'd get cc 1 on the tsch for this subchannel here (no status pending). Maybe peek at the interruption information stored into the lowcore first? Won't be a problem with the code as it is now, though, AFAICS. > + > + return rc; > +} > + > +/* > + * Executes a channel program at a given subchannel. The request to run the > + * channel program is sent to the subchannel, we then wait for the interrupt > + * signaling completion of the I/O operation(s) performed by the channel > + * program. Lastly we verify that the i/o operation completed without error and > + * that the interrupt we received was for the subchannel used to run the > + * channel program. > + * > + * Note: This function assumes it is running in an environment where no other > + * cpus are generating or receiving I/O interrupts. So either run it in a > + * single-cpu environment or make sure all other cpus are not doing I/O and > + * have I/O interrupts masked off. > + * > + * Returns non-zero on error. > + */ > +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt) > +{ > + Irb irb = {}; > + SenseDataEckdDasd sd; > + int rc, retries = 0; > + > + while (true) { > + rc = __do_cio(schid, ccw_addr, fmt, &irb); > + > + if (rc == -1) { > + retries++; > + continue; > + } > + if (rc) { > + /* ssch/tsch error. Message already reported by __do_cio */ You might also want to consider retrying on cc 2. Not very likely, though. > + break; > + } > + > + if (!irb_error(&irb)) { > + break; > + } > + > + /* > + * Unexpected unit check, or interface-control-check. Use sense to > + * clear (unit check only) then retry. > + */ > + if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) { > + if (unit_check(&irb)) { > + basic_sense(schid, &sd, sizeof(sd)); Unless I'm confused: I think you can still descend into the unit check rabbit hole here. basic_sense() calls do_cio(), which calls basic_sense(),... and we don't even get to the retries check. Maybe call __do_cio() from basic_sense() instead and make that return an error instead of panicking? Then you could just bump retries here and give up after some retries... > + } > + retries++; > + continue; > + } > + > + rc = -1; > + break; > + } > + > + return rc; > +}
On 01/03/2019 19.59, Jason J. Herne wrote: > Add struct for format-0 ccws. Support executing format-0 channel > programs and waiting for their completion before continuing execution. > This will be used for real dasd ipl. > > Add cu_type() to channel io library. This will be used to query control > unit type which is used to determine if we are booting a virtio device or a > real dasd device. > > Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com> > --- [...] > diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S > index 5c22cb0..2b4ea4c 100644 > --- a/pc-bios/s390-ccw/start.S > +++ b/pc-bios/s390-ccw/start.S > @@ -71,6 +71,26 @@ consume_sclp_int: > larl %r1, enabled_wait_psw > lpswe 0(%r1) > > +/* > + * void consume_io_int(void) > + * > + * eats one I/O interrupt > + */ > + .globl consume_io_int > +consume_io_int: > + /* enable I/O interrupts in cr6 */ > + stctg 6,6,0(15) > + oi 4(15), 0xff > + lctlg 6,6,0(15) Could you please use %-register names? If we ever want to compile the code with Clang again, this will likely be required (see commit 0d3a76139827f7d08f1b for example). I.e.: stctg %c6,%c6,0(%r15) oi 4(%r15),0xff lctlg %c6,%c6,0(%r15) (indenting the parameters of the instruction would also be nice) > + /* prepare i/o call handler */ > + larl %r1, io_new_code > + stg %r1, 0x1f8 > + larl %r1, io_new_mask > + mvc 0x1f0(8),0(%r1) > + /* load enabled wait PSW */ > + larl %r1, enabled_wait_psw > + lpswe 0(%r1) > + > external_new_code: > /* disable service interrupts in cr0 */ > stctg %c0,%c0,0(%r15) > @@ -78,6 +98,15 @@ external_new_code: > lctlg %c0,%c0,0(%r15) > br %r14 > > +io_new_code: > + /* disable I/O interrupts in cr6 */ > + stctg 6,6,0(15) > + ni 4(15), 0x00 > + lctlg 6,6,0(15) dito Thanks, Thomas
On 3/4/19 1:25 PM, Cornelia Huck wrote: > On Fri, 1 Mar 2019 13:59:30 -0500 > "Jason J. Herne" <jjherne@linux.ibm.com> wrote: > >> Add struct for format-0 ccws. Support executing format-0 channel >> programs and waiting for their completion before continuing execution. > > That sentence is a bit confusing. What about: > > "Introduce a library function for executing format-0 and format-1 > channel programs..." > Agreed. Fixed. >> This will be used for real dasd ipl. > > But also for virtio in the follow-on patches, won't it? > True. I removed that line. It is obvious and not really useful anyway. ... >> + orb.fmt = fmt ; > > extra ' ' before ';' > Fixed. >> + orb.pfch = 1; /* QEMU's cio implementation requires prefetch */ >> + orb.c64 = 1; /* QEMU's cio implementation requires 64-bit idaws */ >> + orb.lpm = 0xFF; /* All paths allowed */ >> + orb.cpa = ccw_addr; >> + >> + rc = ssch(schid, &orb); >> + if (rc == 1) { >> + /* Status pending, not sure why. Eat status and ask for retry. */ >> + tsch(schid, irb); >> + return -1; >> + } >> + if (rc) { >> + print_int("ssch failed with rc=", rc); > > Better 'cc' than 'rc' in the message? > Fixed here and for tsch as well. >> + return rc; >> + } >> + >> + consume_io_int(); >> + >> + /* collect status */ >> + rc = tsch(schid, irb); >> + if (rc) { >> + print_int("tsch failed with rc=", rc); >> + } > > Hm. The whole code flow relies on the fact that not only no more than > one cpu is enabled for I/O interrupts, but also only one subchannel. > Otherwise, you could get an interrupt for another subchannel, which > would be the only way you'd get cc 1 on the tsch for this subchannel > here (no status pending). Maybe peek at the interruption information > stored into the lowcore first? > > Won't be a problem with the code as it is now, though, AFAICS. > Agreed, voting to leave as is. Perhaps a comment to explain that we rely on only one "Active" i/o device? >> + >> + return rc; >> +} >> + >> +/* >> + * Executes a channel program at a given subchannel. The request to run the >> + * channel program is sent to the subchannel, we then wait for the interrupt >> + * signaling completion of the I/O operation(s) performed by the channel >> + * program. Lastly we verify that the i/o operation completed without error and >> + * that the interrupt we received was for the subchannel used to run the >> + * channel program. >> + * >> + * Note: This function assumes it is running in an environment where no other >> + * cpus are generating or receiving I/O interrupts. So either run it in a >> + * single-cpu environment or make sure all other cpus are not doing I/O and >> + * have I/O interrupts masked off. >> + * >> + * Returns non-zero on error. >> + */ >> +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt) >> +{ >> + Irb irb = {}; >> + SenseDataEckdDasd sd; >> + int rc, retries = 0; >> + >> + while (true) { >> + rc = __do_cio(schid, ccw_addr, fmt, &irb); >> + >> + if (rc == -1) { >> + retries++; >> + continue; >> + } >> + if (rc) { >> + /* ssch/tsch error. Message already reported by __do_cio */ > > You might also want to consider retrying on cc 2. Not very likely, > though. > It is easy to retry on cc=2, fixed. >> + break; >> + } >> + >> + if (!irb_error(&irb)) { >> + break; >> + } >> + >> + /* >> + * Unexpected unit check, or interface-control-check. Use sense to >> + * clear (unit check only) then retry. >> + */ >> + if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) { >> + if (unit_check(&irb)) { >> + basic_sense(schid, &sd, sizeof(sd)); > > Unless I'm confused: I think you can still descend into the unit check > rabbit hole here. basic_sense() calls do_cio(), which calls > basic_sense(),... and we don't even get to the retries check. > > Maybe call __do_cio() from basic_sense() instead and make that return > an error instead of panicking? Then you could just bump retries here > and give up after some retries... > Yes, good point. This is now fixed.
On Thu, 7 Mar 2019 14:25:00 -0500 "Jason J. Herne" <jjherne@linux.ibm.com> wrote: > On 3/4/19 1:25 PM, Cornelia Huck wrote: > > On Fri, 1 Mar 2019 13:59:30 -0500 > > "Jason J. Herne" <jjherne@linux.ibm.com> wrote: > >> + consume_io_int(); > >> + > >> + /* collect status */ > >> + rc = tsch(schid, irb); > >> + if (rc) { > >> + print_int("tsch failed with rc=", rc); > >> + } > > > > Hm. The whole code flow relies on the fact that not only no more than > > one cpu is enabled for I/O interrupts, but also only one subchannel. > > Otherwise, you could get an interrupt for another subchannel, which > > would be the only way you'd get cc 1 on the tsch for this subchannel > > here (no status pending). Maybe peek at the interruption information > > stored into the lowcore first? > > > > Won't be a problem with the code as it is now, though, AFAICS. > > > Agreed, voting to leave as is. Perhaps a comment to explain that we rely on only one > "Active" i/o device? Yes, sounds good.
diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c index 605f6f0..e61cfd3 100644 --- a/pc-bios/s390-ccw/cio.c +++ b/pc-bios/s390-ccw/cio.c @@ -12,6 +12,8 @@ #include "libc.h" #include "s390-ccw.h" +#include "s390-arch.h" +#include "helper.h" #include "cio.h" static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); @@ -41,3 +43,142 @@ void enable_subchannel(SubChannelId schid) schib.pmcw.ena = 1; msch(schid, &schib); } + +uint16_t cu_type(SubChannelId schid) +{ + Ccw1 sense_id_ccw; + SenseId sense_data; + + sense_id_ccw.cmd_code = CCW_CMD_SENSE_ID; + sense_id_ccw.cda = ptr2u32(&sense_data); + sense_id_ccw.count = sizeof(sense_data); + sense_id_ccw.flags |= CCW_FLAG_SLI; + + if (do_cio(schid, ptr2u32(&sense_id_ccw), CCW_FMT1)) { + panic("Failed to run SenseID CCw\n"); + } + + return sense_data.cu_type; +} + +void basic_sense(SubChannelId schid, void *sense_data, uint16_t data_size) +{ + Ccw1 senseCcw; + + senseCcw.cmd_code = CCW_CMD_BASIC_SENSE; + senseCcw.cda = ptr2u32(sense_data); + senseCcw.count = data_size; + + if (do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1)) { + panic("Failed to run Basic Sense CCW\n"); + } +} + +static bool irb_error(Irb *irb) +{ + if (irb->scsw.cstat) { + return true; + } + return irb->scsw.dstat != (SCSW_DSTAT_DEVEND | SCSW_DSTAT_CHEND); +} + +/* + * Handles executing ssch, tsch and returns the irb obtained from tsch. + * Returns 0 on success, -1 if unexpected status pending and we need to retry, + * otherwse returns condition code from ssch/tsch for error cases. + */ +static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb) +{ + CmdOrb orb = {}; + int rc; + + IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format"); + + /* ccw_addr must be <= 24 bits and point to at least one whole ccw. */ + if (fmt == 0) { + IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address"); + } + + orb.fmt = fmt ; + orb.pfch = 1; /* QEMU's cio implementation requires prefetch */ + orb.c64 = 1; /* QEMU's cio implementation requires 64-bit idaws */ + orb.lpm = 0xFF; /* All paths allowed */ + orb.cpa = ccw_addr; + + rc = ssch(schid, &orb); + if (rc == 1) { + /* Status pending, not sure why. Eat status and ask for retry. */ + tsch(schid, irb); + return -1; + } + if (rc) { + print_int("ssch failed with rc=", rc); + return rc; + } + + consume_io_int(); + + /* collect status */ + rc = tsch(schid, irb); + if (rc) { + print_int("tsch failed with rc=", rc); + } + + return rc; +} + +/* + * Executes a channel program at a given subchannel. The request to run the + * channel program is sent to the subchannel, we then wait for the interrupt + * signaling completion of the I/O operation(s) performed by the channel + * program. Lastly we verify that the i/o operation completed without error and + * that the interrupt we received was for the subchannel used to run the + * channel program. + * + * Note: This function assumes it is running in an environment where no other + * cpus are generating or receiving I/O interrupts. So either run it in a + * single-cpu environment or make sure all other cpus are not doing I/O and + * have I/O interrupts masked off. + * + * Returns non-zero on error. + */ +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt) +{ + Irb irb = {}; + SenseDataEckdDasd sd; + int rc, retries = 0; + + while (true) { + rc = __do_cio(schid, ccw_addr, fmt, &irb); + + if (rc == -1) { + retries++; + continue; + } + if (rc) { + /* ssch/tsch error. Message already reported by __do_cio */ + break; + } + + if (!irb_error(&irb)) { + break; + } + + /* + * Unexpected unit check, or interface-control-check. Use sense to + * clear (unit check only) then retry. + */ + if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) { + if (unit_check(&irb)) { + basic_sense(schid, &sd, sizeof(sd)); + } + retries++; + continue; + } + + rc = -1; + break; + } + + return rc; +} diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h index d454050..9de67ec 100644 --- a/pc-bios/s390-ccw/cio.h +++ b/pc-bios/s390-ccw/cio.h @@ -70,9 +70,46 @@ struct scsw { __u16 count; } __attribute__ ((packed)); -#define SCSW_FCTL_CLEAR_FUNC 0x1000 -#define SCSW_FCTL_HALT_FUNC 0x2000 +/* Function Control */ #define SCSW_FCTL_START_FUNC 0x4000 +#define SCSW_FCTL_HALT_FUNC 0x2000 +#define SCSW_FCTL_CLEAR_FUNC 0x1000 + +/* Activity Control */ +#define SCSW_ACTL_RESUME_PEND 0x0800 +#define SCSW_ACTL_START_PEND 0x0400 +#define SCSW_ACTL_HALT_PEND 0x0200 +#define SCSW_ACTL_CLEAR_PEND 0x0100 +#define SCSW_ACTL_CH_ACTIVE 0x0080 +#define SCSW_ACTL_DEV_ACTIVE 0x0040 +#define SCSW_ACTL_SUSPENDED 0x0020 + +/* Status Control */ +#define SCSW_SCTL_ALERT 0x0010 +#define SCSW_SCTL_INTERMED 0x0008 +#define SCSW_SCTL_PRIMARY 0x0004 +#define SCSW_SCTL_SECONDARY 0x0002 +#define SCSW_SCTL_STATUS_PEND 0x0001 + +/* SCSW Device Status Flags */ +#define SCSW_DSTAT_ATTN 0x80 +#define SCSW_DSTAT_STATMOD 0x40 +#define SCSW_DSTAT_CUEND 0x20 +#define SCSW_DSTAT_BUSY 0x10 +#define SCSW_DSTAT_CHEND 0x08 +#define SCSW_DSTAT_DEVEND 0x04 +#define SCSW_DSTAT_UCHK 0x02 +#define SCSW_DSTAT_UEXCP 0x01 + +/* SCSW Subchannel Status Flags */ +#define SCSW_CSTAT_PCINT 0x80 +#define SCSW_CSTAT_BADLEN 0x40 +#define SCSW_CSTAT_PROGCHK 0x20 +#define SCSW_CSTAT_PROTCHK 0x10 +#define SCSW_CSTAT_CHDCHK 0x08 +#define SCSW_CSTAT_CHCCHK 0x04 +#define SCSW_CSTAT_ICCHK 0x02 +#define SCSW_CSTAT_CHAINCHK 0x01 /* * subchannel information block @@ -127,7 +164,23 @@ struct tpi_info { __u32 reserved4:12; } __attribute__ ((packed, aligned(4))); -/* channel command word (type 1) */ +/* channel command word (format 0) */ +typedef struct ccw0 { + __u8 cmd_code; + __u32 cda:24; + __u32 chainData:1; + __u32 chain:1; + __u32 sli:1; + __u32 skip:1; + __u32 pci:1; + __u32 ida:1; + __u32 suspend:1; + __u32 mida:1; + __u8 reserved; + __u16 count; +} __attribute__ ((packed, aligned(8))) Ccw0; + +/* channel command word (format 1) */ typedef struct ccw1 { __u8 cmd_code; __u8 flags; @@ -135,6 +188,10 @@ typedef struct ccw1 { __u32 cda; } __attribute__ ((packed, aligned(8))) Ccw1; +/* do_cio() CCW formats */ +#define CCW_FMT0 0x00 +#define CCW_FMT1 0x01 + #define CCW_FLAG_DC 0x80 #define CCW_FLAG_CC 0x40 #define CCW_FLAG_SLI 0x20 @@ -190,6 +247,9 @@ struct ciw { __u16 count; }; +#define CU_TYPE_VIRTIO 0x3832 +#define CU_TYPE_DASD_3990 0x3990 + /* * sense-id response buffer layout */ @@ -205,6 +265,64 @@ typedef struct senseid { struct ciw ciw[62]; } __attribute__ ((packed, aligned(4))) SenseId; +/* + * architected values for first sense byte - common_status. Bits 0-5 of this + * field are common to all device types. + */ +#define SNS_STAT0_CMD_REJECT 0x80 +#define SNS_STAT0_INTERVENTION_REQ 0x40 +#define SNS_STAT0_BUS_OUT_CHECK 0x20 +#define SNS_STAT0_EQUIPMENT_CHECK 0x10 +#define SNS_STAT0_DATA_CHECK 0x08 +#define SNS_STAT0_OVERRUN 0x04 +#define SNS_STAT0_INCOMPL_DOMAIN 0x01 + +/* ECKD DASD status[0] byte */ +#define SNS_STAT1_PERM_ERR 0x80 +#define SNS_STAT1_INV_TRACK_FORMAT 0x40 +#define SNS_STAT1_EOC 0x20 +#define SNS_STAT1_MESSAGE_TO_OPER 0x10 +#define SNS_STAT1_NO_REC_FOUND 0x08 +#define SNS_STAT1_FILE_PROTECTED 0x04 +#define SNS_STAT1_WRITE_INHIBITED 0x02 +#define SNS_STAT1_IMPRECISE_END 0x01 + +/* ECKD DASD status[1] byte */ +#define SNS_STAT2_REQ_INH_WRITE 0x80 +#define SNS_STAT2_CORRECTABLE 0x40 +#define SNS_STAT2_FIRST_LOG_ERR 0x20 +#define SNS_STAT2_ENV_DATA_PRESENT 0x10 +#define SNS_STAT2_IMPRECISE_END 0x04 + +/* ECKD DASD 24-byte Sense fmt_msg codes */ +#define SENSE24_FMT_PROG_SYS 0x0 +#define SENSE24_FMT_EQUIPMENT 0x2 +#define SENSE24_FMT_CONTROLLER 0x3 +#define SENSE24_FMT_MISC 0xF + +/* basic sense response buffer layout */ +typedef struct SenseDataEckdDasd { + uint8_t common_status; + uint8_t status[2]; + uint8_t res_count; + uint8_t phys_drive_id; + uint8_t low_cyl_addr; + uint8_t head_high_cyl_addr; + uint8_t fmt_msg; + uint64_t fmt_dependent_info[2]; + uint8_t reserved; + uint8_t program_action_code; + uint16_t config_info; + uint8_t mcode_hicyl; + uint8_t cyl_head_addr[3]; +} __attribute__ ((packed, aligned(4))) SenseDataEckdDasd; + +#define ECKD_SENSE24_GET_FMT(sd) (sd->fmt_msg & 0xF0 >> 4) +#define ECKD_SENSE24_GET_MSG(sd) (sd->fmt_msg & 0x0F) + +#define unit_check(irb) ((irb)->scsw.dstat & SCSW_DSTAT_UCHK) +#define iface_ctrl_check(irb) ((irb)->scsw.cstat & SCSW_CSTAT_ICCHK) + /* interruption response block */ typedef struct irb { struct scsw scsw; @@ -215,6 +333,9 @@ typedef struct irb { int enable_mss_facility(void); void enable_subchannel(SubChannelId schid); +uint16_t cu_type(SubChannelId schid); +void basic_sense(SubChannelId schid, void *sense_data, uint16_t data_size); +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt); /* * Some S390 specific IO instructions as inline diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index b39ee5d..11bce7d 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -52,6 +52,7 @@ typedef unsigned long long __u64; /* start.s */ void disabled_wait(void); void consume_sclp_int(void); +void consume_io_int(void); /* main.c */ void panic(const char *string); diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S index 5c22cb0..2b4ea4c 100644 --- a/pc-bios/s390-ccw/start.S +++ b/pc-bios/s390-ccw/start.S @@ -71,6 +71,26 @@ consume_sclp_int: larl %r1, enabled_wait_psw lpswe 0(%r1) +/* + * void consume_io_int(void) + * + * eats one I/O interrupt + */ + .globl consume_io_int +consume_io_int: + /* enable I/O interrupts in cr6 */ + stctg 6,6,0(15) + oi 4(15), 0xff + lctlg 6,6,0(15) + /* prepare i/o call handler */ + larl %r1, io_new_code + stg %r1, 0x1f8 + larl %r1, io_new_mask + mvc 0x1f0(8),0(%r1) + /* load enabled wait PSW */ + larl %r1, enabled_wait_psw + lpswe 0(%r1) + external_new_code: /* disable service interrupts in cr0 */ stctg %c0,%c0,0(%r15) @@ -78,6 +98,15 @@ external_new_code: lctlg %c0,%c0,0(%r15) br %r14 +io_new_code: + /* disable I/O interrupts in cr6 */ + stctg 6,6,0(15) + ni 4(15), 0x00 + lctlg 6,6,0(15) + br 14 + + + .align 8 disabled_wait_psw: .quad 0x0002000180000000,0x0000000000000000 @@ -85,3 +114,5 @@ enabled_wait_psw: .quad 0x0302000180000000,0x0000000000000000 external_new_mask: .quad 0x0000000180000000 +io_new_mask: + .quad 0x0000000180000000
Add struct for format-0 ccws. Support executing format-0 channel programs and waiting for their completion before continuing execution. This will be used for real dasd ipl. Add cu_type() to channel io library. This will be used to query control unit type which is used to determine if we are booting a virtio device or a real dasd device. Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com> --- pc-bios/s390-ccw/cio.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ pc-bios/s390-ccw/cio.h | 127 ++++++++++++++++++++++++++++++++++++++- pc-bios/s390-ccw/s390-ccw.h | 1 + pc-bios/s390-ccw/start.S | 31 ++++++++++ 4 files changed, 297 insertions(+), 3 deletions(-)