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

Commit 5b36ad60 authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe
Browse files

mg_disk: dequeue and track in-flight request



mg_disk has at most single request in flight per device.  Till now,
whenever it needs to access the in-flight request it called
elv_next_request().  This patch makes mg_disk track the in-flight
request directly using mg_host->req and dequeue it when processing
starts.

q->queuedata is set to mg_host so that mg_host can be determined
without fetching request from the queue.

[ Impact: dequeue in-flight request, one elv_next_request() per request ]

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Cc: unsik Kim <donari75@gmail.com>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 9a8d23d8
Loading
Loading
Loading
Loading
+59 −50
Original line number Original line Diff line number Diff line
@@ -135,6 +135,7 @@ struct mg_host {
	struct device *dev;
	struct device *dev;


	struct request_queue *breq;
	struct request_queue *breq;
	struct request *req;
	spinlock_t lock;
	spinlock_t lock;
	struct gendisk *gd;
	struct gendisk *gd;


@@ -171,17 +172,27 @@ struct mg_host {


static void mg_request(struct request_queue *);
static void mg_request(struct request_queue *);


static bool mg_end_request(struct mg_host *host, int err, unsigned int nr_bytes)
{
	if (__blk_end_request(host->req, err, nr_bytes))
		return true;

	host->req = NULL;
	return false;
}

static bool mg_end_request_cur(struct mg_host *host, int err)
{
	return mg_end_request(host, err, blk_rq_cur_bytes(host->req));
}

static void mg_dump_status(const char *msg, unsigned int stat,
static void mg_dump_status(const char *msg, unsigned int stat,
		struct mg_host *host)
		struct mg_host *host)
{
{
	char *name = MG_DISK_NAME;
	char *name = MG_DISK_NAME;
	struct request *req;


	if (host->breq) {
	if (host->req)
		req = elv_next_request(host->breq);
		name = host->req->rq_disk->disk_name;
		if (req)
			name = req->rq_disk->disk_name;
	}


	printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
	printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
	if (stat & ATA_BUSY)
	if (stat & ATA_BUSY)
@@ -217,13 +228,9 @@ static void mg_dump_status(const char *msg, unsigned int stat,
			printk("AddrMarkNotFound ");
			printk("AddrMarkNotFound ");
		printk("}");
		printk("}");
		if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) {
		if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) {
			if (host->breq) {
			if (host->req)
				req = elv_next_request(host->breq);
				if (req)
				printk(", sector=%u",
				printk(", sector=%u",
					       (unsigned int)blk_rq_pos(req));
				       (unsigned int)blk_rq_pos(host->req));
			}

		}
		}
		printk("\n");
		printk("\n");
	}
	}
@@ -453,11 +460,10 @@ static int mg_disk_init(struct mg_host *host)


static void mg_bad_rw_intr(struct mg_host *host)
static void mg_bad_rw_intr(struct mg_host *host)
{
{
	struct request *req = elv_next_request(host->breq);
	if (host->req)
	if (req != NULL)
		if (++host->req->errors >= MG_MAX_ERRORS ||
		if (++req->errors >= MG_MAX_ERRORS ||
		    host->error == MG_ERR_TIMEOUT)
		    host->error == MG_ERR_TIMEOUT)
			__blk_end_request_cur(req, -EIO);
			mg_end_request_cur(host, -EIO);
}
}


static unsigned int mg_out(struct mg_host *host,
static unsigned int mg_out(struct mg_host *host,
@@ -515,7 +521,7 @@ static void mg_read(struct request *req)


		outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base +
		outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base +
				MG_REG_COMMAND);
				MG_REG_COMMAND);
	} while (__blk_end_request(req, 0, MG_SECTOR_SIZE));
	} while (mg_end_request(host, 0, MG_SECTOR_SIZE));
}
}


static void mg_write(struct request *req)
static void mg_write(struct request *req)
@@ -545,14 +551,14 @@ static void mg_write(struct request *req)


		outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
		outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
				MG_REG_COMMAND);
				MG_REG_COMMAND);
	} while (__blk_end_request(req, 0, MG_SECTOR_SIZE));
	} while (mg_end_request(host, 0, MG_SECTOR_SIZE));
}
}


