diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2016-01-23 04:05:05 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2016-03-11 00:48:14 -0500 |
commit | 71e7ae8e1fb2102bb373e6507c3f6540ead999f0 (patch) | |
tree | 18d10db1ceeaf616833b74704e0da3b237a447ed | |
parent | 5f27edad953cfde6339f17ce461f57bc7060dc4f (diff) |
usb-gadget/tcm: Conversion to percpu_ida tag pre-allocation
This patch converts usb-gadget target to use percpu_ida tag
pre-allocation for struct usbg_cmd descriptor, in order to
avoid fast-path struct usbg_cmd memory allocations.
Note by default this is currently hardcoded to 128.
Tested-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Felipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/usb/gadget/function/f_tcm.c | 97 | ||||
-rw-r--r-- | drivers/usb/gadget/function/tcm.h | 2 |
2 files changed, 60 insertions, 39 deletions
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index e803724c7ee3..cd2ef373cbfc 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c | |||
@@ -1073,39 +1073,66 @@ out: | |||
1073 | usbg_cleanup_cmd(cmd); | 1073 | usbg_cleanup_cmd(cmd); |
1074 | } | 1074 | } |
1075 | 1075 | ||
1076 | static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu, | ||
1077 | struct tcm_usbg_nexus *tv_nexus, u32 scsi_tag) | ||
1078 | { | ||
1079 | struct se_session *se_sess = tv_nexus->tvn_se_sess; | ||
1080 | struct usbg_cmd *cmd; | ||
1081 | int tag; | ||
1082 | |||
1083 | tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC); | ||
1084 | if (tag < 0) | ||
1085 | return ERR_PTR(-ENOMEM); | ||
1086 | |||
1087 | cmd = &((struct usbg_cmd *)se_sess->sess_cmd_map)[tag]; | ||
1088 | memset(cmd, 0, sizeof(*cmd)); | ||
1089 | cmd->se_cmd.map_tag = tag; | ||
1090 | cmd->se_cmd.tag = cmd->tag = scsi_tag; | ||
1091 | cmd->fu = fu; | ||
1092 | |||
1093 | return cmd; | ||
1094 | } | ||
1095 | |||
1096 | static void usbg_release_cmd(struct se_cmd *); | ||
1097 | |||
1076 | static int usbg_submit_command(struct f_uas *fu, | 1098 | static int usbg_submit_command(struct f_uas *fu, |
1077 | void *cmdbuf, unsigned int len) | 1099 | void *cmdbuf, unsigned int len) |
1078 | { | 1100 | { |
1079 | struct command_iu *cmd_iu = cmdbuf; | 1101 | struct command_iu *cmd_iu = cmdbuf; |
1080 | struct usbg_cmd *cmd; | 1102 | struct usbg_cmd *cmd; |
1081 | struct usbg_tpg *tpg; | 1103 | struct usbg_tpg *tpg = fu->tpg; |
1082 | struct tcm_usbg_nexus *tv_nexus; | 1104 | struct tcm_usbg_nexus *tv_nexus = tpg->tpg_nexus; |
1083 | u32 cmd_len; | 1105 | u32 cmd_len; |
1106 | u16 scsi_tag; | ||
1084 | 1107 | ||
1085 | if (cmd_iu->iu_id != IU_ID_COMMAND) { | 1108 | if (cmd_iu->iu_id != IU_ID_COMMAND) { |
1086 | pr_err("Unsupported type %d\n", cmd_iu->iu_id); | 1109 | pr_err("Unsupported type %d\n", cmd_iu->iu_id); |
1087 | return -EINVAL; | 1110 | return -EINVAL; |
1088 | } | 1111 | } |
1089 | 1112 | ||
1090 | cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); | 1113 | tv_nexus = tpg->tpg_nexus; |
1091 | if (!cmd) | 1114 | if (!tv_nexus) { |
1092 | return -ENOMEM; | 1115 | pr_err("Missing nexus, ignoring command\n"); |
1116 | return -EINVAL; | ||
1117 | } | ||
1093 | 1118 | ||
1094 | cmd->fu = fu; | 1119 | cmd_len = (cmd_iu->len & ~0x3) + 16; |
1120 | if (cmd_len > USBG_MAX_CMD) | ||
1121 | return -EINVAL; | ||
1122 | |||
1123 | scsi_tag = be16_to_cpup(&cmd_iu->tag); | ||
1124 | cmd = usbg_get_cmd(fu, tv_nexus, scsi_tag); | ||
1125 | if (IS_ERR(cmd)) { | ||
1126 | pr_err("usbg_get_cmd failed\n"); | ||
1127 | return -ENOMEM; | ||
1128 | } | ||
1095 | 1129 | ||
1096 | /* XXX until I figure out why I can't free in on complete */ | 1130 | /* XXX until I figure out why I can't free in on complete */ |
1097 | kref_init(&cmd->ref); | 1131 | kref_init(&cmd->ref); |
1098 | kref_get(&cmd->ref); | 1132 | kref_get(&cmd->ref); |
1099 | 1133 | ||
1100 | tpg = fu->tpg; | ||
1101 | cmd_len = (cmd_iu->len & ~0x3) + 16; | ||
1102 | if (cmd_len > USBG_MAX_CMD) | ||
1103 | goto err; | ||
1104 | |||
1105 | memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len); | 1134 | memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len); |
1106 | 1135 | ||
1107 | cmd->tag = be16_to_cpup(&cmd_iu->tag); | ||
1108 | cmd->se_cmd.tag = cmd->tag; | ||
1109 | if (fu->flags & USBG_USE_STREAMS) { | 1136 | if (fu->flags & USBG_USE_STREAMS) { |
1110 | if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS) | 1137 | if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS) |
1111 | goto err; | 1138 | goto err; |
@@ -1117,12 +1144,6 @@ static int usbg_submit_command(struct f_uas *fu, | |||
1117 | cmd->stream = &fu->stream[0]; | 1144 | cmd->stream = &fu->stream[0]; |
1118 | } | 1145 | } |
1119 | 1146 | ||
1120 | tv_nexus = tpg->tpg_nexus; | ||
1121 | if (!tv_nexus) { | ||
1122 | pr_err("Missing nexus, ignoring command\n"); | ||
1123 | goto err; | ||
1124 | } | ||
1125 | |||
1126 | switch (cmd_iu->prio_attr & 0x7) { | 1147 | switch (cmd_iu->prio_attr & 0x7) { |
1127 | case UAS_HEAD_TAG: | 1148 | case UAS_HEAD_TAG: |
1128 | cmd->prio_attr = TCM_HEAD_TAG; | 1149 | cmd->prio_attr = TCM_HEAD_TAG; |
@@ -1148,7 +1169,7 @@ static int usbg_submit_command(struct f_uas *fu, | |||
1148 | 1169 | ||
1149 | return 0; | 1170 | return 0; |
1150 | err: | 1171 | err: |
1151 | kfree(cmd); | 1172 | usbg_release_cmd(&cmd->se_cmd); |
1152 | return -EINVAL; | 1173 | return -EINVAL; |
1153 | } | 1174 | } |
1154 | 1175 | ||
@@ -1190,7 +1211,7 @@ static int bot_submit_command(struct f_uas *fu, | |||
1190 | { | 1211 | { |
1191 | struct bulk_cb_wrap *cbw = cmdbuf; | 1212 | struct bulk_cb_wrap *cbw = cmdbuf; |
1192 | struct usbg_cmd *cmd; | 1213 | struct usbg_cmd *cmd; |
1193 | struct usbg_tpg *tpg; | 1214 | struct usbg_tpg *tpg = fu->tpg; |
1194 | struct tcm_usbg_nexus *tv_nexus; | 1215 | struct tcm_usbg_nexus *tv_nexus; |
1195 | u32 cmd_len; | 1216 | u32 cmd_len; |
1196 | 1217 | ||
@@ -1207,28 +1228,25 @@ static int bot_submit_command(struct f_uas *fu, | |||
1207 | if (cmd_len < 1 || cmd_len > 16) | 1228 | if (cmd_len < 1 || cmd_len > 16) |
1208 | return -EINVAL; | 1229 | return -EINVAL; |
1209 | 1230 | ||
1210 | cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); | 1231 | tv_nexus = tpg->tpg_nexus; |
1211 | if (!cmd) | 1232 | if (!tv_nexus) { |
1212 | return -ENOMEM; | 1233 | pr_err("Missing nexus, ignoring command\n"); |
1234 | return -ENODEV; | ||
1235 | } | ||
1213 | 1236 | ||
1214 | cmd->fu = fu; | 1237 | cmd = usbg_get_cmd(fu, tv_nexus, cbw->Tag); |
1238 | if (IS_ERR(cmd)) { | ||
1239 | pr_err("usbg_get_cmd failed\n"); | ||
1240 | return -ENOMEM; | ||
1241 | } | ||
1215 | 1242 | ||
1216 | /* XXX until I figure out why I can't free in on complete */ | 1243 | /* XXX until I figure out why I can't free in on complete */ |
1217 | kref_init(&cmd->ref); | 1244 | kref_init(&cmd->ref); |
1218 | kref_get(&cmd->ref); | 1245 | kref_get(&cmd->ref); |
1219 | 1246 | ||
1220 | tpg = fu->tpg; | ||
1221 | |||
1222 | memcpy(cmd->cmd_buf, cbw->CDB, cmd_len); | 1247 | memcpy(cmd->cmd_buf, cbw->CDB, cmd_len); |
1223 | 1248 | ||
1224 | cmd->bot_tag = cbw->Tag; | 1249 | cmd->bot_tag = cbw->Tag; |
1225 | |||
1226 | tv_nexus = tpg->tpg_nexus; | ||
1227 | if (!tv_nexus) { | ||
1228 | pr_err("Missing nexus, ignoring command\n"); | ||
1229 | goto err; | ||
1230 | } | ||
1231 | |||
1232 | cmd->prio_attr = TCM_SIMPLE_TAG; | 1250 | cmd->prio_attr = TCM_SIMPLE_TAG; |
1233 | cmd->unpacked_lun = cbw->Lun; | 1251 | cmd->unpacked_lun = cbw->Lun; |
1234 | cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0; | 1252 | cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0; |
@@ -1239,9 +1257,6 @@ static int bot_submit_command(struct f_uas *fu, | |||
1239 | queue_work(tpg->workqueue, &cmd->work); | 1257 | queue_work(tpg->workqueue, &cmd->work); |
1240 | 1258 | ||
1241 | return 0; | 1259 | return 0; |
1242 | err: | ||
1243 | kfree(cmd); | ||
1244 | return -EINVAL; | ||
1245 | } | 1260 | } |
1246 | 1261 | ||
1247 | /* Start fabric.c code */ | 1262 | /* Start fabric.c code */ |
@@ -1294,8 +1309,10 @@ static void usbg_release_cmd(struct se_cmd *se_cmd) | |||
1294 | { | 1309 | { |
1295 | struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, | 1310 | struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, |
1296 | se_cmd); | 1311 | se_cmd); |
1312 | struct se_session *se_sess = se_cmd->se_sess; | ||
1313 | |||
1297 | kfree(cmd->data_buf); | 1314 | kfree(cmd->data_buf); |
1298 | kfree(cmd); | 1315 | percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); |
1299 | } | 1316 | } |
1300 | 1317 | ||
1301 | static int usbg_shutdown_session(struct se_session *se_sess) | 1318 | static int usbg_shutdown_session(struct se_session *se_sess) |
@@ -1607,7 +1624,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) | |||
1607 | goto out_unlock; | 1624 | goto out_unlock; |
1608 | } | 1625 | } |
1609 | 1626 | ||
1610 | tv_nexus->tvn_se_sess = target_alloc_session(&tpg->se_tpg, 0, 0, | 1627 | tv_nexus->tvn_se_sess = target_alloc_session(&tpg->se_tpg, |
1628 | USB_G_DEFAULT_SESSION_TAGS, | ||
1629 | sizeof(struct usbg_cmd), | ||
1611 | TARGET_PROT_NORMAL, name, | 1630 | TARGET_PROT_NORMAL, name, |
1612 | tv_nexus, usbg_alloc_sess_cb); | 1631 | tv_nexus, usbg_alloc_sess_cb); |
1613 | if (IS_ERR(tv_nexus->tvn_se_sess)) { | 1632 | if (IS_ERR(tv_nexus->tvn_se_sess)) { |
diff --git a/drivers/usb/gadget/function/tcm.h b/drivers/usb/gadget/function/tcm.h index b75c6f3e1980..a27e6e34db0b 100644 --- a/drivers/usb/gadget/function/tcm.h +++ b/drivers/usb/gadget/function/tcm.h | |||
@@ -23,6 +23,8 @@ enum { | |||
23 | #define USB_G_ALT_INT_BBB 0 | 23 | #define USB_G_ALT_INT_BBB 0 |
24 | #define USB_G_ALT_INT_UAS 1 | 24 | #define USB_G_ALT_INT_UAS 1 |
25 | 25 | ||
26 | #define USB_G_DEFAULT_SESSION_TAGS 128 | ||
27 | |||
26 | struct tcm_usbg_nexus { | 28 | struct tcm_usbg_nexus { |
27 | struct se_session *tvn_se_sess; | 29 | struct se_session *tvn_se_sess; |
28 | }; | 30 | }; |