#ifndef _QIB_KERNEL_H
#define _QIB_KERNEL_H
/*
- * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
- * All rights reserved.
+ * Copyright (c) 2012 Intel Corporation. All rights reserved.
+ * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
/* read mostly */
struct qib_sdma_desc *sdma_descq;
+ struct workqueue_struct *qib_wq;
struct qib_sdma_state sdma_state;
dma_addr_t sdma_descq_phys;
volatile __le64 *sdma_head_dma; /* DMA'ed by chip */
/* ppd->sdma_lock should be locked before calling this. */
int qib_sdma_make_progress(struct qib_pportdata *dd);
+static inline int qib_sdma_empty(const struct qib_pportdata *ppd)
+{
+ return ppd->sdma_descq_added == ppd->sdma_descq_removed;
+}
+
/* must be called under qib_sdma_lock */
static inline u16 qib_sdma_descq_freecnt(const struct qib_pportdata *ppd)
{
/*
- * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
- * All rights reserved.
+ * Copyright (c) 2012 Intel Corporation. All rights reserved.
+ * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
init_timer(&ppd->symerr_clear_timer);
ppd->symerr_clear_timer.function = qib_clear_symerror_on_linkup;
ppd->symerr_clear_timer.data = (unsigned long)ppd;
+
+ ppd->qib_wq = NULL;
}
static int init_pioavailregs(struct qib_devdata *dd)
}
/**
+ * qib_create_workqueues - create per port workqueues
+ * @dd: the qlogic_ib device
+ */
+static int qib_create_workqueues(struct qib_devdata *dd)
+{
+ int pidx;
+ struct qib_pportdata *ppd;
+
+ for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+ ppd = dd->pport + pidx;
+ if (!ppd->qib_wq) {
+ char wq_name[8]; /* 3 + 2 + 1 + 1 + 1 */
+ snprintf(wq_name, sizeof(wq_name), "qib%d_%d",
+ dd->unit, pidx);
+ ppd->qib_wq =
+ create_singlethread_workqueue(wq_name);
+ if (!ppd->qib_wq)
+ goto wq_error;
+ }
+ }
+ return 0;
+wq_error:
+ pr_err(
+ QIB_DRV_NAME ": create_singlethread_workqueue failed for port %d\n",
+ pidx + 1);
+ for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+ ppd = dd->pport + pidx;
+ if (ppd->qib_wq) {
+ destroy_workqueue(ppd->qib_wq);
+ ppd->qib_wq = NULL;
+ }
+ }
+ return -ENOMEM;
+}
+
+/**
* qib_init - do the actual initialization sequence on the chip
* @dd: the qlogic_ib device
* @reinit: reinitializing, so don't allocate new memory
* We can't count on interrupts since we are stopping.
*/
dd->f_quiet_serdes(ppd);
+
+ if (ppd->qib_wq) {
+ destroy_workqueue(ppd->qib_wq);
+ ppd->qib_wq = NULL;
+ }
}
qib_update_eeprom_log(dd);
if (ret)
goto bail; /* error already printed */
+ ret = qib_create_workqueues(dd);
+ if (ret)
+ goto bail;
+
/* do the generic initialization */
initfail = qib_init(dd, 0);
* @qp: the QP to post on
* @wr: the work request to send
*/
-static int qib_post_one_send(struct qib_qp *qp, struct ib_send_wr *wr)
+static int qib_post_one_send(struct qib_qp *qp, struct ib_send_wr *wr,
+ int *scheduled)
{
struct qib_swqe *wqe;
u32 next;
bail_inval:
ret = -EINVAL;
bail:
+ if (!ret && !wr->next &&
+ !qib_sdma_empty(
+ dd_from_ibdev(qp->ibqp.device)->pport + qp->port_num - 1)) {
+ qib_schedule_send(qp);
+ *scheduled = 1;
+ }
spin_unlock_irqrestore(&qp->s_lock, flags);
return ret;
}
{
struct qib_qp *qp = to_iqp(ibqp);
int err = 0;
+ int scheduled = 0;
for (; wr; wr = wr->next) {
- err = qib_post_one_send(qp, wr);
+ err = qib_post_one_send(qp, wr, &scheduled);
if (err) {
*bad_wr = wr;
goto bail;
}
/* Try to do the send work in the caller's context. */
- qib_do_send(&qp->s_work);
+ if (!scheduled)
+ qib_do_send(&qp->s_work);
bail:
return err;
get_order(lk_tab_size));
kfree(dev->qp_table);
}
+
+/*
+ * This must be called with s_lock held.
+ */
+void qib_schedule_send(struct qib_qp *qp)
+{
+ if (qib_send_ok(qp)) {
+ struct qib_ibport *ibp =
+ to_iport(qp->ibqp.device, qp->port_num);
+ struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+
+ queue_work(ppd->qib_wq, &qp->s_work);
+ }
+}
struct qib_opcode_stats opstats[128];
};
+
struct qib_ibdev {
struct ib_device ibdev;
struct list_head pending_mmaps;
/*
* This must be called with s_lock held.
*/
-static inline void qib_schedule_send(struct qib_qp *qp)
-{
- if (qib_send_ok(qp))
- queue_work(ib_wq, &qp->s_work);
-}
+void qib_schedule_send(struct qib_qp *qp);
static inline int qib_pkey_ok(u16 pkey1, u16 pkey2)
{