Windows 11 / 10 / 8.1 / 8 / 7 / Vista / XP (32/64-bit)
Интерфейс:
русский / английский
Рейтинг:
Ваша оценка:
О программе
Что нового
Новое в версии 3.10.08.506 (21.10.2021):
Новое в версии 2.17.25.506 (02.06.2021):
Исправлены проблемы:
Известные проблемы:
Новое в версии 2.04.28.626 (Windows 7, 64-bit):
Системные требования
AMD Ryzen Chipset Drivers 2.10.13.408
AMD Ryzen Chipset Drivers 2.04.28.626
AMD Chipset Drivers 18.10.0830
Полезные ссылки
Подробное описание
Установка новейшей версии драйвера необходима для правильной работы всех компонентов компьютера, таких как контроллеры PCI Express, SATA и USB, а также для правильного управления питанием и энергосбережением.
Новейший драйвер AMD Chipset Drivers включает следующие компоненты:
Для Windows 11 и 10:
Для Windows 11, 10 и 7:
Для Windows 7:
Использование последней версии драйвера чипсета сведет к минимуму проблемы с работой установленных комплектующих и всех компонентов системы, а также оградит от возможных сбоев и проблем совместимости.
Драйвер виртуальных GPIO с контроллером прерываний на базе QEMU ivshmem для Linux
Трудно недооценить роль GPIO, особенно в мире встраиваемых систем ARM. Помимо того, что это крайне популярный материал для всех руководств для начинающих, GPIO обеспечивают способ для управления многими периферийными устройствами, выступают в качестве источника ценных прерываний, или даже могут быть единственным доступным способом общения с миром для SOC.
Основываясь на собственном скромном опыте, могу сказать, что прерывания далеко не самая освященная тема в сообществе Linux. Из-за своих особенностей, а так же сильной привязки к аппаратной части, все обучающие материалы посвященные прерываниям лишены реального и легко воспроизводимого примера. Данный факт мешает пониманию того, что очень часто прерывания и GPIO неразделимы, особенно в области встраиваемого Linux. Многие начинают верить, что GPIO это очень простая и скучная вещь (которая кстати и стала таковой благодаря подсистеме sysfs).
Даже в примере приведенном в LDD3 (драйвер snull) прерывания эмитируются явным вызовом функции парного устройства. Так же имеются примеры в курсах USFCA (http://cs.usfca.edu/
cruse/cs686s08/), но они используют чужое прерывание, тесно связаны с архитектурой x86 и сильно устарели.
Предлагаемое решение способно решить данные проблемы. С точки зрения пространства пользователя и, во многом, во внутренней реализации драйвер неотличим от большинства «реальных», предоставляющих прерывания портов входов/выходов общего назначения. На данный момент драйвер поддерживает прерывания по переднему или заднему фронту и может быть использован как источник прерываний для других устройств.
ivshmem — разделяемая память Inter-VM
Разработано для совместного использования разделяемой памяти (выделенной на хост-платформе через механизм POSIX shared memory API) множественными процессами QEMU с различными гостевыми платформами. Для того чтобы все гостевые платформы имели доступ к области разделяемой памяти, ivshmem моделирует PCI устройство предоставляя доступ к памяти как PCI BAR.
и проанализировал быстродействие в целом.
В настоящей момент, официально, сопровождение ivshmem никто не осуществляет, тем не менее большой вклад в развитие ivshmem вносят сотрудники Red Hat.
ivshmem может послужить основой для симуляции и отладки многих классов устройств. В данной статье мы рассматриваем виртуальную pci плату ввода/вывода общего назначения (general-purpose input/output, GPIO), которая так же является источником прерываний, и соответствующий драйвер с предоставлением доступа и управления посредством механизма sysfs.
Для разработки и тестирования использовалась виртуальная плата qemu versatilepb (system ARM).
g>> — команды или вывод выполняемые на гостевой системе. h>> — на основной.
Пример и оригинальный код
Для начала продемонстрируем оригинальный код, основанный на оригинальном коде ( https://github.com/henning-schild/ivshmem-guest-code ), и модифицированном, в последствии, Siro Mugabi.
В принципе этого вполне достаточно для эмуляции GPIO уже в таком виде. И во многих случаях так и поступали, когда достаточно простого состояния входа или записи в выход, использование sysfs и прерываний предполагают небольшую надстройку на I/O mem.
Реализация
Заметим, что /dev/ivshmem0 и ne_ivshmem_shm_guest_usr.c нам более не нужны, вся работа с устройством со стороны гостевой машины из пространства пользователя (user-space) будет осуществляться средствами интерфейса sysfs.
Прежде чем разметить наше устройство в памяти, хотелось бы отметить, что мы просто дублируем схему применяемую в большинстве gpio драйверов.
Во-первых все входа/выхода gpio разделены на порты, как правило по 8, 16, 32 входа. Каждый порт имеет, как минимум, регистр состояния входов (GPIO_DATA), регистр направления, если переключение in/out поддерживается (GPIO_OUTPUT). Далее (если есть поддержка в самом устройстве), регистр состояния прерываний, регистры прерывания по переднему фронту (rising) и заднему фронту (falling) и по уровню (high и low). Аппаратное прерывание, поставляемое главным контроллером прерываний, как правило, одно на весь порт и делится между всеми входами порта.
Включение/выключения прерывания для входа по низкому уровню сигнала
GPIO_LEVELDETECT1
0x144
OMAP4_GPIO_LEVELDETECT1
Включение/выключения прерывания для входа по высокому уровню сигнала
GPIO_RISINGDETECT
0x148
OMAP4_GPIO_RISINGDETECT
Включение/выключения прерывания для входа по переднему фронту
GPIO_FALLINGDETECT
0x14С
OMAP4_GPIO_FALLINGDETECT
Включение/выключения прерывания для входа по заднему фронту
GPIO_CLEARDATAOUT
0x190
OMAP4_GPIO_CLEARDATAOUT
Переключает соответствующий вход в состояние low
GPIO_SETDATAOUT
0x194
OMAP4_GPIO_SETDATAOUT
Переключает соответствующий вход в состояние high
Примечание: GPIO_IRQSTATUS_N также используется для IRQ ACK. Управление дребезгом, а так же питанием выходит за рамки данной статьи.
ep9301
Разработчик: Cirrus Logic Документация: EP9301 User’s Guide (page 523) Соответствующий ему драйвер gpio: linux/drivers/gpio/gpio-ep93xx.c Соответствующий заголовок: linux/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h Количество входов/выходов: 56 (7 портов gpio — по 8 контактов каждый)
Имя регистра
Смещение
Имя в драйвере
Описание
PADR
0x00
EP93XX_GPIO_REG(0x0)
Регистр состояние входов/выходов доступен для чтения записи
PADDR
0x10
EP93XX_GPIO_REG(0x10)
Контролирует состояние вход/выход (in/out)
GPIOAIntEn
0x9C
int_en_register_offset[0]
Включает прерывания по заданному входу
GPIOAIntType1
0x90
int_type1_register_offset[0]
Задает тип прерывания level/edge
GPIOAIntType2
0x94
int_type2_register_offset[0]
Задает high/rising или low/fallingв зависимости от выбранного типа прерываний
GPIOAEOI
0x98
eoi_register_offset[0]
Регистр для оповещения об обработанном прерывании
IntStsA
0xA0
EP93XX_GPIO_A_INT_STATUS
Регистр состояние прерывания
Примечание: Из них для доступны 7 портов по 8, 8, 1, 2, 3, 2, 4 входов/выходов причем регистрами прерываний обладают только первый, второй и пятый порты. В таблице рассмотрен только порт A. Одной из особенностей ep9301, является то что тип прерываний both на аппаратном уровне не поддерживается, в драйвере происходит переключение в момент срабатывания прерывания. Другая интересная особенность — на порту F каждый контакт имеет свое собственное прерывание.
Регистр состояние входов/выходов доступен для чтения и записи
BT848_GPIO_DATA
0x200
BT848_GPIO_DATA
Контролирует состояние вход/выход (in/out)
Поддержки прерываний нет. Всего два регистра — состояние и настройка in/out.
Размечаем в памяти наше устройство
Для начала выделим место под данные и управление состоянием.
Пусть устройство обладает 8 входами/выходами общего назначения, тогда:
Имя регистра
Смещение
Имя в драйвере
Описание
DATA
0x00
VIRTUAL_GPIO_DATA
Регистр состояние входов/выходов доступен для чтения и записи
OUTPUTEN
0x01
VIRTUAL_GPIO_OUT_EN
Контролирует состояние вход/выход (in/out)
Краткая справка по интерфейсу gpio
Состояние выхода при переключении
Необходимо отметить параметр int value в функции direction_output, которая обслуживает файл /sys/class/gpio/gpioN/direction, принимающий значение не только “in”/”out”, но так же и “high”/“low”, значения которых передаются как параметр value (этот простой факт, по какой-то причине, редко упоминается в руководствах для начинающих).
Динамическое присвоение int base и наследие ARCH_NR_GPIOS
Исторически, количество GPIO в ядре было ограничено параметром ARCH_NR_GPIOS, по умолчанию равном 256 и, впоследствии увеличенном до 512 (версия 3.18).
Его смысл достаточно прост, в ядре не может быть больше GPIO чем значение параметра, если планируемое количество было больше чем значение по умолчанию, он переопределялся в соответствующем заголовочном файле платформы.
Причиной такого поведения было определение таблицы описаний GPIO как статической и максимальная величина смещения для каждого порта была ограничена:
Порты GPIO и их смещения были жестко определены в файлах описывающих аппаратную часть конкретного SOC, например:
Начиная с версии 3.19 статический массив был заменен на динамические для каждого порта GPIO, выделяемого в фукнции gpiochip_add().
Тем не менее ARCH_NR_GPIOS все еще здесь (на момент версии 4.7) и используется для поиска смещения при динамическом присваивании base.
Определим следующие функции нашего драйвера
Задать соответствующий контакт как вход:
Чтение текущего состояния контакта:
Задать соответствующий контакт как выход:
Задать состояние выхода:
Функция регистрации нашего драйвера как устройства gpio_chip:
vgread и vgwrite это просто обертки для функций iowrite8 и ioread8:
Передача значения gpiobase в качестве параметра при динамической загрузки модуля
Загрузка и тестирования модуля
DATA выставлен, OUTPUTEN выставлен.
Добавляем прерывания
Разметка регистров прерываний и базовая обработка прерывания
Примечание: В виртуальном драйвере рассматриваются только EDGEDETECT_RISE и EDGEDETECT_FALL.
Добавляем следующие регистры:
Имя регистра
Смещение
Имя в драйвере
Описание
INTERRUPT_EN
0x01
VIRTUAL_GPIO_INT_EN
Включает прерывания по заданному входу
INTERRUPT_ST
0x02
VIRTUAL_GPIO_INT_ST
Регистр состояния прерывания
INTERRUPT_EOI
0x03
VIRTUAL_GPIO_INT_EOI
Регистр для оповещения об обработанном прерывании
EDGEDETECT_RISE
0x04
VIRTUAL_GPIO_RISING
Включение/выключения прерывания для входа по переднему фронту
EDGEDETECT_FALL
0x05
VIRTUAL_GPIO_FALLING
Включение/выключения прерывания для входа по заднему фронту
LEVELDETECT_HIGH
NC
NOT CONNECTED
LEVELDETECT_LOW
NC
NOT CONNECTED
За обработку прерывания от pci шины отвечает следующая функция, на данный момент её роль заключается всего лишь в уведомлении об обработанном прерывании:
irq_chip и концепция chained_interrupt
На данный момент для нас является главным тот факт, что порты GPIO предоставляющие прерывания каскадируемые от родительского контроллера прерываний обычная практика в дни современного линукса.
Вот почему часть драйвера GPIO отвечающего за прерывания использует irq_chip. Другими словами такой драйвер использует две подсистемы одновременно: gpio_chip и irq_chip.
Беглый взгляд на подсистему irq дает нам следующую картину:
High-Level Interrupt Service Routines (ISRs) — Выполняет всю необходимую работу по обслуживанию прерывания на драйвере устройства. Например, если прерывание используется для индикации доступных для чтения новых данных, работа ISR будет заключаться в копировании данных в соответствующее место.
Interrupt Flow Handling — Данная подсистема отвечает за особенности в реализации обработок прерываний, таких как срабатывание по уровню сигнала (level) или по фронту (edge).
Срабатывание по фронту (Edge-triggering) происходит при определении, что на линии произошло изменение потенциала. Срабатывание по уровню (Level-triggering), определяется как определенное значение потенциала, при этом изменение потенциала не играет роли.
С точки зрения ядра, срабатывание по уровню более сложный случай, так как, после в начале каждого прерывания его необходимо маскировать.
Chip-Level Hardware Encapsulation — Используется для инкапсуляции особенностей реализации работы с аппаратной частью. Данную подсистему можно рассматривать как разновидность “драйвера устройства” для контроллеров прерываний.
Как мы видим ядро берет на себя управление обработкой цепочки прерывания и разницу в реализации типов (по фронту и по уровню), если предоставить соответствующую инфраструктуру.
IRQ Domains
Подсистема IRQ Domain появившееся в патче irq: add irq_domain translation infrastructure позволила отделить локальные для контроллера номера прерываний от номеров прерываний в ядре, предоставив общий массив номеров прерываний. Цитируя официальную документацию: «Сегодня номер IRQ, это просто номер».
До данного обновления аппаратные номера отображались на номерами ядра как 1:1, а каскадирование не поддерживалось. Под аппаратными номерами, понимается локальные для контроллера номера прерывания, которые в нашем случае совпадают с локальными номерами GPIO.
Поскольку наш вектор прерываний достаточно мал, и у нас точно нет интереса в «No map» отображении, наше отображение линейно, фактически номера сопоставляются 1:1 со смещением, разница со старым подходом состоит в том что за присвоение номеров irq и за вычисление смещения отвечает ядро, при этом гарантируется непрерывность выделяемого диапазона.
В каждую функцию интерфейса irq_chip передается указатель на структуру struct irq_data, где irq_data->irq это номер прерывания в ядре linux, a irq_data->hwirq это наш локальный номер прерывания в рамках драйвера. Так же в struct irq_data передается указатель на нашу структуру struct virtual_gpio, что неудивительно.
Связывание irq_chip и gpio_chip
Если бы мы ориентировались на более младшие версии ядра, нам пришлось бы воспользоваться функцией irq_domain_add_simple для отображения наших номер, но с версии 3.15 в патче gpio: add IRQ chip helpers in gpiolib patch нет необходимости напрямую использовать интерфейс IRQ Domain.
Поэтому вместо прямого использования интерфейса IRQ Domain и предоставления инфраструктуры для отображения локальных номеров на глобальные (.map() ops), мы воспользуемся функциями gpiochip_irqchip_add и gpiochip_set_chained_irqchip (зависят от параметра GPIOLIB_IRQCHIP Kconfig).
Прекрасным примером использования и простоты в применении, является драйвер gpio-pl061.
Привязываем наш irq_chip к уже существующему gpio_chip:
handle_edge_irq — это один из встроенных обработчиков потока, который берет на себя управление цепочкой прерывания по фронтам.
Примечание: прерывания по фронтам является наиболее распространенным. Главное отличие от прерываний по уровню заключается как раз в управлении цепочкой, прерывание по уровню маскируется в ядре сразу после получения.
Вызовом функции gpiochip_set_chained_irqchip мы сообщаем ядру, что наш irq_chip использует прерывание от PCI шины и наши прерывания каскадируются от pdev->irq.
Доработаем наш обработчик, чтобы он генерировал прерывания в зависимости от состояния VIRTUAL_GPIO_INT_ST:
irq_find_mapping — вспомогательная функция для трансляции локального номера входа в глобальный номер прерывания.
Собираем все вместе
Прежде всего, отметим, что интерфейс irq_chip нашего драйвера, выглядит следующим образом:
Функция ack() всегда тесна связана с аппаратной спецификой контроллера. Некоторым устройствам, например требуется подтверждение обработки запроса прерывания, прежде чем могут быть обслужены последующие запросы.
В нашем случае в программе vg_get_set – используется достаточно грубая эмуляция регистра eoi. После выставления флага статуса прерывания, в цикле постоянно опрашивается eoi регистр. Когда бит входа уведомления о прерывании выставляется драйвером, происходит обнуление регистра eoi и снятие бита статуса прерывания на входе.
Маскирование и демаскирование производится записью соответствующего значения в регистр INTERRUPT_EN.
irq_type позволяет задать тип триггера — на текущий момент в ядре определены следующие типы: IRQ_TYPE_NONE — тип не задан IRQ_TYPE_EDGE_RISING — по переднему фронту IRQ_TYPE_EDGE_FALLING — по заднему фронту IRQ_TYPE_EDGE_BOTH — по переднему и заднему фронту IRQ_TYPE_LEVEL_HIGH — по высокому уровню IRQ_TYPE_LEVEL_LOW — по низкому уровню
Тестирование и результаты
Для тестирования передачи информации о прерываниях в user space, воспользуемся специально написанной утилитой vg_guest_client. Согласно документации по gpio_sysfs, “Если вы используете select для отслеживания событий, задайте файловый дескриптор (входа) в exceptfds”.
Подготавливаем входы к работе при помощи sysfs:
Примечание: gpio на подавляющем большинстве устройств по умолчанию инициализируются как входы.
Цепочка вызовов от нашего обработчика прерывания к уведомлению pselect:
Заключение
Данная статья подразумевалась мной, как базовая для материала, который сложно, или даже невозможно, представить без какого-либо общего вступления. Qemu в паре с ivshmem послужили отличным и понятным базисом для этой цели. Причиной выбора этой конкретной связки является наличие вменяемой документации и прозрачности использования.
Сама работа с gpio sysfs ничем не отличается для любых устройств с реализованной поддержкой sysfs, любая инструкция по использованию GPIO может быть успешно применена к другому подобному устройству, как и задумывалось при разработке данного интерфейса. Все различия заканчиваются на уровне конкретного драйвера устройства.
Сам драйвер, несмотря на безусловную образовательную ценность, далек от идеала в контексте современного ядра. Для подобного простого драйвера стоит использовать generic-gpio драйвер, созданный, чтобы избежать похожего, повторяющегося кода для mmio gpio драйверов, использование которого, правда, не так очевидно. Обработку прерываний можно было бы сделать более элегантной, а значения смещений регистров лучше хранить в структуре драйвера.
Так же нельзя упускать из виду последние изменения в gpiolib — sysfs gpio теперь является устаревшей. Новый основанный на ioctl интерфейс для gpiolib на пути становления как новый стандарт для общения с GPIO. Но младшие версии еще долго будут использоваться, к тому же никто не собирается на данный момент убирать из ядра старый интерфейс. У меня например до сих пор есть устройства успешно работающие на версии ядра 2.6.34.
Драйвер входит в состав пакета AMD Chipset Drivers.
Скорее всего нужен для корректной работы шины PCI и для обеспечения максимальной скорости. Что такое шина PCI? Это разьем на материнской плате, часто не один, в который могут устанавливаться разные устройства — например сетевая плата, звуковая плата, внешний Wi-Fi модуль, дополнительные порты USB, и конечно же видеокарта. Последнее — пожалуй наиболее важное, поэтому ставить драйвер нужно. Тем более, что AMD добавила поддержку PCI Express 4.0, для корректной работы как раз возможно и нужен драйвер.
Windows 10 способна автоматически обновить данный драйвер. Это хорошо, но после установки, можно попробовать установить и драйвер с официального сайта AMD или с сайта вашей модели материнки. Редко, но иногда Windows ставит драйвер не очень старый, но стабильный, однако при этом не самой последней версии.
Вообще на самом деле шина называется не PCI, а PCI-E.
Вот как выглядит разьем PCI-E на материнке:
Кстати здесь первые три слева — это просто PCI, не Express, а обычные, и они существовали еще во времена Pentium 4. Сегодня их уже нет на современных платах, потому что они медленные. Три PCI, которые справа — уже современные разьемы, быстрее, скорости достаточно для современных видеокарт. PS: устройства просто PCI и PCI Express не совместимы, там элементарно физически нет совместимости.
Чтобы посмотреть установлены дрова или нет, то стоит открыть диспетчер устройств (Win + R > devmgmt.msc) и посмотреть нет ли устройства с восклицательным знаком. Второе — это открыть окно Программы и компоненты (Win + R > appwiz.cpl) и посмотреть в списке нет ли там установленных драйверов AMD PCI Device Driver, кроме этого, в этом же окне можно нажать Просмотр установленных обновлений — там тоже может быть нужная информация.
Собственно если драйвер не установлен, то может быть такая картина в диспетчере:
Надеюсь информация оказалась полезной. Удачи и добра, до новых встреч друзья!