static void mg_read_intr(struct mg_host *host)
static void mg_read_intr(struct mg_host *host)
{
{
	struct request *req = host->req;
	u32 i;
	u32 i;
	u16 *buff;
	u16 *buff;
	struct request *req;


	/* check status */
	/* check status */
	do {
	do {
@@ -571,7 +577,6 @@ static void mg_read_intr(struct mg_host *host)


ok_to_read:
ok_to_read:
	/* get current segment of request */
	/* get current segment of request */
	req = elv_next_request(host->breq);
	buff = (u16 *)req->buffer;
	buff = (u16 *)req->buffer;


	/* read 1 sector */
	/* read 1 sector */
@@ -585,7 +590,7 @@ ok_to_read:
	/* send read confirm */
	/* send read confirm */
	outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND);
	outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND);


	if (__blk_end_request(req, 0, MG_SECTOR_SIZE)) {
	if (mg_end_request(host, 0, MG_SECTOR_SIZE)) {
		/* set handler if read remains */
		/* set handler if read remains */
		host->mg_do_intr = mg_read_intr;
		host->mg_do_intr = mg_read_intr;
		mod_timer(&host->timer, jiffies + 3 * HZ);
		mod_timer(&host->timer, jiffies + 3 * HZ);
@@ -595,14 +600,11 @@ ok_to_read:


static void mg_write_intr(struct mg_host *host)
static void mg_write_intr(struct mg_host *host)
{
{
	struct request *req = host->req;
	u32 i, j;
	u32 i, j;
	u16 *buff;
	u16 *buff;
	struct request *req;
	bool rem;
	bool rem;


	/* get current segment of request */
	req = elv_next_request(host->breq);

	/* check status */
	/* check status */
	do {
	do {
		i = inb((unsigned long)host->dev_base + MG_REG_STATUS);
		i = inb((unsigned long)host->dev_base + MG_REG_STATUS);
@@ -619,7 +621,7 @@ static void mg_write_intr(struct mg_host *host)
	return;
	return;


ok_to_write:
ok_to_write:
	if ((rem = __blk_end_request(req, 0, MG_SECTOR_SIZE))) {
	if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) {
		/* write 1 sector and set handler if remains */
		/* write 1 sector and set handler if remains */
		buff = (u16 *)req->buffer;
		buff = (u16 *)req->buffer;
		for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) {
		for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) {
@@ -644,44 +646,47 @@ void mg_times_out(unsigned long data)
{
{
	struct mg_host *host = (struct mg_host *)data;
	struct mg_host *host = (struct mg_host *)data;
	char *name;
	char *name;
	struct request *req;


	spin_lock_irq(&host->lock);
	spin_lock_irq(&host->lock);


	req = elv_next_request(host->breq);
	if (!host->req)
	if (!req)
		goto out_unlock;
		goto out_unlock;


	host->mg_do_intr = NULL;
	host->mg_do_intr = NULL;


	name = req->rq_disk->disk_name;
	name = host->req->rq_disk->disk_name;
	printk(KERN_DEBUG "%s: timeout\n", name);
	printk(KERN_DEBUG "%s: timeout\n", name);


	host->error = MG_ERR_TIMEOUT;
	host->error = MG_ERR_TIMEOUT;
	mg_bad_rw_intr(host);
	mg_bad_rw_intr(host);


	mg_request(host->breq);
out_unlock:
out_unlock:
	mg_request(host->breq);
	spin_unlock_irq(&host->lock);
	spin_unlock_irq(&host->lock);
}
}


static void mg_request_poll(struct request_queue *q)
static void mg_request_poll(struct request_queue *q)
{
{
	struct request *req;
	struct mg_host *host = q->queuedata;
	struct mg_host *host;


	while ((req = elv_next_request(q)) != NULL) {
	while (1) {
		host = req->rq_disk->private_data;
		if (!host->req) {
			host->req = elv_next_request(q);
			if (host->req)
				blkdev_dequeue_request(host->req);
			else
				break;
		}


		if (unlikely(!blk_fs_request(req))) {
		if (unlikely(!blk_fs_request(host->req))) {
			__blk_end_request_cur(req, -EIO);
			mg_end_request_cur(host, -EIO);
			continue;
			continue;
		}
		}


		if (rq_data_dir(req) == READ)
		if (rq_data_dir(host->req) == READ)
			mg_read(req);
			mg_read(host->req);
		else
		else
			mg_write(req);
			mg_write(host->req);
	}
	}
}
}


@@ -733,16 +738,19 @@ static unsigned int mg_issue_req(struct request *req,
/* This function also called from IRQ context */
/* This function also called from IRQ context */
static void mg_request(struct request_queue *q)
static void mg_request(struct request_queue *q)
{
{
	struct mg_host *host = q->queuedata;
	struct request *req;
	struct request *req;
	struct mg_host *host;
	u32 sect_num, sect_cnt;
	u32 sect_num, sect_cnt;


	while (1) {
	while (1) {
		req = elv_next_request(q);
		if (!host->req) {
		if (!req)
			host->req = elv_next_request(q);
			return;
			if (host->req)

				blkdev_dequeue_request(host->req);
		host = req->rq_disk->private_data;
			else
				break;
		}
		req = host->req;


		/* check unwanted request call */
		/* check unwanted request call */
		if (host->mg_do_intr)
		if (host->mg_do_intr)
@@ -762,12 +770,12 @@ static void mg_request(struct request_queue *q)
					"%s: bad access: sector=%d, count=%d\n",
					"%s: bad access: sector=%d, count=%d\n",
					req->rq_disk->disk_name,
					req->rq_disk->disk_name,
					sect_num, sect_cnt);
					sect_num, sect_cnt);
			__blk_end_request_cur(req, -EIO);
			mg_end_request_cur(host, -EIO);
			continue;
			continue;
		}
		}


		if (unlikely(!blk_fs_request(req))) {
		if (unlikely(!blk_fs_request(req))) {
			__blk_end_request_cur(req, -EIO);
			mg_end_request_cur(host, -EIO);
			continue;
			continue;
		}
		}


@@ -981,6 +989,7 @@ static int mg_probe(struct platform_device *plat_dev)
				__func__, __LINE__);
				__func__, __LINE__);
		goto probe_err_5;
		goto probe_err_5;
	}
	}
	host->breq->queuedata = host;


	/* mflash is random device, thanx for the noop */
	/* mflash is random device, thanx for the noop */
	elevator_exit(host->breq->elevator);
	elevator_exit(host->breq->elevator);