1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This file contains functions to handle discovery of PMC metrics located
4  * in the PMC SSRAM PCI device.
5  *
6  * Copyright (c) 2023, Intel Corporation.
7  * All Rights Reserved.
8  *
9  */
10 
11 #include <linux/pci.h>
12 #include <linux/io-64-nonatomic-lo-hi.h>
13 
14 #include "core.h"
15 
16 #define SSRAM_HDR_SIZE		0x100
17 #define SSRAM_PWRM_OFFSET	0x14
18 #define SSRAM_DVSEC_OFFSET	0x1C
19 #define SSRAM_DVSEC_SIZE	0x10
20 #define SSRAM_PCH_OFFSET	0x60
21 #define SSRAM_IOE_OFFSET	0x68
22 #define SSRAM_DEVID_OFFSET	0x70
23 
pmc_core_find_regmap(struct pmc_info * list,u16 devid)24 static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid)
25 {
26 	for (; list->map; ++list)
27 		if (devid == list->devid)
28 			return list->map;
29 
30 	return NULL;
31 }
32 
get_base(void __iomem * addr,u32 offset)33 static inline u64 get_base(void __iomem *addr, u32 offset)
34 {
35 	return lo_hi_readq(addr + offset) & GENMASK_ULL(63, 3);
36 }
37 
38 static void
pmc_core_pmc_add(struct pmc_dev * pmcdev,u64 pwrm_base,const struct pmc_reg_map * reg_map,int pmc_index)39 pmc_core_pmc_add(struct pmc_dev *pmcdev, u64 pwrm_base,
40 		 const struct pmc_reg_map *reg_map, int pmc_index)
41 {
42 	struct pmc *pmc = pmcdev->pmcs[pmc_index];
43 
44 	if (!pwrm_base)
45 		return;
46 
47 	/* Memory for primary PMC has been allocated in core.c */
48 	if (!pmc) {
49 		pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL);
50 		if (!pmc)
51 			return;
52 	}
53 
54 	pmc->map = reg_map;
55 	pmc->base_addr = pwrm_base;
56 	pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length);
57 
58 	if (!pmc->regbase) {
59 		devm_kfree(&pmcdev->pdev->dev, pmc);
60 		return;
61 	}
62 
63 	pmcdev->pmcs[pmc_index] = pmc;
64 }
65 
66 static void
pmc_core_ssram_get_pmc(struct pmc_dev * pmcdev,void __iomem * ssram,u32 offset,int pmc_idx)67 pmc_core_ssram_get_pmc(struct pmc_dev *pmcdev, void __iomem *ssram, u32 offset,
68 		       int pmc_idx)
69 {
70 	u64 pwrm_base;
71 	u16 devid;
72 
73 	if (pmc_idx != PMC_IDX_SOC) {
74 		u64 ssram_base = get_base(ssram, offset);
75 
76 		if (!ssram_base)
77 			return;
78 
79 		ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
80 		if (!ssram)
81 			return;
82 	}
83 
84 	pwrm_base = get_base(ssram, SSRAM_PWRM_OFFSET);
85 	devid = readw(ssram + SSRAM_DEVID_OFFSET);
86 
87 	if (pmcdev->regmap_list) {
88 		const struct pmc_reg_map *map;
89 
90 		map = pmc_core_find_regmap(pmcdev->regmap_list, devid);
91 		if (map)
92 			pmc_core_pmc_add(pmcdev, pwrm_base, map, pmc_idx);
93 	}
94 
95 	if (pmc_idx != PMC_IDX_SOC)
96 		iounmap(ssram);
97 }
98 
pmc_core_ssram_init(struct pmc_dev * pmcdev)99 void pmc_core_ssram_init(struct pmc_dev *pmcdev)
100 {
101 	void __iomem *ssram;
102 	struct pci_dev *pcidev;
103 	u64 ssram_base;
104 	int ret;
105 
106 	pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, 2));
107 	if (!pcidev)
108 		goto out;
109 
110 	ret = pcim_enable_device(pcidev);
111 	if (ret)
112 		goto release_dev;
113 
114 	ssram_base = pcidev->resource[0].start;
115 	ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
116 	if (!ssram)
117 		goto disable_dev;
118 
119 	pmcdev->ssram_pcidev = pcidev;
120 
121 	pmc_core_ssram_get_pmc(pmcdev, ssram, 0, PMC_IDX_SOC);
122 	pmc_core_ssram_get_pmc(pmcdev, ssram, SSRAM_IOE_OFFSET, PMC_IDX_IOE);
123 	pmc_core_ssram_get_pmc(pmcdev, ssram, SSRAM_PCH_OFFSET, PMC_IDX_PCH);
124 
125 	iounmap(ssram);
126 out:
127 	return;
128 
129 disable_dev:
130 	pci_disable_device(pcidev);
131 release_dev:
132 	pci_dev_put(pcidev);
133 }
134