Handling PCI read/write to configuration space in a QEMU device - c

I'm working on implementing a simple PCI device in QEMU and a kernel driver for it, and I have some trouble with handling pci_read/write_config_* function calls from the device side.
Unlike simple rw operations on a memory mapped bar, where the MemoryRegionOps callbacks receive the exact offset used by the driver, the config_read/write callbacks implemented as members in PCIDevice struct, receive an address that went through some manipulations/mapping that I have a hard time understanding.
Following the code path up to pci_config_host_read/write in QEMU sources, and the same in the kernel side for pci_read/write_config_* functions, didn't provide any clear answers.
Can anyone help me understand how to extract the config offset used by the driver when calling the pci config rw functions?

If you set your PCI device model up to implement the QEMU PCIDevice config_read and config_write methods, the addresses passed to them should be the offsets into the PCI config space (ie starting with the standard 0 == PCI_VENDOR_ID, 2 == PCI_DEVICE_ID, 4 == PCI_COMMAND and so on, and any device-specific stuff after the 64 bytes of standardized config space).

Related

Linux device driver for banana pi and device tree

I'm trying to write ethernet driver for Linux kernel 4.13.x for Banana Pi M2 ultra.
Some time ago so called "device tree" (DT) has been introduced in Linux kernel infrastructure.
I have no much experience with using DT while writing device drivers and because of that
I've got a few questions.
As far as I know - in case of banana pi system - it is needed to provide some clock source for given
peripheral device. It is function of CCU in banana pi to provide such a clock. The CCU is memory mapped
resource available at some address in the linux kernel. I'd like to write driver for ethernet which
needs some clock from CCU.
I know that physical address of CCU must be mapped via ioremap() or similar function to virtual address.
My question is how can I fetch the virtual address of CCU in my ethernet driver? Is it possible to do via
device tree? If yes - how to do this? Or maybe this virtual address can be get another way?
I'm just not sure if it is done (fetching virt address) via DT or just by some procedure or via global pointer.
Any ideas or suggestions?
There are examples in Linux kernel for platform drivers. I have worked on i2c and i2s on raspberry pi so I can quote those examples.
In http://elixir.free-electrons.com/linux/v4.3.2/source/drivers/i2c/busses/i2c-bcm2835.c
Look at the probe function, it calls the subsystem api
platform_get_resource(pdev, IORESOURCE_MEM, 0);
This can gives physical address which is ioremap ..
For this it is required to create a device node in device tree as in
https://github.com/raspberrypi/linux/blob/rpi-4.9.y/arch/arm/boot/dts/bcm283x.dtsi
check for i2c0 device node in file bcm283x.dtsi.
The reg key is where physical address is stored
reg = <0x7e205000 0x1000>;
physical add size
Hope this help you.
Device tree may be considered analogus to platform data previously

Pci express - communicate kernel -> graphic card

