|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v2 2/2] ns16550: enable use of PCI MSI
On Mon, Oct 01, 2018 at 10:26:05AM -0600, Jan Beulich wrote:
> 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>
> ---
> v2: Re-base.
>
> --- a/docs/misc/xen-command-line.markdown
> +++ b/docs/misc/xen-command-line.markdown
> @@ -307,7 +307,7 @@ Flag to indicate whether to probe for a
> 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.
>
> @@ -328,7 +328,7 @@ Both option `com1` and `com2` follow the
> * `<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
> --- a/xen/arch/x86/msi.c
> +++ b/xen/arch/x86/msi.c
> @@ -742,6 +742,16 @@ static int msi_capability_init(struct pc
>
> *desc = entry;
> /* Restore the original MSI enabled bits */
> + if ( !hardware_domain )
Wouldn't it be better to assign the device to dom_xen (pdev->domain =
dom_xen), and then check if the owner is dom_xen here?
Or at the point where this is called from the serial console driver is
too early for dom_xen to exist?
> + {
> + /*
> + * ..., 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, 0);
If you use bool with pci_intx then you can just pass false here.
> + 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 p
> ++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, 0);
> + 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
>
> dev = entry->dev;
> msi_set_enable(dev, 0);
> + if ( entry->irq > 0 && !(irq_to_desc(entry->irq)->status & IRQ_GUEST) )
> + pci_intx(dev, 1);
>
> BUG_ON(list_empty(&dev->msi_list));
> }
> --- 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_t 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(s
> 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(
> 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(
> 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);
Before attempting to enable MSI, shouldn't you make sure memory
decoding is enabled in case the device uses MSIX?
I think this code assumes the device will always use MSI? (in which
case my above question is likely moot).
> + 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_
>
> 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(stru
> }
>
> if ( *conf == ',' && *++conf != ',' )
> - uart->irq = simple_strtol(conf, &conf, 10);
> + {
> +#ifdef CONFIG_HAS_PCI
> + if ( strncmp(conf, "msi", 3) == 0 )
> + {
> + conf += 3;
> + uart->msi = 1;
> + uart->irq = 0;
> + }
> + else
> +#endif
> + uart->irq = simple_strtol(conf, &conf, 10);
> + }
>
> #ifdef CONFIG_HAS_PCI
> if ( *conf == ',' && *++conf != ',' )
> --- a/xen/drivers/pci/pci.c
> +++ b/xen/drivers/pci/pci.c
> @@ -115,6 +115,21 @@ int pci_find_next_ext_capability(int seg
> return 0;
> }
>
> +void pci_intx(const struct pci_dev *pdev, bool_t enable)
Please use bool.
Thanks, Roger.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |