Hiring manager: Miklos Reiter
Your prep for the manager/CV round — who he is, what he tests, your pitch and the bridge from 5G TX to the NIC datapath, the Onload/ef_vi context to know cold, likely questions, and a pre-call checklist. Built from public sources only; keep it professional and don't imply inside knowledge.
🎙 Opener — your CV, performed
The Identity I’m a low-level C engineer who lives at the high-stakes boundary where software has to meet a hardware clock. For the last few years, my world has been the 5G modem—specifically, the "make-or-break" moment when data actually hits the wire.
The Thread My core work was building a hard real-time TX channel arbiter on a DSP. It was the ultimate traffic cop: scheduler modules would hit my API, and I had to decide, within a very tight n1/n2 look-ahead window, which request won the slot. Once that decision was made, I was firing callbacks to program accelerators via descriptors over a shared AXI DMA bus. It was all ISR-driven and strictly deterministic; if my code was late by even a few cycles, the transmit opportunity was dead and the frame was gone. I owned that logic from the 3GPP spec through to production, which meant I spent as much time on evidence-led triage and Google Test coverage as I did on the hot path.
The Bridge Hook Now, to be completely honest, I haven't shipped a production Linux netdev driver yet. But when I look at the work you’re doing here with Onload and ef_vi, I see the exact same DNA. A TX arbiter is essentially a hardware pacer; managing an AXI descriptor ring is the mirror image of PCIe bus-mastering. The discipline of proving memory visibility before hitting a doorbell or ensuring that an interrupt-driven system doesn't collapse under jitter is exactly what I’ve been doing in the modem space. I’m looking to move from the radio side to the host datapath because that intersection of low-level correctness and shipped-product reality is where I do my best work.
Delivery
- Time: ~65 seconds at a natural, conversational pace.
- Pace: Start steady. Speed up slightly during the "The Thread" to show energy for the technical details, then slow down for "The Bridge Hook" to show sincerity and confidence.
- Emphasis: Lean into the technical terms like
n1/n2andAXI DMA—they are your "defensible claims." - Tone: You aren't reciting a list; you are explaining "this is who I am and why I'm a safe pair of hands."
🎙 Signature story — the TX arbiter
Setup I want to take you inside the 5G transmit path of the modem SoC I worked on, because while it was an embedded environment, the architectural challenges were almost identical to what you are doing with ultra-low-latency NICs. We had multiple scheduler modules all competing for time on the TX channel. My job was to own the central arbiter—the logic that decides exactly which request wins the right to transmit in any given slot.
Stakes This was hard real-time, governed by what we called n1 and n2 parameters. n1 was my look-ahead window to make a decision, and n2 was the absolute commit deadline. If the arbiter was even a few microseconds late, the entire transmit opportunity was dead. We weren't just moving bits; we were managing a strict timing budget where the "tail" wasn't just a performance metric—it was a functional failure.
What I did I designed the arbiter's request-and-callback API. When a module won, the arbiter fired a callback that triggered the module to program the TX accelerators—specifically the bit-rate processing and the digital front end. We did this by writing descriptors over a shared AXI bus for the DMA to pick up. I had to ensure that the hand-off from the high-level scheduler logic down to the hardware descriptors was seamless and, most importantly, deterministic.
The hard part The real "depth" of the work was managing the concurrency between the asynchronous request API and the high-priority ISRs. I had to be obsessed with memory visibility. There was a classic race: if I triggered the DMA or sent a "go" signal before the full descriptor was actually visible across the AXI fabric, the hardware would fetch garbage. I spent a lot of time enforcing strict ordering discipline—essentially ensuring a memory barrier existed before the "doorbell" was rung—and instrumenting the boundaries to prove that our timing margins were defensible under load.
Result The result was a rock-solid TX path that met every 3GPP timing requirement. We moved from "it usually works" to having evidence-led triage. I added Google Test coverage for the arbiter logic and handled over a hundred support issues where I had to prove, using trace data, exactly why a packet was late or why a descriptor was misconfigured. It taught me that in high-performance datapaths, "correct" doesn't just mean the right bits; it means the right bits at the right microsecond.
Land it I know my experience is on RTOS and DSPs rather than Linux netdev drivers, but when I look at a Solarflare TX scheduler or a kernel-bypass ring buffer, I see the same fundamental patterns. A descriptor ring is just an API for hardware; a doorbell is just a trigger with a memory-visibility requirement; and the obsession with ef_vi or Onload tail latency is the same "deadline" discipline I lived in the 5G world. I’m ready to apply that same low-level rigor to the host-side datapath here.
Delivery Keep the pace steady and conversational. Pause for a beat after the Stakes to let the "dead packet" concept sink in. When discussing The hard part, lean in slightly—this is where you prove you understand the "why" behind the code (memory barriers and races). The Land it section should be delivered with confident eye contact; you are showing him that you already "speak" his architectural language, even if the OS is different. Total time: approx. 2 minutes 45 seconds.
🎙 The hard-bug story
Symptom I remember a bug on the 5G TX arbiter that really tested my discipline. We were seeing intermittent transmit timeouts—literally missing our n1/n2 commit deadlines—but only during high-throughput stress tests. On the bench, it was perfect. Under load, the arbiter would occasionally "lose" a request, the DSP would miss its slot, and the whole 5G link would drop.
The Trap Initially, we fell into the "cycles trap." We assumed the DSP was just over-subscribed and couldn't process the arbiter Symptom We had a "phantom" failure in the 5G uplink that only showed up under heavy network load. Occasionally, the TX accelerators—the BSRP and the digital front end—would report a configuration error or simply miss a transmit slot entirely. On the bench, the code was rock solid. But in stress testing, it was a one-in-ten-thousand occurrence that we couldn't reliably trigger.
The Trap My first instinct was that we were simply missing our n1 timing deadline—that the arbiter was being delayed by other ISRs and firing too late for the accelerators to process the descriptors. I spent a few shifts chasing scheduler jitter and measuring execution cycles, but the numbers didn't support it. The arbiter was firing exactly when it was supposed to. I realized I was looking at *when* the code ran, rather than *what* the hardware was actually seeing at that moment.
How I cornered it I needed to see the handover between the task context and the ISR. I implemented a lightweight, lock-less trace buffer in the DSP internal memory. It captured a high-res timestamp of the API submission, the exact state of the descriptor bits, and the moment the arbiter fired the callback. I wasn't just looking for logic errors; I was looking for the order of visibility across the AXI bus.
Root cause It was a classic memory-visibility race. The module was writing the BSRP configuration to shared memory and then updating a "ready" flag. However, because of the write-combining behavior on our SoC, the arbiter ISR—which was triggered by a hardware timer—was occasionally seeing that "ready" flag before the full descriptor data had actually landed in the shared RAM. We were effectively giving the hardware a "go" signal while the descriptors were still stuck in a CPU write-buffer.
Fix + Lesson The fix was a surgical memory barrier to ensure architectural visibility before the flag update, but the real takeaway was about ownership. We refactored the API to make the handover of that memory region explicit. It taught me that in hard real-time systems, "correct" code isn't just about the right logic; it’s about proving that the hardware and software have a consistent view of memory at the exact moment of a trigger.
Land it I know that at the speeds you’re hitting with the X-series NICs, the boundary between the host and the PCIe bus is exactly where these bugs live. If a doorbell hits the hardware before a descriptor ring update is visible, you get the same kind of silent, non-deterministic failure. I haven't shipped a Linux netdev driver yet, but I have the "scar tissue" from chasing these memory-ordering issues at the metal. I approach debugging with the assumption that if I can't see the memory visibility, I don't actually know why the bug is happening.
Delivery
- Pace: Steady and narrative. Don't rush the "Root cause" beat; let the technical weight of "write-combining" and "visibility" land.
- Emphasis: Stress words like "visible," "ownership," and "consistent."
- Tone: Professional and evidence-led. You aren't bragging about finding it; you're describing the process of elimination.
- Time: This should take approximately 110-120 seconds at a natural speaking rate.
🎙 Why AMD, and the close
Why Now I’ve spent the last few years in the 5G space, and what I realized is that I’m at my best when I’m working at that exact point where software has to meet a hardware deadline. In the modem world, we live and die by the n1/n2 timing parameters—if my arbiter doesn’t make a scheduling decision and fire that callback by a precise microsecond, the transmit opportunity is gone. When I started looking at the ultra-low-latency networking space, and specifically what you do here, I saw the exact same engineering craft. It’s that same obsession with the datapath, the determinism, and the hardware-software contract. I want to move from wireless PHY to NICs because, to me, this is the purest expression of that "right moment" engineering.
Why AMD To be honest, it’s the Solarflare lineage. There’s a specific culture here of not just chasing a buzzword, but building a "shipped-product reality." I’ve read about how Onload and ef_vi manage the kernel bypass, and it feels like the natural evolution of the work I’ve been doing on a DSP. You’re managing descriptor rings, DMA transfers over a bus, and memory visibility, but doing it for the most demanding deployments in the world. I want to be part of a team where "low latency" isn't just a marketing slide, but a defensible, technical claim that survives a real-world production environment.
Owning the Concern If I look at my CV from your perspective, I think the most obvious question is: "He’s a deep embedded guy, but has he ever shipped a production Linux netdev driver?" And the honest answer is no, I haven't. I’ve spent my time in the firmware and RTOS layers. But while the environment is different, the physics are the same. I speak the language of AXI DMA, interrupt-vs-poll trade-offs, and ensuring a memory barrier is in the right place before hitting a doorbell. I see the move to AMD as a bounded ramp-up—I’m not changing the *kind* of engineer I am; I’m just changing the domain where I apply that discipline. I’m ready to bridge that gap by bringing the same evidence-led triage and testing rigor I used to stabilize 5G releases.
Close I’m looking for a place where correctness at the low level is what actually drives the quality of the release. From everything I’ve seen, that’s exactly how this team operates, and that’s why I’m here.
Delivery
- Pace: Start steady and conversational. Speed up slightly during the "Why AMD" section to show genuine enthusiasm for the tech, then slow down and lower your pitch for "Owning the Concern" to project honesty and confidence.
- Emphasis: Lean into the technical terms like
n1/n2anddescriptor rings—Miklos will appreciate that you know the underlying mechanics. - The Gap: When you mention the lack of a Linux driver, don't look down. Keep eye contact. It shows you aren't afraid of the challenge.
- Time: This clocks in at approximately 85-90 seconds. It leaves plenty of room for his follow-ups.
🎬 How the 30 minutes actually go
This is a rehearsal inference, not inside knowledge. Treat it as a script to practise against, not a prediction.
The arc. Intro/role framing (0-3 min) → CV walkthrough (3-8) → one project deep-dive, almost certainly the TX arbiter (8-18) → the Linux-driver gap (18-23) → a light technical sanity check off your own words (23-27) → your questions and the close (27-30).
[0:30] You set the honest frame early. "I'm not coming from Ethernet NIC drivers directly. My strongest experience is production embedded C at the hardware/software boundary, under hard real-time constraints. I'd like to show where that overlaps with low-latency datapath work, and be clear about what I'd need to ramp on." This pre-empts the whole risk conversation and reads as senior.
**[1:50] "You said you were *central to* the arbiter. We'll come back to exactly what that means."** Expect him to flag vague ownership words and circle back. Have the precise boundary ready before he asks twice.
[5:10] "Have you written production Linux driver code?" Say it flat: "No, I have not shipped a production Linux Ethernet NIC driver." Then immediately give the adjacent evidence. Do not soften it to "not directly, but it's similar" — that's the answer he's listening for, and it reads as a tell.
[5:15] "Then why should I take that risk?" "The risk is real, so I won't ask you to ignore it. I'd reduce it two ways: I can contribute fast in adjacent low-level C — hardware-facing APIs, timing-sensitive code, descriptor setup, tests, debug — and I'd ramp deliberately on the Linux side: netdev, the DMA API, NAPI, interrupt moderation, PCIe device lifecycle. What I bring on day one isn't Ethernet vocabulary; it's discipline around hardware contracts, races, real-time behaviour, and production support."
**[7:45] "What specifically did *you* own in the arbiter?" The single most important answer of the call. Strong version: "I owned the control and timing path — the request API, arbitration decision logic, the timing windows around `n1`/`n2`, the callback path, the descriptor-facing programming sequence, the tests and the release behaviour. I did not** write the BSRP/DFE signal-processing kernels; those were owned elsewhere. The part I can defend deeply is the ownership transition from scheduler request → selected request → hardware-visible descriptor programming."
[9:45] "Two modules both think they're urgent. What decides?" "It had to be deterministic and tied to the transmission contract, not whichever interrupt ran first — request type, timing eligibility, accelerator constraints, and whether the callback could still meet its deadline. The key point is that failure was represented as state, not hidden as accidental timing."
[10:45] "What's a descriptor ring, in your own words?" Walk the lifecycle, not a definition: "A fixed-size ring of small hardware-readable records. On TX, software picks a free slot, fills a descriptor with the DMA address, length and flags, makes those writes visible, then rings a doorbell. The NIC fetches the descriptor, DMA-reads the buffer, transmits, and later posts completion so software can reclaim the slot. The whole thing lives or dies on ownership and memory ordering — neither side may touch a slot the other still owns."
**[15:50] "When is kernel bypass the *wrong* choice?"** Frame it as a product trade-off: "When the system gains more from the kernel's generality than from shaving latency — broad tooling, isolation, shaping, simple fleet deployment, observability. It's also wrong when the bottleneck is elsewhere and the app can't even use the lower latency, or when polling burns cores you can't spare."
[27:05] "Why not hire someone who already knows Linux networking?" Concede, then differentiate: "You should prefer that person if they also bring strong production discipline and cross-boundary debugging. My case isn't that the gap is irrelevant — it's that I bring a rare adjacent profile: release-quality embedded C in a timing-critical datapath, descriptor-based accelerator programming, real support exposure, and a habit of making hardware/software contracts explicit. If you need immediate deep kernel ownership, I'm not the lowest-risk hire. If you want someone who ramps into the domain and contributes strongly at the seam, I'm a serious candidate."
If the vibe is rushed/checkbox: lead with the labels he's ticking — "no production Linux NIC driver; yes production low-level C; yes descriptor-based accelerator programming; yes support exposure" — and don't spend two minutes on wireless context unless asked.
If the vibe is deeply technical: slow down, define ownership/state/invariants precisely, and say "I haven't shipped that exact Linux mechanism" where true, then reason from first principles.
If the vibe is friendly/selling the role: keep the gap visible anyway, and ask sharper product questions — first-90-days, host-driver vs Onload/ef_vi balance, observability and support pain.
Who Miklos Reiter is
Verified public profile. Miklos Reiter's current public title is Senior Manager Software Development at AMD in Cambridge, UK. LinkedIn and The Org both show this title. The Org also says he has held the AMD senior-manager role since February 2022, but that profile is marked Unverified, so treat that date as useful context rather than a hard fact.
Professional lineage. The public career thread to know is Solarflare -> Xilinx -> AMD. Xilinx announced its acquisition of Solarflare in 2019, and AMD completed its acquisition of Xilinx on 2022-02-14. That does not prove anything about internal AMD reporting lines, but it is a reasonable public frame for the Solarflare/Onload context around AMD Cambridge.
Most concrete technical signal. Red Hat's 2019 article says Reiter was Software Development Manager at Solarflare and led development of the Solarflare Cloud Onload Operator, which brought Cloud Onload deployment into OpenShift/Kubernetes. This is the strongest verified clue about his relevant technical world: high-performance NIC software, Onload, Linux/user-space networking, container deployment, and the practical work of turning low-latency datapath technology into something installable and supportable.
Academic and analytical background. Public sources also point to a Cambridge mathematics / operations-research background. LinkedIn and The Org list University of Cambridge degrees in mathematics / operations research. A Richard Steinberg CV lists Miklos Reiter as a Cambridge PhD student, PhD 2007, with the thesis title "Internet Congestion Pricing: Long-Term Bandwidth Contracts and Investment in Oligopoly." DBLP lists two networking/economics publications with Steinberg, from INFOCOM 2010 and IEEE/ACM Transactions on Networking 2012.
Useful-but-unverified career context. The Org lists earlier roles including Head of Software Development at Genomics plc, Senior Research Developer at Navetas, and Senior Quantitative Researcher at eValue and Sungard APT. Because The Org marks the profile unverified, mention these only lightly if they become relevant.
Interview inference. A fair, professional read is that he may value engineers who combine low-level technical precision with product discipline: C at the hardware/software boundary, performance reasoning, testability, observability, release quality, and honest communication about what they have and have not shipped. For a candidate coming from production 5G TX DSP firmware, the safest bridge is not "wireless PHY is basically NIC work," but that both domains require careful ownership of hardware-visible state, timing, data movement, debugging evidence, and correctness under performance pressure.
Sources: Red Hat: Launching OpenShift/Kubernetes Support for Solarflare Cloud Onload, AMD: AMD Completes Acquisition of Xilinx
What he values
Verified signal from public work: Red Hat’s 2019 article says Miklos Reiter was Software Development Manager at Solarflare and led development of the Solarflare Cloud Onload Operator for OpenShift/Kubernetes. The article describes an operator that deployed Onload kernel drivers and user-space libraries, integrated with Kubernetes device-plugin style mechanisms, used Node Feature Discovery to target nodes with Solarflare NICs, and worked with networking plugins such as Multus, macvlan, and ipvlan. That is the most concrete public evidence to use in interview preparation: Launching OpenShift/Kubernetes Support for Solarflare Cloud Onload.
Interview-useful inference: this suggests he values networking software as a shipped product, not only as clever C. The important signal is not just “kernel bypass” or “low latency”; it is the work needed to make acceleration usable in real customer environments. Drivers and user-space libraries have to install, upgrade, survive kernel-version differences, expose device nodes correctly, produce useful diagnostics, and leave a supportable path when performance or deployment goes wrong.
For you, the strongest move is to connect low-level correctness to release reality. Your 5G TX DSP firmware background gives you credible language around timing, ownership, constrained C, hardware/software boundaries, test coverage, CI, and release pressure. Make that concrete: when you discuss a bug or feature, explain who owned each interface, how state became visible, what instrumentation proved the issue, how edge cases were tested, and what made the final code release-quality.
Line to adapt: "My strongest background is production embedded C at the hardware/software boundary. What I want to show today is not that I have already shipped a Solarflare driver, but that I can reason about ownership, timing, observability, and release-quality code in a hardware-facing product."
Also frame benchmarks the way a product-minded networking manager would expect: reproducible setup first, number second. Say what hardware, kernel, driver, firmware, traffic shape, CPU isolation, queue configuration, container setup, and comparison baseline were used. Avoid sounding impressed by cherry-picked latency numbers without the conditions that make them meaningful.
Finally, show that hardware acceleration in containers is not just a speed story. AMD’s Onload documentation describes accelerated applications directly accessing a partition on the network adapter while preserving isolation through hardware-level Virtual NIC partitioning: AMD Onload User Guide UG1586. A reasonable inference is that he will appreciate candidates who mention isolation, partitioning, device assignment, node labeling, and operational debugging alongside datapath performance.
🎯 What he scores — and what flips him to yes
Miklos is a Cambridge maths/operations-research PhD turned software leader who shipped the Cloud Onload Operator — he models systems rigorously and thinks about products, not just fast paths. In 30 minutes he isn't proving you can already maintain a Solarflare driver. He's deciding one thing: is this a production low-level engineer with honest boundaries who can ramp into NIC work — or a wireless-firmware candidate over-selling into Linux networking?
What he's actually scoring:
- Honest self-assessment. Can you state the Linux-driver gap *before* being cornered, without sounding weak? Pass: "I haven't shipped a production NIC driver; here's the adjacent substrate." Fail: "wireless PHY is basically the same as Ethernet."
- Reasoning from mechanism. Do you explain systems by state, ownership, invariants and failure modes — or by buzzwords? Pass: the arbiter as an ownership model with
n1/n2timing and descriptor contracts. Fail: "it was a complex real-time system and I optimised it." - Productization instinct. Do you get that AMD/Solarflare networking is a shipped product — deploy, upgrade, diagnose, support, compatibility — not just nanoseconds? Feed this with the 100+ support issues, framed as evidence-led cross-team triage.
- Ramp risk / coachability. Will the panel see a serious learner or someone who needs basic Linux correction? Feed this with a concrete first-month plan and the
UL-DAIspec → C → GoogleTest → CI → release ownership story. - Communication under compression. 60-second CV then stop; every deep-dive in the same shape: context, *your* ownership, mechanism, failure mode, evidence of correctness, result. Never blur "we" and "I".
- **Genuine motivation for *this* team.** Solarflare lineage,
Onload/ef_vi, low-latency NICs — not "AMD is a great company" or generic AI enthusiasm.
The decision he leaves with:
- Yes, send to panel — "real gap, but bounded; the panel can test depth." Flips here when you state the gap cleanly *then* give credible adjacent evidence, your arbiter/bug story shows mechanism-level reasoning, and your questions are product-aware.
- Maybe — "interesting, but I can't tell if the transfer is real." Happens when you're honest but too abstract ("hardware/software boundary" with no concrete state machine), you know the
Onload/ef_vinames but not the trade-off, or your questions are generic. Escape it: pull back to one concrete ownership story, use exact boundaries, and ask the concern question near the end. - No — "too much ramp risk, or too much self-presentation risk." Flips here on overclaiming (Linux driver, Ethernet, TCP/IP, kernel, DSP kernels), inability to explain your *own* strongest project mechanistically, or treating performance as benchmark theatre. The hard rule he uses: overclaiming is more dangerous than ignorance — ignorance can be trained; unreliable self-calibration burns panel time.
Speak his language (use only when true):
- "Before the decision point, requests are candidates; after it, exactly one module owns the right to program the downstream path, and the descriptors are the contract with hardware."
- "For latency I wouldn't quote one number — I'd want the distribution, especially
p99/p999, then separate queueing, scheduling, cache/NUMA, interrupt-vs-poll, and device-facing effects." - "What caught my attention about Cloud Onload is that it's productization of a fast path — drivers, user-space libs, deployment, upgrade compatibility, diagnostics all have to work before performance matters to a customer."
- "A good fix isn't just the code change — it's the test, the counter or trace point that would have caught it earlier, and a clear statement of which boundary owned the bug."
- "The transfer from modem firmware to NIC software isn't protocol equivalence — it's discipline equivalence: hardware-visible state, constrained C, timing, ownership, observability, release quality."
The close (last 3 minutes) — compress the decision case and invite the objection: "I want to be clear on fit. I haven't shipped a production Linux NIC driver, so there's a domain ramp. What I bring is production low-level C at a hardware/software boundary — timing-sensitive firmware, descriptor-facing accelerator control, interrupts, tests, CI/release, cross-layer debug under real support pressure. The reason it's *this* team is the Solarflare/AMD lineage: Onload, ef_vi, low-latency NICs, and the product side of making that deployable. I think the right next step is for the panel to test whether my mechanism-level reasoning transfers. Is there any concern you'd want me to address before you decide whether to move me forward?"
Onload, ef_vi, TCPDirect & CTPIO — cold
The clean mental model: Onload, TCPDirect, and ef_vi sit on a compatibility-versus-control spectrum. Onload is the high-compatibility option: sockets-compatible acceleration using a user-space TCP/UDP stack. ef_vi is the raw option: layer-2 direct NIC datapath access where the application sends and receives Ethernet frames and owns more protocol logic. TCPDirect is the specialized middle ground: lower-latency and more explicit than ordinary Onload sockets, but not as raw as ef_vi.
Verified facts from UG1586: AMD describes conventional networking as requiring the application to call into the OS kernel for send/receive, with the user/kernel transition itself being expensive. For Onload, an accelerated application can directly access a partition on the network adapter, while system integrity is preserved by hardware-level Virtual NIC partitioning; a VNIC gives an Onload stack an isolated send/receive channel from user mode. AMD also says user-level event processing reduces kernel/user context switching and interrupts when the application is actively making socket calls. See AMD Onload User Guide UG1586.
The professional way to explain kernel bypass is not "the kernel is bad." The kernel is general-purpose and has to support fairness, isolation, scheduling, security, observability, and blocking semantics. Those are good properties, but they carry costs: syscalls, wakeups, copies, interrupts, and per-packet kernel work. Kernel bypass is a concrete cost reduction for latency-critical paths.
Onload in one line: sockets-compatible acceleration that bypasses the kernel fast path with a user-space TCP/UDP stack.
`ef_vi` in one line: raw layer-2 direct NIC datapath access for applications willing to own more of the protocol stack, with zero-copy and the lowest per-message overhead.
TCPDirect in one line: the specialized middle ground between the two.
CTPIO in one line: cut-through PIO that streams the packet over PCIe to begin transmit without waiting for the normal DMA path, for the lowest send latency.
`ef_vi` specifically: AMD defines ef_vi as a layer-2 API giving an application direct access to the Solarflare network adapter datapath. It sends and receives raw Ethernet frames, supports zero-copy because the process directly accesses hardware RX/TX buffers, can deliver lower latency and reduced per-message overhead than Onload, and requires the application to implement higher-layer protocols. That is the tradeoff: it removes layers, but the application has to do their work. See AMD UG1586 ef_vi section.
CTPIO specifically: AMD describes Cut-Through Programmed I/O as a lowest-send-path-latency feature where packets are streamed directly over PCIe to the network port, bypassing the main adapter transmit datapath. It coexists with host-buffered DMA transmit and legacy PIO buffering, and UG1586 says those methods can be mixed frame-by-frame with per-frame ordering maintained. Mechanistically, the point is timing: instead of waiting for the normal DMA descriptor path, doorbell processing, adapter fetch, and memory-visibility chain, CTPIO starts pushing the packet toward the port earlier. See AMD UG1586 CTPIO section.
Reasonable interview inference: for a 5G TX DSP firmware background, the useful bridge is not claiming shipped Onload experience. It is saying: "I have shipped timing-sensitive firmware where ownership, ordering, and hardware-visible memory matter; I have studied the Onload/ef_vi distinction, and I understand the tradeoff between compatibility and raw datapath control."
The product lineage — X4 & Pollara
Use the product references carefully: the safe purpose is to show awareness of the Solarflare/Onload lineage and AMD's public networking direction, not to claim that Miklos Reiter's Cambridge/Solarflare team owns any specific current product. Do not imply inside knowledge of AMD team structure, roadmap, or unreleased products.
Verified public facts: Solarflare X4. AMD publicly positions the AMD Solarflare X4 Ethernet adapters as ultra-low-latency Ethernet adapters for high-performance electronic trading and capital-markets workloads. The public X4 page and X4 product brief PDF list PCIe Gen5 x8 and models including:
X4542-PLUS: dualQSFP, with dual40/50/100 GbEor four1/10/25 GbEconfigurations.X4522-PLUS: dualSFP, with dual1/10/25/50 GbEconfigurations.
AMD also publishes sub-microsecond latency examples for X4, including a roughly 590 ns 4-byte latency result on an AMD EPYC test setup, and presents X4 as improving over X2 and X3. Treat those as AMD-published benchmark results under specific configurations, not as universal numbers to repeat as if they are architectural constants. In the interview, the stronger point is the product shape: low-latency NICs, capital-markets use cases, Onload compatibility, direct attention to datapath latency, and hardware/software co-design around packet movement.
Verified public facts: AMD AI networking direction. Separately, AMD publicly presents the AMD Pensando Pollara 400 AI NIC as a 400 Gbps UEC-ready AI NIC for scale-out AI infrastructure. AMD lists features such as intelligent packet spray, out-of-order packet handling with in-order message delivery, selective retransmission, path-aware congestion control, and rapid fault detection. AMD's broader networking solutions page frames this direction around AI data-center networking, scale-out performance, resiliency, programmability, and Ethernet/UEC evolution.
Interview-useful inference, with caveats. The public story suggests two useful axes to reference: Solarflare remains associated with ultra-low-latency Ethernet and capital markets, while AMD is also pushing networking as a first-class part of AI infrastructure. You can say: "I do not know how AMD splits this internally, and I would not assume the Cambridge/Solarflare team owns Pollara. But publicly, AMD's networking direction makes the NIC datapath increasingly important both for sub-microsecond trading paths and for cluster-level AI performance."
How to connect your 5G TX DSP background. The bridge is not that wireless PHY and Ethernet are the same. The bridge is disciplined hardware-facing software: bounded hot paths, ownership and visibility, timing, testability, and debugging at the boundary between firmware, hardware, and system behavior. A good framing is: "X4 makes me think about per-packet latency, descriptor ownership, DMA, PCIe, and completion paths; Pollara makes me think about distributed performance, congestion, retransmission, ordering, and fault handling. I have shipped production C in a timing-sensitive 5G TX DSP environment, and I am trying to move that same rigor into NIC datapath work."
🌐 Why one slow NIC stalls a GPU cluster
This is the one-sentence-away upgrade that separates you from every candidate who read a press release. The headline version is "AI is exploding, latency matters." The version that proves you understand the actual problem the team solves is a mechanism: in distributed training the network, not the GPU, is the bottleneck — and here is exactly why.
What "the network is the bottleneck" actually means. Training a large model is data-parallel: you put a copy of the model on every GPU, each GPU computes gradients on its own slice of the batch, and then — before the next step can start — every GPU has to end up holding the *sum* of all the gradients. That synchronization is a collective operation called an all-reduce, and it runs on every single training step. The most common implementation is a ring all-reduce: the GPUs form a logical ring and each one repeatedly sends its chunk to the next neighbour while adding in what it receives, so the gradients flow around the ring and accumulate. It is bandwidth-optimal, but it is fundamentally a lot of GPU-to-GPU network traffic that the compute cannot proceed without.
Why one stalled NIC stalls the whole cluster. An all-reduce is a barrier: the step is not complete until every participant has finished its part. So the collective moves at the speed of the *slowest link*. A single NIC that is slow — congestion, a dropped packet and a retransmit, a poorly paced flow — does not just slow down its own GPU. It holds the barrier open, and every other GPU in the collective sits idle waiting for it. One bad link can stall thousands of accelerators at once. This is why tail latency and loss recovery on the NIC matter so much more in AI fabrics than in ordinary networking: the whole job is only as fast as its unluckiest packet.
Why this is a cost argument, not just a speed argument. GPUs are the most expensive thing in the building. Every microsecond a collective stalls is idle time on hardware you are paying for whether it computes or not — so shaving network latency is not a nice-to-have, it directly raises utilization on the priciest silicon in the data center. That is the whole reason Ultra Ethernet and AMD Pollara exist: purpose-built congestion control, fast loss recovery, and packet spraying / multipath so the fabric stops being the thing that idles the GPUs. Frame it that way and "reduce cost" stops being abstract: low-latency networking is how you stop paying for GPUs to wait.
How to say it in the room. Do not lead with "AI is exploding." Lead with the mechanism and let it land in four short beats: every GPU syncs its gradients each step through a collective; the collective runs at the speed of the slowest link; one stalled NIC idles the whole cluster; and idle GPUs are the most expensive thing you own. Then close on commitment — "that is where networking is going, and it is exactly the team I want to be on." That sequence proves you understand the problem AMD's AI-networking line is built to solve, not just the buzzwords around it.
Your 60-second CV
The common thread in my CV is low-level C at the hardware/software boundary. My strongest experience is production TX DSP firmware on an RTOS-based modem SoC: implementing 3GPP PHY behaviour, owning feature work, adding Google Test coverage, supporting CI and release, and debugging across firmware, RF, power amplifier, calibration, and test teams. I am used to systems where software decisions have direct timing and hardware consequences.
The deepest example is a 5G TX-channel arbiter I owned on the DSP. Scheduler modules submitted transmit requests through an API; the arbiter evaluated them at a precise point in the scheduling period, using n1 and n2 as the look-ahead window and commit deadline. It selected the winning request and fired a callback into that module, which programmed the TX accelerators through descriptors over shared AXI DMA. The accelerators included BSRP and the DFE; my ownership was the arbiter, request timing, descriptor-facing control path, and real-time behaviour, not the BSRP or DFE signal-processing kernels. The code was interrupt-driven, ISR-sensitive, and hard real-time, so bugs had to be reasoned about in terms of ownership, ordering, visibility, and bounded latency.
That is why I see AMD networking as an adjacent move, not a reset. Wireless PHY and Ethernet NIC datapaths are different domains, but the engineering pattern is familiar: hardware-visible state, constrained C, DMA-driven data movement, timing pressure, and cross-team debugging. I have not shipped a production Linux Ethernet NIC driver, and I would not pretend otherwise. The transferable part is that I already think in terms of queues, deadlines, callbacks, descriptors, interrupts, observability, and hardware/software contracts. Public AMD/Solarflare material around Onload and ef_vi points to the low-latency, hardware-facing networking stack I want to grow into: reducing kernel-path overhead while preserving correctness and isolation in real products (AMD Onload User Guide, AMD `ef_vi` section).
- Arbiter decision logic maps to a NIC TX scheduler or packet pacer: choose what can transmit, when, and under which constraints.
- Request API plus callback maps to a
descriptor ring,doorbell, and completion model: software publishes work, hardware consumes it, and ownership comes back. - Shared
AXI DMAmaps toPCIe DMAand bus-mastering: visibility, ordering, and buffer ownership. - ISR-driven timing maps to interrupt-versus-poll tradeoffs: jitter, determinism, latency outliers, and hot-path work.
- The
n1/n2right-moment problem maps to tail latency, deadlines, and hardware timestamping, which are central themes in the Solarflare low-latency lineage.
The bridge: your TX arbiter → a NIC datapath
The bridge I would make is not “wireless PHY equals Ethernet.” They are different protocol domains. The bridge is the control problem around a hardware datapath: ownership, timing, memory visibility, bounded latency, and evidence when something goes wrong.
In my 5G TX work, the centrepiece was an arbiter. Scheduler modules submitted requests through an API. At a precise point in the scheduling period, the arbiter decided which request won. The n1 / n2 timing parameters effectively gave us a look-ahead window and a commit deadline: the system could see enough of the near future to make the right decision, but it still had a hard point where ownership had to become final.
The NIC analogy I would use is a TX scheduler or pacer. In my system, a module submitted a request, the arbiter selected a winner, and then fired a callback into the owning module. That module programmed the TX accelerators using descriptors over a shared AXI DMA. In a NIC datapath, the comparable shape is: software publishes descriptors into a TX ring, makes them visible to the device, rings a doorbell, and later observes completion. The mechanism changes, but the reasoning pattern is familiar.
arbitermaps to a NICTX scheduler/pacer- request API plus callback maps to descriptor ring, doorbell, and completion
- shared
AXI DMAmaps toPCIe DMA/ bus-mastering ISRtiming maps to interrupt-versus-poll tradeoffs, jitter, and determinism- the “right moment” plus
n1/n2maps to deadlines, tail latency, and hardware timestamping
Verified public context: AMD’s Onload documentation describes kernel-bypass acceleration where applications can directly access a partition on the adapter, and the ef_vi section describes direct layer-2 access to the Solarflare adapter datapath with lower overhead for applications willing to own more protocol behavior AMD Onload User Guide, AMD `ef_vi`. Interview-useful inference: that makes timestamping, queue ownership, and TX/RX boundary behavior central topics in this lineage, so my best bridge is to show how I reason at exactly that boundary.
The first deep spot is ordering before the doorbell. In my arbiter work, once a winner was selected, the downstream owner had to see a coherent decision before programming the accelerator. In a NIC TX path, the equivalent rule is stricter and very concrete: fill the descriptor, make the descriptor memory visible in the required order, then ring the doorbell. The device must never be able to fetch a half-written descriptor. I would expect to think carefully about memory barriers, cache coherence, DMA visibility, and the exact ownership transition between CPU and device.
/* publish descriptor contents before notifying device */
tx_desc[i] = desc;
dma_wmb();
write_doorbell(q, i);
The second deep spot is submit-API versus ISR concurrency. In the arbiter, a module could submit through the API while the arbiter ISR was running or about to run. That creates the same class of producer/consumer problem as a NIC ring: who owns the slot, when does the consumer see it, what happens at wraparound, and how do we avoid losing a request or consuming one too early? I am comfortable reducing those bugs to ownership state, visibility rules, and edge-case tests rather than treating them as vague timing problems.
My honesty boundary is important here. I owned the arbiter deeply. I configured BSRP through descriptors and understood its timing budget, and I worked with the DFE programming path, but I did not write the DSP signal-processing kernels inside BSRP. So I would not claim to be a DSP algorithm owner. The transferable part I can defend is the hardware-facing scheduling, descriptor programming, ISR behavior, real-time timing, and debugging across the software/hardware boundary.
The way I would present the transfer is this: in 5G TX firmware I learned to define ownership, prove visibility, bound the hot path, instrument the boundary, and test the edges. In NIC datapath work, the objects become rings, DMA mappings, PCIe ordering, interrupts or polling, completions, timestamps, and packet latency. The domain changes, but the engineering discipline is the same: make ownership explicit, make timing measurable, keep the hot path small, and make boundary failures diagnosable.
Owning the gap honestly
Say the gap plainly: I have not shipped a production Linux netdev driver, and I should not present myself as if I have. My production background is embedded C firmware for RTOS modem SoCs and 5G TX DSP work, not Linux Ethernet driver ownership.
Frame the ramp without shrinking the risk: the gap is real, but it is a domain ramp rather than a change in the kind of engineer I am. I am moving from one communications datapath to another: from 3GPP PHY behavior, DSP timing, firmware/RF/calibration boundaries, and release-quality modem code into Ethernet/NIC concepts such as RX/TX rings, DMA mappings, queue ownership, PCIe ordering, driver/firmware contracts, and packet latency.
That is the honest bridge to make with Miklos Reiter. The public brief suggests he is likely to care whether the CV is explained clearly without exaggerating Linux NIC-driver experience, especially given the Solarflare/Onload lineage. The useful line is not "I have already done this exact job." It is: "I have shipped production C at the hardware/software boundary, I know how to debug timing and ownership problems under release pressure, and I am deliberately ramping into the Linux/NIC-specific parts."
Early contribution while ramping: I would expect to start with contained, evidence-led work rather than pretending to own the whole stack on day one:
- C fixes in bounded areas after learning the local build, test, and review flow.
- Diagnostics that make driver, firmware, queue, or packet-path state easier to inspect.
- Contained bug fixes where the failure can be reproduced, instrumented, and verified.
- Test and observability improvements around edge cases, regressions, counters, logs, and trace points.
- Systematic debugging of hardware/software boundary issues: ownership, ordering, timing, state transitions, and release reproducibility.
Interview wording to use: "I have not shipped a production Linux NIC driver. I would rather be precise about that upfront. The reason I still think this is a credible move is that I am not changing from high-level software into low-level systems; I am changing communications domains. My job is to ramp fast on Linux networking and the Solarflare-style stack while contributing early through C, diagnostics, tests, contained fixes, and disciplined debugging."
What he's testing in 30 minutes
What he wants: A CV story that makes the move feel adjacent, not random. Lead with low-level C at the hardware/software boundary: production TX DSP firmware, timing constraints, hardware-visible state and tests. AMD NIC work changes the domain from 5G PHY to Ethernet datapaths, but keeps the same engineering center of gravity.
How to show it: Use a 60-90 second narrative: "My strongest fit is production embedded C close to hardware. I have shipped 5G TX DSP firmware on RTOS modem SoCs, turning 3GPP PHY behavior into tested release code. I am now moving that background toward NIC datapaths: queues, descriptors, DMA, drivers and kernel-bypass networking." Keep the bridge explicit.
What he wants: Defensible claims. Any impressive word can get one follow-up: kernel bypass, DMA, driver, TCP/IP, ef_vi, Onload. He is checking whether you know what you have shipped versus studied.
How to show it: Mark the boundary first: "I have shipped production 5G TX DSP firmware; I have not shipped a Linux NIC driver. My NIC work so far is self-study around descriptor rings, DMA ownership, Linux networking and user-space datapaths." AMD documents Onload and ef_vi in the AMD Onload User Guide and `ef_vi` section. Treat those as verified facts, not insider knowledge.
What he wants: A specific "why AMD, why this team" answer. Verified public facts: Red Hat discusses Solarflare Cloud Onload; AMD sells Solarflare X4 Ethernet adapters; AMD positions the Pensando Pollara 400 AI NIC in AI networking. AMD's Xilinx acquisition is broader platform context, not proof of this team's work.
How to show it: Say the inference carefully: "What attracts me is the former Solarflare lineage around ultra-low-latency NICs, Onload and ef_vi, where C-level choices affect latency and tail behavior. I also see AMD investing publicly in AI networking. I do not assume the Cambridge team's roadmap; I am using public material as the reason this role fits."
What he wants: Evidence you can ramp without creating risk: learn the system before broad changes, and respect the cost of careless fast-path edits.
How to show it: Give a first-90-days plan: get build, test and hardware setup working; reproduce known tests; trace RX/TX through queues, descriptors, ownership transitions and completions; take diagnostics and contained bug fixes; then move to bounded performance or feature work once the queue/descriptor model and measurement setup are clear.
What he wants: Someone easy to manage while ramping: clear status, honest uncertainty, ownership and low drama when corrected.
How to show it: Use direct operating principles: "I communicate early when blocked, separate facts from assumptions, write down what I have verified, and ask for review on risky paths. I am comfortable taking feedback, but I still own the follow-through: reproduce, explain, fix, test and report the result." That matters as much as technical depth.
📋 Live job ad + fresh reports (2026)
Fresh public-source pass (checked 2026-06-17). Anonymous interview reports are pattern-matching, not guarantees — but the live job ads and AMD docs are firm signal.
The live Cambridge job ad names the gap. AMD's current Cambridge networking role (job 72655) asks for: 2+ years software, commercial C, low-level algorithms/data structures, embedded systems ideally with device drivers, PCIe, hardware/software co-design, Linux, Python/scripting, Ethernet/TCP-IP, and communication. A sister Cambridge listing (job 80314) explicitly wants engineers to design and implement Linux network device drivers. So the driver gap is real and named — pre-empting it isn't optional, and your embedded-C + hardware/software-boundary experience is squarely what they list.
Will this call be technical? Calibrated read: ~65% chance of *some* technical content, but ~85% of that is verbal and CV-led, not a coding exercise. Live coding or full driver design in *this* call: under 5%. So rehearse explaining mechanism out loud — not whiteboarding. Don't assume "manager round" means non-technical when your CV is full of low-level nouns; he may do light checks on DMA, descriptor ownership, interrupts vs polling, endianness, bit ops, structures, and kernel-vs-user split.
The manager round is a risk filter before panel time. The strongest UK process report is HR 30 min → hiring-manager 30 min general CV overview → four 45-min engineer rounds. A separate AMD manager-round report describes a brief 30-minute hiring-manager conversation to understand the role and discuss work background, with the prompt "discuss an interesting or notable problem you worked on." The manager call decides whether four engineers' time is worth spending on you.
Most-likely questions in *your* manager call:
- "Walk me through your CV / current role."
- "Explain one project in detail — what did you personally own?"
- "Tell me about a notable hard bug / debugging problem."
- "How do you learn an established codebase?"
- "Why AMD / why this networking team?"
- "What is your Linux / NIC-driver experience, exactly?"
- "How does your embedded firmware map to PCIe / Ethernet / TCP-IP / device-driver work?"
- A culture probe seen in reports: "Can you adhere to a team's existing conventions, or are you rigid in your personal style?" — for a mature inherited driver codebase, answer with humility plus early review.
- Light checks from his own vocabulary:
DMA/ descriptor ownership / interrupts, endianness, bit operations, structures.
The team is actively shipping, so talk operations not just speed. The current Onload User Guide (rev dated 2026-06-08) lists live work on X4 transmit descriptor-ring sizing, NIC-reset filter handling, shared-buffer resource management, and sub-nanosecond timestamping; the public OpenOnload repo ships a version of the sfc driver and tracks recent kernels closely. That tells you the day-job is maintaining a real Linux-facing product across moving kernel versions — so frame answers around reset/recovery, kernel compatibility, diagnostics and supportability, not only the fast path.
Miklos read — verified vs inferred. Verified: Senior Manager Software Development at AMD Cambridge; Solarflare → Xilinx → AMD; led the Cloud Onload Operator (Kubernetes device-plugin, Multus/macvlan/ipvlan, Node Feature Discovery, kernel-module loading, user-space lib injection); Cambridge maths/OR PhD on internet congestion pricing. No public talks on hiring or interviewing were found. Inference (use to shape tone, don't recite): he likely values engineers who make complex systems *operational*, respects precise ownership boundaries, is comfortable with systems-level trade-offs, and is skeptical of vague analogy — so "wireless PHY is basically NIC work" is weak, while "I haven't shipped a Linux NIC driver, but I've shipped production C at a hardware/software boundary with timing, interrupts, descriptor-style programming, tests and release support" is strong.
Likely questions — and your answers
Walk me through your CV.
The common thread is low-level C at the hardware/software boundary. My strongest example is production 5G TX DSP firmware: an arbiter where modules submit requests, the arbiter chooses at the right point in the period, then calls back into the winner to program TX accelerators through descriptors over shared AXI DMA. AMD is an adjacent move, not a reset: the protocol changes, but the engineering pattern remains ownership, timing, visibility, constrained C, and performance-sensitive data movement.
What do you mean by kernel bypass / DMA / driver?
By DMA, I mean hardware bus mastering memory through descriptors rather than the CPU copying every byte. By driver, I mean the software that initializes hardware, owns queues/registers/interrupts, exposes an OS interface, and handles errors. By kernel bypass, I mean avoiding the normal kernel networking fast path for latency; AMD describes Onload and ef_vi in that Solarflare adapter context (Onload, `ef_vi`). Shipped: embedded C, AXI DMA, descriptors, ISRs, hard real-time. Studied: Linux NIC drivers, PCIe, Onload, ef_vi, kernel bypass.
Why AMD and why this team?
The attraction is the Solarflare lineage: ultra-low-latency NICs, Onload, ef_vi, and close hardware/software work. The public Cloud Onload Operator work also shows product reality, not just lab performance (Red Hat). I do not know AMD's internal boundaries, but AMD's public AI-networking direction is also compelling: NIC behavior affects cluster latency, congestion, and fault handling (AMD Pollara).
What would you learn first?
First, I would get the build, test, debug, and hardware setup working. Then I would trace one RX path and one TX path end to end: queue setup, descriptor ownership, DMA mapping, interrupt or polling behavior, completions, resets, and diagnostics. Early contributions would be contained diagnostics and bug fixes; then bounded performance or feature work with clear measurements.
Tell me about a hard hardware/software bug.
The best example is an ownership/timing bug around the TX arbiter boundary. Multiple modules could request accelerator time, the arbiter had to decide within the n1 look-ahead and n2 commit deadline, and the winner programmed BSRP/DFE through descriptors. I did not write the signal-processing kernels; I configured the accelerators and knew their timing budget. The triage was evidence-led: request state, ISR timing, descriptor publication, and callback ordering.
The submit-API vs ISR race: a scheduler module calls the submit API while the arbiter ISR is firing -- how did you keep the request queue consistent?
I treated the request queue as shared state with explicit priority-level ownership. The submit path updated pending fields only inside a short critical section, or under interrupt masking where needed. The ISR consumed a stable snapshot and advanced arbiter state. The rule was single-writer discipline for a field, or a protected handoff.
Data-visible-before-trigger ordering: how did you guarantee the descriptors/data were fully written and visible before the trigger/doorbell fired?
The contract was publish data first, then publish the pointer or trigger. Descriptor fields and buffers had to be complete before the accelerator was kicked, with the required compiler and hardware ordering, such as a memory barrier or platform fence. The NIC mapping is direct: fill the descriptor ring, order writes so DMA can see them, then ring the doorbell.
Starvation / fairness: with multiple scheduler modules competing, how did you stop one starving the others and still hit the deadline?
The arbiter was priority- and deadline-aware, not just first-come-first-served. The n1 window gave look-ahead; the n2 point was the commit deadline. The goal was bounded worst case: choose fairly where possible, but never miss the hard timing point. That maps to NIC TX scheduling, packet pacing, and tail latency.
🎤 Mock drill — manager Q&A, coached
These are the manager/behavioral questions you drilled in the mock — reconstructed with the model answer each one was converging on, plus the trap and the one line that lands it. The coaching verdict across the whole session: your raw material is right, but under pressure it circles, buries the strongest card, and ends on soft words ("curious to explore"). The fix is always the same shape — lead with the strongest card, confront the real question head-on, land each sentence and stop.
Q1 — "Why this move? You're solid PHY/3GPP/DSP, but this is Ethernet, TCP/IP, Linux drivers. Are you just trying to get out of MediaTek — and how do I know you won't miss the wireless work a year in?"
This is the commitment gate. The trap is the word "curious to explore" — to a manager gating £70k it reads *tourist*, the exact fear he's probing. And you must answer the second half ("are you escaping?") out loud, not skate past it. Four beats, ~30s:
- Reframe escape → trajectory. "Let me be honest first — this isn't me running from wireless. I like the work. It's me moving *up the stack* while staying *at the metal*."
- Proof you ramp (your strongest card — lead with it, don't bury it). "I joined the 5G PHY team knowing the fundamentals and nothing about the codebase, and within months I was shipping fixes and debugging real datapath issues in the stack. Ramping fast into a hard new domain — I've already done that once, successfully."
- Make the transfer concrete. "My DSP work lives in non-coherent shared memory with explicit cache maintenance around inter-processor data — that's the same coherence problem as NIC DMA. Hard real-time, latency-critical, right at the hardware/software seam. The medium changes; the core problem doesn't."
- Why now, why this team — the AI hook. "What pulls me to networking now is AI. In distributed training every GPU syncs gradients each step through a collective — an all-reduce — and the whole collective moves at the speed of the slowest link. One stalled NIC doesn't slow one GPU, it stalls the entire cluster, thousands of accelerators, waiting. The network, not the GPU, becomes the bottleneck — that's the whole reason Ultra Ethernet and Pollara exist. And idle GPUs are the most expensive thing in the building, so shaving network latency directly raises utilization on the priciest hardware in the data center. That's exactly where I want to spend the next stage of my career, and this is the team building it."
The upgrade that separates you from the field: don't say "AI is exploding, latency matters" (everyone who read a press release says that) — say the *mechanism*: collective → slowest link → whole cluster stalls → idle GPUs are what you're actually paying for. And close on "I want to be part of the team that delivers this" — commitment, never "curious."
Q1b — "What does 'moving up the stack' actually mean?" (Never say a line you can't defend.) "The stack is the protocol stack. I'm at L1 today — the physical layer: modulation, SerDes, hard real-time DSP, bits on a radio channel. The NIC role sits at L2–L4: Ethernet framing, IP, and the team's signature work — Onload, ef_vi — is TCP/UDP in userspace via kernel bypass. So *up the stack* = from physical-layer signaling to framing, packets, transport; the unit of work goes from 'a symbol on a channel' to 'a packet, a descriptor, a TCP segment.' And *staying at the metal* = I'm not drifting into application or cloud software — still low-level C, drivers, DMA, doorbells, cache coherence, counting cycles. My altitude in the stack rises; my distance from the hardware doesn't. One nuance: a 100GbE NIC has a PHY and SerDes too, so my L1 intuition isn't wasted — I'm adding the layers above what I already know below." That double meaning kills two opposite worries at once: *"is he just doing the same thing?"* (no — up the stack) and *"is he abandoning low-level for app/cloud?"* (no — still at the metal).
Q2 — "Tell me about the nastiest bug you've tracked down — vague symptom, cause could be anywhere, ideally near the hardware/software boundary. And who else was involved?"
The bug you told: an early NTN PoC where, after a long simulation run, the modem went dead to 5G test commands — the 5G DSP was *powered down* by a power-saving module when commands were sent, so they never crossed. A hardware/software-boundary bug in its purest form. Three things a sharp manager docks, and the fix for each:
- Don't make it sound like trial-and-error. "Called the right API with different parameters until it worked" reads as flailing. You weren't flailing — you had a hypothesis (DSP is off → something must wake it → the wake path is an API/register) and you used your *automated build-flash-test* to systematically sweep the candidate calls and watch for the one that flipped the power state. That's hypothesis-driven search, and the automation is the *hero of the fix* — it turned a blind search into a controlled sweep, results in minutes instead of re-flashing by hand.
- Name the instrument. The hinge of the whole story is *how you saw* the DSP was off / the commands weren't crossing — a power-domain status register? a power-management log? a trace? a debugger the developer showed you? That one detail is what makes a manager believe you actually did this. Never leave it blank.
- Answer the collaboration question. Don't tell it solo, and don't over-correct into giving the developer all the diagnostic credit (you become "the legs, not the brain"). Balance: "I collaborated with the automation team on the harness; the developer pointed a direction; *I* did the systematic confirmation."
The spine — situation (early NTN PoC, thin HQ support, you owned the test path end to end — autonomy, not the apology "I had little experience") → symptom (modem dead to 5G commands after a long run) → localize (DSP powered down — *and the tool that showed it*) → root cause + *why* (a power-saving module gates the DSP — was that a legitimate feature the harness didn't account for?) → fix (automation-driven sweep of the wake path) → impact (that wake sequence is still how NTN brings the 5G DSP up in `main` today) → collaboration. Land on impact; drop the opening apology.
Q3 — "Where do you feel least prepared for this job — and what are you actually doing about it?"
Trap on both sides: claim no gap → he stops trusting you; name a gap and shrug → he doubts you'll close it. He wants honesty + initiative + evidence you're already moving. Three beats:
- Honest, bounded gap. "No production experience with Linux drivers or the networking stack — that's the obvious gap."
- What you have that's closer than it looks (lead your rebuttal with this). "But I've debugged real networking problems: I triaged a throughput regression — our device underperforming the reference — and to find the cause I had to understand how lower-layer behavior propagated up into TCP throughput. That forced me to learn TCP for real, from a live performance problem, not a textbook." Then one concrete analogy (not "interesting analogies" — name *one*): "non-coherent shared memory and DMA on my DSP is the same coherence problem a NIC has."
- Concrete plan, led by what you've already done. "I've been reading
ixy, a minimal NIC driver, to see how descriptor rings and DMA work in real driver code, and I'm going through the PCIe and Ethernet standards next." Close on the track record: "The gap is real — but ramping into an unfamiliar domain from fundamentals is something I've already proven I can do once, at MediaTek." That's the reassurance he wants: not "I have a plan" but "I have a track record of executing one."
Q4 — "Tell me about a time you disagreed with a technical decision — ideally one made by someone more senior — what you did, and how it ended." *(You ran out of clock before answering this one — here's the model.)*
Trap on both sides: "I don't really disagree with senior people" → no spine/judgment; "I pushed until I won and they were wrong" → hard to work with. He's listening for: hold a position on the merits, voice it respectfully, and commit gracefully even if overruled. Structure (use a real one — e.g. a design choice on the NTN harness or arbiter path):
- Situation + the disagreement, on the merits. State the technical call, what the senior engineer wanted, and *why you saw it differently* — framed as a risk/trade-off, not a personality clash. ("The proposed approach optimized for X; I thought it would cost us Y under the load profile we'd actually see.")
- What you did. "I didn't argue in the abstract — I brought *evidence*: a measurement / a trace / a small repro that made the trade-off concrete, and I raised it directly but respectfully, one-to-one first." (Evidence-led is your whole brand — use it here too.)
- How it ended — including if you lost. Either: data shifted the decision (own it modestly), *or* you were overruled and you committed fully — "they had context I didn't; I disagreed and committed, made it work, and flagged the risk so we'd catch it early if it bit." The graceful-commit ending is often the *stronger* answer for a manager: it proves you're safe to overrule.
- The lesson. One line on what it taught you about disagreeing well — separate the idea from the person, lead with data, and once the call is made, row in the same direction.
The through-line for all four: lead with the strongest card, confront the literal question he asked (don't answer the one you wish he'd asked), trade headline buzzwords for one concrete *mechanism*, keep sentences short and *land* them, and close on commitment. The real round is a conversation — he'll interrupt and dig in — so you don't need a flawless monologue, just the spine solid enough to hit the beats and stop.
🎤 More manager questions — model answers
These are seven more manager/behavioral questions, beyond the ones in the mock — new topics, same coaching shape. The rule does not change: lead with the strongest card, confront the literal question, use one concrete mechanism instead of buzzwords, keep sentences short and land them, and close on commitment, not "curious." Each block ends with what he's actually scoring.
Q1 — "Tell me about a time you had to learn something hard from scratch, fast, with nobody to hand you the answer."
The strongest card is that you've done this twice, so lead with the one that maps onto this job. "I had to learn TCP under pressure. We had a throughput regression — our device-under-test was underperforming the reference — and the only way to explain it was to follow how lower-layer behavior propagated up into TCP throughput. I didn't take a course; I learned it from a live performance bug, tracing cause from the bottom up." Then the second proof, fast: "Same pattern when I joined the 5G PHY team — I knew the fundamentals and nothing about the codebase, and I ramped by reading it and shipping fixes within months." Close on the meta-skill: "Learning a hard domain from fundamentals, against a real problem, on a deadline — that's the thing I've repeatedly proven I can do. That's exactly what this move asks of me, and I know I can do it because I already have."
What he's testing: can you self-start into an unfamiliar domain without hand-holding — the core risk of hiring you into Linux/NIC work you haven't shipped.
Q2 — "Tell me about a real mistake you made. What broke, and what did you change afterward?"
Don't reach for a fake-humble "I work too hard" — pick a real one and own it cleanly, then show the change. "Early on in the NTN PoC I trusted a clean test pass too quickly. After a long simulation run the modem went dead to 5G commands, and my first instinct was to suspect my test sequence rather than the system underneath it." Name the lesson concretely, not vaguely: "It turned out a power-saving module had powered the 5G DSP down, so commands sent before it woke never crossed the boundary — a real state in the system, not noise in my test. What I changed: I stopped treating a green run as proof and started asking what state the hardware was actually in when a command was issued. I built that assumption into the automation — sweep the wake path, confirm the power domain is up, then test." Close: "That wake sequence is still how NTN brings the DSP up in main today. The mistake taught me to make hardware state explicit instead of assumed — which is the whole game in a datapath."
What he's testing: do you own failure without spin, and do you convert it into a durable change in how you work — not a one-off apology.
Q3 — "This role depends on teams that own silicon and firmware you don't control. Tell me about working with, or depending on, a team that owned the hardware."
Lead with the fact that your whole job already lives on that dependency. "My arbiter doesn't own the accelerators it drives — BSRP and DFE are owned elsewhere. I owned the request API, the arbitration logic, the n1/n2 timing and the callback, but to actually transmit I program those blocks through descriptors over a shared AXI DMA I don't own either." Then the concrete mechanism that proves you respect the boundary: "So I had to treat their hardware contract as law — the descriptor format, the ordering, when a write becomes visible to the block. On non-coherent shared memory that means explicit cache maintenance and hardware semaphores for inter-processor sync; if I get the contract wrong, it fails as a race, not a clean error." On the NTN bug, add: "I also worked across the boundary with HQ and the automation team — thin support, so I leaned on them for direction and owned the confirmation myself." Close: "I'm used to being the software side of a hardware contract I don't control. That's the NIC relationship — the silicon team owns the block, I own getting the datapath to honor its rules."
What he's testing: can you operate across an org boundary on someone else's hardware contract without either overstepping or going passive.
Q4 — "Tell me about something you took ownership of that nobody else owned — work that would have fallen through the cracks otherwise."
Go straight to the NTN PoC, because the ownership was total. "On the NTN proof-of-concept I owned the build-flash-test path end to end, with only thin support from HQ. Nobody was going to hand me a working harness — so I automated the whole loop myself." Then the payoff that proves ownership means results, not effort: "That ownership is what let me fix the dead-modem bug. Because I'd built the automation, I could sweep the wake-path API systematically and watch for the call that flipped the power state — minutes per cycle instead of re-flashing by hand. A blind hardware bug became a controlled search because I owned the tooling." Close on durability: "And the fix outlived the PoC — that wake sequence is still in main. I don't think of ownership as doing the task; I think of it as owning the gap nobody else is standing in front of."
What he's testing: will you pick up the unglamorous, unowned work in a small team — or wait to be assigned tasks with clean boundaries.
Q5 — "Where do you want to be in three to five years? I need to know this isn't a sideways step you'll bounce off in a year."
This is the tourist question in disguise — kill it directly, then ground it in why now. "Three to five years out I want to be the person on this team who owns a piece of the datapath deeply — not learning the domain anymore, but one of the people others come to on the low-level networking path." Then make the commitment specific to AI, with the mechanism so it doesn't read as a slogan: "I'm not arriving on a sideways step. I'm moving toward where I think the next decade of low-level systems work is — AI networking. In distributed training every GPU syncs gradients each step through a collective, an all-reduce, and the collective runs at the speed of the slowest link. One stalled NIC stalls the whole cluster; idle GPUs are the most expensive thing in the building. That's why Ultra Ethernet and Pollara exist, and it's exactly the problem I want to spend years on." Close: "This isn't a stop on the way somewhere else. The thing I want to get deep in is the thing this team builds. I want to be part of delivering it, not passing through it."
What he's testing: commitment and growth trajectory — whether you'll stay and deepen, or treat the role as a stepping stone and leave once you've learned the domain.
Q6 — "Our datapath work has hard deadlines — a packet either makes its window or it's late. Tell me about working under a hard real-time deadline."
Lead with the fact that hard real-time is your native environment, not a stretch. "Hard deadlines are the world I come from. The 5G TX arbiter runs on the radio period — there's an n1 look-ahead window where I can still decide, and an n2 commit deadline after which it's physically too late to program the transmit accelerators." Then the mechanism that shows you think in deadlines, not best-effort: "So arbitration couldn't be best-effort. The decision had to account for whether the selected request's callback could still program its descriptors and meet n2 — if it couldn't, that's a represented state, not an accidental miss. Missing the window isn't a slow path, it's a wrong output on the air." Map it across: "A NIC TX window is the same shape — fill the descriptor, make the writes visible, ring the doorbell before the slot is needed, or you've added latency or dropped the packet. I'm used to code where late equals wrong, and where you design the timing margin in rather than hope for it." Close: "Deterministic behavior under a deadline is the discipline I'd bring on day one."
What he's testing: can you reason about and design for hard timing constraints — the literal nature of datapath work — rather than treating latency as a nice-to-have.
Q7 — "Why should I hire you over a candidate who already has NIC or Linux driver experience?"
Concede first — it's the honest move and it disarms him. "If they also bring strong production discipline and cross-boundary debugging, you might be right to prefer them, and I won't pretend the gap isn't real. I have not shipped a production Linux NIC driver." Then differentiate on the adjacent profile that's genuinely rare: "What I bring is release-quality embedded C in a timing-critical datapath, descriptor-based accelerator programming, and a habit of making hardware/software contracts explicit — the DMA coherence, the memory ordering, the races. Someone who learned NIC drivers in pure software may know the Linux vocabulary but not the metal underneath it; I know the metal and I'm learning the vocabulary — ixy, the PCIe and Ethernet standards." Be honest about the trade for him: "If you need someone to own deep kernel internals from week one, I'm not your lowest-risk hire. If you want someone who ramps fast, contributes immediately at the hardware seam, and has a proven record of learning a hard domain from fundamentals, that's a real and uncommon case." Close: "I'd rather you hire me knowing exactly what I am than oversell and surprise you."
What he's testing: self-awareness under direct comparison — can you make an honest differentiated case without either deflating or overselling against a stronger-on-paper candidate.
🧩 C drill — SPSC ring buffer, reasoned cold
This is the C live-coding exercise you actually drilled — the lock-free single-producer / single-consumer ring buffer — reconstructed as a clean Socratic chain so you can re-run it cold. For each beat: the interviewer's prompt, the model answer, and the trap he's listening for. Don't recite it — re-derive it out loud.
The exercise. *"Implement a lock-free SPSC ring buffer in C. Walk me through why each decision is what it is: why the capacity is a power of two, how you distinguish full from empty, where the memory barrier goes and why, and what you'd do about false sharing."*
Beat 1 — wrap-around & power-of-two. *Why power-of-two capacity?* Model answer: "An index has to wrap when it reaches the end of the array. The naive way is i = (i + 1) % capacity, but % is a division — tens of cycles on a hot path. If capacity is a power of two, the wrap is i & (capacity - 1) — a single-cycle AND. So I store mask = capacity - 1 and index with buf[i & mask]. That's the only reason power-of-two matters: it turns a modulo into a mask." Trap: saying "it's faster" without naming *modulo → AND*. He wants the mechanism.
Beat 2 — full vs empty, the classic ambiguity. *When read == write, is the buffer empty or full?* Model answer: "Both look identical if you wrap the indices, so you need to break the tie. Three classic options: (a) sacrifice one slot — full is (write + 1) & mask == read, so a 4096-ring holds 4095; (b) keep an explicit count; (c) free-running indices that never wrap — empty is head == tail, full is head - tail == capacity, and you only mask *when indexing*. SPSC uses (c)." Trap: the "write first, then check" mistake — you must test fullness *before* writing or you overwrite live data.
Beat 3 — why explicit `count` breaks lock-freedom. *Why not just keep a count?* Model answer: "In SPSC the whole point is no shared mutable state: the producer owns head, the consumer owns tail, each only *reads* the other's index. A count has two writers — producer does count++, consumer does count--. That's a shared read-modify-write, so you're back to needing a lock or an atomic_fetch_add, a locked bus cycle on every enqueue *and* dequeue — exactly the cost you were avoiding. Free-running indices keep single-writer discipline per variable, so no lock and no atomic RMW." Trap: not spotting that count has two writers. This is the insight Lamport (1977) is built on.
Beat 4 — does the unsigned counter overflow? *head is a uint32_t running forever — what happens at 0xFFFFFFFF?* Model answer: "Unsigned overflow is *defined* in C — it wraps mod 2³². And the arithmetic still holds: head - tail is computed mod 2³², so as long as capacity is well below 2³¹ the difference is always the true number of outstanding items, and head & mask is always a valid slot. Empty, full, and indexing all survive the wrap. (Signed overflow would be UB — that's why these are unsigned.)" Trap: thinking overflow is a bug to guard against. It isn't — it's load-bearing.
Beat 5 — the ARM reordering bug (the one that catches people). *Producer writes buf[head & mask] = v; then publishes head. What breaks on ARM that x86 hides?* Model answer: "ARM is weakly ordered — the CPU and compiler may make the head store visible to the consumer core *before* the payload store. The consumer sees the new head, reads the slot, and gets stale garbage. x86 is strongly ordered (TSO) so it rarely bites there, but ARM / POWER / RISC-V will. This isn't caching — it's *store reordering* / visibility." Trap: calling it "a caching problem." Be precise: reordering of when writes become *visible*.
Beat 6 — the fix: release/acquire, not a lone barrier. *How do you fix it?* Model answer: "Express the ordering on the atomic itself, not a standalone fence. The producer publishes with atomic_store_explicit(&head, h+1, memory_order_release) — nothing *before* it (the payload write) can move *after* it. The consumer reads with atomic_load_explicit(&head, memory_order_acquire) — nothing *after* it (the slot read) can move *before* it. The release/acquire pair creates the happens-before edge: payload-write → head-publish → head-load → payload-read. A lone release or lone acquire does nothing on its own; they only work as a pair." Trap: saying "a compiler barrier" — that only stops compiler reordering; the CPU still reorders at runtime on ARM. You need acquire/release (compiles to LDAR/STLR on ARM).
Beat 7 — false sharing. *head and tail are atomics in the same struct — what's the performance bug?* Model answer: "They likely land on the same 64-byte cache line. The producer writes head, the consumer writes tail — different variables, but the coherence protocol tracks whole lines, so the line ping-pongs between the two cores on every operation, ~100–300 cycles a transfer. That's false sharing. Fix: alignas(64) each onto its own line so each core owns its line outright." Trap: not naming the term, or thinking it's a correctness bug. It's purely performance.
**The myth to get crisp — atomics read from *cache*, not memory. You pushed on this in the drill and it's worth nailing, because it can come up: `atomic_load` does not** go to DRAM. On x86 a plain acquire/relaxed load compiles to an ordinary MOV; on ARM to LDAR — both read the L1/L2/L3 cache hierarchy like any load. What memory_order buys you is *visibility ordering across cores*, not data location; coherence (MESI) guarantees the cached value you read is the latest committed one. volatile only stops the compiler keeping a value in a register — the CPU still uses cache. The *only* time a load truly bypasses cache is memory mapped uncacheable — which is exactly the NIC MMIO doorbell register, and precisely why ringing a doorbell is expensive compared to a normal store. That distinction — *normal atomics = cached + coherent; MMIO = uncached* — is the one to have ready, because it's the same split that governs NIC DMA coherency.
The bridge to say out loud (your edge). "On a cache-coherent multi-core, atomics ride the coherence protocol. On a DSP SoC there often *is* no coherence domain across processors, so the inter-processor shared memory is mapped non-cacheable and reads genuinely hit shared SRAM — and 'atomic' across cores leans on a hardware semaphore peripheral, not plain load/store. That's the same coherence split as a NIC descriptor ring: coherent mapping → rely on the protocol; non-coherent → explicit cache clean/invalidate around the DMA buffers; the MMIO doorbell is always uncached. I've shipped the non-coherent side on a DSP — it maps straight onto NIC DMA."
Now write it — the whole thing assembled. Put all seven beats into the struct and the put/get:
#include <stdatomic.h>
#include <stdalign.h>
#include <stdint.h>
typedef struct {
alignas(64) _Atomic uint32_t head; // producer writes; consumer reads
alignas(64) _Atomic uint32_t tail; // consumer writes; producer reads
uint32_t mask; // capacity - 1 (capacity = power of two)
void **buf; // capacity slots
} spsc_t;
// Producer. Returns 0 if full.
int spsc_put(spsc_t *q, void *item) {
uint32_t head = atomic_load_explicit(&q->head, memory_order_relaxed); // we own head
uint32_t tail = atomic_load_explicit(&q->tail, memory_order_acquire); // see consumer's frees
if (head - tail == q->mask + 1) // full: capacity items outstanding
return 0;
q->buf[head & q->mask] = item; // (1) publish payload
atomic_store_explicit(&q->head, head + 1, memory_order_release); // (2) publish index
return 1;
}
// Consumer. Returns 0 if empty.
int spsc_get(spsc_t *q, void **out) {
uint32_t tail = atomic_load_explicit(&q->tail, memory_order_relaxed); // we own tail
uint32_t head = atomic_load_explicit(&q->head, memory_order_acquire); // see producer's writes
if (head == tail) // empty
return 0;
*out = q->buf[tail & q->mask]; // read payload (ordered after the acquire)
atomic_store_explicit(&q->tail, tail + 1, memory_order_release); // free the slot
return 1;
}
The checklist he's scoring — say each one as you go: power-of-two → mask (modulo killed) · free-running indices (no full/empty ambiguity, no wasted slot) · single-writer per index (why count breaks lock-freedom) · unsigned overflow is safe and load-bearing · weak memory ordering on ARM · release/acquire pair as the happens-before edge · false sharing → alignas(64). Hit all seven and you've walked the whole thing from first principles.
🧩 More C / datapath follow-ups
These are the second-layer follow-ups an interviewer pushes after the ring-buffer mechanics are nailed: descriptor lifecycle, DMA coherency, doorbell cost, polling vs interrupts, and the offloads above them. Mechanism first, then where it maps onto my real DSP / AXI-DMA / descriptor work, with an honest line on what I've studied vs shipped.
1. Walk a TX packet end to end. Who owns the buffer and the descriptor slot at each step, and how does the driver know it can reuse a slot?
The slot has exactly one owner at a time; ownership transfers, it isn't shared. Steps:
- Driver allocates/owns a packet buffer and fills it with the payload.
- Driver writes the descriptor: buffer physical (DMA) address, length, flags. While writing, the driver owns the slot.
- Driver issues a release barrier so the descriptor body is visible before the slot is handed off, then publishes ownership: either it sets an OWN bit the NIC polls, or it advances the producer index. After this point the NIC owns the slot — the driver must not touch it.
- Driver rings the doorbell (MMIO write of the new producer index) to wake the NIC.
- NIC DMA-fetches the descriptor, then DMA-reads the buffer, puts it on the wire.
- NIC signals completion: it writes a completion/event entry (or flips the OWN bit back) and DMA-writes an updated consumer/completion index back to host memory.
- Driver sees the completion (polling that index, or via interrupt), reclaims the slot and frees/recycles the buffer. Ownership is back with the driver.
The driver knows a slot is reusable purely from this ownership signal — completion index or OWN bit — never from a timer or a guess.
Bridge: This is exactly my AXI-DMA descriptor rings on the DSP: I built descriptor chains, set a hardware-owned bit, kicked the engine, and reclaimed on the completion interrupt. The NIC TX ring is the same producer/consumer ownership handshake at a larger scale.
2. Coherent vs streaming DMA mappings — when do you use each, and what explicit steps does a non-coherent system force?
A coherent (consistent) mapping is memory the device and CPU can both touch with hardware keeping caches in sync (or the region mapped uncached); you use it for long-lived control structures like descriptor rings and index/doorbell-shadow areas where both sides poke constantly. A streaming mapping is set up per-transfer for the bulk packet payload, with a direction (to-device or from-device), and torn down (unmapped) when the transfer completes.
On a non-coherent system the software must do the cache maintenance the hardware isn't doing:
- Before the device reads host memory (TX), clean/flush the payload out of CPU cache to DRAM, so the device's DMA sees the real bytes.
- Before the CPU reads device-written memory (RX), invalidate those cache lines first, so the CPU re-fetches from DRAM instead of reading stale cached data.
Direction matters because it tells the DMA layer which of clean-vs-invalidate to do. You also respect the ownership window: don't touch a streaming buffer between map and unmap.
Bridge: This is precisely my non-coherent shared-memory work — I hand-managed clean-before-DMA and invalidate-before-CPU-read on a DSP with software-managed coherence. Honesty: On Linux I'd be calling dma_map_single / dma_sync_single_for_device / _for_cpu rather than raw cache ops; same semantics, I'd confirm the exact API in the tree.
3. Why is the doorbell always uncached MMIO and not a normal cached write?
The doorbell is a register in the device, not a memory location — its job is the side effect of poking the NIC, and that side effect must actually leave the CPU. A cached write could sit in the store buffer / cache indefinitely and coalesce, so the NIC would never be told. Mapping it uncached (device memory) forces every write to go out on the bus to the device. That's also why it's the one place you accept the cost: it's the explicit "go" signal.
Bridge: Same reason I never cached an AXI peripheral control register — writes to a device must take effect, not get absorbed by a write-back cache.
4. volatile vs `_Atomic` vs a memory barrier — what does each actually guarantee, and what does it NOT?
volatile: the compiler must emit the load/store and may not cache the value in a register or elide the access. That's it. It does NOT give ordering between cores, does NOT prevent the CPU from reordering, and is NOT atomic. Its real use is single-threaded access to memory-mapped device registers.- A memory barrier (fence): orders memory operations relative to each other — e.g. a release barrier guarantees prior stores are visible before a later store. It constrains ordering but does not by itself make any single access atomic or stop the compiler from caching an unrelated value.
_Atomic/ C11 atomics: indivisible read-modify-write or load/store, plus an attached memory-ordering parameter (relaxed/acquire/release/seq_cst). This is the right tool for cross-core shared indices — it bundles atomicity and the ordering you need.
The classic mistake is using volatile for inter-thread synchronization: it stops register caching but gives you no ordering and no atomicity across cores.
5. Posted vs non-posted PCIe, and why you avoid an MMIO read on the fast path.
An MMIO write is a posted transaction: the CPU fires it and moves on, no acknowledgement waited for — relatively cheap, fire-and-forget. An MMIO read is non-posted: the CPU issues the request and must stall until the device returns the data, a full round-trip across the PCIe fabric — hundreds of nanoseconds to microseconds. So on the datapath you push state to the host (NIC DMA-writes its consumer index into host memory, the driver reads that cached copy) instead of reading a device register. Write-combining can further batch multiple posted writes into one burst where the region allows it. The rule of thumb: writes to the device are cheap-ish and posted, reads from the device are expensive round-trips you design out of the hot loop.
Bridge: I learned this the hard way on embedded buses — polling a status register in a tight loop kills latency; mirroring device state into a memory the CPU reads cheaply is the fix, which is exactly the host-resident index pattern here.
6. Why ring the doorbell once per batch, and how do producer/consumer indices make that work?
Each doorbell is a posted MMIO write plus a wakeup of the NIC — small but not free, and per-packet it dominates at high rates. Because the producer index is a single number that says "everything up to here is ready," you can fill N descriptors, issue one release barrier, then write the producer index once. The NIC then processes the whole run. Completions amortize the same way: the NIC advances a single consumer/completion index, so the driver reclaims a whole batch of slots in one sweep (a loop from old index to new index) instead of one event per packet. One index update describes an arbitrary-length run, so both submission and reclaim are batched.
// fill a batch, publish once
for (i = 0; i < n; i++)
fill_desc(&ring[(prod + i) & mask], pkt[i]);
atomic_thread_fence(memory_order_release);
prod += n;
write_doorbell(prod); // one posted MMIO
7. Interrupt vs busy-poll, plus NAPI and interrupt coalescing — what's the trade-off?
An interrupt is efficient when traffic is sparse: the CPU sleeps and is woken only on work, but each interrupt costs a context switch / handler entry and adds latency (the wake-up delay). Busy-polling spins reading the completion index, so it catches work the instant it lands — lowest latency — at the cost of burning a core 100% even when idle. For ultra-low-latency trading-style workloads you pay that core and poll.
In between:
- Interrupt coalescing: the NIC holds off and fires one interrupt for several packets or after a short timer, trading a little latency for far fewer interrupts under load.
- NAPI: interrupt on the first packet, then mask the interrupt and poll the ring to drain a batch, re-enabling interrupts when it goes quiet — you get interrupt efficiency at idle and poll-like throughput under load.
Honesty: I've run hard-real-time ISRs and tight poll loops on a DSP and I understand the latency-vs-CPU trade directly; NAPI specifically I've studied rather than shipped in a Linux driver.
8. What does kernel bypass (Onload / ef_vi) change about this picture, and how do the two differ?
Kernel bypass maps the NIC's queues and a slice of packet buffers directly into the application's address space, so the fast path — doorbell, descriptor posting, completion polling — happens in user space with no syscall and no kernel networking stack in the way. That removes context-switch and copy overhead and makes busy-polling from the app natural.
- Onload keeps the normal BSD sockets API: existing
send/recvcode runs unchanged, but the TCP/UDP processing and the datapath are done in a user-space library that talks to the NIC directly, falling back to the kernel for the slow path. You get bypass latency without rewriting the app. - ef_vi is the lower-level layer-2 virtual interface: the application directly owns NIC receive/transmit queues, the packet buffers, and the event queue, and posts/reaps descriptors itself. There's no sockets abstraction and typically no built-in TCP — the app (or a library on top) owns more of the protocol behavior. It's the most control and lowest overhead, at the cost of doing more yourself.
So Onload trades a little control for a drop-in sockets API; ef_vi hands you the raw queues and events that look a lot like the descriptor-ring machinery in the rest of these answers.
Honesty: This is Solarflare's own stack — I've studied the Onload/ef_vi model and it maps cleanly onto descriptor rings I've built; I haven't run it in production, so I'd ramp on the exact ef_vi calls in the codebase.
9. MESI in one breath, and how it connects to false sharing.
MESI is the cache-coherence protocol that keeps per-core caches consistent. A line in a core's cache is in one of:
- Modified: this core has the only, dirty copy; memory is stale.
- Exclusive: this core has the only, clean copy.
- Shared: multiple cores may hold this clean line read-only.
- Invalid: not valid here.
When a core wants to write, it must get the line into Modified, which means sending an invalidate so every other core drops its copy to Invalid. That invalidation traffic is the cost. False sharing falls straight out of this: two cores writing two different variables that happen to live in the same 64-byte line still bounce that one line Modified-to-Invalid between them on every write, because coherence works at line granularity, not variable granularity — even though the variables are logically independent. Padding/aligning the hot variables to separate cache lines stops the ping-pong.
Bridge: This is the hardware reason behind the alignas(64) separation of the producer and consumer indices in the ring — MESI is why touching one shouldn't invalidate the other.
🧠 Concept check — quick-fire
Rapid-fire concept check — cover the question, then read the answer; if it doesn't come out crisp and cold, you don't own it yet.
Ring buffer & indices
Why must ring capacity be a power of two? So the wrap is a single AND: i & (cap - 1) instead of a % division. You store mask = cap - 1 and mask every index.
What are the three ways to tell full from empty? Sacrifice one slot (full when (head + 1) & mask == tail); keep an explicit count; or use free-running indices where empty is head == tail and full is head - tail == capacity.
Why does an explicit count break lock-freedom in SPSC? Both the producer and consumer must write count, so two writers touch one variable — that needs a lock or an atomic read-modify-write. Free-running indices keep one writer per index.
Is unsigned index overflow a bug? No. Unsigned overflow is defined wraparound mod 2^N, and the subtraction head - tail still yields the correct outstanding distance across the wrap, as long as capacity is a power of two that divides 2^N.
What is the single-writer discipline? Each index has exactly one writer; the other side only ever reads it. That is the core SPSC invariant that lets you drop locks — producer owns head, consumer owns tail.
Memory model & ordering
Weak vs strong memory model? ARM, POWER, and RISC-V are weakly ordered and freely reorder loads/stores, so you need explicit barriers. x86 is TSO (total store order), strongly ordered — only store-load can reorder.
What does a release store do? What does an acquire load do? A release store publishes everything written before it (no prior memory op moves after it). An acquire load makes everything after it see those writes (no later memory op moves before it).
Why do release and acquire only work as a pair? They create a happens-before edge: the acquire load that reads the released value is guaranteed to see all writes the releasing thread did before the release. One half alone establishes no ordering across threads.
What do release and acquire compile to on ARM? Release store becomes STLR, acquire load becomes LDAR — store-release / load-acquire instructions, no separate fence needed.
Caches & coherence
Does atomic_load go to DRAM? No — it reads the cache hierarchy, and coherence guarantees you get the latest value. On x86 a plain (relaxed/acquire) atomic load is just a MOV.
volatile vs atomic? volatile only stops the compiler from caching the value in a register and forces the access; it gives no cross-core ordering and no atomicity. atomic gives both.
When does a load truly bypass cache? Only on uncacheable mappings — for example a NIC MMIO doorbell or status register mapped uncached. Normal memory always goes through cache.
Why is a doorbell / MMIO write expensive versus a normal store? It is uncached and travels out over PCIe. A posted write you fire and forget, but an MMIO read is non-posted — a full round-trip to the device and back, hundreds of ns.
MESI in one line? Modified / Exclusive / Shared / Invalid: a write must gain Modified, which invalidates every other core's copy of that cache line before the store completes.
What is false sharing and how do you fix it? Two hot variables share one 64-byte cache line, so writes from different cores ping-pong the line back and forth even though the data is logically independent. Fix by padding/aligning each to its own line with alignas(64).
DMA & descriptor rings
DMA coherency in one line? A coherent mapping relies on the cache-coherence protocol so no flushing is needed; a non-coherent mapping needs a cache clean before the device reads and an invalidate before the CPU reads.
What is a descriptor ring? A ring of fixed-size descriptors in memory that hand buffer addresses and lengths between CPU and NIC, each side advancing its own index.
Give the TX lifecycle in order. Allocate buffer, fill the descriptor (address/len/flags), order the writes with a barrier, ring the doorbell, the NIC DMA-fetches the descriptor and data, it writes a completion, then the driver reclaims the buffer.
Where does the memory barrier go? Fill the descriptor and buffer first, then a barrier, then the doorbell — publish the data before the pointer/trigger, so the device never fetches a half-written descriptor.
Networking & latency
Kernel bypass: Onload vs ef_vi in one line each? Onload is a transparent user-space TCP/UDP stack that accelerates existing sockets with no code change. ef_vi is the low-level layer-2 API giving raw access to the NIC's rings for maximum control and minimum latency.
Interrupt vs polling at low latency? Busy-poll to eliminate interrupt-delivery latency at the cost of a burned core; NAPI takes one interrupt then polls a batch; interrupt coalescing trades latency for fewer interrupts and lower CPU.
TSO / LRO / GRO in one line? Offloads that cut per-packet CPU: TSO segments one big buffer into MTU-sized packets in the NIC on TX; LRO/GRO reassemble many received packets into one large buffer on RX.
What is the AI-networking hook? A GPU all-reduce runs at the speed of the slowest link, so one stalled NIC stalls the whole collective and the entire cluster; idle GPUs are the most expensive thing in the building, which is exactly why Ultra Ethernet and AMD Pollara exist.
Your 5G analogy
What were n1 and n2 in your 5G arbiter? n1 is the look-ahead window (how far ahead you schedule) and n2 is the hard commit deadline (the slot by which the decision must be locked) — the same latency-discipline pattern as descriptor publish-before-doorbell timing.
What does "up the stack, at the metal" mean? Move from L1 PHY physics up to L2-L4 packets and transport, but stay in low-level C, drivers, and DMA — going up the protocol stack without going up into apps or cloud.
⚠️ Traps & recovery — the follow-up chains
A skeptical manager can expose technical inflation in under five minutes. These are the follow-up chains most likely to do it — and the exact sentence that stops each spiral. The pattern that beats all of them: what I did → what I did NOT do → the mechanism/invariant I can defend.
Chain 1 — the soft "no". "Have you written a Linux kernel driver?" → "Not directly, but I've worked close to drivers." → "Close how? Have you shipped code in the kernel?" → the spiral has begun. The tell is "close to drivers", "driver-like", "same concepts" — a manager hears you answering the question you *wish* he asked. Escape: "No. I haven't shipped a production Linux kernel or NIC driver. My shipped depth is embedded C at a hardware/software boundary: interrupts, hardware-visible state, descriptor-programmed accelerators, hard timing, tests, release support. The fit case isn't that I'm already a NIC-driver engineer — it's that I have the low-level C discipline to ramp into it."
Chain 2 — ownership blur. "Walk me through the arbiter." → "It arbitrates between modules and programs BSRP/DFE." → "What exactly did *you* write?" → "I worked on the arbiter and the accelerator interaction." → "So you configured a block someone else designed?" The tell is blurred verbs: worked on, handled, managed, dealt with. Escape: name the owned code paths — request API, arbitration logic, n1/n2 timing windows, callback path, descriptor sequence, tests — and explicitly disown the DSP kernels. Then turn it into a strength: "that exact boundary is why it's a useful story here — production hardware/software work *is* ownership contracts between software, firmware, and blocks you didn't design."
Chain 3 — the API-vs-ISR race (most likely bluff-exposer). "What contexts touch the request state?" → "scheduler writes, arbiter reads." → "Could the task-context API update a request while the arbiter ISR is selecting it?" → "We had locks." → "What lock works in an ISR on a DSP? Masking? Atomic flag? Double-buffering? Versioning?" The fatal move is saying "we had locks" when you don't remember the exact primitive. Escape: describe the *invariant*, not a half-remembered primitive — "request state can't be both mutable by the submitter and consumable by the arbiter at the same time. The safe patterns are a short critical section around publication, a ready/valid bit written last, double-buffered slots, or versioning so the ISR never reads a partial update. I'd verify MediaTek's exact mechanism rather than invent it." Recovery if you already said "locks": "Let me be more careful — 'lock' was too vague; what matters is the publication and ownership protocol."
Chain 4 — descriptor-ring lifecycle. "What's a descriptor ring?" → "A circular buffer for DMA." → "That's a definition. Walk me through a TX packet." → "Who owns the buffer before and after the doorbell?" → "How does the driver know it can reuse the slot?" The tell is vocabulary fragments with no lifecycle. Escape: allocate → fill → order writes → doorbell → DMA fetch → completion → reclaim, with ownership at every step. Tie it back honestly: "mine were TX-accelerator descriptors, not Ethernet packets, but the discipline is the same."
Chain 5 — is `volatile` enough? "You fill the descriptor and ring the doorbell — is volatile enough?" → "It stops the compiler optimising it away." → "Compiler order isn't CPU/device ordering. What barrier do you need, and why?" The trap is knowing the slogan "volatile isn't enough" but not why. Escape: "No. volatile affects compiler treatment of an access; it doesn't give the device a correct publication protocol. Descriptor and buffer writes must be visible to the device *before* the doorbell, so you need the right DMA/barrier primitive for the mapping and architecture — I'd use the kernel's barrier primitives, not hand-roll it." Honesty clause: "I know the principle and the failure mode; I'd check the codebase's house style before naming the exact macro."
Chain 6 — `Onload` vs `ef_vi`, one level past the slogan. "Explain the difference." → "Onload is kernel bypass for sockets, ef_vi is lower-level." → "Lower-level how? What does the application become responsible for?" → "...performance tuning." → "No — protocol behaviour, packet construction, event handling, queue ownership." Escape: "Onload preserves a sockets-style model while bypassing the kernel fast path; ef_vi is a lower-level layer-2 virtual interface where the app owns NIC queues, packet buffers, events and more of the protocol. I've studied the model — I haven't run either in production, and I'll say so."
**Chain 7 — "why leave wireless? why not *any* AMD job?"** "New challenge, AMD's a great company" → "That's generic. Why *this* team?" → "I like low-level systems" → "You could say that to GPU, CPU, automotive. Why networking?" Escape: name the exact adjacency — "hardware-facing datapath software: queues, descriptors, DMA, interrupts vs polling, tight latency budgets, contracts with silicon. My depth is 5G TX DSP firmware; this is a deliberate move into NIC datapaths, not a random AMD application."
Chain 8 — TCP/IP depth you don't have. "How deep is your TCP/IP experience?" → "I understand the stack." → "Explain retransmission and congestion control interacting with a low-latency NIC. Delayed ACKs? Offloads? TSO/LRO/GRO? Timestamping?" Escape: "My TCP/IP depth isn't production-stack depth yet. I know the fundamentals and I'm ramping; my defensible depth is lower-level — timing, descriptors, interrupts, debug. I'd rather be precise than pretend I've debugged production TCP behaviour."
Recovery phrasebook — memorise three of these:
- "Let me be precise: I haven't shipped that in production."
- "I know the principle, but I won't invent implementation details from memory."
- "The boundary I owned was X; Y was owned by another block/team."
- "That wording was too broad — the safer version is..."
- "If I reason from first principles, the invariant has to be..."
- "I should separate what I've done from what I've studied."
- "I'd verify the exact primitive/API in the codebase before changing that path."
The one rejection to avoid. If you don't prepare, the most likely reason he passes is: *"he's stretching wireless firmware into NIC experience, and under pressure his answers become vocabulary instead of mechanism."* In a 30-minute call, ambiguity is expensive — if he has to spend the whole time discovering the real boundary of your experience, he picks a candidate whose boundary is already obvious. Lead with calibrated honesty, then prove mechanism.
Questions to ask Miklos
Pick 3-4 of these on the day. The best pattern is to start with the role-shape question, ask one ramp-up question, ask one technical-depth question, then close with the direct CV-risk question if there is time.
- "Which part of the stack would this role touch most: Linux host driver, firmware interface, Onload/`ef_vi`, diagnostics, hardware bring-up, performance work, or a mixture?"
This lands well because Miklos has public history close to Solarflare Cloud Onload productization in Kubernetes/OpenShift, and AMD's public docs describe Onload as user-space TCP/UDP acceleration while ef_vi gives lower-level datapath access to raw Ethernet frames (Red Hat Solarflare Cloud Onload article, AMD Onload User Guide UG1586, AMD UG1586 ef_vi section). From a 5G TX DSP background, it shows you are already mapping the role onto real boundary layers: hardware queues, firmware contracts, host software, diagnostics, and latency.
- "For someone coming from strong embedded PHY work rather than shipped Linux NIC drivers, what would you expect me to learn first to become productive here?"
This is honest without sounding weak. It frames the transition around transferable skills: embedded C, timing-sensitive firmware, RTOS debugging, hardware/software interfaces, and production fault isolation. It also invites him to name the fastest ramp path, whether that is Linux driver mechanics, DMA and descriptor rings, Onload/ef_vi, lab diagnostics, or internal test workflows.
- "What are the hardest bugs the team sees most often: PCIe/DMA issues, packet drops, latency outliers, firmware/driver interface bugs, concurrency, reset/recovery, or hardware bring-up?"
This is probably the strongest technical question from your background. It lets you connect PHY issues such as timing, buffers, state machines, and rare race conditions to NIC datapath realities: DMA mappings, queue state, PCIe ordering, packet loss, tail latency, and recovery behavior.
- "How does the team balance the ultra-low-latency Solarflare heritage with AMD's broader public AI-networking direction?"
Keep this phrased as public context, not an assumption about team ownership. AMD publicly positions Solarflare X4 around ultra-low-latency Ethernet, including published latency examples, while Pensando Pollara 400 is positioned for AI networking and 400 Gbps UEC-ready use cases (AMD Solarflare X4 Ethernet adapters, AMD Pensando Pollara 400 AI NIC, AMD networking solutions page). The question shows commercial awareness without pretending to know the roadmap.
- "What would a strong first 90 days look like for this role?"
This turns the interview toward execution. Coming from embedded PHY, it lets you listen for the expected first contribution: contained bug fixes, test coverage, diagnostics, performance analysis, driver/firmware interface understanding, or lab bring-up.
- "Is there anything in my CV that gives you concern, especially around the wireless-to-Ethernet transition, that I can address directly?"
Use this near the end. It is direct and confident, and it gives you a chance to handle the main perceived risk: no shipped production Linux NIC driver. The answer should bring the discussion back to low-level C, hardware/software boundary debugging, production discipline, and fast ramp into Ethernet-specific concepts.
What to avoid
Use this section as a guardrail: the goal is to sound precise, curious, and honest about the domain move, not to force your 5G background to look like NIC experience.
- Do not say wireless PHY is basically Ethernet. Say it is adjacent: both are hardware-facing, timing-sensitive datapaths, but the protocol objects differ. Better: "I am moving domains, not pretending they are identical."
- Do not claim production Linux NIC-driver experience. The strong answer is the honest one: you have production embedded C / RTOS modem firmware experience, and you are ramping on Linux networking, RX/TX rings, DMA, PCIe, Onload,
ef_vi, and kernel bypass.
- Do not overclaim AMD internal structure. Treat Solarflare, Xilinx, AMD, Onload, and Cambridge as public context, not evidence that you know team ownership, roadmap, or unreleased products. The brief explicitly warns not to imply inside knowledge.
- Do not recite product names as badges. If you mention Onload or
ef_vi, explain the mechanism: sockets-compatible kernel bypass versus raw layer-2 direct NIC datapath access, as described in the AMD Onload User Guide and its `ef_vi` section.
- Do not present Pensando Pollara as this team's product. Use it only as AMD public direction: AMD positions Pensando Pollara 400 around AI networking, congestion, tail latency, selective retransmission, and fault handling. Better: "I do not know how AMD splits this internally, but the public direction shows NIC behavior matters at cluster scale."
- Do not lead with compensation. In a 30-minute hiring-manager interview, spend the scarce time on role fit, ramp plan, technical transfer, and the risks he may be testing.
- Do not bring up irrelevant personal or public records. Keep the discussion strictly professional: his public Solarflare/Onload work, AMD networking context, the role, and your fit.
10-minute pre-call checklist
Use the last 10 minutes to load the exact stories and wording you want available, not to learn anything new.
- 60-second CV walkthrough: low-level C at the hardware/software boundary; production 5G TX DSP firmware on RTOS modem SoCs; 3GPP PHY, tests, CI/release; then bridge to AMD NIC datapath work through ownership, timing, visibility, queues, descriptors, and DMA.
- Ownership story: have the UL-DAI-style feature ready: requirement, C design, firmware implementation, Google Test coverage, integration issues, and release confidence.
- Hardware/software bug story: choose one: the TX arbiter issue, or an MCU-DSP ownership/timing/visibility problem. Explain symptom, false leads, evidence, root cause, and fix.
- Cross-team story: prepare one evidence-led triage example across firmware, RF, PA, calibration, and test. Emphasise logs, reproducibility, boundary narrowing, and known versus inferred facts.
- Onload versus `ef_vi`: say it in 30 seconds: Onload is sockets-compatible kernel-bypass with a user-space TCP/UDP stack;
ef_viis raw layer-2 direct NIC datapath where the app owns higher-layer protocols. AMD documents both in UG1586 (Onload guide, `ef_vi` section). - NIC RX/TX ring: verbal model: software fills descriptors, marks ownership, rings a doorbell; hardware DMA reads or writes packet buffers; completions return ownership and status.
- Three questions for Miklos: pick now: which stack layer this role touches most; what a strong first 90 days looks like from embedded PHY; and which bugs are hardest: PCIe/DMA, drops, latency outliers, firmware/driver interfaces, concurrency, or reset/recovery.