mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
vpci/msix: fix PBA accesses
Map the PBA in order to access it from the MSI-X read and write
handlers. Note that previously the handlers would pass the physical
host address into the {read,write}{l,q} handlers, which is wrong as
those expect a linear address.
Map the PBA using ioremap when the first access is performed. Note
that 32bit arches might want to abstract the call to ioremap into a
vPCI arch handler, so they can use a fixmap range to map the PBA.
Reported-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Alex Olson <Alex.Olson@starlab.io>
master commit: b4f2116060
master date: 2022-03-09 16:21:01 +0100
This commit is contained in:
1 parent
a3b6ec391c
commit
47188b2fdc
3 files changed
+65
-4
No files matched your search
+61
-4
@@ -194,6 +194,38 @@ static struct vpci_msix_entry *get_entry(struct vpci_msix *msix,
|
||||
return &msix->entries[(addr - start) / PCI_MSIX_ENTRY_SIZE];
|
||||
}
|
||||
|
||||
static void __iomem *get_pba(struct vpci *vpci)
|
||||
{
|
||||
struct vpci_msix *msix = vpci->msix;
|
||||
/*
|
||||
* PBA will only be unmapped when the device is deassigned, so access it
|
||||
* without holding the vpci lock.
|
||||
*/
|
||||
void __iomem *pba = read_atomic(&msix->pba);
|
||||
|
||||
if ( likely(pba) )
|
||||
return pba;
|
||||
|
||||
pba = ioremap(vmsix_table_addr(vpci, VPCI_MSIX_PBA),
|
||||
vmsix_table_size(vpci, VPCI_MSIX_PBA));
|
||||
if ( !pba )
|
||||
return read_atomic(&msix->pba);
|
||||
|
||||
spin_lock(&vpci->lock);
|
||||
if ( !msix->pba )
|
||||
{
|
||||
write_atomic(&msix->pba, pba);
|
||||
spin_unlock(&vpci->lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
spin_unlock(&vpci->lock);
|
||||
iounmap(pba);
|
||||
}
|
||||
|
||||
return read_atomic(&msix->pba);
|
||||
}
|
||||
|
||||
static int msix_read(struct vcpu *v, unsigned long addr, unsigned int len,
|
||||
unsigned long *data)
|
||||
{
|
||||
@@ -212,6 +244,10 @@ static int msix_read(struct vcpu *v, unsigned long addr, unsigned int len,
|
||||
|
||||
if ( VMSIX_ADDR_IN_RANGE(addr, msix->pdev->vpci, VPCI_MSIX_PBA) )
|
||||
{
|
||||
struct vpci *vpci = msix->pdev->vpci;
|
||||
unsigned int idx = addr - vmsix_table_addr(vpci, VPCI_MSIX_PBA);
|
||||
const void __iomem *pba = get_pba(vpci);
|
||||
|
||||
/*
|
||||
* Access to PBA.
|
||||
*
|
||||
@@ -219,14 +255,22 @@ static int msix_read(struct vcpu *v, unsigned long addr, unsigned int len,
|
||||
* guest address space. If this changes the address will need to be
|
||||
* translated.
|
||||
*/
|
||||
if ( !pba )
|
||||
{
|
||||
gprintk(XENLOG_WARNING,
|
||||
"%pp: unable to map MSI-X PBA, report all pending\n",
|
||||
msix->pdev);
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
switch ( len )
|
||||
{
|
||||
case 4:
|
||||
*data = readl(addr);
|
||||
*data = readl(pba + idx);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
*data = readq(addr);
|
||||
*data = readq(pba + idx);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -290,14 +334,27 @@ static int msix_write(struct vcpu *v, unsigned long addr, unsigned int len,
|
||||
/* Ignore writes to PBA for DomUs, it's behavior is undefined. */
|
||||
if ( is_hardware_domain(d) )
|
||||
{
|
||||
struct vpci *vpci = msix->pdev->vpci;
|
||||
unsigned int idx = addr - vmsix_table_addr(vpci, VPCI_MSIX_PBA);
|
||||
const void __iomem *pba = get_pba(vpci);
|
||||
|
||||
if ( !pba )
|
||||
{
|
||||
/* Unable to map the PBA, ignore write. */
|
||||
gprintk(XENLOG_WARNING,
|
||||
"%pp: unable to map MSI-X PBA, write ignored\n",
|
||||
msix->pdev);
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
switch ( len )
|
||||
{
|
||||
case 4:
|
||||
writel(data, addr);
|
||||
writel(data, pba + idx);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
writeq(data, addr);
|
||||
writeq(data, pba + idx);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -48,6 +48,8 @@ void vpci_remove_device(struct pci_dev *pdev)
|
||||
xfree(r);
|
||||
}
|
||||
spin_unlock(&pdev->vpci->lock);
|
||||
if ( pdev->vpci->msix && pdev->vpci->msix->pba )
|
||||
iounmap(pdev->vpci->msix->pba);
|
||||
xfree(pdev->vpci->msix);
|
||||
xfree(pdev->vpci->msi);
|
||||
xfree(pdev->vpci);
|
||||
|
||||
@@ -127,6 +127,8 @@ struct vpci {
|
||||
bool enabled : 1;
|
||||
/* Masked? */
|
||||
bool masked : 1;
|
||||
/* PBA map */
|
||||
void __iomem *pba;
|
||||
/* Entries. */
|
||||
struct vpci_msix_entry {
|
||||
uint64_t addr;
|
||||
|
||||