History

Merge patch series "scsi: ufs: Add support for the aggregated read query opcode"

Hyeoncheol Jeong <hyenc.jeong@samsung.com> says: UFS 5.0 / JEDEC 220H introduces the AGGREGATED READ query opcode (0x9), which retrieves an aggregated data packet bundling multiple Descriptors, Attributes and Flags in a single QUERY RESPONSE UPIU. Such a packet can be far larger than a single descriptor, so the reserved (device management) tag gets a dedicated UCD with an enlarged response area. Patch 1 is a preparatory cleanup that switches the BSG query descriptor length to unsigned types. Patch 2 adds the aggregated read support. v3: https://lore.kernel.org/linux-scsi/20260724030812epcms2p4eb2c77cb4dcd5fd51ca9c3eaa5ea4bfa@epcms2p4/ v2: https://lore.kernel.org/linux-scsi/20260722084819epcms2p49c27fce999e821385f7b5d7ea5a02868@epcms2p4/

Martin K. Petersen (Oracle) committed 3 months ago

Commit f574a022 parents 654fdae 8f5bbff6 files · +143 −48Browse files

Unified · Split

6 files
  1. drivers/ufs/core/ufs-mcq.c +10 −4
  2. drivers/ufs/core/ufs_bsg.c +21 −20
  3. drivers/ufs/core/ufshcd.c +74 −24
  4. include/ufs/ufs.h +6 −0
  5. include/ufs/ufshcd.h +20 −0
  6. include/ufs/ufshci.h +12 −0
