Картографирование MMIO региона с обратной записью не работает
Я хочу, чтобы все запросы на чтение и запись к устройству PCIe кэшировались кэшем ЦП. Тем не менее, это не работает, как я ожидал.
Это мои предположения о регионах с обратной записью MMIO.
- Запись на устройство PCIe происходит только при обратной записи в кэш.
- Размер полезной нагрузки TLP равен размеру блока кеша (64B).
Однако захваченные TLP не соответствуют моим предположениям.
- Запись на устройство PCIe происходит при каждой записи в регион MMIO.
- Размер полезной нагрузки TLP составляет 1B.
Я пишу 8 байт 0xff
в регион MMIO со следующей программой пространства пользователя и драйвером устройства.
Часть пользовательской программы
struct pcie_ioctl ioctl_control;
ioctl_control.bar_select = BAR_ID;
ioctl_control.num_bytes_to_write = atoi(argv[1]);
if (ioctl(fd, IOCTL_WRITE_0xFF, &ioctl_control) < 0) {
printf("ioctl failed\n");
}
Часть драйвера устройства
case IOCTL_WRITE_0xFF:
{
int i;
char *buff;
struct pci_cdev_struct *pci_cdev = pci_get_drvdata(fpga_pcie_dev.pci_device);
copy_from_user(&ioctl_control, (void __user *)arg, sizeof(ioctl_control));
buff = kmalloc(sizeof(char) * ioctl_control.num_bytes_to_write, GFP_KERNEL);
for (i = 0; i < ioctl_control.num_bytes_to_write; i++) {
buff[i] = 0xff;
}
memcpy(pci_cdev->bar[ioctl_control.bar_select], buff, ioctl_control.num_bytes_to_write);
kfree(buff);
break;
}
Я изменил MTRR для обратной записи соответствующего региона MMIO. Регион MMIO начинается с 0x0c7300000, а длина составляет 0x100000 (1 МБ). Следующие cat /proc/mtrr
результаты для разных политик. Обратите внимание, что я сделал каждый регион эксклюзивным.
Uncacheable
reg00: base=0x080000000 ( 2048MB), size= 1024MB, count=1: uncachable
reg01: base=0x380000000000 (58720256MB), size=524288MB, count=1: uncachable
reg02: base=0x0c0000000 ( 3072MB), size= 64MB, count=1: uncachable
reg03: base=0x0c4000000 ( 3136MB), size= 32MB, count=1: uncachable
reg04: base=0x0c6000000 ( 3168MB), size= 16MB, count=1: uncachable
reg05: base=0x0c7000000 ( 3184MB), size= 1MB, count=1: uncachable
reg06: base=0x0c7100000 ( 3185MB), size= 1MB, count=1: uncachable
reg07: base=0x0c7200000 ( 3186MB), size= 1MB, count=1: uncachable
reg08: base=0x0c7300000 ( 3187MB), size= 1MB, count=1: uncachable
reg09: base=0x0c7400000 ( 3188MB), size= 1MB, count=1: uncachable
Написать комбинирование
reg00: base=0x080000000 ( 2048MB), size= 1024MB, count=1: uncachable
reg01: base=0x380000000000 (58720256MB), size=524288MB, count=1: uncachable
reg02: base=0x0c0000000 ( 3072MB), size= 64MB, count=1: uncachable
reg03: base=0x0c4000000 ( 3136MB), size= 32MB, count=1: uncachable
reg04: base=0x0c6000000 ( 3168MB), size= 16MB, count=1: uncachable
reg05: base=0x0c7000000 ( 3184MB), size= 1MB, count=1: uncachable
reg06: base=0x0c7100000 ( 3185MB), size= 1MB, count=1: uncachable
reg07: base=0x0c7200000 ( 3186MB), size= 1MB, count=1: uncachable
reg08: base=0x0c7300000 ( 3187MB), size= 1MB, count=1: write-combining
reg09: base=0x0c7400000 ( 3188MB), size= 1MB, count=1: uncachable
Write-назад
reg00: base=0x080000000 ( 2048MB), size= 1024MB, count=1: uncachable
reg01: base=0x380000000000 (58720256MB), size=524288MB, count=1: uncachable
reg02: base=0x0c0000000 ( 3072MB), size= 64MB, count=1: uncachable
reg03: base=0x0c4000000 ( 3136MB), size= 32MB, count=1: uncachable
reg04: base=0x0c6000000 ( 3168MB), size= 16MB, count=1: uncachable
reg05: base=0x0c7000000 ( 3184MB), size= 1MB, count=1: uncachable
reg06: base=0x0c7100000 ( 3185MB), size= 1MB, count=1: uncachable
reg07: base=0x0c7200000 ( 3186MB), size= 1MB, count=1: uncachable
reg08: base=0x0c7300000 ( 3187MB), size= 1MB, count=1: write-back
reg09: base=0x0c7400000 ( 3188MB), size= 1MB, count=1: uncachable
Далее приведены захваты сигналов для записи 8B с различными политиками. Я использовал встроенный логический анализатор (ILA) для захвата этих сигналов. Пожалуйста посмотри pcie_endpoint_litepcietlpdepacketizer_tlp_req_payload_dat
когда pcie_endpoint_litepcietlpdepacketizer_tlp_req_valid
установлено. Вы можете посчитать количество пакетов, считая pcie_endpoint_litepcietlpdepacketizer_tlp_req_valid
в этом примере формы волны.
- Uncacheable: ссылка -> правильно, 1B x 8 пакетов
- Комбинирование записи: ссылка -> правильно, 8B x 1 пакет
- Обратная запись: ссылка -> неожиданная, 1B x 8 пакетов
Конфигурация системы, как показано ниже.
- Процессор: Intel(R) Xeon(R) CPU E5-2630 v4 @ 2,20 ГГц
- ОС: ядро Linux 4.15.0-38
- Устройство PCIe: Xilinx FPGA KC705, запрограммированный с litepcie
Ссылки по теме
- Генерация 64-байтового чтения PCIe TLP из процессора x86
- Как реализовать 64B PCIe* Burst Transfer на архитектуре Intel®
- Пишет объединяющий буфер из строя, пишет и PCIe
- Поддерживает ли Ryzen кэширование с обратной записью для Memory Mapped IO (через интерфейс PCIe)?
- MTRR (регистр диапазона типа памяти)
- Паттинг линукс
- Вплоть до TLP: как говорят устройства PCI Express (Часть I)
1 ответ
Короче говоря, кажется, что отображение обратной записи MMIO не работает по проекту.
Пожалуйста, загрузите ответ, если кто-то обнаружит, что это возможно.
Я пришел, чтобы найти статьи и ответы Джона Маккальпина. Во-первых, отображение обратной записи MMIO невозможно. Во-вторых, на некоторых процессорах возможен обходной путь.
Картирование MMIO региона с обратной записью невозможно
К вашему сведению: тип WB не будет работать с отображенным в память вводом-выводом. Вы можете запрограммировать биты для установки отображения как WB, но система потерпит крах, как только получит транзакцию, которую она не знает, как обрабатывать. Теоретически возможно использовать WP или WT для получения кэшированных чтений из MMIO, но согласованность должна обрабатываться программно.
Только когда я установил для PAT и MTRR значение WB, происходит сбой ядра
Обходной путь возможен на некоторых процессорах
Заметки о кэшированном доступе к отображенным в память областям ввода-вывода, Джон Маккальпин
Существует один набор отображений, который можно настроить для работы, по крайней мере, на некоторых процессорах x86-64, и он основан на двойном отображении пространства MMIO. Сопоставьте диапазон MMIO с набором атрибутов, которые позволяют объединять записи (но только чтение без кэширования). Сопоставьте диапазон MMIO во второй раз с набором атрибутов, которые разрешают чтение строки кэша (но только не кэшированные, не объединенные в запись хранилища).