xref: /linux/drivers/peci/device.c (revision 55d0969c451159cff86949b38c39171cab962069)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2018-2021 Intel Corporation
3 
4 #include <linux/bitfield.h>
5 #include <linux/peci.h>
6 #include <linux/peci-cpu.h>
7 #include <linux/slab.h>
8 
9 #include "internal.h"
10 
11 /*
12  * PECI device can be removed using sysfs, but the removal can also happen as
13  * a result of controller being removed.
14  * Mutex is used to protect PECI device from being double-deleted.
15  */
16 static DEFINE_MUTEX(peci_device_del_lock);
17 
18 #define REVISION_NUM_MASK GENMASK(15, 8)
19 static int peci_get_revision(struct peci_device *device, u8 *revision)
20 {
21 	struct peci_request *req;
22 	u64 dib;
23 
24 	req = peci_xfer_get_dib(device);
25 	if (IS_ERR(req))
26 		return PTR_ERR(req);
27 
28 	/*
29 	 * PECI device may be in a state where it is unable to return a proper
30 	 * DIB, in which case it returns 0 as DIB value.
31 	 * Let's treat this as an error to avoid carrying on with the detection
32 	 * using invalid revision.
33 	 */
34 	dib = peci_request_dib_read(req);
35 	if (dib == 0) {
36 		peci_request_free(req);
37 		return -EIO;
38 	}
39 
40 	*revision = FIELD_GET(REVISION_NUM_MASK, dib);
41 
42 	peci_request_free(req);
43 
44 	return 0;
45 }
46 
47 static int peci_get_cpu_id(struct peci_device *device, u32 *cpu_id)
48 {
49 	struct peci_request *req;
50 	int ret;
51 
52 	req = peci_xfer_pkg_cfg_readl(device, PECI_PCS_PKG_ID, PECI_PKG_ID_CPU_ID);
53 	if (IS_ERR(req))
54 		return PTR_ERR(req);
55 
56 	ret = peci_request_status(req);
57 	if (ret)
58 		goto out_req_free;
59 
60 	*cpu_id = peci_request_data_readl(req);
61 out_req_free:
62 	peci_request_free(req);
63 
64 	return ret;
65 }
66 
67 static unsigned int peci_x86_cpu_family(unsigned int sig)
68 {
69 	unsigned int x86;
70 
71 	x86 = (sig >> 8) & 0xf;
72 
73 	if (x86 == 0xf)
74 		x86 += (sig >> 20) & 0xff;
75 
76 	return x86;
77 }
78 
79 static unsigned int peci_x86_cpu_model(unsigned int sig)
80 {
81 	unsigned int fam, model;
82 
83 	fam = peci_x86_cpu_family(sig);
84 
85 	model = (sig >> 4) & 0xf;
86 
87 	if (fam >= 0x6)
88 		model += ((sig >> 16) & 0xf) << 4;
89 
90 	return model;
91 }
92 
93 static int peci_device_info_init(struct peci_device *device)
94 {
95 	u8 revision;
96 	u32 cpu_id;
97 	int ret;
98 
99 	ret = peci_get_cpu_id(device, &cpu_id);
100 	if (ret)
101 		return ret;
102 
103 	device->info.x86_vfm = IFM(peci_x86_cpu_family(cpu_id), peci_x86_cpu_model(cpu_id));
104 
105 	ret = peci_get_revision(device, &revision);
106 	if (ret)
107 		return ret;
108 	device->info.peci_revision = revision;
109 
110 	device->info.socket_id = device->addr - PECI_BASE_ADDR;
111 
112 	return 0;
113 }
114 
115 static int peci_detect(struct peci_controller *controller, u8 addr)
116 {
117 	/*
118 	 * PECI Ping is a command encoded by tx_len = 0, rx_len = 0.
119 	 * We expect correct Write FCS if the device at the target address
120 	 * is able to respond.
121 	 */
122 	struct peci_request req = { 0 };
123 	int ret;
124 
125 	mutex_lock(&controller->bus_lock);
126 	ret = controller->ops->xfer(controller, addr, &req);
127 	mutex_unlock(&controller->bus_lock);
128 
129 	return ret;
130 }
131 
132 static bool peci_addr_valid(u8 addr)
133 {
134 	return addr >= PECI_BASE_ADDR && addr < PECI_BASE_ADDR + PECI_DEVICE_NUM_MAX;
135 }
136 
137 static int peci_dev_exists(struct device *dev, void *data)
138 {
139 	struct peci_device *device = to_peci_device(dev);
140 	u8 *addr = data;
141 
142 	if (device->addr == *addr)
143 		return -EBUSY;
144 
145 	return 0;
146 }
147 
148 int peci_device_create(struct peci_controller *controller, u8 addr)
149 {
150 	struct peci_device *device;
151 	int ret;
152 
153 	if (!peci_addr_valid(addr))
154 		return -EINVAL;
155 
156 	/* Check if we have already detected this device before. */
157 	ret = device_for_each_child(&controller->dev, &addr, peci_dev_exists);
158 	if (ret)
159 		return 0;
160 
161 	ret = peci_detect(controller, addr);
162 	if (ret) {
163 		/*
164 		 * Device not present or host state doesn't allow successful
165 		 * detection at this time.
166 		 */
167 		if (ret == -EIO || ret == -ETIMEDOUT)
168 			return 0;
169 
170 		return ret;
171 	}
172 
173 	device = kzalloc(sizeof(*device), GFP_KERNEL);
174 	if (!device)
175 		return -ENOMEM;
176 
177 	device_initialize(&device->dev);
178 
179 	device->addr = addr;
180 	device->dev.parent = &controller->dev;
181 	device->dev.bus = &peci_bus_type;
182 	device->dev.type = &peci_device_type;
183 
184 	ret = peci_device_info_init(device);
185 	if (ret)
186 		goto err_put;
187 
188 	ret = dev_set_name(&device->dev, "%d-%02x", controller->id, device->addr);
189 	if (ret)
190 		goto err_put;
191 
192 	ret = device_add(&device->dev);
193 	if (ret)
194 		goto err_put;
195 
196 	return 0;
197 
198 err_put:
199 	put_device(&device->dev);
200 
201 	return ret;
202 }
203 
204 void peci_device_destroy(struct peci_device *device)
205 {
206 	mutex_lock(&peci_device_del_lock);
207 	if (!device->deleted) {
208 		device_unregister(&device->dev);
209 		device->deleted = true;
210 	}
211 	mutex_unlock(&peci_device_del_lock);
212 }
213 
214 int __peci_driver_register(struct peci_driver *driver, struct module *owner,
215 			   const char *mod_name)
216 {
217 	driver->driver.bus = &peci_bus_type;
218 	driver->driver.owner = owner;
219 	driver->driver.mod_name = mod_name;
220 
221 	if (!driver->probe) {
222 		pr_err("peci: trying to register driver without probe callback\n");
223 		return -EINVAL;
224 	}
225 
226 	if (!driver->id_table) {
227 		pr_err("peci: trying to register driver without device id table\n");
228 		return -EINVAL;
229 	}
230 
231 	return driver_register(&driver->driver);
232 }
233 EXPORT_SYMBOL_NS_GPL(__peci_driver_register, PECI);
234 
235 void peci_driver_unregister(struct peci_driver *driver)
236 {
237 	driver_unregister(&driver->driver);
238 }
239 EXPORT_SYMBOL_NS_GPL(peci_driver_unregister, PECI);
240 
241 static void peci_device_release(struct device *dev)
242 {
243 	struct peci_device *device = to_peci_device(dev);
244 
245 	kfree(device);
246 }
247 
248 const struct device_type peci_device_type = {
249 	.groups		= peci_device_groups,
250 	.release	= peci_device_release,
251 };
252