Commit 3254c902 authored by Roland Dreier's avatar Roland Dreier Committed by Linus Torvalds

[PATCH] InfiniBand/mthca: optimize event queue handling

From: "Michael S. Tsirkin" <mst@mellanox.co.il>

Event queue handling performance improvements:
 - Only calculate EQ entry address once, and don't truncate the
   consumer index until we really need to.
 - Only read ECR once.  If a new event occurs while we're in the
   interrupt handler, we'll get another interrupt anyway, since we
   only clear events once.
Signed-off-by: default avatarMichael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: default avatarRoland Dreier <roland@topspin.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3ad404b7
...@@ -164,12 +164,12 @@ static inline u64 async_mask(struct mthca_dev *dev) ...@@ -164,12 +164,12 @@ static inline u64 async_mask(struct mthca_dev *dev)
MTHCA_ASYNC_EVENT_MASK; MTHCA_ASYNC_EVENT_MASK;
} }
static inline void set_eq_ci(struct mthca_dev *dev, int eqn, int ci) static inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
{ {
u32 doorbell[2]; u32 doorbell[2];
doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_SET_CI | eqn); doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_SET_CI | eq->eqn);
doorbell[1] = cpu_to_be32(ci); doorbell[1] = cpu_to_be32(ci & (eq->nent - 1));
mthca_write64(doorbell, mthca_write64(doorbell,
dev->kar + MTHCA_EQ_DOORBELL, dev->kar + MTHCA_EQ_DOORBELL,
...@@ -200,21 +200,22 @@ static inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn) ...@@ -200,21 +200,22 @@ static inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn)
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
} }
static inline struct mthca_eqe *get_eqe(struct mthca_eq *eq, int entry) static inline struct mthca_eqe *get_eqe(struct mthca_eq *eq, u32 entry)
{ {
return eq->page_list[entry * MTHCA_EQ_ENTRY_SIZE / PAGE_SIZE].buf unsigned long off = (entry & (eq->nent - 1)) * MTHCA_EQ_ENTRY_SIZE;
+ (entry * MTHCA_EQ_ENTRY_SIZE) % PAGE_SIZE; return eq->page_list[off / PAGE_SIZE].buf + off % PAGE_SIZE;
} }
static inline int next_eqe_sw(struct mthca_eq *eq) static inline struct mthca_eqe* next_eqe_sw(struct mthca_eq *eq)
{ {
return !(MTHCA_EQ_ENTRY_OWNER_HW & struct mthca_eqe* eqe;
get_eqe(eq, eq->cons_index)->owner); eqe = get_eqe(eq, eq->cons_index);
return (MTHCA_EQ_ENTRY_OWNER_HW & eqe->owner) ? NULL : eqe;
} }
static inline void set_eqe_hw(struct mthca_eq *eq, int entry) static inline void set_eqe_hw(struct mthca_eqe *eqe)
{ {
get_eqe(eq, entry)->owner = MTHCA_EQ_ENTRY_OWNER_HW; eqe->owner = MTHCA_EQ_ENTRY_OWNER_HW;
} }
static void port_change(struct mthca_dev *dev, int port, int active) static void port_change(struct mthca_dev *dev, int port, int active)
...@@ -235,10 +236,10 @@ static void mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq) ...@@ -235,10 +236,10 @@ static void mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
{ {
struct mthca_eqe *eqe; struct mthca_eqe *eqe;
int disarm_cqn; int disarm_cqn;
int eqes_found = 0;
while (next_eqe_sw(eq)) { while ((eqe = next_eqe_sw(eq))) {
int set_ci = 0; int set_ci = 0;
eqe = get_eqe(eq, eq->cons_index);
/* /*
* Make sure we read EQ entry contents after we've * Make sure we read EQ entry contents after we've
...@@ -328,12 +329,13 @@ static void mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq) ...@@ -328,12 +329,13 @@ static void mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
break; break;
}; };
set_eqe_hw(eq, eq->cons_index); set_eqe_hw(eqe);
eq->cons_index = (eq->cons_index + 1) & (eq->nent - 1); ++eq->cons_index;
eqes_found = 1;
if (set_ci) { if (set_ci) {
wmb(); /* see comment below */ wmb(); /* see comment below */
set_eq_ci(dev, eq->eqn, eq->cons_index); set_eq_ci(dev, eq, eq->cons_index);
set_ci = 0; set_ci = 0;
} }
} }
...@@ -347,8 +349,10 @@ static void mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq) ...@@ -347,8 +349,10 @@ static void mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
* possibility of the HCA writing an entry and then * possibility of the HCA writing an entry and then
* having set_eqe_hw() overwrite the owner field. * having set_eqe_hw() overwrite the owner field.
*/ */
wmb(); if (likely(eqes_found)) {
set_eq_ci(dev, eq->eqn, eq->cons_index); wmb();
set_eq_ci(dev, eq, eq->cons_index);
}
eq_req_not(dev, eq->eqn); eq_req_not(dev, eq->eqn);
} }
...@@ -362,7 +366,7 @@ static irqreturn_t mthca_interrupt(int irq, void *dev_ptr, struct pt_regs *regs) ...@@ -362,7 +366,7 @@ static irqreturn_t mthca_interrupt(int irq, void *dev_ptr, struct pt_regs *regs)
if (dev->eq_table.clr_mask) if (dev->eq_table.clr_mask)
writel(dev->eq_table.clr_mask, dev->eq_table.clr_int); writel(dev->eq_table.clr_mask, dev->eq_table.clr_int);
while ((ecr = readl(dev->hcr + MTHCA_ECR_OFFSET + 4)) != 0) { if ((ecr = readl(dev->hcr + MTHCA_ECR_OFFSET + 4)) != 0) {
work = 1; work = 1;
writel(ecr, dev->hcr + MTHCA_ECR_CLR_OFFSET + 4); writel(ecr, dev->hcr + MTHCA_ECR_CLR_OFFSET + 4);
...@@ -440,7 +444,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, ...@@ -440,7 +444,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
} }
for (i = 0; i < nent; ++i) for (i = 0; i < nent; ++i)
set_eqe_hw(eq, i); set_eqe_hw(get_eqe(eq, i));
eq->eqn = mthca_alloc(&dev->eq_table.alloc); eq->eqn = mthca_alloc(&dev->eq_table.alloc);
if (eq->eqn == -1) if (eq->eqn == -1)
......
...@@ -66,11 +66,11 @@ struct mthca_eq { ...@@ -66,11 +66,11 @@ struct mthca_eq {
struct mthca_dev *dev; struct mthca_dev *dev;
int eqn; int eqn;
u32 ecr_mask; u32 ecr_mask;
u32 cons_index;
u16 msi_x_vector; u16 msi_x_vector;
u16 msi_x_entry; u16 msi_x_entry;
int have_irq; int have_irq;
int nent; int nent;
int cons_index;
struct mthca_buf_list *page_list; struct mthca_buf_list *page_list;
struct mthca_mr mr; struct mthca_mr mr;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment