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 | |
| 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>
| -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 b11b2b89ae2..57b42bfc7d2 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); |
