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

Use atomic notifier chain for interrupt handling

This commit is contained in:
Alex Forencich 2021-12-10 21:05:31 -08:00
parent 5e65a384e2
commit ddeb8bad94
5 changed files with 42 additions and 29 deletions

View File

@ -104,6 +104,7 @@ struct mqnic_dev {
int irq_count;
int irq_map[32];
struct atomic_notifier_head irq_nh[MQNIC_MAX_IRQ];
unsigned int id;
struct list_head dev_list_node;
@ -255,7 +256,7 @@ struct mqnic_eq_ring {
int int_index;
int active;
int irq;
struct notifier_block irq_nb;
void (*handler)(struct mqnic_eq_ring *ring);

View File

@ -35,6 +35,16 @@
#include "mqnic.h"
static int mqnic_eq_int(struct notifier_block *nb, unsigned long action, void *data)
{
struct mqnic_eq_ring *ring = container_of(nb, struct mqnic_eq_ring, irq_nb);
mqnic_process_eq(ring);
mqnic_arm_eq(ring);
return NOTIFY_DONE;
}
int mqnic_create_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring **ring_ptr,
int size, int stride, int index, u8 __iomem *hw_addr)
{
@ -52,6 +62,8 @@ int mqnic_create_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring **ring_pt
ring->ring_index = index;
ring->active = 0;
ring->irq_nb.notifier_call = mqnic_eq_int;
ring->size = roundup_pow_of_two(size);
ring->size_mask = ring->size - 1;
ring->stride = roundup_pow_of_two(stride);
@ -111,10 +123,20 @@ void mqnic_destroy_eq_ring(struct mqnic_eq_ring **ring_ptr)
int mqnic_activate_eq_ring(struct mqnic_eq_ring *ring, int int_index)
{
int ret = 0;
if (ring->active)
mqnic_deactivate_eq_ring(ring);
if (int_index < 0 || int_index >= ring->priv->mdev->irq_count)
return -EINVAL;
// register interrupt
ring->int_index = int_index;
ret = atomic_notifier_chain_register(&ring->priv->mdev->irq_nh[int_index], &ring->irq_nb);
if (ret)
return ret;
// deactivate queue
iowrite32(0, ring->hw_addr + MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG);
@ -134,16 +156,22 @@ int mqnic_activate_eq_ring(struct mqnic_eq_ring *ring, int int_index)
ring->active = 1;
return 0;
return ret;
}
void mqnic_deactivate_eq_ring(struct mqnic_eq_ring *ring)
{
int ret = 0;
// 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);
// unregister interrupt
if (ring->active)
ret = atomic_notifier_chain_unregister(&ring->priv->mdev->irq_nh[ring->int_index], &ring->irq_nb);
ring->active = 0;
}

View File

@ -38,6 +38,8 @@
#include <linux/types.h>
#define MQNIC_MAX_IRQ 32
#define MQNIC_MAX_IF 8
#define MQNIC_MAX_PORTS 8
#define MQNIC_MAX_SCHED 8

View File

@ -80,30 +80,9 @@ static unsigned int mqnic_get_free_id(void)
static irqreturn_t mqnic_interrupt(int irq, void *data)
{
struct mqnic_dev *mqnic = data;
struct mqnic_priv *priv;
struct atomic_notifier_head *nh = data;
int k, l;
for (k = 0; k < ARRAY_SIZE(mqnic->ndev); k++) {
if (unlikely(!mqnic->ndev[k]))
continue;
priv = netdev_priv(mqnic->ndev[k]);
if (unlikely(!priv->port_up))
continue;
for (l = 0; l < priv->event_queue_count; l++) {
if (unlikely(!priv->event_ring[l]))
continue;
if (priv->event_ring[l]->irq == irq) {
mqnic_process_eq(priv->event_ring[l]);
mqnic_arm_eq(priv->event_ring[l]);
}
}
}
atomic_notifier_call_chain(nh, 0, NULL);
return IRQ_HANDLED;
}
@ -291,9 +270,13 @@ static int mqnic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent
}
// 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, "%s-%d", mqnic->name, k);
&mqnic->irq_nh[k], "%s-%d", mqnic->name, k);
if (ret < 0) {
dev_err(dev, "Failed to request IRQ");
goto fail_irq;
@ -366,7 +349,7 @@ fail_init_netdev:
fail_board:
mqnic_board_deinit(mqnic);
for (k = 0; k < mqnic->irq_count; k++)
pci_free_irq(pdev, k, mqnic);
pci_free_irq(pdev, k, &mqnic->irq_nh[k]);
fail_irq:
pci_free_irq_vectors(pdev);
fail_map_bars:
@ -409,7 +392,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);
pci_free_irq(pdev, k, &mqnic->irq_nh[k]);
pci_free_irq_vectors(pdev);
if (mqnic->hw_addr)
pci_iounmap(pdev, mqnic->hw_addr);

View File

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