diff options
author | Alex Dubov <oakad@yahoo.com> | 2011-01-12 20:01:05 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 11:03:22 -0500 |
commit | 496fc1a68a45ae159d26331775411f6fea36d4d3 (patch) | |
tree | c93203cad7f470c7f1b4bac49582d3c150e2e5f6 /drivers | |
parent | edb50b3b1d9bf6d51dc68f7f885e78285f8d6f18 (diff) |
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: Alex Dubov <oakad@yahoo.com>
Reported-by: Maxim Levitsky <maximlevitsky@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/memstick/core/mspro_block.c | 136 |
1 files changed, 74 insertions, 62 deletions
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index b11b2b89ae22..57b42bfc7d23 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c | |||
@@ -159,6 +159,13 @@ struct mspro_block_data { | |||
159 | int (*mrq_handler)(struct memstick_dev *card, | 159 | int (*mrq_handler)(struct memstick_dev *card, |
160 | struct memstick_request **mrq); | 160 | struct memstick_request **mrq); |
161 | 161 | ||
162 | |||
163 | /* Default request setup function for data access method preferred by | ||
164 | * this host instance. | ||
165 | */ | ||
166 | void (*setup_transfer)(struct memstick_dev *card, | ||
167 | u64 offset, size_t length); | ||
168 | |||
162 | struct attribute_group attr_group; | 169 | struct attribute_group attr_group; |
163 | 170 | ||
164 | struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; | 171 | struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; |
@@ -656,14 +663,43 @@ has_int_reg: | |||
656 | } | 663 | } |
657 | } | 664 | } |
658 | 665 | ||
666 | /*** Transfer setup functions for different access methods. ***/ | ||
667 | |||
668 | /** Setup data transfer request for SET_CMD TPC with arguments in card | ||
669 | * registers. | ||
670 | * | ||
671 | * @card Current media instance | ||
672 | * @offset Target data offset in bytes | ||
673 | * @length Required transfer length in bytes. | ||
674 | */ | ||
675 | static void h_mspro_block_setup_cmd(struct memstick_dev *card, u64 offset, | ||
676 | size_t length) | ||
677 | { | ||
678 | struct mspro_block_data *msb = memstick_get_drvdata(card); | ||
679 | struct mspro_param_register param = { | ||
680 | .system = msb->system, | ||
681 | .data_count = cpu_to_be16((uint16_t)(length / msb->page_size)), | ||
682 | /* ISO C90 warning precludes direct initialization for now. */ | ||
683 | .data_address = 0, | ||
684 | .tpc_param = 0 | ||
685 | }; | ||
686 | |||
687 | do_div(offset, msb->page_size); | ||
688 | param.data_address = cpu_to_be32((uint32_t)offset); | ||
689 | |||
690 | card->next_request = h_mspro_block_req_init; | ||
691 | msb->mrq_handler = h_mspro_block_transfer_data; | ||
692 | memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, | ||
693 | ¶m, sizeof(param)); | ||
694 | } | ||
695 | |||
659 | /*** Data transfer ***/ | 696 | /*** Data transfer ***/ |
660 | 697 | ||
661 | static int mspro_block_issue_req(struct memstick_dev *card, int chunk) | 698 | static int mspro_block_issue_req(struct memstick_dev *card, int chunk) |
662 | { | 699 | { |
663 | struct mspro_block_data *msb = memstick_get_drvdata(card); | 700 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
664 | sector_t t_sec; | 701 | u64 t_off; |
665 | unsigned int count; | 702 | unsigned int count; |
666 | struct mspro_param_register param; | ||
667 | 703 | ||
668 | try_again: | 704 | try_again: |
669 | while (chunk) { | 705 | while (chunk) { |
@@ -678,30 +714,17 @@ try_again: | |||
678 | continue; | 714 | continue; |
679 | } | 715 | } |
680 | 716 | ||
681 | t_sec = blk_rq_pos(msb->block_req) << 9; | 717 | t_off = blk_rq_pos(msb->block_req); |
682 | sector_div(t_sec, msb->page_size); | 718 | t_off <<= 9; |
683 | |||
684 | count = blk_rq_bytes(msb->block_req); | 719 | count = blk_rq_bytes(msb->block_req); |
685 | count /= msb->page_size; | ||
686 | 720 | ||
687 | param.system = msb->system; | 721 | msb->setup_transfer(card, t_off, count); |
688 | param.data_count = cpu_to_be16(count); | ||
689 | param.data_address = cpu_to_be32((uint32_t)t_sec); | ||
690 | param.tpc_param = 0; | ||
691 | 722 | ||
692 | msb->data_dir = rq_data_dir(msb->block_req); | 723 | msb->data_dir = rq_data_dir(msb->block_req); |
693 | msb->transfer_cmd = msb->data_dir == READ | 724 | msb->transfer_cmd = msb->data_dir == READ |
694 | ? MSPRO_CMD_READ_DATA | 725 | ? MSPRO_CMD_READ_DATA |
695 | : MSPRO_CMD_WRITE_DATA; | 726 | : MSPRO_CMD_WRITE_DATA; |
696 | 727 | ||
697 | dev_dbg(&card->dev, "data transfer: cmd %x, " | ||
698 | "lba %x, count %x\n", msb->transfer_cmd, | ||
699 | be32_to_cpu(param.data_address), count); | ||
700 | |||
701 | card->next_request = h_mspro_block_req_init; | ||
702 | msb->mrq_handler = h_mspro_block_transfer_data; | ||
703 | memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, | ||
704 | ¶m, sizeof(param)); | ||
705 | memstick_new_req(card->host); | 728 | memstick_new_req(card->host); |
706 | return 0; | 729 | return 0; |
707 | } | 730 | } |
@@ -956,18 +979,16 @@ try_again: | |||
956 | static int mspro_block_read_attributes(struct memstick_dev *card) | 979 | static int mspro_block_read_attributes(struct memstick_dev *card) |
957 | { | 980 | { |
958 | struct mspro_block_data *msb = memstick_get_drvdata(card); | 981 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
959 | struct mspro_param_register param = { | ||
960 | .system = msb->system, | ||
961 | .data_count = cpu_to_be16(1), | ||
962 | .data_address = 0, | ||
963 | .tpc_param = 0 | ||
964 | }; | ||
965 | struct mspro_attribute *attr = NULL; | 982 | struct mspro_attribute *attr = NULL; |
966 | struct mspro_sys_attr *s_attr = NULL; | 983 | struct mspro_sys_attr *s_attr = NULL; |
967 | unsigned char *buffer = NULL; | 984 | unsigned char *buffer = NULL; |
968 | int cnt, rc, attr_count; | 985 | int cnt, rc, attr_count; |
969 | unsigned int addr; | 986 | /* While normally physical device offsets, represented here by |
970 | unsigned short page_count; | 987 | * attr_offset and attr_len will be of large numeric types, we can be |
988 | * sure, that attributes are close enough to the beginning of the | ||
989 | * device, to save ourselves some trouble. | ||
990 | */ | ||
991 | unsigned int addr, attr_offset = 0, attr_len = msb->page_size; | ||
971 | 992 | ||
972 | attr = kmalloc(msb->page_size, GFP_KERNEL); | 993 | attr = kmalloc(msb->page_size, GFP_KERNEL); |
973 | if (!attr) | 994 | if (!attr) |
@@ -980,10 +1001,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) | |||
980 | msb->data_dir = READ; | 1001 | msb->data_dir = READ; |
981 | msb->transfer_cmd = MSPRO_CMD_READ_ATRB; | 1002 | msb->transfer_cmd = MSPRO_CMD_READ_ATRB; |
982 | 1003 | ||
983 | card->next_request = h_mspro_block_req_init; | 1004 | msb->setup_transfer(card, attr_offset, attr_len); |
984 | msb->mrq_handler = h_mspro_block_transfer_data; | 1005 | |
985 | memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, | ||
986 | sizeof(param)); | ||
987 | memstick_new_req(card->host); | 1006 | memstick_new_req(card->host); |
988 | wait_for_completion(&card->mrq_complete); | 1007 | wait_for_completion(&card->mrq_complete); |
989 | if (card->current_mrq.error) { | 1008 | if (card->current_mrq.error) { |
@@ -1014,13 +1033,12 @@ static int mspro_block_read_attributes(struct memstick_dev *card) | |||
1014 | } | 1033 | } |
1015 | msb->attr_group.name = "media_attributes"; | 1034 | msb->attr_group.name = "media_attributes"; |
1016 | 1035 | ||
1017 | buffer = kmalloc(msb->page_size, GFP_KERNEL); | 1036 | buffer = kmalloc(attr_len, GFP_KERNEL); |
1018 | if (!buffer) { | 1037 | if (!buffer) { |
1019 | rc = -ENOMEM; | 1038 | rc = -ENOMEM; |
1020 | goto out_free_attr; | 1039 | goto out_free_attr; |
1021 | } | 1040 | } |
1022 | memcpy(buffer, (char *)attr, msb->page_size); | 1041 | memcpy(buffer, (char *)attr, attr_len); |
1023 | page_count = 1; | ||
1024 | 1042 | ||
1025 | for (cnt = 0; cnt < attr_count; ++cnt) { | 1043 | for (cnt = 0; cnt < attr_count; ++cnt) { |
1026 | s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL); | 1044 | 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 | 1049 | ||
1032 | msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; | 1050 | msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; |
1033 | addr = be32_to_cpu(attr->entries[cnt].address); | 1051 | addr = be32_to_cpu(attr->entries[cnt].address); |
1034 | rc = be32_to_cpu(attr->entries[cnt].size); | 1052 | s_attr->size = be32_to_cpu(attr->entries[cnt].size); |
1035 | dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " | 1053 | dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " |
1036 | "size %x\n", cnt, attr->entries[cnt].id, addr, rc); | 1054 | "size %zx\n", cnt, attr->entries[cnt].id, addr, |
1055 | s_attr->size); | ||
1037 | s_attr->id = attr->entries[cnt].id; | 1056 | s_attr->id = attr->entries[cnt].id; |
1038 | if (mspro_block_attr_name(s_attr->id)) | 1057 | if (mspro_block_attr_name(s_attr->id)) |
1039 | snprintf(s_attr->name, sizeof(s_attr->name), "%s", | 1058 | snprintf(s_attr->name, sizeof(s_attr->name), "%s", |
@@ -1047,57 +1066,47 @@ static int mspro_block_read_attributes(struct memstick_dev *card) | |||
1047 | s_attr->dev_attr.attr.mode = S_IRUGO; | 1066 | s_attr->dev_attr.attr.mode = S_IRUGO; |
1048 | s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); | 1067 | s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); |
1049 | 1068 | ||
1050 | if (!rc) | 1069 | if (!s_attr->size) |
1051 | continue; | 1070 | continue; |
1052 | 1071 | ||
1053 | s_attr->size = rc; | 1072 | s_attr->data = kmalloc(s_attr->size, GFP_KERNEL); |
1054 | s_attr->data = kmalloc(rc, GFP_KERNEL); | ||
1055 | if (!s_attr->data) { | 1073 | if (!s_attr->data) { |
1056 | rc = -ENOMEM; | 1074 | rc = -ENOMEM; |
1057 | goto out_free_buffer; | 1075 | goto out_free_buffer; |
1058 | } | 1076 | } |
1059 | 1077 | ||
1060 | if (((addr / msb->page_size) | 1078 | if (((addr / msb->page_size) == (attr_offset / msb->page_size)) |
1061 | == be32_to_cpu(param.data_address)) | 1079 | && (((addr + s_attr->size - 1) / msb->page_size) |
1062 | && (((addr + rc - 1) / msb->page_size) | 1080 | == (attr_offset / msb->page_size))) { |
1063 | == be32_to_cpu(param.data_address))) { | ||
1064 | memcpy(s_attr->data, buffer + addr % msb->page_size, | 1081 | memcpy(s_attr->data, buffer + addr % msb->page_size, |
1065 | rc); | 1082 | s_attr->size); |
1066 | continue; | 1083 | continue; |
1067 | } | 1084 | } |
1068 | 1085 | ||
1069 | if (page_count <= (rc / msb->page_size)) { | 1086 | attr_offset = (addr / msb->page_size) * msb->page_size; |
1087 | |||
1088 | if ((attr_offset + attr_len) < (addr + s_attr->size)) { | ||
1070 | kfree(buffer); | 1089 | kfree(buffer); |
1071 | page_count = (rc / msb->page_size) + 1; | 1090 | attr_len = (((addr + s_attr->size) / msb->page_size) |
1072 | buffer = kmalloc(page_count * msb->page_size, | 1091 | + 1 ) * msb->page_size - attr_offset; |
1073 | GFP_KERNEL); | 1092 | buffer = kmalloc(attr_len, GFP_KERNEL); |
1074 | if (!buffer) { | 1093 | if (!buffer) { |
1075 | rc = -ENOMEM; | 1094 | rc = -ENOMEM; |
1076 | goto out_free_attr; | 1095 | goto out_free_attr; |
1077 | } | 1096 | } |
1078 | } | 1097 | } |
1079 | 1098 | ||
1080 | param.system = msb->system; | 1099 | sg_init_one(&msb->req_sg[0], buffer, attr_len); |
1081 | param.data_count = cpu_to_be16((rc / msb->page_size) + 1); | ||
1082 | param.data_address = cpu_to_be32(addr / msb->page_size); | ||
1083 | param.tpc_param = 0; | ||
1084 | |||
1085 | sg_init_one(&msb->req_sg[0], buffer, | ||
1086 | be16_to_cpu(param.data_count) * msb->page_size); | ||
1087 | msb->seg_count = 1; | 1100 | msb->seg_count = 1; |
1088 | msb->current_seg = 0; | 1101 | msb->current_seg = 0; |
1089 | msb->current_page = 0; | 1102 | msb->current_page = 0; |
1090 | msb->data_dir = READ; | 1103 | msb->data_dir = READ; |
1091 | msb->transfer_cmd = MSPRO_CMD_READ_ATRB; | 1104 | msb->transfer_cmd = MSPRO_CMD_READ_ATRB; |
1092 | 1105 | ||
1093 | dev_dbg(&card->dev, "reading attribute pages %x, %x\n", | 1106 | dev_dbg(&card->dev, "reading attribute range %x, %x\n", |
1094 | be32_to_cpu(param.data_address), | 1107 | attr_offset, attr_len); |
1095 | be16_to_cpu(param.data_count)); | ||
1096 | 1108 | ||
1097 | card->next_request = h_mspro_block_req_init; | 1109 | msb->setup_transfer(card, attr_offset, attr_len); |
1098 | msb->mrq_handler = h_mspro_block_transfer_data; | ||
1099 | memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, | ||
1100 | (char *)¶m, sizeof(param)); | ||
1101 | memstick_new_req(card->host); | 1110 | memstick_new_req(card->host); |
1102 | wait_for_completion(&card->mrq_complete); | 1111 | wait_for_completion(&card->mrq_complete); |
1103 | if (card->current_mrq.error) { | 1112 | if (card->current_mrq.error) { |
@@ -1105,7 +1114,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) | |||
1105 | goto out_free_buffer; | 1114 | goto out_free_buffer; |
1106 | } | 1115 | } |
1107 | 1116 | ||
1108 | memcpy(s_attr->data, buffer + addr % msb->page_size, rc); | 1117 | memcpy(s_attr->data, buffer + addr % msb->page_size, |
1118 | s_attr->size); | ||
1109 | } | 1119 | } |
1110 | 1120 | ||
1111 | rc = 0; | 1121 | rc = 0; |
@@ -1123,6 +1133,8 @@ static int mspro_block_init_card(struct memstick_dev *card) | |||
1123 | int rc = 0; | 1133 | int rc = 0; |
1124 | 1134 | ||
1125 | msb->system = MEMSTICK_SYS_SERIAL; | 1135 | msb->system = MEMSTICK_SYS_SERIAL; |
1136 | msb->setup_transfer = h_mspro_block_setup_cmd; | ||
1137 | |||
1126 | card->reg_addr.r_offset = offsetof(struct mspro_register, status); | 1138 | card->reg_addr.r_offset = offsetof(struct mspro_register, status); |
1127 | card->reg_addr.r_length = sizeof(struct ms_status_register); | 1139 | card->reg_addr.r_length = sizeof(struct ms_status_register); |
1128 | card->reg_addr.w_offset = offsetof(struct mspro_register, param); | 1140 | card->reg_addr.w_offset = offsetof(struct mspro_register, param); |