Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9861dbd5 authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky
Browse files

s390/scm: use multiple queues



Exploit multiple hardware contexts (queues) that can process
requests in parallel.

Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent c7b3e923
Loading
Loading
Loading
Loading
+41 −11
Original line number Diff line number Diff line
@@ -273,30 +273,36 @@ static void scm_request_start(struct scm_request *scmrq)
	}
}

struct scm_queue {
	struct scm_request *scmrq;
	spinlock_t lock;
};

static int scm_blk_request(struct blk_mq_hw_ctx *hctx,
			   const struct blk_mq_queue_data *qd)
{
	struct scm_device *scmdev = hctx->queue->queuedata;
	struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev);
	struct scm_queue *sq = hctx->driver_data;
	struct request *req = qd->rq;
	struct scm_request *scmrq;

	spin_lock(&bdev->rq_lock);
	spin_lock(&sq->lock);
	if (!scm_permit_request(bdev, req)) {
		spin_unlock(&bdev->rq_lock);
		spin_unlock(&sq->lock);
		return BLK_MQ_RQ_QUEUE_BUSY;
	}

	scmrq = hctx->driver_data;
	scmrq = sq->scmrq;
	if (!scmrq) {
		scmrq = scm_request_fetch();
		if (!scmrq) {
			SCM_LOG(5, "no request");
			spin_unlock(&bdev->rq_lock);
			spin_unlock(&sq->lock);
			return BLK_MQ_RQ_QUEUE_BUSY;
		}
		scm_request_init(bdev, scmrq);
		hctx->driver_data = scmrq;
		sq->scmrq = scmrq;
	}
	scm_request_set(scmrq, req);

@@ -307,20 +313,43 @@ static int scm_blk_request(struct blk_mq_hw_ctx *hctx,
		if (scmrq->aob->request.msb_count)
			scm_request_start(scmrq);

		hctx->driver_data = NULL;
		spin_unlock(&bdev->rq_lock);
		sq->scmrq = NULL;
		spin_unlock(&sq->lock);
		return BLK_MQ_RQ_QUEUE_BUSY;
	}
	blk_mq_start_request(req);

	if (qd->last || scmrq->aob->request.msb_count == nr_requests_per_io) {
		scm_request_start(scmrq);
		hctx->driver_data = NULL;
		sq->scmrq = NULL;
	}
	spin_unlock(&bdev->rq_lock);
	spin_unlock(&sq->lock);
	return BLK_MQ_RQ_QUEUE_OK;
}

static int scm_blk_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
			     unsigned int idx)
{
	struct scm_queue *qd = kzalloc(sizeof(*qd), GFP_KERNEL);

	if (!qd)
		return -ENOMEM;

	spin_lock_init(&qd->lock);
	hctx->driver_data = qd;

	return 0;
}

static void scm_blk_exit_hctx(struct blk_mq_hw_ctx *hctx, unsigned int idx)
{
	struct scm_queue *qd = hctx->driver_data;

	WARN_ON(qd->scmrq);
	kfree(hctx->driver_data);
	hctx->driver_data = NULL;
}

static void __scmrq_log_error(struct scm_request *scmrq)
{
	struct aob *aob = scmrq->aob;
@@ -396,6 +425,8 @@ static const struct block_device_operations scm_blk_devops = {
static const struct blk_mq_ops scm_mq_ops = {
	.queue_rq = scm_blk_request,
	.complete = scm_blk_request_done,
	.init_hctx = scm_blk_init_hctx,
	.exit_hctx = scm_blk_exit_hctx,
};

int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
@@ -413,12 +444,11 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)

	bdev->scmdev = scmdev;
	bdev->state = SCM_OPER;
	spin_lock_init(&bdev->rq_lock);
	spin_lock_init(&bdev->lock);
	atomic_set(&bdev->queued_reqs, 0);

	bdev->tag_set.ops = &scm_mq_ops;
	bdev->tag_set.nr_hw_queues = 1;
	bdev->tag_set.nr_hw_queues = nr_requests;
	bdev->tag_set.queue_depth = nr_requests_per_io * nr_requests;
	bdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;

+1 −2
Original line number Diff line number Diff line
@@ -19,8 +19,7 @@ struct scm_blk_dev {
	struct gendisk *gendisk;
	struct blk_mq_tag_set tag_set;
	struct scm_device *scmdev;
	spinlock_t rq_lock;	/* guard the request queue */
	spinlock_t lock;	/* guard the rest of the blockdev */
	spinlock_t lock;
	atomic_t queued_reqs;
	enum {SCM_OPER, SCM_WR_PROHIBIT} state;
	struct list_head finished_requests;