LINUX.ORG.RU

remap PCI memory в user-space


0

0

Никак не получается получить доступ к памяти с pci платки в программе, может кто знает что не правильно:

В драйвере память мапируется так:

vma->vm_pgoff = pciBase >> PAGE_SHIFT; //pciBase начало окна памяти на плате в pci

if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot) != 0) { printk(«Uni mmap: remap_pfn_range failed !\n»); return (-EAGAIN); }

vma->vm_file = file; vma->vm_flags |= VM_IO | VM_RESERVED;

В програмке пытаюсь смапировать так:

char * data;

printf(«\n\r\t Start open dev»); handl = open(«/dev/vxb_m0»,O_RDWR,0); if(handl > 0)

data = (char *) mmap(0,0x10000,PROT_WRITE|PROT_READ,MAP_SHARED,handl,0);

printf(«\n\r\t test_addr0x%X : 0x%X \n»,(data+0xc000),*(data+0xc000));

Все вроде выделяется и мапируется, но при обращении по указателю читается 0xff.


Вот это работает:

static int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
        struct my_dev *dev = (struct my_dev *)filp->private_data;
        resource_size_t addr;
        unsigned long len, pfn;
        int bar = vma->vm_pgoff;

        if (bar >= PCI_BARS_NUM)
                return -EINVAL;

        len = pci_resource_len(dev->pdev, bar);
        if (!len)
                return -EINVAL;

        if (PAGE_ALIGN(len) != PAGE_ALIGN(vma->vm_end - vma->vm_start))
                return -EINVAL;

        addr = pci_resource_start(dev->pdev, bar);
        pfn  = virt_to_phys(bus_to_virt(addr)) >> PAGE_SHIFT;

        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        vma->vm_flags |= VM_IO;

        if (io_remap_pfn_range(vma, vma->vm_start, pfn,
                               len, vma->vm_page_prot)) {
                printk(KERN_ERR "mmap: io_remap_pfn_range failed\n");
                return -EAGAIN;
        }

        printk("mmap: bar=%d, offset=%llx\n", bar, addr & (~PAGE_MASK));
        return 0;
}
ttnl ★★★★★
()
Ответ на: комментарий от ttnl

И не забудь сделать отступ от начала страницы. Ресурсы не обязательно
сначала начинаются.

ttnl ★★★★★
()

Кажется, вы изобретаете UIO

tailgunner ★★★★★
()
Ответ на: комментарий от ttnl

pci плата самодельная, сконфигурирован только первый BAR на 4к для конфигурационных регистров поэтому pci_resource_start тут не поможет ) окна выделяю сам. а флаг vma->VM _RESERVED когда нужен? поправил по аналогии, но чтот всеравно не заработало.

вот код моей функции:



static int uni_mmap(struct file *file, struct vm_area_struct *vma)
{
    unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
    image_desc_t *p;


    file->private_data =  pciBase;//&image[minor];
   // p = file->private_data;



printk("\n\runi_mmap minor:%i phys_start:0x%X",minor,pciBase);


if (minor < MAX_IMAGE) {                     // master image
        
	if (vma->vm_end - vma->vm_start > 0x10000){ //p->size) {
            printk ("Uni mmap: INVALID, start at 0x%08lx end 0x%08lx,pstart 0x%08x, pend 0x%08x\n", vma->vm_start,vma->vm_end, pciBase, pciBase+0x10000);//p->phys_start, p->phys_end);
            return -EINVAL;
        }

        vma->vm_pgoff = virt_to_phys(bus_to_virt(pciBase)) >> PAGE_SHIFT; //p->phys_start >> PAGE_SHIFT;
	printk("\n\r\t\t pg_off:0x%X ",vma->vm_pgoff);
	//vma->vm_pgoff << PAGE_SHIFT
    }


    if ((minor == CONTROL_MINOR) || (minor > MAX_MINOR))
        return -EBADF;

         vma->vm_flags |= VM_IO;
         vma->vm_flags |= VM_RESERVED;

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

    if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                        vma->vm_end - vma->vm_start, vma->vm_page_prot) != 0) {
        printk("Uni mmap: remap_pfn_range failed !\n");
        return (-EAGAIN);
    }

    vma->vm_file = file;

       
   


return 0;


}

cxz
() автор топика
Ответ на: комментарий от cxz
...
pciBase=getPciBase(0x1000);
...

