summaryrefslogtreecommitdiff
path: root/tools/proxyclient/hv/trace_wlan.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/proxyclient/hv/trace_wlan.py')
-rw-r--r--tools/proxyclient/hv/trace_wlan.py446
1 files changed, 446 insertions, 0 deletions
diff --git a/tools/proxyclient/hv/trace_wlan.py b/tools/proxyclient/hv/trace_wlan.py
new file mode 100644
index 0000000..1e4c4b1
--- /dev/null
+++ b/tools/proxyclient/hv/trace_wlan.py
@@ -0,0 +1,446 @@
+import struct
+from construct import *
+
+from m1n1.utils import irange
+from m1n1.hw.dart import DART
+from m1n1.utils import chexdump
+from m1n1.proxyutils import RegMonitor
+from m1n1.constructutils import *
+
+from m1n1.trace.pcie import *
+
+PCIeDevTracer = PCIeDevTracer._reloadcls()
+
+mon = RegMonitor(hv.u)
+
+class WLANCfgSpace(PCICfgSpace):
+ BAR0_WINDOW = 0x80, Register32
+ WRAPPERBASE = 0x70, Register32
+ INTSTATUS = 0x90, Register32
+ INTMASK = 0x94, Register32
+ SBMBX = 0x98, Register32
+ LINK_STATUS_CTRL = 0xbc, Register32
+
+class WLANBAR0(RegMap):
+ INTMASK = 0x2024, Register32
+ MAILBOXINT = 0x2048, Register32
+ MAILBOXMASK = 0x204c, Register32
+ CONFIGADDR = 0x2120, Register32
+ CONFIGDATA = 0x2124, Register32
+ H2D_MAILBOX_0 = 0x2140, Register32
+ H2D_MAILBOX_1 = 0x2144, Register32
+
+ # Linux uses these, via offset 0 instead of 0x2000
+ H2D_MAILBOX_0_ALT = 0x140, Register32
+ H2D_MAILBOX_1_ALT = 0x144, Register32
+ H2D_MAILBOX_0_64 = 0xa20, Register32
+ H2D_MAILBOX_1_64 = 0xa24, Register32
+ INTMASK_64 = 0xc14, Register32
+ MAILBOXINT_64 = 0xc30, Register32
+ MAILBOXMASK_64 = 0xc34, Register32
+
+class WLANSRAMEnd(RegMap):
+ PAD = 0x00, Register32
+ SHARED_BASE = 0x04, Register32
+
+class WLANSRAMShared(RegMap):
+ FLAGS = 0, Register32
+ CONSOLE_ADDR = 20, Register32
+ FWID = 28, Register32
+ MAX_RXBUFPOST = 34, Register16
+ RX_DATAOFFSET = 36, Register32
+ HTOD_MB_DATA_ADDR = 40, Register32
+ DTOH_MB_DATA_ADDR = 44, Register32
+ RING_INFO_ADDR = 48, Register32
+ DMA_SCRATCH_LEN = 52, Register32
+ DMA_SCRATCH_ADDR = 56, Register64
+ HOST_SCB_ADDR = 64, Register64
+ HOST_SCB_SIZE = 72, Register32
+ BUZZ_DBG_PTR = 76, Register32
+ FLAGS2 = 80, Register32
+ HOST_CAP = 84, Register32
+ HOST_TRAP_ADDR = 88, Register64
+ DEVICE_FATAL_LOGBUF_START = 96, Register32
+ HOFFLOAD_ADDR = 100, Register64
+ FLAGS3 = 108, Register32
+ HOST_CAP2 = 112, Register32
+ HOST_CAP3 = 116, Register32
+
+class WLANSRAMRingInfo(RegMap):
+ RINGMEM = 0x00, Register32
+ H2D_W_IDX_PTR = 0x04, Register32
+ H2D_R_IDX_PTR = 0x08, Register32
+ D2H_W_IDX_PTR = 0x0c, Register32
+ D2H_R_IDX_PTR = 0x10, Register32
+ H2D_W_IDX_HOSTADDR = 0x14, Register64
+ H2D_R_IDX_HOSTADDR = 0x1c, Register64
+ D2H_W_IDX_HOSTADDR = 0x24, Register64
+ D2H_R_IDX_HOSTADDR = 0x2c, Register64
+ MAX_FLOWRINGS = 0x34, Register32
+ MAX_SUBMISSIONRINGS = 0x38, Register32
+ MAX_COMPLETIONRINGS = 0x3c, Register32
+
+COMMON_RING_CNT = 5
+
+class WLANSRAMRingMem(RegMap):
+ MAX_ITEM = irange(0x04, COMMON_RING_CNT, 0x10), Register16
+ LEN_ITEMS = irange(0x06, COMMON_RING_CNT, 0x10), Register16
+ BASE_ADDR = irange(0x08, COMMON_RING_CNT, 0x10), Register32
+
+class MsgHeader(ConstructClass):
+ subcon = Struct(
+ "msg_type" / Int8ul,
+ "if_id" / Int8sl,
+ "flags" / Int8ul,
+ "epoch" / Int8ul,
+ "request_id" / Int32ul,
+ )
+
+class ComplHeader(ConstructClass):
+ subcon = Struct(
+ "status" / Int16ul,
+ "ring_id" / Int16ul,
+ )
+
+class IOCtlPtrReq(ConstructClass):
+ subcon = Struct(
+ "cmd" / Int32ul,
+ "trans_id" / Int16ul,
+ "input_buf_len" / Int16ul,
+ "output_buf_len" / Int16ul,
+ "rsvd" / Array(3, Int16ul),
+ "host_input_buf_addr" / Int64ul,
+ )
+
+class IOCtlResp(ConstructClass):
+ subcon = Struct(
+ "compl" / ComplHeader,
+ "resp_len" / Int16ul,
+ "trans_id" / Int16ul,
+ "cmd" / Int32ul,
+ )
+
+class H2DMailboxData(ConstructClass):
+ subcon = Struct(
+ "data" / Int32ul
+ )
+
+class D2HMailboxData(ConstructClass):
+ subcon = Struct(
+ "compl" / ComplHeader,
+ "data" / Int32ul,
+ )
+
+class RingMessage(ConstructClass):
+ subcon = Struct(
+ "hdr" / MsgHeader,
+ "payload" / Switch(this.hdr.msg_type, {
+ 0x09: IOCtlPtrReq,
+ 0x0c: IOCtlResp,
+ 0x23: H2DMailboxData,
+ 0x24: D2HMailboxData,
+
+ }, default=HexDump(GreedyBytes))
+ )
+
+class RingState:
+ pass
+
+class WLANRingTracer(PCIeDevTracer):
+ def __init__(self, wlan, info):
+ self.wlan = wlan
+ self.hv = wlan.hv
+ self.p = wlan.hv.p
+ self.u = wlan.hv.u
+ self.ringid = self.RX, self.PTR_IDX
+ if self.ringid in wlan.state.rings:
+ self.state = wlan.state.rings[self.ringid]
+ else:
+ self.state = wlan.state.rings[self.ringid] = RingState()
+ self.state.rptr = 0
+
+ self.info = info
+ assert info.item_size == self.ITEM_SIZE
+ self.base_addr = info.base_addr
+ self.count = info.count
+
+ if self.RX:
+ d2h_paddr = self.wlan.iotranslate(self.wlan.state.d2h_w_idx_ha + 4 * self.PTR_IDX, 4)[0][0]
+ assert d2h_paddr is not None
+ self.hv.add_tracer(irange(d2h_paddr, 4), self.wlan.ident, TraceMode.SYNC,
+ read=self.d2h_w_idx_readhook)
+
+ def d2h_w_idx_readhook(self, evt):
+ self.log("W idx read")
+ self.poll()
+
+ def poll(self):
+ if self.RX:
+ wptr = self.wlan.ioread(self.wlan.state.d2h_w_idx_ha + 4 * self.PTR_IDX, 4)
+ else:
+ wptr = self.wlan.ioread(self.wlan.state.h2d_w_idx_ha + 4 * self.PTR_IDX, 4)
+
+ wptr = struct.unpack("<I", wptr)[0]
+
+ while wptr != self.state.rptr:
+ off = self.state.rptr * self.ITEM_SIZE
+ addr = self.base_addr + off
+ data = self.wlan.ioread(addr, self.ITEM_SIZE)
+ self.pkt(data)
+ self.state.rptr = (self.state.rptr + 1) % self.count
+
+ def pkt(self, data):
+ self.log("Got packet:")
+ pkt = RingMessage.parse(data)
+ self.log(pkt)
+ if pkt.hdr.msg_type == 0x09:
+ self.wlan.ioctlptr_req(pkt)
+ if pkt.hdr.msg_type == 0x0c:
+ self.wlan.ioctlresp(pkt)
+
+ def log(self, msg):
+ self.wlan.log(f"[{self.NAME}]{msg!s}")
+
+class WLANControlSubmitRingTracer(WLANRingTracer):
+ NAME = "CTLSubmit"
+ PTR_IDX = 0
+ RX = False
+ ITEM_SIZE = 0x28
+
+class WLANControlCompleteRingTracer(WLANRingTracer):
+ NAME = "CTLCompl"
+ PTR_IDX = 0
+ RX = True
+ ITEM_SIZE = 0x18
+
+class RingInfo:
+ def __init__(self):
+ self.count = None
+ self.item_size = None
+ self.base_addr = None
+
+ def ready(self):
+ return self.count is not None and self.item_size is not None and self.base_addr is not None
+
+class WLANTracer(PCIeDevTracer):
+ DEFAULT_MODE = TraceMode.SYNC
+
+ SRAM_BASE = 0x740000
+ SRAM_SIZE = 0x1f9000
+
+ BARMAPS = [WLANBAR0, None, None]
+ CFGMAP = WLANCfgSpace
+
+ RINGS = [
+ WLANControlSubmitRingTracer,
+ None, # RXPost
+ WLANControlCompleteRingTracer,
+ None, # TX complete
+ None, # RX complete
+ ]
+
+ CMDS = {
+ 1: "GET_VERSION",
+ 2: "UP",
+ 3: "DOWN",
+ 262: "GET_VAR",
+ 263: "SET_VAR",
+ }
+
+ def __init__(self, hv, apcie, bus, dev, fn, dart_path=None, verbose=False):
+ super().__init__(hv, apcie, bus, dev, fn, verbose=verbose)
+ self.u = hv.u
+ self.p = hv.p
+ self.dart_path = dart_path
+ self.dart_dev = None
+ self.dart = None
+ self.rings = {}
+
+ def init_state(self):
+ super().init_state()
+ self.state.shared_base = None
+ self.state.ring_info_base = None
+ self.state.ring_mem_base = None
+ self.state.tcm_base = None
+ self.state.tcm_size = None
+ self.state.ring_info = None
+ self.state.ring_mem = None
+ self.state.ring_info_data = {}
+ self.state.rings = {}
+ self.state.ioctls = {}
+ self.state.h2d_w_idx_ha = None
+ self.state.h2d_r_idx_ha = None
+ self.state.d2h_w_idx_ha = None
+ self.state.d2h_r_idx_ha = None
+
+ def config_dart(self):
+ # Ugly...
+ if self.dart_dev is None:
+ for i in range (16):
+ ttbr = self.dart.regs.TTBR[i, 0].reg
+ if ttbr.VALID:
+ self.log(f"DART device: {i}")
+ self.dart_dev = i
+ break
+ else:
+ raise Exception("Failed to find DART device")
+
+ def ioread(self, addr, size):
+ self.config_dart()
+ return self.dart.ioread(self.dart_dev, addr, size)
+
+ def iotranslate(self, addr, size):
+ self.config_dart()
+ return self.dart.iotranslate(self.dart_dev, addr, size)
+
+ def r_SHARED_BASE(self, base):
+ if base.value & 0xffff == (base.value >> 16) ^ 0xffff:
+ return
+
+ self.state.shared_base = base.value
+ self.update_shared()
+
+ def w_H2D_W_IDX_HOSTADDR(self, addr):
+ self.state.h2d_w_idx_ha = addr.value
+
+ def w_H2D_R_IDX_HOSTADDR(self, addr):
+ self.state.h2d_r_idx_ha = addr.value
+
+ def w_D2H_W_IDX_HOSTADDR(self, addr):
+ self.state.d2h_w_idx_ha = addr.value
+
+ def w_D2H_R_IDX_HOSTADDR(self, addr):
+ self.state.d2h_r_idx_ha = addr.value
+
+ def w_MAX_ITEM(self, val, index):
+ info = self.state.ring_info_data.setdefault(index, RingInfo())
+ info.count = val.value
+ self.update_ring(index)
+
+ def w_LEN_ITEMS(self, val, index):
+ info = self.state.ring_info_data.setdefault(index, RingInfo())
+ info.item_size = val.value
+ self.update_ring(index)
+
+ def w_BASE_ADDR(self, val, index):
+ info = self.state.ring_info_data.setdefault(index, RingInfo())
+ info.base_addr = val.value
+ self.update_ring(index)
+
+ def update_ring(self, idx):
+ if idx not in self.state.ring_info_data:
+ return
+ info = self.state.ring_info_data[idx]
+ if not info.ready():
+ return
+
+ if idx in self.rings:
+ return
+
+ if idx > len(self.RINGS):
+ return
+
+ ringcls = self.RINGS[idx]
+
+ if ringcls is None:
+ return
+
+ self.rings[idx] = ringcls(self, info)
+
+ def w_H2D_MAILBOX_0(self, val):
+ ring = self.rings.get(2, None)
+ if ring is not None:
+ ring.poll()
+
+ ring = self.rings.get(0, None)
+ if ring is not None:
+ ring.poll()
+
+ w_H2D_MAILBOX_0_64 = w_H2D_MAILBOX_0
+ w_H2D_MAILBOX_0_ALT = w_H2D_MAILBOX_0
+
+ def ioctlptr_req(self, pkt):
+ data = self.ioread(pkt.payload.host_input_buf_addr, pkt.payload.input_buf_len)
+ cmd = self.CMDS.get(pkt.payload.cmd, "unk")
+ self.log(f"IOCTL request ({cmd}):")
+ chexdump(data, print_fn = self.log)
+ self.state.ioctls[pkt.payload.trans_id] = pkt
+
+ def ioctlresp(self, pkt):
+ req = self.state.ioctls.get(pkt.payload.trans_id, None)
+ if req is None:
+ self.log(f"ERROR: unknown transaction ID {pkt.payload.trans_id:#x}")
+ return
+
+ data = self.ioread(req.payload.host_input_buf_addr, req.payload.output_buf_len)
+ cmd = self.CMDS.get(pkt.payload.cmd, "unk")
+ self.log(f"IOCTL response ({cmd}):")
+ chexdump(data, print_fn = self.log)
+ del self.state.ioctls[pkt.payload.trans_id]
+
+ def trace_bar(self, idx, start, size):
+ if idx != 2:
+ return super().trace_bar(idx, start, size)
+
+ self.state.tcm_base = start
+ self.state.tcm_size = size
+
+ self.update_tcm_tracers()
+
+ def update_tcm_tracers(self):
+ if self.state.tcm_base is None:
+ return
+
+ if self.dart is None:
+ self.dart = DART.from_adt(self.u, self.dart_path)
+
+ self.trace_regmap(self.state.tcm_base + self.SRAM_BASE + self.SRAM_SIZE - 8, 8,
+ WLANSRAMEnd, name="sram")
+
+ def update_shared(self):
+ base = self.state.shared_base
+ if base is None:
+ return
+
+ if self.state.ring_info_base is None:
+ self.shared = WLANSRAMShared(self.hv.u, self.state.tcm_base + base)
+
+ self.log("Reading shared info")
+ self.shared.dump_regs()
+
+ self.state.ring_info_base = self.shared.RING_INFO_ADDR.val
+
+ if self.state.ring_mem_base is None:
+ self.ring_info = WLANSRAMRingInfo(self.hv.u,
+ self.state.tcm_base + self.state.ring_info_base)
+ self.log("Reading ring info")
+ self.ring_info.dump_regs()
+
+ self.state.ring_mem_base = self.ring_info.RINGMEM.val
+
+ self.trace_regmap(self.state.tcm_base + base, 0x100,
+ WLANSRAMShared, name="shared")
+
+ self.trace_regmap(self.state.tcm_base + self.state.ring_info_base, 0x40,
+ WLANSRAMRingInfo, name="ringinfo")
+
+ self.ring_mem = WLANSRAMRingMem(self.hv.u,
+ self.state.tcm_base + self.state.ring_mem_base)
+ self.log("Reading ring mem")
+ self.ring_mem.dump_regs()
+
+ self.trace_regmap(self.state.tcm_base + self.state.ring_mem_base,
+ COMMON_RING_CNT * 0x10, WLANSRAMRingMem, name="ringmem")
+
+ def start(self):
+ super().start()
+
+ self.update_tcm_tracers()
+ self.update_shared()
+ for i in range(len(self.RINGS)):
+ self.update_ring(i)
+
+wlan_tracer = WLANTracer(hv, "/arm-io/apcie",
+ 4, 0, 0, "/arm-io/dart-apcie0")
+
+wlan_tracer.start()