From 265292f2b0da0eb414c409871ba0f94a99ec33c1 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 8 May 2017 22:06:04 +0200 Subject: [PATCH 027/198] arm_coreboot: Support DMA. This is needed to support USB and some other busses. --- grub-core/Makefile.am | 1 + grub-core/Makefile.core.def | 1 + grub-core/kern/arm/cache.c | 34 ++++++++++++++++++++++ grub-core/kern/arm/cache_armv7.S | 12 ++++++++ grub-core/kern/arm/coreboot/dma.c | 59 +++++++++++++++++++++++++++++++++++++++ include/grub/cache.h | 7 ++--- include/grub/dma.h | 44 +++++++++++++++++++++++++++++ include/grub/pci.h | 22 +-------------- 8 files changed, 155 insertions(+), 25 deletions(-) create mode 100644 grub-core/kern/arm/coreboot/dma.c create mode 100644 include/grub/dma.h diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index a2aaf9f54..104513847 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -248,6 +248,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gfxterm.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/font.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bufio.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/dma.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/coreboot/kernel.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdtbus.h endif diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 6be6e7f61..e4f253a20 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -163,6 +163,7 @@ kernel = { arm_coreboot = term/ps2.c; arm_coreboot = term/arm/pl050.c; arm_coreboot = commands/keylayouts.c; + arm_coreboot = kern/arm/coreboot/dma.c; terminfoinkernel = term/terminfo.c; terminfoinkernel = term/tparm.c; diff --git a/grub-core/kern/arm/cache.c b/grub-core/kern/arm/cache.c index 34154ccdb..af1c4bbf5 100644 --- a/grub-core/kern/arm/cache.c +++ b/grub-core/kern/arm/cache.c @@ -29,6 +29,8 @@ void grub_arm_clean_dcache_range_armv6 (grub_addr_t start, grub_addr_t end, grub_addr_t dlinesz); void grub_arm_clean_dcache_range_armv7 (grub_addr_t start, grub_addr_t end, grub_addr_t dlinesz); +void grub_arm_clean_dcache_range_poc_armv7 (grub_addr_t start, grub_addr_t end, + grub_addr_t dlinesz); void grub_arm_invalidate_icache_range_armv6 (grub_addr_t start, grub_addr_t end, grub_addr_t dlinesz); void grub_arm_invalidate_icache_range_armv7 (grub_addr_t start, grub_addr_t end, @@ -252,6 +254,38 @@ grub_arch_sync_caches (void *address, grub_size_t len) } } +void +grub_arch_sync_dma_caches (volatile void *address, grub_size_t len) +{ + grub_addr_t start = (grub_addr_t) address; + grub_addr_t end = start + len; + + if (type == ARCH_UNKNOWN) + probe_caches (); + start = ALIGN_DOWN (start, grub_arch_cache_max_linesz); + end = ALIGN_UP (end, grub_arch_cache_max_linesz); + switch (type) + { + case ARCH_ARMV6: + grub_arm_clean_dcache_range_armv6 (start, end, grub_arch_cache_dlinesz); + grub_arm_invalidate_icache_range_armv6 (start, end, + grub_arch_cache_ilinesz); + break; + case ARCH_ARMV5_WRITE_THROUGH: + case ARCH_ARMV6_UNIFIED: + grub_arm_clean_dcache_range_armv6 (start, end, grub_arch_cache_dlinesz); + break; + case ARCH_ARMV7: + grub_arm_clean_dcache_range_poc_armv7 (start, end, grub_arch_cache_dlinesz); + grub_arm_invalidate_icache_range_armv7 (start, end, + grub_arch_cache_ilinesz); + break; + /* Pacify GCC. */ + case ARCH_UNKNOWN: + break; + } +} + void grub_arm_disable_caches_mmu (void) { diff --git a/grub-core/kern/arm/cache_armv7.S b/grub-core/kern/arm/cache_armv7.S index 1ef2754af..5ae76a3d8 100644 --- a/grub-core/kern/arm/cache_armv7.S +++ b/grub-core/kern/arm/cache_armv7.S @@ -33,6 +33,18 @@ # define ISB isb #define ARMV7 1 +FUNCTION(grub_arm_clean_dcache_range_poc_armv7) + DSB + @ Clean data cache for range to point-of-coherence +1: cmp r0, r1 + bge 2f + mcr p15, 0, r0, c7, c14, 1 @ DCCMVAC + add r0, r0, r2 @ Next line + b 1b +2: DSB + bx lr + + @ r0 - CLIDR @ r1 - LoC @ r2 - current level diff --git a/grub-core/kern/arm/coreboot/dma.c b/grub-core/kern/arm/coreboot/dma.c new file mode 100644 index 000000000..2c2a62789 --- /dev/null +++ b/grub-core/kern/arm/coreboot/dma.c @@ -0,0 +1,59 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_pci_dma_chunk * +grub_memalign_dma32 (grub_size_t align, grub_size_t size) +{ + void *ret; + if (align < 64) + align = 64; + size = ALIGN_UP (size, align); + ret = grub_memalign (align, size); + if (!ret) + return 0; + grub_arch_sync_dma_caches (ret, size); + return ret; +} + +void +grub_dma_free (struct grub_pci_dma_chunk *ch) +{ + grub_size_t size = (((struct grub_mm_header *) ch) - 1)->size * GRUB_MM_ALIGN; + grub_arch_sync_dma_caches (ch, size); + grub_free (ch); +} + +volatile void * +grub_dma_get_virt (struct grub_pci_dma_chunk *ch) +{ + return (void *) ch; +} + +grub_uint32_t +grub_dma_get_phys (struct grub_pci_dma_chunk *ch) +{ + return (grub_uint32_t) (grub_addr_t) ch; +} + diff --git a/include/grub/cache.h b/include/grub/cache.h index fc669dfd1..1c98ce270 100644 --- a/include/grub/cache.h +++ b/include/grub/cache.h @@ -34,15 +34,14 @@ void EXPORT_FUNC(grub_arch_sync_caches) (void *address, grub_size_t len); #endif #ifndef GRUB_MACHINE_EMU -#ifdef _mips -void EXPORT_FUNC(grub_arch_sync_dma_caches) (volatile void *address, - grub_size_t len); -#else +#if defined (__i386__) || defined (__x86_64__) static inline void grub_arch_sync_dma_caches (volatile void *address __attribute__ ((unused)), grub_size_t len __attribute__ ((unused))) { } +#else +void EXPORT_FUNC(grub_arch_sync_dma_caches) (volatile void *address, grub_size_t len); #endif #endif diff --git a/include/grub/dma.h b/include/grub/dma.h new file mode 100644 index 000000000..19992ebc1 --- /dev/null +++ b/include/grub/dma.h @@ -0,0 +1,44 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_DMA_H +#define GRUB_DMA_H 1 + +struct grub_pci_dma_chunk; + +struct grub_pci_dma_chunk *EXPORT_FUNC(grub_memalign_dma32) (grub_size_t align, + grub_size_t size); +void EXPORT_FUNC(grub_dma_free) (struct grub_pci_dma_chunk *ch); +volatile void *EXPORT_FUNC(grub_dma_get_virt) (struct grub_pci_dma_chunk *ch); +grub_uint32_t EXPORT_FUNC(grub_dma_get_phys) (struct grub_pci_dma_chunk *ch); + +static inline void * +grub_dma_phys2virt (grub_uint32_t phys, struct grub_pci_dma_chunk *chunk) +{ + return ((grub_uint8_t *) grub_dma_get_virt (chunk) + + (phys - grub_dma_get_phys (chunk))); +} + +static inline grub_uint32_t +grub_dma_virt2phys (volatile void *virt, struct grub_pci_dma_chunk *chunk) +{ + return (((grub_uint8_t *) virt - (grub_uint8_t *) grub_dma_get_virt (chunk)) + + grub_dma_get_phys (chunk)); +} + +#endif diff --git a/include/grub/pci.h b/include/grub/pci.h index 70d9a0513..262c89b74 100644 --- a/include/grub/pci.h +++ b/include/grub/pci.h @@ -142,27 +142,7 @@ grub_pci_address_t EXPORT_FUNC(grub_pci_make_address) (grub_pci_device_t dev, void EXPORT_FUNC(grub_pci_iterate) (grub_pci_iteratefunc_t hook, void *hook_data); -struct grub_pci_dma_chunk; - -struct grub_pci_dma_chunk *EXPORT_FUNC(grub_memalign_dma32) (grub_size_t align, - grub_size_t size); -void EXPORT_FUNC(grub_dma_free) (struct grub_pci_dma_chunk *ch); -volatile void *EXPORT_FUNC(grub_dma_get_virt) (struct grub_pci_dma_chunk *ch); -grub_uint32_t EXPORT_FUNC(grub_dma_get_phys) (struct grub_pci_dma_chunk *ch); - -static inline void * -grub_dma_phys2virt (grub_uint32_t phys, struct grub_pci_dma_chunk *chunk) -{ - return ((grub_uint8_t *) grub_dma_get_virt (chunk) - + (phys - grub_dma_get_phys (chunk))); -} - -static inline grub_uint32_t -grub_dma_virt2phys (volatile void *virt, struct grub_pci_dma_chunk *chunk) -{ - return (((grub_uint8_t *) virt - (grub_uint8_t *) grub_dma_get_virt (chunk)) - + grub_dma_get_phys (chunk)); -} +#include grub_uint8_t EXPORT_FUNC (grub_pci_find_capability) (grub_pci_device_t dev, grub_uint8_t cap); -- 2.14.3