aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2016-01-23 04:05:05 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2016-03-11 00:48:14 -0500
commit71e7ae8e1fb2102bb373e6507c3f6540ead999f0 (patch)
tree18d10db1ceeaf616833b74704e0da3b237a447ed
parent5f27edad953cfde6339f17ce461f57bc7060dc4f (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.c97
-rw-r--r--drivers/usb/gadget/function/tcm.h2
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
1076static 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
1096static void usbg_release_cmd(struct se_cmd *);
1097
1076static int usbg_submit_command(struct f_uas *fu, 1098static 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;
1150err: 1171err:
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;
1242err:
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
1301static int usbg_shutdown_session(struct se_session *se_sess) 1318static 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
26struct tcm_usbg_nexus { 28struct tcm_usbg_nexus {
27 struct se_session *tvn_se_sess; 29 struct se_session *tvn_se_sess;
28}; 30};