Source
x
/*
* Annapurna Labs MSIX support services
*
* Copyright (C) 2016, Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Antoine Tenart <antoine.tenart@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
/* MSIX message address format: local GIC target */
struct alpine_msix_data {
spinlock_t msi_map_lock;
phys_addr_t addr;
u32 spi_first; /* The SGI number that MSIs start */
u32 num_spis; /* The number of SGIs for MSIs */
unsigned long *msi_map;
};
static void alpine_msix_mask_msi_irq(struct irq_data *d)
{
pci_msi_mask_irq(d);
irq_chip_mask_parent(d);
}
static void alpine_msix_unmask_msi_irq(struct irq_data *d)
{
pci_msi_unmask_irq(d);
irq_chip_unmask_parent(d);
}
static struct irq_chip alpine_msix_irq_chip = {
.name = "MSIx",
.irq_mask = alpine_msix_mask_msi_irq,
.irq_unmask = alpine_msix_unmask_msi_irq,
.irq_eoi = irq_chip_eoi_parent,
.irq_set_affinity = irq_chip_set_affinity_parent,
};
static int alpine_msix_allocate_sgi(struct alpine_msix_data *priv, int num_req)
{
int first;
spin_lock(&priv->msi_map_lock);
first = bitmap_find_next_zero_area(priv->msi_map, priv->num_spis, 0,
num_req, 0);
if (first >= priv->num_spis) {
spin_unlock(&priv->msi_map_lock);
return -ENOSPC;
}
bitmap_set(priv->msi_map, first, num_req);
spin_unlock(&priv->msi_map_lock);
return priv->spi_first + first;
}
static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned sgi,
int num_req)
{
int first = sgi - priv->spi_first;
spin_lock(&priv->msi_map_lock);
bitmap_clear(priv->msi_map, first, num_req);
spin_unlock(&priv->msi_map_lock);
}
static void alpine_msix_compose_msi_msg(struct irq_data *data,
struct msi_msg *msg)