How Not to Flash Your Jetson: 19 Attempts and One Kernel Parameter
It took two MacBook Pros, two operating systems, two hypervisors, three flash tools, an OTA upgrade that bricked the bootloader, raw PyUSB debugging, and one kernel parameter change to flash an NVIDIA Jetson AGX Orin 64GB. Over 20 attempts across two days. Here's everything that went wrong, what I learned about USB at the kernel level, and the one-line fix that finally worked.
Why I bothered
The Jetson AGX Orin 64GB on my desk was running JetPack 5.1.2 — L4T R35.4.1, CUDA 11.4, Ubuntu 20.04. Ollama worked, but it was slow. The GPU was being used (CUDA compute 8.7, Ampere architecture) but the driver was old. JetPack 6.2.2 ships with CUDA 12.6, updated GPU drivers, and better memory management. The promised throughput improvement on Nemotron Nano 8B was significant.
"What needs to happen to upgrade the Jetson? I was told it's not running the latest stuff from NVIDIA."
That question kicked off two days of pain.
The OTA attempt that broke everything
NVIDIA doesn't support in-place JetPack major-version upgrades. There's a tool — l4t_generate_ota_package.sh — but it only works within the same major version. I tried it anyway:
Target board(JETSON_AGX_ORIN_DEVKIT) and base version(R35_4) is not supported
So the only path from JetPack 5.x to 6.x is a full reflash: wipe the eMMC and write a fresh image over USB from a Linux host. I backed up everything — dotfiles, SSH keys, systemd services, .env files, git repos — and started.
The first attempt from a UTM VM on the M2 MBP failed mid-write. The Jetson's bootloader was now corrupted. It wouldn't boot at all — just sat cycling into USB recovery mode. What started as a performance upgrade became a rescue mission.
The problem: I don't have a Linux machine. NVIDIA's flash tools require an x86_64 Linux host. No macOS support. No ARM support. All I had was a 2016 Intel MacBook Pro collecting dust and the M2 MBP I work on every day.
Two days of increasingly creative workarounds — with Claude Code as my co-pilot on both machines the entire time.
The phases of failure
Phase 0 (Apple Silicon, attempts 1–4). UTM VM running Ubuntu 22.04 ARM64 with QEMU user-mode emulation for the x86 flash tools. The flash tool detected the Jetson, read its chip info, and timed out on the first USB bulk write. Every time.
Phase 1 (Intel MBP, macOS VMs, attempts 5–10). VirtualBox: USB passthrough wouldn't grab the Jetson. Dead end. VMware Fusion: VM ran, SDK Manager detected the Jetson, started downloading JetPack — then disk space ran out, copy-paste broke, the Mac became unusably slow, and SDK Manager complained about the USB cable. After hours of fighting VMs, I gave up on the macOS-host approach entirely.
Phase 2 (Intel MBP, native Linux, attempts 11–17). Booted the Intel MBP from an Ubuntu 22.04 USB stick. Native x86_64 Linux — exactly what NVIDIA wants. The Jetson showed up in lsusb as 0955:7023 NVIDIA Corp. APX. Recovery mode detected.
Every single attempt died at the very first USB bulk write:
[ ] Sending bct_br
[ ] ERROR: USB write timeout
I tried everything obvious. Different cables. Different flash tools (flash.sh, l4t_initrd_flash.sh, SDK Manager CLI). Different USB hubs. Different physical ports. Fresh downloads with checksum verification. Patched flash.sh to bypass CHIPID detection that was also failing. Same error every time.
The 2016 MacBook Pro has a specific USB topology that matters: Bus 01 is an Intel 100 Series xHCI controller that handles ALL USB 2.0 traffic. The Jetson in recovery mode operates at USB 2.0. So no matter which port I plugged into, every path routed through that single Intel xHCI controller. Hubs and docks don't help — they just add another hop on the same bus.
Phase 3 (back to M2 MBP, attempts 13–18). While the Intel MBP made partial progress, I tried the M2 MBP's modern USB controller. UTM VMs, USB redirection, direct passthrough, raw PyUSB. The result was definitive:
- USB control transfers (endpoint 0): worked. I could read chip ID, board info.
- USB bulk transfers (data writes):
ETIMEDOUT. Every single time.
The "timeout" wasn't really a timeout. It was macOS IOKit returning kIOReturnNotResponding, which libusb maps to ETIMEDOUT. macOS fundamentally blocks USB bulk writes to devices it doesn't recognize. Confirmed by QEMU issue #2178: USB passthrough on Apple Silicon is unusable. The bottleneck is macOS IOKit, not the VM layer.
No one has successfully flashed a Jetson from an Apple Silicon Mac using any method I could find documented. The Apple Silicon path is dead.
The fix (attempt 19)
Back to the Intel MBP. Attempts 11–12 had proved the USB controller could handle small writes — it just choked on larger ones. The Linux kernel's USB filesystem buffer (usbfs_memory_mb) defaults to 16MB. The Jetson flash tool stages a 22.9MB blob transfer. The math is right there.
I'd already tried 1024 MB. Not enough. I doubled it.
# Disable USB autosuspend (kernel was putting the device to sleep between transfers)
echo -1 | sudo tee /sys/module/usbcore/parameters/autosuspend
# 2GB USB filesystem buffer (default 16MB; we'd already tried 1GB)
echo 2048 | sudo tee /sys/module/usbcore/parameters/usbfs_memory_mb
# Disable power management on ALL USB devices
for dev in /sys/bus/usb/devices/*/power/control; do
echo on | sudo tee "$dev"
done
for dev in /sys/bus/usb/devices/*/power/autosuspend_delay_ms; do
echo -1 | sudo tee "$dev"
done
Attempt 19 ran clean from bct_br through the full BSP transfer through the rootfs flash. The Jetson rebooted into JetPack 6.2.2 with a fresh Ubuntu 22.04, CUDA 12.6, and a 540-series driver. About forty minutes end to end once the buffer was right.
What I'd tell NVIDIA
Four small fixes that would save someone else two days:
- Check
usbfs_memory_mbbefore flashing.flash.shalready validates dependencies. Addingif [ $(cat /sys/module/usbcore/parameters/usbfs_memory_mb) -lt 2048 ]; then warnwould catch this before users debug opaque USB timeouts. - Improve the error message. "USB write timeout" gives no actionable information. The flash tool knows the payload size and could suggest
usbfs_memory_mb=2048when a bulk transfer fails on a large payload. - Document USB tuning. The L4T Developer Guide doesn't mention
usbfs_memory_mborusbcore.autosuspend. A "Troubleshooting USB Flash Failures" section would prevent a common class of failures. - Auto-tune in
flash.sh. The script already runs as root. It could temporarily set the parameters for the duration of the flash and restore them after.
The role of Claude Code
The flash odyssey was driven by Claude Code running on both Macs simultaneously. On the Intel MBP, Claude Code set up VMs, configured USB passthrough, sent keystrokes when copy-paste broke, screenshotted the VMware window to monitor progress, SSHed into the live Ubuntu boot to download BSPs and tune kernel parameters, and parsed lsusb -t output to map the xHCI topology.
On the M2 MBP, Claude Code SSHed into the Intel MBP to run flash commands remotely (so I could stay on my main machine), built UTM VMs with QEMU user-mode emulation, wrote raw PyUSB scripts to isolate the macOS IOKit limitation, and researched QEMU upstream issues to confirm the dead end.
The successful attempt #19 was orchestrated entirely from the M2 MBP, SSHing into the Intel MBP's live Ubuntu boot, with two terminal panes, two file trees, and a model that remembered every previous failure mode. The kind of patient, methodical, multi-machine debugging that would have taken much longer solo.
That's the second-order lesson: agentic engineering isn't only for greenfield software. It works for hardware debugging too, especially the messy kind where state is spread across multiple machines and the next experiment depends on the last result. Keep the agent in the loop.
Takeaways
usbfs_memory_mbmatters. The default 16MB is inadequate for flashing embedded devices. If you're getting USB bulk transfer timeouts, increase it to 2048.- USB autosuspend kills flash tools. Always disable it:
echo -1 > /sys/module/usbcore/parameters/autosuspend. - Apple Silicon Macs cannot flash Jetson devices. The limitation is in macOS IOKit, not the hardware. No VM or USB passthrough tool works around it.
- USB 2.0 on MacBook Pros is bottlenecked. All USB 2.0 traffic goes through one Intel xHCI controller regardless of physical port. Hubs and docks don't help.
- VMs add complexity without solving USB problems. Booting native Linux from USB is simpler and more reliable.
- Keep old Intel hardware around. That dusty 2016 MacBook Pro just saved a $2,000 Jetson from becoming a paperweight.
- AI pair programming works for hardware debugging. The methodical elimination across 19 attempts is exactly the kind of work where agents are at their best.
Running into hardware-adjacent AI infrastructure problems? AISOFT operates and supports edge-AI deployments — Jetson, GB10, on-prem GPU. hello@aisoft.us · book a 30-min consult →