From patchwork Tue Jan 26 23:21:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laszlo Ersek X-Patchwork-Id: 60548 Delivered-To: patch@linaro.org Received: by 10.112.130.2 with SMTP id oa2csp2262949lbb; Tue, 26 Jan 2016 15:22:02 -0800 (PST) X-Received: by 10.140.108.8 with SMTP id i8mr32218986qgf.83.1453850522400; Tue, 26 Jan 2016 15:22:02 -0800 (PST) Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id 134si3215606qhz.5.2016.01.26.15.22.02 for (version=TLS1 cipher=AES128-SHA bits=128/128); Tue, 26 Jan 2016 15:22:02 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org Received: from localhost ([::1]:47335 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aOCvx-0002hd-SG for patch@linaro.org; Tue, 26 Jan 2016 18:22:01 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38916) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aOCva-0002Ql-Fl for qemu-devel@nongnu.org; Tue, 26 Jan 2016 18:21:39 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aOCvY-0003jT-T4 for qemu-devel@nongnu.org; Tue, 26 Jan 2016 18:21:38 -0500 Received: from mx1.redhat.com ([209.132.183.28]:34978) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aOCvT-0003im-S6; Tue, 26 Jan 2016 18:21:32 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (Postfix) with ESMTPS id CCE61C60E4; Tue, 26 Jan 2016 23:21:30 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-113-150.phx2.redhat.com [10.3.113.150]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0QNLQhk015795; Tue, 26 Jan 2016 18:21:27 -0500 From: Laszlo Ersek To: qemu-devel@nongnu.org Date: Wed, 27 Jan 2016 00:21:23 +0100 Message-Id: <1453850483-27511-1-git-send-email-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Kevin Wolf , Feng Tian , "open list:nvme" , Keith Busch , Gonglei , Vladislav Vovchenko , Gerd Hoffmann , Kevin O'Connor Subject: [Qemu-devel] [PATCH] nvme: generate OpenFirmware device path in the "bootorder" fw_cfg file X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.org Background on QEMU boot indices ------------------------------- Normally, the "bootindex" property is configured for bootable devices with: DEVICE_instance_init() device_add_bootindex_property(..., "bootindex", ...) object_property_add(..., device_get_bootindex, device_set_bootindex, ...) and when the bootindex is set on the QEMU command line, with -device DEVICE,...,bootindex=N the setter that was configured above is invoked: device_set_bootindex() /* parse boot index */ visit_type_int32() /* verify unicity */ check_boot_index() /* store parsed boot index */ ... /* insert device path to boot order */ add_boot_device_path() In the last step, add_boot_device_path() ensures that an OpenFirmware device path will show up in the "bootorder" fw_cfg file, at a position corresponding to the device's boot index. Thus guest firmware (SeaBIOS and OVMF) can try to boot off the device with the right priority. NVMe boot index --------------- In QEMU commit 33739c712982, nvma: ide: add bootindex to qom property the following generic setters / getters: - device_set_bootindex() - device_get_bootindex() were open-coded for NVMe, under the names - nvme_set_bootindex() - nvme_get_bootindex() Plus nvme_instance_init() was added to configure the "bootindex" property manually, designating the open-coded getter & setter, rather than calling device_add_bootindex_property(). Crucially, nvme_set_bootindex() avoided the final add_boot_device_path() call. This fact is spelled out in the message of commit 33739c712982, and it was presumably the entire reason for all of the code duplication. Now, Vladislav filed an RFE for OVMF ; OVMF should boot off NVMe devices. It is simple to build edk2's existent NvmExpressDxe driver into OVMF, but the boot order matching logic in OVMF can only handle NVMe if the "bootorder" fw_cfg file includes such devices. Therefore this patch converts the NVMe device model to device_set_bootindex() all the way. Device paths ------------ device_set_bootindex() accepts an optional parameter called "suffix". When present, it is expected to take the form of an OpenFirmware device path node, and it gets appended as last node to the otherwise auto-generated OFW path. For NVMe, the auto-generated part is /pci@i0cf8/pci8086,5845@6[,1] ^ ^ ^ ^ | | PCI slot and (present when nonzero) | | function of the NVMe controller, both hex | "driver name" component, built from PCI vendor & device IDs PCI root at system bus port, PIO to which here we append the suffix /namespace@1,0 ^ ^ | big endian (MSB at lowest address) numeric interpretation | of the 64-bit IEEE Extended Unique Identifier, aka EUI-64, | hex 32-bit NVMe namespace identifier, aka NSID, hex resulting in the OFW device path /pci@i0cf8/pci8086,5845@6[,1]/namespace@1,0 The reason for including the NSID and the EUI-64 is that an NVMe device can in theory produce several different namespaces (distinguished by NSID). Additionally, each of those may (optionally) have an EUI-64 value. For now, QEMU only provides namespace 1. Furthermore, QEMU doesn't even represent the EUI-64 as a standalone field; it is embedded (and left unused) inside the "NvmeIdNs.res30" array, at the last eight bytes. (Which is fine, since EUI-64 can be left zero-filled if unsupported by the device.) Based on the above, we set the "unit address" part of the last ("namespace") node to fixed "1,0". OVMF will then map the above OFW device path to the following UEFI device path fragment, for boot order processing: PciRoot(0x0)/Pci(0x6,0x1)/NVMe(0x1,00-00-00-00-00-00-00-00) ^ ^ ^ ^ ^ ^ | | | | | octets of the EUI-64 in address order | | | | NSID | | | NVMe namespace messaging device path node | PCI slot and function PCI root bridge Cc: Keith Busch (supporter:nvme) Cc: Kevin Wolf (supporter:Block layer core) Cc: qemu-block@nongnu.org (open list:nvme) Cc: Gonglei Cc: Vladislav Vovchenko Cc: Feng Tian Cc: Gerd Hoffmann Cc: Kevin O'Connor Signed-off-by: Laszlo Ersek --- hw/block/nvme.c | 42 +++++------------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) -- 1.8.3.1 diff --git a/hw/block/nvme.c b/hw/block/nvme.c index a5fedb2..c68b625 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -916,45 +916,13 @@ static void nvme_class_init(ObjectClass *oc, void *data) dc->vmsd = &nvme_vmstate; } -static void nvme_get_bootindex(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - NvmeCtrl *s = NVME(obj); - - visit_type_int32(v, &s->conf.bootindex, name, errp); -} - -static void nvme_set_bootindex(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - NvmeCtrl *s = NVME(obj); - int32_t boot_index; - Error *local_err = NULL; - - visit_type_int32(v, &boot_index, name, &local_err); - if (local_err) { - goto out; - } - /* check whether bootindex is present in fw_boot_order list */ - check_boot_index(boot_index, &local_err); - if (local_err) { - goto out; - } - /* change bootindex to a new one */ - s->conf.bootindex = boot_index; - -out: - if (local_err) { - error_propagate(errp, local_err); - } -} - static void nvme_instance_init(Object *obj) { - object_property_add(obj, "bootindex", "int32", - nvme_get_bootindex, - nvme_set_bootindex, NULL, NULL, NULL); - object_property_set_int(obj, -1, "bootindex", NULL); + NvmeCtrl *s = NVME(obj); + + device_add_bootindex_property(obj, &s->conf.bootindex, + "bootindex", "/namespace@1,0", + DEVICE(obj), &error_abort); } static const TypeInfo nvme_info = {