Habilitando o acesso de E / S de combinação de gravação no espaço do usuário

Eu tenho um dispositivo PCIe com um driver de espaço de usuário. Estou escrevendo comandos para o dispositivo através de uma BAR, os comandos são sensíveis à latência e a quantidade de dados é pequena (~ 64 bytes), portanto, não quero usar o DMA.

Se eu remapear o endereço físico da BAR no kernel usandoioremap_wc e depois escreva 64 bytes na barradentro do kernel, Posso ver que os 64 bytes são gravados como um único TLP sobre PCIe. Se eu permitir que meu programa de espaço de usuáriommap a região com oMAP_SHARED flag e escreva 64 bytes. Vejo vários TPLs no barramento PCIe, em vez de uma única transação.

De acordo com o kernelDocumentação PAT Deveria ser capaz de exportar páginas combinadas de gravação para o espaço do usuário:

Os drivers que desejam exportar algumas páginas para o espaço do usuário fazem isso usando a interface mmap e uma combinação de

1)pgprot_noncached()

2)io_remap_pfn_range() ouremap_pfn_range() ouvm_insert_pfn()

Com suporte para PAT, uma nova APIpgprot_writecombine está sendo adicionado. Portanto, os drivers podem continuar usando a sequência acima, compgprot_noncached() oupgprot_writecombine() na etapa 1, seguida pela etapa 2.

Com base nesta documentação, o código relevante do kernel do meu manipulador mmap se parece com o seguinte:

 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);

 return io_remap_pfn_range(vma,
                           vma->vm_start,
                           info->mem[vma->vm_pgoff].addr >> PAGE_SHIFT,
                           vma->vm_end - vma->vm_start,
                           vma->vm_page_prot);

Meu dispositivo PCIe aparece em lspci com as barras marcadas como pré-selecionáveis conforme o esperado:

    Latency: 0, Cache Line Size: 64 bytes
    Interrupt: pin A routed to IRQ 11
    Region 0: Memory at d8000000 (64-bit, prefetchable) [size=32M]
    Region 2: Memory at d4000000 (64-bit, prefetchable) [size=64M]

Quando eu ligommap from userspace, vejo uma mensagem de log (tendo definido o parâmetro de inicialização do kernel debugpat):

reserve_memtype adicionado [mem 0xd4000000-0xd7ffffff], acompanhamento de combinação de gravação, combinação de req gravação e combinação de gravação ret

Eu também posso ver em/sys/kernel/debug/x86/pat_memtype_list que uma entrada PAT parece correta e não há regiões sobrepostas:

write-combining @ 0xd4000000-0xd8000000
uncached-minus  @ 0xd8000000-0xda000000

Também verifiquei se não há entradas MTRR que entrariam em conflito com a configuração PAT. Até onde eu posso ver, tudo está configurado corretamente para que a combinação de gravação ocorra no espaço do usuário, porém, usando um analisador PCIe para observar as transações no barramento PCIe, o padrão de acesso do espaço do usuário é completamente diferente da mesma gravação executada no kernel depois de umioremap_wc ligar.

Por que a combinação de gravação não está funcionando conforme o esperado no espaço do usuário?

O que posso fazer para depurar ainda mais?

Atualmente, estou executando em um único soquete i7-3930K de 6 núcleos.

questionAnswers(1)

yourAnswerToTheQuestion