Page MenuHomeFreeBSD

D57087.id178080.diff
No OneTemporary

D57087.id178080.diff

diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -173,6 +173,18 @@
num_entries = min(num_entries, mqes + 1);
num_entries = min(num_entries, max_entries);
+ /*
+ * Apple T2 ANS2 (SHARED_TAGS): admin and IO queues share a single CID
+ * table in the controller firmware. Admin uses CIDs
+ * 0..adminq.num_trackers-1; IO must use the remainder without
+ * exceeding the table size (NVME_ADMIN_ENTRIES). Cap both num_entries
+ * and num_trackers so that cid_base + num_trackers <= NVME_ADMIN_ENTRIES.
+ */
+ if (ctrlr->quirks & QUIRK_APPLE_SHARED_TAGS) {
+ num_entries = min(num_entries, NVME_ADMIN_ENTRIES);
+ /* Leave room below the table ceiling for the admin CID range. */
+ }
+
num_trackers = NVME_IO_TRACKERS;
TUNABLE_INT_FETCH("hw.nvme.io_trackers", &num_trackers);
@@ -185,6 +197,15 @@
*/
num_trackers = min(num_trackers, (num_entries-1));
+ /*
+ * Apple T2 ANS2: IO CIDs are offset by cid_base (= adminq.num_trackers).
+ * Ensure cid_base + num_trackers <= NVME_ADMIN_ENTRIES so IO CIDs stay
+ * within the controller's shared tag table.
+ */
+ if (ctrlr->quirks & QUIRK_APPLE_SHARED_TAGS)
+ num_trackers = min(num_trackers,
+ NVME_ADMIN_ENTRIES - ctrlr->adminq.num_trackers);
+
/*
* Our best estimate for the maximum number of I/Os that we should
* normally have in flight at one time. This should be viewed as a hint,
@@ -383,7 +404,16 @@
cc |= NVMEF(NVME_CC_REG_CSS, 0);
cc |= NVMEF(NVME_CC_REG_AMS, 0);
cc |= NVMEF(NVME_CC_REG_SHN, 0);
- cc |= NVMEF(NVME_CC_REG_IOSQES, 6); /* SQ entry size == 64 == 2^6 */
+ /*
+ * Apple T2 ANS2 uses 128-byte SQ entries (CC.IOSQES = 7).
+ * The T2 appears to ignore CC.IOSQES entirely and always operates
+ * with 128-byte SQEs regardless of what is written here.
+ * We set it anyway for spec compliance.
+ */
+ if (ctrlr->quirks & QUIRK_APPLE_128_BYTES_SQES)
+ cc |= NVMEF(NVME_CC_REG_IOSQES, 7);
+ else
+ cc |= NVMEF(NVME_CC_REG_IOSQES, 6); /* SQ entry size == 64 == 2^6 */
cc |= NVMEF(NVME_CC_REG_IOCQES, 4); /* CQ entry size == 16 == 2^4 */
/*
@@ -749,6 +779,11 @@
struct nvme_async_event_request *aer;
uint32_t i;
+ if (ctrlr->quirks & QUIRK_APPLE_NO_ASYNC_EVENT) {
+ ctrlr->num_aers = 0;
+ return;
+ }
+
ctrlr->async_event_config = NVME_CRIT_WARN_ST_AVAILABLE_SPARE |
NVME_CRIT_WARN_ST_DEVICE_RELIABILITY |
NVME_CRIT_WARN_ST_READ_ONLY |
diff --git a/sys/dev/nvme/nvme_pci.c b/sys/dev/nvme/nvme_pci.c
--- a/sys/dev/nvme/nvme_pci.c
+++ b/sys/dev/nvme/nvme_pci.c
@@ -92,7 +92,12 @@
{ 0xa821144d, 0, 0, "Samsung PM1725", QUIRK_DELAY_B4_CHK_RDY },
{ 0xa822144d, 0, 0, "Samsung PM1725a", QUIRK_DELAY_B4_CHK_RDY },
{ 0x07f015ad, 0, 0, "VMware NVMe Controller" },
- { 0x2003106b, 0, 0, "Apple S3X NVMe Controller" },
+ { 0x2003106b, 0, 0, "Apple S3X NVMe Controller",
+ QUIRK_DELAY_B4_CHK_RDY },
+ { 0x2005106b, 0, 0, "Apple ANS2 NVMe Controller (T2)",
+ QUIRK_DELAY_B4_CHK_RDY | QUIRK_APPLE_SINGLE_VECTOR |
+ QUIRK_APPLE_128_BYTES_SQES | QUIRK_APPLE_SHARED_TAGS |
+ QUIRK_APPLE_IDENTIFY_CNS | QUIRK_APPLE_NO_ASYNC_EVENT },
{ 0x00000000, 0, 0, NULL }
};
@@ -314,7 +319,7 @@
device_t dev;
int force_intx, num_io_queues, per_cpu_io_queues;
int min_cpus_per_ioq;
- int num_vectors_requested;
+ int num_vectors_requested, n;
dev = ctrlr->dev;
@@ -323,6 +328,26 @@
if (force_intx)
return (nvme_ctrlr_setup_shared(ctrlr, 0));
+ /*
+ * Apple T2 ANS2 requires a single shared interrupt and only supports
+ * one IO queue. The ANS2 has no INTx pin and no MSI-X capability;
+ * it only supports MSI. Try MSI-X first for future-proofing, then
+ * fall back to MSI.
+ */
+ if (ctrlr->quirks & QUIRK_APPLE_SINGLE_VECTOR) {
+ n = 1;
+ if (pci_alloc_msix(dev, &n) == 0 && n >= 1) {
+ ctrlr->msi_count = n;
+ return (nvme_ctrlr_setup_shared(ctrlr, 1));
+ }
+ n = 1;
+ if (pci_alloc_msi(dev, &n) == 0) {
+ ctrlr->msi_count = n;
+ return (nvme_ctrlr_setup_shared(ctrlr, 1));
+ }
+ return (nvme_ctrlr_setup_shared(ctrlr, 0));
+ }
+
if (pci_msix_count(dev) == 0)
goto msi;
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -165,6 +165,8 @@
uint32_t num_entries;
uint32_t num_trackers;
+ uint32_t sqe_size; /* SQ entry size in bytes (64 or 128) */
+ uint16_t cid_base; /* CID offset for SHARED_TAGS IO queues */
uint32_t sq_tdbl_off;
uint32_t cq_hdbl_off;
@@ -224,6 +226,11 @@
#define QUIRK_DISABLE_TIMEOUT 2 /* Disable broken completion timeout feature */
#define QUIRK_INTEL_ALIGNMENT 4 /* Pre NVMe 1.3 performance alignment */
#define QUIRK_AHCI 8 /* Attached via AHCI redirect */
+#define QUIRK_APPLE_SINGLE_VECTOR 0x10 /* Single MSI vector (Apple T2) */
+#define QUIRK_APPLE_128_BYTES_SQES 0x20 /* 128-byte SQ entries (Apple T2) */
+#define QUIRK_APPLE_SHARED_TAGS 0x40 /* Admin/IO share CID space (Apple T2) */
+#define QUIRK_APPLE_IDENTIFY_CNS 0x80 /* Limit identify CNS <= 1 (Apple T2) */
+#define QUIRK_APPLE_NO_ASYNC_EVENT 0x100 /* No async event support (Apple T2) */
int resource_id;
struct resource *resource;
diff --git a/sys/dev/nvme/nvme_qpair.c b/sys/dev/nvme/nvme_qpair.c
--- a/sys/dev/nvme/nvme_qpair.c
+++ b/sys/dev/nvme/nvme_qpair.c
@@ -231,7 +231,7 @@
nvme_qpair_print_completion(qpair, cpl);
}
- qpair->act_tr[cpl->cid] = NULL;
+ qpair->act_tr[cpl->cid - qpair->cid_base] = NULL;
KASSERT(cpl->cid == req->cmd.cid, ("cpl cid does not match cmd cid\n"));
@@ -305,7 +305,7 @@
memset(&cpl, 0, sizeof(cpl));
cpl.sqid = qpair->id;
- cpl.cid = tr->cid;
+ cpl.cid = qpair->cid_base + tr->cid;
cpl.status = nvme_qpair_make_status(sct, sc, dnr);
nvme_qpair_complete_tracker(tr, &cpl, print_on_error);
}
@@ -433,8 +433,9 @@
NVME_STATUS_GET_P(status) == NVME_STATUS_GET_P(cpl.status),
("Phase unexpectedly inconsistent"));
- if (cpl.cid < qpair->num_trackers)
- tr = qpair->act_tr[cpl.cid];
+ if (cpl.cid >= qpair->cid_base &&
+ cpl.cid < qpair->cid_base + qpair->num_trackers)
+ tr = qpair->act_tr[cpl.cid - qpair->cid_base];
else
tr = NULL;
@@ -530,6 +531,26 @@
qpair->num_trackers = num_trackers;
qpair->ctrlr = ctrlr;
+ /*
+ * Apple T2 ANS2 quirks:
+ * - 128-byte SQ entries instead of standard 64-byte
+ * - SHARED_TAGS: IO queue CIDs must not overlap with admin CIDs (0..
+ * adminq.num_trackers-1), so IO queues start their CIDs at
+ * adminq.num_trackers.
+ */
+ /*
+ * Admin queue always uses 64-byte SQ entries per NVMe spec.
+ * APPLE_128_BYTES_SQES applies only to IO queues (CC.IOSQES).
+ */
+ if (qpair->id != 0 && (ctrlr->quirks & QUIRK_APPLE_128_BYTES_SQES))
+ qpair->sqe_size = 128;
+ else
+ qpair->sqe_size = sizeof(struct nvme_command);
+ if ((ctrlr->quirks & QUIRK_APPLE_SHARED_TAGS) && qpair->id != 0)
+ qpair->cid_base = ctrlr->adminq.num_trackers;
+ else
+ qpair->cid_base = 0;
+
mtx_init(&qpair->lock, "nvme qpair lock", NULL, MTX_DEF);
mtx_init(&qpair->recovery, "nvme qpair recovery", NULL, MTX_DEF);
@@ -553,7 +574,7 @@
* Each component must be page aligned, and individual PRP lists
* cannot cross a page boundary.
*/
- cmdsz = qpair->num_entries * sizeof(struct nvme_command);
+ cmdsz = qpair->num_entries * qpair->sqe_size;
cmdsz = roundup2(cmdsz, ctrlr->page_size);
cplsz = qpair->num_entries * sizeof(struct nvme_completion);
cplsz = roundup2(cplsz, ctrlr->page_size);
@@ -987,7 +1008,8 @@
* queue which will reset the card if it
* times out.
*/
- nvme_ctrlr_cmd_abort(ctrlr, tr->cid, qpair->id,
+ nvme_ctrlr_cmd_abort(ctrlr,
+ qpair->cid_base + tr->cid, qpair->id,
nvme_abort_complete, tr);
} else {
/*
@@ -1040,7 +1062,7 @@
mtx_assert(&qpair->lock, MA_OWNED);
req = tr->req;
- req->cmd.cid = tr->cid;
+ req->cmd.cid = qpair->cid_base + tr->cid;
qpair->act_tr[tr->cid] = tr;
ctrlr = qpair->ctrlr;
@@ -1061,7 +1083,8 @@
tr->deadline = SBT_MAX;
/* Copy the command from the tracker to the submission queue. */
- memcpy(&qpair->cmd[qpair->sq_tail], &req->cmd, sizeof(req->cmd));
+ memcpy((uint8_t *)qpair->cmd + qpair->sq_tail * qpair->sqe_size,
+ &req->cmd, sizeof(req->cmd));
if (++qpair->sq_tail == qpair->num_entries)
qpair->sq_tail = 0;
@@ -1235,7 +1258,7 @@
qpair->phase = 1;
memset(qpair->cmd, 0,
- qpair->num_entries * sizeof(struct nvme_command));
+ qpair->num_entries * qpair->sqe_size);
memset(qpair->cpl, 0,
qpair->num_entries * sizeof(struct nvme_completion));
}
diff --git a/sys/dev/nvme/nvme_sim.c b/sys/dev/nvme/nvme_sim.c
--- a/sys/dev/nvme/nvme_sim.c
+++ b/sys/dev/nvme/nvme_sim.c
@@ -96,6 +96,20 @@
struct nvme_controller *ctrlr;
ctrlr = sim2ctrlr(sim);
+
+ /*
+ * Apple T2 ANS2 (QUIRK_APPLE_IDENTIFY_CNS) does not support IDENTIFY
+ * with CNS >= 2 (e.g., Active Namespace ID List). Reject these before
+ * sending to avoid confusing the firmware.
+ */
+ if ((ctrlr->quirks & QUIRK_APPLE_IDENTIFY_CNS) &&
+ nvmeio->cmd.opc == NVME_OPC_IDENTIFY &&
+ (le32toh(nvmeio->cmd.cdw10) & 0xff) >= 2) {
+ nvmeio->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+
payload = nvmeio->data_ptr;
size = nvmeio->dxfer_len;
/* SG LIST ??? */
diff --git a/sys/dev/nvme/nvme_sysctl.c b/sys/dev/nvme/nvme_sysctl.c
--- a/sys/dev/nvme/nvme_sysctl.c
+++ b/sys/dev/nvme/nvme_sysctl.c
@@ -69,7 +69,8 @@
printf("Submission queue:\n");
for (i = 0; i < qpair->num_entries; i++) {
- cmd = &qpair->cmd[i];
+ cmd = (struct nvme_command *)((uint8_t *)qpair->cmd +
+ i * qpair->sqe_size);
printf("%05d: ", i);
nvme_qpair_print_command(qpair, cmd);
}

File Metadata

Mime Type
text/plain
Expires
Sat, May 23, 4:23 PM (9 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33449524
Default Alt Text
D57087.id178080.diff (9 KB)

Event Timeline