Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.17-rc4 100 lines 2.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * PCI Endpoint *Controller* (EPC) MSI library 4 * 5 * Copyright (C) 2025 NXP 6 * Author: Frank Li <Frank.Li@nxp.com> 7 */ 8 9#include <linux/device.h> 10#include <linux/export.h> 11#include <linux/irqdomain.h> 12#include <linux/module.h> 13#include <linux/msi.h> 14#include <linux/of_irq.h> 15#include <linux/pci-epc.h> 16#include <linux/pci-epf.h> 17#include <linux/pci-ep-cfs.h> 18#include <linux/pci-ep-msi.h> 19#include <linux/slab.h> 20 21static void pci_epf_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg) 22{ 23 struct pci_epc *epc; 24 struct pci_epf *epf; 25 26 epc = pci_epc_get(dev_name(msi_desc_to_dev(desc))); 27 if (!epc) 28 return; 29 30 epf = list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list); 31 32 if (epf && epf->db_msg && desc->msi_index < epf->num_db) 33 memcpy(&epf->db_msg[desc->msi_index].msg, msg, sizeof(*msg)); 34 35 pci_epc_put(epc); 36} 37 38int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db) 39{ 40 struct pci_epc *epc = epf->epc; 41 struct device *dev = &epf->dev; 42 struct irq_domain *domain; 43 void *msg; 44 int ret; 45 int i; 46 47 /* TODO: Multi-EPF support */ 48 if (list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list) != epf) { 49 dev_err(dev, "MSI doorbell doesn't support multiple EPF\n"); 50 return -EINVAL; 51 } 52 53 domain = of_msi_map_get_device_domain(epc->dev.parent, 0, 54 DOMAIN_BUS_PLATFORM_MSI); 55 if (!domain) { 56 dev_err(dev, "Can't find MSI domain for EPC\n"); 57 return -ENODEV; 58 } 59 60 if (!irq_domain_is_msi_parent(domain)) 61 return -ENODEV; 62 63 if (!irq_domain_is_msi_immutable(domain)) { 64 dev_err(dev, "Mutable MSI controller not supported\n"); 65 return -ENODEV; 66 } 67 68 dev_set_msi_domain(epc->dev.parent, domain); 69 70 msg = kcalloc(num_db, sizeof(struct pci_epf_doorbell_msg), GFP_KERNEL); 71 if (!msg) 72 return -ENOMEM; 73 74 epf->num_db = num_db; 75 epf->db_msg = msg; 76 77 ret = platform_device_msi_init_and_alloc_irqs(epc->dev.parent, num_db, 78 pci_epf_write_msi_msg); 79 if (ret) { 80 dev_err(dev, "Failed to allocate MSI\n"); 81 kfree(msg); 82 return ret; 83 } 84 85 for (i = 0; i < num_db; i++) 86 epf->db_msg[i].virq = msi_get_virq(epc->dev.parent, i); 87 88 return ret; 89} 90EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell); 91 92void pci_epf_free_doorbell(struct pci_epf *epf) 93{ 94 platform_device_msi_free_irqs_all(epf->epc->dev.parent); 95 96 kfree(epf->db_msg); 97 epf->db_msg = NULL; 98 epf->num_db = 0; 99} 100EXPORT_SYMBOL_GPL(pci_epf_free_doorbell);