I've got a pci device driver that currently uses dma_map_page to map a userspace address to a dma address. This is working fine but I'm trying to port this to the iommu api to get some of the benefits using groups and domains give.
Current Code: This works fine
ret = get_user_pages_fast(user_addr, one_page, flags, page);
dma_addr = dma_map_page(dev, off, size, *page, DMA_BIDIRECTIONAL);
IOMMU Code: This doesn't work
ret = get_user_pages_fast(...);
pfn = page_to_pfn(*page);
group = iommu_group_get(dev);
domain = iommu_domain_alloc(dev->bus);
iommu_attach_device(domain, dev);
iommu_attach_group(domain, group);
iommu_map(domain, iova, pfn << PAGE_SHIFT, size, IOMMU_READ|IOMMU_WRITE);
All functions return successfully, but when I pass the iova to the device the device can't use it. Has anyone worked with the iommu before and know where my problem is or where I can look? I haven't been able to find much on Linux's iommu implementation anywhere.
Edit:
There were some entries in dmesg that I missed the first time around:
DEBUG: phys addr 0x7738de000
DEBUG: iova 0xdeadb000
DMAR: DRHD: handling fault status reg 2
DMAR: DMAR:[DMA Read] Request device [50:00.0] fault addr 1fdaee4000
DMAR:[fault reason 06] PTE Read access is not set
Such operations are privileged because it is accessing page tables or may be data structures maintained inside task structure.
Please check how hypervisor do this stuff or Virtual machines handles such calls. There may be some driver interface which sets the IOMMU paging unit from Guest OS via hypervisor.
Hypervisor also executes in privileged mode.
Related
I am writing a Linux kernel driver (kernel 4.9) for our custom setup.
We do use a ARM64 based board with a PCIe interface.
Connected to the interface we have an extension board with a FPGA on it.
At this moment I succeed at creating a device that registers my FPGA with some basic functions, like reading the version of the FPGA in a certain register in the FPGA.
In the FPGA we do have some additional "devices" like GPIO, memory regions ... that I would like to add as its own chardevice. We do have existing drivers for these.
Normally, Linux goes over the DTB and calls the correct driver for our FPGA, following the correct drivers for our child devices.
Now I would like to archieve the same with this PCIe interface. To do this, I look for a node in my DTB fpga and add its children.
for_each_available_child_of_node(np, nc) {
subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
list_add(&subdev->subdev_entry, &priv->subdev_list.subdev_entry);
...
}
list_for_each_entry(subdev, &priv->subdev_list.subdev_entry,
subdev_entry) {
ret = mfd_add_devices(priv->dev, PLATFORM_DEVID_NONE,
subdev->mfd_cell, 1, NULL, irq_base, NULL);
if (ret) {
dev_err(priv->dev, "Failed to add mfd cell\n");
goto err_mfd_add;
}
}
For some reason, the driver is not loaded for its children.
print's in the device drivers probe function shows nothing, not being called.
Added print's to the loops and it shows its children (all properties and values check out with what I set in the DTB).
Yes, the driver is compiled an available in the kernel.
I also tried building the driver as a kmod and load it that way, no change in behaviour. The output of lsmod shows the module is loaded but not used.
Somebody got an idea why my driver is not being loaded?
EDIT:
I also can see the "nodes" from my DTB that should be created as a chardevice.
They can be found in the expected location /sys/class/my_fpga/fpga/device/, in this case GPIO.
Under the GPIO folder I can see the driver_override (which is (null) ), modalias, power, sybsystem and uevent.
So my device (my_fpga) seems to be enumerated, only its children are not created.
A reboot does not solve it, nor a rescan of the PCIe-bus. The extension-board is powered via an external powersupply and is already configured before booting Linux
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).
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
How will I map register addresses specifically UART registers to kernel for writing device drivers for UART?
I have gone through the omap-serial.c.But I did not find the mapping of the registers defined in it.
Is it different from the mapping of standalone UART driver?
As a device driver writer, it is your job to read the hardware documentation. The serial port documentation will specify the bits in the control and status registers and provide guidance on how to determine their addresses. Usually that guidance is in a system integrator's document.
Let's say your research determines that the UART's registers are at 0x31080220. Your code would then have:
struct resource *uart_res; // resource handle
uint *uart; // pointer to actual control/status registers
uart_res = request_mem_region (0x31080220, 4*4, "my_uart"); // map 16 bytes
if (!uart_res)
{
error ("unable to map memory region");
return -ENOMEM;
}
uart = ioremap (0x31080220, 4*4);
if (!uart)
{
release_mem_region (0x31080220, 4*4);
error ("unable to map");
return -ENOMEM;
}
Then you can use the uart pointer to access the registers.
status = ioread32 (uart + 0); // read the status register
iowrite32 (0xf0f0, uart + 4); // foo foo to control register
Give precise target information for the manufacturer, model, and options—just like an automobile—and someone will help you find the specifics.
Mapping uart in kernel may be definded as uart device (not driver) in the some place: kernel/arch/arm/'machine'/(devices | serial or some else).
Usualy there is no neet for mapping. When uart driver probe, it connects to device and create tty character driver. To operate tty from kernel, you may add your own line discipline to tty. Then user space progam can open needed ttySX port and attach it to your line discipline. Then your code in kernel will operates communication thrue the uart port (tty->driver).
Im struggling to read(and write) to HW registers from Linux user space. The goal is to configure some GPIO pins from and be able to set and read this pins.
According to the spec for the processor(imx27 from Freescale) the physical address for the register bank controlling GPIO this is 0x10015000
My assumption was that I could use something like this:
unsigned long *gpio;
fd = open("/dev/mem", O_RDWR);
gpio = (unsigned long *) mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x10015000);
I now expected to be able to read and set data to the registers in the processor. The problem is that it does not matter which location I read, I always get 0.
For example register in physical location 0x10015220 contains a register showing which pins are in us as GPIO. This Defaults to 0xFFFFFFFF. Reading this register I expected to get something different than 0:
printf("PTC_GIUS: 0x%08lX\n", gpio[0x220]);
gives PTC_GIUS: 0x00000000.
Where am I going wrong ?
The mmap on /dev/mem should work. Have you tried running your code as root? Maybe some security is preventing your program from accessing the address-space. Also make sure you've passed the correct physical address of your GPIO-Space.
The approach you've used works on my Cortex-A8 ARM-board running linux without problems.
If you can't get it working there is not much you can do except finding or writing a device-driver for the gpio (writing one is not that hard btw.).
With a bit of luck someone already did that for you. Does a node named /dev/gpio exist in your filesystem? If so you already have a driver.
A google search on /dev/gpio will give you all details on how to use it. You may also find the source for a simple gpio driver that you can modify to suit your needs.
Also, if you're using a kernel source code from 2009 and on, you should open /dev/mem with the O_SYNC flag set, if you want your memory access to be uncached.
If you are using a recent version of the Linux kernel it may be blocking access to the /dev/mem device. User mode access to that device is deprecated and dangerous. It is used mainly for user mode access to video memory within X. In embedded projects it can be useful to have access to memory mapped hardware (like GPIO).
Check your Kernel compile flags for CONFIG_STRICT_DEVMEM or other flags that restrict access to /dev/mem. It could be mistakenly blocking access to this memory range.
However, as Nils mentioned the best solution is to find a gpio module for the iMX27 or write your own.