LINUX.ORG.RU

История изменений

Исправление I-Love-Microsoft, (текущая версия) :

Решил инициализировать перед запросом блока не нулями, а например AAAAAAAA... и увидел что там где ошибки - всегда эти А. Ну ясно, всё теперь понятно - не успевает упасть в память, не долетают пакеты. А ведь я полагал точно так же, что раз TLP пакет с прерыванием высылается после последнего пакета с данными то всё должно быть окей.

Сбойные данные возникают последовательной пачкой, размер которой не кратен размеру TLP-пакетов (они по 64 байта payload, или по 16 DW). Сбои наблюдаются в в районе первой тысячи DW (всего 65 тысяч).

Я полагаю, что я должен добавить некоторую задержку после последнего пакета с данными, и лишь после этого высылать MSI (прерывание). Но какой же размер задержки? Как узнать когда хост всё прожевал? Не люблю костыли вроде задержек, времен i80386.

Поинтер volatile?

dma_addr_t dma_device;
void *dma_driver; // работаю с этим
...
unsigned int *dw;
dw = (unsigned int*) device->dma_driver;

Данные смотрю в device->dma_driver. Как volatile поможет?

Проверяю так:

static ssize_t mypci_read(struct file *f, char *buffer, size_t size, loff_t *offset)
{
        int i = 0, err = 0;
        unsigned int *dw;
        unsigned int prev = 0;

        int minor = iminor(f->f_inode), ret, sz = 0;
        struct mypci_device *device = NULL;

        if(minor >= mypci_used) return 0;
        if(f->f_flags & O_NONBLOCK) return 0;
        if(size == 0) return 0;

        device = &devices[minor];
        device->dma_finished = 0;
        dw = (unsigned int*) device->dma_driver;
        for(i = 0; i < (MYPCI_DMA_BLOCK / 4); i++) dw[i] = 0xAAAAAAAA;
        writel(device->dma_device & 0xFFFFFFFF, device->mmio);
        if(wait_event_interruptible(device->wait, device->dma_finished != 0)) return 0;

#if 1 // check counter data
        prev = dw[0];
        for(i = 1; i < (MYPCI_DMA_BLOCK / 4); i++)
        {
                if(dw[i] != (prev + 1))
                {
                        printk(KERN_ERR "mypci: 0x%08X -> %d @ %d\n", dw[i], err, i);
                        err++;
                }
                prev = dw[i];
        }
        if(err > 0) printk(KERN_ERR "mypci: read err %d\n", err);
        else printk(KERN_ERR "mypci: read no errors\n");
        printk(KERN_ERR "mypci: 0x%08X / 0x%08X\n", dw[0], dw[(MYPCI_DMA_BLOCK / 4) - 1]);
#endif

Так читаются 8 блоков: http://paste.org.ru/?7r2dk5

Исправление I-Love-Microsoft, :

Решил инициализировать перед запросом блока не нулями, а например AAAAAAAA... и увидел что там где ошибки - всегда эти А. Ну ясно, всё теперь понятно - не успевает упасть в память, не долетают пакеты. А ведь я полагал точно так же, что раз TLP пакет с прерыванием высылается после последнего пакета с данными то всё должно быть окей.

Сбойные данные возникают последовательной пачкой, размер которой не кратен размеру TLP-пакетов (они по 64 байта payload, или по 16 DW). Сбои наблюдаются в в районе первой тысячи DW (всего 65 тысяч).

Я полагаю, что я должен добавить некоторую задержку после последнего пакета с данными, и лишь после этого высылать MSI (прерывание). Но какой же размер задержки? Как узнать когда хост всё прожевал? Не люблю костыли вроде задержек, времен i80386.

Поинтер volatile?

dma_addr_t dma_device;
void *dma_driver; // работаю с этим
...
unsigned int *dw;
dw = (unsigned int*) device->dma_driver;

Данные смотрю в device->dma_driver. Как volatile поможет?

Проверяю так:

static ssize_t mypci_read(struct file *f, char *buffer, size_t size, loff_t *offset)
{
        int i = 0, err = 0;
        unsigned int *dw;
        unsigned int prev = 0;

        int minor = iminor(f->f_inode), ret, sz = 0;
        struct mypci_device *device = NULL;

        if(minor >= mypci_used) return 0;
        if(f->f_flags & O_NONBLOCK) return 0;
        if(size == 0) return 0;

        device = &devices[minor];
        device->dma_finished = 0;
        dw = (unsigned int*) device->dma_driver;
        for(i = 0; i < (MYPCI_DMA_BLOCK / 4); i++) dw[i] = 0xAAAAAAAA;
        writel(device->dma_device & 0xFFFFFFFF, device->mmio);
        if(wait_event_interruptible(device->wait, device->dma_finished != 0)) return 0;

#if 1 // check counter data
        prev = dw[0];
        for(i = 1; i < (MYPCI_DMA_BLOCK / 4); i++)
        {
                if(dw[i] != (prev + 1))
                {
                        printk(KERN_ERR "mypci: 0x%08X -> %d @ %d\n", dw[i], err, i);
                        err++;
                }
                prev = dw[i];
        }
        if(err > 0) printk(KERN_ERR "mypci: read err %d\n", err);
        else printk(KERN_ERR "mypci: read no errors\n");
        printk(KERN_ERR "mypci: 0x%08X / 0x%08X\n", dw[0], dw[(MYPCI_DMA_BLOCK / 4) - 1]);
#endif

Исправление I-Love-Microsoft, :

Решил инициализировать перед запросом блока не нулями, а например AAAAAAAA... и увидел что там где ошибки - всегда эти А. Ну ясно, всё теперь понятно - не успевает упасть в память, не долетают пакеты. А ведь я полагал точно так же, что раз TLP пакет с прерыванием высылается после последнего пакета с данными то всё должно быть окей.

Сбойные данные возникают последовательной пачкой, размер которой не кратен размеру TLP-пакетов (они по 64 байта payload, или по 16 DW). Сбои наблюдаются в в районе первой тысячи DW (всего 65 тысяч).

Я полагаю, что я должен добавить некоторую задержку после последнего пакета с данными, и лишь после этого высылать MSI (прерывание). Но какой же размер задержки? Как узнать когда хост всё прожевал? Не люблю костыли вроде задержек, времен i80386.

Поинтер volatile?

dma_addr_t dma_device;
void *dma_driver; // работаю с этим
...
unsigned int *dw;
dw = (unsigned int*) device->dma_driver;

Данные смотрю в device->dma_driver. Как volatile поможет?

Исходная версия I-Love-Microsoft, :

Решил инициализировать перед запросом блока не нулями, а например AAAAAAAA... и увидел что там где ошибки - всегда эти А. Ну ясно, всё теперь понятно - не успевает упасть в память, не долетают пакеты. А ведь я полагал точно так же, что раз TLP пакет с прерыванием высылается после последнего пакета с данными то всё должно быть окей.

Сбойные данные возникают последовательной пачкой, размер которой не кратен размеру TLP-пакетов (они по 64 байта payload, или по 16 DW). Сбои наблюдаются в в районе первой тысячи DW (всего 65 тысяч).

Я полагаю, что я должен добавить некоторую задержку после последнего пакета с данными, и лишь после этого высылать MSI (прерывание). Но какой же размер задержки? Как узнать когда хост всё прожевал? Не люблю костыли вроде задержек, времен i80386.