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