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:
parent
5e65a384e2
commit
ddeb8bad94
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user