Jump to content

    

PCIe Driver

Посмотрел примеры драйверов, все, оказывается, пользуются read, write???

Share this post


Link to post
Share on other sites

"Нативными" методами работы с драйверами устройств являются open,read,write,close.

fopen,fread,fwrite,fclose - это уже функции библитеки libc, они удобны для работы с файлами, как с потоками данных (stream), поэтому читают из устройства (как бы файла) сразу большими блоками и буферизируют внутри себя данные. Это позволяет добиться существенного выиграша в скорости при работе с файловой системой, даже если верхний уровень читает по 16 байт, в "глубине души" чтение идёт блоками, удобными устройству и буферизируется, а когда юзер снова попросит следующие 16 байт, уже ничего читать не нужно, можно скопировать из буфера уже прочитанное...

Share this post


Link to post
Share on other sites

Ясно, пользуемся open, read, write, close и всё будет работать.

Share this post


Link to post
Share on other sites
Откуда взялся номер 11 в конфигурационной области? Если его пишет система (или BIOS), то почему после переопределения номера линии прерывания он не переписывается на правильный?

 

Полагаю, что он задается в device tree.

Share this post


Link to post
Share on other sites

Приветствую!

Возник вопрос, какой максимальный размер памяти с непрерывной адресацией можно выделить в ядре?

Посмотрел, что kmalloc, dma_alloc_coherent максимум дают 4МБ, что делать если хочу больше?

Спасибо.

Share this post


Link to post
Share on other sites

Если использовать alloc_pages, то вообще выделяет только 8 страниц, далее выдаёт ошибку.

Share this post


Link to post
Share on other sites

Приветствую.

В функции инициализации модуля pcievx7_init хочу добраться до struct pci_dev *pdev, вроде как должно помочь container_of, но получаются

разные значения для pdev и my_pdev. Может кто подскажет, что тут неправильно? Значения pdev->driver и &pcievx7_pci_driver одинаковы.

static int pcievx7_probe(struct pci_dev *pdev , const struct pci_device_id *id)
{
    ...
    PINFO("pdev = %p\n", pdev);
    PINFO("pdev->driver = %p\n", pdev->driver); // выводит в syslog адрес pcievx7_pci_driver = DRIVER_ADDRESS
    ...
}

static struct pci_driver pcievx7_pci_driver =
{
    .name        = DRIVER_NAME,
    .probe        = pcievx7_probe,
    .remove        = pcievx7_remove,
    .id_table    = pcievx7_pci_driver_ids
};

static int __init pcievx7_init(void)
{
    struct pci_dev *my_pdev; 
    ...
    pci_register_driver(&pcievx7_pci_driver);
    PINFO("&pcievx7_pci_driver = %p\n", &pcievx7_pci_driver); // выводит в syslog адрес pcievx7_pci_driver = DRIVER_ADDRESS
    my_pdev = container_of(&pcievx7_pci_driver, struct pci_dev, driver);
    PINFO("my_pdev = %p\n", my_pdev);
    ...
}

Share this post


Link to post
Share on other sites

Я бы поле имени pdev->driver->name напечатал в консоль для обоих. Может помочь понять. Перед печатью проверьте если pdev->driver не равен нулю иначе система рухнет.

Share this post


Link to post
Share on other sites
Я бы поле имени pdev->driver->name напечатал в консоль для обоих. Может помочь понять. Перед печатью проверьте если pdev->driver не равен нулю иначе система рухнет.

Если правильно Вас понял, то сделал это:

static int pcievx7_probe(struct pci_dev *pdev , const struct pci_device_id *id)
{
    PINFO("%s\n", pdev->driver->name); // выводит в syslog имя драйвера "pcievx7"
}

static struct pci_driver pcievx7_pci_driver =
{
    .name        = DRIVER_NAME,
    .probe       = pcievx7_probe,
    .remove      = pcievx7_remove,
    .id_table    = pcievx7_pci_driver_ids
};

static int __init pcievx7_init(void)
{
    pci_register_driver(&pcievx7_pci_driver);
    PINFO("%s\n", (&pcievx7_pci_driver)->name); // выводит в syslog имя драйвера "pcievx7"
}

Имя драйвера в обоих случаях одинаково. Вопрос остался.

 

Попробовал сделать так:

static int pcievx7_probe(struct pci_dev *pdev , const struct pci_device_id *id)
{
    struct pci_dev *test_pdev;

    test_pdev = container_of(pdev->driver, struct pci_dev, driver);

    PINFO("%p\n", test_pdev);
    PINFO("%p\n", pdev);
}

Получаю разные значения для test_pdev и pdev. Объясните, что тут неправильно?

Спасибо.

Share this post


Link to post
Share on other sites

Надо было так:

static int pcievx7_probe(struct pci_dev *pdev , const struct pci_device_id *id)
{
    struct pci_dev *test_pdev;

    test_pdev = container_of(&pdev->driver, struct pci_dev, driver);

    PINFO("%p\n", test_pdev);
    PINFO("%p\n", pdev);
}

Share this post


Link to post
Share on other sites
Если использовать alloc_pages, то вообще выделяет только 8 страниц, далее выдаёт ошибку.

Так это же известнейшее ограничение что нельзя сразу много страниц вподряд выделить. Для этого надо использовать SG-DMA подход (LDD3, 15.4. Direct Memory Access). Я как раз сам в процессе освоения этого.

 

У Вас что-то получилось по этой теме? Куча вопросов, я пока только смог сделать запись и чтение регистров своего устройства через MMIO...

Share this post


Link to post
Share on other sites
Так это же известнейшее ограничение что нельзя сразу много страниц вподряд выделить.

 

В последних ядрах есть CMA (Contiguous Memory Allocator), в принципе можно выделить и подряд много, сам пробовал, получалось.

Share this post


Link to post
Share on other sites
В последних ядрах есть CMA (Contiguous Memory Allocator), в принципе можно выделить и подряд много, сам пробовал, получалось.

Я может что-то не понимаю, но меня искренне удивляет что работа устройства будет отдана воле случая, выделится а может нет - зачем такое делать?

 

Допустим в системе 16 гигабайт ОЗУ. CMA может выделить буфер 5 гигабайт? Я знаю что так делать не хорошо, но что если будет некоторое устройство, которому именно что требуется это, и пользователь будет предупрежден что именно столько надо для работы устройства.

 

Я сторонник исключительно 100% надежно работающих подходов.

Share this post


Link to post
Share on other sites
Я может что-то не понимаю, но меня искренне удивляет что работа устройства будет отдана воле случая, выделится а может нет - зачем такое делать?

 

Допустим в системе 16 гигабайт ОЗУ. CMA может выделить буфер 5 гигабайт? Я знаю что так делать не хорошо, но что если будет некоторое устройство, которому именно что требуется это, и пользователь будет предупрежден что именно столько надо для работы устройства.

 

Я сторонник исключительно 100% надежно работающих подходов.

 

Я так понимаю, если в системе только один драйвер использует подобный алгоритм выделения памяти, то вообще никаких проблем не будет, если несколько, то надо следить за суммарным размером области. В целом да, специфично, но зато можно без SGDMA обойтись. Да и производительность чуть-чуть будет повыше.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this