2013-06-04 3 views
2

Введение:Linux ядро ​​flush_cache_range() вызов, кажется, не делать ничего

У нас есть приложение, в котором Linux работает на ARM принимает данные от внешнего процессора, DMA-данных в области памяти руки. Затем ARM должен получить доступ к этим данным из кода пользовательского режима.

Диапазон адресов должен быть физически смежным, поскольку двигатель DMA во внешнем процессоре не поддерживает разброс/сбор. Этот диапазон памяти первоначально выделяется из ядра ARM посредством вызова __get_free_pages (GFP_KERNEL | __GFP_DMA, order), поскольку это гарантирует нам, что выделенная память будет физически смежной. Затем вызов virt_to_phys() на возвращаемом указателе дает нам физический адрес, который затем предоставляется внешнему процессору в начале процесса.

Этот физический адрес известен также в коде режима пользователя Linux, который использует его (в пользовательском режиме) для вызова API mmap(), чтобы получить указатель режима пользователя к этой области памяти. Затем наш драйвер ядра Linux видит соответствующий вызов его подпрограммы mmap в структуре файла file_operations. Затем драйвер сохраняет указатель vm_area_struct «vma», который передается ему при вызове его процедуры mmap для использования позже.

Когда код пользовательского режима получает сигнал о том, что новые данные были DMA'd на этот адрес памяти, ему необходимо получить доступ к нему из пользовательского режима с помощью указателя пользовательского режима, который мы получили от вызова на mmap(), упомянутого выше. Прежде чем код режима пользователя сделает это, конечно, должен быть сброшен кеш, соответствующий этому диапазону памяти. Для выполнения этого сброса код режима пользователя вызывает драйвер (через ioctl), а в режиме ядра выполняется вызов для flush_cache_range():

flush_cache_range (vma, start, end);

Аргументы, переданные вышеперечисленному вызову, представляют собой «vma», который был захвачен драйвером при вызове его команды mmap, а «start» и «end» - это адреса пользовательского режима, переданные в драйвер из кода режима пользователя в структура, предоставляемая вызову ioctl().

Проблема:

То, что мы видим, что буфер не кажется, становится покраснел, как мы видим, что, как представляется, устаревшие данные, когда доступ из пользовательского режима сделаны. В качестве теста, а не получения адреса режима пользователя из вызова mmap() нашему драйверу, мы вместо этого называем mmap() API/dev/mem. В этом случае мы получаем доступ к буферу без доступа (без необходимости промывки), а затем все работает отлично.

Наша версия ядра - 3.8.3, и она работает на ARM 9. Есть ли логическая ошибка в подходе, который мы пытаемся сделать?

Спасибо!

+0

Дополнительная подсказка заключается в том, что если вместо вызова flush_cache_range (vma, start, end); Я вызываю flush_cache_mm (vma-> vm_mm); то код работает отлично. – user1967844

ответ

0

У меня есть несколько вопросов, после которых я мог бы ответить: 1) Как вы используете «ФИЗИЧЕСКИЙ» адрес в своем вызове mmap()? mmap не должен иметь ничего общего с физическими адресами. 2) Что именно вы делаете, чтобы получить пользовательские виртуальные адреса в своем драйвере? 3) Как вы сопоставляете эти пользовательские виртуальные адреса с физическими адресами и где вы это делаете? 4) Поскольку вы переназначаете использование get_free_pages(), сопоставляете ли вы его в пространстве ядра с помощью ioremap_cache()?

Смежные вопросы