Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+60 -39
+58 -39
drivers/usb/gadget/function/f_tcm.c
··· 1073 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 1098 static int usbg_submit_command(struct f_uas *fu, 1077 1099 void *cmdbuf, unsigned int len) 1078 1100 { 1079 1101 struct command_iu *cmd_iu = cmdbuf; 1080 1102 struct usbg_cmd *cmd; 1081 - struct usbg_tpg *tpg; 1082 - struct tcm_usbg_nexus *tv_nexus; 1103 + struct usbg_tpg *tpg = fu->tpg; 1104 + struct tcm_usbg_nexus *tv_nexus = tpg->tpg_nexus; 1083 1105 u32 cmd_len; 1106 + u16 scsi_tag; 1084 1107 1085 1108 if (cmd_iu->iu_id != IU_ID_COMMAND) { 1086 1109 pr_err("Unsupported type %d\n", cmd_iu->iu_id); 1087 1110 return -EINVAL; 1088 1111 } 1089 1112 1090 - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); 1091 - if (!cmd) 1092 - return -ENOMEM; 1113 + tv_nexus = tpg->tpg_nexus; 1114 + if (!tv_nexus) { 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 1130 /* XXX until I figure out why I can't free in on complete */ 1097 1131 kref_init(&cmd->ref); 1098 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 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 1136 if (fu->flags & USBG_USE_STREAMS) { 1110 1137 if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS) 1111 1138 goto err; ··· 1142 1115 cmd->stream = &fu->stream[cmd->tag - 1]; 1143 1116 } else { 1144 1117 cmd->stream = &fu->stream[0]; 1145 - } 1146 - 1147 - tv_nexus = tpg->tpg_nexus; 1148 - if (!tv_nexus) { 1149 - pr_err("Missing nexus, ignoring command\n"); 1150 - goto err; 1151 1118 } 1152 1119 1153 1120 switch (cmd_iu->prio_attr & 0x7) { ··· 1169 1148 1170 1149 return 0; 1171 1150 err: 1172 - kfree(cmd); 1151 + usbg_release_cmd(&cmd->se_cmd); 1173 1152 return -EINVAL; 1174 1153 } 1175 1154 ··· 1211 1190 { 1212 1191 struct bulk_cb_wrap *cbw = cmdbuf; 1213 1192 struct usbg_cmd *cmd; 1214 - struct usbg_tpg *tpg; 1193 + struct usbg_tpg *tpg = fu->tpg; 1215 1194 struct tcm_usbg_nexus *tv_nexus; 1216 1195 u32 cmd_len; 1217 1196 ··· 1228 1207 if (cmd_len < 1 || cmd_len > 16) 1229 1208 return -EINVAL; 1230 1209 1231 - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); 1232 - if (!cmd) 1233 - return -ENOMEM; 1210 + tv_nexus = tpg->tpg_nexus; 1211 + if (!tv_nexus) { 1212 + pr_err("Missing nexus, ignoring command\n"); 1213 + return -ENODEV; 1214 + } 1234 1215 1235 - cmd->fu = fu; 1216 + cmd = usbg_get_cmd(fu, tv_nexus, cbw->Tag); 1217 + if (IS_ERR(cmd)) { 1218 + pr_err("usbg_get_cmd failed\n"); 1219 + return -ENOMEM; 1220 + } 1236 1221 1237 1222 /* XXX until I figure out why I can't free in on complete */ 1238 1223 kref_init(&cmd->ref); 1239 1224 kref_get(&cmd->ref); 1240 1225 1241 - tpg = fu->tpg; 1242 - 1243 1226 memcpy(cmd->cmd_buf, cbw->CDB, cmd_len); 1244 1227 1245 1228 cmd->bot_tag = cbw->Tag; 1246 - 1247 - tv_nexus = tpg->tpg_nexus; 1248 - if (!tv_nexus) { 1249 - pr_err("Missing nexus, ignoring command\n"); 1250 - goto err; 1251 - } 1252 - 1253 1229 cmd->prio_attr = TCM_SIMPLE_TAG; 1254 1230 cmd->unpacked_lun = cbw->Lun; 1255 1231 cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0; ··· 1257 1239 queue_work(tpg->workqueue, &cmd->work); 1258 1240 1259 1241 return 0; 1260 - err: 1261 - kfree(cmd); 1262 - return -EINVAL; 1263 1242 } 1264 1243 1265 1244 /* Start fabric.c code */ ··· 1309 1294 { 1310 1295 struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, 1311 1296 se_cmd); 1297 + struct se_session *se_sess = se_cmd->se_sess; 1298 + 1312 1299 kfree(cmd->data_buf); 1313 - kfree(cmd); 1300 + percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); 1314 1301 } 1315 1302 1316 1303 static int usbg_shutdown_session(struct se_session *se_sess) ··· 1624 1607 goto out_unlock; 1625 1608 } 1626 1609 1627 - tv_nexus->tvn_se_sess = target_alloc_session(&tpg->se_tpg, 0, 0, 1610 + tv_nexus->tvn_se_sess = target_alloc_session(&tpg->se_tpg, 1611 + USB_G_DEFAULT_SESSION_TAGS, 1612 + sizeof(struct usbg_cmd), 1628 1613 TARGET_PROT_NORMAL, name, 1629 1614 tv_nexus, usbg_alloc_sess_cb); 1630 1615 if (IS_ERR(tv_nexus->tvn_se_sess)) {
+2
drivers/usb/gadget/function/tcm.h
··· 23 23 #define USB_G_ALT_INT_BBB 0 24 24 #define USB_G_ALT_INT_UAS 1 25 25 26 + #define USB_G_DEFAULT_SESSION_TAGS 128 27 + 26 28 struct tcm_usbg_nexus { 27 29 struct se_session *tvn_se_sess; 28 30 };