Message ID | 1478875829-35000-2-git-send-email-christophe.milard@linaro.org |
---|---|
State | New |
Headers | show |
One comment inline: On 11 November 2016 at 22:50, Christophe Milard < christophe.milard@linaro.org> wrote: > The function _odp_ishmphy_virt_to_phys() is added to query for physical > addresses (given a virtual address) > This function is meant to be used to populate the physical address > of packet segments which are to be used by drivers (without iommu). > The function _odp_ishmphy_can_virt_to_phys(), also added, return true if > _odp_ishmphy_virt_to_phys() is able to works (as it requires specific > permission) > > Signed-off-by: Christophe Milard <christophe.milard@linaro.org> > --- > platform/linux-generic/_ishmphy.c | 82 > ++++++++++++++++++++++ > platform/linux-generic/include/_ishmphy_internal.h | 14 ++++ > 2 files changed, 96 insertions(+) > > diff --git a/platform/linux-generic/_ishmphy.c b/platform/linux-generic/_ > ishmphy.c > index 2b2d100..8c0f46e 100644 > --- a/platform/linux-generic/_ishmphy.c > +++ b/platform/linux-generic/_ishmphy.c > @@ -29,6 +29,7 @@ > #include <fcntl.h> > #include <sys/types.h> > #include <sys/wait.h> > +#include <inttypes.h> > #include <_ishmphy_internal.h> > > static void *common_va_address; > @@ -38,6 +39,8 @@ static uint64_t common_va_len; > #define MAP_ANONYMOUS MAP_ANON > #endif > > +#define PAGEMAP_FILE "/proc/self/pagemap" > + > /* Book some virtual address space > * This function is called at odp_init_global() time to pre-book some > * virtual address space inherited by all odpthreads (i.e. descendant > @@ -183,3 +186,82 @@ int _odp_ishmphy_unmap(void *start, uint64_t len, int > flags) > ODP_ERR("_ishmphy_free failure: %s\n", strerror(errno)); > return ret; > } > + > +/* > + * Get physical address from virtual address addr. > + */ > I saw DPDK API commented that "The page must be locked", and provides an API rte_mem_lock_page to do so, in this API is the locking guarenteed by like _odp_ishm_reserve calls already? +phys_addr_t _odp_ishmphy_virt_to_phys(const void *addr) > +{ > + int page_sz; > + int fd; > + off_t offset; > + int read_bytes; > + uint64_t page; > + phys_addr_t phys_addr; > + > + /* get normal page sizes: */ > + page_sz = odp_sys_page_size(); > + > + /* read 8 bytes (uint64_t) at position N*8, where N is > addr/page_sz */ > + fd = open(PAGEMAP_FILE, O_RDONLY); > + if (fd < 0) { > + ODP_ERR("cannot open " PAGEMAP_FILE ": %s\n", > + strerror(errno)); > + return PHYS_ADDR_INVALID; > + } > + > + offset = ((unsigned long)addr / page_sz) * sizeof(uint64_t); > + if (lseek(fd, offset, SEEK_SET) == (off_t)-1) { > + ODP_ERR("cannot seek " PAGEMAP_FILE ": %s\n", > + strerror(errno)); > + close(fd); > + return PHYS_ADDR_INVALID; > + } > + > + read_bytes = read(fd, &page, sizeof(uint64_t)); > + close(fd); > + if (read_bytes < 0) { > + ODP_ERR("cannot read " PAGEMAP_FILE ": %s\n", > + strerror(errno)); > + return PHYS_ADDR_INVALID; > + } else if (read_bytes != sizeof(uint64_t)) { > + ODP_ERR("read %d bytes from " PAGEMAP_FILE " " > + "but expected %d:\n", > + read_bytes, sizeof(uint64_t)); > + return PHYS_ADDR_INVALID; > + } > + > + /* some kernel return PFN zero when permission is denied: */ > + if (!(page & 0x7fffffffffffffULL)) > + return PHYS_ADDR_INVALID; > + > + /* > + * the pfn (page frame number) are bits 0-54 (see > + * pagemap.txt in linux Documentation) > + */ > + phys_addr = ((page & 0x7fffffffffffffULL) * page_sz) > + + ((unsigned long)addr % page_sz); > + > + return phys_addr; > +} > + > +/* > + * check if physical address are readable > + * return true if physical addresses can be retrieved. > + * Just do a test to see if it works > + */ > +int _odp_ishmphy_can_virt_to_phys(void) > +{ > + int block_index; > + phys_addr_t phy; > + > + /* allocate a block, locked in memory and try to grab its phy > address */ > + block_index = _odp_ishm_reserve(NULL, 10, -1, 0, _ODP_ISHM_LOCK, > 0); > + phy = _odp_ishmphy_virt_to_phys((void *)_odp_ishm_address(block_ > index)); > + _odp_ishm_free_by_index(block_index); > + > + if (phy == PHYS_ADDR_INVALID) > + return 0; > + > + return 1; > +} > diff --git a/platform/linux-generic/include/_ishmphy_internal.h > b/platform/linux-generic/include/_ishmphy_internal.h > index 4fe560f..2022590 100644 > --- a/platform/linux-generic/include/_ishmphy_internal.h > +++ b/platform/linux-generic/include/_ishmphy_internal.h > @@ -13,11 +13,25 @@ extern "C" { > > #include <stdint.h> > > +typedef uint64_t phys_addr_t; /* Physical address definition. */ > +#define PHYS_ADDR_INVALID ((phys_addr_t)-1) > + > void *_odp_ishmphy_book_va(uintptr_t len, intptr_t align); > int _odp_ishmphy_unbook_va(void); > void *_odp_ishmphy_map(int fd, void *start, uint64_t size, int flags); > int _odp_ishmphy_unmap(void *start, uint64_t len, int flags); > > +/* > + * check if physical address are readable > + * return true if physical addresses can be retrieved. > + */ > +int _odp_ishmphy_can_virt_to_phys(void); > + > +/* > + * Get physical address from virtual address addr. > + */ > +phys_addr_t _odp_ishmphy_virt_to_phys(const void *addr); > + > #ifdef __cplusplus > } > #endif > -- > 2.7.4 > >
Th page must be locked, indeed: if the page is swapped out its physical address does not exist... _ishm (the internal ODP memory allocator has a flag to lock memory: _ODP_ISHM_LOCK On the north API (odp_*), any memory reserved is locked anyway. This was a requirement from Petri: that is any odp_shm_reserve() will get locked page. Assuming we are using the _ishm memory allocator on the north interface (this patch serie is still waiting for Petri's blessing) On the south interface (odpdrv_*) both the driver still has the choice, through a flag: ODPDRV_SHM_LOCK ODPDRV_SHM_LOCK maps to the _ishm _ODP_ISHM_LOCK flag. Christophe On 14 November 2016 at 06:00, Yi He <yi.he@linaro.org> wrote: > One comment inline: > > On 11 November 2016 at 22:50, Christophe Milard > <christophe.milard@linaro.org> wrote: >> >> The function _odp_ishmphy_virt_to_phys() is added to query for physical >> addresses (given a virtual address) >> This function is meant to be used to populate the physical address >> of packet segments which are to be used by drivers (without iommu). >> The function _odp_ishmphy_can_virt_to_phys(), also added, return true if >> _odp_ishmphy_virt_to_phys() is able to works (as it requires specific >> permission) >> >> Signed-off-by: Christophe Milard <christophe.milard@linaro.org> >> --- >> platform/linux-generic/_ishmphy.c | 82 >> ++++++++++++++++++++++ >> platform/linux-generic/include/_ishmphy_internal.h | 14 ++++ >> 2 files changed, 96 insertions(+) >> >> diff --git a/platform/linux-generic/_ishmphy.c >> b/platform/linux-generic/_ishmphy.c >> index 2b2d100..8c0f46e 100644 >> --- a/platform/linux-generic/_ishmphy.c >> +++ b/platform/linux-generic/_ishmphy.c >> @@ -29,6 +29,7 @@ >> #include <fcntl.h> >> #include <sys/types.h> >> #include <sys/wait.h> >> +#include <inttypes.h> >> #include <_ishmphy_internal.h> >> >> static void *common_va_address; >> @@ -38,6 +39,8 @@ static uint64_t common_va_len; >> #define MAP_ANONYMOUS MAP_ANON >> #endif >> >> +#define PAGEMAP_FILE "/proc/self/pagemap" >> + >> /* Book some virtual address space >> * This function is called at odp_init_global() time to pre-book some >> * virtual address space inherited by all odpthreads (i.e. descendant >> @@ -183,3 +186,82 @@ int _odp_ishmphy_unmap(void *start, uint64_t len, int >> flags) >> ODP_ERR("_ishmphy_free failure: %s\n", strerror(errno)); >> return ret; >> } >> + >> +/* >> + * Get physical address from virtual address addr. >> + */ > > > I saw DPDK API commented that "The page must be locked", and provides an API > rte_mem_lock_page to do so, in this API is the locking guarenteed by like > _odp_ishm_reserve calls already? > >> +phys_addr_t _odp_ishmphy_virt_to_phys(const void *addr) >> +{ >> + int page_sz; >> + int fd; >> + off_t offset; >> + int read_bytes; >> + uint64_t page; >> + phys_addr_t phys_addr; >> + >> + /* get normal page sizes: */ >> + page_sz = odp_sys_page_size(); >> + >> + /* read 8 bytes (uint64_t) at position N*8, where N is >> addr/page_sz */ >> + fd = open(PAGEMAP_FILE, O_RDONLY); >> + if (fd < 0) { >> + ODP_ERR("cannot open " PAGEMAP_FILE ": %s\n", >> + strerror(errno)); >> + return PHYS_ADDR_INVALID; >> + } >> + >> + offset = ((unsigned long)addr / page_sz) * sizeof(uint64_t); >> + if (lseek(fd, offset, SEEK_SET) == (off_t)-1) { >> + ODP_ERR("cannot seek " PAGEMAP_FILE ": %s\n", >> + strerror(errno)); >> + close(fd); >> + return PHYS_ADDR_INVALID; >> + } >> + >> + read_bytes = read(fd, &page, sizeof(uint64_t)); >> + close(fd); >> + if (read_bytes < 0) { >> + ODP_ERR("cannot read " PAGEMAP_FILE ": %s\n", >> + strerror(errno)); >> + return PHYS_ADDR_INVALID; >> + } else if (read_bytes != sizeof(uint64_t)) { >> + ODP_ERR("read %d bytes from " PAGEMAP_FILE " " >> + "but expected %d:\n", >> + read_bytes, sizeof(uint64_t)); >> + return PHYS_ADDR_INVALID; >> + } >> + >> + /* some kernel return PFN zero when permission is denied: */ >> + if (!(page & 0x7fffffffffffffULL)) >> + return PHYS_ADDR_INVALID; >> + >> + /* >> + * the pfn (page frame number) are bits 0-54 (see >> + * pagemap.txt in linux Documentation) >> + */ >> + phys_addr = ((page & 0x7fffffffffffffULL) * page_sz) >> + + ((unsigned long)addr % page_sz); >> + >> + return phys_addr; >> +} >> + >> +/* >> + * check if physical address are readable >> + * return true if physical addresses can be retrieved. >> + * Just do a test to see if it works >> + */ >> +int _odp_ishmphy_can_virt_to_phys(void) >> +{ >> + int block_index; >> + phys_addr_t phy; >> + >> + /* allocate a block, locked in memory and try to grab its phy >> address */ >> + block_index = _odp_ishm_reserve(NULL, 10, -1, 0, _ODP_ISHM_LOCK, >> 0); >> + phy = _odp_ishmphy_virt_to_phys((void >> *)_odp_ishm_address(block_index)); >> + _odp_ishm_free_by_index(block_index); >> + >> + if (phy == PHYS_ADDR_INVALID) >> + return 0; >> + >> + return 1; >> +} >> diff --git a/platform/linux-generic/include/_ishmphy_internal.h >> b/platform/linux-generic/include/_ishmphy_internal.h >> index 4fe560f..2022590 100644 >> --- a/platform/linux-generic/include/_ishmphy_internal.h >> +++ b/platform/linux-generic/include/_ishmphy_internal.h >> @@ -13,11 +13,25 @@ extern "C" { >> >> #include <stdint.h> >> >> +typedef uint64_t phys_addr_t; /* Physical address definition. */ >> +#define PHYS_ADDR_INVALID ((phys_addr_t)-1) >> + >> void *_odp_ishmphy_book_va(uintptr_t len, intptr_t align); >> int _odp_ishmphy_unbook_va(void); >> void *_odp_ishmphy_map(int fd, void *start, uint64_t size, int flags); >> int _odp_ishmphy_unmap(void *start, uint64_t len, int flags); >> >> +/* >> + * check if physical address are readable >> + * return true if physical addresses can be retrieved. >> + */ >> +int _odp_ishmphy_can_virt_to_phys(void); >> + >> +/* >> + * Get physical address from virtual address addr. >> + */ >> +phys_addr_t _odp_ishmphy_virt_to_phys(const void *addr); >> + >> #ifdef __cplusplus >> } >> #endif >> -- >> 2.7.4 >> >
diff --git a/platform/linux-generic/_ishmphy.c b/platform/linux-generic/_ishmphy.c index 2b2d100..8c0f46e 100644 --- a/platform/linux-generic/_ishmphy.c +++ b/platform/linux-generic/_ishmphy.c @@ -29,6 +29,7 @@ #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> +#include <inttypes.h> #include <_ishmphy_internal.h> static void *common_va_address; @@ -38,6 +39,8 @@ static uint64_t common_va_len; #define MAP_ANONYMOUS MAP_ANON #endif +#define PAGEMAP_FILE "/proc/self/pagemap" + /* Book some virtual address space * This function is called at odp_init_global() time to pre-book some * virtual address space inherited by all odpthreads (i.e. descendant @@ -183,3 +186,82 @@ int _odp_ishmphy_unmap(void *start, uint64_t len, int flags) ODP_ERR("_ishmphy_free failure: %s\n", strerror(errno)); return ret; } + +/* + * Get physical address from virtual address addr. + */ +phys_addr_t _odp_ishmphy_virt_to_phys(const void *addr) +{ + int page_sz; + int fd; + off_t offset; + int read_bytes; + uint64_t page; + phys_addr_t phys_addr; + + /* get normal page sizes: */ + page_sz = odp_sys_page_size(); + + /* read 8 bytes (uint64_t) at position N*8, where N is addr/page_sz */ + fd = open(PAGEMAP_FILE, O_RDONLY); + if (fd < 0) { + ODP_ERR("cannot open " PAGEMAP_FILE ": %s\n", + strerror(errno)); + return PHYS_ADDR_INVALID; + } + + offset = ((unsigned long)addr / page_sz) * sizeof(uint64_t); + if (lseek(fd, offset, SEEK_SET) == (off_t)-1) { + ODP_ERR("cannot seek " PAGEMAP_FILE ": %s\n", + strerror(errno)); + close(fd); + return PHYS_ADDR_INVALID; + } + + read_bytes = read(fd, &page, sizeof(uint64_t)); + close(fd); + if (read_bytes < 0) { + ODP_ERR("cannot read " PAGEMAP_FILE ": %s\n", + strerror(errno)); + return PHYS_ADDR_INVALID; + } else if (read_bytes != sizeof(uint64_t)) { + ODP_ERR("read %d bytes from " PAGEMAP_FILE " " + "but expected %d:\n", + read_bytes, sizeof(uint64_t)); + return PHYS_ADDR_INVALID; + } + + /* some kernel return PFN zero when permission is denied: */ + if (!(page & 0x7fffffffffffffULL)) + return PHYS_ADDR_INVALID; + + /* + * the pfn (page frame number) are bits 0-54 (see + * pagemap.txt in linux Documentation) + */ + phys_addr = ((page & 0x7fffffffffffffULL) * page_sz) + + ((unsigned long)addr % page_sz); + + return phys_addr; +} + +/* + * check if physical address are readable + * return true if physical addresses can be retrieved. + * Just do a test to see if it works + */ +int _odp_ishmphy_can_virt_to_phys(void) +{ + int block_index; + phys_addr_t phy; + + /* allocate a block, locked in memory and try to grab its phy address */ + block_index = _odp_ishm_reserve(NULL, 10, -1, 0, _ODP_ISHM_LOCK, 0); + phy = _odp_ishmphy_virt_to_phys((void *)_odp_ishm_address(block_index)); + _odp_ishm_free_by_index(block_index); + + if (phy == PHYS_ADDR_INVALID) + return 0; + + return 1; +} diff --git a/platform/linux-generic/include/_ishmphy_internal.h b/platform/linux-generic/include/_ishmphy_internal.h index 4fe560f..2022590 100644 --- a/platform/linux-generic/include/_ishmphy_internal.h +++ b/platform/linux-generic/include/_ishmphy_internal.h @@ -13,11 +13,25 @@ extern "C" { #include <stdint.h> +typedef uint64_t phys_addr_t; /* Physical address definition. */ +#define PHYS_ADDR_INVALID ((phys_addr_t)-1) + void *_odp_ishmphy_book_va(uintptr_t len, intptr_t align); int _odp_ishmphy_unbook_va(void); void *_odp_ishmphy_map(int fd, void *start, uint64_t size, int flags); int _odp_ishmphy_unmap(void *start, uint64_t len, int flags); +/* + * check if physical address are readable + * return true if physical addresses can be retrieved. + */ +int _odp_ishmphy_can_virt_to_phys(void); + +/* + * Get physical address from virtual address addr. + */ +phys_addr_t _odp_ishmphy_virt_to_phys(const void *addr); + #ifdef __cplusplus } #endif
The function _odp_ishmphy_virt_to_phys() is added to query for physical addresses (given a virtual address) This function is meant to be used to populate the physical address of packet segments which are to be used by drivers (without iommu). The function _odp_ishmphy_can_virt_to_phys(), also added, return true if _odp_ishmphy_virt_to_phys() is able to works (as it requires specific permission) Signed-off-by: Christophe Milard <christophe.milard@linaro.org> --- platform/linux-generic/_ishmphy.c | 82 ++++++++++++++++++++++ platform/linux-generic/include/_ishmphy_internal.h | 14 ++++ 2 files changed, 96 insertions(+) -- 2.7.4