From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Jan Beulich" Subject: [PATCH RFC 4/4] ns16550: enable use of PCI MSI Date: Tue, 23 Feb 2016 04:30:41 -0700 Message-ID: <56CC50F102000078000D52DB@prv-mh.provo.novell.com> References: <56CC4F0B02000078000D5290@prv-mh.provo.novell.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=__Part4176D6F1.2__=" Return-path: Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1aYBB1-00033J-Hh for xen-devel@lists.xenproject.org; Tue, 23 Feb 2016 11:30:47 +0000 In-Reply-To: <56CC4F0B02000078000D5290@prv-mh.provo.novell.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel Cc: Ian Campbell , Andrew Cooper , Keir Fraser , Ian Jackson , Tim Deegan List-Id: xen-devel@lists.xenproject.org This is a MIME message. If you are reading this text, you may want to consider changing to a mail reader or gateway that understands how to properly handle MIME multipart messages. --=__Part4176D6F1.2__= Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable Content-Disposition: inline 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 --- RFC reason: No interrupts occur for an unknown reason (presumably broken hardware/firmware on the device I have). --- a/xen/arch/x86/msi.c +++ b/xen/arch/x86/msi.c @@ -738,6 +738,16 @@ static int msi_capability_init(struct pc =20 *desc =3D 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, 0); + control |=3D PCI_MSI_FLAGS_ENABLE; + } pci_conf_write16(seg, bus, slot, func, msi_control_reg(pos), = control); =20 return 0; @@ -1071,6 +1081,8 @@ static void __pci_disable_msi(struct msi =20 dev =3D entry->dev; msi_set_enable(dev, 0); + if ( entry->irq > 0 && !(irq_to_desc(entry->irq)->status & IRQ_GUEST) = ) + pci_intx(dev, 1); =20 BUG_ON(list_empty(&dev->msi_list)); } --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -74,6 +74,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] =3D { { 0 } }; @@ -644,6 +645,16 @@ static void __init ns16550_init_preirq(s uart->fifo_size =3D 16; } =20 +static void __init ns16550_init_irq(struct serial_port *port) +{ +#ifdef CONFIG_HAS_PCI + struct ns16550 *uart =3D port->uart; + + if ( uart->msi ) + uart->irq =3D create_irq(0); +#endif +} + static void ns16550_setup_postirq(struct ns16550 *uart) { if ( uart->irq > 0 ) @@ -678,17 +689,6 @@ static void __init ns16550_init_postirq( uart->timeout_ms =3D max_t( unsigned int, 1, (bits * uart->fifo_size * 1000) / uart->baud); =20 - if ( uart->irq > 0 ) - { - uart->irqaction.handler =3D ns16550_interrupt; - uart->irqaction.name =3D "ns16550"; - uart->irqaction.dev_id =3D port; - if ( (rc =3D setup_irq(uart->irq, 0, &uart->irqaction)) !=3D 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 ) { @@ -709,8 +709,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 =3D { + .bus =3D uart->ps_bdf[0], + .devfn =3D PCI_DEVFN(uart->ps_bdf[1], uart->ps_bdf[2]), + .irq =3D rc =3D uart->irq, + .entry_nr =3D 1 + }; + + if ( rc > 0 ) + { + struct msi_desc *msi_desc =3D NULL; + + spin_lock(&pcidevs_lock); + + rc =3D pci_enable_msi(&msi, &msi_desc); + if ( !rc ) + { + struct irq_desc *desc =3D irq_to_desc(msi.irq); + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + rc =3D setup_msi_irq(desc, msi_desc); + spin_unlock_irqrestore(&desc->lock, flags); + if ( rc ) + pci_disable_msi(msi_desc); + } + + spin_unlock(&pcidevs_lock); + + if ( rc ) + { + uart->irq =3D 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 =3D ns16550_interrupt; + uart->irqaction.name =3D "ns16550"; + uart->irqaction.dev_id =3D port; + if ( (rc =3D setup_irq(uart->irq, 0, &uart->irqaction)) !=3D 0 ) + printk("ERROR: Failed to allocate ns16550 IRQ %d\n", = uart->irq); + } + + ns16550_setup_postirq(uart); } =20 static void ns16550_suspend(struct serial_port *port) @@ -820,6 +877,7 @@ static const struct vuart_info *ns16550_ =20 static struct uart_driver __read_mostly ns16550_driver =3D { .init_preirq =3D ns16550_init_preirq, + .init_irq =3D ns16550_init_irq, .init_postirq =3D ns16550_init_postirq, .endboot =3D ns16550_endboot, .suspend =3D ns16550_suspend, @@ -1123,7 +1181,18 @@ static void __init ns16550_parse_port_co } =20 if ( *conf =3D=3D ',' && *++conf !=3D ',' ) - uart->irq =3D simple_strtol(conf, &conf, 10); + { +#ifdef CONFIG_HAS_PCI + if ( strncmp(conf, "msi", 3) =3D=3D 0 ) + { + conf +=3D 3; + uart->msi =3D 1; + uart->irq =3D 0; + } + else +#endif + uart->irq =3D simple_strtol(conf, &conf, 10); + } =20 #ifdef CONFIG_HAS_PCI if ( *conf =3D=3D ',' && *++conf !=3D ',' ) --- 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; } =20 +void pci_intx(const struct pci_dev *pdev, bool_t enable) +{ + uint16_t seg =3D pdev->seg; + uint8_t bus =3D pdev->bus; + uint8_t slot =3D PCI_SLOT(pdev->devfn); + uint8_t func =3D PCI_FUNC(pdev->devfn); + uint16_t cmd =3D pci_conf_read16(seg, bus, slot, func, PCI_COMMAND); + + if ( enable ) + cmd &=3D ~PCI_COMMAND_INTX_DISABLE; + else + cmd |=3D 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) --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -152,6 +152,7 @@ int pci_find_next_ext_capability(int seg const char *parse_pci(const char *, unsigned int *seg, unsigned int *bus, unsigned int *dev, unsigned int *func); =20 +void pci_intx(const struct pci_dev *, bool_t enable); bool_t pcie_aer_get_firmware_first(const struct pci_dev *); =20 struct pirq; --=__Part4176D6F1.2__= Content-Type: text/plain; name="ns16550-MSI.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="ns16550-MSI.patch" ns16550: enable use of PCI MSI=0A=0AWhich, on x86, requires fiddling with = the INTx bit in PCI config space,=0Asince for internally used MSI we can't = delegate this to Dom0.=0A=0Ans16550_init_postirq() also needs (benign) = re-ordering of its=0Aoperations.=0A=0ASigned-off-by: Jan Beulich =0A---=0ARFC reason: No interrupts occur for an unknown reason = (presumably=0A broken hardware/firmware on the device I = have).=0A=0A--- a/xen/arch/x86/msi.c=0A+++ b/xen/arch/x86/msi.c=0A@@ = -738,6 +738,16 @@ static int msi_capability_init(struct pc=0A =0A = *desc =3D entry;=0A /* Restore the original MSI enabled bits */=0A+ = if ( !hardware_domain )=0A+ {=0A+ /*=0A+ * Except for = internal requests (before Dom0 starts), in which case=0A+ * we = rather need to behave "normally", i.e. not follow the split=0A+ * = brain model where Dom0 actually enables MSI (and disables INTx).=0A+ = */=0A+ pci_intx(dev, 0);=0A+ control |=3D PCI_MSI_FLAGS_ENA= BLE;=0A+ }=0A pci_conf_write16(seg, bus, slot, func, msi_control_reg= (pos), control);=0A =0A return 0;=0A@@ -1071,6 +1081,8 @@ static void = __pci_disable_msi(struct msi=0A =0A dev =3D entry->dev;=0A = msi_set_enable(dev, 0);=0A+ if ( entry->irq > 0 && !(irq_to_desc(entry->= irq)->status & IRQ_GUEST) )=0A+ pci_intx(dev, 1);=0A =0A = BUG_ON(list_empty(&dev->msi_list));=0A }=0A--- a/xen/drivers/char/ns16550.c= =0A+++ b/xen/drivers/char/ns16550.c=0A@@ -74,6 +74,7 @@ static struct = ns16550 {=0A u32 bar64;=0A u16 cr;=0A u8 bar_idx;=0A+ = bool_t msi;=0A const struct ns16550_config_param *param; /* Points = into .init.*! */=0A #endif=0A } ns16550_com[2] =3D { { 0 } };=0A@@ -644,6 = +645,16 @@ static void __init ns16550_init_preirq(s=0A uart->fifo_s= ize =3D 16;=0A }=0A =0A+static void __init ns16550_init_irq(struct = serial_port *port)=0A+{=0A+#ifdef CONFIG_HAS_PCI=0A+ struct ns16550 = *uart =3D port->uart;=0A+=0A+ if ( uart->msi )=0A+ uart->irq =3D = create_irq(0);=0A+#endif=0A+}=0A+=0A static void ns16550_setup_postirq(stru= ct ns16550 *uart)=0A {=0A if ( uart->irq > 0 )=0A@@ -678,17 +689,6 @@ = static void __init ns16550_init_postirq(=0A uart->timeout_ms =3D = max_t(=0A unsigned int, 1, (bits * uart->fifo_size * 1000) / = uart->baud);=0A =0A- if ( uart->irq > 0 )=0A- {=0A- uart->irqa= ction.handler =3D ns16550_interrupt;=0A- uart->irqaction.name = =3D "ns16550";=0A- uart->irqaction.dev_id =3D port;=0A- if = ( (rc =3D setup_irq(uart->irq, 0, &uart->irqaction)) !=3D 0 )=0A- = printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);=0A- = }=0A-=0A- ns16550_setup_postirq(uart);=0A-=0A #ifdef CONFIG_HAS_PCI=0A = if ( uart->bar || uart->ps_bdf_enable )=0A {=0A@@ -709,8 +709,65 @@ = static void __init ns16550_init_postirq(=0A = uart->ps_bdf[0], uart->ps_bdf[1],=0A = uart->ps_bdf[2]);=0A }=0A+=0A+ if ( uart->msi )=0A+ = {=0A+ struct msi_info msi =3D {=0A+ .bus =3D = uart->ps_bdf[0],=0A+ .devfn =3D PCI_DEVFN(uart->ps_bdf[1], = uart->ps_bdf[2]),=0A+ .irq =3D rc =3D uart->irq,=0A+ = .entry_nr =3D 1=0A+ };=0A+=0A+ if ( rc > 0 = )=0A+ {=0A+ struct msi_desc *msi_desc =3D = NULL;=0A+=0A+ spin_lock(&pcidevs_lock);=0A+=0A+ = rc =3D pci_enable_msi(&msi, &msi_desc);=0A+ if ( !rc = )=0A+ {=0A+ struct irq_desc *desc =3D = irq_to_desc(msi.irq);=0A+ unsigned long flags;=0A+=0A+ = spin_lock_irqsave(&desc->lock, flags);=0A+ = rc =3D setup_msi_irq(desc, msi_desc);=0A+ = spin_unlock_irqrestore(&desc->lock, flags);=0A+ if ( rc = )=0A+ pci_disable_msi(msi_desc);=0A+ = }=0A+=0A+ spin_unlock(&pcidevs_lock);=0A+=0A+ = if ( rc )=0A+ {=0A+ uart->irq =3D = 0;=0A+ if ( msi_desc )=0A+ = msi_free_irq(msi_desc);=0A+ else=0A+ = destroy_irq(msi.irq);=0A+ }=0A+ }=0A+=0A+ = if ( rc )=0A+ printk(XENLOG_WARNING=0A+ = "MSI setup failed (%d) for %02x:%02x.%o\n",=0A+ = rc, uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2]);=0A+ = }=0A }=0A #endif=0A+=0A+ if ( uart->irq > 0 )=0A+ {=0A+ = uart->irqaction.handler =3D ns16550_interrupt;=0A+ uart->irqaction.n= ame =3D "ns16550";=0A+ uart->irqaction.dev_id =3D port;=0A+ = if ( (rc =3D setup_irq(uart->irq, 0, &uart->irqaction)) !=3D 0 )=0A+ = printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);=0A= + }=0A+=0A+ ns16550_setup_postirq(uart);=0A }=0A =0A static void = ns16550_suspend(struct serial_port *port)=0A@@ -820,6 +877,7 @@ static = const struct vuart_info *ns16550_=0A =0A static struct uart_driver = __read_mostly ns16550_driver =3D {=0A .init_preirq =3D ns16550_init_pr= eirq,=0A+ .init_irq =3D ns16550_init_irq,=0A .init_postirq =3D = ns16550_init_postirq,=0A .endboot =3D ns16550_endboot,=0A = .suspend =3D ns16550_suspend,=0A@@ -1123,7 +1181,18 @@ static void = __init ns16550_parse_port_co=0A }=0A =0A if ( *conf =3D=3D ',' && = *++conf !=3D ',' )=0A- uart->irq =3D simple_strtol(conf, &conf, = 10);=0A+ {=0A+#ifdef CONFIG_HAS_PCI=0A+ if ( strncmp(conf, = "msi", 3) =3D=3D 0 )=0A+ {=0A+ conf +=3D 3;=0A+ = uart->msi =3D 1;=0A+ uart->irq =3D 0;=0A+ }=0A+ = else=0A+#endif=0A+ uart->irq =3D simple_strtol(conf, &conf, = 10);=0A+ }=0A =0A #ifdef CONFIG_HAS_PCI=0A if ( *conf =3D=3D ',' && = *++conf !=3D ',' )=0A--- a/xen/drivers/pci/pci.c=0A+++ b/xen/drivers/pci/pc= i.c=0A@@ -115,6 +115,21 @@ int pci_find_next_ext_capability(int seg=0A = return 0;=0A }=0A =0A+void pci_intx(const struct pci_dev *pdev, bool_t = enable)=0A+{=0A+ uint16_t seg =3D pdev->seg;=0A+ uint8_t bus =3D = pdev->bus;=0A+ uint8_t slot =3D PCI_SLOT(pdev->devfn);=0A+ uint8_t = func =3D PCI_FUNC(pdev->devfn);=0A+ uint16_t cmd =3D pci_conf_read16(seg= , bus, slot, func, PCI_COMMAND);=0A+=0A+ if ( enable )=0A+ cmd = &=3D ~PCI_COMMAND_INTX_DISABLE;=0A+ else=0A+ cmd |=3D PCI_COMMAND= _INTX_DISABLE;=0A+ pci_conf_write16(seg, bus, slot, func, PCI_COMMAND, = cmd);=0A+}=0A+=0A const char *__init parse_pci(const char *s, unsigned int = *seg_p,=0A unsigned int *bus_p, unsigned int = *dev_p,=0A unsigned int *func_p)=0A--- = a/xen/include/xen/pci.h=0A+++ b/xen/include/xen/pci.h=0A@@ -152,6 +152,7 = @@ int pci_find_next_ext_capability(int seg=0A const char *parse_pci(const = char *, unsigned int *seg, unsigned int *bus,=0A = unsigned int *dev, unsigned int *func);=0A =0A+void pci_intx(const struct = pci_dev *, bool_t enable);=0A bool_t pcie_aer_get_firmware_first(const = struct pci_dev *);=0A =0A struct pirq;=0A --=__Part4176D6F1.2__= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel --=__Part4176D6F1.2__=--