]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - tools/testing/nvdimm/test/nfit.c
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
[linux.git] / tools / testing / nvdimm / test / nfit.c
index 021e6f97f33e7af2a7e570ba46cd29b72523b130..40ab4476c80a2039ab543cc94b09725789b2fe57 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/ndctl.h>
 #include <linux/sizes.h>
+#include <linux/list.h>
 #include <linux/slab.h>
 #include <nfit.h>
 #include <nd.h>
  * +------+  |                 blk5.0             |  pm1.0  |    3      region5
  *           +-------------------------+----------+-+-------+
  *
+ * +--+---+
+ * | cpu1 |
+ * +--+---+                   (Hotplug DIMM)
+ *    |      +----------------------------------------------+
+ * +--+---+  |                 blk6.0/pm7.0                 |    4      region6/7
+ * | imc0 +--+----------------------------------------------+
+ * +------+
+ *
+ *
  * *) In this layout we have four dimms and two memory controllers in one
  *    socket.  Each unique interface (BLK or PMEM) to DPA space
  *    is identified by a region device with a dynamically assigned id.
@@ -85,8 +96,8 @@
  *    reference an NVDIMM.
  */
 enum {
-       NUM_PM  = 2,
-       NUM_DCR = 4,
+       NUM_PM  = 3,
+       NUM_DCR = 5,
        NUM_BDW = NUM_DCR,
        NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW,
        NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */,
@@ -115,6 +126,7 @@ static u32 handle[NUM_DCR] = {
        [1] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1),
        [2] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0),
        [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1),
