xref: /linux/drivers/misc/issei/pci_heci.c (revision 93e4b3076b5f2d853462b9777d083c77fc0b7b23)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2023-2026 Intel Corporation */
3 #include <linux/device.h>
4 #include <linux/dev_printk.h>
5 #include <linux/dma-mapping.h>
6 #include <linux/err.h>
7 #include <linux/interrupt.h>
8 #include <linux/module.h>
9 #include <linux/pci.h>
10 #include <linux/pm.h>
11 
12 #include "cdev.h"
13 #include "hw_heci.h"
14 #include "hw_heci_regs.h"
15 
16 static int issei_heci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
17 {
18 	struct device *dev = &pdev->dev;
19 	const struct hw_heci_cfg *cfg;
20 	struct issei_device *idev;
21 	struct issei_heci_hw *hw;
22 	char __iomem *registers;
23 	int err;
24 
25 	cfg = issei_heci_get_cfg(ent->driver_data);
26 	if (!cfg)
27 		return dev_err_probe(dev, -ENODEV, "no usable configuration.\n");
28 
29 	err = pcim_enable_device(pdev);
30 	if (err)
31 		return dev_err_probe(dev, err, "failed to enable pci device.\n");
32 
33 	pci_set_master(pdev);
34 
35 	registers = pcim_iomap_region(pdev, 0, KBUILD_MODNAME);
36 	if (IS_ERR(registers))
37 		return dev_err_probe(dev, PTR_ERR(registers), "failed to get pci region.\n");
38 
39 	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
40 	if (err)
41 		return dev_err_probe(dev, err, "no usable DMA configuration.\n");
42 
43 	idev = issei_register(sizeof(*hw), dev, &cfg->dma_length, issei_heci_get_ops());
44 	if (IS_ERR(idev))
45 		return dev_err_probe(dev, PTR_ERR(idev), "register failure.\n");
46 
47 	issei_heci_dev_init(idev, registers, cfg);
48 
49 	pci_set_drvdata(pdev, idev);
50 
51 	err = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
52 	if (err < 0) {
53 		dev_err_probe(dev, err, "pci_alloc_irq_vectors failure.\n");
54 		goto deregister;
55 	}
56 
57 	hw = to_heci_hw(idev);
58 	hw->irq = pci_irq_vector(pdev, 0);
59 
60 	err = request_threaded_irq(hw->irq,
61 				   issei_heci_irq_quick_handler,
62 				   NULL,
63 				   IRQF_SHARED, KBUILD_MODNAME, idev);
64 	if (err)
65 		goto release_irq;
66 
67 	err = issei_start(idev);
68 	if (err) {
69 		dev_err_probe(dev, err, "init hw failure.\n");
70 		goto free_irq;
71 	}
72 
73 	return 0;
74 
75 free_irq:
76 	idev->ops->irq_disable(idev);
77 	free_irq(hw->irq, idev);
78 release_irq:
79 	pci_free_irq_vectors(pdev);
80 deregister:
81 	issei_deregister(idev);
82 	return err;
83 }
84 
85 static void issei_heci_shutdown(struct pci_dev *pdev)
86 {
87 	struct issei_device *idev = pci_get_drvdata(pdev);
88 	struct issei_heci_hw *hw = to_heci_hw(idev);
89 
90 	issei_stop(idev);
91 
92 	idev->ops->irq_disable(idev);
93 	free_irq(hw->irq, idev);
94 	pci_free_irq_vectors(pdev);
95 }
96 
97 static void issei_heci_remove(struct pci_dev *pdev)
98 {
99 	issei_heci_shutdown(pdev);
100 
101 	issei_deregister(pci_get_drvdata(pdev));
102 }
103 
104 static int issei_heci_pm_suspend(struct device *device)
105 {
106 	struct issei_device *idev = dev_get_drvdata(device);
107 
108 	issei_stop(idev);
109 	idev->ops->irq_disable(idev);
110 
111 	return 0;
112 }
113 
114 static int issei_heci_pm_resume(struct device *device)
115 {
116 	struct issei_device *idev = dev_get_drvdata(device);
117 
118 	return issei_start(idev);
119 }
120 
121 static const struct dev_pm_ops issei_heci_pm_ops = {
122 	SYSTEM_SLEEP_PM_OPS(issei_heci_pm_suspend, issei_heci_pm_resume)
123 };
124 
125 static const struct pci_device_id heci_pci_tbl[] = {
126 	{PCI_VDEVICE(INTEL, 0xA85D)}, /* Lunar Lake M */
127 	{PCI_VDEVICE(INTEL, 0xE35D)}, /* Panther Lake H */
128 	{PCI_VDEVICE(INTEL, 0xE45D)}, /* Panther Lake P */
129 	{PCI_VDEVICE(INTEL, 0xD470)}, /* Nova Lake S */
130 	{PCI_VDEVICE(INTEL, 0xD358)}, /* Nova Lake H */
131 	{PCI_VDEVICE(INTEL, 0x4D5D)}, /* Wildcat Lake */
132 	{}
133 };
134 MODULE_DEVICE_TABLE(pci, heci_pci_tbl);
135 
136 static struct pci_driver issei_heci_driver = {
137 	.name = KBUILD_MODNAME,
138 	.id_table = heci_pci_tbl,
139 	.probe = issei_heci_probe,
140 	.remove = issei_heci_remove,
141 	.shutdown = issei_heci_shutdown,
142 	.driver = {
143 		.pm = &issei_heci_pm_ops,
144 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
145 	},
146 };
147 module_pci_driver(issei_heci_driver);
148 
149 MODULE_DESCRIPTION("Intel(R) Silicon Security Engine Interface - HECI");
150 MODULE_LICENSE("GPL");
151 MODULE_IMPORT_NS("INTEL_SSEI");
152