/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
1
#include <linux/version.h>
2
#include <linux/string.h>
3
#include <linux/types.h>
4
#include <linux/list.h>
5
#include <linux/pci.h>
6
#include <linux/wait.h>
7
#include <linux/mm.h>
8
#include <linux/pagemap.h>
9
#include <linux/hugetlb.h>
363 by Suren A. Chilingaryan
Resolution of the user-space BAR addresses
10
#include <linux/cdev.h>
410 by Suren A. Chilingaryan
Support kernel 4.12 by Timo
11
#include <linux/version.h>
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
12
365 by Suren A. Chilingaryan
Restructure driver headers
13
#include "base.h"
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
14
15
static unsigned long pcidriver_follow_pte(struct mm_struct *mm, unsigned long address)
16
{
17
    pgd_t *pgd;
18
    pud_t *pud;
19
    pmd_t *pmd;
20
    pte_t *pte;
21
410 by Suren A. Chilingaryan
Support kernel 4.12 by Timo
22
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
23
    spinlock_t *ptl;
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
24
    unsigned long pfn = 0;
25
26
27
    pgd = pgd_offset(mm, address);
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
28
    if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
29
        return 0;
30
410 by Suren A. Chilingaryan
Support kernel 4.12 by Timo
31
        // pud_offset compatibility with pgd_t* broken from Kernel Version 4.12 onwards. See: https://github.com/torvalds/linux/commit/048456dcf2c56ad6f6248e2899dda92fb6a613f6
32
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
33
    p4d_t *p4d;
34
    p4d = p4d_offset(pgd, address);
35
    pud = pud_offset(p4d, address);
411 by Suren A. Chilingaryan
Fix elif -> else
36
#else
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
37
    pud = pud_offset(pgd, address);
410 by Suren A. Chilingaryan
Support kernel 4.12 by Timo
38
#endif
39
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
40
    if (pud_none(*pud) || unlikely(pud_bad(*pud)))
41
        return 0;
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
42
43
    pmd = pmd_offset(pud, address);
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
44
    if (pmd_none(*pmd))
45
        return 0;
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
46
47
    pte = pte_offset_map_lock(mm, pmd, address, &ptl);
48
    if (!pte_none(*pte))
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
49
        pfn = (pte_pfn(*pte) << PAGE_SHIFT);
50
    pte_unmap_unlock(pte, ptl);
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
51
52
    return pfn;
53
}
54
391 by Suren A. Chilingaryan
Resolve also not page-algined BAR addresses in the driver
55
unsigned long pcidriver_resolve_bar(unsigned long bar_address) {
363 by Suren A. Chilingaryan
Resolution of the user-space BAR addresses
56
    int dev, bar;
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
57
    unsigned long pfn;
391 by Suren A. Chilingaryan
Resolve also not page-algined BAR addresses in the driver
58
    unsigned long address;
393 by Suren A. Chilingaryan
Fix compilation of rdma.c in the driver
59
    unsigned long offset;
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
60
391 by Suren A. Chilingaryan
Resolve also not page-algined BAR addresses in the driver
61
    address = (bar_address >> PAGE_SHIFT) << PAGE_SHIFT;
62
    offset = bar_address - address;
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
63
    pfn = pcidriver_follow_pte(current->mm, address);
64
363 by Suren A. Chilingaryan
Resolution of the user-space BAR addresses
65
    for (dev = 0; dev < MAXDEVICES; dev++)
66
    {
67
        pcidriver_privdata_t *privdata =  pcidriver_get_privdata(dev);
68
        if (!privdata) continue;
69
70
        for (bar = 0; bar < 6; bar++)
71
        {
72
            unsigned long start = pci_resource_start(privdata->pdev, bar);
73
            unsigned long end = start + pci_resource_len(privdata->pdev, bar);
74
            if ((pfn >= start)&&(pfn < end))
391 by Suren A. Chilingaryan
Resolve also not page-algined BAR addresses in the driver
75
                return pfn + offset;
363 by Suren A. Chilingaryan
Resolution of the user-space BAR addresses
76
        }
77
        pcidriver_put_privdata(privdata);
78
    }
79
80
    return 0;
362 by Suren A. Chilingaryan
Resolve user-space addresses to physical addresses in the driver
81
}
82
83
EXPORT_SYMBOL(pcidriver_resolve_bar);