Commit ad5fc6bb authored by Jens Axboe's avatar Jens Axboe
Browse files

gdrom: convert to blk-mq



Ditch the deffered list, lock, and workqueue handling. Just mark the
set as being blocking, so we are invoked from a workqueue already.

Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent a9f38e1d
Loading
Loading
Loading
Loading
+79 −95
Original line number Diff line number Diff line
@@ -31,12 +31,11 @@
#include <linux/cdrom.h>
#include <linux/genhd.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <scsi/scsi.h>
#include <asm/io.h>
@@ -102,11 +101,6 @@ static int gdrom_major;
static DECLARE_WAIT_QUEUE_HEAD(command_queue);
static DECLARE_WAIT_QUEUE_HEAD(request_queue);

static DEFINE_SPINLOCK(gdrom_lock);
static void gdrom_readdisk_dma(struct work_struct *work);
static DECLARE_WORK(work, gdrom_readdisk_dma);
static LIST_HEAD(gdrom_deferred);

struct gdromtoc {
	unsigned int entry[99];
	unsigned int first, last;
@@ -122,6 +116,7 @@ static struct gdrom_unit {
	char disk_type;
	struct gdromtoc *toc;
	struct request_queue *gdrom_rq;
	struct blk_mq_tag_set tag_set;
} gd;

struct gdrom_id {
@@ -584,26 +579,19 @@ static int gdrom_set_interrupt_handlers(void)
 * 9 -> sectors >> 8
 * 10 -> sectors
 */
static void gdrom_readdisk_dma(struct work_struct *work)
static blk_status_t gdrom_readdisk_dma(struct request *req)
{
	int block, block_cnt;
	blk_status_t err;
	struct packet_command *read_command;
	struct list_head *elem, *next;
	struct request *req;
	unsigned long timeout;

	if (list_empty(&gdrom_deferred))
		return;
	read_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
	if (!read_command)
		return; /* get more memory later? */
		return BLK_STS_RESOURCE;

	read_command->cmd[0] = 0x30;
	read_command->cmd[1] = 0x20;
	spin_lock(&gdrom_lock);
	list_for_each_safe(elem, next, &gdrom_deferred) {
		req = list_entry(elem, struct request, queuelist);
		spin_unlock(&gdrom_lock);
	block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
	block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
	__raw_writel(virt_to_phys(bio_data(req->bio)), GDROM_DMA_STARTADDR_REG);
@@ -648,39 +636,26 @@ static void gdrom_readdisk_dma(struct work_struct *work)
	err = gd.transfer ? BLK_STS_IOERR : BLK_STS_OK;
	gd.transfer = 0;
	gd.pending = 0;
		/* now seek to take the request spinlock
		* before handling ending the request */
		spin_lock(&gdrom_lock);
		list_del_init(&req->queuelist);
		__blk_end_request_all(req, err);
	}
	spin_unlock(&gdrom_lock);

	blk_mq_end_request(req, err);
	kfree(read_command);
	return BLK_STS_OK;
}

static void gdrom_request(struct request_queue *rq)
static blk_status_t gdrom_queue_rq(struct blk_mq_hw_ctx *hctx,
				   const struct blk_mq_queue_data *bd)
{
	struct request *req;
	blk_mq_start_request(bd->rq);

	while ((req = blk_fetch_request(rq)) != NULL) {
		switch (req_op(req)) {
	switch (req_op(bd->rq)) {
	case REQ_OP_READ:
			/*
			 * Add to list of deferred work and then schedule
			 * workqueue.
			 */
			list_add_tail(&req->queuelist, &gdrom_deferred);
			schedule_work(&work);
			break;
		return gdrom_readdisk_dma(bd->rq);
	case REQ_OP_WRITE:
		pr_notice("Read only device - write request ignored\n");
			__blk_end_request_all(req, BLK_STS_IOERR);
			break;
		return BLK_STS_IOERR;
	default:
		printk(KERN_DEBUG "gdrom: Non-fs request ignored\n");
			__blk_end_request_all(req, BLK_STS_IOERR);
			break;
		}
		return BLK_STS_IOERR;
	}
}

@@ -768,6 +743,10 @@ static int probe_gdrom_setupqueue(void)
	return gdrom_init_dma_mode();
}

static const struct blk_mq_ops gdrom_mq_ops = {
	.queue_rq	= gdrom_queue_rq,
};

/*
 * register this as a block device and as compliant with the
 * universal CD Rom driver interface
@@ -811,11 +790,15 @@ static int probe_gdrom(struct platform_device *devptr)
	err = gdrom_set_interrupt_handlers();
	if (err)
		goto probe_fail_cmdirq_register;
	gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock);
	if (!gd.gdrom_rq) {
		err = -ENOMEM;

	gd.gdrom_rq = blk_mq_init_sq_queue(&gd.tag_set, &gdrom_mq_ops, 1,
				BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
	if (IS_ERR(gd.gdrom_rq)) {
		rc = PTR_ERR(gd.gdrom_rq);
		gd.gdrom_rq = NULL;
		goto probe_fail_requestq;
	}

	blk_queue_bounce_limit(gd.gdrom_rq, BLK_BOUNCE_HIGH);

	err = probe_gdrom_setupqueue();
@@ -832,6 +815,7 @@ static int probe_gdrom(struct platform_device *devptr)

probe_fail_toc:
	blk_cleanup_queue(gd.gdrom_rq);
	blk_mq_free_tag_set(&gd.tag_set);
probe_fail_requestq:
	free_irq(HW_EVENT_GDROM_DMA, &gd);
	free_irq(HW_EVENT_GDROM_CMD, &gd);
@@ -849,8 +833,8 @@ probe_fail_no_mem:

static int remove_gdrom(struct platform_device *devptr)
{
	flush_work(&work);
	blk_cleanup_queue(gd.gdrom_rq);
	blk_mq_free_tag_set(&gd.tag_set);
	free_irq(HW_EVENT_GDROM_CMD, &gd);
	free_irq(HW_EVENT_GDROM_DMA, &gd);
	del_gendisk(gd.disk);