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:
parent
3c6f80b80c
commit
413238f81c
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
107
modules/mqnic/mqnic_irq.c
Normal 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);
|
||||
}
|
@ -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)
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user