1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * processor thermal device RFIM control
4 * Copyright (c) 2020, Intel Corporation.
5 */
6
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/pci.h>
10 #include "processor_thermal_device.h"
11
12 static struct rapl_if_priv rapl_mmio_priv;
13
14 static const struct rapl_mmio_regs rapl_mmio_default = {
15 .reg_unit = 0x5938,
16 .regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930, 0x59b0},
17 .regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
18 .limits[RAPL_DOMAIN_PACKAGE] = BIT(POWER_LIMIT2) | BIT(POWER_LIMIT4),
19 .limits[RAPL_DOMAIN_DRAM] = BIT(POWER_LIMIT2),
20 };
21
rapl_mmio_read_raw(int cpu,struct reg_action * ra)22 static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
23 {
24 if (!ra->reg.mmio)
25 return -EINVAL;
26
27 ra->value = readq(ra->reg.mmio);
28 ra->value &= ra->mask;
29 return 0;
30 }
31
rapl_mmio_write_raw(int cpu,struct reg_action * ra)32 static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
33 {
34 u64 val;
35
36 if (!ra->reg.mmio)
37 return -EINVAL;
38
39 val = readq(ra->reg.mmio);
40 val &= ~ra->mask;
41 val |= ra->value;
42 writeq(val, ra->reg.mmio);
43 return 0;
44 }
45
proc_thermal_rapl_add(struct pci_dev * pdev,struct proc_thermal_device * proc_priv)46 int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
47 {
48 const struct rapl_mmio_regs *rapl_regs = &rapl_mmio_default;
49 struct rapl_package *rp;
50 enum rapl_domain_reg_id reg;
51 enum rapl_domain_type domain;
52 int ret;
53
54 if (!rapl_regs)
55 return 0;
56
57 for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) {
58 for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++)
59 if (rapl_regs->regs[domain][reg])
60 rapl_mmio_priv.regs[domain][reg].mmio =
61 proc_priv->mmio_base +
62 rapl_regs->regs[domain][reg];
63 rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain];
64 }
65 rapl_mmio_priv.type = RAPL_IF_MMIO;
66 rapl_mmio_priv.reg_unit.mmio = proc_priv->mmio_base + rapl_regs->reg_unit;
67
68 rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
69 rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
70
71 rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
72 if (IS_ERR(rapl_mmio_priv.control_type)) {
73 pr_debug("failed to register powercap control_type.\n");
74 return PTR_ERR(rapl_mmio_priv.control_type);
75 }
76
77 /* Register a RAPL package device for package 0 which is always online */
78 rp = rapl_find_package_domain(0, &rapl_mmio_priv, false);
79 if (rp) {
80 ret = -EEXIST;
81 goto err;
82 }
83
84 rp = rapl_add_package(0, &rapl_mmio_priv, false);
85 if (IS_ERR(rp)) {
86 ret = PTR_ERR(rp);
87 goto err;
88 }
89
90 return 0;
91
92 err:
93 powercap_unregister_control_type(rapl_mmio_priv.control_type);
94 rapl_mmio_priv.control_type = NULL;
95 return ret;
96 }
97 EXPORT_SYMBOL_GPL(proc_thermal_rapl_add);
98
proc_thermal_rapl_remove(void)99 void proc_thermal_rapl_remove(void)
100 {
101 struct rapl_package *rp;
102
103 if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
104 return;
105
106 rp = rapl_find_package_domain(0, &rapl_mmio_priv, false);
107 if (rp)
108 rapl_remove_package(rp);
109 powercap_unregister_control_type(rapl_mmio_priv.control_type);
110 }
111 EXPORT_SYMBOL_GPL(proc_thermal_rapl_remove);
112
113 MODULE_LICENSE("GPL v2");
114 MODULE_DESCRIPTION("RAPL interface using MMIO");
115