uart/ns16550, drivers/pcie: add PCI(e) support
A parallel PCI implementation ("pcie") is added with features for PCIe.
In particular, message-signaled interrupts (MSI) are supported, which
are essential to the use of any non-trivial PCIe device.
The NS16550 UART driver is modified to use pcie.
pcie is a complete replacement for the old PCI support ("pci"). It is
smaller, by an order of magnitude, and cleaner. Both pci and pcie can
(and do) coexist in the same builds, but the intent is to rework any
existing drivers that depend on pci and ultimately remove pci entirely.
This patch is large, but things in mirror are smaller than they appear.
Most of the modified files are configuration-related, and are changed
only slightly to accommodate the modified UART driver.
Deficiencies:
64-bit support is minimal. The code works fine with 64-bit capable
devices, but will not cooperate with MMIO regions (or MSI targets) that
have high bits set. This is not needed on any current boards, and is
unlikely to be needed in the future. Only superficial changes would
be required if we change our minds.
The method specifying PCI endpoints in devicetree is somewhat kludgey.
The "right" way would be to hang PCI devices off a topological tree;
while this would be more aesthetically pleasing, I don't think it's
worth the effort, given our non-standard use of devicetree.
Signed-off-by: Charles E. Youse <charles.youse@intel.com>
2019-04-03 01:06:07 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2019 Intel Corporation
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <drivers/pcie/pcie.h>
|
|
|
|
#include <drivers/pcie/msi.h>
|
|
|
|
|
|
|
|
/* functions documented in include/drivers/pcie/msi.h */
|
|
|
|
|
|
|
|
u32_t pcie_get_cap(pcie_bdf_t bdf, u32_t cap_id)
|
|
|
|
{
|
|
|
|
u32_t reg = 0U;
|
|
|
|
u32_t data;
|
|
|
|
|
|
|
|
data = pcie_conf_read(bdf, PCIE_CONF_CMDSTAT);
|
|
|
|
if (data & PCIE_CONF_CMDSTAT_CAPS) {
|
|
|
|
data = pcie_conf_read(bdf, PCIE_CONF_CAPPTR);
|
|
|
|
reg = PCIE_CONF_CAPPTR_FIRST(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (reg) {
|
|
|
|
data = pcie_conf_read(bdf, reg);
|
|
|
|
|
2019-06-04 22:52:23 +08:00
|
|
|
if (PCIE_CONF_CAP_ID(data) == cap_id) {
|
uart/ns16550, drivers/pcie: add PCI(e) support
A parallel PCI implementation ("pcie") is added with features for PCIe.
In particular, message-signaled interrupts (MSI) are supported, which
are essential to the use of any non-trivial PCIe device.
The NS16550 UART driver is modified to use pcie.
pcie is a complete replacement for the old PCI support ("pci"). It is
smaller, by an order of magnitude, and cleaner. Both pci and pcie can
(and do) coexist in the same builds, but the intent is to rework any
existing drivers that depend on pci and ultimately remove pci entirely.
This patch is large, but things in mirror are smaller than they appear.
Most of the modified files are configuration-related, and are changed
only slightly to accommodate the modified UART driver.
Deficiencies:
64-bit support is minimal. The code works fine with 64-bit capable
devices, but will not cooperate with MMIO regions (or MSI targets) that
have high bits set. This is not needed on any current boards, and is
unlikely to be needed in the future. Only superficial changes would
be required if we change our minds.
The method specifying PCI endpoints in devicetree is somewhat kludgey.
The "right" way would be to hang PCI devices off a topological tree;
while this would be more aesthetically pleasing, I don't think it's
worth the effort, given our non-standard use of devicetree.
Signed-off-by: Charles E. Youse <charles.youse@intel.com>
2019-04-03 01:06:07 +08:00
|
|
|
break;
|
2019-06-04 22:52:23 +08:00
|
|
|
}
|
uart/ns16550, drivers/pcie: add PCI(e) support
A parallel PCI implementation ("pcie") is added with features for PCIe.
In particular, message-signaled interrupts (MSI) are supported, which
are essential to the use of any non-trivial PCIe device.
The NS16550 UART driver is modified to use pcie.
pcie is a complete replacement for the old PCI support ("pci"). It is
smaller, by an order of magnitude, and cleaner. Both pci and pcie can
(and do) coexist in the same builds, but the intent is to rework any
existing drivers that depend on pci and ultimately remove pci entirely.
This patch is large, but things in mirror are smaller than they appear.
Most of the modified files are configuration-related, and are changed
only slightly to accommodate the modified UART driver.
Deficiencies:
64-bit support is minimal. The code works fine with 64-bit capable
devices, but will not cooperate with MMIO regions (or MSI targets) that
have high bits set. This is not needed on any current boards, and is
unlikely to be needed in the future. Only superficial changes would
be required if we change our minds.
The method specifying PCI endpoints in devicetree is somewhat kludgey.
The "right" way would be to hang PCI devices off a topological tree;
while this would be more aesthetically pleasing, I don't think it's
worth the effort, given our non-standard use of devicetree.
Signed-off-by: Charles E. Youse <charles.youse@intel.com>
2019-04-03 01:06:07 +08:00
|
|
|
|
|
|
|
reg = PCIE_CONF_CAP_NEXT(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool pcie_set_msi(pcie_bdf_t bdf, unsigned int irq)
|
|
|
|
{
|
|
|
|
bool success = false; /* keepin' the MISRA peeps employed */
|
|
|
|
u32_t base;
|
|
|
|
u32_t mcr;
|
|
|
|
u32_t map;
|
|
|
|
u32_t mdr;
|
|
|
|
|
|
|
|
map = pcie_msi_map(irq);
|
|
|
|
mdr = pcie_msi_mdr(irq);
|
|
|
|
base = pcie_get_cap(bdf, PCIE_MSI_CAP_ID);
|
|
|
|
|
|
|
|
if (base != 0U) {
|
|
|
|
mcr = pcie_conf_read(bdf, base + PCIE_MSI_MCR);
|
|
|
|
pcie_conf_write(bdf, base + PCIE_MSI_MAP0, map);
|
|
|
|
|
|
|
|
if (mcr & PCIE_MSI_MCR_64) {
|
|
|
|
pcie_conf_write(bdf, base + PCIE_MSI_MAP1_64, 0U);
|
|
|
|
pcie_conf_write(bdf, base + PCIE_MSI_MDR_64, mdr);
|
|
|
|
} else {
|
|
|
|
pcie_conf_write(bdf, base + PCIE_MSI_MDR_32, mdr);
|
|
|
|
}
|
|
|
|
|
|
|
|
mcr |= PCIE_MSI_MCR_EN;
|
|
|
|
mcr &= ~PCIE_MSI_MCR_MME; /* only 1 IRQ please */
|
|
|
|
pcie_conf_write(bdf, base + PCIE_MSI_MCR, mcr);
|
|
|
|
pcie_set_cmd(bdf, PCIE_CONF_CMDSTAT_MASTER, true);
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|