2021-02-17 07:09:51 +03:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
/* Copyright(c) 2020 Intel Corporation. */
|
|
|
|
|
|
|
|
#ifndef __CXL_H__
|
|
|
|
#define __CXL_H__
|
|
|
|
|
|
|
|
#include <linux/bitfield.h>
|
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <linux/io.h>
|
|
|
|
|
2021-05-28 03:49:22 +03:00
|
|
|
/* CXL 2.0 8.2.5 CXL.cache and CXL.mem Registers*/
|
|
|
|
#define CXL_CM_OFFSET 0x1000
|
|
|
|
#define CXL_CM_CAP_HDR_OFFSET 0x0
|
|
|
|
#define CXL_CM_CAP_HDR_ID_MASK GENMASK(15, 0)
|
|
|
|
#define CM_CAP_HDR_CAP_ID 1
|
|
|
|
#define CXL_CM_CAP_HDR_VERSION_MASK GENMASK(19, 16)
|
|
|
|
#define CM_CAP_HDR_CAP_VERSION 1
|
|
|
|
#define CXL_CM_CAP_HDR_CACHE_MEM_VERSION_MASK GENMASK(23, 20)
|
|
|
|
#define CM_CAP_HDR_CACHE_MEM_VERSION 1
|
|
|
|
#define CXL_CM_CAP_HDR_ARRAY_SIZE_MASK GENMASK(31, 24)
|
|
|
|
#define CXL_CM_CAP_PTR_MASK GENMASK(31, 20)
|
|
|
|
|
|
|
|
#define CXL_CM_CAP_CAP_ID_HDM 0x5
|
|
|
|
#define CXL_CM_CAP_CAP_HDM_VERSION 1
|
|
|
|
|
|
|
|
/* HDM decoders CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure */
|
|
|
|
#define CXL_HDM_DECODER_CAP_OFFSET 0x0
|
|
|
|
#define CXL_HDM_DECODER_COUNT_MASK GENMASK(3, 0)
|
|
|
|
#define CXL_HDM_DECODER_TARGET_COUNT_MASK GENMASK(7, 4)
|
|
|
|
#define CXL_HDM_DECODER0_BASE_LOW_OFFSET 0x10
|
|
|
|
#define CXL_HDM_DECODER0_BASE_HIGH_OFFSET 0x14
|
|
|
|
#define CXL_HDM_DECODER0_SIZE_LOW_OFFSET 0x18
|
|
|
|
#define CXL_HDM_DECODER0_SIZE_HIGH_OFFSET 0x1c
|
|
|
|
#define CXL_HDM_DECODER0_CTRL_OFFSET 0x20
|
|
|
|
|
2021-02-17 07:09:51 +03:00
|
|
|
/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
|
|
|
|
#define CXLDEV_CAP_ARRAY_OFFSET 0x0
|
|
|
|
#define CXLDEV_CAP_ARRAY_CAP_ID 0
|
|
|
|
#define CXLDEV_CAP_ARRAY_ID_MASK GENMASK_ULL(15, 0)
|
|
|
|
#define CXLDEV_CAP_ARRAY_COUNT_MASK GENMASK_ULL(47, 32)
|
|
|
|
/* CXL 2.0 8.2.8.2 CXL Device Capability Header Register */
|
|
|
|
#define CXLDEV_CAP_HDR_CAP_ID_MASK GENMASK(15, 0)
|
|
|
|
/* CXL 2.0 8.2.8.2.1 CXL Device Capabilities */
|
|
|
|
#define CXLDEV_CAP_CAP_ID_DEVICE_STATUS 0x1
|
|
|
|
#define CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX 0x2
|
|
|
|
#define CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX 0x3
|
|
|
|
#define CXLDEV_CAP_CAP_ID_MEMDEV 0x4000
|
|
|
|
|
|
|
|
/* CXL 2.0 8.2.8.4 Mailbox Registers */
|
|
|
|
#define CXLDEV_MBOX_CAPS_OFFSET 0x00
|
|
|
|
#define CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK GENMASK(4, 0)
|
|
|
|
#define CXLDEV_MBOX_CTRL_OFFSET 0x04
|
|
|
|
#define CXLDEV_MBOX_CTRL_DOORBELL BIT(0)
|
|
|
|
#define CXLDEV_MBOX_CMD_OFFSET 0x08
|
|
|
|
#define CXLDEV_MBOX_CMD_COMMAND_OPCODE_MASK GENMASK_ULL(15, 0)
|
|
|
|
#define CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK GENMASK_ULL(36, 16)
|
|
|
|
#define CXLDEV_MBOX_STATUS_OFFSET 0x10
|
|
|
|
#define CXLDEV_MBOX_STATUS_RET_CODE_MASK GENMASK_ULL(47, 32)
|
|
|
|
#define CXLDEV_MBOX_BG_CMD_STATUS_OFFSET 0x18
|
|
|
|
#define CXLDEV_MBOX_PAYLOAD_OFFSET 0x20
|
|
|
|
|
2021-05-28 03:49:22 +03:00
|
|
|
#define CXL_COMPONENT_REGS() \
|
|
|
|
void __iomem *hdm_decoder
|
|
|
|
|
cxl/mem: Introduce 'struct cxl_regs' for "composable" CXL devices
CXL MMIO register blocks are organized by device type and capabilities.
There are Component registers, Device registers (yes, an ambiguous
name), and Memory Device registers (a specific extension of Device
registers).
It is possible for a given device instance (endpoint or port) to
implement register sets from multiple of the above categories.
The driver code that enumerates and maps the registers is type specific
so it is useful to have a dedicated type and helpers for each block
type.
At the same time, once the registers are mapped the origin type does not
matter. It is overly pedantic to reference the register block type in
code that is using the registers.
In preparation for the endpoint driver to incorporate Component registers
into its MMIO operations reorganize the registers to allow typed
enumeration + mapping, but anonymous usage. With the end state of
'struct cxl_regs' to be:
struct cxl_regs {
union {
struct {
CXL_DEVICE_REGS();
};
struct cxl_device_regs device_regs;
};
union {
struct {
CXL_COMPONENT_REGS();
};
struct cxl_component_regs component_regs;
};
};
With this arrangement the driver can share component init code with
ports, but when using the registers it can directly reference the
component register block type by name without the 'component_regs'
prefix.
So, map + enumerate can be shared across drivers of different CXL
classes e.g.:
void cxl_setup_device_regs(struct device *dev, void __iomem *base,
struct cxl_device_regs *regs);
void cxl_setup_component_regs(struct device *dev, void __iomem *base,
struct cxl_component_regs *regs);
...while inline usage in the driver need not indicate where the
registers came from:
readl(cxlm->regs.mbox + MBOX_OFFSET);
readl(cxlm->regs.hdm + HDM_OFFSET);
...instead of:
readl(cxlm->regs.device_regs.mbox + MBOX_OFFSET);
readl(cxlm->regs.component_regs.hdm + HDM_OFFSET);
This complexity of the definition in .h yields improvement in code
readability in .c while maintaining type-safety for organization of
setup code. It prepares the implementation to maintain organization in
the face of CXL devices that compose register interfaces consisting of
multiple types.
Given that this new container is named 'regs' rename the common register
base pointer @base, and fixup the kernel-doc for the missing @cxlmd
description.
Reviewed-by: Ben Widawsky <ben.widawsky@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/162096971451.1865304.13540251513463515153.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2021-05-14 08:21:54 +03:00
|
|
|
#define CXL_DEVICE_REGS() \
|
|
|
|
void __iomem *status; \
|
|
|
|
void __iomem *mbox; \
|
|
|
|
void __iomem *memdev
|
|
|
|
|
|
|
|
/* See note for 'struct cxl_regs' for the rationale of this organization */
|
2021-05-28 03:49:22 +03:00
|
|
|
/*
|
|
|
|
* CXL_COMPONENT_REGS - Common set of CXL Component register block base pointers
|
|
|
|
* @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure
|
|
|
|
*/
|
|
|
|
struct cxl_component_regs {
|
|
|
|
CXL_COMPONENT_REGS();
|
|
|
|
};
|
|
|
|
|
|
|
|
/* See note for 'struct cxl_regs' for the rationale of this organization */
|
|
|
|
/*
|
|
|
|
* CXL_DEVICE_REGS - Common set of CXL Device register block base pointers
|
|
|
|
* @status: CXL 2.0 8.2.8.3 Device Status Registers
|
|
|
|
* @mbox: CXL 2.0 8.2.8.4 Mailbox Registers
|
|
|
|
* @memdev: CXL 2.0 8.2.8.5 Memory Device Registers
|
|
|
|
*/
|
cxl/mem: Introduce 'struct cxl_regs' for "composable" CXL devices
CXL MMIO register blocks are organized by device type and capabilities.
There are Component registers, Device registers (yes, an ambiguous
name), and Memory Device registers (a specific extension of Device
registers).
It is possible for a given device instance (endpoint or port) to
implement register sets from multiple of the above categories.
The driver code that enumerates and maps the registers is type specific
so it is useful to have a dedicated type and helpers for each block
type.
At the same time, once the registers are mapped the origin type does not
matter. It is overly pedantic to reference the register block type in
code that is using the registers.
In preparation for the endpoint driver to incorporate Component registers
into its MMIO operations reorganize the registers to allow typed
enumeration + mapping, but anonymous usage. With the end state of
'struct cxl_regs' to be:
struct cxl_regs {
union {
struct {
CXL_DEVICE_REGS();
};
struct cxl_device_regs device_regs;
};
union {
struct {
CXL_COMPONENT_REGS();
};
struct cxl_component_regs component_regs;
};
};
With this arrangement the driver can share component init code with
ports, but when using the registers it can directly reference the
component register block type by name without the 'component_regs'
prefix.
So, map + enumerate can be shared across drivers of different CXL
classes e.g.:
void cxl_setup_device_regs(struct device *dev, void __iomem *base,
struct cxl_device_regs *regs);
void cxl_setup_component_regs(struct device *dev, void __iomem *base,
struct cxl_component_regs *regs);
...while inline usage in the driver need not indicate where the
registers came from:
readl(cxlm->regs.mbox + MBOX_OFFSET);
readl(cxlm->regs.hdm + HDM_OFFSET);
...instead of:
readl(cxlm->regs.device_regs.mbox + MBOX_OFFSET);
readl(cxlm->regs.component_regs.hdm + HDM_OFFSET);
This complexity of the definition in .h yields improvement in code
readability in .c while maintaining type-safety for organization of
setup code. It prepares the implementation to maintain organization in
the face of CXL devices that compose register interfaces consisting of
multiple types.
Given that this new container is named 'regs' rename the common register
base pointer @base, and fixup the kernel-doc for the missing @cxlmd
description.
Reviewed-by: Ben Widawsky <ben.widawsky@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/162096971451.1865304.13540251513463515153.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2021-05-14 08:21:54 +03:00
|
|
|
struct cxl_device_regs {
|
|
|
|
CXL_DEVICE_REGS();
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note, the anonymous union organization allows for per
|
|
|
|
* register-block-type helper routines, without requiring block-type
|
2021-06-04 03:50:36 +03:00
|
|
|
* agnostic code to include the prefix.
|
cxl/mem: Introduce 'struct cxl_regs' for "composable" CXL devices
CXL MMIO register blocks are organized by device type and capabilities.
There are Component registers, Device registers (yes, an ambiguous
name), and Memory Device registers (a specific extension of Device
registers).
It is possible for a given device instance (endpoint or port) to
implement register sets from multiple of the above categories.
The driver code that enumerates and maps the registers is type specific
so it is useful to have a dedicated type and helpers for each block
type.
At the same time, once the registers are mapped the origin type does not
matter. It is overly pedantic to reference the register block type in
code that is using the registers.
In preparation for the endpoint driver to incorporate Component registers
into its MMIO operations reorganize the registers to allow typed
enumeration + mapping, but anonymous usage. With the end state of
'struct cxl_regs' to be:
struct cxl_regs {
union {
struct {
CXL_DEVICE_REGS();
};
struct cxl_device_regs device_regs;
};
union {
struct {
CXL_COMPONENT_REGS();
};
struct cxl_component_regs component_regs;
};
};
With this arrangement the driver can share component init code with
ports, but when using the registers it can directly reference the
component register block type by name without the 'component_regs'
prefix.
So, map + enumerate can be shared across drivers of different CXL
classes e.g.:
void cxl_setup_device_regs(struct device *dev, void __iomem *base,
struct cxl_device_regs *regs);
void cxl_setup_component_regs(struct device *dev, void __iomem *base,
struct cxl_component_regs *regs);
...while inline usage in the driver need not indicate where the
registers came from:
readl(cxlm->regs.mbox + MBOX_OFFSET);
readl(cxlm->regs.hdm + HDM_OFFSET);
...instead of:
readl(cxlm->regs.device_regs.mbox + MBOX_OFFSET);
readl(cxlm->regs.component_regs.hdm + HDM_OFFSET);
This complexity of the definition in .h yields improvement in code
readability in .c while maintaining type-safety for organization of
setup code. It prepares the implementation to maintain organization in
the face of CXL devices that compose register interfaces consisting of
multiple types.
Given that this new container is named 'regs' rename the common register
base pointer @base, and fixup the kernel-doc for the missing @cxlmd
description.
Reviewed-by: Ben Widawsky <ben.widawsky@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/162096971451.1865304.13540251513463515153.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2021-05-14 08:21:54 +03:00
|
|
|
*/
|
|
|
|
struct cxl_regs {
|
2021-05-28 03:49:22 +03:00
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
CXL_COMPONENT_REGS();
|
|
|
|
};
|
|
|
|
struct cxl_component_regs component;
|
|
|
|
};
|
cxl/mem: Introduce 'struct cxl_regs' for "composable" CXL devices
CXL MMIO register blocks are organized by device type and capabilities.
There are Component registers, Device registers (yes, an ambiguous
name), and Memory Device registers (a specific extension of Device
registers).
It is possible for a given device instance (endpoint or port) to
implement register sets from multiple of the above categories.
The driver code that enumerates and maps the registers is type specific
so it is useful to have a dedicated type and helpers for each block
type.
At the same time, once the registers are mapped the origin type does not
matter. It is overly pedantic to reference the register block type in
code that is using the registers.
In preparation for the endpoint driver to incorporate Component registers
into its MMIO operations reorganize the registers to allow typed
enumeration + mapping, but anonymous usage. With the end state of
'struct cxl_regs' to be:
struct cxl_regs {
union {
struct {
CXL_DEVICE_REGS();
};
struct cxl_device_regs device_regs;
};
union {
struct {
CXL_COMPONENT_REGS();
};
struct cxl_component_regs component_regs;
};
};
With this arrangement the driver can share component init code with
ports, but when using the registers it can directly reference the
component register block type by name without the 'component_regs'
prefix.
So, map + enumerate can be shared across drivers of different CXL
classes e.g.:
void cxl_setup_device_regs(struct device *dev, void __iomem *base,
struct cxl_device_regs *regs);
void cxl_setup_component_regs(struct device *dev, void __iomem *base,
struct cxl_component_regs *regs);
...while inline usage in the driver need not indicate where the
registers came from:
readl(cxlm->regs.mbox + MBOX_OFFSET);
readl(cxlm->regs.hdm + HDM_OFFSET);
...instead of:
readl(cxlm->regs.device_regs.mbox + MBOX_OFFSET);
readl(cxlm->regs.component_regs.hdm + HDM_OFFSET);
This complexity of the definition in .h yields improvement in code
readability in .c while maintaining type-safety for organization of
setup code. It prepares the implementation to maintain organization in
the face of CXL devices that compose register interfaces consisting of
multiple types.
Given that this new container is named 'regs' rename the common register
base pointer @base, and fixup the kernel-doc for the missing @cxlmd
description.
Reviewed-by: Ben Widawsky <ben.widawsky@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/162096971451.1865304.13540251513463515153.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2021-05-14 08:21:54 +03:00
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
CXL_DEVICE_REGS();
|
|
|
|
};
|
|
|
|
struct cxl_device_regs device_regs;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2021-06-04 03:50:36 +03:00
|
|
|
struct cxl_reg_map {
|
|
|
|
bool valid;
|
|
|
|
unsigned long offset;
|
|
|
|
unsigned long size;
|
|
|
|
};
|
|
|
|
|
2021-05-28 03:49:22 +03:00
|
|
|
struct cxl_component_reg_map {
|
|
|
|
struct cxl_reg_map hdm_decoder;
|
|
|
|
};
|
|
|
|
|
2021-06-04 03:50:36 +03:00
|
|
|
struct cxl_device_reg_map {
|
|
|
|
struct cxl_reg_map status;
|
|
|
|
struct cxl_reg_map mbox;
|
|
|
|
struct cxl_reg_map memdev;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct cxl_register_map {
|
|
|
|
struct list_head list;
|
|
|
|
u64 block_offset;
|
|
|
|
u8 reg_type;
|
|
|
|
u8 barno;
|
|
|
|
union {
|
2021-05-28 03:49:22 +03:00
|
|
|
struct cxl_component_reg_map component_map;
|
2021-06-04 03:50:36 +03:00
|
|
|
struct cxl_device_reg_map device_map;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2021-05-28 03:49:22 +03:00
|
|
|
void cxl_probe_component_regs(struct device *dev, void __iomem *base,
|
|
|
|
struct cxl_component_reg_map *map);
|
2021-06-04 03:50:36 +03:00
|
|
|
void cxl_probe_device_regs(struct device *dev, void __iomem *base,
|
|
|
|
struct cxl_device_reg_map *map);
|
2021-05-28 03:49:22 +03:00
|
|
|
int cxl_map_component_regs(struct pci_dev *pdev,
|
|
|
|
struct cxl_component_regs *regs,
|
|
|
|
struct cxl_register_map *map);
|
2021-06-04 03:50:36 +03:00
|
|
|
int cxl_map_device_regs(struct pci_dev *pdev,
|
|
|
|
struct cxl_device_regs *regs,
|
|
|
|
struct cxl_register_map *map);
|
2021-05-14 08:22:05 +03:00
|
|
|
|
2021-02-17 07:09:52 +03:00
|
|
|
extern struct bus_type cxl_bus_type;
|
2021-02-17 07:09:51 +03:00
|
|
|
#endif /* __CXL_H__ */
|