From nobody Sat Apr 11 23:03:22 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=1773016661; cv=none; d=zohomail.com; s=zohoarc; b=OUpGQ3LKPMSPrRpkHNZ/GJeWWggt/Ay1QhKruo0+K2n6U7gmMG3qrf6INjW+ylF8RfpAayZCibaBSGz1W5JFi0V6nrv4yhF9LhVzXozHVyfeI+tYu0eDSl7wvFLZWqsEiOM2IOOwZ82WT+pxzRJTZxtsz2IqDTuvMhfsy4K7dX8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773016661; 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=Tt860g4vwSH2tC13Nf/qvxSF1eTCcQuOcKOEoiz9YoQ=; b=njgyDHCucrB+1GXWncBiDrGOOgY0eAmRHDX3xRxgxVWPKobjaIqXr2NIpbhezf9A2EsHBjeuZQQzaXBxgSDQBJOIjgFDmup7XJLCL7K6KM43i/qi7BcK+m0G1LjJX72+yptN7IeNtgJCb+gw30VYlfrs9y+t55hT9ZmCQKtDLeY= 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 1773016661461480.67490922397815; Sun, 8 Mar 2026 17:37:41 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vzObx-0006TP-EU; Sun, 08 Mar 2026 20:36:41 -0400 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 1vzObr-0006Pd-As; Sun, 08 Mar 2026 20:36:35 -0400 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 1vzObo-0001gU-Vd; Sun, 08 Mar 2026 20:36:35 -0400 Received: from pps.filterd (m0353729.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 628Ns1kn1681720; Mon, 9 Mar 2026 00:36:31 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 4crcuy4kdf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 09 Mar 2026 00:36:31 +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 628LjP3g015638; Mon, 9 Mar 2026 00:36:30 GMT Received: from smtprelay07.dal12v.mail.ibm.com ([172.16.1.9]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4crybn2yv3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 09 Mar 2026 00:36:30 +0000 Received: from smtpav04.wdc07v.mail.ibm.com (smtpav04.wdc07v.mail.ibm.com [10.39.53.231]) by smtprelay07.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 6290aS7X23200350 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 9 Mar 2026 00:36:29 GMT Received: from smtpav04.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8B83758052; Mon, 9 Mar 2026 00:36:28 +0000 (GMT) Received: from smtpav04.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 6D6ED58050; Mon, 9 Mar 2026 00:36:27 +0000 (GMT) Received: from t15.ibmuc.com (unknown [9.61.180.105]) by smtpav04.wdc07v.mail.ibm.com (Postfix) with ESMTP; Mon, 9 Mar 2026 00:36:27 +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=Tt860g4vwSH2tC13N f/qvxSF1eTCcQuOcKOEoiz9YoQ=; b=KzcBDgMVMI+shAE7uUn7oo3TZzSzG4+QB HzhkQhRF7FpLgahbKu/nkGTubOfcq61WTv5lSA07gNDVustfxj+ZrIfbHlMGarUe qXAEBqt4EOoy9wbKUxV6L7iSF5j9TnXTDMhEjgUtrAytOUWkznqJhRvzayM3ItgW LhrJFowZRbkCBUK0l4rjWqtLlYQdlLdsrNfg014JHroZmW2YnMWc6urzMJ/5vbPU tWI9mXacFVoJiMuMu+W0tNIVOFJy6bP9Yhb3DmpUdpG8n+sEOoTiaazXHHHL8b/t hWA/hb5zS2h7zXkXllanYjcAbLq1GWZ8+AI7MfbWlhGqjFmsK8ohQ== 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 v5 12/15] pc-bios/s390-ccw: Add support for virtio-blk-pci IPL Date: Sun, 8 Mar 2026 20:35:58 -0400 Message-ID: <20260309003601.242634-13-jrossi@linux.ibm.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20260309003601.242634-1-jrossi@linux.ibm.com> References: <20260309003601.242634-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=EK4LElZC c=1 sm=1 tr=0 ts=69ae160f cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=Yq5XynenixoA:10 a=VkNPw1HP01LnGYTKEx00:22 a=RnoormkPH1_aCDwRdu11:22 a=uAbxVGIbfxUO_5tXvNgY:22 a=VnNF1IyMAAAA:8 a=t5V1psBHqKC9bszW1LEA:9 a=O8hF6Hzn-FEA:10 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMzA5MDAwMyBTYWx0ZWRfX0V4IEiiPAtnY BvQTkdwCh4h/3CsL7jNJ+9NxVOpbslEqLyNbYOse2N1d1wSpQS3zrDf+bIWQw8h+Q+pnYWmhfs2 Hmgz6TtE+xaFnfMSQe82Eq5BdXz2j9JKA7fPqiCxeM8mGBYb6SsuN5reFCnOrzqIOxrLc6MURmH Q7KSFDP0QJGWQLxuOoiSeY129hYGb103ADF0P7Q58Khad7gnMTUWsn3xAOR2P7H2LtJPEoidTbE QlDDCdCbsrSzvt0oifih1UNGb6nSRACCPKtvQzTM+DhwgFZDeJ84ZlQG6m0EJ2gEfp+Q+ZaSvKD P97lBjBA/20J9tmZnPxU5dOHB1aQGRJ/2YNMIESgWglmVdGCcy9qfrKCV33ebN6vFjxbTYUlA9K rYxJgmwn0CeV3T4s7Hq4csOxqPbEyLLgvoX9kNTJiRe0z36d+DY+dXRkN8Vmg9VO9/N5Oqso4iF N1GN17cVDlg1Q6GNnNg== X-Proofpoint-GUID: rT_aoT-9SVOY12xcvsMAI-hW_mEXxFa0 X-Proofpoint-ORIG-GUID: rT_aoT-9SVOY12xcvsMAI-hW_mEXxFa0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-03-08_07,2026-03-06_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 lowpriorityscore=0 spamscore=0 suspectscore=0 clxscore=1015 bulkscore=0 impostorscore=0 priorityscore=1501 malwarescore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2602130000 definitions=main-2603090003 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: -9 X-Spam_score: -1.0 X-Spam_bar: - X-Spam_report: (-1.0 / 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.819, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.903, 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: 1773016662506154100 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. Reviewed-by: Eric Farman Signed-off-by: Jared Rossi --- 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 32154c5db8..26287cfd81 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(VDev *vdev) { if (memcmp(loadparm_str, LOADPARM_PROMPT, LOADPARM_LEN) =3D=3D 0) { @@ -240,6 +257,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"); } @@ -276,7 +296,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: @@ -290,7 +310,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 f6ce7ec766..bdb7eca0b7 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 1ef64675f4..d32a4830ca 100644 --- a/pc-bios/s390-ccw/virtio.h +++ b/pc-bios/s390-ccw/virtio.h @@ -273,6 +273,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