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