Commit f1d82698 authored by Alex Dubov's avatar Alex Dubov Committed by Linus Torvalds

memstick: use fully asynchronous request processing

Instead of using a separate thread to pump requests from block layer queue
to memstick, do so inline, utilizing the callback design of the memstick.

[akpm@linux-foundation.org: fix warnings]
Signed-off-by: default avatarAlex Dubov <oakad@yahoo.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 17017d8d
...@@ -249,8 +249,11 @@ EXPORT_SYMBOL(memstick_next_req); ...@@ -249,8 +249,11 @@ EXPORT_SYMBOL(memstick_next_req);
*/ */
void memstick_new_req(struct memstick_host *host) void memstick_new_req(struct memstick_host *host)
{ {
host->retries = cmd_retries; if (host->card) {
host->request(host); host->retries = cmd_retries;
INIT_COMPLETION(host->card->mrq_complete);
host->request(host);
}
} }
EXPORT_SYMBOL(memstick_new_req); EXPORT_SYMBOL(memstick_new_req);
......
...@@ -136,9 +136,8 @@ struct mspro_block_data { ...@@ -136,9 +136,8 @@ struct mspro_block_data {
unsigned int caps; unsigned int caps;
struct gendisk *disk; struct gendisk *disk;
struct request_queue *queue; struct request_queue *queue;
struct request *block_req;
spinlock_t q_lock; spinlock_t q_lock;
wait_queue_head_t q_wait;
struct task_struct *q_thread;
unsigned short page_size; unsigned short page_size;
unsigned short cylinders; unsigned short cylinders;
...@@ -147,9 +146,10 @@ struct mspro_block_data { ...@@ -147,9 +146,10 @@ struct mspro_block_data {
unsigned char system; unsigned char system;
unsigned char read_only:1, unsigned char read_only:1,
active:1, eject:1,
has_request:1, has_request:1,
data_dir:1; data_dir:1,
active:1;
unsigned char transfer_cmd; unsigned char transfer_cmd;
int (*mrq_handler)(struct memstick_dev *card, int (*mrq_handler)(struct memstick_dev *card,
...@@ -160,12 +160,14 @@ struct mspro_block_data { ...@@ -160,12 +160,14 @@ struct mspro_block_data {
struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS];
unsigned int seg_count; unsigned int seg_count;
unsigned int current_seg; unsigned int current_seg;
unsigned short current_page; unsigned int current_page;
}; };
static DEFINE_IDR(mspro_block_disk_idr); static DEFINE_IDR(mspro_block_disk_idr);
static DEFINE_MUTEX(mspro_block_disk_lock); static DEFINE_MUTEX(mspro_block_disk_lock);
static int mspro_block_complete_req(struct memstick_dev *card, int error);
/*** Block device ***/ /*** Block device ***/
static int mspro_block_bd_open(struct inode *inode, struct file *filp) static int mspro_block_bd_open(struct inode *inode, struct file *filp)
...@@ -197,8 +199,10 @@ static int mspro_block_disk_release(struct gendisk *disk) ...@@ -197,8 +199,10 @@ static int mspro_block_disk_release(struct gendisk *disk)
mutex_lock(&mspro_block_disk_lock); mutex_lock(&mspro_block_disk_lock);
if (msb->usage_count) { if (msb) {
msb->usage_count--; if (msb->usage_count)
msb->usage_count--;
if (!msb->usage_count) { if (!msb->usage_count) {
kfree(msb); kfree(msb);
disk->private_data = NULL; disk->private_data = NULL;
...@@ -523,11 +527,13 @@ static int h_mspro_block_req_init(struct memstick_dev *card, ...@@ -523,11 +527,13 @@ static int h_mspro_block_req_init(struct memstick_dev *card,
static int h_mspro_block_default(struct memstick_dev *card, static int h_mspro_block_default(struct memstick_dev *card,
struct memstick_request **mrq) struct memstick_request **mrq)
{ {
complete(&card->mrq_complete); return mspro_block_complete_req(card, (*mrq)->error);
if (!(*mrq)->error) }
return -EAGAIN;
else static int h_mspro_block_default_bad(struct memstick_dev *card,
return (*mrq)->error; struct memstick_request **mrq)
{
return -ENXIO;
} }
static int h_mspro_block_get_ro(struct memstick_dev *card, static int h_mspro_block_get_ro(struct memstick_dev *card,
...@@ -535,44 +541,30 @@ static int h_mspro_block_get_ro(struct memstick_dev *card, ...@@ -535,44 +541,30 @@ static int h_mspro_block_get_ro(struct memstick_dev *card,
{ {
struct mspro_block_data *msb = memstick_get_drvdata(card); struct mspro_block_data *msb = memstick_get_drvdata(card);
if ((*mrq)->error) { if (!(*mrq)->error) {
complete(&card->mrq_complete); if ((*mrq)->data[offsetof(struct ms_status_register, status0)]
return (*mrq)->error; & MEMSTICK_STATUS0_WP)
msb->read_only = 1;
else
msb->read_only = 0;
} }
if ((*mrq)->data[offsetof(struct ms_status_register, status0)] return mspro_block_complete_req(card, (*mrq)->error);
& MEMSTICK_STATUS0_WP)
msb->read_only = 1;
else
msb->read_only = 0;
complete(&card->mrq_complete);
return -EAGAIN;
} }
static int h_mspro_block_wait_for_ced(struct memstick_dev *card, static int h_mspro_block_wait_for_ced(struct memstick_dev *card,
struct memstick_request **mrq) struct memstick_request **mrq)
{ {
if ((*mrq)->error) {
complete(&card->mrq_complete);
return (*mrq)->error;
}
dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]); dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]);
if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) { if (!(*mrq)->error) {
card->current_mrq.error = -EFAULT; if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR))
complete(&card->mrq_complete); (*mrq)->error = -EFAULT;
return card->current_mrq.error; else if (!((*mrq)->data[0] & MEMSTICK_INT_CED))
return 0;
} }
if (!((*mrq)->data[0] & MEMSTICK_INT_CED)) return mspro_block_complete_req(card, (*mrq)->error);
return 0;
else {
card->current_mrq.error = 0;
complete(&card->mrq_complete);
return -EAGAIN;
}
} }
static int h_mspro_block_transfer_data(struct memstick_dev *card, static int h_mspro_block_transfer_data(struct memstick_dev *card,
...@@ -583,10 +575,8 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card, ...@@ -583,10 +575,8 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card,
struct scatterlist t_sg = { 0 }; struct scatterlist t_sg = { 0 };
size_t t_offset; size_t t_offset;
if ((*mrq)->error) { if ((*mrq)->error)
complete(&card->mrq_complete); return mspro_block_complete_req(card, (*mrq)->error);
return (*mrq)->error;
}
switch ((*mrq)->tpc) { switch ((*mrq)->tpc) {
case MS_TPC_WRITE_REG: case MS_TPC_WRITE_REG:
...@@ -617,8 +607,8 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card, ...@@ -617,8 +607,8 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card,
if (msb->current_seg == msb->seg_count) { if (msb->current_seg == msb->seg_count) {
if (t_val & MEMSTICK_INT_CED) { if (t_val & MEMSTICK_INT_CED) {
complete(&card->mrq_complete); return mspro_block_complete_req(card,
return -EAGAIN; 0);
} else { } else {
card->next_request card->next_request
= h_mspro_block_wait_for_ced; = h_mspro_block_wait_for_ced;
...@@ -666,90 +656,120 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card, ...@@ -666,90 +656,120 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card,
/*** Data transfer ***/ /*** Data transfer ***/
static void mspro_block_process_request(struct memstick_dev *card, static int mspro_block_issue_req(struct memstick_dev *card, int chunk)
struct request *req)
{ {
struct mspro_block_data *msb = memstick_get_drvdata(card); struct mspro_block_data *msb = memstick_get_drvdata(card);
struct mspro_param_register param;
int rc, chunk, cnt;
unsigned short page_count;
sector_t t_sec; sector_t t_sec;
unsigned long flags; unsigned int count;
struct mspro_param_register param;
do { try_again:
page_count = 0; while (chunk) {
msb->current_page = 0;
msb->current_seg = 0; msb->current_seg = 0;
msb->seg_count = blk_rq_map_sg(req->q, req, msb->req_sg); msb->seg_count = blk_rq_map_sg(msb->block_req->q,
msb->block_req,
msb->req_sg);
if (msb->seg_count) { if (!msb->seg_count) {
msb->current_page = 0; chunk = __blk_end_request(msb->block_req, -ENOMEM,
for (rc = 0; rc < msb->seg_count; rc++) blk_rq_cur_bytes(msb->block_req));
page_count += msb->req_sg[rc].length continue;
/ msb->page_size; }
t_sec = req->sector;
sector_div(t_sec, msb->page_size >> 9);
param.system = msb->system;
param.data_count = cpu_to_be16(page_count);
param.data_address = cpu_to_be32((uint32_t)t_sec);
param.tpc_param = 0;
msb->data_dir = rq_data_dir(req);
msb->transfer_cmd = msb->data_dir == READ
? MSPRO_CMD_READ_DATA
: MSPRO_CMD_WRITE_DATA;
dev_dbg(&card->dev, "data transfer: cmd %x, "
"lba %x, count %x\n", msb->transfer_cmd,
be32_to_cpu(param.data_address),
page_count);
card->next_request = h_mspro_block_req_init;
msb->mrq_handler = h_mspro_block_transfer_data;
memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
&param, sizeof(param));
memstick_new_req(card->host);
wait_for_completion(&card->mrq_complete);
rc = card->current_mrq.error;
if (rc || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { t_sec = msb->block_req->sector << 9;
for (cnt = 0; cnt < msb->current_seg; cnt++) sector_div(t_sec, msb->page_size);
page_count += msb->req_sg[cnt].length
/ msb->page_size;
if (msb->current_page)
page_count += msb->current_page - 1;
if (page_count && (msb->data_dir == READ))
rc = msb->page_size * page_count;
else
rc = -EIO;
} else
rc = msb->page_size * page_count;
} else
rc = -EFAULT;
spin_lock_irqsave(&msb->q_lock, flags); count = msb->block_req->nr_sectors << 9;
if (rc >= 0) count /= msb->page_size;
chunk = __blk_end_request(req, 0, rc);
else
chunk = __blk_end_request(req, rc, 0);
dev_dbg(&card->dev, "end chunk %d, %d\n", rc, chunk); param.system = msb->system;
spin_unlock_irqrestore(&msb->q_lock, flags); param.data_count = cpu_to_be16(count);
} while (chunk); param.data_address = cpu_to_be32((uint32_t)t_sec);
param.tpc_param = 0;
msb->data_dir = rq_data_dir(msb->block_req);
msb->transfer_cmd = msb->data_dir == READ
? MSPRO_CMD_READ_DATA
: MSPRO_CMD_WRITE_DATA;
dev_dbg(&card->dev, "data transfer: cmd %x, "
"lba %x, count %x\n", msb->transfer_cmd,
be32_to_cpu(param.data_address), count);
card->next_request = h_mspro_block_req_init;
msb->mrq_handler = h_mspro_block_transfer_data;
memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
&param, sizeof(param));
memstick_new_req(card->host);
return 0;
}
dev_dbg(&card->dev, "elv_next\n");
msb->block_req = elv_next_request(msb->queue);
if (!msb->block_req) {
dev_dbg(&card->dev, "issue end\n");
return -EAGAIN;
}
dev_dbg(&card->dev, "trying again\n");
chunk = 1;
goto try_again;
} }
static int mspro_block_has_request(struct mspro_block_data *msb) static int mspro_block_complete_req(struct memstick_dev *card, int error)
{ {
int rc = 0; struct mspro_block_data *msb = memstick_get_drvdata(card);
int chunk, cnt;
unsigned int t_len = 0;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&msb->q_lock, flags); spin_lock_irqsave(&msb->q_lock, flags);
if (kthread_should_stop() || msb->has_request) dev_dbg(&card->dev, "complete %d, %d\n", msb->has_request ? 1 : 0,
rc = 1; error);
if (msb->has_request) {
/* Nothing to do - not really an error */
if (error == -EAGAIN)
error = 0;
if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) {
if (msb->data_dir == READ) {
for (cnt = 0; cnt < msb->current_seg; cnt++)
t_len += msb->req_sg[cnt].length
/ msb->page_size;
if (msb->current_page)
t_len += msb->current_page - 1;
t_len *= msb->page_size;
}
} else
t_len = msb->block_req->nr_sectors << 9;
dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error);
if (error && !t_len)
t_len = blk_rq_cur_bytes(msb->block_req);
chunk = __blk_end_request(msb->block_req, error, t_len);
error = mspro_block_issue_req(card, chunk);
if (!error)
goto out;
else
msb->has_request = 0;
} else {
if (!error)
error = -EAGAIN;
}
card->next_request = h_mspro_block_default_bad;
complete_all(&card->mrq_complete);
out:
spin_unlock_irqrestore(&msb->q_lock, flags); spin_unlock_irqrestore(&msb->q_lock, flags);
return rc; return error;
} }
static void mspro_block_stop(struct memstick_dev *card) static void mspro_block_stop(struct memstick_dev *card)
...@@ -783,54 +803,37 @@ static void mspro_block_start(struct memstick_dev *card) ...@@ -783,54 +803,37 @@ static void mspro_block_start(struct memstick_dev *card)
spin_unlock_irqrestore(&msb->q_lock, flags); spin_unlock_irqrestore(&msb->q_lock, flags);
} }
static int mspro_block_queue_thread(void *data) static int mspro_block_prepare_req(struct request_queue *q, struct request *req)
{ {
struct memstick_dev *card = data; if (!blk_fs_request(req) && !blk_pc_request(req)) {
struct memstick_host *host = card->host; blk_dump_rq_flags(req, "MSPro unsupported request");
struct mspro_block_data *msb = memstick_get_drvdata(card); return BLKPREP_KILL;
struct request *req; }
unsigned long flags;
while (1) {
wait_event(msb->q_wait, mspro_block_has_request(msb));
dev_dbg(&card->dev, "thread iter\n");
spin_lock_irqsave(&msb->q_lock, flags); req->cmd_flags |= REQ_DONTPREP;
req = elv_next_request(msb->queue);
dev_dbg(&card->dev, "next req %p\n", req);
if (!req) {
msb->has_request = 0;
if (kthread_should_stop()) {
spin_unlock_irqrestore(&msb->q_lock, flags);
break;
}
} else
msb->has_request = 1;
spin_unlock_irqrestore(&msb->q_lock, flags);
if (req) { return BLKPREP_OK;
mutex_lock(&host->lock);
mspro_block_process_request(card, req);
mutex_unlock(&host->lock);
}
}
dev_dbg(&card->dev, "thread finished\n");
return 0;
} }
static void mspro_block_request(struct request_queue *q) static void mspro_block_submit_req(struct request_queue *q)
{ {
struct memstick_dev *card = q->queuedata; struct memstick_dev *card = q->queuedata;
struct mspro_block_data *msb = memstick_get_drvdata(card); struct mspro_block_data *msb = memstick_get_drvdata(card);
struct request *req = NULL; struct request *req = NULL;
if (msb->q_thread) { if (msb->has_request)
msb->has_request = 1; return;
wake_up_all(&msb->q_wait);
} else { if (msb->eject) {
while ((req = elv_next_request(q)) != NULL) while ((req = elv_next_request(q)) != NULL)
end_queued_request(req, -ENODEV); end_queued_request(req, -ENODEV);
return;
} }
msb->has_request = 1;
if (mspro_block_issue_req(card, 0))
msb->has_request = 0;
} }
/*** Initialization ***/ /*** Initialization ***/
...@@ -1200,16 +1203,14 @@ static int mspro_block_init_disk(struct memstick_dev *card) ...@@ -1200,16 +1203,14 @@ static int mspro_block_init_disk(struct memstick_dev *card)
goto out_release_id; goto out_release_id;
} }
spin_lock_init(&msb->q_lock); msb->queue = blk_init_queue(mspro_block_submit_req, &msb->q_lock);
init_waitqueue_head(&msb->q_wait);
msb->queue = blk_init_queue(mspro_block_request, &msb->q_lock);
if (!msb->queue) { if (!msb->queue) {
rc = -ENOMEM; rc = -ENOMEM;
goto out_put_disk; goto out_put_disk;
} }
msb->queue->queuedata = card; msb->queue->queuedata = card;
blk_queue_prep_rq(msb->queue, mspro_block_prepare_req);
blk_queue_bounce_limit(msb->queue, limit); blk_queue_bounce_limit(msb->queue, limit);
blk_queue_max_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); blk_queue_max_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES);
...@@ -1235,14 +1236,8 @@ static int mspro_block_init_disk(struct memstick_dev *card) ...@@ -1235,14 +1236,8 @@ static int mspro_block_init_disk(struct memstick_dev *card)
capacity *= msb->page_size >> 9; capacity *= msb->page_size >> 9;
set_capacity(msb->disk, capacity); set_capacity(msb->disk, capacity);
dev_dbg(&card->dev, "capacity set %ld\n", capacity); dev_dbg(&card->dev, "capacity set %ld\n", capacity);
msb->q_thread = kthread_run(mspro_block_queue_thread, card,
DRIVER_NAME"d");
if (IS_ERR(msb->q_thread))
goto out_put_disk;
mutex_unlock(&host->lock);
add_disk(msb->disk); add_disk(msb->disk);
mutex_lock(&host->lock);
msb->active = 1; msb->active = 1;
return 0; return 0;
...@@ -1290,6 +1285,7 @@ static int mspro_block_probe(struct memstick_dev *card) ...@@ -1290,6 +1285,7 @@ static int mspro_block_probe(struct memstick_dev *card)
return -ENOMEM; return -ENOMEM;
memstick_set_drvdata(card, msb); memstick_set_drvdata(card, msb);
msb->card = card; msb->card = card;
spin_lock_init(&msb->q_lock);
rc = mspro_block_init_card(card); rc = mspro_block_init_card(card);
...@@ -1319,26 +1315,17 @@ static int mspro_block_probe(struct memstick_dev *card) ...@@ -1319,26 +1315,17 @@ static int mspro_block_probe(struct memstick_dev *card)
static void mspro_block_remove(struct memstick_dev *card) static void mspro_block_remove(struct memstick_dev *card)
{ {
struct mspro_block_data *msb = memstick_get_drvdata(card); struct mspro_block_data *msb = memstick_get_drvdata(card);
struct task_struct *q_thread = NULL;
unsigned long flags; unsigned long flags;
del_gendisk(msb->disk); del_gendisk(msb->disk);
dev_dbg(&card->dev, "mspro block remove\n"); dev_dbg(&card->dev, "mspro block remove\n");
spin_lock_irqsave(&msb->q_lock, flags); spin_lock_irqsave(&msb->q_lock, flags);
q_thread = msb->q_thread; msb->eject = 1;
msb->q_thread = NULL; blk_start_queue(msb->queue);
msb->active = 0;
spin_unlock_irqrestore(&msb->q_lock, flags); spin_unlock_irqrestore(&msb->q_lock, flags);
if (q_thread) {
mutex_unlock(&card->host->lock);
kthread_stop(q_thread);
mutex_lock(&card->host->lock);
}
dev_dbg(&card->dev, "queue thread stopped\n");
blk_cleanup_queue(msb->queue); blk_cleanup_queue(msb->queue);
msb->queue = NULL;
sysfs_remove_group(&card->dev.kobj, &msb->attr_group); sysfs_remove_group(&card->dev.kobj, &msb->attr_group);
...@@ -1355,19 +1342,13 @@ static void mspro_block_remove(struct memstick_dev *card) ...@@ -1355,19 +1342,13 @@ static void mspro_block_remove(struct memstick_dev *card)
static int mspro_block_suspend(struct memstick_dev *card, pm_message_t state) static int mspro_block_suspend(struct memstick_dev *card, pm_message_t state)
{ {
struct mspro_block_data *msb = memstick_get_drvdata(card); struct mspro_block_data *msb = memstick_get_drvdata(card);
struct task_struct *q_thread = NULL;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&msb->q_lock, flags); spin_lock_irqsave(&msb->q_lock, flags);
q_thread = msb->q_thread;
msb->q_thread = NULL;
msb->active = 0;
blk_stop_queue(msb->queue); blk_stop_queue(msb->queue);
msb->active = 0;
spin_unlock_irqrestore(&msb->q_lock, flags); spin_unlock_irqrestore(&msb->q_lock, flags);
if (q_thread)
kthread_stop(q_thread);
return 0; return 0;
} }
...@@ -1406,14 +1387,7 @@ static int mspro_block_resume(struct memstick_dev *card) ...@@ -1406,14 +1387,7 @@ static int mspro_block_resume(struct memstick_dev *card)
if (memcmp(s_attr->data, r_attr->data, s_attr->size)) if (memcmp(s_attr->data, r_attr->data, s_attr->size))
break; break;
memstick_set_drvdata(card, msb); msb->active = 1;
msb->q_thread = kthread_run(mspro_block_queue_thread,
card, DRIVER_NAME"d");
if (IS_ERR(msb->q_thread))
msb->q_thread = NULL;
else
msb->active = 1;
break; break;
} }
} }
......
...@@ -50,6 +50,7 @@ struct jmb38x_ms_host { ...@@ -50,6 +50,7 @@ struct jmb38x_ms_host {
struct jmb38x_ms *chip; struct jmb38x_ms *chip;
void __iomem *addr; void __iomem *addr;
spinlock_t lock; spinlock_t lock;
struct tasklet_struct notify;
int id; int id;
char host_id[32]; char host_id[32];
int irq; int irq;
...@@ -590,25 +591,35 @@ static void jmb38x_ms_abort(unsigned long data) ...@@ -590,25 +591,35 @@ static void jmb38x_ms_abort(unsigned long data)
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
} }
static void jmb38x_ms_request(struct memstick_host *msh) static void jmb38x_ms_req_tasklet(unsigned long data)
{ {
struct memstick_host *msh = (struct memstick_host *)data;
struct jmb38x_ms_host *host = memstick_priv(msh); struct jmb38x_ms_host *host = memstick_priv(msh);
unsigned long flags; unsigned long flags;
int rc; int rc;
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
if (host->req) { if (!host->req) {
spin_unlock_irqrestore(&host->lock, flags); do {
BUG(); rc = memstick_next_req(msh, &host->req);
return; dev_dbg(&host->chip->pdev->dev, "tasklet req %d\n", rc);
} while (!rc && jmb38x_ms_issue_cmd(msh));
} }
do {
rc = memstick_next_req(msh, &host->req);
} while (!rc && jmb38x_ms_issue_cmd(msh));
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
} }
static void jmb38x_ms_dummy_submit(struct memstick_host *msh)
{
return;
}
static void jmb38x_ms_submit_req(struct memstick_host *msh)
{
struct jmb38x_ms_host *host = memstick_priv(msh);
tasklet_schedule(&host->notify);
}
static int jmb38x_ms_reset(struct jmb38x_ms_host *host) static int jmb38x_ms_reset(struct jmb38x_ms_host *host)
{ {
int cnt; int cnt;
...@@ -816,7 +827,9 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt) ...@@ -816,7 +827,9 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt)
host->id); host->id);
host->irq = jm->pdev->irq; host->irq = jm->pdev->irq;
host->timeout_jiffies = msecs_to_jiffies(1000); host->timeout_jiffies = msecs_to_jiffies(1000);
msh->request = jmb38x_ms_request;
tasklet_init(&host->notify, jmb38x_ms_req_tasklet, (unsigned long)msh);
msh->request = jmb38x_ms_submit_req;
msh->set_param = jmb38x_ms_set_param; msh->set_param = jmb38x_ms_set_param;
msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8;
...@@ -928,6 +941,8 @@ static void jmb38x_ms_remove(struct pci_dev *dev) ...@@ -928,6 +941,8 @@ static void jmb38x_ms_remove(struct pci_dev *dev)
host = memstick_priv(jm->hosts[cnt]); host = memstick_priv(jm->hosts[cnt]);
jm->hosts[cnt]->request = jmb38x_ms_dummy_submit;
tasklet_kill(&host->notify);
writel(0, host->addr + INT_SIGNAL_ENABLE); writel(0, host->addr + INT_SIGNAL_ENABLE);
writel(0, host->addr + INT_STATUS_ENABLE); writel(0, host->addr + INT_STATUS_ENABLE);
mmiowb(); mmiowb();
......
...@@ -71,6 +71,7 @@ struct tifm_ms { ...@@ -71,6 +71,7 @@ struct tifm_ms {
struct tifm_dev *dev; struct tifm_dev *dev;
struct timer_list timer; struct timer_list timer;
struct memstick_request *req; struct memstick_request *req;
struct tasklet_struct notify;
unsigned int mode_mask; unsigned int mode_mask;
unsigned int block_pos; unsigned int block_pos;
unsigned long timeout_jiffies; unsigned long timeout_jiffies;
...@@ -455,40 +456,45 @@ static void tifm_ms_card_event(struct tifm_dev *sock) ...@@ -455,40 +456,45 @@ static void tifm_ms_card_event(struct tifm_dev *sock)
return; return;
} }
static void tifm_ms_request(struct memstick_host *msh) static void tifm_ms_req_tasklet(unsigned long data)
{ {
struct memstick_host *msh = (struct memstick_host *)data;
struct tifm_ms *host = memstick_priv(msh); struct tifm_ms *host = memstick_priv(msh);
struct tifm_dev *sock = host->dev; struct tifm_dev *sock = host->dev;
unsigned long flags; unsigned long flags;
int rc; int rc;
spin_lock_irqsave(&sock->lock, flags); spin_lock_irqsave(&sock->lock, flags);
if (host->req) { if (!host->req) {
printk(KERN_ERR "%s : unfinished request detected\n", if (host->eject) {
sock->dev.bus_id); do {
spin_unlock_irqrestore(&sock->lock, flags); rc = memstick_next_req(msh, &host->req);
tifm_eject(host->dev); if (!rc)
return; host->req->error = -ETIME;
} } while (!rc);
spin_unlock_irqrestore(&sock->lock, flags);
return;
}
if (host->eject) {
do { do {
rc = memstick_next_req(msh, &host->req); rc = memstick_next_req(msh, &host->req);
if (!rc) } while (!rc && tifm_ms_issue_cmd(host));
host->req->error = -ETIME;
} while (!rc);
spin_unlock_irqrestore(&sock->lock, flags);
return;
} }
do {
rc = memstick_next_req(msh, &host->req);
} while (!rc && tifm_ms_issue_cmd(host));
spin_unlock_irqrestore(&sock->lock, flags); spin_unlock_irqrestore(&sock->lock, flags);
}
static void tifm_ms_dummy_submit(struct memstick_host *msh)
{
return; return;
} }
static void tifm_ms_submit_req(struct memstick_host *msh)
{
struct tifm_ms *host = memstick_priv(msh);
tasklet_schedule(&host->notify);
}
static int tifm_ms_set_param(struct memstick_host *msh, static int tifm_ms_set_param(struct memstick_host *msh,
enum memstick_param param, enum memstick_param param,
int value) int value)
...@@ -569,8 +575,9 @@ static int tifm_ms_probe(struct tifm_dev *sock) ...@@ -569,8 +575,9 @@ static int tifm_ms_probe(struct tifm_dev *sock)
host->timeout_jiffies = msecs_to_jiffies(1000); host->timeout_jiffies = msecs_to_jiffies(1000);
setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host); setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host);
tasklet_init(&host->notify, tifm_ms_req_tasklet, (unsigned long)msh);
msh->request = tifm_ms_request; msh->request = tifm_ms_submit_req;
msh->set_param = tifm_ms_set_param; msh->set_param = tifm_ms_set_param;
sock->card_event = tifm_ms_card_event; sock->card_event = tifm_ms_card_event;
sock->data_event = tifm_ms_data_event; sock->data_event = tifm_ms_data_event;
...@@ -592,6 +599,8 @@ static void tifm_ms_remove(struct tifm_dev *sock) ...@@ -592,6 +599,8 @@ static void tifm_ms_remove(struct tifm_dev *sock)
int rc = 0; int rc = 0;
unsigned long flags; unsigned long flags;
msh->request = tifm_ms_dummy_submit;
tasklet_kill(&host->notify);
spin_lock_irqsave(&sock->lock, flags); spin_lock_irqsave(&sock->lock, flags);
host->eject = 1; host->eject = 1;
if (host->req) { if (host->req) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment