Commit e8aeb60c authored by Jon Mason's avatar Jon Mason
Browse files

NTB: Disable interrupts and poll under high load



Disable interrupts and poll under high load

Signed-off-by: default avatarJon Mason <jon.mason@intel.com>
parent 78958433
Loading
Loading
Loading
Loading
+37 −5
Original line number Original line Diff line number Diff line
@@ -141,6 +141,24 @@ void ntb_unregister_event_callback(struct ntb_device *ndev)
	ndev->event_cb = NULL;
	ndev->event_cb = NULL;
}
}


static void ntb_irq_work(unsigned long data)
{
	struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data;
	int rc;

	rc = db_cb->callback(db_cb->data, db_cb->db_num);
	if (rc)
		tasklet_schedule(&db_cb->irq_work);
	else {
		struct ntb_device *ndev = db_cb->ndev;
		unsigned long mask;

		mask = readw(ndev->reg_ofs.ldb_mask);
		clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
		writew(mask, ndev->reg_ofs.ldb_mask);
	}
}

/**
/**
 * ntb_register_db_callback() - register a callback for doorbell interrupt
 * ntb_register_db_callback() - register a callback for doorbell interrupt
 * @ndev: pointer to ntb_device instance
 * @ndev: pointer to ntb_device instance
@@ -155,7 +173,7 @@ void ntb_unregister_event_callback(struct ntb_device *ndev)
 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
 */
 */
int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
			     void *data, void (*func)(void *data, int db_num))
			     void *data, int (*func)(void *data, int db_num))
{
{
	unsigned long mask;
	unsigned long mask;


@@ -166,6 +184,10 @@ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,


	ndev->db_cb[idx].callback = func;
	ndev->db_cb[idx].callback = func;
	ndev->db_cb[idx].data = data;
	ndev->db_cb[idx].data = data;
	ndev->db_cb[idx].ndev = ndev;

	tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work,
		     (unsigned long) &ndev->db_cb[idx]);


	/* unmask interrupt */
	/* unmask interrupt */
	mask = readw(ndev->reg_ofs.ldb_mask);
	mask = readw(ndev->reg_ofs.ldb_mask);
@@ -194,6 +216,8 @@ void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx)
	set_bit(idx * ndev->bits_per_vector, &mask);
	set_bit(idx * ndev->bits_per_vector, &mask);
	writew(mask, ndev->reg_ofs.ldb_mask);
	writew(mask, ndev->reg_ofs.ldb_mask);


	tasklet_disable(&ndev->db_cb[idx].irq_work);

	ndev->db_cb[idx].callback = NULL;
	ndev->db_cb[idx].callback = NULL;
}
}


