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: Alex Dubov <oakad@yahoo.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
17017d8d2c
commit
f1d8269802
|
@ -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 {
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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 @@ has_int_reg:
|
||||||
|
|
||||||
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 @@ has_int_reg:
|
||||||
|
|
||||||
/*** 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;
|
t_sec = msb->block_req->sector << 9;
|
||||||
sector_div(t_sec, msb->page_size >> 9);
|
sector_div(t_sec, msb->page_size);
|
||||||
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);
|
count = msb->block_req->nr_sectors << 9;
|
||||||
msb->transfer_cmd = msb->data_dir == READ
|
count /= msb->page_size;
|
||||||
? MSPRO_CMD_READ_DATA
|
|
||||||
: MSPRO_CMD_WRITE_DATA;
|
|
||||||
|
|
||||||
dev_dbg(&card->dev, "data transfer: cmd %x, "
|
param.system = msb->system;
|
||||||
"lba %x, count %x\n", msb->transfer_cmd,
|
param.data_count = cpu_to_be16(count);
|
||||||
be32_to_cpu(param.data_address),
|
param.data_address = cpu_to_be32((uint32_t)t_sec);
|
||||||
page_count);
|
param.tpc_param = 0;
|
||||||
|
|
||||||
card->next_request = h_mspro_block_req_init;
|
msb->data_dir = rq_data_dir(msb->block_req);
|
||||||
msb->mrq_handler = h_mspro_block_transfer_data;
|
msb->transfer_cmd = msb->data_dir == READ
|
||||||
memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
|
? MSPRO_CMD_READ_DATA
|
||||||
¶m, sizeof(param));
|
: MSPRO_CMD_WRITE_DATA;
|
||||||
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)) {
|
dev_dbg(&card->dev, "data transfer: cmd %x, "
|
||||||
for (cnt = 0; cnt < msb->current_seg; cnt++)
|
"lba %x, count %x\n", msb->transfer_cmd,
|
||||||
page_count += msb->req_sg[cnt].length
|
be32_to_cpu(param.data_address), count);
|
||||||
/ msb->page_size;
|
|
||||||
|
|
||||||
if (msb->current_page)
|
card->next_request = h_mspro_block_req_init;
|
||||||
page_count += msb->current_page - 1;
|
msb->mrq_handler = h_mspro_block_transfer_data;
|
||||||
|
memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
|
||||||
|
¶m, sizeof(param));
|
||||||
|
memstick_new_req(card->host);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (page_count && (msb->data_dir == READ))
|
dev_dbg(&card->dev, "elv_next\n");
|
||||||
rc = msb->page_size * page_count;
|
msb->block_req = elv_next_request(msb->queue);
|
||||||
else
|
if (!msb->block_req) {
|
||||||
rc = -EIO;
|
dev_dbg(&card->dev, "issue end\n");
|
||||||
} else
|
return -EAGAIN;
|
||||||
rc = msb->page_size * page_count;
|
}
|
||||||
} else
|
|
||||||
rc = -EFAULT;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&msb->q_lock, flags);
|
dev_dbg(&card->dev, "trying again\n");
|
||||||
if (rc >= 0)
|
chunk = 1;
|
||||||
chunk = __blk_end_request(req, 0, rc);
|
goto try_again;
|
||||||
else
|
|
||||||
chunk = __blk_end_request(req, rc, 0);
|
|
||||||
|
|
||||||
dev_dbg(&card->dev, "end chunk %d, %d\n", rc, chunk);
|
|
||||||
spin_unlock_irqrestore(&msb->q_lock, flags);
|
|
||||||
} while (chunk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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 = 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) {
|
|
||||||
mutex_lock(&host->lock);
|
|
||||||
mspro_block_process_request(card, req);
|
|
||||||
mutex_unlock(&host->lock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dev_dbg(&card->dev, "thread finished\n");
|
|
||||||
return 0;
|
req->cmd_flags |= REQ_DONTPREP;
|
||||||
|
|
||||||
|
return BLKPREP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ out_free:
|
||||||
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)
|
||||||
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)
|
||||||
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 {
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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 {
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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) {
|
||||||
|
|
Loading…
Reference in New Issue