19eef7f9dSZhang Rui // SPDX-License-Identifier: GPL-2.0-only
29eef7f9dSZhang Rui /*
39eef7f9dSZhang Rui  * intel_rapl_tpmi: Intel RAPL driver via TPMI interface
49eef7f9dSZhang Rui  *
59eef7f9dSZhang Rui  * Copyright (c) 2023, Intel Corporation.
69eef7f9dSZhang Rui  * All Rights Reserved.
79eef7f9dSZhang Rui  *
89eef7f9dSZhang Rui  */
99eef7f9dSZhang Rui #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
109eef7f9dSZhang Rui 
119eef7f9dSZhang Rui #include <linux/auxiliary_bus.h>
129eef7f9dSZhang Rui #include <linux/io.h>
139eef7f9dSZhang Rui #include <linux/intel_tpmi.h>
149eef7f9dSZhang Rui #include <linux/intel_rapl.h>
159eef7f9dSZhang Rui #include <linux/module.h>
169eef7f9dSZhang Rui #include <linux/slab.h>
179eef7f9dSZhang Rui 
189eef7f9dSZhang Rui #define TPMI_RAPL_VERSION 1
199eef7f9dSZhang Rui 
209eef7f9dSZhang Rui /* 1 header + 10 registers + 5 reserved. 8 bytes for each. */
219eef7f9dSZhang Rui #define TPMI_RAPL_DOMAIN_SIZE 128
229eef7f9dSZhang Rui 
239eef7f9dSZhang Rui enum tpmi_rapl_domain_type {
249eef7f9dSZhang Rui 	TPMI_RAPL_DOMAIN_INVALID,
259eef7f9dSZhang Rui 	TPMI_RAPL_DOMAIN_SYSTEM,
269eef7f9dSZhang Rui 	TPMI_RAPL_DOMAIN_PACKAGE,
279eef7f9dSZhang Rui 	TPMI_RAPL_DOMAIN_RESERVED,
289eef7f9dSZhang Rui 	TPMI_RAPL_DOMAIN_MEMORY,
299eef7f9dSZhang Rui 	TPMI_RAPL_DOMAIN_MAX,
309eef7f9dSZhang Rui };
319eef7f9dSZhang Rui 
329eef7f9dSZhang Rui enum tpmi_rapl_register {
339eef7f9dSZhang Rui 	TPMI_RAPL_REG_HEADER,
349eef7f9dSZhang Rui 	TPMI_RAPL_REG_UNIT,
359eef7f9dSZhang Rui 	TPMI_RAPL_REG_PL1,
369eef7f9dSZhang Rui 	TPMI_RAPL_REG_PL2,
379eef7f9dSZhang Rui 	TPMI_RAPL_REG_PL3,
389eef7f9dSZhang Rui 	TPMI_RAPL_REG_PL4,
399eef7f9dSZhang Rui 	TPMI_RAPL_REG_RESERVED,
409eef7f9dSZhang Rui 	TPMI_RAPL_REG_ENERGY_STATUS,
419eef7f9dSZhang Rui 	TPMI_RAPL_REG_PERF_STATUS,
429eef7f9dSZhang Rui 	TPMI_RAPL_REG_POWER_INFO,
43b5cbb42fSZhang Rui 	TPMI_RAPL_REG_DOMAIN_INFO,
449eef7f9dSZhang Rui 	TPMI_RAPL_REG_INTERRUPT,
459eef7f9dSZhang Rui 	TPMI_RAPL_REG_MAX = 15,
469eef7f9dSZhang Rui };
479eef7f9dSZhang Rui 
489eef7f9dSZhang Rui struct tpmi_rapl_package {
499eef7f9dSZhang Rui 	struct rapl_if_priv priv;
509eef7f9dSZhang Rui 	struct intel_tpmi_plat_info *tpmi_info;
519eef7f9dSZhang Rui 	struct rapl_package *rp;
529eef7f9dSZhang Rui 	void __iomem *base;
539eef7f9dSZhang Rui 	struct list_head node;
549eef7f9dSZhang Rui };
559eef7f9dSZhang Rui 
569eef7f9dSZhang Rui static LIST_HEAD(tpmi_rapl_packages);
579eef7f9dSZhang Rui static DEFINE_MUTEX(tpmi_rapl_lock);
589eef7f9dSZhang Rui 
599eef7f9dSZhang Rui static struct powercap_control_type *tpmi_control_type;
609eef7f9dSZhang Rui 
tpmi_rapl_read_raw(int id,struct reg_action * ra)619eef7f9dSZhang Rui static int tpmi_rapl_read_raw(int id, struct reg_action *ra)
629eef7f9dSZhang Rui {
6316e95a62SZhang Rui 	if (!ra->reg.mmio)
649eef7f9dSZhang Rui 		return -EINVAL;
659eef7f9dSZhang Rui 
6616e95a62SZhang Rui 	ra->value = readq(ra->reg.mmio);
679eef7f9dSZhang Rui 
689eef7f9dSZhang Rui 	ra->value &= ra->mask;
699eef7f9dSZhang Rui 	return 0;
709eef7f9dSZhang Rui }
719eef7f9dSZhang Rui 
tpmi_rapl_write_raw(int id,struct reg_action * ra)729eef7f9dSZhang Rui static int tpmi_rapl_write_raw(int id, struct reg_action *ra)
739eef7f9dSZhang Rui {
749eef7f9dSZhang Rui 	u64 val;
759eef7f9dSZhang Rui 
7616e95a62SZhang Rui 	if (!ra->reg.mmio)
779eef7f9dSZhang Rui 		return -EINVAL;
789eef7f9dSZhang Rui 
7916e95a62SZhang Rui 	val = readq(ra->reg.mmio);
809eef7f9dSZhang Rui 
819eef7f9dSZhang Rui 	val &= ~ra->mask;
829eef7f9dSZhang Rui 	val |= ra->value;
839eef7f9dSZhang Rui 
8416e95a62SZhang Rui 	writeq(val, ra->reg.mmio);
859eef7f9dSZhang Rui 	return 0;
869eef7f9dSZhang Rui }
879eef7f9dSZhang Rui 
trp_alloc(int pkg_id)889eef7f9dSZhang Rui static struct tpmi_rapl_package *trp_alloc(int pkg_id)
899eef7f9dSZhang Rui {
909eef7f9dSZhang Rui 	struct tpmi_rapl_package *trp;
919eef7f9dSZhang Rui 	int ret;
929eef7f9dSZhang Rui 
939eef7f9dSZhang Rui 	mutex_lock(&tpmi_rapl_lock);
949eef7f9dSZhang Rui 
959eef7f9dSZhang Rui 	if (list_empty(&tpmi_rapl_packages)) {
969eef7f9dSZhang Rui 		tpmi_control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
979eef7f9dSZhang Rui 		if (IS_ERR(tpmi_control_type)) {
989eef7f9dSZhang Rui 			ret = PTR_ERR(tpmi_control_type);
999eef7f9dSZhang Rui 			goto err_unlock;
1009eef7f9dSZhang Rui 		}
1019eef7f9dSZhang Rui 	}
1029eef7f9dSZhang Rui 
1039eef7f9dSZhang Rui 	trp = kzalloc(sizeof(*trp), GFP_KERNEL);
1049eef7f9dSZhang Rui 	if (!trp) {
1059eef7f9dSZhang Rui 		ret = -ENOMEM;
1069eef7f9dSZhang Rui 		goto err_del_powercap;
1079eef7f9dSZhang Rui 	}
1089eef7f9dSZhang Rui 
1099eef7f9dSZhang Rui 	list_add(&trp->node, &tpmi_rapl_packages);
1109eef7f9dSZhang Rui 
1119eef7f9dSZhang Rui 	mutex_unlock(&tpmi_rapl_lock);
1129eef7f9dSZhang Rui 	return trp;
1139eef7f9dSZhang Rui 
1149eef7f9dSZhang Rui err_del_powercap:
1159eef7f9dSZhang Rui 	if (list_empty(&tpmi_rapl_packages))
1169eef7f9dSZhang Rui 		powercap_unregister_control_type(tpmi_control_type);
1179eef7f9dSZhang Rui err_unlock:
1189eef7f9dSZhang Rui 	mutex_unlock(&tpmi_rapl_lock);
1199eef7f9dSZhang Rui 	return ERR_PTR(ret);
1209eef7f9dSZhang Rui }
1219eef7f9dSZhang Rui 
trp_release(struct tpmi_rapl_package * trp)1229eef7f9dSZhang Rui static void trp_release(struct tpmi_rapl_package *trp)
1239eef7f9dSZhang Rui {
1249eef7f9dSZhang Rui 	mutex_lock(&tpmi_rapl_lock);
1259eef7f9dSZhang Rui 	list_del(&trp->node);
1269eef7f9dSZhang Rui 
1279eef7f9dSZhang Rui 	if (list_empty(&tpmi_rapl_packages))
1289eef7f9dSZhang Rui 		powercap_unregister_control_type(tpmi_control_type);
1299eef7f9dSZhang Rui 
1309eef7f9dSZhang Rui 	kfree(trp);
1319eef7f9dSZhang Rui 	mutex_unlock(&tpmi_rapl_lock);
1329eef7f9dSZhang Rui }
1339eef7f9dSZhang Rui 
1347f628266SZhang Rui /*
1357f628266SZhang Rui  * Bit 0 of TPMI_RAPL_REG_DOMAIN_INFO indicates if the current package is a domain
1367f628266SZhang Rui  * root or not. Only domain root packages can enumerate System (Psys) Domain.
1377f628266SZhang Rui  */
1387f628266SZhang Rui #define TPMI_RAPL_DOMAIN_ROOT	BIT(0)
1397f628266SZhang Rui 
parse_one_domain(struct tpmi_rapl_package * trp,u32 offset)1409eef7f9dSZhang Rui static int parse_one_domain(struct tpmi_rapl_package *trp, u32 offset)
1419eef7f9dSZhang Rui {
1429eef7f9dSZhang Rui 	u8 tpmi_domain_version;
1439eef7f9dSZhang Rui 	enum rapl_domain_type domain_type;
1449eef7f9dSZhang Rui 	enum tpmi_rapl_domain_type tpmi_domain_type;
1459eef7f9dSZhang Rui 	enum tpmi_rapl_register reg_index;
1469eef7f9dSZhang Rui 	enum rapl_domain_reg_id reg_id;
1479eef7f9dSZhang Rui 	int tpmi_domain_size, tpmi_domain_flags;
14816e95a62SZhang Rui 	u64 tpmi_domain_header = readq(trp->base + offset);
1497f628266SZhang Rui 	u64 tpmi_domain_info;
1509eef7f9dSZhang Rui 
1519eef7f9dSZhang Rui 	/* Domain Parent bits are ignored for now */
1529eef7f9dSZhang Rui 	tpmi_domain_version = tpmi_domain_header & 0xff;
1539eef7f9dSZhang Rui 	tpmi_domain_type = tpmi_domain_header >> 8 & 0xff;
1549eef7f9dSZhang Rui 	tpmi_domain_size = tpmi_domain_header >> 16 & 0xff;
1559eef7f9dSZhang Rui 	tpmi_domain_flags = tpmi_domain_header >> 32 & 0xffff;
1569eef7f9dSZhang Rui 
1579eef7f9dSZhang Rui 	if (tpmi_domain_version != TPMI_RAPL_VERSION) {
1589eef7f9dSZhang Rui 		pr_warn(FW_BUG "Unsupported version:%d\n", tpmi_domain_version);
1599eef7f9dSZhang Rui 		return -ENODEV;
1609eef7f9dSZhang Rui 	}
1619eef7f9dSZhang Rui 
1629eef7f9dSZhang Rui 	/* Domain size: in unit of 128 Bytes */
1639eef7f9dSZhang Rui 	if (tpmi_domain_size != 1) {
1649eef7f9dSZhang Rui 		pr_warn(FW_BUG "Invalid Domain size %d\n", tpmi_domain_size);
1659eef7f9dSZhang Rui 		return -EINVAL;
1669eef7f9dSZhang Rui 	}
1679eef7f9dSZhang Rui 
1689eef7f9dSZhang Rui 	/* Unit register and Energy Status register are mandatory for each domain */
1699eef7f9dSZhang Rui 	if (!(tpmi_domain_flags & BIT(TPMI_RAPL_REG_UNIT)) ||
1709eef7f9dSZhang Rui 	    !(tpmi_domain_flags & BIT(TPMI_RAPL_REG_ENERGY_STATUS))) {
1719eef7f9dSZhang Rui 		pr_warn(FW_BUG "Invalid Domain flag 0x%x\n", tpmi_domain_flags);
1729eef7f9dSZhang Rui 		return -EINVAL;
1739eef7f9dSZhang Rui 	}
1749eef7f9dSZhang Rui 
1759eef7f9dSZhang Rui 	switch (tpmi_domain_type) {
1769eef7f9dSZhang Rui 	case TPMI_RAPL_DOMAIN_PACKAGE:
1779eef7f9dSZhang Rui 		domain_type = RAPL_DOMAIN_PACKAGE;
1789eef7f9dSZhang Rui 		break;
1799eef7f9dSZhang Rui 	case TPMI_RAPL_DOMAIN_SYSTEM:
1807f628266SZhang Rui 		if (!(tpmi_domain_flags & BIT(TPMI_RAPL_REG_DOMAIN_INFO))) {
1817f628266SZhang Rui 			pr_warn(FW_BUG "System domain must support Domain Info register\n");
1827f628266SZhang Rui 			return -ENODEV;
1837f628266SZhang Rui 		}
1847f628266SZhang Rui 		tpmi_domain_info = readq(trp->base + offset + TPMI_RAPL_REG_DOMAIN_INFO);
1857f628266SZhang Rui 		if (!(tpmi_domain_info & TPMI_RAPL_DOMAIN_ROOT))
1867f628266SZhang Rui 			return 0;
1879eef7f9dSZhang Rui 		domain_type = RAPL_DOMAIN_PLATFORM;
1889eef7f9dSZhang Rui 		break;
1899eef7f9dSZhang Rui 	case TPMI_RAPL_DOMAIN_MEMORY:
1909eef7f9dSZhang Rui 		domain_type = RAPL_DOMAIN_DRAM;
1919eef7f9dSZhang Rui 		break;
1929eef7f9dSZhang Rui 	default:
1939eef7f9dSZhang Rui 		pr_warn(FW_BUG "Unsupported Domain type %d\n", tpmi_domain_type);
1949eef7f9dSZhang Rui 		return -EINVAL;
1959eef7f9dSZhang Rui 	}
1969eef7f9dSZhang Rui 
19716e95a62SZhang Rui 	if (trp->priv.regs[domain_type][RAPL_DOMAIN_REG_UNIT].mmio) {
1989eef7f9dSZhang Rui 		pr_warn(FW_BUG "Duplicate Domain type %d\n", tpmi_domain_type);
1999eef7f9dSZhang Rui 		return -EINVAL;
2009eef7f9dSZhang Rui 	}
2019eef7f9dSZhang Rui 
2029eef7f9dSZhang Rui 	reg_index = TPMI_RAPL_REG_HEADER;
2039eef7f9dSZhang Rui 	while (++reg_index != TPMI_RAPL_REG_MAX) {
2049eef7f9dSZhang Rui 		if (!(tpmi_domain_flags & BIT(reg_index)))
2059eef7f9dSZhang Rui 			continue;
2069eef7f9dSZhang Rui 
2079eef7f9dSZhang Rui 		switch (reg_index) {
2089eef7f9dSZhang Rui 		case TPMI_RAPL_REG_UNIT:
2099eef7f9dSZhang Rui 			reg_id = RAPL_DOMAIN_REG_UNIT;
2109eef7f9dSZhang Rui 			break;
2119eef7f9dSZhang Rui 		case TPMI_RAPL_REG_PL1:
2129eef7f9dSZhang Rui 			reg_id = RAPL_DOMAIN_REG_LIMIT;
2139eef7f9dSZhang Rui 			trp->priv.limits[domain_type] |= BIT(POWER_LIMIT1);
2149eef7f9dSZhang Rui 			break;
2159eef7f9dSZhang Rui 		case TPMI_RAPL_REG_PL2:
2169eef7f9dSZhang Rui 			reg_id = RAPL_DOMAIN_REG_PL2;
2179eef7f9dSZhang Rui 			trp->priv.limits[domain_type] |= BIT(POWER_LIMIT2);
2189eef7f9dSZhang Rui 			break;
2199eef7f9dSZhang Rui 		case TPMI_RAPL_REG_PL4:
2209eef7f9dSZhang Rui 			reg_id = RAPL_DOMAIN_REG_PL4;
2219eef7f9dSZhang Rui 			trp->priv.limits[domain_type] |= BIT(POWER_LIMIT4);
2229eef7f9dSZhang Rui 			break;
2239eef7f9dSZhang Rui 		case TPMI_RAPL_REG_ENERGY_STATUS:
2249eef7f9dSZhang Rui 			reg_id = RAPL_DOMAIN_REG_STATUS;
2259eef7f9dSZhang Rui 			break;
2269eef7f9dSZhang Rui 		case TPMI_RAPL_REG_PERF_STATUS:
2279eef7f9dSZhang Rui 			reg_id = RAPL_DOMAIN_REG_PERF;
2289eef7f9dSZhang Rui 			break;
2299eef7f9dSZhang Rui 		case TPMI_RAPL_REG_POWER_INFO:
2309eef7f9dSZhang Rui 			reg_id = RAPL_DOMAIN_REG_INFO;
2319eef7f9dSZhang Rui 			break;
2329eef7f9dSZhang Rui 		default:
2339eef7f9dSZhang Rui 			continue;
2349eef7f9dSZhang Rui 		}
23516e95a62SZhang Rui 		trp->priv.regs[domain_type][reg_id].mmio = trp->base + offset + reg_index * 8;
2369eef7f9dSZhang Rui 	}
2379eef7f9dSZhang Rui 
2389eef7f9dSZhang Rui 	return 0;
2399eef7f9dSZhang Rui }
2409eef7f9dSZhang Rui 
intel_rapl_tpmi_probe(struct auxiliary_device * auxdev,const struct auxiliary_device_id * id)2419eef7f9dSZhang Rui static int intel_rapl_tpmi_probe(struct auxiliary_device *auxdev,
2429eef7f9dSZhang Rui 				 const struct auxiliary_device_id *id)
2439eef7f9dSZhang Rui {
2449eef7f9dSZhang Rui 	struct tpmi_rapl_package *trp;
2459eef7f9dSZhang Rui 	struct intel_tpmi_plat_info *info;
2469eef7f9dSZhang Rui 	struct resource *res;
2479eef7f9dSZhang Rui 	u32 offset;
2489eef7f9dSZhang Rui 	int ret;
2499eef7f9dSZhang Rui 
2509eef7f9dSZhang Rui 	info = tpmi_get_platform_data(auxdev);
2519eef7f9dSZhang Rui 	if (!info)
2529eef7f9dSZhang Rui 		return -ENODEV;
2539eef7f9dSZhang Rui 
2549eef7f9dSZhang Rui 	trp = trp_alloc(info->package_id);
2559eef7f9dSZhang Rui 	if (IS_ERR(trp))
2569eef7f9dSZhang Rui 		return PTR_ERR(trp);
2579eef7f9dSZhang Rui 
2589eef7f9dSZhang Rui 	if (tpmi_get_resource_count(auxdev) > 1) {
2599eef7f9dSZhang Rui 		dev_err(&auxdev->dev, "does not support multiple resources\n");
2609eef7f9dSZhang Rui 		ret = -EINVAL;
2619eef7f9dSZhang Rui 		goto err;
2629eef7f9dSZhang Rui 	}
2639eef7f9dSZhang Rui 
2649eef7f9dSZhang Rui 	res = tpmi_get_resource_at_index(auxdev, 0);
2659eef7f9dSZhang Rui 	if (!res) {
2669eef7f9dSZhang Rui 		dev_err(&auxdev->dev, "can't fetch device resource info\n");
2679eef7f9dSZhang Rui 		ret = -EIO;
2689eef7f9dSZhang Rui 		goto err;
2699eef7f9dSZhang Rui 	}
2709eef7f9dSZhang Rui 
2719eef7f9dSZhang Rui 	trp->base = devm_ioremap_resource(&auxdev->dev, res);
27249776c71SDan Carpenter 	if (IS_ERR(trp->base)) {
27349776c71SDan Carpenter 		ret = PTR_ERR(trp->base);
2749eef7f9dSZhang Rui 		goto err;
2759eef7f9dSZhang Rui 	}
2769eef7f9dSZhang Rui 
2779eef7f9dSZhang Rui 	for (offset = 0; offset < resource_size(res); offset += TPMI_RAPL_DOMAIN_SIZE) {
2789eef7f9dSZhang Rui 		ret = parse_one_domain(trp, offset);
2799eef7f9dSZhang Rui 		if (ret)
2809eef7f9dSZhang Rui 			goto err;
2819eef7f9dSZhang Rui 	}
2829eef7f9dSZhang Rui 
2839eef7f9dSZhang Rui 	trp->tpmi_info = info;
2849eef7f9dSZhang Rui 	trp->priv.type = RAPL_IF_TPMI;
2859eef7f9dSZhang Rui 	trp->priv.read_raw = tpmi_rapl_read_raw;
2869eef7f9dSZhang Rui 	trp->priv.write_raw = tpmi_rapl_write_raw;
2879eef7f9dSZhang Rui 	trp->priv.control_type = tpmi_control_type;
2889eef7f9dSZhang Rui 
2899eef7f9dSZhang Rui 	/* RAPL TPMI I/F is per physical package */
2909eef7f9dSZhang Rui 	trp->rp = rapl_find_package_domain(info->package_id, &trp->priv, false);
2919eef7f9dSZhang Rui 	if (trp->rp) {
2929eef7f9dSZhang Rui 		dev_err(&auxdev->dev, "Domain for Package%d already exists\n", info->package_id);
2939eef7f9dSZhang Rui 		ret = -EEXIST;
2949eef7f9dSZhang Rui 		goto err;
2959eef7f9dSZhang Rui 	}
2969eef7f9dSZhang Rui 
2979eef7f9dSZhang Rui 	trp->rp = rapl_add_package(info->package_id, &trp->priv, false);
2989eef7f9dSZhang Rui 	if (IS_ERR(trp->rp)) {
2999eef7f9dSZhang Rui 		dev_err(&auxdev->dev, "Failed to add RAPL Domain for Package%d, %ld\n",
3009eef7f9dSZhang Rui 			info->package_id, PTR_ERR(trp->rp));
3019eef7f9dSZhang Rui 		ret = PTR_ERR(trp->rp);
3029eef7f9dSZhang Rui 		goto err;
3039eef7f9dSZhang Rui 	}
3049eef7f9dSZhang Rui 
3059eef7f9dSZhang Rui 	auxiliary_set_drvdata(auxdev, trp);
3069eef7f9dSZhang Rui 
3079eef7f9dSZhang Rui 	return 0;
3089eef7f9dSZhang Rui err:
3099eef7f9dSZhang Rui 	trp_release(trp);
3109eef7f9dSZhang Rui 	return ret;
3119eef7f9dSZhang Rui }
3129eef7f9dSZhang Rui 
intel_rapl_tpmi_remove(struct auxiliary_device * auxdev)3139eef7f9dSZhang Rui static void intel_rapl_tpmi_remove(struct auxiliary_device *auxdev)
3149eef7f9dSZhang Rui {
3159eef7f9dSZhang Rui 	struct tpmi_rapl_package *trp = auxiliary_get_drvdata(auxdev);
3169eef7f9dSZhang Rui 
3179eef7f9dSZhang Rui 	rapl_remove_package(trp->rp);
3189eef7f9dSZhang Rui 	trp_release(trp);
3199eef7f9dSZhang Rui }
3209eef7f9dSZhang Rui 
3219eef7f9dSZhang Rui static const struct auxiliary_device_id intel_rapl_tpmi_ids[] = {
3229eef7f9dSZhang Rui 	{.name = "intel_vsec.tpmi-rapl" },
3239eef7f9dSZhang Rui 	{ }
3249eef7f9dSZhang Rui };
3259eef7f9dSZhang Rui 
3269eef7f9dSZhang Rui MODULE_DEVICE_TABLE(auxiliary, intel_rapl_tpmi_ids);
3279eef7f9dSZhang Rui 
3289eef7f9dSZhang Rui static struct auxiliary_driver intel_rapl_tpmi_driver = {
3299eef7f9dSZhang Rui 	.probe = intel_rapl_tpmi_probe,
3309eef7f9dSZhang Rui 	.remove = intel_rapl_tpmi_remove,
3319eef7f9dSZhang Rui 	.id_table = intel_rapl_tpmi_ids,
3329eef7f9dSZhang Rui };
3339eef7f9dSZhang Rui 
3349eef7f9dSZhang Rui module_auxiliary_driver(intel_rapl_tpmi_driver)
3359eef7f9dSZhang Rui 
3369eef7f9dSZhang Rui MODULE_IMPORT_NS(INTEL_TPMI);
3379eef7f9dSZhang Rui 
3389eef7f9dSZhang Rui MODULE_DESCRIPTION("Intel RAPL TPMI Driver");
3399eef7f9dSZhang Rui MODULE_LICENSE("GPL");
340