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: 7431281 Return-Path: X-Original-To: patchwork-kvm@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 49F759F36A for ; Sun, 18 Oct 2015 17:00:56 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2EE3D20145 for ; Sun, 18 Oct 2015 17:00:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F20EB200E7 for ; Sun, 18 Oct 2015 17:00:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932320AbbJRRAm (ORCPT ); Sun, 18 Oct 2015 13:00:42 -0400 Received: from mga11.intel.com ([192.55.52.93]:19148 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932296AbbJRRAf (ORCPT ); Sun, 18 Oct 2015 13:00:35 -0400 Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.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 Cc: gleb@kernel.org, mtosatti@redhat.com, stefanha@redhat.com, mst@redhat.com, rth@twiddle.net, ehabkost@redhat.com, dan.j.williams@intel.com, kvm@vger.kernel.org, qemu-devel@nongnu.org, Xiao Guangrong Subject: [PATCH v4 28/33] nvdimm acpi: support DSM_FUN_IMPLEMENTED function 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> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-5.0 required=5.0 tests=BAYES_00, DATE_IN_FUTURE_06_12, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, 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 __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. */);