drivers/ufs/core/ufs-mcq.c+10−4
@@ -296,14 +296,20 @@ static int ufshcd_mcq_get_tag(struct ufs_hba *hba, struct cq_entry *cqe) · 295 unmodified lines
296296 if (hba->ufs_version >= ufshci_version(4, 1))
297297 return cqe->task_tag;
298298
299− /* sizeof(struct utp_transfer_cmd_desc) must be a multiple of 128 */
299+ /* Both UCD types must have a size that is a multiple of 128 bytes */
300300 BUILD_BUG_ON(sizeof(struct utp_transfer_cmd_desc) & GENMASK(6, 0));
301+ BUILD_BUG_ON(sizeof(struct utp_devman_cmd_desc) & GENMASK(6, 0));
301302
302303 /* Bits 63:7 UCD base address, 6:5 are reserved, 4:0 is SQ ID */
303− addr = (le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA) -
304− hba->ucdl_dma_addr;
304+ addr = le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA;
305305
306− return div_u64(addr, ufshcd_get_ucd_size(hba));
306+ /* The devman UCD is outside the pool; return its reserved tag. */
307+ if (unlikely(addr == hba->devman_ucd_dma_addr))
308+ return hba->dev_cmd.tag;
309+
310+ /* Pool entries follow the reserved tags. */
311+ return div_u64(addr - hba->ucdl_dma_addr, ufshcd_get_ucd_size(hba)) +
312+ UFSHCD_NUM_RESERVED;
307313 }
308314
309315 static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
drivers/ufs/core/ufs_bsg.c+21−20
@@ -13,37 +13,31 @@ · 12 unmodified lines
1313 #include <ufs/ufshcd.h>
1414 #include "ufshcd-priv.h"
1515
16−static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len,
17− struct utp_upiu_query *qr)
18−{
19− int desc_size = be16_to_cpu(qr->length);
20−
21− if (desc_size <= 0)
22− return -EINVAL;
23−
24− *desc_len = min_t(int, QUERY_DESC_MAX_SIZE, desc_size);
25−
26− return 0;
27−}
28−
2916 static int ufs_bsg_alloc_desc_buffer(struct ufs_hba *hba, struct bsg_job *job,
30− uint8_t **desc_buff, int *desc_len,
17+ u8 **desc_buff, u16 *desc_len,
3118 enum query_opcode desc_op)
3219 {
3320 struct ufs_bsg_request *bsg_request = job->request;
3421 struct utp_upiu_query *qr;
22+ u16 max_desc_len;
3523 u8 *descp;
3624
3725 if (desc_op != UPIU_QUERY_OPCODE_WRITE_DESC &&
38− desc_op != UPIU_QUERY_OPCODE_READ_DESC)
26+ desc_op != UPIU_QUERY_OPCODE_READ_DESC &&
27+ desc_op != UPIU_QUERY_OPCODE_AGGREGATED_READ)
3928 goto out;
4029
4130 qr = &bsg_request->upiu_req.qr;
42− if (ufs_bsg_get_query_desc_size(hba, desc_len, qr)) {
31+ *desc_len = be16_to_cpu(qr->length);
32+ if (*desc_len == 0) {
4333 dev_err(hba->dev, "Illegal desc size\n");
4434 return -EINVAL;
4535 }
4636
37+ max_desc_len = desc_op == UPIU_QUERY_OPCODE_AGGREGATED_READ ?
38+ QUERY_AGGREGATED_MAX_SIZE : QUERY_DESC_MAX_SIZE;
39+ *desc_len = min(*desc_len, max_desc_len);
40+
4741 if (*desc_len > job->request_payload.payload_len) {
4842 dev_err(hba->dev, "Illegal desc size\n");
4943 return -EINVAL;
@@ -108,6 +102,9 @@ static int ufs_bsg_exec_advanced_rpmb_req(struct ufs_hba *hba, struct bsg_job *j · 58 unmodified lines
108102 if (!payload->payload_len || !payload->sg_cnt)
109103 return -EINVAL;
110104
105+ if (payload->sg_cnt > UFSHCD_DEVMAN_SG_ENTRIES)
106+ return -EINVAL;
107+
111108 sg_cnt = dma_map_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir);
112109 if (unlikely(!sg_cnt))
113110 return -ENOMEM;
@@ -136,8 +133,9 @@ static int ufs_bsg_request(struct bsg_job *job) · 22 unmodified lines
136133 struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent));
137134 struct uic_command uc = {};
138135 int msgcode;
139− uint8_t *buff = NULL;
140− int desc_len = 0;
136+ u8 *buff = NULL;
137+ u16 desc_len = 0;
138+ int buff_len;
141139 enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP;
142140 int ret;
143141 bool rpmb = false;
@@ -156,12 +154,15 @@ static int ufs_bsg_request(struct bsg_job *job) · 12 unmodified lines
156154 fallthrough;
157155 case UPIU_TRANSACTION_NOP_OUT:
158156 case UPIU_TRANSACTION_TASK_REQ:
157+ buff_len = desc_len;
159158 ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req,
160159 &bsg_reply->upiu_rsp, msgcode,
161− buff, &desc_len, desc_op);
160+ buff, &buff_len, desc_op);
161+ desc_len = buff_len;
162162 if (ret)
163163 dev_err(hba->dev, "exe raw upiu: error code %d\n", ret);
164− else if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len) {
164+ else if ((desc_op == UPIU_QUERY_OPCODE_READ_DESC ||
165+ desc_op == UPIU_QUERY_OPCODE_AGGREGATED_READ) && desc_len) {
165166 bsg_reply->reply_payload_rcv_len =
166167 sg_copy_from_buffer(job->request_payload.sg_list,
167168 job->request_payload.sg_cnt,
drivers/ufs/core/ufshcd.c+74−24
@@ -2947,23 +2947,44 @@ static void ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct scsi_cmnd *cmd) · 2946 unmodified lines
29472947 static void ufshcd_init_lrb(struct ufs_hba *hba, struct scsi_cmnd *cmd)
29482948 {
29492949 const int i = scsi_cmd_to_rq(cmd)->tag;
2950− struct utp_transfer_cmd_desc *cmd_descp =
2951− (void *)hba->ucdl_base_addr + i * ufshcd_get_ucd_size(hba);
29522950 struct utp_transfer_req_desc *utrdlp = hba->utrdl_base_addr;
2953− dma_addr_t cmd_desc_element_addr =
2954− hba->ucdl_dma_addr + i * ufshcd_get_ucd_size(hba);
29552951 u16 response_offset = le16_to_cpu(utrdlp[i].response_upiu_offset);
29562952 u16 prdt_offset = le16_to_cpu(utrdlp[i].prd_table_offset);
29572953 struct ufshcd_lrb *lrb = scsi_cmd_priv(cmd);
2954+ u8 *command_upiu, *response_upiu, *prd_table;
2955+ dma_addr_t cmd_desc_element_addr;
2956+
2957+ /* The reserved tag uses a dedicated UCD outside the pool. */
2958+ if (unlikely(blk_mq_is_reserved_rq(scsi_cmd_to_rq(cmd)))) {
2959+ struct utp_devman_cmd_desc *cmd_descp = hba->devman_ucd_base_addr;
2960+
2961+ cmd_desc_element_addr = hba->devman_ucd_dma_addr;
2962+ command_upiu = cmd_descp->command_upiu;
2963+ response_upiu = cmd_descp->response_upiu;
2964+ prd_table = cmd_descp->prd_table;
2965+ } else {
2966+ int slot = i - UFSHCD_NUM_RESERVED;
2967+ struct utp_transfer_cmd_desc *cmd_descp;
2968+
2969+ /* Non-reserved tags start at UFSHCD_NUM_RESERVED, so slot >= 0. */
2970+ WARN_ON_ONCE(slot < 0);
2971+ cmd_descp = (void *)hba->ucdl_base_addr + slot * ufshcd_get_ucd_size(hba);
2972+
2973+ cmd_desc_element_addr =
2974+ hba->ucdl_dma_addr + slot * ufshcd_get_ucd_size(hba);
2975+ command_upiu = cmd_descp->command_upiu;
2976+ response_upiu = cmd_descp->response_upiu;
2977+ prd_table = cmd_descp->prd_table;
2978+ }
29582979
29592980 lrb->utr_descriptor_ptr = utrdlp + i;
29602981 lrb->utrd_dma_addr =
29612982 hba->utrdl_dma_addr + i * sizeof(struct utp_transfer_req_desc);
2962− lrb->ucd_req_ptr = (struct utp_upiu_req *)cmd_descp->command_upiu;
2983+ lrb->ucd_req_ptr = (struct utp_upiu_req *)command_upiu;
29632984 lrb->ucd_req_dma_addr = cmd_desc_element_addr;
2964− lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp->response_upiu;
2985+ lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)response_upiu;
29652986 lrb->ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset;
2966− lrb->ucd_prdt_ptr = (struct ufshcd_sg_entry *)cmd_descp->prd_table;
2987+ lrb->ucd_prdt_ptr = (struct ufshcd_sg_entry *)prd_table;
29672988 lrb->ucd_prdt_dma_addr = cmd_desc_element_addr + prdt_offset;
29682989 }
29692990
@@ -3160,6 +3181,7 @@ static void ufshcd_setup_dev_cmd(struct ufs_hba *hba, struct scsi_cmnd *cmd, · 190 unmodified lines
31603181 __ufshcd_setup_cmd(hba, cmd, lun, tag);
31613182 lrbp->intr_cmd = true; /* No interrupt aggregation */
31623183 hba->dev_cmd.type = cmd_type;
3184+ hba->dev_cmd.tag = tag;
31633185 }
31643186
31653187 /*
@@ -4015,8 +4037,8 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) · 849 unmodified lines
40154037 {
40164038 size_t utmrdl_size, utrdl_size, ucdl_size;
40174039
4018− /* Allocate memory for UTP command descriptors */
4019− ucdl_size = ufshcd_get_ucd_size(hba) * hba->nutrs;
4040+ /* The reserved tag uses the dedicated UCD below, not this pool. */
4041+ ucdl_size = ufshcd_get_ucd_size(hba) * (hba->nutrs - UFSHCD_NUM_RESERVED);
40204042 hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev,
40214043 ucdl_size,
40224044 &hba->ucdl_dma_addr,
@@ -4032,6 +4054,21 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) · 9 unmodified lines
40324054 goto out;
40334055 }
40344056
4057+ /* Dedicated UCD for the reserved tag; allocate once (survives MCQ re-init). */
4058+ if (!hba->devman_ucd_base_addr) {
4059+ hba->devman_ucd_base_addr =
4060+ dmam_alloc_coherent(hba->dev,
4061+ ufshcd_get_devman_ucd_size(hba),
4062+ &hba->devman_ucd_dma_addr,
4063+ GFP_KERNEL);
4064+ if (!hba->devman_ucd_base_addr ||
4065+ WARN_ON(hba->devman_ucd_dma_addr & (128 - 1))) {
4066+ dev_err(hba->dev,
4067+ "Devman Command Descriptor Memory allocation failed\n");
4068+ goto out;
4069+ }
4070+ }
4071+
40354072 /*
40364073 * Allocate memory for UTP Transfer descriptors
40374074 * UFSHCI requires 1KB alignment of UTRD
@@ -4098,23 +4135,38 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) · 60 unmodified lines
40984135 dma_addr_t cmd_desc_element_addr;
40994136 u16 response_offset;
41004137 u16 prdt_offset;
4138+ u16 response_len;
41014139 int cmd_desc_size;
41024140 int i;
41034141
41044142 utrdlp = hba->utrdl_base_addr;
41054143
4106− response_offset =
4107− offsetof(struct utp_transfer_cmd_desc, response_upiu);
4108− prdt_offset =
4109− offsetof(struct utp_transfer_cmd_desc, prd_table);
4110−
41114144 cmd_desc_size = ufshcd_get_ucd_size(hba);
41124145 cmd_desc_dma_addr = hba->ucdl_dma_addr;
41134146
41144147 for (i = 0; i < hba->nutrs; i++) {
4148+ /*
4149+ * Reserved tags (low end) use the dedicated devman UCD with a
4150+ * larger response area; other tags index the pool at i - RESERVED.
4151+ */
4152+ if (i < UFSHCD_NUM_RESERVED) {
4153+ cmd_desc_element_addr = hba->devman_ucd_dma_addr;
4154+ response_offset = offsetof(struct utp_devman_cmd_desc,
4155+ response_upiu);
4156+ prdt_offset = offsetof(struct utp_devman_cmd_desc,
4157+ prd_table);
4158+ response_len = ALIGNED_DEVMAN_RSP_SIZE;
4159+ } else {
4160+ cmd_desc_element_addr = cmd_desc_dma_addr +
4161+ cmd_desc_size * (i - UFSHCD_NUM_RESERVED);
4162+ response_offset = offsetof(struct utp_transfer_cmd_desc,
4163+ response_upiu);
4164+ prdt_offset = offsetof(struct utp_transfer_cmd_desc,
4165+ prd_table);
4166+ response_len = ALIGNED_UPIU_SIZE;
4167+ }
4168+
41154169 /* Configure UTRD with command descriptor base address */
4116− cmd_desc_element_addr =
4117− (cmd_desc_dma_addr + (cmd_desc_size * i));
41184170 utrdlp[i].command_desc_base_addr =
41194171 cpu_to_le64(cmd_desc_element_addr);
41204172
@@ -4125,14 +4177,14 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) · 4 unmodified lines
41254177 utrdlp[i].prd_table_offset =
41264178 cpu_to_le16(prdt_offset);
41274179 utrdlp[i].response_upiu_length =
4128− cpu_to_le16(ALIGNED_UPIU_SIZE);
4180+ cpu_to_le16(response_len);
41294181 } else {
41304182 utrdlp[i].response_upiu_offset =
41314183 cpu_to_le16(response_offset >> 2);
41324184 utrdlp[i].prd_table_offset =
41334185 cpu_to_le16(prdt_offset >> 2);
41344186 utrdlp[i].response_upiu_length =
4135− cpu_to_le16(ALIGNED_UPIU_SIZE >> 2);
4187+ cpu_to_le16(response_len >> 2);
41364188 }
41374189 }
41384190 }
@@ -7657,7 +7709,8 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, · 3518 unmodified lines
76577709
76587710 /* just copy the upiu response as it is */
76597711 memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu));
7660− if (desc_buff && desc_op == UPIU_QUERY_OPCODE_READ_DESC) {
7712+ if (desc_buff && (desc_op == UPIU_QUERY_OPCODE_READ_DESC ||
7713+ desc_op == UPIU_QUERY_OPCODE_AGGREGATED_READ)) {
76617714 u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + sizeof(*rsp_upiu);
76627715 u16 resp_len = be16_to_cpu(lrbp->ucd_rsp_ptr->header
76637716 .data_segment_length);
@@ -7829,10 +7882,7 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r · 165 unmodified lines
78297882 * Message is 02h
78307883 */
78317884 if (ehs_len == 2 && rsp_ehs) {
7832− /*
7833− * ucd_rsp_ptr points to a buffer with a length of 512 bytes
7834− * (ALIGNED_UPIU_SIZE = 512), and the EHS data just starts from byte32
7835− */
7885+ /* EHS data starts from byte32 of the devman UCD response area. */
78367886 ehs_data = (u8 *)lrbp->ucd_rsp_ptr + EHS_OFFSET_IN_RESPONSE;
78377887 memcpy(rsp_ehs, ehs_data, ehs_len * 32);
78387888 }
@@ -9256,7 +9306,7 @@ static void ufshcd_release_sdb_queue(struct ufs_hba *hba, int nutrs) · 1417 unmodified lines
92569306 {
92579307 size_t ucdl_size, utrdl_size;
92589308
9259− ucdl_size = ufshcd_get_ucd_size(hba) * nutrs;
9309+ ucdl_size = ufshcd_get_ucd_size(hba) * (nutrs - UFSHCD_NUM_RESERVED);
92609310 dmam_free_coherent(hba->dev, ucdl_size, hba->ucdl_base_addr,
92619311 hba->ucdl_dma_addr);
92629312
include/ufs/ufs.h+6−0
@@ -25,6 +25,11 @@ static_assert(sizeof(struct utp_upiu_query) == 20); · 24 unmodified lines
2525
2626 #define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req))
2727 #define QUERY_DESC_MAX_SIZE 255
28+/*
29+ * Max aggregated read data segment: the devman response area
30+ * (ALIGNED_DEVMAN_RSP_SIZE) minus the fixed UPIU header it follows.
31+ */
32+#define QUERY_AGGREGATED_MAX_SIZE (4096 - GENERAL_UPIU_REQUEST_SIZE)
2833 #define QUERY_DESC_MIN_SIZE 2
2934 #define QUERY_DESC_HDR_SIZE 2
3035 #define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \
@@ -464,6 +469,7 @@ enum query_opcode { · 433 unmodified lines
464469 UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
465470 UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
466471 UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
472+ UPIU_QUERY_OPCODE_AGGREGATED_READ = 0x9,
467473 };
468474
469475 /* bRefClkFreq attribute values */
include/ufs/ufshcd.h+20−0
@@ -235,11 +235,13 @@ struct ufs_query { · 234 unmodified lines
235235 * @type: device management command type - Query, NOP OUT
236236 * @lock: lock to allow one command at a time
237237 * @query: Device management query information
238+ * @tag: tag of the reserved request in use
238239 */
239240 struct ufs_dev_cmd {
240241 enum dev_cmd_type type;
241242 struct mutex lock;
242243 struct ufs_query query;
244+ u8 tag;
243245 };
244246
245247 /**
@@ -954,9 +956,13 @@ enum ufshcd_mcq_opr { · 708 unmodified lines
954956 * @ucdl_base_addr: UFS Command Descriptor base address
955957 * @utrdl_base_addr: UTP Transfer Request Descriptor base address
956958 * @utmrdl_base_addr: UTP Task Management Descriptor base address
959+ * @devman_ucd_base_addr: UFS Command Descriptor base address for the reserved
960+ * device management tag (has a larger response area)
957961 * @ucdl_dma_addr: UFS Command Descriptor DMA address
958962 * @utrdl_dma_addr: UTRDL DMA address
959963 * @utmrdl_dma_addr: UTMRDL DMA address
964+ * @devman_ucd_dma_addr: UFS Command Descriptor DMA address for the reserved
965+ * device management tag
960966 * @host: Scsi_Host instance of the driver
961967 * @dev: device handle
962968 * @ufs_device_wlun: WLUN that controls the entire UFS device.
@@ -1098,11 +1104,13 @@ struct ufs_hba { · 135 unmodified lines
10981104 struct utp_transfer_cmd_desc *ucdl_base_addr;
10991105 struct utp_transfer_req_desc *utrdl_base_addr;
11001106 struct utp_task_req_desc *utmrdl_base_addr;
1107+ struct utp_devman_cmd_desc *devman_ucd_base_addr;
11011108
11021109 /* DMA memory reference */
11031110 dma_addr_t ucdl_dma_addr;
11041111 dma_addr_t utrdl_dma_addr;
11051112 dma_addr_t utmrdl_dma_addr;
1113+ dma_addr_t devman_ucd_dma_addr;
11061114
11071115 struct Scsi_Host *host;
11081116 struct device *dev;
@@ -1361,6 +1369,18 @@ static inline size_t ufshcd_get_ucd_size(const struct ufs_hba *hba) · 252 unmodified lines
13611369 return sizeof(struct utp_transfer_cmd_desc) + SG_ALL * ufshcd_sg_entry_size(hba);
13621370 }
13631371
1372+/*
1373+ * Two entries should be enough for the largest devman PRDT transfer (4 KiB),
1374+ * like advanced RPMB.
1375+ */
1376+#define UFSHCD_DEVMAN_SG_ENTRIES 2
1377+
1378+static inline size_t ufshcd_get_devman_ucd_size(const struct ufs_hba *hba)
1379+{
1380+ return sizeof(struct utp_devman_cmd_desc) +
1381+ UFSHCD_DEVMAN_SG_ENTRIES * ufshcd_sg_entry_size(hba);
1382+}
1383+
13641384 /* Returns true if clocks can be gated. Otherwise false */
13651385 static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba)
13661386 {
include/ufs/ufshci.h+12−0
@@ -18,6 +18,8 @@ enum { · 17 unmodified lines
1818 TASK_REQ_UPIU_SIZE_DWORDS = 8,
1919 TASK_RSP_UPIU_SIZE_DWORDS = 8,
2020 ALIGNED_UPIU_SIZE = 512,
21+ /* Larger response area, only for the devman UCD */
22+ ALIGNED_DEVMAN_RSP_SIZE = 4096,
2123 };
2224
2325 /* UFSHCI Registers */
@@ -501,6 +503,16 @@ struct utp_transfer_cmd_desc { · 477 unmodified lines
501503 u8 prd_table[];
502504 };
503505
506+/* Dedicated UCD for the devman/reserved slot */
507+struct utp_devman_cmd_desc {
508+ u8 command_upiu[ALIGNED_UPIU_SIZE];
509+ u8 response_upiu[ALIGNED_DEVMAN_RSP_SIZE];
510+ u8 prd_table[];
511+};
512+
513+static_assert(sizeof(struct utp_upiu_req) + QUERY_AGGREGATED_MAX_SIZE <=
514+ ALIGNED_DEVMAN_RSP_SIZE);
515+
504516 /**
505517 * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD
506518 */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t