Page MenuHomeFreeBSD

nvme: add Apple T2 ANS2 NVMe quirks
Needs ReviewPublic

Authored by guest-seuros on Tue, May 19, 10:26 AM.
Referenced Files
F159203748: D57087.diff
Thu, Jun 11, 7:24 AM
Unknown Object (File)
Mon, Jun 8, 9:57 AM
Unknown Object (File)
Mon, Jun 8, 8:20 AM
Unknown Object (File)
Thu, Jun 4, 3:07 PM
Unknown Object (File)
Thu, Jun 4, 12:16 PM
Unknown Object (File)
Thu, Jun 4, 9:26 AM
Unknown Object (File)
Wed, Jun 3, 3:56 PM
Unknown Object (File)
Wed, Jun 3, 7:15 AM
Subscribers

Details

Reviewers
adrian
ngie
imp
Summary

The Apple T2 (ANS2, PCI 106b:2005) requires several quirks:

  • 128-byte submission queue entries (CC.IOSQES = 7)
  • Single MSI vector, one IO queue
  • Admin and IO queues share a CID table; IO CIDs offset by adminq.num_trackers to avoid overlap
  • No async event support
  • IDENTIFY CNS >= 2 rejected to avoid firmware confusion

Tested-on:

  • MacBookPro16,2 (A2251)
  • Mac mini 8,1 (A1993)
  • Multiple Non-Apple computers

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 73648
Build 70531: arc lint + arc unit

Event Timeline

sys/dev/nvme/nvme_qpair.c
1078

Does this work instead? I'm not a huge fan of "wild pointer" arithmetic; the array notation makes alignment, sizing, and indexing clearer to me, if that strategy could be used instead.

sys/dev/nvme/nvme_sim.c
107

Is there a well-defined constant that can be used in place of 2?

sys/dev/nvme/nvme_sysctl.c
72โ€“73

Does this work instead?

Also: what kinds of tests did you run? Attach/detach? Read/write tests (with dd/fio)? Etc.

sys/dev/nvme/nvme_private.h
230

Does it make sense to think about how one might do this as a subclass instead of a series of particularly specific quirks?

Also: what kinds of tests did you run? Attach/detach? Read/write tests (with dd/fio)? Etc.

Well , i didn't test detach since the nvme is soldered and it the disk i booted from.

However i did use it a daily and compiled the kernel 40+ times and build the world 5 time without any hiccups.

guest-seuros added inline comments.
sys/dev/nvme/nvme_private.h
230

Yes, but i'm thinking we could land it without too much mutation and early optimisations, then refactor it.

PS: A bunch of the code/logic is reused in the Apple Sillicon implementation. (I have both running). And the Diff will make no sense without the full picture.

sys/dev/nvme/nvme_sim.c
107

We can add it.

sys/dev/nvme/nvme_pci.c
96

So this is a big ugly hammer for early, buggy NVMe drives. Maybe you can help me understand the symptom this cures? And if the really long time we delay before we check for ready is needed?

336

How does trying something we know won't work future proof the code? Is there other NVMe drives that apple makes with this quirk coming soon?

sys/dev/nvme/nvme_private.h
230

I know that Linux went the subclass route, and I think that these operations may be such that we might want to do that too.
Plus I have access to a crypto card that uses the NVMe interface that has other special needs which a properly designed subclass system will fit into.

Having said that, I'm cool with the hacks for the moment until we have something working and solid. Then we can refactor... I know this is a bit of a risk because once it's working, people move on...

sys/dev/nvme/nvme_qpair.c
1078

Maybe make it a macro instead of inlining it, since we'll need to do this in multiple places.

sys/dev/nvme/nvme_sim.c
107

Yea. I'd be tempted to just make this a field (maybe ctrlr->max_id_cns) and compare against it always for OPC_IDENTIFY commands?

And is this the right place to put it? I'd think we'd want to put it lower in the stack since not all identify commands come through here.

sys/dev/nvme/nvme_sysctl.c
72โ€“73

See my comment about a macro instead.

I will update this diff shortly. I need to retest in the hardware.

Once this diff land, users can install the OS on the internal NVME.

They will need the other linked diffs to get Keyboard,mouse, audio.

sys/dev/nvme/nvme_pci.c
336

There are few other NVME with other models that i could not test on. This code was defensive, i will remove it.

guest-seuros marked an inline comment as done.

Address review: NVME_SQE macro, max_id_cns field, removed defensive code

remove DELAY_B4_CHK_RDY, the timeout is much smaller, will measure later. not a blocker

Some final nits to simplify things a bit. Also, if you can find the size of the sqe from the identify and/or the capabilities stuff, that would be better than a quirk. Have you investigated it.

sys/dev/nvme/nvme_ctrlr.c
183

I'll note for future work that we generally have shifted to if ((flag & FLAG) != 0) elsewhere in the kernel. However, this is correct for this driver because it's older and uses the older if (flag & FLAG) style.

sys/dev/nvme/nvme_pci.c
143

As a design thing, I think that this might be better as it's own quirk, though that might be slicing things too thinly.

sys/dev/nvme/nvme_private.h
338

If you normally set sqe_size to 1, and bumped that to '2' for apple, then this macro could actually be the much simpler &(qpair)->cmd[idx] (maybe with an extra set of parens).

sys/dev/nvme/nvme_qpair.c
548

This is where you'd do '1' or '2'.

569

and this would need an additional * sizeof(struct nvme_command) at the end.

1252

same here.

sys/dev/nvme/nvme_sim.c
107

how does

One last suggestion on the sqe size. I just realized we read the size from (ctrlr->cdata.sqes >> 4) & 0xf; and it's really a shift vale. we should leverage that and just shoft this number - 6 since our default SQE size is 64.

sys/dev/nvme/nvme_qpair.c
539

so if sqes_max is 6 or 7, then we cna simplify sqe_size to be seq_max - 6 always and rename to sqe_shift. But that would also need to change the * seq_size to a << seq_shift.

In D57087#1317346, @imp wrote:

One last suggestion on the sqe size. I just realized we read the size from (ctrlr->cdata.sqes >> 4) & 0xf; and it's really a shift vale. we should leverage that and just shoft this number - 6 since our default SQE size is 64.

ok seuros, this is the last one, right warner? ๐Ÿ“ฆ

I forgot to submit this comment earlier:

What kinds of tests did you run? Attach/detach? Read/write tests (with dd/fio)? Etc.

In general I'm ok with the diff modulo the unnecessary goto, but I would want someone like @imp to weigh in before merging the change to :main since it's not my domain of expertise.

sys/dev/nvme/nvme_ctrlr.c
1128โ€“1137

This is odd to create a goto/label which only jumps a few lines like this. Is there a reason why the previous logic was insufficient? I've proposed an alternative diff which avoids the goto/label.

sys/dev/nvme/nvme_ctrlr.c
1128โ€“1137

So it occurs to me that

if (nvme_ctrlr_identify(ctrlr) == 0 &&
    nvme_ctrlr_set_num_qpairs(ctrlr) == 0 &&
    nvme_ctrlr_construct_io_qpairs(ctrlr) == 0)
        nvme_ctrlr_start(ctrlr, false);
else
        nvme_ctrlr_fail(ctrlr, false);

might be even better. If all three things succeed, start the controller, otherwise fail it.

sys/dev/nvme/nvme_ctrlr.c
1128โ€“1137

I like @imp's suggestion: it's a lot cleaner than mine.