pci: review setpci and devmem manipulations

This commit is contained in:
Ciro Santilli
2018-05-22 17:29:50 +01:00
parent 6d90e1244e
commit 09bc49bdde

View File

@@ -3766,6 +3766,25 @@ PCI driver for our minimal `pci_min.c` QEMU fork device:
insmod /pci_min.ko
....
Outcome:
....
<4>[ 10.608241] pci_min: loading out-of-tree module taints kernel.
<6>[ 10.609935] probe
<6>[ 10.651881] dev->irq = 11
lkmc_pci_min mmio_write addr = 0 val = 12345678 size = 4
<6>[ 10.668515] irq_handler irq = 11 dev = 251
lkmc_pci_min mmio_write addr = 4 val = 0 size = 4
....
What happened:
* right at probe time, we write to a register
* our hardware model is coded such that it generates an interrupt when written to
* the Linux kernel interrupt handler write to another register, which tells the hardware to stop sending interrupts
Kernel messages and printks from inside QEMU are shown all together, to see that more clearly, run in <<graphic-mode>> instead.
Source:
* Kernel module: link:kernel_module/pci_min.c[].
@@ -3788,12 +3807,12 @@ Small upstream educational PCI device:
/pci.sh
....
Source:
This tests a lot of features of the edu device, to understand the results, compare the inputs with the documentation of the hardware: https://github.com/qemu/qemu/blob/v2.12.0/docs/specs/edu.txt
Sources:
* kernel module: link:kernel_module/pci.c[]
* QEMU device:
** source: https://github.com/qemu/qemu/blob/v2.12.0/hw/misc/edu.c
** documentation: https://github.com/qemu/qemu/blob/v2.12.0/docs/specs/edu.txt
* QEMU device: https://github.com/qemu/qemu/blob/v2.12.0/hw/misc/edu.c
* test script: link:rootfs_overlay/pci.sh[]
Works because we add to our default QEMU CLI:
@@ -3814,31 +3833,41 @@ TODO exercise DMA on the kernel module. The `edu` hardware model has that featur
* https://stackoverflow.com/questions/32592734/are-there-any-dma-driver-example-pcie-and-fpga/44716747#44716747
* https://stackoverflow.com/questions/17913679/how-to-instantiate-and-use-a-dma-driver-linux-module
===== setpci
===== Manipulate PCI registers directly
There are two versions of `setpci` and `lspci`:
In this section we will try to interact with PCI devices directly from userland without kernel modules.
* a simple one from BusyBox
* a more complete one from link:https://github.com/pciutils/pciutils[pciutils] which Buildroot has a package for. This is the one we enable by default.
`setpci` can read and write to PCI configuration registers.
Read is possible from Linux with:
First identify the PCI device with:
....
hexdump /sys/bus/pci/devices/0000:00:05.0/config
lspci
....
and `/dev/mem` can of course do both reads and writes, but `setpci` provides nice human readable register names, e.g.:
In our case for example, we see:
....
00:06.0 Unclassified device [00ff]: Device 1234:11e8 (rev 10)
00:07.0 Unclassified device [00ff]: Device 1234:11e9
....
which we identify as being `edu` and `pci_min` by the magic numbers: `1234:11e?`
Read the configuration registers as binary:
....
hexdump /sys/bus/pci/devices/0000:00:06.0/config
....
Get those values with nice disassembled human readable names:
....
setpci --dumpregs
....
then and then get the values with either bus or device id:
Then and then get the values with either bus or device id:
....
setpci -s 0000:00:05.0 BASE_ADDRESS_0
setpci -s 0000:00:06.0 BASE_ADDRESS_0
setpci -d 1234:11e9 BASE_ADDRESS_0
....
@@ -3856,6 +3885,13 @@ devmem 0xfeb52000 w 0x12345678
which for our <<pci_min>> device fires interrupts.
There are two versions of `setpci` and `lspci`:
* a simple one from BusyBox
* a more complete one from link:https://github.com/pciutils/pciutils[pciutils] which Buildroot has a package for. This is the one we enable by default.
`setpci` can read and write to PCI configuration registers.
===== Introduction to PCI
The PCI standard is non-free, obviously like everything in low level: https://pcisig.com/specifications but Google gives several illegal PDF hits :-)