As a consequence we need to maintain a separate I/O range within OFMEM, and add management functions similar to those that exist for the virtual and physical ranges. At the same time, we introduce a couple of new OFMEM arch functions called ofmem_arch_get_iomem_base() and ofmem_arch_get_iomem_top() to control the range of allocatable I/O memory which is again similar to the existing method used for the virtual and physical ranges.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@siriusit.co.uk --- openbios-devel/arch/ppc/qemu/ofmem.c | 12 ++++++ openbios-devel/arch/sparc32/ofmem_sparc32.c | 10 +++++ openbios-devel/arch/sparc64/ofmem_sparc64.c | 12 ++++++ openbios-devel/include/libopenbios/ofmem.h | 9 ++++- openbios-devel/libopenbios/ofmem_common.c | 52 +++++++++++++++++++++++++++ 5 files changed, 93 insertions(+), 2 deletions(-)
diff --git a/openbios-devel/arch/ppc/qemu/ofmem.c b/openbios-devel/arch/ppc/qemu/ofmem.c index 80fad75..4c6825e 100644 --- a/openbios-devel/arch/ppc/qemu/ofmem.c +++ b/openbios-devel/arch/ppc/qemu/ofmem.c @@ -132,6 +132,18 @@ void ofmem_arch_early_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell /* none yet */ }
+ucell ofmem_arch_get_iomem_base(void) +{ + /* Currently unused */ + return 0; +} + +ucell ofmem_arch_get_iomem_top(void) +{ + /* Currently unused */ + return 0; +} + retain_t *ofmem_arch_get_retained(void) { /* not implemented */ diff --git a/openbios-devel/arch/sparc32/ofmem_sparc32.c b/openbios-devel/arch/sparc32/ofmem_sparc32.c index 77112ec..6815349 100644 --- a/openbios-devel/arch/sparc32/ofmem_sparc32.c +++ b/openbios-devel/arch/sparc32/ofmem_sparc32.c @@ -71,6 +71,16 @@ phys_addr_t ofmem_arch_get_phys_top(void) return (uintptr_t)ofmem->ramsize - 0x1000000; }
+ucell ofmem_arch_get_iomem_base(void) +{ + return pointer2cell(&_end); +} + +ucell ofmem_arch_get_iomem_top(void) +{ + return pointer2cell(&_iomem); +} + retain_t *ofmem_arch_get_retained(void) { /* Not used */ diff --git a/openbios-devel/arch/sparc64/ofmem_sparc64.c b/openbios-devel/arch/sparc64/ofmem_sparc64.c index 6a4fb5e..1655978 100644 --- a/openbios-devel/arch/sparc64/ofmem_sparc64.c +++ b/openbios-devel/arch/sparc64/ofmem_sparc64.c @@ -70,6 +70,18 @@ phys_addr_t ofmem_arch_get_phys_top(void) return ofmem->ramsize; }
+ucell ofmem_arch_get_iomem_base(void) +{ + /* Currently unused */ + return 0; +} + +ucell ofmem_arch_get_iomem_top(void) +{ + /* Currently unused */ + return 0; +} + retain_t *ofmem_arch_get_retained(void) { /* Retained area is at the top of physical RAM */ diff --git a/openbios-devel/include/libopenbios/ofmem.h b/openbios-devel/include/libopenbios/ofmem.h index e350dec..940f5cc 100644 --- a/openbios-devel/include/libopenbios/ofmem.h +++ b/openbios-devel/include/libopenbios/ofmem.h @@ -46,6 +46,7 @@ typedef struct {
range_t *phys_range; range_t *virt_range; + range_t *io_range;
translation_t *trans; /* this is really a translation_t */ } ofmem_t; @@ -63,6 +64,8 @@ extern void* ofmem_arch_get_malloc_base(void); extern ucell ofmem_arch_get_heap_top(void); extern ucell ofmem_arch_get_virt_top(void); extern phys_addr_t ofmem_arch_get_phys_top(void); +extern ucell ofmem_arch_get_iomem_base(void); +extern ucell ofmem_arch_get_iomem_top(void); extern retain_t* ofmem_arch_get_retained(void); extern int ofmem_arch_get_physaddr_cellsize(void); extern int ofmem_arch_encode_physaddr(ucell *p, phys_addr_t value); @@ -104,25 +107,27 @@ extern void ofmem_register( phandle_t ph_memory, phandle_t ph_mmu ); extern ucell ofmem_claim( ucell addr, ucell size, ucell align ); extern phys_addr_t ofmem_claim_phys( phys_addr_t mphys, ucell size, ucell align ); extern ucell ofmem_claim_virt( ucell mvirt, ucell size, ucell align ); +extern ucell ofmem_claim_io( ucell virt, ucell size, ucell align );
extern phys_addr_t ofmem_retain( phys_addr_t phys, ucell size, ucell align );
extern int ofmem_map( phys_addr_t phys, ucell virt, ucell size, ucell mode ); extern int ofmem_unmap( ucell virt, ucell size ); +extern ucell ofmem_map_io( phys_addr_t phys, ucell size );
extern void ofmem_release( ucell virt, ucell size ); extern void ofmem_release_phys( phys_addr_t phys, ucell size ); extern void ofmem_release_virt( ucell virt, ucell size ); extern phys_addr_t ofmem_translate( ucell virt, ucell *ret_mode );
-#ifdef CONFIG_PPC +/* Currently the same for all architectures */ #define PAGE_SHIFT 12
+#ifdef CONFIG_PPC unsigned long get_ram_top( void ); unsigned long get_ram_bottom( void );
#elif defined(CONFIG_SPARC32) -#define PAGE_SHIFT 12
/* arch/sparc32/lib.c */ struct mem; diff --git a/openbios-devel/libopenbios/ofmem_common.c b/openbios-devel/libopenbios/ofmem_common.c index e1accb2..7f6223b 100644 --- a/openbios-devel/libopenbios/ofmem_common.c +++ b/openbios-devel/libopenbios/ofmem_common.c @@ -551,6 +551,35 @@ ucell ofmem_claim_virt( ucell virt, ucell size, ucell align ) get_ram_size(), ofmem_arch_get_virt_top(), 1 ); }
+static ucell ofmem_claim_io_( ucell virt, ucell size, ucell align, + ucell min, ucell max, int reverse ) +{ + ofmem_t *ofmem = ofmem_arch_get_private(); + if( !align ) { + if( !is_free( virt, size, ofmem->io_range ) ) { + OFMEM_TRACE("Non-free I/O memory claimed!\n"); + return -1; + } + add_entry( virt, size, &ofmem->io_range ); + return virt; + } + + virt = find_area( align, size, ofmem->io_range, min, max, reverse ); + if( virt == -1 ) { + printk("ofmem_claim_io - out of space (failed request for " FMT_ucellx " bytes)\n", size); + return -1; + } + add_entry( virt, size, &ofmem->io_range ); + return virt; +} + +ucell ofmem_claim_io( ucell virt, ucell size, ucell align ) +{ + /* Claim a section of memory from the I/O range */ + return ofmem_claim_io_( virt, size, align, + ofmem_arch_get_iomem_base(), ofmem_arch_get_iomem_top(), 0 ); +} + /* if align != 0, phys is ignored. Returns -1 on error */ phys_addr_t ofmem_retain( phys_addr_t phys, ucell size, ucell align ) { @@ -797,6 +826,29 @@ int ofmem_unmap( ucell virt, ucell size ) return 0; }
+ucell ofmem_map_io( phys_addr_t phys, ucell size ) +{ + /* Claim virtual memory from the I/O range and map the page-aligned + physical address phys to it, returning the newly allocated + virtual address */ + ucell virt, mode; + phys_addr_t off; + int npages; + + off = phys & (PAGE_SIZE - 1); + npages = (off + size - 1) / PAGE_SIZE + 1; + phys &= ~(PAGE_SIZE - 1); + + virt = ofmem_claim_io(-1, npages * PAGE_SIZE, PAGE_SIZE); + + mode = ofmem_arch_io_translation_mode(off); + + ofmem_map_page_range(phys, virt, npages * PAGE_SIZE, mode); + ofmem_arch_early_map_pages(phys, virt, npages * PAGE_SIZE, mode); + + return (virt + off); +} + /* virtual -> physical. */ phys_addr_t ofmem_translate( ucell virt, ucell *mode ) {