@@ -955,12 +979,16 @@ static irqreturn_t bwd_callback_msix_irq(int irq, void *data)
{
{
	struct ntb_db_cb *db_cb = data;
	struct ntb_db_cb *db_cb = data;
	struct ntb_device *ndev = db_cb->ndev;
	struct ntb_device *ndev = db_cb->ndev;
	unsigned long mask;


	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
		db_cb->db_num);
		db_cb->db_num);


	if (db_cb->callback)
	mask = readw(ndev->reg_ofs.ldb_mask);
		db_cb->callback(db_cb->data, db_cb->db_num);
	set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
	writew(mask, ndev->reg_ofs.ldb_mask);

	tasklet_schedule(&db_cb->irq_work);


	/* No need to check for the specific HB irq, any interrupt means
	/* No need to check for the specific HB irq, any interrupt means
	 * we're connected.
	 * we're connected.
@@ -976,12 +1004,16 @@ static irqreturn_t xeon_callback_msix_irq(int irq, void *data)
{
{
	struct ntb_db_cb *db_cb = data;
	struct ntb_db_cb *db_cb = data;
	struct ntb_device *ndev = db_cb->ndev;
	struct ntb_device *ndev = db_cb->ndev;
	unsigned long mask;


	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
		db_cb->db_num);
		db_cb->db_num);


	if (db_cb->callback)
	mask = readw(ndev->reg_ofs.ldb_mask);
		db_cb->callback(db_cb->data, db_cb->db_num);
	set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
	writew(mask, ndev->reg_ofs.ldb_mask);

	tasklet_schedule(&db_cb->irq_work);


	/* On Sandybridge, there are 16 bits in the interrupt register
	/* On Sandybridge, there are 16 bits in the interrupt register
	 * but only 4 vectors.  So, 5 bits are assigned to the first 3
	 * but only 4 vectors.  So, 5 bits are assigned to the first 3
+4 −3
Original line number Original line Diff line number Diff line
@@ -106,10 +106,11 @@ struct ntb_mw {
};
};


struct ntb_db_cb {
struct ntb_db_cb {
	void (*callback) (void *data, int db_num);
	int (*callback)(void *data, int db_num);
	unsigned int db_num;
	unsigned int db_num;
	void *data;
	void *data;
	struct ntb_device *ndev;
	struct ntb_device *ndev;
	struct tasklet_struct irq_work;
};
};


struct ntb_device {
struct ntb_device {
@@ -228,7 +229,7 @@ struct ntb_device *ntb_register_transport(struct pci_dev *pdev,
void ntb_unregister_transport(struct ntb_device *ndev);
void ntb_unregister_transport(struct ntb_device *ndev);
void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr);
void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr);
int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
			     void *data, void (*db_cb_func) (void *data,
			     void *data, int (*db_cb_func)(void *data,
							   int db_num));
							   int db_num));
void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx);
void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx);
int ntb_register_event_callback(struct ntb_device *ndev,
int ntb_register_event_callback(struct ntb_device *ndev,
+7 −18
Original line number Original line Diff line number Diff line
@@ -119,7 +119,6 @@ struct ntb_transport_qp {


	void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
	void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
			    void *data, int len);
			    void *data, int len);
	struct tasklet_struct rx_work;
	struct list_head rx_pend_q;
	struct list_head rx_pend_q;
	struct list_head rx_free_q;
	struct list_head rx_free_q;
	spinlock_t ntb_rx_pend_q_lock;
	spinlock_t ntb_rx_pend_q_lock;
@@ -1188,11 +1187,14 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
	goto out;
	goto out;
}
}


static void ntb_transport_rx(unsigned long data)
static int ntb_transport_rxc_db(void *data, int db_num)
{
{
	struct ntb_transport_qp *qp = (struct ntb_transport_qp *)data;
	struct ntb_transport_qp *qp = data;
	int rc, i;
	int rc, i;


	dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n",
		__func__, db_num);

	/* Limit the number of packets processed in a single interrupt to
	/* Limit the number of packets processed in a single interrupt to
	 * provide fairness to others
	 * provide fairness to others
	 */
	 */
@@ -1204,16 +1206,8 @@ static void ntb_transport_rx(unsigned long data)


	if (qp->dma_chan)
	if (qp->dma_chan)
		dma_async_issue_pending(qp->dma_chan);
		dma_async_issue_pending(qp->dma_chan);
}

static void ntb_transport_rxc_db(void *data, int db_num)
{
	struct ntb_transport_qp *qp = data;


	dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n",
	return i;
		__func__, db_num);

	tasklet_schedule(&qp->rx_work);
}
}


static void ntb_tx_copy_callback(void *data)
static void ntb_tx_copy_callback(void *data)
@@ -1446,19 +1440,15 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev,
			     &qp->tx_free_q);
			     &qp->tx_free_q);
	}
	}


	tasklet_init(&qp->rx_work, ntb_transport_rx, (unsigned long) qp);

	rc = ntb_register_db_callback(qp->ndev, free_queue, qp,
	rc = ntb_register_db_callback(qp->ndev, free_queue, qp,
				      ntb_transport_rxc_db);
				      ntb_transport_rxc_db);
	if (rc)
	if (rc)
		goto err3;
		goto err2;


	dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num);
	dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num);


	return qp;
	return qp;


err3:
	tasklet_disable(&qp->rx_work);
err2:
err2:
	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
		kfree(entry);
		kfree(entry);
@@ -1505,7 +1495,6 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
	}
	}


	ntb_unregister_db_callback(qp->ndev, qp->qp_num);
	ntb_unregister_db_callback(qp->ndev, qp->qp_num);
	tasklet_disable(&qp->rx_work);


	cancel_delayed_work_sync(&qp->link_work);
	cancel_delayed_work_sync(&qp->link_work);