1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2005, 2006 IBM Corporation |
4 | * Copyright (C) 2014, 2015 Intel Corporation |
5 | * |
6 | * Authors: |
7 | * Leendert van Doorn <leendert@watson.ibm.com> |
8 | * Kylene Hall <kjhall@us.ibm.com> |
9 | * |
10 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> |
11 | * |
12 | * Device driver for TCG/TCPA TPM (trusted platform module). |
13 | * Specifications at www.trustedcomputinggroup.org |
14 | * |
15 | * This device driver implements the TPM interface as defined in |
16 | * the TCG TPM Interface Spec version 1.2, revision 1.0. |
17 | */ |
18 | #include <linux/init.h> |
19 | #include <linux/module.h> |
20 | #include <linux/moduleparam.h> |
21 | #include <linux/pnp.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/interrupt.h> |
24 | #include <linux/wait.h> |
25 | #include <linux/acpi.h> |
26 | #include <linux/freezer.h> |
27 | #include <linux/of.h> |
28 | #include <linux/kernel.h> |
29 | #include "tpm.h" |
30 | #include "tpm_tis_core.h" |
31 | |
32 | struct tpm_info { |
33 | struct resource res; |
34 | /* irq > 0 means: use irq $irq; |
35 | * irq = 0 means: autoprobe for an irq; |
36 | * irq = -1 means: no irq support |
37 | */ |
38 | int irq; |
39 | }; |
40 | |
41 | struct tpm_tis_tcg_phy { |
42 | struct tpm_tis_data priv; |
43 | void __iomem *iobase; |
44 | }; |
45 | |
46 | static inline struct tpm_tis_tcg_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *data) |
47 | { |
48 | return container_of(data, struct tpm_tis_tcg_phy, priv); |
49 | } |
50 | |
51 | #ifdef CONFIG_PREEMPT_RT |
52 | /* |
53 | * Flush previous write operations with a dummy read operation to the |
54 | * TPM MMIO base address. |
55 | */ |
56 | static inline void tpm_tis_flush(void __iomem *iobase) |
57 | { |
58 | ioread8(iobase + TPM_ACCESS(0)); |
59 | } |
60 | #else |
61 | #define tpm_tis_flush(iobase) do { } while (0) |
62 | #endif |
63 | |
64 | /* |
65 | * Write a byte word to the TPM MMIO address, and flush the write queue. |
66 | * The flush ensures that the data is sent immediately over the bus and not |
67 | * aggregated with further requests and transferred later in a batch. The large |
68 | * write requests can lead to unwanted latency spikes by blocking the CPU until |
69 | * the complete batch has been transferred. |
70 | */ |
71 | static inline void tpm_tis_iowrite8(u8 b, void __iomem *iobase, u32 addr) |
72 | { |
73 | iowrite8(b, iobase + addr); |
74 | tpm_tis_flush(iobase); |
75 | } |
76 | |
77 | /* |
78 | * Write a 32-bit word to the TPM MMIO address, and flush the write queue. |
79 | * The flush ensures that the data is sent immediately over the bus and not |
80 | * aggregated with further requests and transferred later in a batch. The large |
81 | * write requests can lead to unwanted latency spikes by blocking the CPU until |
82 | * the complete batch has been transferred. |
83 | */ |
84 | static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr) |
85 | { |
86 | iowrite32(b, iobase + addr); |
87 | tpm_tis_flush(iobase); |
88 | } |
89 | |
90 | static bool interrupts; |
91 | module_param(interrupts, bool, 0444); |
92 | MODULE_PARM_DESC(interrupts, "Enable interrupts" ); |
93 | |
94 | static bool itpm; |
95 | module_param(itpm, bool, 0444); |
96 | MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)" ); |
97 | |
98 | static bool force; |
99 | #ifdef CONFIG_X86 |
100 | module_param(force, bool, 0444); |
101 | MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry" ); |
102 | #endif |
103 | |
104 | #if defined(CONFIG_PNP) && defined(CONFIG_ACPI) |
105 | static int has_hid(struct acpi_device *dev, const char *hid) |
106 | { |
107 | struct acpi_hardware_id *id; |
108 | |
109 | list_for_each_entry(id, &dev->pnp.ids, list) |
110 | if (!strcmp(hid, id->id)) |
111 | return 1; |
112 | |
113 | return 0; |
114 | } |
115 | |
116 | static inline int is_itpm(struct acpi_device *dev) |
117 | { |
118 | if (!dev) |
119 | return 0; |
120 | return has_hid(dev, hid: "INTC0102" ); |
121 | } |
122 | #else |
123 | static inline int is_itpm(struct acpi_device *dev) |
124 | { |
125 | return 0; |
126 | } |
127 | #endif |
128 | |
129 | #if defined(CONFIG_ACPI) |
130 | #define DEVICE_IS_TPM2 1 |
131 | |
132 | static const struct acpi_device_id tpm_acpi_tbl[] = { |
133 | {"MSFT0101" , DEVICE_IS_TPM2}, |
134 | {}, |
135 | }; |
136 | MODULE_DEVICE_TABLE(acpi, tpm_acpi_tbl); |
137 | |
138 | static int check_acpi_tpm2(struct device *dev) |
139 | { |
140 | const struct acpi_device_id *aid = acpi_match_device(ids: tpm_acpi_tbl, dev); |
141 | struct acpi_table_tpm2 *tbl; |
142 | acpi_status st; |
143 | int ret = 0; |
144 | |
145 | if (!aid || aid->driver_data != DEVICE_IS_TPM2) |
146 | return 0; |
147 | |
148 | /* If the ACPI TPM2 signature is matched then a global ACPI_SIG_TPM2 |
149 | * table is mandatory |
150 | */ |
151 | st = acpi_get_table(ACPI_SIG_TPM2, instance: 1, out_table: (struct acpi_table_header **)&tbl); |
152 | if (ACPI_FAILURE(st) || tbl->header.length < sizeof(*tbl)) { |
153 | dev_err(dev, FW_BUG "failed to get TPM2 ACPI table\n" ); |
154 | return -EINVAL; |
155 | } |
156 | |
157 | /* The tpm2_crb driver handles this device */ |
158 | if (tbl->start_method != ACPI_TPM2_MEMORY_MAPPED) |
159 | ret = -ENODEV; |
160 | |
161 | acpi_put_table(table: (struct acpi_table_header *)tbl); |
162 | return ret; |
163 | } |
164 | #else |
165 | static int check_acpi_tpm2(struct device *dev) |
166 | { |
167 | return 0; |
168 | } |
169 | #endif |
170 | |
171 | static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len, |
172 | u8 *result, enum tpm_tis_io_mode io_mode) |
173 | { |
174 | struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); |
175 | __le16 result_le16; |
176 | __le32 result_le32; |
177 | |
178 | switch (io_mode) { |
179 | case TPM_TIS_PHYS_8: |
180 | while (len--) |
181 | *result++ = ioread8(phy->iobase + addr); |
182 | break; |
183 | case TPM_TIS_PHYS_16: |
184 | result_le16 = cpu_to_le16(ioread16(phy->iobase + addr)); |
185 | memcpy(result, &result_le16, sizeof(u16)); |
186 | break; |
187 | case TPM_TIS_PHYS_32: |
188 | result_le32 = cpu_to_le32(ioread32(phy->iobase + addr)); |
189 | memcpy(result, &result_le32, sizeof(u32)); |
190 | break; |
191 | } |
192 | |
193 | return 0; |
194 | } |
195 | |
196 | static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, |
197 | const u8 *value, enum tpm_tis_io_mode io_mode) |
198 | { |
199 | struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); |
200 | |
201 | switch (io_mode) { |
202 | case TPM_TIS_PHYS_8: |
203 | while (len--) |
204 | tpm_tis_iowrite8(b: *value++, iobase: phy->iobase, addr); |
205 | break; |
206 | case TPM_TIS_PHYS_16: |
207 | return -EINVAL; |
208 | case TPM_TIS_PHYS_32: |
209 | tpm_tis_iowrite32(le32_to_cpu(*((__le32 *)value)), iobase: phy->iobase, addr); |
210 | break; |
211 | } |
212 | |
213 | return 0; |
214 | } |
215 | |
216 | static const struct tpm_tis_phy_ops tpm_tcg = { |
217 | .read_bytes = tpm_tcg_read_bytes, |
218 | .write_bytes = tpm_tcg_write_bytes, |
219 | }; |
220 | |
221 | static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info) |
222 | { |
223 | struct tpm_tis_tcg_phy *phy; |
224 | int irq = -1; |
225 | int rc; |
226 | |
227 | rc = check_acpi_tpm2(dev); |
228 | if (rc) |
229 | return rc; |
230 | |
231 | phy = devm_kzalloc(dev, size: sizeof(struct tpm_tis_tcg_phy), GFP_KERNEL); |
232 | if (phy == NULL) |
233 | return -ENOMEM; |
234 | |
235 | phy->iobase = devm_ioremap_resource(dev, res: &tpm_info->res); |
236 | if (IS_ERR(ptr: phy->iobase)) |
237 | return PTR_ERR(ptr: phy->iobase); |
238 | |
239 | if (interrupts) |
240 | irq = tpm_info->irq; |
241 | |
242 | if (itpm || is_itpm(ACPI_COMPANION(dev))) |
243 | set_bit(nr: TPM_TIS_ITPM_WORKAROUND, addr: &phy->priv.flags); |
244 | |
245 | return tpm_tis_core_init(dev, priv: &phy->priv, irq, phy_ops: &tpm_tcg, |
246 | ACPI_HANDLE(dev)); |
247 | } |
248 | |
249 | static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume); |
250 | |
251 | static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, |
252 | const struct pnp_device_id *pnp_id) |
253 | { |
254 | struct tpm_info tpm_info = {}; |
255 | struct resource *res; |
256 | |
257 | res = pnp_get_resource(dev: pnp_dev, IORESOURCE_MEM, num: 0); |
258 | if (!res) |
259 | return -ENODEV; |
260 | tpm_info.res = *res; |
261 | |
262 | if (pnp_irq_valid(dev: pnp_dev, bar: 0)) |
263 | tpm_info.irq = pnp_irq(dev: pnp_dev, bar: 0); |
264 | else |
265 | tpm_info.irq = -1; |
266 | |
267 | return tpm_tis_init(dev: &pnp_dev->dev, tpm_info: &tpm_info); |
268 | } |
269 | |
270 | /* |
271 | * There is a known bug caused by 93e1b7d42e1e ("[PATCH] tpm: add HID module |
272 | * parameter"). This commit added IFX0102 device ID, which is also used by |
273 | * tpm_infineon but ignored to add quirks to probe which driver ought to be |
274 | * used. |
275 | */ |
276 | |
277 | static struct pnp_device_id tpm_pnp_tbl[] = { |
278 | {"PNP0C31" , 0}, /* TPM */ |
279 | {"ATM1200" , 0}, /* Atmel */ |
280 | {"IFX0102" , 0}, /* Infineon */ |
281 | {"BCM0101" , 0}, /* Broadcom */ |
282 | {"BCM0102" , 0}, /* Broadcom */ |
283 | {"NSC1200" , 0}, /* National */ |
284 | {"ICO0102" , 0}, /* Intel */ |
285 | /* Add new here */ |
286 | {"" , 0}, /* User Specified */ |
287 | {"" , 0} /* Terminator */ |
288 | }; |
289 | MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); |
290 | |
291 | static void tpm_tis_pnp_remove(struct pnp_dev *dev) |
292 | { |
293 | struct tpm_chip *chip = pnp_get_drvdata(pdev: dev); |
294 | |
295 | tpm_chip_unregister(chip); |
296 | tpm_tis_remove(chip); |
297 | } |
298 | |
299 | static struct pnp_driver tis_pnp_driver = { |
300 | .name = "tpm_tis" , |
301 | .id_table = tpm_pnp_tbl, |
302 | .probe = tpm_tis_pnp_init, |
303 | .remove = tpm_tis_pnp_remove, |
304 | .driver = { |
305 | .pm = &tpm_tis_pm, |
306 | }, |
307 | }; |
308 | |
309 | #define TIS_HID_USR_IDX (ARRAY_SIZE(tpm_pnp_tbl) - 2) |
310 | module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id, |
311 | sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); |
312 | MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe" ); |
313 | |
314 | static struct platform_device *force_pdev; |
315 | |
316 | static int tpm_tis_plat_probe(struct platform_device *pdev) |
317 | { |
318 | struct tpm_info tpm_info = {}; |
319 | struct resource *res; |
320 | |
321 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
322 | if (res == NULL) { |
323 | dev_err(&pdev->dev, "no memory resource defined\n" ); |
324 | return -ENODEV; |
325 | } |
326 | tpm_info.res = *res; |
327 | |
328 | tpm_info.irq = platform_get_irq_optional(pdev, 0); |
329 | if (tpm_info.irq <= 0) { |
330 | if (pdev != force_pdev) |
331 | tpm_info.irq = -1; |
332 | else |
333 | /* When forcing auto probe the IRQ */ |
334 | tpm_info.irq = 0; |
335 | } |
336 | |
337 | return tpm_tis_init(dev: &pdev->dev, tpm_info: &tpm_info); |
338 | } |
339 | |
340 | static void tpm_tis_plat_remove(struct platform_device *pdev) |
341 | { |
342 | struct tpm_chip *chip = dev_get_drvdata(dev: &pdev->dev); |
343 | |
344 | tpm_chip_unregister(chip); |
345 | tpm_tis_remove(chip); |
346 | } |
347 | |
348 | #ifdef CONFIG_OF |
349 | static const struct of_device_id tis_of_platform_match[] = { |
350 | {.compatible = "tcg,tpm-tis-mmio" }, |
351 | {}, |
352 | }; |
353 | MODULE_DEVICE_TABLE(of, tis_of_platform_match); |
354 | #endif |
355 | |
356 | static struct platform_driver tis_drv = { |
357 | .probe = tpm_tis_plat_probe, |
358 | .remove_new = tpm_tis_plat_remove, |
359 | .driver = { |
360 | .name = "tpm_tis" , |
361 | .pm = &tpm_tis_pm, |
362 | .of_match_table = of_match_ptr(tis_of_platform_match), |
363 | .acpi_match_table = ACPI_PTR(tpm_acpi_tbl), |
364 | }, |
365 | }; |
366 | |
367 | static int tpm_tis_force_device(void) |
368 | { |
369 | struct platform_device *pdev; |
370 | static const struct resource x86_resources[] = { |
371 | DEFINE_RES_MEM(0xFED40000, TIS_MEM_LEN) |
372 | }; |
373 | |
374 | if (!force) |
375 | return 0; |
376 | |
377 | /* The driver core will match the name tpm_tis of the device to |
378 | * the tpm_tis platform driver and complete the setup via |
379 | * tpm_tis_plat_probe |
380 | */ |
381 | pdev = platform_device_register_simple(name: "tpm_tis" , id: -1, res: x86_resources, |
382 | ARRAY_SIZE(x86_resources)); |
383 | if (IS_ERR(ptr: pdev)) |
384 | return PTR_ERR(ptr: pdev); |
385 | force_pdev = pdev; |
386 | |
387 | return 0; |
388 | } |
389 | |
390 | static int __init init_tis(void) |
391 | { |
392 | int rc; |
393 | |
394 | rc = tpm_tis_force_device(); |
395 | if (rc) |
396 | goto err_force; |
397 | |
398 | rc = platform_driver_register(&tis_drv); |
399 | if (rc) |
400 | goto err_platform; |
401 | |
402 | |
403 | if (IS_ENABLED(CONFIG_PNP)) { |
404 | rc = pnp_register_driver(drv: &tis_pnp_driver); |
405 | if (rc) |
406 | goto err_pnp; |
407 | } |
408 | |
409 | return 0; |
410 | |
411 | err_pnp: |
412 | platform_driver_unregister(&tis_drv); |
413 | err_platform: |
414 | if (force_pdev) |
415 | platform_device_unregister(force_pdev); |
416 | err_force: |
417 | return rc; |
418 | } |
419 | |
420 | static void __exit cleanup_tis(void) |
421 | { |
422 | pnp_unregister_driver(drv: &tis_pnp_driver); |
423 | platform_driver_unregister(&tis_drv); |
424 | |
425 | if (force_pdev) |
426 | platform_device_unregister(force_pdev); |
427 | } |
428 | |
429 | module_init(init_tis); |
430 | module_exit(cleanup_tis); |
431 | MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)" ); |
432 | MODULE_DESCRIPTION("TPM Driver" ); |
433 | MODULE_VERSION("2.0" ); |
434 | MODULE_LICENSE("GPL" ); |
435 | |