BSACPLD 14 28 апреля, 2023 Опубликовано 28 апреля, 2023 · Жалоба Народ, подскажите, пожалуйста, как правильно использовать dma_mmap_coherent на ARM (RK3588). Пытаюсь маппить из kernel в userspace следующим образом: static int dma_dev_remap_mmap(struct file *filp, struct vm_area_struct *vma) { dma_dev_dev_t* dma_dev_dev_ptr = 0; dma_dev_dev_ptr = (dma_dev_dev_t*)filp->private_data; #ifdef VM_RESERVED vma->vm_flags |= (VM_PFNMAP | VM_SHARED | VM_RESERVED); #else vma->vm_flags |= (VM_PFNMAP | VM_SHARED | (VM_DONTEXPAND | VM_DONTDUMP) ); #endif .......... vma->vm_pgoff = 0; if(dma_mmap_coherent(&(dma_dev_dev_ptr->pci_dev->dev), vma, (void*)(vma->vm_start), virt_to_phys(dma_dev_dev_ptr->tx_dma_buffers[index_tx_buffer].base_va), (size_t)(vma->vm_end - vma->vm_start))) { printk(KERN_ALERT "dma_dev: tx_dma_buffers map error!"); return -EAGAIN; } vma->vm_ops = &dma_dev_remap_vm_ops; .......... } Но в userspace получаю какой-то левый указатель. В драйвере при создании буфера я забиваю его магическими числами 0xEB, а из userspace читается 0x00. Что я делаю не так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 1 28 апреля, 2023 Опубликовано 28 апреля, 2023 (изменено) · Жалоба Помоему адрес неправильно указываете - надо виртуальный адрес буфера в ядре а не юзерспейс Quote if(dma_mmap_coherent(&(dma_dev_dev_ptr->pci_dev->dev), vma, >>>>> dma_dev_dev_ptr->tx_dma_buffers[index_tx_buffer].base_va, // (void*)(vma->vm_start), virt_to_phys(dma_dev_dev_ptr->tx_dma_buffers[index_tx_buffer].base_va), (size_t)(vma->vm_end - vma->vm_start))) https://elixir.bootlin.com/linux/latest/source/sound/core/memalloc.c#L480 Изменено 28 апреля, 2023 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 14 28 апреля, 2023 Опубликовано 28 апреля, 2023 · Жалоба Разобрался. Надо было физический адрес не из виртуального через virt_to_phys получать, а брать тот что возвращает dma_alloc_coherent. Ну и ещё момент. Если делать универсально ARM/x86, для для x86 ветки нужно использовать remap_pfn_range. vm_pgoff_old = vma->vm_pgoff; #if defined(__aarch64__) || defined(__arm__) vma->vm_pgoff = 0; if(dma_mmap_coherent(&(dma_dev_dev_ptr->pci_dev->dev), vma, (void*)(vma->vm_start), dma_dev_dev_ptr->tx_dma_buffers[index_tx_buffer].base_ba, (size_t)(vma->vm_end - vma->vm_start))) #else if(remap_pfn_range(vma, vma->vm_start, page_to_pfn(virt_to_page(dma_dev_dev_ptr->tx_dma_buffers[index_tx_buffer].base_va)), vma->vm_end - vma->vm_start, vma->vm_page_prot)) #endif { printk(KERN_ALERT "dma_dev: tx_dma_buffers map error!"); return -EAGAIN; } vma->vm_pgoff = vm_pgoff_old; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 1 28 апреля, 2023 Опубликовано 28 апреля, 2023 (изменено) · Жалоба On 4/28/2023 at 12:05 PM, BSACPLD said: Разобрался. не совсем On 4/28/2023 at 12:05 PM, BSACPLD said: Надо было физический адрес не из виртуального через virt_to_phys получать, а брать тот что возвращает dma_alloc_coherent. dma_alloc_coherent возвращает виртуальный адрес для пространства ядра - его и надо вместо (void*)(vma->vm_start), соответственно и физический адрес надо брать тот который она инициализирует через указатель dma_addr_t *dma_handle в параметрах вызова Quote static inline void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp) https://elixir.bootlin.com/linux/latest/source/include/linux/dma-mapping.h#L420 On 4/28/2023 at 12:05 PM, BSACPLD said: Ну и ещё момент. Если делать универсально ARM/x86, для для x86 ветки нужно использовать remap_pfn_range. если ядро старше 3.6, а на сегодня это практически всегда - не надо https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=64ccc9c033c6089b2d426dad3c56477ab066c999 Изменено 28 апреля, 2023 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 14 28 апреля, 2023 Опубликовано 28 апреля, 2023 · Жалоба 1 hour ago, sasamy said: если ядро старше 3.6, а на сегодня это практически всегда - не надо На практике у меня получилось обратное. На x86 dma_mmap_coherent некорректно отрабатывает. Приходится использовать remap_pfn_range для x86 ветки. UPD. Вы были правы. Если вместо (void*)(vma->vm_start) передавать виртуальный адрес от dma_alloc_coherent, то dma_mmap_coherent работает и на x86 тоже 🙂 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 14 29 апреля, 2023 Опубликовано 29 апреля, 2023 · Жалоба Ещё один вопрос возник. Как корректно маппить регистры BAR PCIe устройства чтобы это работало и на x86 и на ARM? Вот такой код: if(remap_pfn_range(vma, vma->vm_start, PHYS_PFN(dma_dev_dev_ptr->regs_pa[0]), vma->vm_end - vma->vm_start, vma->vm_page_prot)) { printk(KERN_ALERT "dma_dev: reg map BAR0_REGS_BASE_ADDR error!"); return -EAGAIN; } работает только на x86 😞 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 1 29 апреля, 2023 Опубликовано 29 апреля, 2023 · Жалоба On 4/29/2023 at 12:27 PM, BSACPLD said: Как корректно маппить регистры BAR PCIe устройства чтобы это работало и на x86 и на ARM? в ядре начиная с 4.12 есть кроссплатформенная pci_mmap_resource_range Quote int pci_mmap_resource_range(struct pci_dev *dev, int bar, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); https://elixir.bootlin.com/linux/v6.3/source/include/linux/pci.h#L1977 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 14 3 мая, 2023 Опубликовано 3 мая, 2023 · Жалоба Странная проблема... На RK3588 на компьютере от Radxa работает без проблем, а на том же RK3588 на компьютере от Firefly зависает при вызове mmap. При этом dmesg выдает следующую информацию об ошибке: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 14 5 мая, 2023 Опубликовано 5 мая, 2023 · Жалоба Нашел причину. В функции: static int dma_dev_remap_mmap(struct file *filp, struct vm_area_struct *vma) { unsigned long vm_pgoff_old; dma_dev_dev_t* dma_dev_dev_ptr = 0; dma_dev_dev_ptr = (dma_dev_dev_t*)filp->private_data; #ifdef VM_RESERVED vma->vm_flags |= (VM_PFNMAP | VM_SHARED | VM_RESERVED); #else vma->vm_flags |= (VM_PFNMAP | VM_SHARED | (VM_DONTEXPAND | VM_DONTDUMP) ); #endif ... if(direction == PC_2_DEV) { ... } if(direction == DEV_2_PC) { printk(KERN_NOTICE "dma_dev: tx_dma_buffers map %lx\n", vma->vm_pgoff); if(dma_dev_dev_ptr->tx_dma_buffers[index_tx_buffer].base_va == NULL) { printk(KERN_ALERT "dma_dev: tx_dma_buffers[%d].base_va == NULL\n", index_tx_buffer); direction = NO_TRANSFER; return -EAGAIN; } vm_pgoff_old = vma->vm_pgoff; vma->vm_pgoff = 0; if(dma_mmap_coherent(&(dma_dev_dev_ptr->pci_dev->dev), vma, dma_dev_dev_ptr->tx_dma_buffers[index_tx_buffer].base_va, dma_dev_dev_ptr->tx_dma_buffers[index_tx_buffer].base_ba, (size_t)(vma->vm_end - vma->vm_start))) { printk(KERN_ALERT "dma_dev: tx_dma_buffers map error!"); return -EAGAIN; } vma->vm_pgoff = vm_pgoff_old; direction = NO_TRANSFER; vma->vm_ops = &dma_dev_remap_vm_ops; dma_dev_vma_open(vma); return 0; } return -EAGAIN; } через указатель некорректно передается структура с дескриптором устройства: dma_dev_dev_ptr = (dma_dev_dev_t*)filp->private_data; На x86, Radxa Rockchip работает, а на Firefly Rockchip - нет. Но если передать структуру с дескриптором устройства просто через глобальную переменную: dma_dev_dev_ptr = &(dma_dev_dev[0]); то корректно работает на всех выше перечисленных платформах. Может быть я как-то некорректно работаю с данным указателем или неправильно сохраняю указатель на структуру? // Открытие файла устройства int dma_dev_open(struct inode *inode, struct file *filp) { dma_dev_dev_t* dev; /* device information */ printk(KERN_NOTICE "dma_dev_open.\n"); // Сохраняем указатель на структуру dev = container_of(inode->i_cdev, dma_dev_dev_t, cdev); filp->private_data = dev; /* for other methods */ return 0; /* success */ } // Инициализация для устройства dma_dev_dev_t структуры cdev и ее регистрация в ОС static void dma_dev_setup_cdev(dma_dev_dev_t *dev, int index) { int err, devno = MKDEV(dma_dev_major, dma_dev_minor + index); //printk(KERN_NOTICE "dma_dev_setup_cdev"); cdev_init(&dev->cdev, &dma_dev_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &dma_dev_fops; err = cdev_add (&dev->cdev, devno, 1); if(err) { printk(KERN_ALERT "dma_dev: error %d at adding dma_dev%d", err, index); } } Коллеги, нужна ваша помощь Я в упор не вижу в чем проблема Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 1 6 мая, 2023 Опубликовано 6 мая, 2023 · Жалоба On 5/5/2023 at 11:02 PM, BSACPLD said: MKDEV(dma_dev_major, dma_dev_minor + index); откуда берёте dma_dev_major, dma_dev_minor ? устройство похоже нестандартное. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 14 6 мая, 2023 Опубликовано 6 мая, 2023 · Жалоба 21 minutes ago, sasamy said: откуда берёте dma_dev_major, dma_dev_minor ? устройство похоже нестандартное. Из define присваиваются константы. static int dma_dev_major = DEV_MAJOR; // < Major ID для символьного устройства static int dma_dev_minor = DEV_MINOR; // < Minor ID для символьного устройства #define DEV_MAJOR (83) #define DEV_MINOR (12) Устройство действительно нестандартное - специализированный сопроцессор. Поэтому и свой драйвер. DMA там тоже свой. Из готовых IP только AXI Memory Mapped To PCI Express. И если это важно, устройство в системе только одно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 1 6 мая, 2023 Опубликовано 6 мая, 2023 (изменено) · Жалоба On 5/6/2023 at 2:53 PM, BSACPLD said: Устройство действительно нестандартное - специализированный сопроцессор. ошибок я не вижу, но если бы писал сам то взял готовый класс устройств misc device - готовая обёртка для необычных устройств над голым char device https://embetronicx.com/tutorials/linux/device-drivers/misc-device-driver/ там пример немного куцый, приватные данные автоматом цепляются - свою open не надо дописывать https://docs.kernel.org/6.1/driver-api/misc_devices.html Quote The structure passed is linked into the kernel and may not be destroyed until it has been unregistered. By default, an open syscall to the device sets file->private_data to point to the structure. Drivers don't need open in fops for this. чтобы потом получать указатель на свою структуру данных аналогично с cdev надо включить в неё miscdev https://elixir.bootlin.com/linux/v6.2.14/source/drivers/misc/pci_endpoint_test.c#L116 https://elixir.bootlin.com/linux/v6.2.14/source/drivers/misc/pci_endpoint_test.c#L86 https://elixir.bootlin.com/linux/v6.2.14/source/drivers/misc/pci_endpoint_test.c#L727 Изменено 6 мая, 2023 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 14 12 мая, 2023 Опубликовано 12 мая, 2023 · Жалоба On 4/29/2023 at 1:46 PM, sasamy said: в ядре начиная с 4.12 есть кроссплатформенная pci_mmap_resource_range Можно пример использования? Беглый поиск примеров в google ничего не дал 😞 Не пойму что передавать в mmap_state... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 1 12 мая, 2023 Опубликовано 12 мая, 2023 (изменено) · Жалоба On 5/12/2023 at 8:31 PM, BSACPLD said: Беглый поиск примеров в google ничего не дал неудивительно - это довольно специфичный случай отображать регистры устроства в юзерспейс - драйверы Linux в ядре работают On 5/12/2023 at 8:31 PM, BSACPLD said: Не пойму что передавать в mmap_state... enum pci_mmap_state { pci_mmap_io, pci_mmap_mem }; https://elixir.bootlin.com/linux/v6.2.15/source/include/linux/pci.h#L90 у вас похоже pci_mmap_mem но если не уверены - посмотрите BAR-ы своего устройства через lspci в юзерспейс, например для устройства с VID 1002 Quote $ sudo lspci -nvvd 1002: | grep Region Region 0: Memory at fce0000000 (64-bit, prefetchable) Region 2: Memory at fcf0000000 (64-bit, prefetchable) Region 4: I/O ports at 1000 Region 5: Memory at d0400000 (32-bit, non-prefetchable) у вас там наверно от ксилинка VID 10ee Quote sudo lspci -nvvd 10ee: | grep Region Quote int pci_mmap_resource_range(struct pci_dev *dev, int bar, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); int bar - номер региона 0,1,2... int write_combine - если нужна буферизованная запись передайте тут 1, но в общем случае для регистров тут надо 0 https://elixir.bootlin.com/linux/v6.2.15/source/drivers/pci/mmap.c#L22 Изменено 12 мая, 2023 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 14 12 мая, 2023 Опубликовано 12 мая, 2023 · Жалоба Попробовал собрать с pci_mmap_resource_range: ERROR: "pci_mmap_resource_range" [.../dma_dev.ko] undefined! #include <linux/pci.h> включен, но pci_mmap_resource_range не видится при сборке. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться