Commit 496fc1a6 authored by Alex Dubov's avatar Alex Dubov Committed by Linus Torvalds

memstick: factor out transfer initiating functionality in mspro_block.c

Apart from currently used standard memstick data transfer method, Sony
introduced several newer ones, to uncover full bandwidth/capacity of its
Pro, HG and XC media formats. This patch lays a foundation to enable
those methods as made possible by host/media capabilities.

As a side effect of this patch, mspro_block_read_attributes became more
streamlined and readable.

[akpm@linux-foundation.org: fix printk warning]
Signed-off-by: default avatarAlex Dubov <oakad@yahoo.com>
Reported-by: default avatarMaxim Levitsky <maximlevitsky@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent edb50b3b
...@@ -159,6 +159,13 @@ struct mspro_block_data { ...@@ -159,6 +159,13 @@ struct mspro_block_data {
int (*mrq_handler)(struct memstick_dev *card, int (*mrq_handler)(struct memstick_dev *card,
struct memstick_request **mrq); struct memstick_request **mrq);
/* Default request setup function for data access method preferred by
* this host instance.
*/
void (*setup_transfer)(struct memstick_dev *card,
u64 offset, size_t length);
struct attribute_group attr_group; struct attribute_group attr_group;
struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS];
...@@ -656,14 +663,43 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card, ...@@ -656,14 +663,43 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card,
} }
} }
/*** Transfer setup functions for different access methods. ***/
/** Setup data transfer request for SET_CMD TPC with arguments in card
* registers.
*
* @card Current media instance
* @offset Target data offset in bytes
* @length Required transfer length in bytes.
*/
static void h_mspro_block_setup_cmd(struct memstick_dev *card, u64 offset,
size_t length)
{
struct mspro_block_data *msb = memstick_get_drvdata(card);
struct mspro_param_register param = {
.system = msb->system,
.data_count = cpu_to_be16((uint16_t)(length / msb->page_size)),
/* ISO C90 warning precludes direct initialization for now. */
.data_address = 0,
.tpc_param = 0
};
do_div(offset, msb->page_size);
param.data_address = cpu_to_be32((uint32_t)offset);
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));
}
/*** Data transfer ***/ /*** Data transfer ***/
static int mspro_block_issue_req(struct memstick_dev *card, int chunk) static int mspro_block_issue_req(struct memstick_dev *card, int chunk)
{ {
struct mspro_block_data *msb = memstick_get_drvdata(card); struct mspro_block_data *msb = memstick_get_drvdata(card);
sector_t t_sec; u64 t_off;
unsigned int count; unsigned int count;
struct mspro_param_register param;
try_again: try_again:
while (chunk) { while (chunk) {
...@@ -678,30 +714,17 @@ static int mspro_block_issue_req(struct memstick_dev *card, int chunk) ...@@ -678,30 +714,17 @@ static int mspro_block_issue_req(struct memstick_dev *card, int chunk)
continue; continue;
} }
t_sec = blk_rq_pos(msb->block_req) << 9; t_off = blk_rq_pos(msb->block_req);
sector_div(t_sec, msb->page_size); t_off <<= 9;
count = blk_rq_bytes(msb->block_req); count = blk_rq_bytes(msb->block_req);
count /= msb->page_size;
param.system = msb->system; msb->setup_transfer(card, t_off, count);
param.data_count = cpu_to_be16(count);
param.data_address = cpu_to_be32((uint32_t)t_sec);
param.tpc_param = 0;
msb->data_dir = rq_data_dir(msb->block_req); msb->data_dir = rq_data_dir(msb->block_req);
msb->transfer_cmd = msb->data_dir == READ msb->transfer_cmd = msb->data_dir == READ
? MSPRO_CMD_READ_DATA ? MSPRO_CMD_READ_DATA
: MSPRO_CMD_WRITE_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); memstick_new_req(card->host);
return 0; return 0;
} }
...@@ -956,18 +979,16 @@ static int mspro_block_switch_interface(struct memstick_dev *card) ...@@ -956,18 +979,16 @@ static int mspro_block_switch_interface(struct memstick_dev *card)
static int mspro_block_read_attributes(struct memstick_dev *card) static int mspro_block_read_attributes(struct memstick_dev *card)
{ {
struct mspro_block_data *msb = memstick_get_drvdata(card); struct mspro_block_data *msb = memstick_get_drvdata(card);
struct mspro_param_register param = {
.system = msb->system,
.data_count = cpu_to_be16(1),
.data_address = 0,
.tpc_param = 0
};
struct mspro_attribute *attr = NULL; struct mspro_attribute *attr = NULL;
struct mspro_sys_attr *s_attr = NULL; struct mspro_sys_attr *s_attr = NULL;
unsigned char *buffer = NULL; unsigned char *buffer = NULL;
int cnt, rc, attr_count; int cnt, rc, attr_count;
unsigned int addr; /* While normally physical device offsets, represented here by
unsigned short page_count; * attr_offset and attr_len will be of large numeric types, we can be
* sure, that attributes are close enough to the beginning of the
* device, to save ourselves some trouble.
*/
unsigned int addr, attr_offset = 0, attr_len = msb->page_size;
attr = kmalloc(msb->page_size, GFP_KERNEL); attr = kmalloc(msb->page_size, GFP_KERNEL);
if (!attr) if (!attr)
...@@ -980,10 +1001,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) ...@@ -980,10 +1001,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
msb->data_dir = READ; msb->data_dir = READ;
msb->transfer_cmd = MSPRO_CMD_READ_ATRB; msb->transfer_cmd = MSPRO_CMD_READ_ATRB;
card->next_request = h_mspro_block_req_init; msb->setup_transfer(card, attr_offset, attr_len);
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); memstick_new_req(card->host);
wait_for_completion(&card->mrq_complete); wait_for_completion(&card->mrq_complete);
if (card->current_mrq.error) { if (card->current_mrq.error) {
...@@ -1014,13 +1033,12 @@ static int mspro_block_read_attributes(struct memstick_dev *card) ...@@ -1014,13 +1033,12 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
} }
msb->attr_group.name = "media_attributes"; msb->attr_group.name = "media_attributes";
buffer = kmalloc(msb->page_size, GFP_KERNEL); buffer = kmalloc(attr_len, GFP_KERNEL);
if (!buffer) { if (!buffer) {
rc = -ENOMEM; rc = -ENOMEM;
goto out_free_attr; goto out_free_attr;
} }
memcpy(buffer, (char *)attr, msb->page_size); memcpy(buffer, (char *)attr, attr_len);
page_count = 1;
for (cnt = 0; cnt < attr_count; ++cnt) { for (cnt = 0; cnt < attr_count; ++cnt) {
s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL); s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL);
...@@ -1031,9 +1049,10 @@ static int mspro_block_read_attributes(struct memstick_dev *card) ...@@ -1031,9 +1049,10 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr;
addr = be32_to_cpu(attr->entries[cnt].address); addr = be32_to_cpu(attr->entries[cnt].address);
rc = be32_to_cpu(attr->entries[cnt].size); s_attr->size = be32_to_cpu(attr->entries[cnt].size);
dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, "
"size %x\n", cnt, attr->entries[cnt].id, addr, rc); "size %zx\n", cnt, attr->entries[cnt].id, addr,
s_attr->size);
s_attr->id = attr->entries[cnt].id; s_attr->id = attr->entries[cnt].id;
if (mspro_block_attr_name(s_attr->id)) if (mspro_block_attr_name(s_attr->id))
snprintf(s_attr->name, sizeof(s_attr->name), "%s", snprintf(s_attr->name, sizeof(s_attr->name), "%s",
...@@ -1047,57 +1066,47 @@ static int mspro_block_read_attributes(struct memstick_dev *card) ...@@ -1047,57 +1066,47 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
s_attr->dev_attr.attr.mode = S_IRUGO; s_attr->dev_attr.attr.mode = S_IRUGO;
s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id);
if (!rc) if (!s_attr->size)
continue; continue;
s_attr->size = rc; s_attr->data = kmalloc(s_attr->size, GFP_KERNEL);
s_attr->data = kmalloc(rc, GFP_KERNEL);
if (!s_attr->data) { if (!s_attr->data) {
rc = -ENOMEM; rc = -ENOMEM;
goto out_free_buffer; goto out_free_buffer;
} }
if (((addr / msb->page_size) if (((addr / msb->page_size) == (attr_offset / msb->page_size))
== be32_to_cpu(param.data_address)) && (((addr + s_attr->size - 1) / msb->page_size)
&& (((addr + rc - 1) / msb->page_size) == (attr_offset / msb->page_size))) {
== be32_to_cpu(param.data_address))) {
memcpy(s_attr->data, buffer + addr % msb->page_size, memcpy(s_attr->data, buffer + addr % msb->page_size,
rc); s_attr->size);
continue; continue;
} }
if (page_count <= (rc / msb->page_size)) { attr_offset = (addr / msb->page_size) * msb->page_size;
if ((attr_offset + attr_len) < (addr + s_attr->size)) {
kfree(buffer); kfree(buffer);
page_count = (rc / msb->page_size) + 1; attr_len = (((addr + s_attr->size) / msb->page_size)
buffer = kmalloc(page_count * msb->page_size, + 1 ) * msb->page_size - attr_offset;
GFP_KERNEL); buffer = kmalloc(attr_len, GFP_KERNEL);
if (!buffer) { if (!buffer) {
rc = -ENOMEM; rc = -ENOMEM;
goto out_free_attr; goto out_free_attr;
} }
} }
param.system = msb->system; sg_init_one(&msb->req_sg[0], buffer, attr_len);
param.data_count = cpu_to_be16((rc / msb->page_size) + 1);
param.data_address = cpu_to_be32(addr / msb->page_size);
param.tpc_param = 0;
sg_init_one(&msb->req_sg[0], buffer,
be16_to_cpu(param.data_count) * msb->page_size);
msb->seg_count = 1; msb->seg_count = 1;
msb->current_seg = 0; msb->current_seg = 0;
msb->current_page = 0; msb->current_page = 0;
msb->data_dir = READ; msb->data_dir = READ;
msb->transfer_cmd = MSPRO_CMD_READ_ATRB; msb->transfer_cmd = MSPRO_CMD_READ_ATRB;
dev_dbg(&card->dev, "reading attribute pages %x, %x\n", dev_dbg(&card->dev, "reading attribute range %x, %x\n",
be32_to_cpu(param.data_address), attr_offset, attr_len);
be16_to_cpu(param.data_count));
card->next_request = h_mspro_block_req_init; msb->setup_transfer(card, attr_offset, attr_len);
msb->mrq_handler = h_mspro_block_transfer_data;
memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
(char *)&param, sizeof(param));
memstick_new_req(card->host); memstick_new_req(card->host);
wait_for_completion(&card->mrq_complete); wait_for_completion(&card->mrq_complete);
if (card->current_mrq.error) { if (card->current_mrq.error) {
...@@ -1105,7 +1114,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) ...@@ -1105,7 +1114,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
goto out_free_buffer; goto out_free_buffer;
} }
memcpy(s_attr->data, buffer + addr % msb->page_size, rc); memcpy(s_attr->data, buffer + addr % msb->page_size,
s_attr->size);
} }
rc = 0; rc = 0;
...@@ -1123,6 +1133,8 @@ static int mspro_block_init_card(struct memstick_dev *card) ...@@ -1123,6 +1133,8 @@ static int mspro_block_init_card(struct memstick_dev *card)
int rc = 0; int rc = 0;
msb->system = MEMSTICK_SYS_SERIAL; msb->system = MEMSTICK_SYS_SERIAL;
msb->setup_transfer = h_mspro_block_setup_cmd;
card->reg_addr.r_offset = offsetof(struct mspro_register, status); card->reg_addr.r_offset = offsetof(struct mspro_register, status);
card->reg_addr.r_length = sizeof(struct ms_status_register); card->reg_addr.r_length = sizeof(struct ms_status_register);
card->reg_addr.w_offset = offsetof(struct mspro_register, param); card->reg_addr.w_offset = offsetof(struct mspro_register, param);
......
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