RE: [RFC PATCH 10/11] PCI/MSI: Split the generic MSI code into new file
-Original Message- From: linux-pci-ow...@vger.kernel.org [mailto:linux-pci-ow...@vger.kernel.org] On Behalf Of Yijing Wang Sent: Saturday, July 26, 2014 8:39 AM To: linux-ker...@vger.kernel.org Cc: Xinwei Hu; Wuyun; Bjorn Helgaas; linux-...@vger.kernel.org; paul.mu...@huawei.com; James E.J. Bottomley; Marc Zyngier; linux-arm- ker...@lists.infradead.org; Russell King; linux-a...@vger.kernel.org; Basu Arnab-B45036; virtualization@lists.linux-foundation.org; Hanjun Guo; Yijing Wang Subject: [RFC PATCH 10/11] PCI/MSI: Split the generic MSI code into new file MSI interrupt will not only used in PCI device, more and more Non-PCI device also want to use MSI. ARM GIC v3 spec says in ARM platform with GIC v3 controller, Non-PCI device can also be design to support MSI to simplify interrupt wires, for the existing Non-PCI device, consolidator is designed and used to translate legacy interrupt to MSI. So for support Non-PCI MSI device, generic MSI driver is needed. Split the generic MSI code into new location, drivers/msi/msi.c. Then MSI driver does not depend PCI anymore. Signed-off-by: Yijing Wang wangyij...@huawei.com --- drivers/Kconfig |1 + drivers/Makefile |1 + drivers/msi/Kconfig |8 + drivers/msi/Makefile |1 + drivers/msi/msi.c| 540 ++ drivers/pci/Kconfig |6 +- drivers/pci/msi.c| 500 --- include/linux/msi.h | 31 +++- 8 files changed, 617 insertions(+), 471 deletions(-) create mode 100644 drivers/msi/Kconfig create mode 100644 drivers/msi/Makefile create mode 100644 drivers/msi/msi.c diff --git a/drivers/Kconfig b/drivers/Kconfig index 0e87a34..4d05749 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -176,4 +176,5 @@ source drivers/powercap/Kconfig source drivers/mcb/Kconfig +source drivers/msi/Kconfig endmenu diff --git a/drivers/Makefile b/drivers/Makefile index f98b50d..47ae3d1 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -158,3 +158,4 @@ obj-$(CONFIG_NTB) += ntb/ obj-$(CONFIG_FMC)+= fmc/ obj-$(CONFIG_POWERCAP) += powercap/ obj-$(CONFIG_MCB)+= mcb/ +obj-$(CONFIG_MSI)+= msi/ diff --git a/drivers/msi/Kconfig b/drivers/msi/Kconfig new file mode 100644 index 000..739bd13 --- /dev/null +++ b/drivers/msi/Kconfig @@ -0,0 +1,8 @@ +config MSI + bool Message Signaled Interrupts (MSI and MSI-X) + default y + help + This allows device drivers to use generic MSI(Message + Signaled Interrupt). Message Signaled Interrupts enable + a device to generate an interrupt using an inbound Memory + Write to a specific target address. diff --git a/drivers/msi/Makefile b/drivers/msi/Makefile new file mode 100644 index 000..39cb026 --- /dev/null +++ b/drivers/msi/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MSI) += msi.o diff --git a/drivers/msi/msi.c b/drivers/msi/msi.c new file mode 100644 index 000..3fbd539 --- /dev/null +++ b/drivers/msi/msi.c @@ -0,0 +1,540 @@ +/* + * File: msi.c + * Purpose: Message Signaled Interrupt (MSI) + * + * Copyright (C) 2014 Huawei Ltd. + * Copyright (C) Yijing Wang wangyij...@huawei.com + */ +#include linux/err.h +#include linux/mm.h +#include linux/irq.h +#include linux/interrupt.h +#include linux/export.h +#include linux/ioport.h +#include linux/proc_fs.h +#include linux/msi.h +#include linux/smp.h +#include linux/errno.h +#include linux/io.h +#include linux/slab.h +#include linux/device.h +#include linux/pci.h + +/* Arch hooks */ + +int __weak arch_setup_msi_irq(struct msi_irqs *msi, struct msi_desc *desc) +{ + struct pci_dev *dev = msi-data; + struct msi_chip *chip = dev-bus-msi; //TO BE DONE: rework msi_chip to support Non-PCI MSI + int err; + + if (!chip || !chip-setup_irq) + return -EINVAL; + + err = chip-setup_irq(chip, dev, desc); + if (err 0) + return err; + + irq_set_chip_data(desc-irq, chip); + return 0; +} + +void __weak arch_teardown_msi_irq(unsigned int irq) +{ + struct msi_chip *chip = irq_get_chip_data(irq); + + if (!chip || !chip-teardown_irq) + return; + + chip-teardown_irq(chip, irq); +} + +int __weak arch_msi_check_device(struct msi_irqs *msi, int nvec, int type) +{ + struct pci_dev *dev = msi-data; + struct msi_chip *chip = dev-bus-msi; //TO BE DONE: rework msi_chip to support Non-PCI MSI + + if (!chip || !chip-check_device) + return 0; + + return chip-check_device(chip, dev, nvec, type); +} + +int __weak arch_setup_msi_irqs(struct msi_irqs *msi, int nvec, int type) +{ + struct msi_desc *entry; + int ret; + + /* + * If an architecture wants to support multiple MSI, it needs to + * override
Re: [RFC PATCH 10/11] PCI/MSI: Split the generic MSI code into new file
+int msi_capability_init(struct msi_irqs *msi, int nvec) +{ +struct msi_desc *entry; +int ret; +unsigned mask; + +msi_set_enable(msi, 0, MSI_TYPE); /* Disable MSI during set up */ + +/* MSI Entry Initialization */ +entry = msi_setup_entry(msi); +if (!entry) +return -ENOMEM; + +/* All MSIs are unmasked by default, Mask them all */ Will this be true for non-pci devices as well? In my opinion, yes, I think all msi devices should be masked during the setup. Of course, mask and unmask functions will be override by private mask/unmask functions. Thanks -Bharat +mask = msi_mask(entry-msi_attrib.multi_cap); +msi_mask_irq(entry, mask, mask); + +/* Configure MSI capability structure */ +ret = arch_setup_msi_irqs(msi, nvec, MSI_TYPE); +if (ret) +goto err; + +/* Set MSI enabled bits */ +msi_set_intx(msi, 0); +msi_set_enable(msi, 1, MSI_TYPE); +msi-msi_enabled = 1; + +return 0; + +err: +msi_mask_irq(entry, mask, ~mask); +free_msi_irqs(msi); +return ret; +} + +static void msix_program_entries(struct msi_irqs *msi, + struct msix_entry *entries) +{ +struct msi_desc *entry; +int i = 0; + +list_for_each_entry(entry, msi-msi_list, list) { +entries[i].vector = entry-irq; +irq_set_msi_desc(entry-irq, entry); +i++; +} +} + +/** + * msix_capability_init - configure device's MSI-X capability + * @dev: pointer to the pci_dev data structure of MSI-X device function + * @entries: pointer to an array of struct msix_entry entries + * @nvec: number of @entries + * + * Setup the MSI-X capability structure of device function with a + * single MSI-X irq. A return of zero indicates the successful setup of + * requested MSI-X entries with allocated irqs or non-zero for otherwise. + **/ +int msix_capability_init(struct msi_irqs *msi, void __iomem *base, +struct msix_entry *entries, int nvec) +{ +int ret; + +/* Ensure MSI-X is disabled while it is set up */ +msi_set_enable(msi, 0, MSIX_TYPE); + +ret = msix_setup_entries(msi, base, entries, nvec); +if (ret) +return ret; + +ret = arch_setup_msi_irqs(msi, nvec, MSIX_TYPE); +if (ret) +goto out_avail; + +msix_program_entries(msi, entries); + +/* Set MSI-X enabled bits and unmask the function */ +msi_set_intx(msi, 0); +msi-msix_enabled = 1; + +msi_set_enable(msi, 1, MSIX_TYPE); + +return 0; + +out_avail: +if (ret 0) { +/* + * If we had some success, report the number of irqs + * we succeeded in setting up. + */ +struct msi_desc *entry; +int avail = 0; + +list_for_each_entry(entry, msi-msi_list, list) { +if (entry-irq != 0) +avail++; +} +if (avail != 0) +ret = avail; +} + +free_msi_irqs(msi); + +return ret; +} + diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 893503f..1a10488 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -2,10 +2,10 @@ # PCI configuration # config PCI_MSI -bool Message Signaled Interrupts (MSI and MSI-X) -depends on PCI +bool PCI Message Signaled Interrupts (MSI and MSI-X) +depends on PCI MSI help - This allows device drivers to enable MSI (Message Signaled + This allows PCI device drivers to enable MSI (Message Signaled Interrupts). Message Signaled Interrupts enable a device to generate an interrupt using an inbound Memory Write on its PCI bus instead of asserting a device IRQ pin. diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f0c5989..df7223c 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -26,121 +26,8 @@ static int pci_msi_enable = 1; #define msix_table_size(flags) ((flags PCI_MSIX_FLAGS_QSIZE) + 1) - -/* Arch hooks */ - -int __weak arch_setup_msi_irq(struct msi_irqs *msi, struct msi_desc *desc) -{ -struct pci_dev *dev = msi-data; //TO BE DONE: rework msi_chip to support Non-PCI -struct msi_chip *chip = dev-bus-msi; -int err; - -if (!chip || !chip-setup_irq) -return -EINVAL; - -err = chip-setup_irq(chip, dev, desc); -if (err 0) -return err; - -irq_set_chip_data(desc-irq, chip); - -return 0; -} - -void __weak arch_teardown_msi_irq(unsigned int irq) -{ -struct msi_chip *chip = irq_get_chip_data(irq); - -if (!chip || !chip-teardown_irq) -return; - -chip-teardown_irq(chip, irq); -} - -int __weak arch_msi_check_device(struct msi_irqs *msi, int nvec, int type) -{ -struct pci_dev *dev = msi-data; //TO BE DONE: rework
[RFC PATCH 10/11] PCI/MSI: Split the generic MSI code into new file
MSI interrupt will not only used in PCI device, more and more Non-PCI device also want to use MSI. ARM GIC v3 spec says in ARM platform with GIC v3 controller, Non-PCI device can also be design to support MSI to simplify interrupt wires, for the existing Non-PCI device, consolidator is designed and used to translate legacy interrupt to MSI. So for support Non-PCI MSI device, generic MSI driver is needed. Split the generic MSI code into new location, drivers/msi/msi.c. Then MSI driver does not depend PCI anymore. Signed-off-by: Yijing Wang wangyij...@huawei.com --- drivers/Kconfig |1 + drivers/Makefile |1 + drivers/msi/Kconfig |8 + drivers/msi/Makefile |1 + drivers/msi/msi.c| 540 ++ drivers/pci/Kconfig |6 +- drivers/pci/msi.c| 500 --- include/linux/msi.h | 31 +++- 8 files changed, 617 insertions(+), 471 deletions(-) create mode 100644 drivers/msi/Kconfig create mode 100644 drivers/msi/Makefile create mode 100644 drivers/msi/msi.c diff --git a/drivers/Kconfig b/drivers/Kconfig index 0e87a34..4d05749 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -176,4 +176,5 @@ source drivers/powercap/Kconfig source drivers/mcb/Kconfig +source drivers/msi/Kconfig endmenu diff --git a/drivers/Makefile b/drivers/Makefile index f98b50d..47ae3d1 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -158,3 +158,4 @@ obj-$(CONFIG_NTB) += ntb/ obj-$(CONFIG_FMC) += fmc/ obj-$(CONFIG_POWERCAP) += powercap/ obj-$(CONFIG_MCB) += mcb/ +obj-$(CONFIG_MSI) += msi/ diff --git a/drivers/msi/Kconfig b/drivers/msi/Kconfig new file mode 100644 index 000..739bd13 --- /dev/null +++ b/drivers/msi/Kconfig @@ -0,0 +1,8 @@ +config MSI + bool Message Signaled Interrupts (MSI and MSI-X) + default y + help + This allows device drivers to use generic MSI(Message + Signaled Interrupt). Message Signaled Interrupts enable + a device to generate an interrupt using an inbound Memory + Write to a specific target address. diff --git a/drivers/msi/Makefile b/drivers/msi/Makefile new file mode 100644 index 000..39cb026 --- /dev/null +++ b/drivers/msi/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MSI) += msi.o diff --git a/drivers/msi/msi.c b/drivers/msi/msi.c new file mode 100644 index 000..3fbd539 --- /dev/null +++ b/drivers/msi/msi.c @@ -0,0 +1,540 @@ +/* + * File: msi.c + * Purpose:Message Signaled Interrupt (MSI) + * + * Copyright (C) 2014 Huawei Ltd. + * Copyright (C) Yijing Wang wangyij...@huawei.com + */ +#include linux/err.h +#include linux/mm.h +#include linux/irq.h +#include linux/interrupt.h +#include linux/export.h +#include linux/ioport.h +#include linux/proc_fs.h +#include linux/msi.h +#include linux/smp.h +#include linux/errno.h +#include linux/io.h +#include linux/slab.h +#include linux/device.h +#include linux/pci.h + +/* Arch hooks */ + +int __weak arch_setup_msi_irq(struct msi_irqs *msi, struct msi_desc *desc) +{ + struct pci_dev *dev = msi-data; + struct msi_chip *chip = dev-bus-msi; //TO BE DONE: rework msi_chip to support Non-PCI MSI + int err; + + if (!chip || !chip-setup_irq) + return -EINVAL; + + err = chip-setup_irq(chip, dev, desc); + if (err 0) + return err; + + irq_set_chip_data(desc-irq, chip); + return 0; +} + +void __weak arch_teardown_msi_irq(unsigned int irq) +{ + struct msi_chip *chip = irq_get_chip_data(irq); + + if (!chip || !chip-teardown_irq) + return; + + chip-teardown_irq(chip, irq); +} + +int __weak arch_msi_check_device(struct msi_irqs *msi, int nvec, int type) +{ + struct pci_dev *dev = msi-data; + struct msi_chip *chip = dev-bus-msi; //TO BE DONE: rework msi_chip to support Non-PCI MSI + + if (!chip || !chip-check_device) + return 0; + + return chip-check_device(chip, dev, nvec, type); +} + +int __weak arch_setup_msi_irqs(struct msi_irqs *msi, int nvec, int type) +{ + struct msi_desc *entry; + int ret; + + /* +* If an architecture wants to support multiple MSI, it needs to +* override arch_setup_msi_irqs() +*/ + if (type == MSI_TYPE nvec 1) + return 1; + + list_for_each_entry(entry, msi-msi_list, list) { + ret = arch_setup_msi_irq(msi, entry); + if (ret 0) + return ret; + if (ret 0) + return -ENOSPC; + } + return 0; +} + + +void __weak arch_teardown_msi_irqs(struct msi_irqs *msi) +{ + return default_teardown_msi_irqs(msi); +} + +/* + * We have a default implementation available as a separate non-weak + * function, as it is used by the Xen x86 PCI code + */ +void