// SPDX-License-Identifier: GPL-2.0-or-later // // The KPI: the Linux symbols a hosted driver actually calls, implemented. // // docs/architecture/ldls.md, "The KPI". The stub passes measured what a driver asks for // and in what order; this is what answers, for real, against `/dev/pci` and // `/dev/netdev`. // // **Rule 3 governs every file here.** A symbol exists and takes these // arguments is a fact and is reproduced; the comment above it, the macro body // and the implementation are expression and are never carried over. What each // function *does* is written from documentation and from what the driver's // behaviour requires -- which is the part BTF cannot give and is the whole of // the real work. // // Organised under Linux's own header names so it is navigable: a reader who // knows where `pci_iomap` lives in Linux knows where it is here. #include "types.h" // One entry per symbol LDLS can answer. The loader consults this before // falling back to a logging stub, so an unimplemented symbol still reports // itself rather than silently returning zero -- which is what made L1's // measurement possible and stays useful for exactly the same reason. struct kpi_sym { const char *name; void *fn; }; extern const struct kpi_sym kpi_table[]; extern const int kpi_count; // Look one up. Returns 0 when LDLS has no implementation, which is not an // error: it means the caller should install a stub and find out whether the // driver ever calls it. void *kpi_find(const char *name); // --- what the host gives the KPI --------------------------------------------- // // The KPI cannot open these for itself: `/dev/pci` is one device per process // and the host has already claimed it. So the host hands over what it holds, // once, before the driver runs. struct kpi_ctx { int pcifd; // /dev/pci, with the device claimed int index; // which device, for the ioctls that name one int netfd; // /dev/netdev, or -1 until register_netdev // The BARs, as PCIIOC_INFO reported them. `pci_iomap` maps out of these and // refuses anything else, which is the same check the kernel makes and is // repeated here so the failure says which BAR rather than -EACCES. unsigned long long bar_base[6]; unsigned long long bar_size[6]; unsigned int bar_flags[6]; // The mapping pci_iomap handed out, so register access can be checked // against it. A foreign driver writing outside its own BAR is precisely the // thing worth catching, and without an IOMMU it is also the thing nothing // else will catch. unsigned long io_base; unsigned long io_len; long io_stray; // accesses refused, so it is countable unsigned char mac[6]; // filled in by dev_addr_mod int have_mac; }; extern struct kpi_ctx kpi; // The struct offsets the KPI needs at run time, read from the kernel's own BTF // by the host before the driver starts. See ldls/btf.h -- nothing here is // written down, because a compiled driver and this code have to agree about // them exactly and only the kernel that driver was built for can say. struct kpi_layout { unsigned int nd_netdev_ops; unsigned int nd_dev_addr, nd_perm_addr, nd_addr_len; unsigned int nd_mc, nd_uc; unsigned int nd_tx, nd_num_tx, nd_real_num_tx; unsigned int nq_size, nq_dev; unsigned int nd_state, nd_flags; unsigned int pd_dev, dev_kobj, kobj_name; unsigned int ndo_open, ndo_stop, ndo_start_xmit; // work_struct.func -- where a deferred work item keeps the function to call. // `struct delayed_work` starts with a work_struct, so one offset serves both. unsigned int work_func; // __LINK_STATE_NOCARRIER, from BTF. `netif_carrier_ok` is an inline that // tests this bit of net_device.state, so it is the one number that decides // whether a driver believes its link came up. unsigned int link_nocarrier; unsigned int skb_size; unsigned int skb_len, skb_data, skb_head, skb_tail, skb_end, skb_dev; }; extern struct kpi_layout kpi_l; // The driver's NAPI poll, captured when it registers one. // // A NAPI driver does almost nothing in its interrupt handler: it schedules, // and the receive happens later in the poll. LDLS has no softirq to run that // from, so it keeps the function pointer and calls it from its own loop -- // which is what a poll loop is, arrived at from the other direction. extern int (*kpi_napi_poll)(void *napi, int budget); extern void *kpi_napi; // The driver's own interrupt handler, kept and called from the loop. See the // note in kpi.c: this is not about receiving packets, it is about everything a // driver only ever does from inside its handler. int kpi_request_irq(unsigned int irq, void *handler, void *thread_fn, unsigned long flags, const char *name, void *dev); int kpi_free_irq(unsigned int irq, void *dev); int kpi_irq_poll(void); // A driver's deferred work, run from the same loop that polls. See work.c -- // e1000 enables its transmitter from a watchdog, so this is not optional. int kpi_queue_work_on(int cpu, void *q, void *work); int kpi_queue_delayed_work_on(int cpu, void *q, void *dwork, unsigned long delay); int kpi_cancel_work_sync(void *work); int kpi_cancel_delayed_work_sync(void *dwork); int kpi_cancel_delayed_work(void *dwork); int kpi_flush_work(void *work); int kpi_work_run(void); // The clock those deadlines are measured against, and the `jiffies` a driver // reads directly. extern unsigned long kpi_jiffies; unsigned long kpi_jiffies_now(void); // Output. The KPI is inside a process with no libc, and every implementation // wants to be able to say what it did. void kpi_log(const char *s); void kpi_lognum(long long v); void kpi_loghex(unsigned long long v, int digits); // Whether to narrate every call. Register access is far too noisy to print by // default -- 538 of 8139too's 552 probe calls are ioread8/iowrite8. extern int kpi_verbose; // Memory a device can be pointed at, in pieces smaller than a PCIIOC_DMA call. // The skb path uses it, because a driver that maps an skb for its device needs // the bus address of the data. See the long note in kpi.c. void *kpi_dma_heap(unsigned long n, unsigned long align); unsigned long long kpi_phys_of(const void *va); // Is this a register address we handed out? Reports the first few that are // not, then goes quiet -- a driver that is off the rails produces thousands. int kpi_io_ok(void *addr, int width, int write);