|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] ns16550: enable use of PCI MSI
commit ae01a8e315fecb1914edd99980a619d387951d3f
Author: Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Thu Dec 6 12:21:34 2018 +0100
Commit: Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Dec 6 12:21:34 2018 +0100
ns16550: enable use of PCI MSI
Which, on x86, requires fiddling with the INTx bit in PCI config space,
since for internally used MSI we can't delegate this to Dom0.
ns16550_init_postirq() also needs (benign) re-ordering of its
operations.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
Acked-by: Wei Liu <wei.liu2@xxxxxxxxxx>
Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
---
docs/misc/xen-command-line.markdown | 4 +-
xen/arch/x86/msi.c | 24 ++++++++++
xen/drivers/char/ns16550.c | 93 ++++++++++++++++++++++++++++++++-----
xen/drivers/pci/pci.c | 15 ++++++
xen/include/xen/pci.h | 1 +
5 files changed, 123 insertions(+), 14 deletions(-)
diff --git a/docs/misc/xen-command-line.markdown
b/docs/misc/xen-command-line.markdown
index 764f33a3ca..6f671d3219 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -278,7 +278,7 @@ Flag to indicate whether to probe for a CMOS Real Time
Clock irrespective of
ACPI indicating none to be there.
### com1,com2
-> `=
<baud>[/<base-baud>][,[DPS][,[<io-base>|pci|amt][,[<irq>][,[<port-bdf>][,[<bridge-bdf>]]]]]]`
+> `=
<baud>[/<base-baud>][,[DPS][,[<io-base>|pci|amt][,[<irq>|msi][,[<port-bdf>][,[<bridge-bdf>]]]]]]`
Both option `com1` and `com2` follow the same format.
@@ -299,7 +299,7 @@ Both option `com1` and `com2` follow the same format.
* `<io-base>` is an integer which specifies the IO base port for UART
registers.
* `<irq>` is the IRQ number to use, or `0` to use the UART in poll
- mode only.
+ mode only, or `msi` to set up a Message Signaled Interrupt.
* `<port-bdf>` is the PCI location of the UART, in
`<bus>:<device>.<function>` notation.
* `<bridge-bdf>` is the PCI bridge behind which is the UART, in
diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c
index 5567990fbd..babc4147c4 100644
--- a/xen/arch/x86/msi.c
+++ b/xen/arch/x86/msi.c
@@ -742,6 +742,16 @@ static int msi_capability_init(struct pci_dev *dev,
*desc = entry;
/* Restore the original MSI enabled bits */
+ if ( !hardware_domain )
+ {
+ /*
+ * ..., except for internal requests (before Dom0 starts), in which
+ * case we rather need to behave "normally", i.e. not follow the split
+ * brain model where Dom0 actually enables MSI (and disables INTx).
+ */
+ pci_intx(dev, false);
+ control |= PCI_MSI_FLAGS_ENABLE;
+ }
pci_conf_write16(seg, bus, slot, func, msi_control_reg(pos), control);
return 0;
@@ -1019,6 +1029,18 @@ static int msix_capability_init(struct pci_dev *dev,
++msix->used_entries;
/* Restore MSI-X enabled bits */
+ if ( !hardware_domain )
+ {
+ /*
+ * ..., except for internal requests (before Dom0 starts), in which
+ * case we rather need to behave "normally", i.e. not follow the split
+ * brain model where Dom0 actually enables MSI (and disables INTx).
+ */
+ pci_intx(dev, false);
+ control |= PCI_MSIX_FLAGS_ENABLE;
+ control &= ~PCI_MSIX_FLAGS_MASKALL;
+ maskall = 0;
+ }
msix->host_maskall = maskall;
pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos), control);
@@ -1073,6 +1095,8 @@ static void __pci_disable_msi(struct msi_desc *entry)
dev = entry->dev;
msi_set_enable(dev, 0);
+ if ( entry->irq > 0 && !(irq_to_desc(entry->irq)->status & IRQ_GUEST) )
+ pci_intx(dev, true);
BUG_ON(list_empty(&dev->msi_list));
}
diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index 3eba56eadc..189e121b7e 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -92,6 +92,7 @@ static struct ns16550 {
u32 bar64;
u16 cr;
u8 bar_idx;
+ bool msi;
const struct ns16550_config_param *param; /* Points into .init.*! */
#endif
} ns16550_com[2] = { { 0 } };
@@ -712,6 +713,16 @@ static void __init ns16550_init_preirq(struct serial_port
*port)
uart->fifo_size = 16;
}
+static void __init ns16550_init_irq(struct serial_port *port)
+{
+#ifdef CONFIG_HAS_PCI
+ struct ns16550 *uart = port->uart;
+
+ if ( uart->msi )
+ uart->irq = create_irq(0);
+#endif
+}
+
static void ns16550_setup_postirq(struct ns16550 *uart)
{
if ( uart->irq > 0 )
@@ -746,17 +757,6 @@ static void __init ns16550_init_postirq(struct serial_port
*port)
uart->timeout_ms = max_t(
unsigned int, 1, (bits * uart->fifo_size * 1000) / uart->baud);
- if ( uart->irq > 0 )
- {
- uart->irqaction.handler = ns16550_interrupt;
- uart->irqaction.name = "ns16550";
- uart->irqaction.dev_id = port;
- if ( (rc = setup_irq(uart->irq, 0, &uart->irqaction)) != 0 )
- printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
- }
-
- ns16550_setup_postirq(uart);
-
#ifdef CONFIG_HAS_PCI
if ( uart->bar || uart->ps_bdf_enable )
{
@@ -777,8 +777,65 @@ static void __init ns16550_init_postirq(struct serial_port
*port)
uart->ps_bdf[0], uart->ps_bdf[1],
uart->ps_bdf[2]);
}
+
+ if ( uart->msi )
+ {
+ struct msi_info msi = {
+ .bus = uart->ps_bdf[0],
+ .devfn = PCI_DEVFN(uart->ps_bdf[1], uart->ps_bdf[2]),
+ .irq = rc = uart->irq,
+ .entry_nr = 1
+ };
+
+ if ( rc > 0 )
+ {
+ struct msi_desc *msi_desc = NULL;
+
+ pcidevs_lock();
+
+ rc = pci_enable_msi(&msi, &msi_desc);
+ if ( !rc )
+ {
+ struct irq_desc *desc = irq_to_desc(msi.irq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ rc = setup_msi_irq(desc, msi_desc);
+ spin_unlock_irqrestore(&desc->lock, flags);
+ if ( rc )
+ pci_disable_msi(msi_desc);
+ }
+
+ pcidevs_unlock();
+
+ if ( rc )
+ {
+ uart->irq = 0;
+ if ( msi_desc )
+ msi_free_irq(msi_desc);
+ else
+ destroy_irq(msi.irq);
+ }
+ }
+
+ if ( rc )
+ printk(XENLOG_WARNING
+ "MSI setup failed (%d) for %02x:%02x.%o\n",
+ rc, uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2]);
+ }
}
#endif
+
+ if ( uart->irq > 0 )
+ {
+ uart->irqaction.handler = ns16550_interrupt;
+ uart->irqaction.name = "ns16550";
+ uart->irqaction.dev_id = port;
+ if ( (rc = setup_irq(uart->irq, 0, &uart->irqaction)) != 0 )
+ printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
+ }
+
+ ns16550_setup_postirq(uart);
}
static void ns16550_suspend(struct serial_port *port)
@@ -908,6 +965,7 @@ static const struct vuart_info *ns16550_vuart_info(struct
serial_port *port)
static struct uart_driver __read_mostly ns16550_driver = {
.init_preirq = ns16550_init_preirq,
+ .init_irq = ns16550_init_irq,
.init_postirq = ns16550_init_postirq,
.endboot = ns16550_endboot,
.suspend = ns16550_suspend,
@@ -1261,7 +1319,18 @@ static bool __init parse_positional(struct ns16550
*uart, char **str)
}
if ( *conf == ',' && *++conf != ',' )
- uart->irq = simple_strtol(conf, &conf, 10);
+ {
+#ifdef CONFIG_HAS_PCI
+ if ( strncmp(conf, "msi", 3) == 0 )
+ {
+ conf += 3;
+ uart->msi = true;
+ uart->irq = 0;
+ }
+ else
+#endif
+ uart->irq = simple_strtol(conf, &conf, 10);
+ }
#ifdef CONFIG_HAS_PCI
if ( *conf == ',' && *++conf != ',' )
diff --git a/xen/drivers/pci/pci.c b/xen/drivers/pci/pci.c
index 13d3309ad4..1c808d6632 100644
--- a/xen/drivers/pci/pci.c
+++ b/xen/drivers/pci/pci.c
@@ -115,6 +115,21 @@ int pci_find_next_ext_capability(int seg, int bus, int
devfn, int start, int cap
return 0;
}
+void pci_intx(const struct pci_dev *pdev, bool enable)
+{
+ uint16_t seg = pdev->seg;
+ uint8_t bus = pdev->bus;
+ uint8_t slot = PCI_SLOT(pdev->devfn);
+ uint8_t func = PCI_FUNC(pdev->devfn);
+ uint16_t cmd = pci_conf_read16(seg, bus, slot, func, PCI_COMMAND);
+
+ if ( enable )
+ cmd &= ~PCI_COMMAND_INTX_DISABLE;
+ else
+ cmd |= PCI_COMMAND_INTX_DISABLE;
+ pci_conf_write16(seg, bus, slot, func, PCI_COMMAND, cmd);
+}
+
const char *__init parse_pci(const char *s, unsigned int *seg_p,
unsigned int *bus_p, unsigned int *dev_p,
unsigned int *func_p)
diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
index a934662713..8b21e8dc84 100644
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -200,6 +200,7 @@ unsigned int pci_size_mem_bar(pci_sbdf_t sbdf, unsigned int
pos,
uint64_t *paddr, uint64_t *psize,
unsigned int flags);
+void pci_intx(const struct pci_dev *, bool enable);
bool_t pcie_aer_get_firmware_first(const struct pci_dev *);
struct pirq;
--
generated by git-patchbot for /home/xen/git/xen.git#master
_______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |