Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157545573
D57087.id178080.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D57087.id178080.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D57087: nvme: add Apple T2 ANS2 NVMe quirks
Attached
Detach File
Event Timeline
Log In to Comment