Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISP (work in progress) #319

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft

ISP (work in progress) #319

wants to merge 15 commits into from

Conversation

eiln
Copy link
Contributor

@eiln eiln commented Aug 14, 2023

No description provided.

{"/arm-io/dart-aop", 1},
{"/arm-io/dart-mtp", 1},
{"/arm-io/dart-pmp", 1},
{"/arm-io/dart-isp", 5},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider deriving the register range index from ADT. I think it was the instance property that held that info? Would that work here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instance are names of each dapf entry (DAPF, SMMU, TLL, DART). I couldn't find another prop either. But for all of my test cases (t8103 ane/aop/isp; mtp/pmp gets dropped anyway) it's the last range index, which we could get from reg_len / ((a_cells + s_cells) * 4). If this holds up I can revert this & add adt_get_reg_count() instead.

Also enable power if domain exists.

Signed-off-by: Eileen Yoon <[email protected]>
Signed-off-by: Eileen Yoon <[email protected]>
Handle /arm-io/isp0 and diff CTRR writes.

Signed-off-by: Eileen Yoon <[email protected]>

/* ISP DART has some quirks we must work around */

#define DART_T8020_ENABLED_STREAMS 0xfc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to do all this DART stuff? Linux should be in charge of DARTs, and this is unlikely to work on M2+ as they use a different DART type. dart,t8110 uses very different registers, I don't think it's going to work with the stream selects for dart,t8020.

We've generally gotten away without these DART tunables, just by describing things properly in the DT. Do we know what they do? In particular the TCRs should be managed by Linux, so it shouldn't be necessary to poke them. If we need to apply the tunables in m1n1 due to "fun special stuff" that's fine, but we should try to figure out the minimum viable init sequence.

This should also probably be in common DART code, not specific to ISP, since as far as I know it's all part of the DART nodes anyway. There's lots of regs/etc defined in dart.c you can use. If we only need it for ISP we'll only call it for ISP, but it's common support code after all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For normal DARTs, its register range count is 1 or 2, with the optional second range specifying DAPF. Walking ADT, the DART nodes with a reg count > 2:

dart-isp 6, dart-ane 4, dart-ave 4

Conveniently, both the ANE & AVE are derivatives of ISP. I also briefly looked at AVE for this exact reason. All three have the same DMA setup, involving an n-number of "fake" dart domains referenced by its periperal DMA channels. For the ISP, the (actual) dart is index 0, the next 2 are the fake/reference darts, and the last range is DAPF. ANE is n=2, AVE is n=1. These ranges look like real darts, and when poked, the registers somewhat behave like a real one, but they cannot substitute the main dart nor provide a new address space.

Instead, certain values must be manually "synced" to the main domain for DMA to work, notably TTBR and TLB invalidation. E.g. without syncing TTBR, the AVE/ISP firmware boots fine (ASC PTE is ok) but will fail when asked to do work (for the ISP, frames are dropped); the ANE specifically cannot DMA to/from L2 without TTBR synced; its internal command DMA channel works fine. Also, both ANE/ISP cannot reuse pages without also calling TLB invalidation on the fake domains beforehand (DART IRQ gets stuck). TTBR we can call once after init (though not quite a tunable because the main TTBR isn't initialized yet), but TLB invalidation must follow the main dart call every time, so that's really not a tunable.

Currently isp-iommu.c hacks around this, mainly because I can and without bothering sven (though I'm the only one outside of iommu calling iommu_flush_iotlb_all()), but clearly we need changes to core DART code. Especially if we're gonna use it again ;)

src/kboot.c Outdated
if (fdt_node < 0)
bail("FDT: '%s' node not found\n", path);

if (fdt_appendprop_u64(dt, fdt_node, "apple,isp-heap-base", heap_base))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this really need to be fixed here? It kind of sounds like the heap memory is supposed to be dynamically allocated depending on what the firmware requests, or some other metadata somewhere? If it's not in Apple's DT then it has to come from somewhere else...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was once revealed to me in a dream that the firmware sizes are hardcoded in their kext. It also varies per device on the same the OS version (there's a firmware for each device). I'm pretty sure ah-'s t6000 issue was this.

src/kboot.c Outdated

int count = segments_len / sizeof(*segments);
for (int i = 0; i < count; i++)
segments[i].remap = segments[i].iova; // match sio segment-ranges
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mutating the ADT in-place, that's not a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is mutated to match the sio segment-ranges struct (for dt_reserve_asc_firmware()). Should I not mutate in-place (call adt_setprop()with full struct) or not mutate at all (fix dt_reserve_asc_firmware() to accept an index?)

src/kboot.c Outdated
bail("FDT: couldn't get ISP CTRR size (%d)\n", os_firmware.version);
}

u64 heap_base = segments[count - 1].iova + segments[count - 1].size;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this right? Taking an iova, adding a size, yields an iova... then ctrr_size minus that? So the base iova is effectively 0? But then calling this size CTRR makes no sense, CTRR is a read-only region that should cover the firmware text and rodata regions only, definitely not a heap after that. It kind of sounds like what you call "ctrr_size" is more like the entire ISP low iova area?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppleH13CamIn::mapFwCTRRRegion - FW __TEXT segment phy: 0x10000a58000, virt: 0x0, remap: 0x10000a58000, size: 0x980000
AppleH13CamIn::mapFwCTRRRegion - FW __DATA segment phy: 0x10001b60000, virt: 0x980000, remap: 0x1f000980000, size: 0x324000
AppleH13CamIn::mapFwCTRRRegion - physical start: 0xca4000, heap size: 0x25c000
AppleH13CamIn::start - CTRR firmware is loaded, size: 0xf00000

The "heap" is where the firmware code executes. The problem is that there isn't a mechanism to separate the address space. We can set DMA dst to the heap all we want. XNU has some (kernel-level) page protections. Also the "physical start" is a typo, as the heap is allocated at probe and can be discontiguous.

marcan and others added 9 commits September 10, 2023 20:27
The iova field is different, handle it with a flag.

Signed-off-by: Hector Martin <[email protected]>
For ISP stuff which is not declared in the ADT

Signed-off-by: Hector Martin <[email protected]>
Allocating this in m1n1 means we can treat it as a reserved-memory node
and deal with knowing the size in m1n1, instead of the kernel. It also
means we can deal with the firmware version dependency mess here.

Signed-off-by: Hector Martin <[email protected]>
This means we can use it with pre-created nodes in the DT.

Signed-off-by: Hector Martin <[email protected]>
So of_iommu can detect it.

Signed-off-by: Eileen Yoon <[email protected]>
Still needed to fill out the fw bootargs.

Signed-off-by: Eileen Yoon <[email protected]>
@@ -2052,6 +2113,9 @@ int kboot_prepare_dt(void *fdt)
dt = NULL;
}

/* Need to init ISP early to carve out heap */
isp_init();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this either needs if (fdt_get_alias(dt, "isp")) or isp_init should silently fail if the ADT misses isp/isp0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants