Драйвер Linux PCI, предварительная выборка mmap

У меня есть PCI-устройство, его драйвер для Linux и пользовательское приложение. Приложение mmap делает первый BAR устройства PCI через драйвер. Весь доступ осуществляется через 32-битные целые числа, и это важно, поскольку чтение/запись в регистр может иметь побочные эффекты (запуск операции и т. д.).

На платформах x86 это работает очень хорошо. Однако я только что перешел на платформу ARM, и у меня странное поведение:

  • Чтение/запись из драйвера ведут себя корректно
  • Чтение из пользовательского пространства вызывает запрос на чтение PCI размером 64 байта, который не может быть выполнен моим устройством, поскольку оно принимает только 32-битный доступ (+ я не хочу этого из-за побочных эффектов).

Я думаю, проблема в том, что mmap хочет предварительно загрузить некоторые данные и выдает эти 64 байта. Я пропустил флаг или что-то, что может отключить предварительную выборку mmap?

Моя текущая реализация mmap на стороне водителя просто

vma->vm_flags |= VM_RESERVED;
remap_pfn_range(vma,vma->vm_start,  pfn, Size_UL, vma->vm_page_prot)

person Julien    schedule 16.10.2012    source источник
comment
Ваше PCI-устройство рекламирует себя как предзагружаемое? (Бит 3 в строке памяти.)   -  person myron-semack    schedule 16.10.2012
comment
Нет, флаг PCI равен 0x0040200 (флаг PREFETCHABLE равен 0x2000 согласно моим заголовкам)   -  person Julien    schedule 17.10.2012


Ответы (1)


Я нашел решение!

Как предположил коллега, 64 байта - это строка кэша, это может быть механизм кэширования, игнорирующий мою "непредварительно извлекаемую" информацию, потому что она теряется во время mmap() (хотя она была сохранена на x86...), поэтому я пришлось добавить эти флаги в vma, чтобы предотвратить кэширование:

vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot) | L_PTE_PRESENT |
                         L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY;

На самом деле не уверен, что нужны все флаги, но, эй, это работает!

person Julien    schedule 17.10.2012