From patchwork Thu Mar 17 08:32:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiao Guangrong X-Patchwork-Id: 8608061 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E00749F44D for ; Thu, 17 Mar 2016 08:34:56 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 192AD2026F for ; Thu, 17 Mar 2016 08:34:56 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 29F782020F for ; Thu, 17 Mar 2016 08:34:55 +0000 (UTC) Received: from localhost ([::1]:33314 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1agTOQ-0000wc-Ez for patchwork-qemu-devel@patchwork.kernel.org; Thu, 17 Mar 2016 04:34:54 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37404) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1agTMd-0005s5-PH for qemu-devel@nongnu.org; Thu, 17 Mar 2016 04:33:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1agTMb-0001Uk-0A for qemu-devel@nongnu.org; Thu, 17 Mar 2016 04:33:03 -0400 Received: from mga14.intel.com ([192.55.52.115]:49128) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1agTMa-0001Sg-MO for qemu-devel@nongnu.org; Thu, 17 Mar 2016 04:33:00 -0400 Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP; 17 Mar 2016 01:33:00 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.24,349,1455004800"; d="scan'208";a="671127383" Received: from xiaoreal1.sh.intel.com (HELO xiaoreal1.sh.intel.com.sh.intel.com) ([10.239.48.79]) by FMSMGA003.fm.intel.com with ESMTP; 17 Mar 2016 01:32:57 -0700 From: Xiao Guangrong To: pbonzini@redhat.com, imammedo@redhat.com Date: Thu, 17 Mar 2016 16:32:50 +0800 Message-Id: <1458203581-59143-5-git-send-email-guangrong.xiao@linux.intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1458203581-59143-1-git-send-email-guangrong.xiao@linux.intel.com> References: <1458203581-59143-1-git-send-email-guangrong.xiao@linux.intel.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 192.55.52.115 Cc: Xiao Guangrong , ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com, gleb@kernel.org, mtosatti@redhat.com, qemu-devel@nongnu.org, stefanha@redhat.com, dan.j.williams@intel.com, rth@twiddle.net Subject: [Qemu-devel] [PATCH 04/15] nvdimm: support nvdimm label 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+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Introduce a parameter, 'reserve-label', which is false on default. If it is set, we will reserve 128K memory which is the minimum namespace label size required by NVDIMM Namespace Spec at the end of backend memory as NVDIMM label area Two callbacks, read_label_data() and write_label_data(), are used to operate the label area Signed-off-by: Xiao Guangrong --- hw/mem/nvdimm.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/mem/nvdimm.h | 61 ++++++++++++++++++++++++++++++- 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index 0a602f2..921e6a1 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -25,18 +25,113 @@ #include "qemu/osdep.h" #include "hw/mem/nvdimm.h" +static bool nvdimm_get_reserve_label(Object *obj, Error **errp) +{ + NVDIMMDevice *nvdimm = NVDIMM(obj); + + return nvdimm->reserve_label; +} + +static void nvdimm_set_reserve_label(Object *obj, bool value, Error **errp) +{ + NVDIMMDevice *nvdimm = NVDIMM(obj); + + nvdimm->reserve_label = value; +} + +static void nvdimm_init(Object *obj) +{ + object_property_add_bool(obj, "reserve-label", nvdimm_get_reserve_label, + nvdimm_set_reserve_label, NULL); +} + +static MemoryRegion *nvdimm_get_memory_region(PCDIMMDevice *dimm) +{ + NVDIMMDevice *nvdimm = NVDIMM(dimm); + + return &nvdimm->nvdimm_mr; +} + +static void nvdimm_realize(PCDIMMDevice *dimm, Error **errp) +{ + MemoryRegion *mr = host_memory_backend_get_memory(dimm->hostmem, errp); + NVDIMMDevice *nvdimm = NVDIMM(dimm); + uint64_t size = memory_region_size(mr); + + nvdimm->label_size = nvdimm->reserve_label ? MIN_NAMESPACE_LABEL_SIZE : 0; + + if (size <= nvdimm->label_size) { + HostMemoryBackend *hostmem = dimm->hostmem; + char *path = object_get_canonical_path_component(OBJECT(hostmem)); + + error_setg(errp, "the size of memdev %s (0x%" PRIx64 ") is too" + "small to contain nvdimm label (0x%" PRIx64 ")", + path, memory_region_size(mr), nvdimm->label_size); + return; + } + + size -= nvdimm->label_size; + memory_region_init_alias(&nvdimm->nvdimm_mr, OBJECT(dimm), + "nvdimm-memory", mr, 0, size); + nvdimm->nvdimm_mr.align = memory_region_get_alignment(mr); + + nvdimm->label_data = memory_region_get_ram_ptr(mr) + size; +} + +static void nvdimm_assert_rw_label_data(NVDIMMDevice *nvdimm, uint64_t size, + uint64_t offset) +{ + assert(nvdimm->reserve_label && + (nvdimm->label_size >= size + offset) && (offset + size > offset)); +} + +static void nvdimm_read_label_data(NVDIMMDevice *nvdimm, void *buf, + uint64_t size, uint64_t offset) +{ + nvdimm_assert_rw_label_data(nvdimm, size, offset); + + memcpy(buf, nvdimm->label_data + offset, size); +} + +static void nvdimm_write_label_data(NVDIMMDevice *nvdimm, const void *buf, + uint64_t size, uint64_t offset) +{ + MemoryRegion *mr; + PCDIMMDevice *dimm = PC_DIMM(nvdimm); + uint64_t backend_offset; + + nvdimm_assert_rw_label_data(nvdimm, size, offset); + + memcpy(nvdimm->label_data + offset, buf, size); + + mr = host_memory_backend_get_memory(dimm->hostmem, &error_abort); + backend_offset = memory_region_size(mr) - nvdimm->label_size + offset; + memory_region_set_dirty(mr, backend_offset, size); +} + static void nvdimm_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc); + NVDIMMClass *nvc = NVDIMM_CLASS(oc); /* nvdimm hotplug has not been supported yet. */ dc->hotpluggable = false; + + ddc->realize = nvdimm_realize; + ddc->get_memory_region = nvdimm_get_memory_region; + + nvc->read_label_data = nvdimm_read_label_data; + nvc->write_label_data = nvdimm_write_label_data; } static TypeInfo nvdimm_info = { .name = TYPE_NVDIMM, .parent = TYPE_PC_DIMM, + .class_size = sizeof(NVDIMMClass), .class_init = nvdimm_class_init, + .instance_size = sizeof(NVDIMMDevice), + .instance_init = nvdimm_init, }; static void nvdimm_register_types(void) diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h index 517de9c..bb5c74a 100644 --- a/include/hw/mem/nvdimm.h +++ b/include/hw/mem/nvdimm.h @@ -33,7 +33,66 @@ } \ } while (0) -#define TYPE_NVDIMM "nvdimm" +/* + * The minimum label data size is required by NVDIMM Namespace + * specification, see the chapter 2 Namespaces: + * "NVDIMMs following the NVDIMM Block Mode Specification use an area + * at least 128KB in size, which holds around 1000 labels." + */ +#define MIN_NAMESPACE_LABEL_SIZE (128UL << 10) + +#define TYPE_NVDIMM "nvdimm" +#define NVDIMM(obj) OBJECT_CHECK(NVDIMMDevice, (obj), TYPE_NVDIMM) +#define NVDIMM_CLASS(oc) OBJECT_CLASS_CHECK(NVDIMMClass, (oc), TYPE_NVDIMM) +#define NVDIMM_GET_CLASS(obj) OBJECT_GET_CLASS(NVDIMMClass, (obj), \ + TYPE_NVDIMM) +struct NVDIMMDevice { + /* private */ + PCDIMMDevice parent_obj; + + /* public */ + + /* + * if we need to reserve memory region for NVDIMM label at the + * end of backend memory? + */ + bool reserve_label; + + /* + * the size of label data in NVDIMM device which is presented to + * guest via __DSM "Get Namespace Label Size" function. + */ + uint64_t label_size; + + /* + * the address of label data which is read by __DSM "Get Namespace + * Label Data" function and written by __DSM "Set Namespace Label + * Data" function. + */ + void *label_data; + + /* + * it's the PMEM region in NVDIMM device, which is presented to + * guest via ACPI NFIT and _FIT method if NVDIMM hotplug is supported. + */ + MemoryRegion nvdimm_mr; +}; +typedef struct NVDIMMDevice NVDIMMDevice; + +struct NVDIMMClass { + /* private */ + PCDIMMDeviceClass parent_class; + + /* public */ + + /* read @size bytes from NVDIMM label data at @offset into @buf. */ + void (*read_label_data)(NVDIMMDevice *nvdimm, void *buf, + uint64_t size, uint64_t offset); + /* write @size bytes from @buf to NVDIMM label data at @offset. */ + void (*write_label_data)(NVDIMMDevice *nvdimm, const void *buf, + uint64_t size, uint64_t offset); +}; +typedef struct NVDIMMClass NVDIMMClass; #define NVDIMM_DSM_MEM_FILE "etc/acpi/nvdimm-mem"