From patchwork Mon Oct 19 00:54:14 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiao Guangrong X-Patchwork-Id: 531969 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 1FDB91406AA for ; Mon, 19 Oct 2015 04:04:41 +1100 (AEDT) Received: from localhost ([::1]:34711 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZnrNv-0007Hd-0m for incoming@patchwork.ozlabs.org; Sun, 18 Oct 2015 13:04:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42954) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZnrK2-0008KY-Up for qemu-devel@nongnu.org; Sun, 18 Oct 2015 13:00:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZnrJz-0000Pv-HW for qemu-devel@nongnu.org; Sun, 18 Oct 2015 13:00:38 -0400 Received: from mga09.intel.com ([134.134.136.24]:58036) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZnrJz-0000CK-64 for qemu-devel@nongnu.org; Sun, 18 Oct 2015 13:00:35 -0400 Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP; 18 Oct 2015 10:00:34 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.17,698,1437462000"; d="scan'208";a="583275986" 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; 18 Oct 2015 10:00:32 -0700 From: Xiao Guangrong To: pbonzini@redhat.com, imammedo@redhat.com Date: Mon, 19 Oct 2015 08:54:14 +0800 Message-Id: <1445216059-88521-29-git-send-email-guangrong.xiao@linux.intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1445216059-88521-1-git-send-email-guangrong.xiao@linux.intel.com> References: <1445216059-88521-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: 134.134.136.24 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 v4 28/33] nvdimm acpi: support DSM_FUN_IMPLEMENTED function 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org __DSM is defined in ACPI 6.0: 9.14.1 _DSM (Device Specific Method) Function 0 is a query function. We do not support any function on root device and only 3 functions are support for NVDIMM device, DSM_DEV_FUN_NAMESPACE_LABEL_SIZE, DSM_DEV_FUN_GET_NAMESPACE_LABEL_DATA and DSM_DEV_FUN_SET_NAMESPACE_LABEL_DATA, that means we currently only allow to access device's Label Namespace Signed-off-by: Xiao Guangrong --- hw/acpi/nvdimm.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 2 deletions(-) diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index b211b8b..37fea1c 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -260,6 +260,22 @@ static uint32_t nvdimm_slot_to_dcr_index(int slot) return nvdimm_slot_to_spa_index(slot) + 1; } +static NVDIMMDevice +*nvdimm_get_device_by_handle(GSList *list, uint32_t handle) +{ + for (; list; list = list->next) { + NVDIMMDevice *nvdimm = list->data; + int slot = object_property_get_int(OBJECT(nvdimm), DIMM_SLOT_PROP, + NULL); + + if (nvdimm_slot_to_handle(slot) == handle) { + return nvdimm; + } + } + + return NULL; +} + /* * Please refer to ACPI 6.0: 5.2.25.1 System Physical Address Range * Structure @@ -411,6 +427,60 @@ static void nvdimm_build_nfit(GArray *structures, GArray *table_offsets, /* detailed _DSM design please refer to docs/specs/acpi_nvdimm.txt */ #define NOTIFY_VALUE 0x99 +enum { + DSM_FUN_IMPLEMENTED = 0, + + /* NVDIMM Root Device Functions */ + DSM_ROOT_DEV_FUN_ARS_CAP = 1, + DSM_ROOT_DEV_FUN_ARS_START = 2, + DSM_ROOT_DEV_FUN_ARS_QUERY = 3, + + /* NVDIMM Device (non-root) Functions */ + DSM_DEV_FUN_SMART = 1, + DSM_DEV_FUN_SMART_THRESHOLD = 2, + DSM_DEV_FUN_BLOCK_NVDIMM_FLAGS = 3, + DSM_DEV_FUN_NAMESPACE_LABEL_SIZE = 4, + DSM_DEV_FUN_GET_NAMESPACE_LABEL_DATA = 5, + DSM_DEV_FUN_SET_NAMESPACE_LABEL_DATA = 6, + DSM_DEV_FUN_VENDOR_EFFECT_LOG_SIZE = 7, + DSM_DEV_FUN_GET_VENDOR_EFFECT_LOG = 8, + DSM_DEV_FUN_VENDOR_SPECIFIC = 9, +}; + +enum { + /* Common return status codes. */ + DSM_STATUS_SUCCESS = 0, /* Success */ + DSM_STATUS_NOT_SUPPORTED = 1, /* Not Supported */ + + /* NVDIMM Root Device _DSM function return status codes*/ + DSM_ROOT_DEV_STATUS_INVALID_PARAS = 2, /* Invalid Input Parameters */ + DSM_ROOT_DEV_STATUS_FUNCTION_SPECIFIC_ERROR = 3, /* Function-Specific + Error */ + + /* NVDIMM Device (non-root) _DSM function return status codes*/ + DSM_DEV_STATUS_NON_EXISTING_MEM_DEV = 2, /* Non-Existing Memory Device */ + DSM_DEV_STATUS_INVALID_PARAS = 3, /* Invalid Input Parameters */ + DSM_DEV_STATUS_VENDOR_SPECIFIC_ERROR = 4, /* Vendor Specific Error */ +}; + +/* Current revision supported by DSM specification is 1. */ +#define DSM_REVISION (1) + +/* + * please refer to ACPI 6.0: 9.14.1 _DSM (Device Specific Method): Return + * Value Information: + * if set to zero, no functions are supported (other than function zero) + * for the specified UUID and Revision ID. If set to one, at least one + * additional function is supported. + */ + +/* do not support any function on root. */ +#define ROOT_SUPPORT_FUN (0ULL) +#define DIMM_SUPPORT_FUN ((1 << DSM_FUN_IMPLEMENTED) \ + | (1 << DSM_DEV_FUN_NAMESPACE_LABEL_SIZE) \ + | (1 << DSM_DEV_FUN_GET_NAMESPACE_LABEL_DATA) \ + | (1 << DSM_DEV_FUN_SET_NAMESPACE_LABEL_DATA)) + struct dsm_in { uint32_t handle; uint32_t revision; @@ -420,6 +490,11 @@ struct dsm_in { } QEMU_PACKED; typedef struct dsm_in dsm_in; +struct cmd_out_implemented { + uint64_t cmd_list; +}; +typedef struct cmd_out_implemented cmd_out_implemented; + struct dsm_out { /* the size of buffer filled by QEMU. */ uint32_t len; @@ -434,12 +509,115 @@ nvdimm_dsm_read(void *opaque, hwaddr addr, unsigned size) return 0; } +static void nvdimm_dsm_write_status(GArray *out, uint32_t status) +{ + /* status locates in the first 4 bytes in the dsm memory. */ + assert(!out->len); + + status = cpu_to_le32(status); + g_array_append_vals(out, &status, sizeof(status)); +} + +static void nvdimm_dsm_write_root(dsm_in *in, GArray *out) +{ + uint32_t status = DSM_STATUS_NOT_SUPPORTED; + + /* please refer to ACPI 6.0: 9.14.1 _DSM (Device Specific Method) */ + if (in->function == DSM_FUN_IMPLEMENTED) { + uint64_t cmd_list = cpu_to_le64(ROOT_SUPPORT_FUN); + + g_array_append_vals(out, &cmd_list, sizeof(cmd_list)); + return; + } + + nvdimm_debug("Return status %#x.\n", status); + nvdimm_dsm_write_status(out, status); +} + +static void nvdimm_dsm_write_nvdimm(dsm_in *in, GArray *out) +{ + GSList *list = nvdimm_get_plugged_device_list(); + NVDIMMDevice *nvdimm = nvdimm_get_device_by_handle(list, in->handle); + uint32_t status = DSM_DEV_STATUS_NON_EXISTING_MEM_DEV; + uint64_t cmd_list; + + if (!nvdimm) { + goto set_status_free; + } + + switch (in->function) { + /* please refer to ACPI 6.0: 9.14.1 _DSM (Device Specific Method) */ + case DSM_FUN_IMPLEMENTED: + cmd_list = cpu_to_le64(DIMM_SUPPORT_FUN); + g_array_append_vals(out, &cmd_list, sizeof(cmd_list)); + goto free; + default: + status = DSM_STATUS_NOT_SUPPORTED; + }; + +set_status_free: + nvdimm_debug("Return status %#x.\n", status); + nvdimm_dsm_write_status(out, status); +free: + g_slist_free(list); +} + static void nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { + NVDIMMState *state = opaque; + MemoryRegion *dsm_ram_mr; + dsm_in *in; + GArray *out; + void *dsm_ram_addr; + if (val != NOTIFY_VALUE) { fprintf(stderr, "BUG: unexepected notify value 0x%" PRIx64, val); } + + dsm_ram_mr = memory_region_find(&state->mr, getpagesize(), + getpagesize()).mr; + dsm_ram_addr = memory_region_get_ram_ptr(dsm_ram_mr); + + /* + * copy all input data to our local memory to avoid potential issue + * as the dsm memory is visible to guest. + */ + in = g_malloc(memory_region_size(dsm_ram_mr)); + memcpy(in, dsm_ram_addr, memory_region_size(dsm_ram_mr)); + + le32_to_cpus(&in->revision); + le32_to_cpus(&in->function); + le32_to_cpus(&in->handle); + + nvdimm_debug("Revision %#x Handler %#x Function %#x.\n", in->revision, + in->handle, in->function); + + out = g_array_new(false, true /* clear */, 1); + + if (in->revision != DSM_REVISION) { + nvdimm_debug("Revision %#x is not supported, expect %#x.\n", + in->revision, DSM_REVISION); + nvdimm_dsm_write_status(out, DSM_STATUS_NOT_SUPPORTED); + goto exit; + } + + /* Handle 0 is reserved for NVDIMM Root Device. */ + if (!in->handle) { + nvdimm_dsm_write_root(in, out); + goto exit; + } + + nvdimm_dsm_write_nvdimm(in, out); + +exit: + /* Write our output result to dsm memory. */ + ((dsm_out *)dsm_ram_addr)->len = out->len; + memcpy(((dsm_out *)dsm_ram_addr)->data, out->data, out->len); + + g_free(in); + g_array_free(out, true); + memory_region_unref(dsm_ram_mr); } static const MemoryRegionOps nvdimm_dsm_ops = { @@ -547,7 +725,8 @@ static void build_nvdimm_devices(NVDIMMState *state, GSList *device_list, */ BUILD_DSM_METHOD(dev, method, handle /* NVDIMM Device Handle */, - 3 /* Invalid Input Parameters */, + DSM_DEV_STATUS_INVALID_PARAS, /* error code if UUID + is not matched. */ "4309AC30-0D11-11E4-9191-0800200C9A66" /* UUID for NVDIMM Devices. */); @@ -669,7 +848,8 @@ static void nvdimm_build_acpi_devices(NVDIMMState *state, GSList *device_list, */ BUILD_DSM_METHOD(dev, method, 0 /* 0 is reserved for NVDIMM Root Device*/, - 2 /* Invalid Input Parameters */, + DSM_ROOT_DEV_STATUS_INVALID_PARAS, /* error code if + UUID is not matched. */ "2F10E7A4-9E91-11E4-89D3-123B93F75CBA" /* UUID for NVDIMM Root Devices. */);