mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
vdpa/octeon_ep: enable support for multiple interrupts per device
Updated the driver to utilize all the MSI-X interrupt vectors supported by each OCTEON endpoint VF, instead of relying on a single vector. Enabling more interrupts allows packets from multiple rings to be distributed across multiple cores, improving parallelism and performance. Reviewed-by: Dan Carpenter <dan.carpenter@linaro.org> Acked-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Shijith Thotton <sthotton@marvell.com> Message-Id: <20250103153226.1933479-1-sthotton@marvell.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
6f3955a62c
commit
26f8ce06af
|
|
@ -29,12 +29,12 @@
|
||||||
#define OCTEP_EPF_RINFO(x) (0x000209f0 | ((x) << 25))
|
#define OCTEP_EPF_RINFO(x) (0x000209f0 | ((x) << 25))
|
||||||
#define OCTEP_VF_MBOX_DATA(x) (0x00010210 | ((x) << 17))
|
#define OCTEP_VF_MBOX_DATA(x) (0x00010210 | ((x) << 17))
|
||||||
#define OCTEP_PF_MBOX_DATA(x) (0x00022000 | ((x) << 4))
|
#define OCTEP_PF_MBOX_DATA(x) (0x00022000 | ((x) << 4))
|
||||||
|
#define OCTEP_VF_IN_CTRL(x) (0x00010000 | ((x) << 17))
|
||||||
#define OCTEP_EPF_RINFO_RPVF(val) (((val) >> 32) & 0xF)
|
#define OCTEP_VF_IN_CTRL_RPVF(val) (((val) >> 48) & 0xF)
|
||||||
#define OCTEP_EPF_RINFO_NVFS(val) (((val) >> 48) & 0x7F)
|
|
||||||
|
|
||||||
#define OCTEP_FW_READY_SIGNATURE0 0xFEEDFEED
|
#define OCTEP_FW_READY_SIGNATURE0 0xFEEDFEED
|
||||||
#define OCTEP_FW_READY_SIGNATURE1 0x3355ffaa
|
#define OCTEP_FW_READY_SIGNATURE1 0x3355ffaa
|
||||||
|
#define OCTEP_MAX_CB_INTR 8
|
||||||
|
|
||||||
enum octep_vdpa_dev_status {
|
enum octep_vdpa_dev_status {
|
||||||
OCTEP_VDPA_DEV_STATUS_INVALID,
|
OCTEP_VDPA_DEV_STATUS_INVALID,
|
||||||
|
|
@ -48,9 +48,8 @@ enum octep_vdpa_dev_status {
|
||||||
struct octep_vring_info {
|
struct octep_vring_info {
|
||||||
struct vdpa_callback cb;
|
struct vdpa_callback cb;
|
||||||
void __iomem *notify_addr;
|
void __iomem *notify_addr;
|
||||||
u32 __iomem *cb_notify_addr;
|
void __iomem *cb_notify_addr;
|
||||||
phys_addr_t notify_pa;
|
phys_addr_t notify_pa;
|
||||||
char msix_name[256];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct octep_hw {
|
struct octep_hw {
|
||||||
|
|
@ -68,7 +67,8 @@ struct octep_hw {
|
||||||
u64 features;
|
u64 features;
|
||||||
u16 nr_vring;
|
u16 nr_vring;
|
||||||
u32 config_size;
|
u32 config_size;
|
||||||
int irq;
|
int nb_irqs;
|
||||||
|
int *irqs;
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 octep_hw_get_status(struct octep_hw *oct_hw);
|
u8 octep_hw_get_status(struct octep_hw *oct_hw);
|
||||||
|
|
|
||||||
|
|
@ -495,8 +495,6 @@ int octep_hw_caps_read(struct octep_hw *oct_hw, struct pci_dev *pdev)
|
||||||
if (!oct_hw->vqs)
|
if (!oct_hw->vqs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
oct_hw->irq = -1;
|
|
||||||
|
|
||||||
dev_info(&pdev->dev, "Device features : %llx\n", oct_hw->features);
|
dev_info(&pdev->dev, "Device features : %llx\n", oct_hw->features);
|
||||||
dev_info(&pdev->dev, "Maximum queues : %u\n", oct_hw->nr_vring);
|
dev_info(&pdev->dev, "Maximum queues : %u\n", oct_hw->nr_vring);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,25 @@ static irqreturn_t octep_vdpa_intr_handler(int irq, void *data)
|
||||||
struct octep_hw *oct_hw = data;
|
struct octep_hw *oct_hw = data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < oct_hw->nr_vring; i++) {
|
/* Each device has multiple interrupts (nb_irqs) shared among rings
|
||||||
if (oct_hw->vqs[i].cb.callback && ioread32(oct_hw->vqs[i].cb_notify_addr)) {
|
* (nr_vring). Device interrupts are mapped to the rings in a
|
||||||
/* Acknowledge the per queue notification to the device */
|
* round-robin fashion.
|
||||||
iowrite32(0, oct_hw->vqs[i].cb_notify_addr);
|
*
|
||||||
|
* For example, if nb_irqs = 8 and nr_vring = 64:
|
||||||
|
* 0 -> 0, 8, 16, 24, 32, 40, 48, 56;
|
||||||
|
* 1 -> 1, 9, 17, 25, 33, 41, 49, 57;
|
||||||
|
* ...
|
||||||
|
* 7 -> 7, 15, 23, 31, 39, 47, 55, 63;
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = irq - oct_hw->irqs[0]; i < oct_hw->nr_vring; i += oct_hw->nb_irqs) {
|
||||||
|
if (ioread8(oct_hw->vqs[i].cb_notify_addr)) {
|
||||||
|
/* Acknowledge the per ring notification to the device */
|
||||||
|
iowrite8(0, oct_hw->vqs[i].cb_notify_addr);
|
||||||
|
|
||||||
|
if (likely(oct_hw->vqs[i].cb.callback))
|
||||||
oct_hw->vqs[i].cb.callback(oct_hw->vqs[i].cb.private);
|
oct_hw->vqs[i].cb.callback(oct_hw->vqs[i].cb.private);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,44 +77,53 @@ static irqreturn_t octep_vdpa_intr_handler(int irq, void *data)
|
||||||
static void octep_free_irqs(struct octep_hw *oct_hw)
|
static void octep_free_irqs(struct octep_hw *oct_hw)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = oct_hw->pdev;
|
struct pci_dev *pdev = oct_hw->pdev;
|
||||||
|
int irq;
|
||||||
|
|
||||||
if (oct_hw->irq != -1) {
|
if (!oct_hw->irqs)
|
||||||
devm_free_irq(&pdev->dev, oct_hw->irq, oct_hw);
|
return;
|
||||||
oct_hw->irq = -1;
|
|
||||||
|
for (irq = 0; irq < oct_hw->nb_irqs; irq++) {
|
||||||
|
if (!oct_hw->irqs[irq])
|
||||||
|
break;
|
||||||
|
|
||||||
|
devm_free_irq(&pdev->dev, oct_hw->irqs[irq], oct_hw);
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_free_irq_vectors(pdev);
|
pci_free_irq_vectors(pdev);
|
||||||
|
devm_kfree(&pdev->dev, oct_hw->irqs);
|
||||||
|
oct_hw->irqs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int octep_request_irqs(struct octep_hw *oct_hw)
|
static int octep_request_irqs(struct octep_hw *oct_hw)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = oct_hw->pdev;
|
struct pci_dev *pdev = oct_hw->pdev;
|
||||||
int ret, irq;
|
int ret, irq, idx;
|
||||||
|
|
||||||
/* Currently HW device provisions one IRQ per VF, hence
|
oct_hw->irqs = devm_kcalloc(&pdev->dev, oct_hw->nb_irqs, sizeof(int), GFP_KERNEL);
|
||||||
* allocate one IRQ for all virtqueues call interface.
|
if (!oct_hw->irqs)
|
||||||
*/
|
return -ENOMEM;
|
||||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
|
|
||||||
|
ret = pci_alloc_irq_vectors(pdev, 1, oct_hw->nb_irqs, PCI_IRQ_MSIX);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "Failed to alloc msix vector");
|
dev_err(&pdev->dev, "Failed to alloc msix vector");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(oct_hw->vqs->msix_name, sizeof(oct_hw->vqs->msix_name),
|
for (idx = 0; idx < oct_hw->nb_irqs; idx++) {
|
||||||
OCTEP_VDPA_DRIVER_NAME "-vf-%d", pci_iov_vf_id(pdev));
|
irq = pci_irq_vector(pdev, idx);
|
||||||
|
|
||||||
irq = pci_irq_vector(pdev, 0);
|
|
||||||
ret = devm_request_irq(&pdev->dev, irq, octep_vdpa_intr_handler, 0,
|
ret = devm_request_irq(&pdev->dev, irq, octep_vdpa_intr_handler, 0,
|
||||||
oct_hw->vqs->msix_name, oct_hw);
|
dev_name(&pdev->dev), oct_hw);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Failed to register interrupt handler\n");
|
dev_err(&pdev->dev, "Failed to register interrupt handler\n");
|
||||||
goto free_irq_vec;
|
goto free_irqs;
|
||||||
|
}
|
||||||
|
oct_hw->irqs[idx] = irq;
|
||||||
}
|
}
|
||||||
oct_hw->irq = irq;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_irq_vec:
|
free_irqs:
|
||||||
pci_free_irq_vectors(pdev);
|
octep_free_irqs(oct_hw);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -559,6 +582,7 @@ static void octep_vdpa_setup_task(struct work_struct *work)
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct octep_hw *oct_hw;
|
struct octep_hw *oct_hw;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
|
u64 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
oct_hw = &mgmt_dev->oct_hw;
|
oct_hw = &mgmt_dev->oct_hw;
|
||||||
|
|
@ -590,6 +614,13 @@ static void octep_vdpa_setup_task(struct work_struct *work)
|
||||||
if (ret)
|
if (ret)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
val = readq(oct_hw->base[OCTEP_HW_MBOX_BAR] + OCTEP_VF_IN_CTRL(0));
|
||||||
|
oct_hw->nb_irqs = OCTEP_VF_IN_CTRL_RPVF(val);
|
||||||
|
if (!oct_hw->nb_irqs || oct_hw->nb_irqs > OCTEP_MAX_CB_INTR) {
|
||||||
|
dev_err(dev, "Invalid number of interrupts %d\n", oct_hw->nb_irqs);
|
||||||
|
goto unmap_region;
|
||||||
|
}
|
||||||
|
|
||||||
ret = octep_hw_caps_read(oct_hw, pdev);
|
ret = octep_hw_caps_read(oct_hw, pdev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto unmap_region;
|
goto unmap_region;
|
||||||
|
|
@ -768,12 +799,6 @@ static int octep_vdpa_pf_setup(struct octep_pf *octpf)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OCTEP_EPF_RINFO_RPVF(val) != BIT_ULL(0)) {
|
|
||||||
val &= ~GENMASK_ULL(35, 32);
|
|
||||||
val |= BIT_ULL(32);
|
|
||||||
writeq(val, addr + OCTEP_EPF_RINFO(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
len = pci_resource_len(pdev, OCTEP_HW_CAPS_BAR);
|
len = pci_resource_len(pdev, OCTEP_HW_CAPS_BAR);
|
||||||
|
|
||||||
octpf->vf_stride = len / totalvfs;
|
octpf->vf_stride = len / totalvfs;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user