+       [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0),
 };
 
 struct nfit_test {
@@ -138,6 +150,7 @@ struct nfit_test {
        dma_addr_t *dcr_dma;
        int (*alloc)(struct nfit_test *t);
        void (*setup)(struct nfit_test *t);
+       int setup_hotplug;
 };
 
 static struct nfit_test *to_nfit_test(struct device *dev)
@@ -428,6 +441,10 @@ static int nfit_test0_alloc(struct nfit_test *t)
        if (!t->spa_set[1])
                return -ENOMEM;
 
+       t->spa_set[2] = test_alloc_coherent(t, SPA0_SIZE, &t->spa_set_dma[2]);
+       if (!t->spa_set[2])
+               return -ENOMEM;
+
        for (i = 0; i < NUM_DCR; i++) {
                t->dimm[i] = test_alloc(t, DIMM_SIZE, &t->dimm_dma[i]);
                if (!t->dimm[i])
@@ -950,6 +967,126 @@ static void nfit_test0_setup(struct nfit_test *t)
        flush->hint_count = 1;
        flush->hint_address[0] = t->flush_dma[3];
 
+       if (t->setup_hotplug) {
+               offset = offset + sizeof(struct acpi_nfit_flush_address) * 4;
+               /* dcr-descriptor4 */
+               dcr = nfit_buf + offset;
+               dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
+               dcr->header.length = sizeof(struct acpi_nfit_control_region);
+               dcr->region_index = 4+1;
+               dcr->vendor_id = 0xabcd;
+               dcr->device_id = 0;
+               dcr->revision_id = 1;
+               dcr->serial_number = ~handle[4];
+               dcr->windows = 1;
+               dcr->window_size = DCR_SIZE;
+               dcr->command_offset = 0;
+               dcr->command_size = 8;
+               dcr->status_offset = 8;
+               dcr->status_size = 4;
+
+               offset = offset + sizeof(struct acpi_nfit_control_region);
+               /* bdw4 (spa/dcr4, dimm4) */
+               bdw = nfit_buf + offset;
+               bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION;
+               bdw->header.length = sizeof(struct acpi_nfit_data_region);
+               bdw->region_index = 4+1;
+               bdw->windows = 1;
+               bdw->offset = 0;
+               bdw->size = BDW_SIZE;
+               bdw->capacity = DIMM_SIZE;
+               bdw->start_address = 0;
+
+               offset = offset + sizeof(struct acpi_nfit_data_region);
+               /* spa10 (dcr4) dimm4 */
+               spa = nfit_buf + offset;
+               spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
+               spa->header.length = sizeof(*spa);
+               memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
+               spa->range_index = 10+1;
+               spa->address = t->dcr_dma[4];
+               spa->length = DCR_SIZE;
+
+               /*
+                * spa11 (single-dimm interleave for hotplug, note storage
+                * does not actually alias the related block-data-window
+                * regions)
+                */
+               spa = nfit_buf + offset + sizeof(*spa);
+               spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
+               spa->header.length = sizeof(*spa);
+               memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
+               spa->range_index = 11+1;
+               spa->address = t->spa_set_dma[2];
+               spa->length = SPA0_SIZE;
+
+               /* spa12 (bdw for dcr4) dimm4 */
+               spa = nfit_buf + offset + sizeof(*spa) * 2;
+               spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
+               spa->header.length = sizeof(*spa);
+               memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
+               spa->range_index = 12+1;
+               spa->address = t->dimm_dma[4];
+               spa->length = DIMM_SIZE;
+
+               offset = offset + sizeof(*spa) * 3;
+               /* mem-region14 (spa/dcr4, dimm4) */
+               memdev = nfit_buf + offset;
+               memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
+               memdev->header.length = sizeof(*memdev);
+               memdev->device_handle = handle[4];
+               memdev->physical_id = 4;
+               memdev->region_id = 0;
+               memdev->range_index = 10+1;
+               memdev->region_index = 4+1;
+               memdev->region_size = 0;
+               memdev->region_offset = 0;
+               memdev->address = 0;
+               memdev->interleave_index = 0;
+               memdev->interleave_ways = 1;
+
+               /* mem-region15 (spa0, dimm4) */
+               memdev = nfit_buf + offset +
+                               sizeof(struct acpi_nfit_memory_map);
+               memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
+               memdev->header.length = sizeof(*memdev);
+               memdev->device_handle = handle[4];
+               memdev->physical_id = 4;
+               memdev->region_id = 0;
+               memdev->range_index = 11+1;
+               memdev->region_index = 4+1;
+               memdev->region_size = SPA0_SIZE;
+               memdev->region_offset = t->spa_set_dma[2];
+               memdev->address = 0;
+               memdev->interleave_index = 0;
+               memdev->interleave_ways = 1;
+
+               /* mem-region16 (spa/dcr4, dimm4) */
+               memdev = nfit_buf + offset +
+                               sizeof(struct acpi_nfit_memory_map) * 2;
+               memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
+               memdev->header.length = sizeof(*memdev);
+               memdev->device_handle = handle[4];
+               memdev->physical_id = 4;
+               memdev->region_id = 0;
+               memdev->range_index = 12+1;
+               memdev->region_index = 4+1;
+               memdev->region_size = 0;
+               memdev->region_offset = 0;
+               memdev->address = 0;
+               memdev->interleave_index = 0;
+               memdev->interleave_ways = 1;
+
+               offset = offset + sizeof(struct acpi_nfit_memory_map) * 3;
+               /* flush3 (dimm4) */
+               flush = nfit_buf + offset;
+               flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
+               flush->header.length = sizeof(struct acpi_nfit_flush_address);
+               flush->device_handle = handle[4];
+               flush->hint_count = 1;
+               flush->hint_address[0] = t->flush_dma[4];
+       }
+
        acpi_desc = &t->acpi_desc;
        set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en);
        set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
@@ -998,7 +1135,7 @@ static void nfit_test1_setup(struct nfit_test *t)
        memdev->interleave_ways = 1;
        memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED
                | ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED
-               | ACPI_NFIT_MEM_ARMED;
+               | ACPI_NFIT_MEM_NOT_ARMED;
 
        offset += sizeof(*memdev);
        /* dcr-descriptor0 */
@@ -1108,6 +1245,29 @@ static int nfit_test_probe(struct platform_device *pdev)
        if (!acpi_desc->nvdimm_bus)
                return -ENXIO;
 
+       INIT_LIST_HEAD(&acpi_desc->spa_maps);
+       INIT_LIST_HEAD(&acpi_desc->spas);
+       INIT_LIST_HEAD(&acpi_desc->dcrs);
+       INIT_LIST_HEAD(&acpi_desc->bdws);
+       INIT_LIST_HEAD(&acpi_desc->idts);
+       INIT_LIST_HEAD(&acpi_desc->flushes);
+       INIT_LIST_HEAD(&acpi_desc->memdevs);
+       INIT_LIST_HEAD(&acpi_desc->dimms);
+       mutex_init(&acpi_desc->spa_map_mutex);
+       mutex_init(&acpi_desc->init_mutex);
+
+       rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size);
+       if (rc) {
+               nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+               return rc;
+       }
+
+       if (nfit_test->setup != nfit_test0_setup)
+               return 0;
+
+       nfit_test->setup_hotplug = 1;
+       nfit_test->setup(nfit_test);
+
        rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size);
        if (rc) {
                nvdimm_bus_unregister(acpi_desc->nvdimm_bus);