История изменений
Исправление 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.