From nobody Sun Apr 12 00:55:20 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=linux.ibm.com ARC-Seal: i=1; a=rsa-sha256; t=1772593306; cv=none; d=zohomail.com; s=zohoarc; b=gpWBWqFSbYctjb6D4gSrFDQV8dUJ0wgvFNDSS72sJNMYwwizj+aHhCrJTEkNzHe3YaV4X37fXYtan9q0Xc5Hh9Gjam5JsdUYK6jTj0JKi/qyy6eNBUlIm7ew/7h4dyHGtbAJRWeM/D3P76fovyOxmxDupO/h/0RMnrKyKcp94mY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1772593306; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=vtKLwohNigpA/wf0JdtDnYWekMOC0ifaU6lgKFdxHPI=; b=LdLcXNy11cKr9u2JGCwxpRytGyb/IiO4h0F9CQpPgVS9PoCRPF4Bn9Y/Fa2J3Nazq/bPvlUwSyuyy+K+h3hZhKJYF80QDKJdZCd7vgnFtA7/2zg1zTh73KRW9dlMP/YQvlrjos5qdo0Qw8NJKZuytmrAZAYKnC5yLFhyggayA+Y= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1772593306196603.4525189001603; Tue, 3 Mar 2026 19:01:46 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vxcTt-0003Th-4U; Tue, 03 Mar 2026 22:01:01 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vxcSm-0002S7-3u; Tue, 03 Mar 2026 21:59:52 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vxcSj-0000YN-P9; Tue, 03 Mar 2026 21:59:51 -0500 Received: from pps.filterd (m0356517.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 623J7NH82198741; Wed, 4 Mar 2026 02:59:48 GMT Received: from ppma21.wdc07v.mail.ibm.com (5b.69.3da9.ip4.static.sl-reverse.com [169.61.105.91]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4cksjddq7n-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 04 Mar 2026 02:59:48 +0000 (GMT) Received: from pps.filterd (ppma21.wdc07v.mail.ibm.com [127.0.0.1]) by ppma21.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 623N5jTd016397; Wed, 4 Mar 2026 02:59:47 GMT Received: from smtprelay07.wdc07v.mail.ibm.com ([172.16.1.74]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4cmbpn50hk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 04 Mar 2026 02:59:47 +0000 Received: from smtpav05.wdc07v.mail.ibm.com (smtpav05.wdc07v.mail.ibm.com [10.39.53.232]) by smtprelay07.wdc07v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 6242xjAH4981258 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 4 Mar 2026 02:59:45 GMT Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A364E58053; Wed, 4 Mar 2026 02:59:45 +0000 (GMT) Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 78E9A58043; Wed, 4 Mar 2026 02:59:44 +0000 (GMT) Received: from t15.ibmuc.com (unknown [9.61.180.105]) by smtpav05.wdc07v.mail.ibm.com (Postfix) with ESMTP; Wed, 4 Mar 2026 02:59:44 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=vtKLwohNigpA/wf0J dtDnYWekMOC0ifaU6lgKFdxHPI=; b=qS6F1vOZmc/pJdVItVZVR4/NAotKdKXxG CdMS4cXUj2ZnerU3PTgrUkiKSxqrceJHQrmbX0yJMkLYY3PWV0CgpuBdbR8dBt/A pSCCQedPBXUHK+E2D5IkO5oEv9pHpvJ4Ilo7Y8TIFH51wu5st7EGILsGP/cmHUFO MTuF8pO7iD1krzwC23l1LRrPSfwcINwnh8uHEkdG/QlF88/1Hm9e/eT6mxQOwlok x006Vmaj185HICJtQ4ZYZ2y73tcp1Ts9jw+qhCM6Sc4NhwgddWEnkQBeFIdh/ocs fiv5Kdy0QXcTVjvcH4ficZcUF7Mxes3FPoHeNSNViu+qTt/Kab5dw== From: jrossi@linux.ibm.com To: qemu-devel@nongnu.org, qemu-s390x@nongnu.org, thuth@redhat.com, mst@redhat.com Cc: jjherne@linux.ibm.com, alifm@linux.ibm.com, farman@linux.ibm.com, mjrosato@linux.ibm.com, jrossi@linux.ibm.com, zycai@linux.ibm.com Subject: [PATCH v4 12/15] pc-bios/s390-ccw: Add support for virtio-blk-pci IPL Date: Tue, 3 Mar 2026 21:59:14 -0500 Message-ID: <20260304025917.2157032-13-jrossi@linux.ibm.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20260304025917.2157032-1-jrossi@linux.ibm.com> References: <20260304025917.2157032-1-jrossi@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Authority-Analysis: v=2.4 cv=M9BA6iws c=1 sm=1 tr=0 ts=69a7a024 cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=Yq5XynenixoA:10 a=VkNPw1HP01LnGYTKEx00:22 a=RnoormkPH1_aCDwRdu11:22 a=U7nrCbtTmkRpXpFmAIza:22 a=VnNF1IyMAAAA:8 a=t5V1psBHqKC9bszW1LEA:9 a=O8hF6Hzn-FEA:10 X-Proofpoint-ORIG-GUID: krkqKE5BMQ6Q38JnYRodUFk3lu1LRprM X-Proofpoint-GUID: krkqKE5BMQ6Q38JnYRodUFk3lu1LRprM X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMzA0MDAyMSBTYWx0ZWRfX/iSCt2QcAR8z eO+JxxagVM9EN8BNCZ1cE229AOsH9gWBE6LX0Rj2Hv3czBqfEWV+obcZ8ErfBdJ52KlJeqwupGL IP6GsPoPEBf2xzhiHKMSFd/pNMJVIJ6xdcgEyHzpUOo6jRnWxMVnwU0OREdazQ1Asa4N18JPe08 MT51ifCKt2ViY29dZLlcY//UdkysVpeq7OdDJxRr3zNfvektAyQtQb8B869jqEFjQZBbi/e30/Z o1xMy6M2eRmc+Q7AWAMRCxYQThVaQAkPmX7RvsQtUDtBhCWzSe01ofJDfxtV2dU1fa59cktWVMo +cXr6ypEZyRzg1ENMK0bRVG2Aj3r5inYc6UNHRSKOv6f2Er8yF2nv1XOYkeulGZafBZYXjQr3s2 ADABRhESVnu2qGc5L4dCNa/6J5sm7ueyNhCj+A3JOHLjB/22ja57mWSbmflo3b04DQH3PqrlRV1 LEo12BlwMIULFgZ0HcA== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-03-04_01,2026-03-03_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 spamscore=0 adultscore=0 malwarescore=0 bulkscore=0 lowpriorityscore=0 impostorscore=0 phishscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2602130000 definitions=main-2603040021 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=148.163.156.1; envelope-from=jrossi@linux.ibm.com; helo=mx0a-001b2d01.pphosted.com X-Spam_score_int: -11 X-Spam_score: -1.2 X-Spam_bar: - X-Spam_report: (-1.2 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.322, RCVD_IN_VALIDITY_SAFE_BLOCKED=1.141, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @ibm.com) X-ZM-MESSAGEID: 1772593307780139100 Content-Type: text/plain; charset="utf-8" From: Jared Rossi Add little-endian virt-queue configuration and support for virtio-blk-pci I= PL devices. Signed-off-by: Jared Rossi Reviewed-by: Eric Farman --- pc-bios/s390-ccw/main.c | 61 ++++++- pc-bios/s390-ccw/pci.h | 3 + pc-bios/s390-ccw/virtio-blkdev.c | 18 +++ pc-bios/s390-ccw/virtio-pci.c | 265 +++++++++++++++++++++++++++++++ pc-bios/s390-ccw/virtio-pci.h | 2 + pc-bios/s390-ccw/virtio.c | 54 ++++++- pc-bios/s390-ccw/virtio.h | 1 + 7 files changed, 399 insertions(+), 5 deletions(-) diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index c5ee575385..0e59ee3ea1 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -18,6 +18,8 @@ #include "virtio.h" #include "virtio-scsi.h" #include "dasd-ipl.h" +#include "clp.h" +#include "virtio-pci.h" =20 static SubChannelId blk_schid =3D { .one =3D 1 }; static char loadparm_str[LOADPARM_LEN + 1]; @@ -151,6 +153,21 @@ static bool find_subch(int dev_no) return false; } =20 +static bool find_fid(uint32_t fid) +{ + ClpFhListEntry entry; + VDev *vdev =3D virtio_get_device(); + + if (find_pci_function(fid, &entry)) { + return false; + } + + vdev->pci_fh =3D entry.fh; + virtio_pci_id2type(vdev, entry.device_id); + + return vdev->dev_type !=3D 0; +} + static void menu_setup(void) { if (memcmp(loadparm_str, LOADPARM_PROMPT, LOADPARM_LEN) =3D=3D 0) { @@ -239,6 +256,9 @@ static bool find_boot_device(void) blk_schid.ssid =3D iplb.scsi.ssid & 0x3; found =3D find_subch(iplb.scsi.devno); break; + case S390_IPL_TYPE_PCI: + found =3D find_fid(iplb.pci.fid); + break; default: puts("Unsupported IPLB"); } @@ -275,7 +295,7 @@ static int virtio_setup(void) return ret; } =20 -static void ipl_boot_device(void) +static void ipl_ccw_device(void) { switch (cutype) { case CU_TYPE_DASD_3990: @@ -289,7 +309,44 @@ static void ipl_boot_device(void) } break; default: - printf("Attempting to boot from unexpected device type 0x%X\n", cu= type); + printf("Cannot boot CCW device with cu type 0x%X\n", cutype); + } +} + +static void ipl_pci_device(void) +{ + VDev *vdev =3D virtio_get_device(); + vdev->is_cdrom =3D false; + vdev->scsi_device_selected =3D false; + + if (virtio_pci_setup_device()) { + return; + } + + switch (vdev->dev_type) { + case VIRTIO_ID_BLOCK: + if (virtio_setup() =3D=3D 0) { + zipl_load(); /* only return on error */ + virtio_reset(virtio_get_device()); + } + break; + default: + printf("Cannot boot PCI device type 0x%X\n", vdev->dev_type); + } +} + +static void ipl_boot_device(void) +{ + switch (virtio_get_device()->ipl_type) { + case S390_IPL_TYPE_QEMU_SCSI: + case S390_IPL_TYPE_CCW: + ipl_ccw_device(); + break; + case S390_IPL_TYPE_PCI: + ipl_pci_device(); + break; + default: + puts("Unrecognized IPL type!"); } } =20 diff --git a/pc-bios/s390-ccw/pci.h b/pc-bios/s390-ccw/pci.h index 40a0bf9dcb..63825dd21c 100644 --- a/pc-bios/s390-ccw/pci.h +++ b/pc-bios/s390-ccw/pci.h @@ -29,8 +29,11 @@ union register_pair { #define PCIST_ENABLED 0x1 =20 #define PCI_CFGBAR 0xF /* Base Address Register for config sp= ace */ +#define PCI_CMD_REG 0x4 /* Offset of command register */ #define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list ent= ry */ =20 +#define PCI_BUS_MASTER_MASK 0x0020 /* LE bit 3 of 16 bit register */ + int pci_write(uint32_t fhandle, uint64_t offset, uint8_t pcias, uint64_t d= ata, uint8_t len); int pci_read(uint32_t fhandle, uint64_t offset, uint8_t pcias, void *buf, diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blk= dev.c index 9722b6970f..98b6cec3a0 100644 --- a/pc-bios/s390-ccw/virtio-blkdev.c +++ b/pc-bios/s390-ccw/virtio-blkdev.c @@ -13,10 +13,22 @@ #include "virtio.h" #include "virtio-scsi.h" #include "virtio-ccw.h" +#include "virtio-pci.h" +#include "bswap.h" =20 #define VIRTIO_BLK_F_GEOMETRY (1 << 4) #define VIRTIO_BLK_F_BLK_SIZE (1 << 6) =20 +/* + * Format header for little endian IPL + */ +static void fmt_blk_hdr_le(VirtioBlkOuthdr *hdr) +{ + hdr->type =3D bswap32(hdr->type); + hdr->ioprio =3D bswap32(hdr->ioprio); + hdr->sector =3D bswap64(hdr->sector); +} + static int virtio_blk_read_many(VDev *vdev, unsigned long sector, void *lo= ad_addr, int sec_num) { @@ -29,6 +41,10 @@ static int virtio_blk_read_many(VDev *vdev, unsigned lon= g sector, void *load_add out_hdr.ioprio =3D 99; out_hdr.sector =3D virtio_sector_adjust(sector); =20 + if (!be_ipl()) { + fmt_blk_hdr_le(&out_hdr); + } + vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT); =20 /* This is where we want to receive data */ @@ -240,6 +256,8 @@ int virtio_blk_setup_device(VDev *vdev) case S390_IPL_TYPE_QEMU_SCSI: case S390_IPL_TYPE_CCW: return virtio_ccw_setup(vdev); + case S390_IPL_TYPE_PCI: + return virtio_pci_setup(vdev); default: return 1; } diff --git a/pc-bios/s390-ccw/virtio-pci.c b/pc-bios/s390-ccw/virtio-pci.c index 2cfb84bf66..beb97961d0 100644 --- a/pc-bios/s390-ccw/virtio-pci.c +++ b/pc-bios/s390-ccw/virtio-pci.c @@ -165,3 +165,268 @@ int vpci_read_flex(uint64_t offset, uint8_t pcias, vo= id *buf, int len) =20 return 0; } + +static int vpci_set_selected_vq(uint16_t queue_num) +{ + return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_SELECT, c_cap.ba= r, queue_num); +} + +static int vpci_set_queue_enable(uint16_t enabled) +{ + return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_ENABLE, c_cap.ba= r, enabled); +} + +static int set_pci_vq_addr(uint64_t config_off, void *addr) +{ + return vpci_bswap64_write(c_cap.off + config_off, c_cap.bar, (uint64_t= ) addr); +} + +static int virtio_pci_get_blk_config(void) +{ + VirtioBlkConfig *cfg =3D &virtio_get_device()->config.blk; + int rc =3D vpci_read_flex(d_cap.off, d_cap.bar, cfg, sizeof(VirtioBlkC= onfig)); + + /* single byte fields are not touched */ + cfg->capacity =3D bswap64(cfg->capacity); + cfg->size_max =3D bswap32(cfg->size_max); + cfg->seg_max =3D bswap32(cfg->seg_max); + + cfg->geometry.cylinders =3D bswap16(cfg->geometry.cylinders); + + cfg->blk_size =3D bswap32(cfg->blk_size); + cfg->min_io_size =3D bswap16(cfg->min_io_size); + cfg->opt_io_size =3D bswap32(cfg->opt_io_size); + + return rc; +} + +static int virtio_pci_negotiate(void) +{ + int i, rc; + VDev *vdev =3D virtio_get_device(); + struct VirtioFeatureDesc { + uint32_t features; + uint8_t index; + } __attribute__((packed)) feats; + + for (i =3D 0; i < ARRAY_SIZE(vdev->guest_features); i++) { + feats.features =3D 0; + feats.index =3D i; + + rc =3D vpci_bswap32_write(c_cap.off + VPCI_C_OFFSET_DFSELECT, c_ca= p.bar, + feats.index); + rc |=3D vpci_read_flex(c_cap.off + VPCI_C_OFFSET_DF, c_cap.bar, &f= eats, 4); + + vdev->guest_features[i] &=3D bswap32(feats.features); + feats.features =3D vdev->guest_features[i]; + + + rc |=3D vpci_bswap32_write(c_cap.off + VPCI_C_OFFSET_GFSELECT, c_c= ap.bar, + feats.index); + rc |=3D vpci_bswap32_write(c_cap.off + VPCI_C_OFFSET_GF, c_cap.bar, + feats.features); + } + + return rc; +} + +/* + * Find the position of the capability config within PCI configuration + * space for a given cfg type. Return the position if found, otherwise 0. + */ +static uint8_t virtio_pci_find_cap_pos(uint8_t cfg_type) +{ + uint8_t next, cfg; + int rc; + + rc =3D vpci_read_byte(PCI_CAPABILITY_LIST, PCI_CFGBAR, &next); + rc |=3D vpci_read_byte(next + 3, PCI_CFGBAR, &cfg); + + while (!rc && (cfg !=3D cfg_type) && next) { + rc =3D vpci_read_byte(next + 1, PCI_CFGBAR, &next); + rc |=3D vpci_read_byte(next + 3, PCI_CFGBAR, &cfg); + } + + return rc ? 0 : next; +} + +/* + * Read PCI configuration space to find the offset of the Common, Device, = and + * Notification memory regions within the modern memory space. + * Returns 0 if success, 1 if a capability could not be located, or a + * negative RC if the configuration read failed. + */ +static int virtio_pci_read_pci_cap_config(void) +{ + uint8_t pos; + int rc; + + /* Common capabilities */ + pos =3D virtio_pci_find_cap_pos(VPCI_CAP_COMMON_CFG); + if (!pos) { + puts("Failed to locate PCI common configuration"); + return 1; + } + + rc =3D vpci_read_byte(pos + VPCI_CAP_BAR, PCI_CFGBAR, &c_cap.bar); + if (rc || vpci_read_bswap32(pos + VPCI_CAP_OFFSET, PCI_CFGBAR, &c_cap.= off)) { + puts("Failed to read PCI common configuration"); + return -EIO; + } + + /* Device capabilities */ + pos =3D virtio_pci_find_cap_pos(VPCI_CAP_DEVICE_CFG); + if (!pos) { + puts("Failed to locate PCI device configuration"); + return 1; + } + + rc =3D vpci_read_byte(pos + VPCI_CAP_BAR, PCI_CFGBAR, &d_cap.bar); + if (rc || vpci_read_bswap32(pos + VPCI_CAP_OFFSET, PCI_CFGBAR, &d_cap.= off)) { + puts("Failed to read PCI device configuration"); + return -EIO; + } + + /* Notification capabilities */ + pos =3D virtio_pci_find_cap_pos(VPCI_CAP_NOTIFY_CFG); + if (!pos) { + puts("Failed to locate PCI notification configuration"); + return 1; + } + + rc =3D vpci_read_byte(pos + VPCI_CAP_BAR, PCI_CFGBAR, &n_cap.bar); + if (rc || vpci_read_bswap32(pos + VPCI_CAP_OFFSET, PCI_CFGBAR, &n_cap.= off)) { + puts("Failed to read PCI notification configuration"); + return -EIO; + } + + rc =3D vpci_read_bswap32(pos + VPCI_N_CAP_MULT, PCI_CFGBAR, ¬ify_mu= lt); + if (rc || vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.ba= r, + &q_notify_offset)) { + puts("Failed to read notification queue configuration"); + return -EIO; + } + + return 0; +} + +static int enable_pci_bus_master(void) { + uint16_t cmd_reg; + + if (vpci_read_bswap16(PCI_CMD_REG, PCI_CFGBAR, &cmd_reg)) { + puts("Failed to read PCI command register"); + return -EIO; + } + + if (vpci_bswap16_write(PCI_CMD_REG, PCI_CFGBAR, cmd_reg | PCI_BUS_MAST= ER_MASK)) { + puts("Failed to enable PCI bus mastering"); + return -EIO; + } + + return 0; +} + +int virtio_pci_setup(VDev *vdev) +{ + VRing *vr; + int rc; + uint8_t status; + uint16_t vq_size; + int i =3D 0; + + vdev->guessed_disk_nature =3D VIRTIO_GDN_NONE; + vdev->cmd_vr_idx =3D 0; + + if (virtio_pci_read_pci_cap_config()) { + puts("Invalid virtio PCI capabilities"); + return -EIO; + } + + if (enable_pci_bus_master()) { + return -EIO; + } + + if (virtio_reset(vdev)) { + return -EIO; + } + + status =3D VIRTIO_CONFIG_S_ACKNOWLEDGE; + if (virtio_pci_set_status(status)) { + puts("Virtio-pci device Failed to ACKNOWLEDGE"); + return -EIO; + } + + vdev->guest_features[1] =3D VIRTIO_F_VERSION_1; + if (virtio_pci_negotiate()) { + panic("Virtio feature negotation failed!"); + } + + switch (vdev->dev_type) { + case VIRTIO_ID_BLOCK: + vdev->nr_vqs =3D 1; + vdev->cmd_vr_idx =3D 0; + virtio_pci_get_blk_config(); + break; + default: + puts("Unsupported virtio device"); + return -ENODEV; + } + + status |=3D VIRTIO_CONFIG_S_DRIVER; + rc =3D virtio_pci_set_status(status); + if (rc) { + puts("Set status failed"); + return -EIO; + } + + if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) { + puts("Failed to read virt-queue configuration"); + return -EIO; + } + + /* Configure virt-queues for pci */ + for (i =3D 0; i < vdev->nr_vqs; i++) { + VqInfo info =3D { + .queue =3D (unsigned long long) virtio_get_ring_area(i), + .align =3D KVM_S390_VIRTIO_RING_ALIGN, + .index =3D i, + .num =3D vq_size, + }; + + vr =3D &vdev->vrings[i]; + vring_init(vr, &info); + + if (vpci_set_selected_vq(vr->id)) { + puts("Failed to set selected virt-queue"); + return -EIO; + } + + rc =3D set_pci_vq_addr(VPCI_C_OFFSET_Q_DESCLO, vr->desc); + rc |=3D set_pci_vq_addr(VPCI_C_OFFSET_Q_AVAILLO, vr->avail); + rc |=3D set_pci_vq_addr(VPCI_C_OFFSET_Q_USEDLO, vr->used); + if (rc) { + puts("Failed to configure virt-queue address"); + return -EIO; + } + + if (vpci_set_queue_enable(true)) { + puts("Failed to set virt-queue enabled"); + return -EIO; + } + } + + status |=3D VIRTIO_CONFIG_S_FEATURES_OK | VIRTIO_CONFIG_S_DRIVER_OK; + return virtio_pci_set_status(status); +} + +int virtio_pci_setup_device(void) +{ + VDev *vdev =3D virtio_get_device(); + + if (enable_pci_function(&vdev->pci_fh)) { + puts("Failed to enable PCI function"); + return -ENODEV; + } + + return 0; +} diff --git a/pc-bios/s390-ccw/virtio-pci.h b/pc-bios/s390-ccw/virtio-pci.h index 54c524f698..90d07cb9a7 100644 --- a/pc-bios/s390-ccw/virtio-pci.h +++ b/pc-bios/s390-ccw/virtio-pci.h @@ -65,6 +65,8 @@ typedef struct VirtioPciCap VirtioPciCap; void virtio_pci_id2type(VDev *vdev, uint16_t device_id); int virtio_pci_reset(VDev *vdev); long virtio_pci_notify(int vq_id); +int virtio_pci_setup(VDev *vdev); +int virtio_pci_setup_device(void); =20 int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len); int vpci_read_bswap64(uint64_t offset, uint8_t pcias, uint64_t *buf); diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index 956b34ff33..390b55c7b9 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -17,6 +17,7 @@ #include "virtio.h" #include "virtio-scsi.h" #include "virtio-ccw.h" +#include "virtio-pci.h" #include "bswap.h" #include "helper.h" #include "s390-time.h" @@ -96,7 +97,7 @@ void vring_init(VRing *vr, VqInfo *info) vr->avail->idx =3D 0; =20 /* We're running with interrupts off anyways, so don't bother */ - vr->used->flags =3D VRING_USED_F_NO_NOTIFY; + vr->used->flags =3D be_ipl() ? VRING_USED_F_NO_NOTIFY : bswap16(VRING_= USED_F_NO_NOTIFY); vr->used->idx =3D 0; vr->used_idx =3D 0; vr->next_idx =3D 0; @@ -112,6 +113,8 @@ bool vring_notify(VRing *vr) case S390_IPL_TYPE_CCW: vr->cookie =3D virtio_ccw_notify(vdev.schid, vr->id, vr->cookie); break; + case S390_IPL_TYPE_PCI: + vr->cookie =3D virtio_pci_notify(vr->id); default: return 1; } @@ -119,11 +122,45 @@ bool vring_notify(VRing *vr) return vr->cookie >=3D 0; } =20 +/* + * Get endienness of the IPL type + * Return true for s390x native big-endian + */ +bool be_ipl(void) +{ + switch (virtio_get_device()->ipl_type) { + case S390_IPL_TYPE_QEMU_SCSI: + case S390_IPL_TYPE_CCW: + return true; + case S390_IPL_TYPE_PCI: + return false; + default: + return true; + } +} + +/* + * Format the virtio ring descriptor endianness + * Return the available index increment in the appropriate endianness + */ +static void vr_bswap_descriptor(VRingDesc *desc) +{ + desc->addr =3D bswap64(desc->addr); + desc->len =3D bswap32(desc->len); + desc->flags =3D bswap16(desc->flags); + desc->next =3D bswap16(desc->next); +} + void vring_send_buf(VRing *vr, void *p, int len, int flags) { + if (!be_ipl()) { + vr->avail->idx =3D bswap16(vr->avail->idx); + } + /* For follow-up chains we need to keep the first entry point */ if (!(flags & VRING_HIDDEN_IS_CHAIN)) { - vr->avail->ring[vr->avail->idx % vr->num] =3D vr->next_idx; + vr->avail->ring[vr->avail->idx % vr->num] =3D be_ipl() ? vr->next_= idx : + bswap16(vr-= >next_idx); } =20 vr->desc[vr->next_idx].addr =3D (unsigned long)p; @@ -131,12 +168,21 @@ void vring_send_buf(VRing *vr, void *p, int len, int = flags) vr->desc[vr->next_idx].flags =3D flags & ~VRING_HIDDEN_IS_CHAIN; vr->desc[vr->next_idx].next =3D vr->next_idx; vr->desc[vr->next_idx].next++; + + if (!be_ipl()) { + vr_bswap_descriptor(&vr->desc[vr->next_idx]); + } + vr->next_idx++; =20 /* Chains only have a single ID */ if (!(flags & VRING_DESC_F_NEXT)) { vr->avail->idx++; } + + if (!be_ipl()) { + vr->avail->idx =3D bswap16(vr->avail->idx); + } } =20 int vr_poll(VRing *vr) @@ -147,7 +193,7 @@ int vr_poll(VRing *vr) return 0; } =20 - vr->used_idx =3D vr->used->idx; + vr->used_idx =3D vr->used->idx; /* Endianness is preserved */ vr->next_idx =3D 0; vr->desc[0].len =3D 0; vr->desc[0].flags =3D 0; @@ -187,6 +233,8 @@ int virtio_reset(VDev *vdev) case S390_IPL_TYPE_QEMU_SCSI: case S390_IPL_TYPE_CCW: return virtio_ccw_reset(vdev); + case S390_IPL_TYPE_PCI: + return virtio_pci_reset(vdev); default: return -1; } diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h index 0e7dbdb64c..18083b64cb 100644 --- a/pc-bios/s390-ccw/virtio.h +++ b/pc-bios/s390-ccw/virtio.h @@ -275,6 +275,7 @@ struct VirtioCmd { }; typedef struct VirtioCmd VirtioCmd; =20 +bool be_ipl(void); void vring_init(VRing *vr, VqInfo *info); bool virtio_is_supported(VDev *vdev); bool vring_notify(VRing *vr); --=20 2.52.0