cxl/pci: Find and register CXL PMU devices
CXL PMU devices can be found from entries in the Register Locator DVSEC. Reviewed-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Link: https://lore.kernel.org/r/20230526095824.16336-4-Jonathan.Cameron@huawei.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
d717d7f3df
commit
1ad3f701c3
|
@ -12,5 +12,6 @@ cxl_core-y += memdev.o
|
||||||
cxl_core-y += mbox.o
|
cxl_core-y += mbox.o
|
||||||
cxl_core-y += pci.o
|
cxl_core-y += pci.o
|
||||||
cxl_core-y += hdm.o
|
cxl_core-y += hdm.o
|
||||||
|
cxl_core-y += pmu.o
|
||||||
cxl_core-$(CONFIG_TRACING) += trace.o
|
cxl_core-$(CONFIG_TRACING) += trace.o
|
||||||
cxl_core-$(CONFIG_CXL_REGION) += region.o
|
cxl_core-$(CONFIG_CXL_REGION) += region.o
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
extern const struct device_type cxl_nvdimm_bridge_type;
|
extern const struct device_type cxl_nvdimm_bridge_type;
|
||||||
extern const struct device_type cxl_nvdimm_type;
|
extern const struct device_type cxl_nvdimm_type;
|
||||||
|
extern const struct device_type cxl_pmu_type;
|
||||||
|
|
||||||
extern struct attribute_group cxl_base_attribute_group;
|
extern struct attribute_group cxl_base_attribute_group;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/* Copyright(c) 2023 Huawei. All rights reserved. */
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
|
#include <cxlmem.h>
|
||||||
|
#include <pmu.h>
|
||||||
|
#include <cxl.h>
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
static void cxl_pmu_release(struct device *dev)
|
||||||
|
{
|
||||||
|
struct cxl_pmu *pmu = to_cxl_pmu(dev);
|
||||||
|
|
||||||
|
kfree(pmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct device_type cxl_pmu_type = {
|
||||||
|
.name = "cxl_pmu",
|
||||||
|
.release = cxl_pmu_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void remove_dev(void *dev)
|
||||||
|
{
|
||||||
|
device_del(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int devm_cxl_pmu_add(struct device *parent, struct cxl_pmu_regs *regs,
|
||||||
|
int assoc_id, int index, enum cxl_pmu_type type)
|
||||||
|
{
|
||||||
|
struct cxl_pmu *pmu;
|
||||||
|
struct device *dev;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
|
||||||
|
if (!pmu)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pmu->assoc_id = assoc_id;
|
||||||
|
pmu->index = index;
|
||||||
|
pmu->type = type;
|
||||||
|
pmu->base = regs->pmu;
|
||||||
|
dev = &pmu->dev;
|
||||||
|
device_initialize(dev);
|
||||||
|
device_set_pm_not_required(dev);
|
||||||
|
dev->parent = parent;
|
||||||
|
dev->bus = &cxl_bus_type;
|
||||||
|
dev->type = &cxl_pmu_type;
|
||||||
|
switch (pmu->type) {
|
||||||
|
case CXL_PMU_MEMDEV:
|
||||||
|
rc = dev_set_name(dev, "pmu_mem%d.%d", assoc_id, index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rc)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
rc = device_add(dev);
|
||||||
|
if (rc)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return devm_add_action_or_reset(parent, remove_dev, dev);
|
||||||
|
|
||||||
|
err:
|
||||||
|
put_device(&pmu->dev);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS_GPL(devm_cxl_pmu_add, CXL);
|
|
@ -56,6 +56,8 @@ static int cxl_device_id(const struct device *dev)
|
||||||
return CXL_DEVICE_MEMORY_EXPANDER;
|
return CXL_DEVICE_MEMORY_EXPANDER;
|
||||||
if (dev->type == CXL_REGION_TYPE())
|
if (dev->type == CXL_REGION_TYPE())
|
||||||
return CXL_DEVICE_REGION;
|
return CXL_DEVICE_REGION;
|
||||||
|
if (dev->type == &cxl_pmu_type)
|
||||||
|
return CXL_DEVICE_PMU;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <cxlmem.h>
|
#include <cxlmem.h>
|
||||||
#include <cxlpci.h>
|
#include <cxlpci.h>
|
||||||
|
#include <pmu.h>
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
|
||||||
|
@ -379,6 +380,21 @@ int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS_GPL(cxl_count_regblock, CXL);
|
EXPORT_SYMBOL_NS_GPL(cxl_count_regblock, CXL);
|
||||||
|
|
||||||
|
int cxl_map_pmu_regs(struct pci_dev *pdev, struct cxl_pmu_regs *regs,
|
||||||
|
struct cxl_register_map *map)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
resource_size_t phys_addr;
|
||||||
|
|
||||||
|
phys_addr = map->resource;
|
||||||
|
regs->pmu = devm_cxl_iomap_block(dev, phys_addr, CXL_PMU_REGMAP_SIZE);
|
||||||
|
if (!regs->pmu)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS_GPL(cxl_map_pmu_regs, CXL);
|
||||||
|
|
||||||
resource_size_t cxl_rcrb_to_component(struct device *dev,
|
resource_size_t cxl_rcrb_to_component(struct device *dev,
|
||||||
resource_size_t rcrb,
|
resource_size_t rcrb,
|
||||||
enum cxl_rcrb which)
|
enum cxl_rcrb which)
|
||||||
|
|
|
@ -209,6 +209,10 @@ struct cxl_regs {
|
||||||
struct_group_tagged(cxl_device_regs, device_regs,
|
struct_group_tagged(cxl_device_regs, device_regs,
|
||||||
void __iomem *status, *mbox, *memdev;
|
void __iomem *status, *mbox, *memdev;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
struct_group_tagged(cxl_pmu_regs, pmu_regs,
|
||||||
|
void __iomem *pmu;
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cxl_reg_map {
|
struct cxl_reg_map {
|
||||||
|
@ -229,6 +233,10 @@ struct cxl_device_reg_map {
|
||||||
struct cxl_reg_map memdev;
|
struct cxl_reg_map memdev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cxl_pmu_reg_map {
|
||||||
|
struct cxl_reg_map pmu;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct cxl_register_map - DVSEC harvested register block mapping parameters
|
* struct cxl_register_map - DVSEC harvested register block mapping parameters
|
||||||
* @base: virtual base of the register-block-BAR + @block_offset
|
* @base: virtual base of the register-block-BAR + @block_offset
|
||||||
|
@ -237,6 +245,7 @@ struct cxl_device_reg_map {
|
||||||
* @reg_type: see enum cxl_regloc_type
|
* @reg_type: see enum cxl_regloc_type
|
||||||
* @component_map: cxl_reg_map for component registers
|
* @component_map: cxl_reg_map for component registers
|
||||||
* @device_map: cxl_reg_maps for device registers
|
* @device_map: cxl_reg_maps for device registers
|
||||||
|
* @pmu_map: cxl_reg_maps for CXL Performance Monitoring Units
|
||||||
*/
|
*/
|
||||||
struct cxl_register_map {
|
struct cxl_register_map {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
@ -246,6 +255,7 @@ struct cxl_register_map {
|
||||||
union {
|
union {
|
||||||
struct cxl_component_reg_map component_map;
|
struct cxl_component_reg_map component_map;
|
||||||
struct cxl_device_reg_map device_map;
|
struct cxl_device_reg_map device_map;
|
||||||
|
struct cxl_pmu_reg_map pmu_map;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -258,6 +268,8 @@ int cxl_map_component_regs(struct device *dev, struct cxl_component_regs *regs,
|
||||||
unsigned long map_mask);
|
unsigned long map_mask);
|
||||||
int cxl_map_device_regs(struct device *dev, struct cxl_device_regs *regs,
|
int cxl_map_device_regs(struct device *dev, struct cxl_device_regs *regs,
|
||||||
struct cxl_register_map *map);
|
struct cxl_register_map *map);
|
||||||
|
int cxl_map_pmu_regs(struct pci_dev *pdev, struct cxl_pmu_regs *regs,
|
||||||
|
struct cxl_register_map *map);
|
||||||
|
|
||||||
enum cxl_regloc_type;
|
enum cxl_regloc_type;
|
||||||
int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type);
|
int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type);
|
||||||
|
@ -753,6 +765,7 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv);
|
||||||
#define CXL_DEVICE_REGION 6
|
#define CXL_DEVICE_REGION 6
|
||||||
#define CXL_DEVICE_PMEM_REGION 7
|
#define CXL_DEVICE_PMEM_REGION 7
|
||||||
#define CXL_DEVICE_DAX_REGION 8
|
#define CXL_DEVICE_DAX_REGION 8
|
||||||
|
#define CXL_DEVICE_PMU 9
|
||||||
|
|
||||||
#define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
|
#define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
|
||||||
#define CXL_MODALIAS_FMT "cxl:t%d"
|
#define CXL_MODALIAS_FMT "cxl:t%d"
|
||||||
|
|
|
@ -67,6 +67,7 @@ enum cxl_regloc_type {
|
||||||
CXL_REGLOC_RBI_COMPONENT,
|
CXL_REGLOC_RBI_COMPONENT,
|
||||||
CXL_REGLOC_RBI_VIRT,
|
CXL_REGLOC_RBI_VIRT,
|
||||||
CXL_REGLOC_RBI_MEMDEV,
|
CXL_REGLOC_RBI_MEMDEV,
|
||||||
|
CXL_REGLOC_RBI_PMU,
|
||||||
CXL_REGLOC_RBI_TYPES
|
CXL_REGLOC_RBI_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "cxlmem.h"
|
#include "cxlmem.h"
|
||||||
#include "cxlpci.h"
|
#include "cxlpci.h"
|
||||||
#include "cxl.h"
|
#include "cxl.h"
|
||||||
|
#include "pmu.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: cxl pci
|
* DOC: cxl pci
|
||||||
|
@ -657,7 +658,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
struct cxl_register_map map;
|
struct cxl_register_map map;
|
||||||
struct cxl_memdev *cxlmd;
|
struct cxl_memdev *cxlmd;
|
||||||
struct cxl_dev_state *cxlds;
|
struct cxl_dev_state *cxlds;
|
||||||
int rc;
|
int i, rc, pmu_count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Double check the anonymous union trickery in struct cxl_regs
|
* Double check the anonymous union trickery in struct cxl_regs
|
||||||
|
@ -746,6 +747,29 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
if (IS_ERR(cxlmd))
|
if (IS_ERR(cxlmd))
|
||||||
return PTR_ERR(cxlmd);
|
return PTR_ERR(cxlmd);
|
||||||
|
|
||||||
|
pmu_count = cxl_count_regblock(pdev, CXL_REGLOC_RBI_PMU);
|
||||||
|
for (i = 0; i < pmu_count; i++) {
|
||||||
|
struct cxl_pmu_regs pmu_regs;
|
||||||
|
|
||||||
|
rc = cxl_find_regblock_instance(pdev, CXL_REGLOC_RBI_PMU, &map, i);
|
||||||
|
if (rc) {
|
||||||
|
dev_dbg(&pdev->dev, "Could not find PMU regblock\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cxl_map_pmu_regs(pdev, &pmu_regs, &map);
|
||||||
|
if (rc) {
|
||||||
|
dev_dbg(&pdev->dev, "Could not map PMU regs\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = devm_cxl_pmu_add(cxlds->dev, &pmu_regs, cxlmd->id, i, CXL_PMU_MEMDEV);
|
||||||
|
if (rc) {
|
||||||
|
dev_dbg(&pdev->dev, "Could not add PMU instance\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rc = cxl_event_config(host_bridge, cxlds);
|
rc = cxl_event_config(host_bridge, cxlds);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Copyright(c) 2023 Huawei
|
||||||
|
* CXL Specification rev 3.0 Setion 8.2.7 (CPMU Register Interface)
|
||||||
|
*/
|
||||||
|
#ifndef CXL_PMU_H
|
||||||
|
#define CXL_PMU_H
|
||||||
|
#include <linux/device.h>
|
||||||
|
|
||||||
|
enum cxl_pmu_type {
|
||||||
|
CXL_PMU_MEMDEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CXL_PMU_REGMAP_SIZE 0xe00 /* Table 8-32 CXL 3.0 specification */
|
||||||
|
struct cxl_pmu {
|
||||||
|
struct device dev;
|
||||||
|
void __iomem *base;
|
||||||
|
int assoc_id;
|
||||||
|
int index;
|
||||||
|
enum cxl_pmu_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_cxl_pmu(dev) container_of(dev, struct cxl_pmu, dev)
|
||||||
|
struct cxl_pmu_regs;
|
||||||
|
int devm_cxl_pmu_add(struct device *parent, struct cxl_pmu_regs *regs,
|
||||||
|
int assoc_id, int idx, enum cxl_pmu_type type);
|
||||||
|
|
||||||
|
#endif
|
|
@ -57,6 +57,7 @@ cxl_core-y += $(CXL_CORE_SRC)/memdev.o
|
||||||
cxl_core-y += $(CXL_CORE_SRC)/mbox.o
|
cxl_core-y += $(CXL_CORE_SRC)/mbox.o
|
||||||
cxl_core-y += $(CXL_CORE_SRC)/pci.o
|
cxl_core-y += $(CXL_CORE_SRC)/pci.o
|
||||||
cxl_core-y += $(CXL_CORE_SRC)/hdm.o
|
cxl_core-y += $(CXL_CORE_SRC)/hdm.o
|
||||||
|
cxl_core-y += $(CXL_CORE_SRC)/pmu.o
|
||||||
cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o
|
cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o
|
||||||
cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o
|
cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o
|
||||||
cxl_core-y += config_check.o
|
cxl_core-y += config_check.o
|
||||||
|
|
Loading…
Reference in New Issue