Skip to content

Commit 71e7ae8

Browse files
author
Nicholas Bellinger
committed
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>
1 parent 5f27eda commit 71e7ae8

File tree

2 files changed

+60
-39
lines changed

2 files changed

+60
-39
lines changed

drivers/usb/gadget/function/f_tcm.c

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,39 +1073,66 @@ static void usbg_cmd_work(struct work_struct *work)
10731073
usbg_cleanup_cmd(cmd);
10741074
}
10751075

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+
10761098
static int usbg_submit_command(struct f_uas *fu,
10771099
void *cmdbuf, unsigned int len)
10781100
{
10791101
struct command_iu *cmd_iu = cmdbuf;
10801102
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;
10831105
u32 cmd_len;
1106+
u16 scsi_tag;
10841107

10851108
if (cmd_iu->iu_id != IU_ID_COMMAND) {
10861109
pr_err("Unsupported type %d\n", cmd_iu->iu_id);
10871110
return -EINVAL;
10881111
}
10891112

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+
}
10931118

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+
}
10951129

10961130
/* XXX until I figure out why I can't free in on complete */
10971131
kref_init(&cmd->ref);
10981132
kref_get(&cmd->ref);
10991133

1100-
tpg = fu->tpg;
1101-
cmd_len = (cmd_iu->len & ~0x3) + 16;
1102-
if (cmd_len > USBG_MAX_CMD)
1103-
goto err;
1104-
11051134
memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
11061135

1107-
cmd->tag = be16_to_cpup(&cmd_iu->tag);
1108-
cmd->se_cmd.tag = cmd->tag;
11091136
if (fu->flags & USBG_USE_STREAMS) {
11101137
if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
11111138
goto err;
@@ -1117,12 +1144,6 @@ static int usbg_submit_command(struct f_uas *fu,
11171144
cmd->stream = &fu->stream[0];
11181145
}
11191146

1120-
tv_nexus = tpg->tpg_nexus;
1121-
if (!tv_nexus) {
1122-
pr_err("Missing nexus, ignoring command\n");
1123-
goto err;
1124-
}
1125-
11261147
switch (cmd_iu->prio_attr & 0x7) {
11271148
case UAS_HEAD_TAG:
11281149
cmd->prio_attr = TCM_HEAD_TAG;
@@ -1148,7 +1169,7 @@ static int usbg_submit_command(struct f_uas *fu,
11481169

11491170
return 0;
11501171
err:
1151-
kfree(cmd);
1172+
usbg_release_cmd(&cmd->se_cmd);
11521173
return -EINVAL;
11531174
}
11541175

@@ -1190,7 +1211,7 @@ static int bot_submit_command(struct f_uas *fu,
11901211
{
11911212
struct bulk_cb_wrap *cbw = cmdbuf;
11921213
struct usbg_cmd *cmd;
1193-
struct usbg_tpg *tpg;
1214+
struct usbg_tpg *tpg = fu->tpg;
11941215
struct tcm_usbg_nexus *tv_nexus;
11951216
u32 cmd_len;
11961217

@@ -1207,28 +1228,25 @@ static int bot_submit_command(struct f_uas *fu,
12071228
if (cmd_len < 1 || cmd_len > 16)
12081229
return -EINVAL;
12091230

1210-
cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
1211-
if (!cmd)
1212-
return -ENOMEM;
1231+
tv_nexus = tpg->tpg_nexus;
1232+
if (!tv_nexus) {
1233+
pr_err("Missing nexus, ignoring command\n");
1234+
return -ENODEV;
1235+
}
12131236

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+
}
12151242

12161243
/* XXX until I figure out why I can't free in on complete */
12171244
kref_init(&cmd->ref);
12181245
kref_get(&cmd->ref);
12191246

1220-
tpg = fu->tpg;
1221-
12221247
memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
12231248

12241249
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-
12321250
cmd->prio_attr = TCM_SIMPLE_TAG;
12331251
cmd->unpacked_lun = cbw->Lun;
12341252
cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
@@ -1239,9 +1257,6 @@ static int bot_submit_command(struct f_uas *fu,
12391257
queue_work(tpg->workqueue, &cmd->work);
12401258

12411259
return 0;
1242-
err:
1243-
kfree(cmd);
1244-
return -EINVAL;
12451260
}
12461261

12471262
/* Start fabric.c code */
@@ -1294,8 +1309,10 @@ static void usbg_release_cmd(struct se_cmd *se_cmd)
12941309
{
12951310
struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
12961311
se_cmd);
1312+
struct se_session *se_sess = se_cmd->se_sess;
1313+
12971314
kfree(cmd->data_buf);
1298-
kfree(cmd);
1315+
percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag);
12991316
}
13001317

13011318
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)
16071624
goto out_unlock;
16081625
}
16091626

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),
16111630
TARGET_PROT_NORMAL, name,
16121631
tv_nexus, usbg_alloc_sess_cb);
16131632
if (IS_ERR(tv_nexus->tvn_se_sess)) {

drivers/usb/gadget/function/tcm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ enum {
2323
#define USB_G_ALT_INT_BBB 0
2424
#define USB_G_ALT_INT_UAS 1
2525

26+
#define USB_G_DEFAULT_SESSION_TAGS 128
27+
2628
struct tcm_usbg_nexus {
2729
struct se_session *tvn_se_sess;
2830
};

0 commit comments

Comments
 (0)