The final goal is to be able to write to a PCIE device from the kernel, without the already made functions, to understand the inner working (and then, obviously, use them again).
I saw the PCIE specs which are 800+ pages (the 3.0 especially).
Huge is not enough to describe that.
I cannot afford to go along those at the step I currently am (reading 2.0 and 3.1 would be very time consuming).
I read many sources and it seems that we can write to pcie via messages (and not buses anymore like in pci).
Pcie should be memory mapped so I think that we could write to that memory from the kernel and aknowledge the driver that we did it.
The driver will then make the out(l/b) assembly instruction to notify the device in question.
This my very high level understanding of pcie (I don't want to dive into the spec details now). It may not be correct though.
If someone could tell me where I am wrong in my thinking, that would be very helpful.
Here is the pseudo code of my thinking (no error checking and such):
static int64_t my_driver_address;
pcie_write_device(uint32_t * my_data_physical_address) {
// we pass the physical address where the data is. It has to be contiguous.
pcie_send_address(&my_driver_address, my_data_physical_address);
// now the device is acknowledged that some data has been mmaped, knows where and will treat it as such
}
pcie_read_device(anytype_t ** buff){
// this function calls the inq assembly instruction and store the resulting address in the pointer
ptr * address_to_read = pcie_get_data();
// read the mmaped memory region. No mem allocation code.
*buf = get_data_from region(address_to_read);
// now data from device is in the buff, ready to be sent to the OS or anything..
}

How's the Major number allocated for platform device driver?

I wonder how the major number is allocated for platform device driver.
For example, in the driver code, I don't see any of the function calls like
alloc_chrdev_region()
or
register_chrdev_region()
Somebody, please make me understand this.
Thank you.
Kernel creates a great deal of devices attached to various virtual buses (which may or may not represent a physical one). Only some of those devices can be meaningfully accessed directly from user space. And only a subset of those relies on "device node" interface to do so (as ample other options exist in modern kernels). If this particular interface is not used by a driver, then there's no need whatsoever to allocate device node numbers.
Inside the kernel devices are located by their affiliation to particular buses (using internal device names and bus ids). For example, mcspi driver registers as "device" on "platform bus" and as "bus master" on "spi bus". Upon seeing that bus master had registered, spi subsystem will trigger a "bus rescan" on a newly connected bus.
The spidev driver is rigged in such a way as to always "match" an imaginary device present on every spi bus, so it will get instantiated for every "bus master" registration. It will create the user space device node which can be used for direct communication with its "bus master" (spi bus controller, mcspi in this particular case).
Controller doesn't need to be exposed. Hence, no device nos.
On the other hand, SPI devices do require a MAJOR?MINOR no defined in spidev.c, here it is registering the device. And on the top of the same file, there's a macro for the major no defined as:
56 #define SPIDEV_MAJOR 153 /* assigned */
57 #define N_SPI_MINORS 32 /* ... up to 256 */

how to use ioremap() api from user space to read and write registers on SPI Flash memory in uClinux

I am writing one sample application which is used to read registers and write particular value on given SPI Device address.
I am using altera spi 1.0 driver and got base address as 0xE5002460 while registering spi device.
I want to read/write registers from SPI Flash from user space using ioremap call.
Is there any code snippet or any example about how to use ioremap function which can directly read value of registers from base address given without writing any specific driver for that?
#Ritesh, ioremap api is used in the kernel space to memory map the device/module for ex:SPI registers which returns virtual address. This address can be used only by ioread[8|16|32] and iowrite[8|16|32] api's to read or write to the spi registers. You can use mmap to map the SPI registers. Go through the link mmap slower than ioremap.

Linux device model: Same device but different drivers

I'm customising Linux for an ARM9 Atmel AT91SAM960 board.
In the device file Atmel named all the USART the same atmel_usart. Of course with id enumeration:
static struct platform_device at91sam9260_uart0_device = {
.name = "atmel_usart",
.id = 1,
.dev = { ...}
}
According to the Linux Device model, all these devices (5 UARTS on a SAM9260) would be bind to the driver named atmel_usart.
I don't want to set a TTYS driver on all UARTS which will be registerd. I have several own drivers which serve for different specialised purposes (LON, RS-485 etc.) I want the control which driver does serve a certain USART. So what could I do:
The Atmel device files are unsatisfiable and I can do it better. So I rename (patch) the devices in the device file. However, in case I want a TTYS driver on UART4 I would be in trouble.
I manipulate (patch) the device file,
so that I'm able the access the
structures platform_device. I could
change their names before I would
register them. But as far as I
understood the idea of the Linux Driver Model,
devices should be
registered early during boot-up but the binding to a driver follows .... later.
I could write a driver, which has an
alias name and which would be binded
to a specific bus_Id ->
atmel_usart.4. Can I really?
What solutions else exist. I want to touch a minimal set of Kernel files but I want all the freedom possible?
Addendum what freedom means to me: I can specify at runtime how the UARTS can be used
with the Atmel-Serial driver (ttyS)
with my own drivers
It means also, that changes to the kernel source are minimal.
I built my own line discipline drivers. You can build them as kernel modules and attach them to the UARTs at runtime. No changes to the Linux source are necessary.
Any funny timing or control stuff can be done through ioctl(). Specifically, I implemented a timing-sensitive RS-485 protocol in this way.
When I did this (Linux 2.6.17) there was no dynamic registration mechanism, so I overwrote the existing line disciplines. The Linux code is (was) pretty straightforward, and I was satisfied that this would be a safe thing to do.
Your problem is quite easily solved. The 5 UART devices are presently registered at kernel startup and their function is locked. This is now how it normally works for PCI or USB devices, right? So what you need to do is pull the device registration out of the startup code and register it dynamically. You can even register/unregister as needed.
at91_register_uart() is being called from your board file for every UART that needs registered. at91_add_device_serial() will then platform_device_register all those you what setup. One solution is to let at91_register_uart() be called for all 5 UARTS, but then remove the call to at91_add_device_serial() from your board. You can then make it an exported function that can be called by your loadable drivers. You can even add an argument to it (int) so that instead of looping on all UARTS, you can select which ones to register individually. You can also mirror this function by making one that unregisters the devices.
NOTE: I think you'll need to always leave one UART dedicated as your console, if you are using one that way. You could probably hide that in the exported function by only allowing index 0->3 as in input and then mapping 0->3 to 0-4, skipping the UART that you want to use for console.

Resources