From b07319c849a174a85472144014aa3462f90343e0 Mon Sep 17 00:00:00 2001 From: hselasky Date: Wed, 14 Aug 2019 09:36:25 +0000 Subject: [PATCH] Implement pci_enable_msi() and pci_disable_msi() in the LinuxKPI. This patch makes the DRM graphics driver in ports usable on aarch64. Submitted by: Greg V Differential Revision: https://reviews.freebsd.org/D21008 MFC after: 1 week Sponsored by: Mellanox Technologies --- .../linuxkpi/common/include/linux/device.h | 4 +- .../linuxkpi/common/include/linux/interrupt.h | 6 ++- .../linuxkpi/common/include/linux/pci.h | 54 ++++++++++++++++--- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/device.h b/sys/compat/linuxkpi/common/include/linux/device.h index 629ca7b4588..bfbea7c4548 100644 --- a/sys/compat/linuxkpi/common/include/linux/device.h +++ b/sys/compat/linuxkpi/common/include/linux/device.h @@ -110,8 +110,8 @@ struct device { void *driver_data; unsigned int irq; #define LINUX_IRQ_INVALID 65535 - unsigned int msix; - unsigned int msix_max; + unsigned int irq_start; + unsigned int irq_end; const struct attribute_group **groups; struct fwnode_handle *fwnode; diff --git a/sys/compat/linuxkpi/common/include/linux/interrupt.h b/sys/compat/linuxkpi/common/include/linux/interrupt.h index dac5d5e92cc..6bb5880b6cd 100644 --- a/sys/compat/linuxkpi/common/include/linux/interrupt.h +++ b/sys/compat/linuxkpi/common/include/linux/interrupt.h @@ -55,9 +55,11 @@ struct irq_ent { static inline int linux_irq_rid(struct device *dev, unsigned int irq) { - if (irq == dev->irq) + /* check for MSI- or MSIX- interrupt */ + if (irq >= dev->irq_start && irq < dev->irq_end) + return (irq - dev->irq_start + 1); + else return (0); - return irq - dev->msix + 1; } extern void linux_irq_handler(void *); diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h index a938b730e97..82f1124efbc 100644 --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -228,6 +228,7 @@ struct pci_dev { unsigned int devfn; uint32_t class; uint8_t revision; + bool msi_enabled; }; static inline struct resource_list_entry * @@ -262,7 +263,7 @@ linux_pci_find_irq_dev(unsigned int irq) spin_lock(&pci_lock); list_for_each_entry(pdev, &pci_devices, links) { if (irq == pdev->dev.irq || - (irq >= pdev->dev.msix && irq < pdev->dev.msix_max)) { + (irq >= pdev->dev.irq_start && irq < pdev->dev.irq_end)) { found = &pdev->dev; break; } @@ -424,8 +425,23 @@ pci_disable_msix(struct pci_dev *pdev) * linux_pci_find_irq_dev() does no longer see them by * resetting their references to zero: */ - pdev->dev.msix = 0; - pdev->dev.msix_max = 0; + pdev->dev.irq_start = 0; + pdev->dev.irq_end = 0; +} + +#define pci_disable_msi(pdev) \ + linux_pci_disable_msi(pdev) + +static inline void +linux_pci_disable_msi(struct pci_dev *pdev) +{ + + pci_release_msi(pdev->dev.bsddev); + + pdev->dev.irq_start = 0; + pdev->dev.irq_end = 0; + pdev->irq = pdev->dev.irq; + pdev->msi_enabled = false; } unsigned long pci_resource_start(struct pci_dev *pdev, int bar); @@ -562,10 +578,10 @@ pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq) return avail; } rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1); - pdev->dev.msix = rle->start; - pdev->dev.msix_max = rle->start + avail; + pdev->dev.irq_start = rle->start; + pdev->dev.irq_end = rle->start + avail; for (i = 0; i < nreq; i++) - entries[i].vector = pdev->dev.msix + i; + entries[i].vector = pdev->dev.irq_start + i; return (0); } @@ -595,6 +611,32 @@ pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, return (nvec); } +#define pci_enable_msi(pdev) \ + linux_pci_enable_msi(pdev) + +static inline int +pci_enable_msi(struct pci_dev *pdev) +{ + struct resource_list_entry *rle; + int error; + int avail; + + avail = pci_msi_count(pdev->dev.bsddev); + if (avail < 1) + return -EINVAL; + + avail = 1; /* this function only enable one MSI IRQ */ + if ((error = -pci_alloc_msi(pdev->dev.bsddev, &avail)) != 0) + return error; + + rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1); + pdev->dev.irq_start = rle->start; + pdev->dev.irq_end = rle->start + avail; + pdev->irq = rle->start; + pdev->msi_enabled = true; + return (0); +} + static inline int pci_channel_offline(struct pci_dev *pdev) { -- 2.42.0