Регион PCIE не выровнен и не согласован

Я разрабатываю драйвер устройства PCIE для openwrt, и я столкнулся с ошибкой шины данных при попытке доступа к io-памяти в прерывании таймера, о чем я упоминал в моем последний вопрос. После долгих исследований я думаю, что, возможно, нашел причину, но не могу ее решить. Ниже мои проблемы.

На прошлой неделе я узнал, что размер области pcie мог измениться во время запуска системы. Размер области bar0 в моем драйвере составляет 4096 (возврат из pci_resource_len), а размер области - 4097 в lspci -vv, что нарушает размер страницы ядра Linux. Читая исходный код pciutil, я обнаружил, что команда lspci извлекает информацию о pcie из /sys/devices/pci0000:00/0000:00:00.0/resouce файла. Поэтому я удаляю все свои пользовательские компоненты и запускаю исходный openwrt на своем маршрутизаторе. По cat /sys/devices/pci0000:00/0000:00:00.0/resouce первая строка результата (bar0)

0x0000000010008000 0x0000000010009000 0x0000000000040200

Кроме того, я также проверяю содержание /proc/iomem, а содержание, относящееся к PCIE,

10000000-13ffffff : mem_base
    10000000-13ffffff : PCI memory space
        10000000-10007fff : 0000:00:00.0
        10008000-10008fff : 0000:00:00.0

Очень странно, что размер региона bar0, обозначенный двумя файлами выше, отличается! Согласно механизму PCIE размер области всегда должен быть степенью 2. Каким образом размер области становится 4097?


person Woody Huang    schedule 03.11.2017    source источник


Ответы (1)


Потратив несколько недель на чтение исходного кода ядра Linux, я обнаружил, что это ошибка ядра 4.4.14 Linux.

Содержимое /sys/devices/pci0000:00/0000:00:00.0/resouce создается функцией resource_show в файле drivers/pci/pci-sysfs.c. Соответствующий код

for (i = 0; i < max; i++) {
    struct resource *res =  &pci_dev->resource[i];
    pci_resource_to_user(pci_dev, i, res, &start, &end);
    str += sprintf(str, "0x%016llx 0x%016llx 0x%016llx\n",
               (unsigned long long)start,
               (unsigned long long)end,
               (unsigned long long)res->flags);
}

Фактически вызываемая функция pci_resource_to_user находится в arch/mips/include/asm/pci.h

static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
        const struct resource *rsrc, resource_size_t *start,
        resource_size_t *end)
{
    phys_addr_t size = resource_size(rsrc);

    *start = fixup_bigphys_addr(rsrc->start, size);
    *end = rsrc->start + size;
}

Расчет *end неверен и должен быть заменен на

*end = rsrc->start + size - (size ? 1 : 0)
person Woody Huang    schedule 14.11.2017