static u32 getPciBaseAddr(u32 size)
{
    #define MEM_START 0x40000000
    #define MEM_STOP  0xF0000000
    u32 pciAddr, stepping = 0x01000000;

    for (pciAddr = MEM_START; pciAddr < MEM_STOP; pciAddr += stepping)
        if (check_mem_region(pciAddr, size) == 0)
            break;

    if (pciAddr >= MEM_STOP) {
        printk(" \n\r mem request stepping /= 10 \n");
        stepping /= 10;
        for (pciAddr = MEM_START; pciAddr < MEM_STOP; pciAddr += stepping)
            if (check_mem_region(pciAddr, size) == 0)
                break;
    }

    if (pciAddr >= MEM_STOP)
        {
	printk("\n\rerror mem request");
	return 0;
	}
	printk("\n\rZulu: request_mem_region ok!; pciAddr:0x%X size:0x%X  \n",pciAddr,size);
    request_mem_region(pciAddr, size, "uni");

    return pciAddr;

}


cxz
() автор топика
Ответ на: комментарий от ttnl

да вроде правильно, во всяком случае readl и writel нормально работают с этим окном.

cxz
() автор топика
Ответ на: комментарий от cxz

>vma->VM _RESERVED когда нужен

В remap_pfn_range():

* VM_IO tells people not to look at these pages
* (accesses can have side effects).
* VM_RESERVED is specified all over the place, because
* in 2.4 it kept swapout's vma scan off this vma; but
* in 2.6 the LRU scan won't even find its pages, so this
* flag means no more than count its pages in reserved_vm,
* and omit it from core dump, even when VM_IO turned off.

readl и writel нормально работают с этим окном


В каком смысле правильно? Ты сделал pci_iomap, потом распечатал с %u
и появились осмысленные данные?

request_mem_regio/check_mem_region


Такой конструкцией я не пользовался, поэтому проверить не могу.
У тебя, похоже, старое ядро. Странно то, что ты не читаешь
конфигурационное пространство. В этом случае, кажется, была
опция ядра, которая запрещала линуксу настраивать бары, и
предписывала пользоваться настройками BIOS. Ты её используешь?
Вообще советую делать обычным способом: pci_driver, pci_resource* и т.д.

ttnl ★★★★★
()
Ответ на: комментарий от ttnl

В каком смысле правильно? Ты сделал pci_iomap, потом распечатал с %u

и появились осмысленные данные?

Да.

Странно то, что ты не читаешь

конфигурационное пространство.

Ядро новое, 2.6.33, конфигурационное пространство есть, нет остальных 4-х окон памяти для io:

 uni_dev = pci_get_device(0x10e3,0x0000, uni_dev);
    if (!uni_dev) {
        printk("Uni device not found!\n");
        return -1;
    }

    pci_write_config_dword(uni_dev, PCI_MISC0, 0); // Turn latency off

    printk("Uni found at bus %x device %x\n",
           uni_dev->bus->number, uni_dev->devfn);
//---------------------------------------------------------------------------------zulu-------------------------------------
    pci_read_config_dword(uni_dev, PCI_CSR, &status);
    printk(" Vendor = %04X Device = %04X Status = %08X",
           uni_dev->vendor, uni_dev->device, status);
    printk("  Class = %08X\n", uni_dev->class);

    pci_read_config_dword(uni_dev, PCI_MISC0, &temp);
    printk("  Misc0 = %08X\n", temp);

    // Setup Universe Config Space
    // This is a 4k wide memory area that needs to be mapped into the
    // kernel virtual memory space so we can access it.

    pci_write_config_dword(uni_dev, PCI_BS, CONFIG_REG_SPACE); //zulu #define CONFIG_REG_SPACE 0xA0000000

    pci_read_config_dword(uni_dev, PCI_BS, &ba);
    baseaddr = (void __iomem *) ioremap_nocache(ba, 4096);
   

cxz
() автор топика
Ответ на: комментарий от cxz

Блин, ну зачем ты извращаешься. Делай стандартными методами.
Прописываешь id_table, регистрируешь драйвер (pci_register_driver),
и все ресурсы вычисляются автоматически. В probe создаешь файл
устройства и дальше чистый PROFIT.

Там же кучу манипуляций надо с барами произвести, чтобы узнать
адреса и размеры. Все это уже реализовано в ф-ции __pci_read_base.
Зачем изобретать велосипед?!

ttnl ★★★★★
()
Ответ на: комментарий от cxz

Открой любой драйвер и посмотри, *ля.

ttnl ★★★★★
()
Ответ на: комментарий от cxz

Открой любой драйвер и посмотри, *ля.

ttnl ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.