2015-05-20 10:54:31 +08:00
|
|
|
/*
|
|
|
|
* NVDIMM Firmware Interface Table - NFIT
|
|
|
|
*
|
|
|
|
* Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of version 2 of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*/
|
|
|
|
#ifndef __NFIT_H__
|
|
|
|
#define __NFIT_H__
|
2016-02-20 04:16:34 +08:00
|
|
|
#include <linux/workqueue.h>
|
2015-05-20 10:54:31 +08:00
|
|
|
#include <linux/libnvdimm.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/uuid.h>
|
|
|
|
#include <linux/acpi.h>
|
|
|
|
#include <acpi/acuuid.h>
|
|
|
|
|
2016-04-29 07:23:43 +08:00
|
|
|
/* ACPI 6.1 */
|
2015-05-20 10:54:31 +08:00
|
|
|
#define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba"
|
2016-04-29 07:23:43 +08:00
|
|
|
|
|
|
|
/* http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf */
|
2015-05-20 10:54:31 +08:00
|
|
|
#define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
|
2016-04-29 07:23:43 +08:00
|
|
|
|
|
|
|
/* https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/ */
|
|
|
|
#define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6"
|
|
|
|
#define UUID_NFIT_DIMM_N_HPE2 "5008664b-b758-41a0-a03c-27c2f2d04f7e"
|
|
|
|
|
2015-06-24 08:08:34 +08:00
|
|
|
#define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
|
|
|
|
| ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
|
2015-10-19 10:24:52 +08:00
|
|
|
| ACPI_NFIT_MEM_NOT_ARMED)
|
2015-05-20 10:54:31 +08:00
|
|
|
|
|
|
|
enum nfit_uuids {
|
2016-04-29 07:23:43 +08:00
|
|
|
/* for simplicity alias the uuid index with the family id */
|
|
|
|
NFIT_DEV_DIMM = NVDIMM_FAMILY_INTEL,
|
|
|
|
NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1,
|
|
|
|
NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,
|
2015-05-20 10:54:31 +08:00
|
|
|
NFIT_SPA_VOLATILE,
|
|
|
|
NFIT_SPA_PM,
|
|
|
|
NFIT_SPA_DCR,
|
|
|
|
NFIT_SPA_BDW,
|
|
|
|
NFIT_SPA_VDISK,
|
|
|
|
NFIT_SPA_VCD,
|
|
|
|
NFIT_SPA_PDISK,
|
|
|
|
NFIT_SPA_PCD,
|
|
|
|
NFIT_DEV_BUS,
|
|
|
|
NFIT_UUID_MAX,
|
|
|
|
};
|
|
|
|
|
2016-04-29 09:35:23 +08:00
|
|
|
/*
|
|
|
|
* Region format interface codes are stored as an array of bytes in the
|
|
|
|
* NFIT DIMM Control Region structure
|
|
|
|
*/
|
|
|
|
#define NFIT_FIC_BYTE cpu_to_be16(0x101) /* byte-addressable energy backed */
|
|
|
|
#define NFIT_FIC_BLK cpu_to_be16(0x201) /* block-addressable non-energy backed */
|
|
|
|
#define NFIT_FIC_BYTEN cpu_to_be16(0x301) /* byte-addressable non-energy backed */
|
2016-02-02 09:48:42 +08:00
|
|
|
|
2015-07-11 01:06:14 +08:00
|
|
|
enum {
|
2016-02-13 09:01:11 +08:00
|
|
|
NFIT_BLK_READ_FLUSH = 1,
|
|
|
|
NFIT_BLK_DCR_LATCH = 2,
|
|
|
|
NFIT_ARS_STATUS_DONE = 0,
|
|
|
|
NFIT_ARS_STATUS_BUSY = 1 << 16,
|
|
|
|
NFIT_ARS_STATUS_NONE = 2 << 16,
|
|
|
|
NFIT_ARS_STATUS_INTR = 3 << 16,
|
|
|
|
NFIT_ARS_START_BUSY = 6,
|
|
|
|
NFIT_ARS_CAP_NONE = 1,
|
|
|
|
NFIT_ARS_F_OVERFLOW = 1,
|
2016-02-18 05:01:23 +08:00
|
|
|
NFIT_ARS_TIMEOUT = 90,
|
2015-07-11 01:06:14 +08:00
|
|
|
};
|
|
|
|
|
2015-05-20 10:54:31 +08:00
|
|
|
struct nfit_spa {
|
|
|
|
struct acpi_nfit_system_address *spa;
|
|
|
|
struct list_head list;
|
2016-02-18 05:01:23 +08:00
|
|
|
struct nd_region *nd_region;
|
|
|
|
unsigned int ars_done:1;
|
|
|
|
u32 clear_err_unit;
|
|
|
|
u32 max_ars;
|
2015-05-20 10:54:31 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct nfit_dcr {
|
|
|
|
struct acpi_nfit_control_region *dcr;
|
|
|
|
struct list_head list;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct nfit_bdw {
|
|
|
|
struct acpi_nfit_data_region *bdw;
|
|
|
|
struct list_head list;
|
|
|
|
};
|
|
|
|
|
2015-06-25 16:21:02 +08:00
|
|
|
struct nfit_idt {
|
|
|
|
struct acpi_nfit_interleave *idt;
|
|
|
|
struct list_head list;
|
|
|
|
};
|
|
|
|
|
2015-07-11 01:06:13 +08:00
|
|
|
struct nfit_flush {
|
|
|
|
struct acpi_nfit_flush_address *flush;
|
|
|
|
struct list_head list;
|
|
|
|
};
|
|
|
|
|
2015-05-20 10:54:31 +08:00
|
|
|
struct nfit_memdev {
|
|
|
|
struct acpi_nfit_memory_map *memdev;
|
|
|
|
struct list_head list;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* assembled tables for a given dimm/memory-device */
|
|
|
|
struct nfit_mem {
|
2015-04-25 15:56:17 +08:00
|
|
|
struct nvdimm *nvdimm;
|
2015-05-20 10:54:31 +08:00
|
|
|
struct acpi_nfit_memory_map *memdev_dcr;
|
|
|
|
struct acpi_nfit_memory_map *memdev_pmem;
|
2015-06-25 16:21:02 +08:00
|
|
|
struct acpi_nfit_memory_map *memdev_bdw;
|
2015-05-20 10:54:31 +08:00
|
|
|
struct acpi_nfit_control_region *dcr;
|
|
|
|
struct acpi_nfit_data_region *bdw;
|
|
|
|
struct acpi_nfit_system_address *spa_dcr;
|
|
|
|
struct acpi_nfit_system_address *spa_bdw;
|
2015-06-25 16:21:02 +08:00
|
|
|
struct acpi_nfit_interleave *idt_dcr;
|
|
|
|
struct acpi_nfit_interleave *idt_bdw;
|
2015-07-11 01:06:13 +08:00
|
|
|
struct nfit_flush *nfit_flush;
|
2015-05-20 10:54:31 +08:00
|
|
|
struct list_head list;
|
2015-06-09 02:27:06 +08:00
|
|
|
struct acpi_device *adev;
|
2016-04-06 06:26:50 +08:00
|
|
|
struct acpi_nfit_desc *acpi_desc;
|
2015-06-09 02:27:06 +08:00
|
|
|
unsigned long dsm_mask;
|
2016-04-29 07:23:43 +08:00
|
|
|
int family;
|
2015-05-20 10:54:31 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct acpi_nfit_desc {
|
|
|
|
struct nvdimm_bus_descriptor nd_desc;
|
2015-11-21 08:05:49 +08:00
|
|
|
struct acpi_table_header acpi_header;
|
|
|
|
struct acpi_nfit_header *nfit;
|
2015-06-25 16:21:02 +08:00
|
|
|
struct mutex spa_map_mutex;
|
2015-10-28 06:58:27 +08:00
|
|
|
struct mutex init_mutex;
|
2015-06-25 16:21:02 +08:00
|
|
|
struct list_head spa_maps;
|
2015-05-20 10:54:31 +08:00
|
|
|
struct list_head memdevs;
|
2015-07-11 01:06:13 +08:00
|
|
|
struct list_head flushes;
|
2015-05-20 10:54:31 +08:00
|
|
|
struct list_head dimms;
|
|
|
|
struct list_head spas;
|
|
|
|
struct list_head dcrs;
|
|
|
|
struct list_head bdws;
|
2015-06-25 16:21:02 +08:00
|
|
|
struct list_head idts;
|
2015-05-20 10:54:31 +08:00
|
|
|
struct nvdimm_bus *nvdimm_bus;
|
|
|
|
struct device *dev;
|
2016-02-18 05:01:23 +08:00
|
|
|
struct nd_cmd_ars_status *ars_status;
|
|
|
|
size_t ars_status_size;
|
2016-02-20 04:16:34 +08:00
|
|
|
struct work_struct work;
|
|
|
|
unsigned int cancel:1;
|
2016-04-29 07:17:07 +08:00
|
|
|
unsigned long dimm_cmd_force_en;
|
|
|
|
unsigned long bus_cmd_force_en;
|
2015-06-18 05:23:32 +08:00
|
|
|
int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
|
|
|
|
void *iobuf, u64 len, int rw);
|
2015-05-20 10:54:31 +08:00
|
|
|
};
|
|
|
|
|
2015-06-25 16:21:02 +08:00
|
|
|
enum nd_blk_mmio_selector {
|
|
|
|
BDW,
|
|
|
|
DCR,
|
|
|
|
};
|
|
|
|
|
nd_blk: change aperture mapping from WC to WB
This should result in a pretty sizeable performance gain for reads. For
rough comparison I did some simple read testing using PMEM to compare
reads of write combining (WC) mappings vs write-back (WB). This was
done on a random lab machine.
PMEM reads from a write combining mapping:
# dd of=/dev/null if=/dev/pmem0 bs=4096 count=100000
100000+0 records in
100000+0 records out
409600000 bytes (410 MB) copied, 9.2855 s, 44.1 MB/s
PMEM reads from a write-back mapping:
# dd of=/dev/null if=/dev/pmem0 bs=4096 count=1000000
1000000+0 records in
1000000+0 records out
4096000000 bytes (4.1 GB) copied, 3.44034 s, 1.2 GB/s
To be able to safely support a write-back aperture I needed to add
support for the "read flush" _DSM flag, as outlined in the DSM spec:
http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
This flag tells the ND BLK driver that it needs to flush the cache lines
associated with the aperture after the aperture is moved but before any
new data is read. This ensures that any stale cache lines from the
previous contents of the aperture will be discarded from the processor
cache, and the new data will be read properly from the DIMM. We know
that the cache lines are clean and will be discarded without any
writeback because either a) the previous aperture operation was a read,
and we never modified the contents of the aperture, or b) the previous
aperture operation was a write and we must have written back the dirtied
contents of the aperture to the DIMM before the I/O was completed.
In order to add support for the "read flush" flag I needed to add a
generic routine to invalidate cache lines, mmio_flush_range(). This is
protected by the ARCH_HAS_MMIO_FLUSH Kconfig variable, and is currently
only supported on x86.
Signed-off-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-08-28 03:14:20 +08:00
|
|
|
struct nd_blk_addr {
|
|
|
|
union {
|
|
|
|
void __iomem *base;
|
|
|
|
void __pmem *aperture;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2015-06-25 16:21:02 +08:00
|
|
|
struct nfit_blk {
|
|
|
|
struct nfit_blk_mmio {
|
nd_blk: change aperture mapping from WC to WB
This should result in a pretty sizeable performance gain for reads. For
rough comparison I did some simple read testing using PMEM to compare
reads of write combining (WC) mappings vs write-back (WB). This was
done on a random lab machine.
PMEM reads from a write combining mapping:
# dd of=/dev/null if=/dev/pmem0 bs=4096 count=100000
100000+0 records in
100000+0 records out
409600000 bytes (410 MB) copied, 9.2855 s, 44.1 MB/s
PMEM reads from a write-back mapping:
# dd of=/dev/null if=/dev/pmem0 bs=4096 count=1000000
1000000+0 records in
1000000+0 records out
4096000000 bytes (4.1 GB) copied, 3.44034 s, 1.2 GB/s
To be able to safely support a write-back aperture I needed to add
support for the "read flush" _DSM flag, as outlined in the DSM spec:
http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
This flag tells the ND BLK driver that it needs to flush the cache lines
associated with the aperture after the aperture is moved but before any
new data is read. This ensures that any stale cache lines from the
previous contents of the aperture will be discarded from the processor
cache, and the new data will be read properly from the DIMM. We know
that the cache lines are clean and will be discarded without any
writeback because either a) the previous aperture operation was a read,
and we never modified the contents of the aperture, or b) the previous
aperture operation was a write and we must have written back the dirtied
contents of the aperture to the DIMM before the I/O was completed.
In order to add support for the "read flush" flag I needed to add a
generic routine to invalidate cache lines, mmio_flush_range(). This is
protected by the ARCH_HAS_MMIO_FLUSH Kconfig variable, and is currently
only supported on x86.
Signed-off-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-08-28 03:14:20 +08:00
|
|
|
struct nd_blk_addr addr;
|
2015-06-25 16:21:02 +08:00
|
|
|
u64 size;
|
|
|
|
u64 base_offset;
|
|
|
|
u32 line_size;
|
|
|
|
u32 num_lines;
|
|
|
|
u32 table_size;
|
|
|
|
struct acpi_nfit_interleave *idt;
|
|
|
|
struct acpi_nfit_system_address *spa;
|
|
|
|
} mmio[2];
|
|
|
|
struct nd_region *nd_region;
|
|
|
|
u64 bdw_offset; /* post interleave offset */
|
|
|
|
u64 stat_offset;
|
|
|
|
u64 cmd_offset;
|
2015-07-11 01:06:13 +08:00
|
|
|
void __iomem *nvdimm_flush;
|
2015-07-11 01:06:14 +08:00
|
|
|
u32 dimm_flags;
|
2015-07-11 01:06:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
enum spa_map_type {
|
|
|
|
SPA_MAP_CONTROL,
|
|
|
|
SPA_MAP_APERTURE,
|
2015-06-25 16:21:02 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct nfit_spa_mapping {
|
|
|
|
struct acpi_nfit_desc *acpi_desc;
|
|
|
|
struct acpi_nfit_system_address *spa;
|
|
|
|
struct list_head list;
|
|
|
|
struct kref kref;
|
nd_blk: change aperture mapping from WC to WB
This should result in a pretty sizeable performance gain for reads. For
rough comparison I did some simple read testing using PMEM to compare
reads of write combining (WC) mappings vs write-back (WB). This was
done on a random lab machine.
PMEM reads from a write combining mapping:
# dd of=/dev/null if=/dev/pmem0 bs=4096 count=100000
100000+0 records in
100000+0 records out
409600000 bytes (410 MB) copied, 9.2855 s, 44.1 MB/s
PMEM reads from a write-back mapping:
# dd of=/dev/null if=/dev/pmem0 bs=4096 count=1000000
1000000+0 records in
1000000+0 records out
4096000000 bytes (4.1 GB) copied, 3.44034 s, 1.2 GB/s
To be able to safely support a write-back aperture I needed to add
support for the "read flush" _DSM flag, as outlined in the DSM spec:
http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
This flag tells the ND BLK driver that it needs to flush the cache lines
associated with the aperture after the aperture is moved but before any
new data is read. This ensures that any stale cache lines from the
previous contents of the aperture will be discarded from the processor
cache, and the new data will be read properly from the DIMM. We know
that the cache lines are clean and will be discarded without any
writeback because either a) the previous aperture operation was a read,
and we never modified the contents of the aperture, or b) the previous
aperture operation was a write and we must have written back the dirtied
contents of the aperture to the DIMM before the I/O was completed.
In order to add support for the "read flush" flag I needed to add a
generic routine to invalidate cache lines, mmio_flush_range(). This is
protected by the ARCH_HAS_MMIO_FLUSH Kconfig variable, and is currently
only supported on x86.
Signed-off-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-08-28 03:14:20 +08:00
|
|
|
enum spa_map_type type;
|
|
|
|
struct nd_blk_addr addr;
|
2015-06-25 16:21:02 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct nfit_spa_mapping *to_spa_map(struct kref *kref)
|
|
|
|
{
|
|
|
|
return container_of(kref, struct nfit_spa_mapping, kref);
|
|
|
|
}
|
|
|
|
|
2015-05-20 10:54:31 +08:00
|
|
|
static inline struct acpi_nfit_memory_map *__to_nfit_memdev(
|
|
|
|
struct nfit_mem *nfit_mem)
|
|
|
|
{
|
|
|
|
if (nfit_mem->memdev_dcr)
|
|
|
|
return nfit_mem->memdev_dcr;
|
|
|
|
return nfit_mem->memdev_pmem;
|
|
|
|
}
|
2015-04-27 07:26:48 +08:00
|
|
|
|
|
|
|
static inline struct acpi_nfit_desc *to_acpi_desc(
|
|
|
|
struct nvdimm_bus_descriptor *nd_desc)
|
|
|
|
{
|
|
|
|
return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
|
|
|
|
}
|
2015-06-18 05:23:32 +08:00
|
|
|
|
|
|
|
const u8 *to_nfit_uuid(enum nfit_uuids id);
|
|
|
|
int acpi_nfit_init(struct acpi_nfit_desc *nfit, acpi_size sz);
|
2016-02-20 04:29:32 +08:00
|
|
|
void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
|
2015-05-20 10:54:31 +08:00
|
|
|
#endif /* __NFIT_H__ */
|