1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-16 08:12:53 +08:00

Refactor interrupt handling

This commit is contained in:
Alex Forencich 2021-12-12 13:34:33 -08:00
parent 3c6f80b80c
commit 413238f81c
6 changed files with 146 additions and 57 deletions

View File

@ -2,6 +2,7 @@
# object files to build
obj-m += mqnic.o
mqnic-y += mqnic_main.o
mqnic-y += mqnic_irq.o
mqnic-y += mqnic_dev.o
mqnic-y += mqnic_netdev.o
mqnic-y += mqnic_port.o

View File

@ -78,6 +78,12 @@ struct mqnic_i2c_bus {
struct i2c_adapter adapter;
};
struct mqnic_irq {
int index;
int irqn;
struct atomic_notifier_head nh;
};
struct mqnic_dev {
struct device *dev;
struct pci_dev *pdev;
@ -103,8 +109,7 @@ struct mqnic_dev {
char name[16];
int irq_count;
int irq_map[32];
struct atomic_notifier_head irq_nh[MQNIC_MAX_IRQ];
struct mqnic_irq *irq[MQNIC_MAX_IRQ];
unsigned int id;
struct list_head dev_list_node;
@ -255,7 +260,8 @@ struct mqnic_eq_ring {
struct net_device *ndev;
struct mqnic_priv *priv;
int ring_index;
int int_index;
struct mqnic_irq *irq;
int irq_index;
int active;
struct notifier_block irq_nb;
@ -334,6 +340,10 @@ struct mqnic_priv {
// mqnic_main.c
// mqnic_irq.c
int mqnic_irq_init_pcie(struct mqnic_dev *mdev);
void mqnic_irq_deinit_pcie(struct mqnic_dev *mdev);
// mqnic_dev.c
extern const struct file_operations mqnic_fops;
@ -380,7 +390,7 @@ int mqnic_create_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring **ring_pt
void mqnic_destroy_eq_ring(struct mqnic_eq_ring **ring_ptr);
int mqnic_alloc_eq_ring(struct mqnic_eq_ring *ring, int size, int stride);
void mqnic_free_eq_ring(struct mqnic_eq_ring *ring);
int mqnic_activate_eq_ring(struct mqnic_eq_ring *ring, int int_index);
int mqnic_activate_eq_ring(struct mqnic_eq_ring *ring, struct mqnic_irq *irq);
void mqnic_deactivate_eq_ring(struct mqnic_eq_ring *ring);
bool mqnic_is_eq_ring_empty(const struct mqnic_eq_ring *ring);
bool mqnic_is_eq_ring_full(const struct mqnic_eq_ring *ring);

View File

@ -130,32 +130,30 @@ void mqnic_free_eq_ring(struct mqnic_eq_ring *ring)
ring->buf_dma_addr = 0;
}
int mqnic_activate_eq_ring(struct mqnic_eq_ring *ring, int int_index)
int mqnic_activate_eq_ring(struct mqnic_eq_ring *ring, struct mqnic_irq *irq)
{
int ret = 0;
mqnic_deactivate_eq_ring(ring);
if (!ring->buf)
return -EINVAL;
if (int_index < 0 || int_index >= ring->priv->mdev->irq_count)
if (!ring->buf || !irq)
return -EINVAL;
// register interrupt
ring->int_index = int_index;
ret = atomic_notifier_chain_register(&ring->priv->mdev->irq_nh[int_index], &ring->irq_nb);
ret = atomic_notifier_chain_register(&irq->nh, &ring->irq_nb);
if (ret)
return ret;
ring->irq = irq;
ring->irq_index = irq->index;
// deactivate queue
iowrite32(0, ring->hw_addr + MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG);
// set base address
iowrite32(ring->buf_dma_addr, ring->hw_addr + MQNIC_EVENT_QUEUE_BASE_ADDR_REG + 0);
iowrite32(ring->buf_dma_addr >> 32, ring->hw_addr + MQNIC_EVENT_QUEUE_BASE_ADDR_REG + 4);
// set interrupt index
iowrite32(int_index, ring->hw_addr + MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG);
iowrite32(ring->irq_index, ring->hw_addr + MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG);
// set pointers
iowrite32(ring->head_ptr & ring->hw_ptr_mask,
ring->hw_addr + MQNIC_EVENT_QUEUE_HEAD_PTR_REG);
@ -167,7 +165,7 @@ int mqnic_activate_eq_ring(struct mqnic_eq_ring *ring, int int_index)
ring->active = 1;
return ret;
return 0;
}
void mqnic_deactivate_eq_ring(struct mqnic_eq_ring *ring)
@ -177,11 +175,13 @@ void mqnic_deactivate_eq_ring(struct mqnic_eq_ring *ring)
// deactivate queue
iowrite32(ilog2(ring->size), ring->hw_addr + MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG);
// disarm queue
iowrite32(ring->int_index, ring->hw_addr + MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG);
iowrite32(0, ring->hw_addr + MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG);
// unregister interrupt
if (ring->active)
ret = atomic_notifier_chain_unregister(&ring->priv->mdev->irq_nh[ring->int_index], &ring->irq_nb);
if (ring->irq) {
ret = atomic_notifier_chain_unregister(&ring->irq->nh, &ring->irq_nb);
ring->irq = NULL;
}
ring->active = 0;
}
@ -208,7 +208,10 @@ void mqnic_eq_write_tail_ptr(struct mqnic_eq_ring *ring)
void mqnic_arm_eq(struct mqnic_eq_ring *ring)
{
iowrite32(ring->int_index | MQNIC_EVENT_QUEUE_ARM_MASK,
if (!ring->active)
return;
iowrite32(ring->irq_index | MQNIC_EVENT_QUEUE_ARM_MASK,
ring->hw_addr + MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG);
}

107
modules/mqnic/mqnic_irq.c Normal file
View File

@ -0,0 +1,107 @@
// SPDX-License-Identifier: BSD-2-Clause-Views
/*
* Copyright 2021, The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of The Regents of the
* University of California.
*/
#include "mqnic.h"
static irqreturn_t mqnic_irq_handler(int irqn, void *data)
{
struct mqnic_irq *irq = data;
atomic_notifier_call_chain(&irq->nh, 0, NULL);
return IRQ_HANDLED;
}
int mqnic_irq_init_pcie(struct mqnic_dev *mdev)
{
struct pci_dev *pdev = mdev->pdev;
struct device *dev = mdev->dev;
int ret = 0;
int k;
// Allocate MSI IRQs
mdev->irq_count = pci_alloc_irq_vectors(pdev, 1, MQNIC_MAX_IRQ, PCI_IRQ_MSI);
if (mdev->irq_count < 0) {
dev_err(dev, "Failed to allocate IRQs");
return -ENOMEM;
}
// Set up interrupts
for (k = 0; k < mdev->irq_count; k++) {
struct mqnic_irq *irq;
irq = kzalloc(sizeof(*irq), GFP_KERNEL);
if (!irq) {
ret = -ENOMEM;
goto fail;
}
ATOMIC_INIT_NOTIFIER_HEAD(&irq->nh);
ret = pci_request_irq(pdev, k, mqnic_irq_handler, NULL,
irq, "%s-%d", mdev->name, k);
if (ret < 0) {
kfree(irq);
ret = -ENOMEM;
dev_err(dev, "Failed to request IRQ %d", k);
goto fail;
}
irq->index = k;
irq->irqn = pci_irq_vector(pdev, k);
mdev->irq[k] = irq;
}
return 0;
fail:
mqnic_irq_deinit_pcie(mdev);
return ret;
}
void mqnic_irq_deinit_pcie(struct mqnic_dev *mdev)
{
struct pci_dev *pdev = mdev->pdev;
int k;
for (k = 0; k < MQNIC_MAX_IRQ; k++) {
if (mdev->irq[k]) {
pci_free_irq(pdev, k, mdev->irq[k]);
kfree(mdev->irq[k]);
mdev->irq[k] = NULL;
}
}
pci_free_irq_vectors(pdev);
}

View File

@ -78,15 +78,6 @@ static unsigned int mqnic_get_free_id(void)
return id;
}
static irqreturn_t mqnic_interrupt(int irq, void *data)
{
struct atomic_notifier_head *nh = data;
atomic_notifier_call_chain(nh, 0, NULL);
return IRQ_HANDLED;
}
static int mqnic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int ret = 0;
@ -261,28 +252,11 @@ static int mqnic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent
goto fail_map_bars;
}
// Allocate MSI IRQs
mqnic->irq_count = pci_alloc_irq_vectors(pdev, 1, MQNIC_MAX_IRQ, PCI_IRQ_MSI);
if (mqnic->irq_count < 0) {
ret = -ENOMEM;
dev_err(dev, "Failed to allocate IRQs");
goto fail_map_bars;
}
// Set up interrupts
for (k = 0; k < MQNIC_MAX_IRQ; k++) {
ATOMIC_INIT_NOTIFIER_HEAD(&mqnic->irq_nh[k]);
}
for (k = 0; k < mqnic->irq_count; k++) {
ret = pci_request_irq(pdev, k, mqnic_interrupt, NULL,
&mqnic->irq_nh[k], "%s-%d", mqnic->name, k);
if (ret < 0) {
dev_err(dev, "Failed to request IRQ");
goto fail_irq;
}
mqnic->irq_map[k] = pci_irq_vector(pdev, k);
ret = mqnic_irq_init_pcie(mqnic);
if (ret) {
dev_err(dev, "Failed to set up interrupts");
goto fail_map_bars;
}
// Board-specific init
@ -346,11 +320,7 @@ fail_init_netdev:
mqnic_unregister_phc(mqnic);
pci_clear_master(pdev);
fail_board:
mqnic_board_deinit(mqnic);
for (k = 0; k < mqnic->irq_count; k++)
pci_free_irq(pdev, k, &mqnic->irq_nh[k]);
fail_irq:
pci_free_irq_vectors(pdev);
mqnic_irq_deinit_pcie(mqnic);
fail_map_bars:
if (mqnic->hw_addr)
pci_iounmap(pdev, mqnic->hw_addr);
@ -390,9 +360,7 @@ static void mqnic_pci_remove(struct pci_dev *pdev)
pci_clear_master(pdev);
mqnic_board_deinit(mqnic);
for (k = 0; k < mqnic->irq_count; k++)
pci_free_irq(pdev, k, &mqnic->irq_nh[k]);
pci_free_irq_vectors(pdev);
mqnic_irq_deinit_pcie(mqnic);
if (mqnic->hw_addr)
pci_iounmap(pdev, mqnic->hw_addr);
if (mqnic->app_hw_addr)

View File

@ -45,7 +45,7 @@ static int mqnic_start_port(struct net_device *ndev)
// set up event queues
for (k = 0; k < priv->event_queue_count; k++) {
mqnic_activate_eq_ring(priv->event_ring[k], k % mdev->irq_count);
mqnic_activate_eq_ring(priv->event_ring[k], priv->mdev->irq[k % mdev->irq_count]);
mqnic_arm_eq(priv->event_ring[k]);
}