Change how memory is set up, especially before the page allocator is ready Cleanup and divide the work of reserving pre-allocated memory into two pieces: 1. Avoid passing RAM for fixed-address pre-allocated memory to the boot allocator. This is done before the boot allocator is initialized. 2. After the slab allocator is initialized, allocate memory for the pre-allocations that do not have fixed address, then add resources for both fixed and non-fixed address preallocations Also, switch to PREALLOC_* macros in arch/mips/powertv/asic/prealloc-gaia.c to manage their configuration. Signed-off-by: David VomLehn <dvomlehn@xxxxxxxxx> --- arch/mips/include/asm/mach-powertv/asic.h | 30 +- arch/mips/include/asm/mach-powertv/painting.h | 224 ++++++++ .../include/asm/mach-powertv/powertv-prealloc.h | 51 ++ arch/mips/include/asm/mach-powertv/prealloc.h | 121 +++++ arch/mips/powertv/Kconfig | 12 + arch/mips/powertv/asic/Kconfig | 38 +- arch/mips/powertv/asic/Makefile | 6 +- arch/mips/powertv/asic/asic_devices.c | 219 ++------- arch/mips/powertv/asic/asic_int.c | 4 +- arch/mips/powertv/asic/painting.c | 298 ++++++++++ arch/mips/powertv/asic/powertv-prealloc.c | 136 +++++ arch/mips/powertv/asic/prealloc-calliope.c | 9 +- arch/mips/powertv/asic/prealloc-cronus.c | 7 +- arch/mips/powertv/asic/prealloc-cronuslite.c | 5 +- arch/mips/powertv/asic/prealloc-gaia.c | 490 ++++------------- arch/mips/powertv/asic/prealloc-zeus.c | 7 +- arch/mips/powertv/asic/prealloc.c | 566 ++++++++++++++++++++ arch/mips/powertv/asic/prealloc.h | 70 --- arch/mips/powertv/init.c | 4 +- arch/mips/powertv/ioremap.c | 38 +- arch/mips/powertv/memory.c | 203 ++----- arch/mips/powertv/powertv_setup.c | 4 +- 22 files changed, 1690 insertions(+), 852 deletions(-) diff --git a/arch/mips/include/asm/mach-powertv/asic.h b/arch/mips/include/asm/mach-powertv/asic.h index c7077a6..0d7f8a5 100644 --- a/arch/mips/include/asm/mach-powertv/asic.h +++ b/arch/mips/include/asm/mach-powertv/asic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Cisco Systems, Inc. + * Copyright (C) 2009-2010 Cisco Systems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,20 +51,9 @@ extern const struct register_map cronus_register_map; extern const struct register_map gaia_register_map; extern const struct register_map zeus_register_map; -extern struct resource dvr_cronus_resources[]; -extern struct resource dvr_gaia_resources[]; -extern struct resource dvr_zeus_resources[]; -extern struct resource non_dvr_calliope_resources[]; -extern struct resource non_dvr_cronus_resources[]; -extern struct resource non_dvr_cronuslite_resources[]; -extern struct resource non_dvr_gaia_resources[]; -extern struct resource non_dvr_vz_calliope_resources[]; -extern struct resource non_dvr_vze_calliope_resources[]; -extern struct resource non_dvr_vzf_calliope_resources[]; -extern struct resource non_dvr_zeus_resources[]; - +/* Platform resources management */ +extern void platform_reserve_bootmem(void); extern void powertv_platform_init(void); -extern void platform_alloc_bootmem(void); extern enum asic_type platform_get_asic(void); extern enum family_type platform_get_family(void); extern int platform_supports_dvr(void); @@ -73,11 +62,6 @@ extern int platform_supports_pcie(void); extern int platform_supports_display(void); extern void configure_platform(void); -/* Platform Resources */ -#define ASIC_RESOURCE_GET_EXISTS 1 -extern struct resource *asic_resource_get(const char *name); -extern void platform_release_memory(void *baddr, int size); - /* USB configuration */ struct usb_hcd; /* Forward reference */ extern void platform_configure_usb_ehci(void); @@ -87,8 +71,16 @@ extern void platform_unconfigure_usb_ohci(void); /* Resource for ASIC registers */ extern struct resource asic_resource; +#ifdef CONFIG_USB extern int platform_usb_devices_init(struct platform_device **echi_dev, struct platform_device **ohci_dev); +#else +static inline int platform_usb_devices_init(struct platform_device **echi_dev, + struct platform_device **ohci_dev) +{ + return 0; +} +#endif /* Reboot Cause */ extern void set_reboot_cause(char code, unsigned int data, unsigned int data2); diff --git a/arch/mips/include/asm/mach-powertv/painting.h b/arch/mips/include/asm/mach-powertv/painting.h new file mode 100644 index 0000000..b748c81 --- /dev/null +++ b/arch/mips/include/asm/mach-powertv/painting.h @@ -0,0 +1,224 @@ +/* + * painting.h + * + * Definitions to use the paint interface, which allows painting kernel + * memory allocations in order to be able to track memory usage. + * + * Author: David VomLehn + */ +/* + * Copyright (C) 2008-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Systems, Inc. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _PAINTING_H_ +#define _PAINTING_H_ +#include <linux/types.h> +#include <linux/list.h> +#include <linux/rbtree.h> +#include <linux/compiler.h> +#include <linux/err.h> + +/* Classifications of relationships between two areas */ +#define MISMATCH_CUR_ENDS_FIRST ((0 << 1) | 0) +#define MISMATCH_CUR_ENDS_LAST ((0 << 1) | 1) +#define MATCH_CUR_ENDS_FIRST ((1 << 1) | 0) +#define MATCH_CUR_ENDS_LAST ((1 << 1) | 1) + +struct painting_desc { + phys_addr_t p; /* Starting location */ + phys_addr_t q; /* Ending location, inclusive */ + const void *color; /* "color" */ +}; + +/* Data structure that holds the information for one painting area */ +struct painting_area { + struct rb_node node; + struct painting_desc desc; +}; + +/* Operations for a particular painting object */ +struct painting_ops { + struct painting_area *(*alloc)(void *ctx); + void (*free)(void *ctx, + const struct painting_area *area); + bool (*equals)(const void *l, const void *r); +}; + +/* Basic paint object */ +struct painting { + struct rb_root root; + struct list_head areas; +}; + +#define PAINTING_INIT(name) \ + { \ + .root = RB_ROOT, \ + .areas = LIST_HEAD_INIT(name.areas), \ + } + +#define PAINTING(name) struct painting name = PAINTING_INIT(name) + +static inline void INIT_PAINTING(struct painting *this) +{ + this->root = RB_ROOT; +} + +#define painting_for_each_area(pos, this) \ + for ((pos) = painting_first(this); \ + (pos) != NULL; \ + (pos) = painting_next(pos)) + +#define painting_for_each_area_save(pos, n, this) \ + for ((pos) = painting_first(this), \ + (n) = (((pos) == NULL) ? NULL : painting_next(pos)); \ + (pos) != NULL; \ + (pos) = (n), \ + (n) = (((pos) == NULL) ? NULL : painting_next(pos))) + +/* Functions */ +extern struct painting_area *find_neighbor(const struct painting *this, + phys_addr_t p); +extern struct painting_area * + painting_do_prev_overlaps_and_abuts(struct painting *this, + struct painting_area *cur, struct painting_desc *new, + struct painting_area *tail); +extern struct painting_area *do_successor(struct painting *this, + struct painting_area *cur, struct painting_desc *new); +extern int finish_new_allocation(struct painting *this, + struct painting_area *newp, struct painting_desc *new); + +/* + * _painting_from_rb - convert an rb_node to the containing &painting_area + * @rb: Pointer to the &struct rb_node + */ +static struct painting_area *__pure _painting_from_rb(struct rb_node *node) +{ + return (node == NULL) ? NULL : + container_of(node, struct painting_area, node); +} + +/** + * painting_area_first - find the first &painting_area in a &painting + * @painting: Pointer to a &struct pointing + * Returns NULL if no areas are in the &painting, otherwise a pointer to + * the first &struct painting_area. + */ +static inline struct painting_area *__pure + painting_first(const struct painting *p) +{ + return _painting_from_rb(rb_first(&p->root)); +} + +/** + * painting_next - find the next &painting_area + * @p: Pointer to a &struct painting_area + * + * Returns a pointer to the next &struct painting_area + */ +static inline struct painting_area *__pure + painting_next(const struct painting_area *p) +{ + return _painting_from_rb(rb_next(&p->node)); +} + +/** + * painting_prev - find the previous &painting_area + * @p: Pointer to a &struct painting_area + * + * Returns a pointer to the previous &struct painting_area + */ +static inline struct painting_area *__pure + painting_prev(const struct painting_area *p) +{ + return _painting_from_rb(rb_prev(&p->node)); +} + +/** + * classify - categorize the relationship between two areas + * @a: Pointer to a &struct painting_desc for the first area + * @b: Pointer to a &struct painting_desc for the second area + */ +static inline int __pure classify(const struct painting_desc *a, + const struct painting_desc *b) +{ + int same_color, b_ends_before_a, result; + + same_color = (a->color == b->color); + b_ends_before_a = (b->q < a->q); + result = ((same_color << 1) | b_ends_before_a); + return result; +} + +/** + * painting_have_prev - see if the current area preceeds the new area + * @cur: Pointer to the &painting_area for the current area + * @new: Pointer to the &painting_desc for the new area + * + * Returns true if the current area exists before the new area, false otherwise + */ +static inline bool __pure painting_have_prev(const struct painting_area *cur, + const struct painting_desc *new) +{ + return cur != NULL && cur->desc.p < new->p; +} + +/** + * painting_prev_overlaps_or_abuts - does prev area overlaps or abuts new area + * @cur: Pointer to &struct painting_desc for the current area + * @new: Pointer to &struct painting_desc for the current area + * + * Returns true of the current area is before the new area and either overlaps + * or abuts the new area. + */ +static inline bool __pure + painting_prev_overlaps_or_abuts(const struct painting_desc *cur, + const struct painting_desc *new) +{ + return cur->p < new->p && cur->q >= new->p - 1; +} + +/** + * painting_must_make_hole - see if new area makes a hole in the current area + * @cur: Pointer to the &struct painting_desc for the current area + * @new: Pointer to the &struct painting_desc for the new area + * + * Returns true if the new area makes a hole in the current area, i.e. the + * current area ends up on both sides of the new area, false otherwise. + */ +static inline bool __pure + painting_must_make_hole(const struct painting_desc *cur, + const struct painting_desc *new) +{ + return classify(cur, new) == MISMATCH_CUR_ENDS_LAST; +} + +/** + * painting_add_area - see if previous area overlaps or abuts the new area + * @cur: Pointer to &struct painting_desc for the current area + * @new: Pointer to &struct painting_desc for the current area + * + * Returns true of the current area is before the new area and either overlaps + * or abuts the new area. + */ +static inline bool __pure +painting_add_area(const struct painting_desc *cur, + const struct painting_desc *new) +{ + return classify(cur, new) != MATCH_CUR_ENDS_LAST; +} +#endif diff --git a/arch/mips/include/asm/mach-powertv/powertv-prealloc.h b/arch/mips/include/asm/mach-powertv/powertv-prealloc.h new file mode 100644 index 0000000..5b4f938 --- /dev/null +++ b/arch/mips/include/asm/mach-powertv/powertv-prealloc.h @@ -0,0 +1,51 @@ +/* + * Description: Does platform-specific hardware initialization + * + * Copyright (C) 2005-2010 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Systems, Inc. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _POWERTV_ASIC_PREALLOC_H_ +#define _POWERTV_ASIC_PREALLOC_H_ +#include <asm/mach-powertv/asic_regs.h> +#include "prealloc.h" + +/* PLATFORM RESOURCE DEFINITIONS */ +extern const struct dma_resource dvr_cronus_resources[]; +extern const struct dma_resource dvr_gaia_resources[]; +extern const struct dma_resource dvr_zeus_resources[]; +extern const struct dma_resource non_dvr_calliope_resources[]; +extern const struct dma_resource non_dvr_cronus_resources[]; +extern const struct dma_resource non_dvr_cronuslite_resources[]; +extern const struct dma_resource non_dvr_gaia_resources[]; +extern const struct dma_resource non_dvr_vz_calliope_resources[]; +extern const struct dma_resource non_dvr_vze_calliope_resources[]; +extern const struct dma_resource non_dvr_vzf_calliope_resources[]; +extern const struct dma_resource non_dvr_zeus_resources[]; + +extern const struct dma_resource *gp_resources; + +/* Resource for ASIC */ +extern struct resource asic_resource; + +/* Point to resource-s of Low memory and High memory extents */ +extern struct resource *ptv_res_loext_root; +extern struct resource *ptv_res_hiext_root; + +extern void plat_resource_init(void); +extern void register_available_ram(void); +#endif diff --git a/arch/mips/include/asm/mach-powertv/prealloc.h b/arch/mips/include/asm/mach-powertv/prealloc.h new file mode 100644 index 0000000..066c11f --- /dev/null +++ b/arch/mips/include/asm/mach-powertv/prealloc.h @@ -0,0 +1,121 @@ +/* + * Definitions for memory preallocations + * + * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Systems, Inc. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ARCH_MIPS_POWERTV_ASIC_PREALLOC_H +#define _ARCH_MIPS_POWERTV_ASIC_PREALLOC_H +#include <linux/ioport.h> +#include <linux/resource.h> +#include <asm/mach-powertv/painting.h> + +#define KIBIBYTE(n) ((n) * 1024) /* Number of kibibytes */ +#define MEBIBYTE(n) ((n) * KIBIBYTE(1024)) /* Number of mebibytes */ + +#define IORESOURCE_PTV_RES_LOEXT 0x1 /* Resource must go in low mem */ + +/* "struct resource" array element definition */ +#define PREALLOC(NAME, START, END, FLAGS) { \ + .name = (NAME), \ + .start = (START), \ + .end = (END), \ + .flags = (FLAGS) \ + }, + +/* Individual resources in the preallocated resource arrays are defined using + * macros. These macros are conditionally defined based on their + * corresponding kernel configuration flag: + * - CONFIG_PREALLOC_NORMAL: preallocate resources for a normal settop box + * - CONFIG_PREALLOC_TFTP: preallocate the TFTP download resource + * - CONFIG_PREALLOC_DOCSIS: preallocate the DOCSIS resource + * - CONFIG_PREALLOC_PMEM: reserve space for persistent memory + */ +#ifdef CONFIG_PREALLOC_NORMAL +#define PREALLOC_NORMAL(name, start, end, flags) \ + PREALLOC(name, start, end, flags) +#else +#define PREALLOC_NORMAL(name, start, end, flags) +#endif + +#ifdef CONFIG_PREALLOC_TFTP +#define PREALLOC_TFTP(name, start, end, flags) \ + PREALLOC(name, start, end, flags) +#else +#define PREALLOC_TFTP(name, start, end, flags) +#endif + +#ifdef CONFIG_PREALLOC_DOCSIS +#define PREALLOC_DOCSIS(name, start, end, flags) \ + PREALLOC(name, start, end, flags) +#else +#define PREALLOC_DOCSIS(name, start, end, flags) +#endif + +#ifdef CONFIG_PREALLOC_PMEM +#define PREALLOC_PMEM(name, start, end, flags) \ + PREALLOC(name, start, end, flags) +#else +#define PREALLOC_PMEM(name, start, end, flags) +#endif + +/* + * Drivers really just need to look up the physical addresss of a resource + * name. This is the data we pass back to them + */ +struct bus_resource { + phys_addr_t start; + phys_addr_t end; +}; + +/* + * For describing resources as DMA addresses + */ +struct dma_resource { + dma_addr_t start; + dma_addr_t end; + const char *name; + unsigned long flags; +}; + +/* Predefined physical memory types */ +extern const char physmem_bootloader[]; +extern const char physmem_buddy_high[]; +extern const char physmem_buddy_low[]; +extern const char physmem_mem_map[]; +extern const char physmem_ram[]; +extern const char physmem_reserved[]; +extern const char physmem_reset_vector[]; +extern const char physmem_rom_data[]; +extern const char physmem_unknown[]; +extern const char physmem_zero_page[]; + +/* allow drivers get info but use their data struct instead of passing */ +/* something allocated inside the kernel */ +extern int resource_add_ram(phys_addr_t start, size_t size); +extern void resource_reserve_static_prealloc(size_t size, + const struct dma_resource *dma_res); +extern void resource_add_memory_regions(void); +extern size_t __init resource_request_prealloc(size_t n, + const struct dma_resource *dma_resources); +extern bool platform_resource_override(struct resource *plat_res, + const struct dma_resource *dma_res); +extern int platform_lookup_resource(const char *name, + struct bus_resource *bres_p); +extern unsigned long platform_release_memory(unsigned long baddr, int size); +#endif diff --git a/arch/mips/powertv/Kconfig b/arch/mips/powertv/Kconfig index ff0e7e3..e327762 100644 --- a/arch/mips/powertv/Kconfig +++ b/arch/mips/powertv/Kconfig @@ -19,3 +19,15 @@ config BOOTLOADER_FAMILY E1 - Class E F1 - Class F 44 - 45xx 46 - 46xx 85 - 85xx 86 - 86xx + +config PREALLOCATED_AREAS_ITEMS + int "Number items for handling driver pre-allocations" + default 100 + depends on POWERTV + help + Very early allocations of large chunks of memory is done before any + of the memory allocators are in use. This requires that any memory + required be statically allocated. It is difficult to calculate the + exact value, but it is roughly twice the number of preallocations + plus two for the kernel and an extra two for each contiguous chunk + of memory. diff --git a/arch/mips/powertv/asic/Kconfig b/arch/mips/powertv/asic/Kconfig index 2016bfe..1a48e17 100644 --- a/arch/mips/powertv/asic/Kconfig +++ b/arch/mips/powertv/asic/Kconfig @@ -1,28 +1,34 @@ -config MIN_RUNTIME_RESOURCES - bool "Support for minimum runtime resources" - default n +menu "Preallocated resource options" + +config PREALLOC_NORMAL + bool "Preallocate normal resources" depends on POWERTV + default y help - Enables support for minimizing the number of (SA asic) runtime - resources that are preallocated by the kernel. + Enables support for the preallocated kernel resources used in normal + settop operation. This includes all preallocated resources that + aren't individually controlled via a separate CONFIG_PREALLOC_ + option. -config MIN_RUNTIME_DOCSIS - bool "Support for minimum DOCSIS resource" +config PREALLOC_DOCSIS + bool "Preallocate the DOCSIS resource" + depends on POWERTV default y - depends on MIN_RUNTIME_RESOURCES help Enables support for the preallocated DOCSIS resource. -config MIN_RUNTIME_PMEM - bool "Support for minimum PMEM resource" +config PREALLOC_PMEM + bool "Preallocate the PMEM resource" + depends on POWERTV default y - depends on MIN_RUNTIME_RESOURCES help - Enables support for the preallocated Memory resource. + Enables support for the preallocated persistent memory resource. -config MIN_RUNTIME_TFTP - bool "Support for minimum TFTP resource" - default y - depends on MIN_RUNTIME_RESOURCES +config PREALLOC_TFTP + bool "Preallocate the TFTP resource" + depends on POWERTV + default n help Enables support for the preallocated TFTP resource. + +endmenu diff --git a/arch/mips/powertv/asic/Makefile b/arch/mips/powertv/asic/Makefile index f0e95dc..db0846b 100644 --- a/arch/mips/powertv/asic/Makefile +++ b/arch/mips/powertv/asic/Makefile @@ -1,5 +1,6 @@ # # Copyright (C) 2009 Scientific-Atlanta, Inc. +# Copyright (C) 2010 Cisco Systems, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,7 +18,8 @@ # obj-y += asic-calliope.o asic-cronus.o asic-gaia.o asic-zeus.o \ - asic_devices.o asic_int.o irq_asic.o prealloc-calliope.o \ - prealloc-cronus.o prealloc-cronuslite.o prealloc-gaia.o prealloc-zeus.o + asic_devices.o asic_int.o irq_asic.o painting.o \ + powertv-prealloc.o prealloc.o prealloc-calliope.o prealloc-cronus.o \ + prealloc-cronuslite.o prealloc-gaia.o prealloc-zeus.o EXTRA_CFLAGS += -Wall -Werror diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c index e56fa61..a8c018b 100644 --- a/arch/mips/powertv/asic/asic_devices.c +++ b/arch/mips/powertv/asic/asic_devices.c @@ -1,8 +1,9 @@ /* * - * Description: Defines the platform resources for Gaia-based settops. + * Description: Does platform-specific hardware initialization * * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Systems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,22 +22,16 @@ * NOTE: The bootloader allocates persistent memory at an address which is * 16 MiB below the end of the highest address in KSEG0. All fixed * address memory reservations must avoid this region. + * + * NOTE: This does not pre-allocate memory areas with dynamic address in + * memory outside of kseg0/kseg1. Dynamic allocation is restricted to + * kseg0/kseg1 memory. It wouldn't really be all that hard to support it; + * it just hasn't been needed. */ -#include <linux/device.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/resource.h> -#include <linux/serial_reg.h> -#include <linux/io.h> -#include <linux/bootmem.h> -#include <linux/mm.h> -#include <linux/platform_device.h> #include <linux/module.h> -#include <asm/page.h> -#include <linux/swap.h> -#include <linux/highmem.h> -#include <linux/dma-mapping.h> #include <asm/mach-powertv/asic.h> #include <asm/mach-powertv/asic_regs.h> @@ -46,15 +41,11 @@ #include <asm/mach-powertv/kbldr.h> #endif #include <asm/bootinfo.h> +#include <asm/mach-powertv/powertv-prealloc.h> #define BOOTLDRFAMILY(byte1, byte0) (((byte1) << 8) | (byte0)) /* - * Forward Prototypes - */ -static void pmem_setup_resource(void); - -/* * Global Variables */ enum asic_type asic; @@ -66,14 +57,6 @@ EXPORT_SYMBOL(_asic_register_map); /* Exported for testing */ unsigned long asic_phy_base; unsigned long asic_base; EXPORT_SYMBOL(asic_base); /* Exported for testing */ -struct resource *gp_resources; - -/* - * Don't recommend to use it directly, it is usually used by kernel internally. - * Portable code should be using interfaces such as ioremp, dma_map_single, etc. - */ -unsigned long phys_to_dma_offset; -EXPORT_SYMBOL(phys_to_dma_offset); /* * @@ -89,6 +72,13 @@ struct resource asic_resource = { }; /* + * Don't recommend to use it directly, it is usually used by kernel internally. + * Portable code should be using interfaces such as ioremp, dma_map_single, etc. + */ +unsigned long phys_to_dma_offset; +EXPORT_SYMBOL(phys_to_dma_offset); + +/* * Allow override of bootloader-specified model * Returns zero on success, a negative errno value on failure. This parameter * allows overriding of the bootloader-specified model. @@ -236,9 +226,9 @@ static void __init set_register_map(unsigned long phys_base, } /** - * configure_platform - configuration based on platform type. + * powertv_platform_init - configuration based on platform type. */ -void __init configure_platform(void) +void __init powertv_platform_init(void) { platform_set_family(); @@ -374,176 +364,35 @@ void __init configure_platform(void) } } -/* - * RESOURCE ALLOCATION - * - */ -/* - * Allocates/reserves the Platform memory resources early in the boot process. - * This ignores any resources that are designated IORESOURCE_IO - */ -void __init platform_alloc_bootmem(void) -{ - int i; - int total = 0; - - /* Get persistent memory data from command line before allocating - * resources. This need to happen before normal command line parsing - * has been done */ - pmem_setup_resource(); - - /* Loop through looking for resources that want a particular address */ - for (i = 0; gp_resources[i].flags != 0; i++) { - int size = gp_resources[i].end - gp_resources[i].start + 1; - if ((gp_resources[i].start != 0) && - ((gp_resources[i].flags & IORESOURCE_MEM) != 0)) { - reserve_bootmem(dma_to_phys(gp_resources[i].start), - size, 0); - total += gp_resources[i].end - - gp_resources[i].start + 1; - pr_info("reserve resource %s at %08x (%u bytes)\n", - gp_resources[i].name, gp_resources[i].start, - gp_resources[i].end - - gp_resources[i].start + 1); - } - } - - /* Loop through assigning addresses for those that are left */ - for (i = 0; gp_resources[i].flags != 0; i++) { - int size = gp_resources[i].end - gp_resources[i].start + 1; - if ((gp_resources[i].start == 0) && - ((gp_resources[i].flags & IORESOURCE_MEM) != 0)) { - void *mem = alloc_bootmem_pages(size); - - if (mem == NULL) - pr_err("Unable to allocate bootmem pages " - "for %s\n", gp_resources[i].name); - - else { - gp_resources[i].start = - phys_to_dma(virt_to_phys(mem)); - gp_resources[i].end = - gp_resources[i].start + size - 1; - total += size; - pr_info("allocate resource %s at %08x " - "(%u bytes)\n", - gp_resources[i].name, - gp_resources[i].start, size); - } - } - } - - pr_info("Total Platform driver memory allocation: 0x%08x\n", total); - - /* indicate resources that are platform I/O related */ - for (i = 0; gp_resources[i].flags != 0; i++) { - if ((gp_resources[i].start != 0) && - ((gp_resources[i].flags & IORESOURCE_IO) != 0)) { - pr_info("reserved platform resource %s at %08x\n", - gp_resources[i].name, gp_resources[i].start); - } - } -} - -/* - * - * PERSISTENT MEMORY (PMEM) CONFIGURATION - * - */ -static unsigned long pmemaddr __initdata; - -static int __init early_param_pmemaddr(char *p) -{ - pmemaddr = (unsigned long)simple_strtoul(p, NULL, 0); - return 0; -} -early_param("pmemaddr", early_param_pmemaddr); - -static long pmemlen __initdata; - -static int __init early_param_pmemlen(char *p) -{ -/* TODO: we can use this code when and if the bootloader ever changes this */ -#if 0 - pmemlen = (unsigned long)simple_strtoul(p, NULL, 0); +#ifdef CONFIG_USB +#define NUM_USB_IFS 2 #else - pmemlen = 0x20000; +#define NUM_USB_IFS 0 #endif - return 0; -} -early_param("pmemlen", early_param_pmemlen); -/* - * Set up persistent memory. If we were given values, we patch the array of - * resources. Otherwise, persistent memory may be allocated anywhere at all. - */ -static void __init pmem_setup_resource(void) -{ - struct resource *resource; - resource = asic_resource_get("DiagPersistentMemory"); - - if (resource && pmemaddr && pmemlen) { - /* The address provided by bootloader is in kseg0. Convert to - * a bus address. */ - resource->start = phys_to_dma(pmemaddr - 0x80000000); - resource->end = resource->start + pmemlen - 1; - - pr_info("persistent memory: start=0x%x end=0x%x\n", - resource->start, resource->end); - } -} +static struct platform_device *platform_devices[NUM_USB_IFS]; /* - * - * RESOURCE ACCESS FUNCTIONS - * + * platform_devices_init - initialize platform resource usage */ - -/** - * asic_resource_get - retrieves parameters for a platform resource. - * @name: string to match resource - * - * Returns a pointer to a struct resource corresponding to the given name. - * - * CANNOT BE NAMED platform_resource_get, which would be the obvious choice, - * as this function name is already declared - */ -struct resource *asic_resource_get(const char *name) +int __init platform_devices_init(void) { - int i; + int ret; - for (i = 0; gp_resources[i].flags != 0; i++) { - if (strcmp(gp_resources[i].name, name) == 0) - return &gp_resources[i]; - } + asic_resource.start = asic_phy_base; + asic_resource.end += asic_resource.start; - return NULL; -} -EXPORT_SYMBOL(asic_resource_get); - -/** - * platform_release_memory - release pre-allocated memory - * @ptr: pointer to memory to release - * @size: size of resource - * - * This must only be called for memory allocated or reserved via the boot - * memory allocator. - */ -void platform_release_memory(void *ptr, int size) -{ - unsigned long addr; - unsigned long end; + ret = platform_usb_devices_init(&platform_devices[0], + &platform_devices[1]); + if (ret != 0) + return ret; - addr = ((unsigned long)ptr + (PAGE_SIZE - 1)) & PAGE_MASK; - end = ((unsigned long)ptr + size) & PAGE_MASK; + set_io_port_base(0); + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); - for (; addr < end; addr += PAGE_SIZE) { - ClearPageReserved(virt_to_page(__va(addr))); - init_page_count(virt_to_page(__va(addr))); - free_page((unsigned long)__va(addr)); - } + return 0; } -EXPORT_SYMBOL(platform_release_memory); +arch_initcall(platform_devices_init); /* * diff --git a/arch/mips/powertv/asic/asic_int.c b/arch/mips/powertv/asic/asic_int.c index 7362f63..6866302 100644 --- a/arch/mips/powertv/asic/asic_int.c +++ b/arch/mips/powertv/asic/asic_int.c @@ -2,7 +2,7 @@ * Carsten Langgaard, carstenl@xxxxxxxx * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc. * Copyright (C) 2001 Ralf Baechle - * Portions copyright (C) 2009 Cisco Systems, Inc. + * Portions copyright (C) 2009-2010 Cisco Systems, Inc. * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as @@ -37,6 +37,7 @@ #include <asm/mips-boards/generic.h> #include <asm/mach-powertv/asic_regs.h> +#include <asm/mach-powertv/powertv-prealloc.h> static DEFINE_RAW_SPINLOCK(asic_irq_lock); @@ -98,6 +99,7 @@ void __init arch_init_irq(void) { int i; + plat_resource_init(); asic_irq_init(); /* diff --git a/arch/mips/powertv/asic/painting.c b/arch/mips/powertv/asic/painting.c new file mode 100644 index 0000000..306622e --- /dev/null +++ b/arch/mips/powertv/asic/painting.c @@ -0,0 +1,298 @@ +/* + * painting.c + * + * Functions that allow assigning "paints" (really, arbitrary tokens) to + * different areas of a "painting". This is useful for keeping track of + * the usage of given chunks of memory or I/O devices. Areas are + * described using phys_addr_t values to keep the representation as + * abstract as possible. Areas are not intended to wrap around the value + * space, e.g. if an area starts at zero, it won't be consolidated with an area + * of the same color ending at ~0. + * + * Copyright (C) 2008 Scientific-Atlanta, Inc. + * Copyright (C) 2010 Cisco Systems, Inc. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: David VomLehn + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <asm/mach-powertv/painting.h> + +/** + * painting_link - link a &painting_area into a &painting + * @this: Pointer to &struct painting in which to add the + * &struct painting_area + * @new: Pointer to the &struct painting area to add + * + * Returns zero on success or a negative errno value on error + */ +static int painting_link(struct painting *this, struct painting_area *new) +{ + struct rb_node **n = &(this->root.rb_node), *parent = NULL; + + while (*n) { + struct painting_area *this; + phys_addr_t p; + + this = container_of(*n, struct painting_area, node); + parent = *n; + p = new->desc.p; + + if (p < this->desc.p) + n = &((*n)->rb_left); + else if (p > this->desc.p) + n = &((*n)->rb_right); + else + return false; + } + + rb_link_node(&new->node, parent, n); + rb_insert_color(&new->node, &this->root); + + return true; +} + +/** + * find_neighbor - find a neighbor close to the beginning of a &painting_area + * @this: Pointer to the &struct painting we are coloring + * @p: Location the area about which we are search starts + * + * Returns NULL if it didn't find anything at all. Otherwise it returns + * either a pointer to the last &struct painting_area before @p or, if + * there wasn't one, a pointer to the first &struct painting_area after p. + */ +struct painting_area *find_neighbor(const struct painting *this, + phys_addr_t p) +{ + struct rb_node *n = this->root.rb_node; + struct rb_node *parent; + struct painting_area *parent_area = NULL; + + while (n) { + parent = n; + parent_area = container_of(n, struct painting_area, node); + + if (p < parent_area->desc.p) + n = n->rb_left; + else if (p > parent_area->desc.p) + n = n->rb_right; + else + n = NULL; + } + + if (parent_area != NULL && parent_area->desc.p > p) { + struct painting_area *right; + right = painting_prev(parent_area); + if (right != NULL) + parent_area = right; + } + + return parent_area; +} + +/** + * painting_unlink - remove an area from the tree + * @this: Pointer to the &struct painting in which we are working + * @area: Start of the &struct painting_area + */ +static void painting_unlink(struct painting *this, + struct painting_area *cur) +{ + rb_erase(&cur->node, &this->root); +} + +/** + * make_a_hole - create a hole for new area in current area + * @this: Pointer &struct painting + * @cur: Pointer to current &pointer_area. This might be NULL if we're + * all done. + * @new: Starting location of new area. This has not yet been linked + * @tail: Newly allocated &struct painting_area to hold the end of the + * current area + * + * Returns zero on success, a negative errno value on failure. + */ +static int make_a_hole(struct painting *this, + struct painting_desc *cur, struct painting_desc *new, + struct painting_area *tail) +{ + int retval; + + if (tail == NULL) + retval = -ENOMEM; + else { + tail->desc.p = new->q + 1; + tail->desc.q = cur->q; + tail->desc.color = cur->color; + painting_link(this, tail); + + cur->q = new->p - 1; + retval = 0; + } + + return retval; +} + +/** + * extend_new - extend a new painting area, discarding an overlapping area + * @this: Pointer to a &struct painting in which we are working + * @cur: Pointer to the &struct painting_area for the overlapping + * area to be discarded + * @new: Pointer to the &struct painting_desc of an area to be extended + */ +static void extend_new(struct painting *this, struct painting_area *cur, + struct painting_desc *new) +{ + new->p = cur->desc.p; + painting_unlink(this, cur); +} + +/** + * chop_cur - truncate an area current in the list + * @cur: Pointer to a &struct painting_area for an area in the list + * @new: New area that overwrites the current area + */ +static void chop_cur(struct painting_area *cur, const struct painting_desc *new) +{ + cur->desc.q = new->p - 1; +} + +/** + * painting_do_prev_overlaps_and_abuts - handle previous that overlaps or abuts + * @this: Pointer to &struct painting on which we're working + * @cur: Pointer to &struct painting_area for the current area + * @new: Pointer to the &struct painting_desc for the current area + * @tail: Pointer to storage alloted for the left side of the hole made + * in the current area by the new area + * + * Returns an ERR_PTR if an error occurred, a non-NULL pointer of we have + * a &struct painting_area to free, and a NULL pointer otherwise. + * + * Here we handle a current area that is overlapping and before + * the new area. There are four cases: + * Cur RRRRRR RRRRRRRRRR RRRRRR RRRRRRRR + * New bbbbbb bbbbbb RRRRRR RRRR + * Res RRbbbbbb RRbbbbbbRR RRRRRRRR RRRRRRRR + * Rslt New+Cur Cur+New+Head Cur Cur + * Done No Yes No Yes + */ +struct painting_area * + painting_do_prev_overlaps_and_abuts(struct painting *this, + struct painting_area *cur, struct painting_desc *new, + struct painting_area *tail) +{ + struct painting_area *free_me = NULL; + int retval; + + switch (classify(&cur->desc, new)) { + case MISMATCH_CUR_ENDS_FIRST: + chop_cur(cur, new); + break; + + case MISMATCH_CUR_ENDS_LAST: + retval = make_a_hole(this, &cur->desc, new, tail); + if (retval != 0) + free_me = ERR_PTR(retval); + break; + + case MATCH_CUR_ENDS_FIRST: + extend_new(this, cur, new); + free_me = cur; + break; + + case MATCH_CUR_ENDS_LAST: + /* Nothing to do since all of the new area is already the same + * color as the current area. */ + break; + } + + return free_me; +} + +/** + * do_successor - do an area at or following the new area + * @this: Pointer to the &struct painting we're working on + * @cur: Current area in the area list + * @new: Pointer to the &struct painting_desc we're trying to add + * + * Returns a pointer to a &struct painting_area if it needs to be freed, + * otherwise it returns NULL. + */ +struct painting_area *do_successor(struct painting *this, + struct painting_area *cur, struct painting_desc *new) +{ + struct painting_area *retval = NULL; + + /* + * Every remaining area starts after the new area. Cases are therefore + * Cur RRRRRR RRRRRRRR RRRRRR RRRRRRRR + * New bbbbbbbb bbbbbb RRRRRRRR RRRRRR + * Res bbbbbbbb bbbbbbRR RRRRRRRR RRRRRRRR + * Name past end before end overpaint extend + * Rslt New+Cur New New New + */ + switch (classify(&cur->desc, new)) { + case MISMATCH_CUR_ENDS_FIRST: + painting_unlink(this, cur); + retval = cur; + break; + + case MISMATCH_CUR_ENDS_LAST: + painting_unlink(this, cur); + cur->desc.p = new->q + 1; + painting_link(this, cur); + break; + + case MATCH_CUR_ENDS_FIRST: + painting_unlink(this, cur); + retval = cur; + break; + + case MATCH_CUR_ENDS_LAST: + new->q = cur->desc.q; + painting_unlink(this, cur); + retval = cur; + break; + } + + return retval; +} + +/** + * finish_new_allocation - finish the work for add an area to the list + * @this: Pointer to the &struct painting on which we are working + * @newp: Pointer to the newly allocated &struct painting_area. + * @new: Pointer to the &struct painting_desc values to be stored + * in the new area + * + * Returns 0 in success, otherwise a negative errno value + */ +int finish_new_allocation(struct painting *this, + struct painting_area *newp, struct painting_desc *new) +{ + int retval = 0; + + if (newp == NULL) + retval = -ENOMEM; + else { + newp->desc = *new; + painting_link(this, newp); + } + + return retval; +} diff --git a/arch/mips/powertv/asic/powertv-prealloc.c b/arch/mips/powertv/asic/powertv-prealloc.c new file mode 100644 index 0000000..1047b5b --- /dev/null +++ b/arch/mips/powertv/asic/powertv-prealloc.c @@ -0,0 +1,136 @@ +/* + * Handle platform-specific resources + * + * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Systems, Inc. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/init.h> +#include <asm/mach-powertv/asic.h> +#include <asm/mach-powertv/powertv-prealloc.h> + +static struct dma_resource base_resources[] __initdata = { + {0x10000000, 0x10000000 + 0x40000 - 1, physmem_bootloader}, + {0x1fc00000, 0x1fc00000 + 0x400000 - 1, physmem_reset_vector}, +}; + +static unsigned long pmemaddr __initdata; + +static int __init early_param_pmemaddr(char *p) +{ + pmemaddr = (unsigned long)simple_strtoul(p, NULL, 0); + return 0; +} +early_param("pmemaddr", early_param_pmemaddr); + +static long pmemlen __initdata; + +static int __init early_param_pmemlen(char *p) +{ +/* TODO: we can use this code when and if the bootloader ever changes this */ +#if 0 + pmemlen = (unsigned long)simple_strtoul(p, NULL, 0); +#else + pmemlen = 0x20000; +#endif + return 0; +} +early_param("pmemlen", early_param_pmemlen); + +/* + * platform_resource_override - override information from platform resources + * @plat_res: Pointer to &struct resource to set if this resource is being + * overridden. + * @res: Pointer to &struct dma_resource to check whether it should be + * overridden. + * + * Returns true if the resource was overridden and should not be further + * processed, false if the resource wasn't overriden and should be processed + * as normal. + */ +bool __init platform_resource_override(struct resource *plat_res, + const struct dma_resource *res) +{ + if (strcmp(res->name, "DiagPersistentMemory") == 0) { + if (pmemaddr && pmemlen) { + /* The address provided by bootloader is in kseg0. + * Convert to a physical address. */ + plat_res->start = __pa(pmemaddr); + plat_res->end = plat_res->start + pmemlen - 1; + pr_info("persistent memory: start=0x%0*x end=0x%0*x\n", + 2 * sizeof(plat_res->start), plat_res->start, + 2 * sizeof(plat_res->end), plat_res->end); + } + return true; + } + + return false; +} + +/* + * dma_resource_count - tallies the number of DMA resources available + * @plat_res: Pointer to an array of &struct dma_resource objects + * + * Returns the number of non empty entries found + */ +static size_t __init dma_resource_count(const struct dma_resource *dma_res) +{ + int i; + /* Count number of resources */ + for (i = 0; dma_res[i].flags != 0; i++) + ; + return i; +} + +/** + * register_available_ram - give RAM minus preallocations to the sytem + */ +void __init register_available_ram() +{ + size_t num_plat_res; + + /* Subtract all of the preallocated RAM at a static address */ + resource_reserve_static_prealloc(ARRAY_SIZE(base_resources), + base_resources); + num_plat_res = dma_resource_count(gp_resources); + resource_reserve_static_prealloc(num_plat_res, gp_resources); + + /* Give all of the remaining RAM to the system */ + resource_add_memory_regions(); +} + +/** + * plat_resource_init - request resources for preallocated memory + */ +void __init plat_resource_init() +{ + size_t size; + size_t total = 0; + size_t num_plat_res; + + size = resource_request_prealloc(ARRAY_SIZE(base_resources), + base_resources); + if (size > 0) + total += size; + + num_plat_res = dma_resource_count(gp_resources); + size = resource_request_prealloc(num_plat_res, gp_resources); + if (size > 0) + total += size; + + pr_info("Total platform driver memory allocation: 0x%08x\n", total); +} diff --git a/arch/mips/powertv/asic/prealloc-calliope.c b/arch/mips/powertv/asic/prealloc-calliope.c index 3fc5d46..d1ad146 100644 --- a/arch/mips/powertv/asic/prealloc-calliope.c +++ b/arch/mips/powertv/asic/prealloc-calliope.c @@ -2,6 +2,7 @@ * Memory pre-allocations for Calliope boxes. * * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Systems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,12 +25,12 @@ #include <linux/init.h> #include <linux/ioport.h> #include <asm/mach-powertv/asic.h> -#include "prealloc.h" +#include <asm/mach-powertv/powertv-prealloc.h> /* * NON_DVR_CAPABLE CALLIOPE RESOURCES */ -struct resource non_dvr_calliope_resources[] __initdata = +const struct dma_resource non_dvr_calliope_resources[] __initdata = { /* * VIDEO / LX1 @@ -158,7 +159,7 @@ struct resource non_dvr_calliope_resources[] __initdata = }; -struct resource non_dvr_vze_calliope_resources[] __initdata = +const struct dma_resource non_dvr_vze_calliope_resources[] __initdata = { /* * VIDEO / LX1 @@ -264,7 +265,7 @@ struct resource non_dvr_vze_calliope_resources[] __initdata = }, }; -struct resource non_dvr_vzf_calliope_resources[] __initdata = +const struct dma_resource non_dvr_vzf_calliope_resources[] __initdata = { /* * VIDEO / LX1 diff --git a/arch/mips/powertv/asic/prealloc-cronus.c b/arch/mips/powertv/asic/prealloc-cronus.c index c532b50..cd0d034 100644 --- a/arch/mips/powertv/asic/prealloc-cronus.c +++ b/arch/mips/powertv/asic/prealloc-cronus.c @@ -2,6 +2,7 @@ * Memory pre-allocations for Cronus boxes. * * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Systems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,12 +25,12 @@ #include <linux/init.h> #include <linux/ioport.h> #include <asm/mach-powertv/asic.h> -#include "prealloc.h" +#include <asm/mach-powertv/powertv-prealloc.h> /* * DVR_CAPABLE CRONUS RESOURCES */ -struct resource dvr_cronus_resources[] __initdata = +const struct dma_resource dvr_cronus_resources[] __initdata = { /* * VIDEO1 / LX1 @@ -192,7 +193,7 @@ struct resource dvr_cronus_resources[] __initdata = /* * NON_DVR_CAPABLE CRONUS RESOURCES */ -struct resource non_dvr_cronus_resources[] __initdata = +const struct dma_resource non_dvr_cronus_resources[] __initdata = { /* * VIDEO1 / LX1 diff --git a/arch/mips/powertv/asic/prealloc-cronuslite.c b/arch/mips/powertv/asic/prealloc-cronuslite.c index b5537e4..851a626 100644 --- a/arch/mips/powertv/asic/prealloc-cronuslite.c +++ b/arch/mips/powertv/asic/prealloc-cronuslite.c @@ -2,6 +2,7 @@ * Memory pre-allocations for Cronus Lite boxes. * * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Sysems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,12 +25,12 @@ #include <linux/init.h> #include <linux/ioport.h> #include <asm/mach-powertv/asic.h> -#include "prealloc.h" +#include <asm/mach-powertv/powertv-prealloc.h> /* * NON_DVR_CAPABLE CRONUSLITE RESOURCES */ -struct resource non_dvr_cronuslite_resources[] __initdata = +const struct dma_resource non_dvr_cronuslite_resources[] __initdata = { /* * VIDEO2 / LX2 diff --git a/arch/mips/powertv/asic/prealloc-gaia.c b/arch/mips/powertv/asic/prealloc-gaia.c index 8ac8c7a..d3f6694 100644 --- a/arch/mips/powertv/asic/prealloc-gaia.c +++ b/arch/mips/powertv/asic/prealloc-gaia.c @@ -2,6 +2,7 @@ * Memory pre-allocations for Gaia boxes. * * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Sysems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,291 +23,154 @@ #include <linux/init.h> #include <asm/mach-powertv/asic.h> +#include <asm/mach-powertv/powertv-prealloc.h> /* * DVR_CAPABLE GAIA RESOURCES */ -struct resource dvr_gaia_resources[] __initdata = { +const struct dma_resource dvr_gaia_resources[] __initdata = { /* - * * VIDEO1 / LX1 - * */ - { - .name = "ST231aImage", /* Delta-Mu 1 image and ram */ - .start = 0x24000000, - .end = 0x241FFFFF, /* 2MiB */ - .flags = IORESOURCE_MEM, - }, - { - .name = "ST231aMonitor", /* 8KiB block ST231a monitor */ - .start = 0x24200000, - .end = 0x24201FFF, - .flags = IORESOURCE_MEM, - }, - { - .name = "MediaMemory1", - .start = 0x24202000, - .end = 0x25FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ - .flags = IORESOURCE_MEM, - }, + /* Delta-Mu 1 image and RAM (2 MiB) */ + PREALLOC_NORMAL("ST231aImage", 0x24000000, 0x241FFFFF, IORESOURCE_MEM) + /* 8KiB block ST231a monitor */ + PREALLOC_NORMAL("ST231aMonitor", 0x24200000, 0x24201FFF, IORESOURCE_MEM) + /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ + PREALLOC_NORMAL("MediaMemory1", 0x24202000, 0x25FFFFFF, IORESOURCE_MEM) /* - * * VIDEO2 / LX2 - * */ - { - .name = "ST231bImage", /* Delta-Mu 2 image and ram */ - .start = 0x60000000, - .end = 0x601FFFFF, /* 2MiB */ - .flags = IORESOURCE_IO, - }, - { - .name = "ST231bMonitor", /* 8KiB block ST231b monitor */ - .start = 0x60200000, - .end = 0x60201FFF, - .flags = IORESOURCE_IO, - }, - { - .name = "MediaMemory2", - .start = 0x60202000, - .end = 0x61FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ - .flags = IORESOURCE_IO, - }, + /* Delta-Mu 2 image and RAM (2 MiB)*/ + PREALLOC_NORMAL("ST231bImage", 0x60000000, 0x601FFFFF, IORESOURCE_IO) + /* 8KiB block ST231b monitor */ + PREALLOC_NORMAL("ST231bMonitor", 0x60200000, 0x60201FFF, IORESOURCE_IO) + /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ + PREALLOC_NORMAL("MediaMemory2", 0x60202000, 0x61FFFFFF, IORESOURCE_IO) /* - * * Sysaudio Driver - * * This driver requires: - * * Arbitrary Based Buffers: * DSP_Image_Buff - DSP code and data images (1MB) * ADSC_CPU_PCM_Buff - ADSC CPU PCM buffer (40KB) * ADSC_AUX_Buff - ADSC AUX buffer (16KB) * ADSC_Main_Buff - ADSC Main buffer (16KB) - * */ - { - .name = "DSP_Image_Buff", - .start = 0x00000000, - .end = 0x000FFFFF, - .flags = IORESOURCE_MEM, - }, - { - .name = "ADSC_CPU_PCM_Buff", - .start = 0x00000000, - .end = 0x00009FFF, - .flags = IORESOURCE_MEM, - }, - { - .name = "ADSC_AUX_Buff", - .start = 0x00000000, - .end = 0x00003FFF, - .flags = IORESOURCE_MEM, - }, - { - .name = "ADSC_Main_Buff", - .start = 0x00000000, - .end = 0x00003FFF, - .flags = IORESOURCE_MEM, - }, + PREALLOC_NORMAL("DSP_Image_Buff", 0x00000000, 0x000FFFFF, + IORESOURCE_MEM) + PREALLOC_NORMAL("ADSC_CPU_PCM_Buff", 0x00000000, 0x00009FFF, + IORESOURCE_MEM) + PREALLOC_NORMAL("ADSC_AUX_Buff", 0x00000000, 0x00003FFF, IORESOURCE_MEM) + PREALLOC_NORMAL("ADSC_Main_Buff", 0x00000000, 0x00003FFF, + IORESOURCE_MEM) /* - * * STAVEM driver/STAPI - * * This driver requires: - * * Arbitrary Based Buffers: * This memory area is used for allocating buffers for Video decoding * purposes. Allocation/De-allocation within this buffer is managed * by the STAVMEM driver of the STAPI. They could be Decimated * Picture Buffers, Intermediate Buffers, as deemed necessary for * video decoding purposes, for any video decoders on Zeus. - * */ - { - .name = "AVMEMPartition0", - .start = 0x63580000, - .end = 0x64180000 - 1, /* 12 MB total */ - .flags = IORESOURCE_IO, - }, + /* 12 MB total */ + PREALLOC_NORMAL("AVMEMPartition0", 0x63580000, 0x64180000 - 1, + IORESOURCE_IO) /* - * * DOCSIS Subsystem - * * This driver requires: - * * Arbitrary Based Buffers: * Docsis - - * */ - { - .name = "Docsis", - .start = 0x62000000, - .end = 0x62700000 - 1, /* 7 MB total */ - .flags = IORESOURCE_IO, - }, + /* 7 MB total */ + PREALLOC_DOCSIS("Docsis", 0x62000000, 0x62700000 - 1, IORESOURCE_IO) /* - * * GHW HAL Driver - * * This driver requires: - * * Arbitrary Based Buffers: * GraphicsHeap - PowerTV Graphics Heap - * */ - { - .name = "GraphicsHeap", - .start = 0x62700000, - .end = 0x63500000 - 1, /* 14 MB total */ - .flags = IORESOURCE_IO, - }, + /* 14 MB total */ + PREALLOC_NORMAL("GraphicsHeap", 0x62700000, 0x63500000 - 1, + IORESOURCE_IO) /* - * * multi com buffer area - * * This driver requires: - * * Arbitrary Based Buffers: * Docsis - - * */ - { - .name = "MulticomSHM", - .start = 0x26000000, - .end = 0x26020000 - 1, - .flags = IORESOURCE_MEM, - }, + PREALLOC_NORMAL("MulticomSHM", 0x26000000, 0x26020000 - 1, + IORESOURCE_MEM) /* - * * DMA Ring buffer - * * This driver requires: - * * Arbitrary Based Buffers: * Docsis - - * */ - { - .name = "BMM_Buffer", - .start = 0x00000000, - .end = 0x00280000 - 1, - .flags = IORESOURCE_MEM, - }, + PREALLOC_NORMAL("BMM_Buffer", 0x00000000, 0x00280000 - 1, + IORESOURCE_MEM) /* - * * Display bins buffer for unit0 - * * This driver requires: - * * Arbitrary Based Buffers: * Display Bins for unit0 - * */ - { - .name = "DisplayBins0", - .start = 0x00000000, - .end = 0x00000FFF, /* 4 KB total */ - .flags = IORESOURCE_MEM, - }, + /* 4 KB total */ + PREALLOC_NORMAL("DisplayBins0", 0x00000000, 0x00000FFF, IORESOURCE_MEM) /* - * * Display bins buffer - * * This driver requires: - * * Arbitrary Based Buffers: * Display Bins for unit1 - * */ - { - .name = "DisplayBins1", - .start = 0x64AD4000, - .end = 0x64AD5000 - 1, /* 4 KB total */ - .flags = IORESOURCE_IO, - }, + /* 4 KB total */ + PREALLOC_NORMAL("DisplayBins1", 0x64AD4000, 0x64AD5000 - 1, + IORESOURCE_IO) /* - * * ITFS - * * This driver requires: - * * Arbitrary Based Buffers: * Docsis - - * */ - { - .name = "ITFS", - .start = 0x64180000, - /* 815,104 bytes each for 2 ITFS partitions. */ - .end = 0x6430DFFF, - .flags = IORESOURCE_IO, - }, + /* 815, 104 bytes each for 2 ITFS partitions. */ + PREALLOC_NORMAL("ITFS", 0x64180000, 0x6430DFFF, IORESOURCE_IO) /* - * * AVFS - * * This driver requires: - * * Arbitrary Based Buffers: * Docsis - - * */ - { - .name = "AvfsDmaMem", - .start = 0x6430E000, - /* (945K * 8) = (128K *3) 5 playbacks / 3 server */ - .end = 0x64AD0000 - 1, - .flags = IORESOURCE_IO, - }, - { - .name = "AvfsFileSys", - .start = 0x64AD0000, - .end = 0x64AD1000 - 1, /* 4K */ - .flags = IORESOURCE_IO, - }, + /* (945K * 8) = (128K *3) 5 playbacks / 3 server */ + PREALLOC_NORMAL("AvfsDmaMem", 0x6430E000, 0x64AD0000 - 1, IORESOURCE_IO) + /* 4K */ + PREALLOC_NORMAL("AvfsFileSys", 0x64AD0000, 0x64AD1000 - 1, + IORESOURCE_IO) + /* + * PMEM + * This driver requires: + * Arbitrary Based Buffers: + * Persistent memory for diagnostics. + */ + PREALLOC_PMEM("DiagPersistentMemory", 0x00000000, 0x10000 - 1, + IORESOURCE_MEM) /* - * * Smartcard - * * This driver requires: - * * Arbitrary Based Buffers: * Read and write buffers for Internal/External cards - * */ - { - .name = "SmartCardInfo", - .start = 0x64AD1000, - .end = 0x64AD3800 - 1, - .flags = IORESOURCE_IO, - }, + PREALLOC_NORMAL("SmartCardInfo", 0x64AD1000, 0x64AD3800 - 1, + IORESOURCE_IO) /* - * * KAVNET * NP Reset Vector - must be of the form xxCxxxxx * NP Image - must be video bank 1 * NP IPC - must be video bank 2 */ - { - .name = "NP_Reset_Vector", - .start = 0x27c00000, - .end = 0x27c01000 - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "NP_Image", - .start = 0x27020000, - .end = 0x27060000 - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "NP_IPC", - .start = 0x63500000, - .end = 0x63580000 - 1, - .flags = IORESOURCE_IO, - }, + PREALLOC_NORMAL("NP_Reset_Vector", 0x27c00000, 0x27c01000 - 1, + IORESOURCE_MEM) + PREALLOC_NORMAL("NP_Image", 0x27020000, 0x27060000 - 1, IORESOURCE_MEM) + PREALLOC_NORMAL("NP_IPC", 0x63500000, 0x63580000 - 1, IORESOURCE_IO) /* * Add other resources here */ @@ -316,274 +180,134 @@ struct resource dvr_gaia_resources[] __initdata = { /* * NON_DVR_CAPABLE GAIA RESOURCES */ -struct resource non_dvr_gaia_resources[] __initdata = { +const struct dma_resource non_dvr_gaia_resources[] __initdata = { /* - * * VIDEO1 / LX1 - * */ - { - .name = "ST231aImage", /* Delta-Mu 1 image and ram */ - .start = 0x24000000, - .end = 0x241FFFFF, /* 2MiB */ - .flags = IORESOURCE_MEM, - }, - { - .name = "ST231aMonitor", /* 8KiB block ST231a monitor */ - .start = 0x24200000, - .end = 0x24201FFF, - .flags = IORESOURCE_MEM, - }, - { - .name = "MediaMemory1", - .start = 0x24202000, - .end = 0x25FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ - .flags = IORESOURCE_MEM, - }, + /* Delta-Mu 1 image and ram (2 MiB) */ + PREALLOC_NORMAL("ST231aImage", 0x24000000, 0x241FFFFF, IORESOURCE_MEM) + /* 8KiB block ST231a monitor */ + PREALLOC_NORMAL("ST231aMonitor", 0x24200000, 0x24201FFF, IORESOURCE_MEM) + /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ + PREALLOC_NORMAL("MediaMemory1", 0x24202000, 0x25FFFFFF, IORESOURCE_MEM) /* - * * VIDEO2 / LX2 - * */ - { - .name = "ST231bImage", /* Delta-Mu 2 image and ram */ - .start = 0x60000000, - .end = 0x601FFFFF, /* 2MiB */ - .flags = IORESOURCE_IO, - }, - { - .name = "ST231bMonitor", /* 8KiB block ST231b monitor */ - .start = 0x60200000, - .end = 0x60201FFF, - .flags = IORESOURCE_IO, - }, - { - .name = "MediaMemory2", - .start = 0x60202000, - .end = 0x61FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ - .flags = IORESOURCE_IO, - }, + /* Delta-Mu 2 image and ram (2 MiB)*/ + PREALLOC_NORMAL("ST231bImage", 0x60000000, 0x601FFFFF, IORESOURCE_IO) + /* 8KiB block ST231b monitor */ + PREALLOC_NORMAL("ST231bMonitor", 0x60200000, 0x60201FFF, IORESOURCE_IO) + /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ + PREALLOC_NORMAL("MediaMemory2", 0x60202000, 0x61FFFFFF, IORESOURCE_IO) /* - * * Sysaudio Driver - * * This driver requires: - * * Arbitrary Based Buffers: * DSP_Image_Buff - DSP code and data images (1MB) * ADSC_CPU_PCM_Buff - ADSC CPU PCM buffer (40KB) * ADSC_AUX_Buff - ADSC AUX buffer (16KB) * ADSC_Main_Buff - ADSC Main buffer (16KB) - * */ - { - .name = "DSP_Image_Buff", - .start = 0x00000000, - .end = 0x000FFFFF, - .flags = IORESOURCE_MEM, - }, - { - .name = "ADSC_CPU_PCM_Buff", - .start = 0x00000000, - .end = 0x00009FFF, - .flags = IORESOURCE_MEM, - }, - { - .name = "ADSC_AUX_Buff", - .start = 0x00000000, - .end = 0x00003FFF, - .flags = IORESOURCE_MEM, - }, - { - .name = "ADSC_Main_Buff", - .start = 0x00000000, - .end = 0x00003FFF, - .flags = IORESOURCE_MEM, - }, + PREALLOC_NORMAL("DSP_Image_Buff", 0x00000000, 0x000FFFFF, + IORESOURCE_MEM) + PREALLOC_NORMAL("ADSC_CPU_PCM_Buff", 0x00000000, 0x00009FFF, + IORESOURCE_MEM) + PREALLOC_NORMAL("ADSC_AUX_Buff", 0x00000000, 0x00003FFF, IORESOURCE_MEM) + PREALLOC_NORMAL("ADSC_Main_Buff", 0x00000000, 0x00003FFF, + IORESOURCE_MEM) /* - * * STAVEM driver/STAPI - * * This driver requires: - * * Arbitrary Based Buffers: * This memory area is used for allocating buffers for Video decoding * purposes. Allocation/De-allocation within this buffer is managed * by the STAVMEM driver of the STAPI. They could be Decimated * Picture Buffers, Intermediate Buffers, as deemed necessary for * video decoding purposes, for any video decoders on Zeus. - * */ - { - .name = "AVMEMPartition0", - .start = 0x63580000, - .end = 0x64180000 - 1, /* 12 MB total */ - .flags = IORESOURCE_IO, - }, + /* 12 MB total */ + PREALLOC_NORMAL("AVMEMPartition0", 0x63580000, 0x64180000 - 1, + IORESOURCE_IO) /* - * * DOCSIS Subsystem - * * This driver requires: - * * Arbitrary Based Buffers: * Docsis - - * */ - { - .name = "Docsis", - .start = 0x62000000, - .end = 0x62700000 - 1, /* 7 MB total */ - .flags = IORESOURCE_IO, - }, + /* 7 MB total */ + PREALLOC_DOCSIS("Docsis", 0x62000000, 0x62700000 - 1, IORESOURCE_IO) /* - * * GHW HAL Driver - * * This driver requires: - * * Arbitrary Based Buffers: * GraphicsHeap - PowerTV Graphics Heap - * */ - { - .name = "GraphicsHeap", - .start = 0x62700000, - .end = 0x63500000 - 1, /* 14 MB total */ - .flags = IORESOURCE_IO, - }, + /* 14 MB total */ + PREALLOC_NORMAL("GraphicsHeap", 0x62700000, 0x63500000 - 1, + IORESOURCE_IO) /* - * * multi com buffer area - * * This driver requires: - * * Arbitrary Based Buffers: * Docsis - - * */ - { - .name = "MulticomSHM", - .start = 0x26000000, - .end = 0x26020000 - 1, - .flags = IORESOURCE_MEM, - }, + PREALLOC_NORMAL("MulticomSHM", 0x26000000, 0x26020000 - 1, + IORESOURCE_MEM) /* - * * DMA Ring buffer - * * This driver requires: - * * Arbitrary Based Buffers: * Docsis - - * */ - { - .name = "BMM_Buffer", - .start = 0x00000000, - .end = 0x000AA000 - 1, - .flags = IORESOURCE_MEM, - }, + PREALLOC_NORMAL("BMM_Buffer", 0x00000000, 0x000AA000 - 1, + IORESOURCE_MEM) /* - * * Display bins buffer for unit0 - * * This driver requires: - * * Arbitrary Based Buffers: * Display Bins for unit0 - * */ - { - .name = "DisplayBins0", - .start = 0x00000000, - .end = 0x00000FFF, /* 4 KB total */ - .flags = IORESOURCE_MEM, - }, + /* 4 KB total */ + PREALLOC_NORMAL("DisplayBins0", 0x00000000, 0x00000FFF, IORESOURCE_MEM) /* - * * Display bins buffer - * * This driver requires: - * * Arbitrary Based Buffers: * Display Bins for unit1 - * */ - { - .name = "DisplayBins1", - .start = 0x64AD4000, - .end = 0x64AD5000 - 1, /* 4 KB total */ - .flags = IORESOURCE_IO, - }, + /* 4 KB total */ + PREALLOC_NORMAL("DisplayBins1", 0x64AD4000, 0x64AD5000 - 1, + IORESOURCE_IO) /* - * * AVFS: player HAL memory - * - * */ - { - .name = "AvfsDmaMem", - .start = 0x6430E000, - .end = 0x645D2C00 - 1, /* 945K * 3 for playback */ - .flags = IORESOURCE_IO, - }, + /* 945K * 3 for playback */ + PREALLOC_NORMAL("AvfsDmaMem", 0x6430E000, 0x645D2C00 - 1, IORESOURCE_IO) /* - * * PMEM - * * This driver requires: - * * Arbitrary Based Buffers: * Persistent memory for diagnostics. - * */ - { - .name = "DiagPersistentMemory", - .start = 0x00000000, - .end = 0x10000 - 1, - .flags = IORESOURCE_MEM, - }, + PREALLOC_PMEM("DiagPersistentMemory", 0x00000000, 0x10000 - 1, + IORESOURCE_MEM) /* - * * Smartcard - * * This driver requires: - * * Arbitrary Based Buffers: * Read and write buffers for Internal/External cards - * */ - { - .name = "SmartCardInfo", - .start = 0x64AD1000, - .end = 0x64AD3800 - 1, - .flags = IORESOURCE_IO, - }, + PREALLOC_NORMAL("SmartCardInfo", 0x64AD1000, 0x64AD3800 - 1, + IORESOURCE_IO) /* - * * KAVNET * NP Reset Vector - must be of the form xxCxxxxx * NP Image - must be video bank 1 * NP IPC - must be video bank 2 */ - { - .name = "NP_Reset_Vector", - .start = 0x27c00000, - .end = 0x27c01000 - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "NP_Image", - .start = 0x27020000, - .end = 0x27060000 - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "NP_IPC", - .start = 0x63500000, - .end = 0x63580000 - 1, - .flags = IORESOURCE_IO, - }, + PREALLOC_NORMAL("NP_Reset_Vector", 0x27c00000, 0x27c01000 - 1, + IORESOURCE_MEM) + PREALLOC_NORMAL("NP_Image", 0x27020000, 0x27060000 - 1, IORESOURCE_MEM) + PREALLOC_NORMAL("NP_IPC", 0x63500000, 0x63580000 - 1, IORESOURCE_IO) { }, }; diff --git a/arch/mips/powertv/asic/prealloc-zeus.c b/arch/mips/powertv/asic/prealloc-zeus.c index 96480a2..0212f89 100644 --- a/arch/mips/powertv/asic/prealloc-zeus.c +++ b/arch/mips/powertv/asic/prealloc-zeus.c @@ -2,6 +2,7 @@ * Memory pre-allocations for Zeus boxes. * * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Sysems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,12 +25,12 @@ #include <linux/init.h> #include <linux/ioport.h> #include <asm/mach-powertv/asic.h> -#include "prealloc.h" +#include <asm/mach-powertv/powertv-prealloc.h> /* * DVR_CAPABLE RESOURCES */ -struct resource dvr_zeus_resources[] __initdata = +const struct dma_resource dvr_zeus_resources[] __initdata = { /* * VIDEO1 / LX1 @@ -182,7 +183,7 @@ struct resource dvr_zeus_resources[] __initdata = /* * NON_DVR_CAPABLE ZEUS RESOURCES */ -struct resource non_dvr_zeus_resources[] __initdata = +const struct dma_resource non_dvr_zeus_resources[] __initdata = { /* * VIDEO1 / LX1 diff --git a/arch/mips/powertv/asic/prealloc.c b/arch/mips/powertv/asic/prealloc.c new file mode 100644 index 0000000..f2b63aa --- /dev/null +++ b/arch/mips/powertv/asic/prealloc.c @@ -0,0 +1,566 @@ +/* + * + * Description: Preallocate large chunks of memory for drivers + * + * Copyright (C) 2005-2010 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Sysems, Inc. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/bootinfo.h> +#include <asm/mach-powertv/powertv-prealloc.h> +#include <asm/mach-powertv/asic.h> + +/* + * Type Definitions + */ + +const struct dma_resource *gp_resources __initdata; + +/* Definitions for physical memory area information. We don't have + * kmalloc working at this point. In fact, we don't even have the boot + * memory allocator, so we have no choice but to use a static allocation. + * In the best of all possible worlds, we might have a way to switch to + * the boot memory allocator, and then the slab/slob/slub allocator when + * they become available, but this probably isn't really worth the effort. */ +struct alloc_item { + struct list_head free_areas; + struct painting_area area; +}; + +static struct alloc_item areas[CONFIG_PREALLOCATED_AREAS_ITEMS] __initdata; + +static LIST_HEAD(free_areas); /* List of avail. area allocations */ +static int areas_unallocated = ARRAY_SIZE(areas); /* # never-allocated areas */ +static loff_t num_areas; /* Current count of areas */ +static bool alloc_errors; /* Flag to indicate faulty data */ +static PAINTING(ram_painting); + +/* + * Allocate a painting_area. We do the allocation so early that we can't + * count on running any code to initialize the list of free areas, so we + * also have a counter of the number of items unused in the array of areas. + * + * Returns: Pointer to a struct painting_area, or NULL if none is + * available. + */ +static __init struct painting_area *physmem_alloc(void) +{ + struct alloc_item *item; + struct painting_area *result; + + /* First use anything in the areas array that hasn't been used. If + * that fails, then go to our list of free areas. */ + if (areas_unallocated != 0) { + areas_unallocated--; + item = &areas[areas_unallocated]; + } else if (!list_empty(&free_areas)) { + item = list_first_entry(&free_areas, struct alloc_item, + free_areas); + list_del(&item->free_areas); + } + + else + item = NULL; + + /* If we failed to allocate something, then log it and return NULL. + * Otherwise, return a pointer to the painting_area portion */ + if (!item) { + alloc_errors = true; + result = NULL; + } else { + result = &item->area; + num_areas++; + } + + return result; +} + +/* + * Free a painting area + * @p: Pointer to struct painting_area to free + */ +static __init void physmem_free(const struct painting_area *p) +{ + struct alloc_item *item; + + item = container_of(p, struct alloc_item, area); + list_add(&item->free_areas, &free_areas); + num_areas--; +} + +/* + * mem_painting_add - add a painting area to a painting + * @this: Pointer to the &struct painting on which we are working + * @desc: Pointer to a &struct painting_desc to add. + * + * Returns zere on success, otherwise a negative errno value + * + * The approach is to start with the area preceeding the new area, then any + * areas that start at the same place as the new area, then all of rest of + * areas that start before, at, or right after the end of the new area. + */ +int __init mem_painting_add(struct painting *this, + const struct painting_desc *new_desc) +{ + struct painting_area *newp; /* Area we are adding */ + struct painting_area *cur; /* Current area we are working on */ + struct painting_area *next; + struct painting_desc new; + int retval = 0; + bool add_new = true; + + new = *new_desc; /* Make a copy so we can modify these */ + cur = find_neighbor(this, new.p); + + if (painting_have_prev(cur, &new)) { + next = painting_next(cur); + + if (painting_prev_overlaps_or_abuts(&cur->desc, &new)) { + struct painting_area *tail; + struct painting_area *free_me; + + tail = painting_must_make_hole(&cur->desc, &new) ? + physmem_alloc() : NULL; + free_me = painting_do_prev_overlaps_and_abuts(this, + cur, &new, tail); + if (IS_ERR(free_me)) + retval = PTR_ERR(free_me); + else if (free_me != NULL) + physmem_free(free_me); + add_new = painting_add_area(&cur->desc, &new); + } + + cur = next; + } + + /* TODO: Ensure proper handling of wrap-around of value space here */ + while (retval == 0 && cur != NULL && cur->desc.p <= new.q + 1) { + struct painting_area *ret; + + ret = do_successor(this, cur, &new); + if (ret != NULL) + physmem_free(ret); + + cur = painting_next(cur); + } + + /* + * If the new area wasn't subsumed by another area, we need to allocate + * storage for it and line it in. + */ + if (retval == 0 && add_new) { + newp = physmem_alloc(); + retval = finish_new_allocation(this, newp, &new); + } + + return retval; +} + +/** + * resource_add_ram - add actual RAM + * @start: Physical address of the start of RAM + * @end: Physical address of the last byte of RAM + * + * Returns zero on success, a negative errno value on failure + */ +int __init resource_add_ram(phys_addr_t start, phys_addr_t end) +{ + struct painting_desc desc; + int res; + + desc.p = start; + desc.q = end; + desc.color = physmem_ram; + res = mem_painting_add(&ram_painting, &desc); + return res; +} + +/* + * + * RESOURCE ACCESS FUNCTIONS + * + */ + +/* + * lookup_root_resource - finds the right root resource for a range + * @start: the physical address of start of resource. + * @size: the size of resource in byte + * + * Returns a pointer to the resource or NULL upon failure. It finds the most + * deeply nested resource that can hold the resource we were passed. + */ +static __init struct resource *__init lookup_root_resource(unsigned long start, + unsigned long size) +{ + struct resource *result; + struct resource *res_p; + + result = NULL; + res_p = iomem_resource.child; + + while (res_p) { + /* + * If we have a resource that can hold the resource we + * were passed, remember it and then switch to scanning + * its children. + */ + if ((res_p->start <= start) && + (res_p->end >= (start + size - 1))) { + result = res_p; + res_p = result->child; + } else { + res_p = res_p->sibling; + } + } + + if (result == NULL) + pr_err("Can't find root resource for resource at " + "0x%lx-0x%lx\n", start, start + size - 1); + + return result; +} + +/** + * platform_lookup_resource_entry - finds resource entry by name + * @name: pointer to string containing name of resource + * + * Returns a pointer to the corresponding &struct resource or NULL if it + * couldn't find one. + */ +static struct resource *platform_lookup_resource_entry(const char *name) +{ + struct resource *p; + struct resource *next; + + for (p = iomem_resource.child; p != NULL; p = next) { + if (strcmp(p->name, name) == 0) + return p; + + next = p->child; /* Go deeper, if possible */ + + if (next == NULL) { + next = p->sibling; /* Go sideways, if possible */ + + if (next == NULL) { + /* Go up and, possibly, over */ + for (next = p->parent; next != NULL; + next = p->parent) { + p = next; + next = p->sibling; + if (next != NULL) + break; + } + } + } + } + + return NULL; +} + +/* + * set_resource_addresses - set platform resource address information + * @plat_res: Pointer to &struct resource whose addresses to are + * be set + * @res: Pointer to &struct dma_resource from which to get addresses. + * + * Returns true on success, false on failure. + */ +static __init bool set_resource_addresses(struct resource *plat_res, + const struct dma_resource *dma_res) +{ + if (platform_resource_override(plat_res, dma_res)) + return true; + + if (dma_res->start != 0) { + /* Have a statically defined address */ + plat_res->start = dma_to_phys(dma_res->start); + plat_res->end = dma_to_phys(dma_res->end); + + /* We've already warned about these */ + if (plat_res->start >= HIGHMEM_START) + return false; + } else { + void *virt_start; + size_t size; + + /* Need to allocation an address dynamically */ + + size = dma_res->end; + virt_start = kmalloc(size, GFP_KERNEL); + if (virt_start == NULL) { + pr_err("Unable to allocate memory for %s\n", + dma_res->name); + return false; + } + plat_res->start = virt_to_phys(virt_start); + plat_res->end = plat_res->start + size; + } + + return true; +} + +/** + * plat_reserve_resource_list - reserve a list of dma_resources + * @n: Number of &dma_resources to reserve + * @dma_resources: Pointer to the list of &struct dma_resource items + * + * Adds the list of &dma_resources to the ram_painting. This changes + * color from physmem_ram so that the memory areas won't be given to + * the boot memory allocator. Since this is called before any memory + * allocator is initialized, it can't allocate memory. + */ +void __init resource_reserve_static_prealloc(size_t n, + const struct dma_resource *dma_resources) +{ + int i; + + for (i = 0; i < n; i++) { + const struct dma_resource *dma_res; + struct painting_desc desc; + + dma_res = &dma_resources[i]; + + /* Skip anything with a dynamically-assigned address */ + if (dma_res->start == 0) + continue; + + desc.p = dma_to_phys(dma_res->start); + desc.q = dma_to_phys(dma_res->end); + +#ifndef CONFIG_HIGHMEM + if (desc.p >= HIGHMEM_START) { + pr_warn("No highmem--skipping reservation at %0*x " + "for %s\n", + 2 * sizeof(dma_res->start), dma_res->start, + dma_res->name); + continue; + } +#endif + desc.color = dma_res->name; + mem_painting_add(&ram_painting, &desc); + } +} + +/** + * resource_add_memory_region - add non-preallocated ram + */ +void __init resource_add_memory_regions() +{ + struct painting_area *area; + + painting_for_each_area(area, &ram_painting) { + struct painting_desc *desc; + + desc = &area->desc; + add_memory_region(desc->p, desc->q - desc->p + 1, + (desc->color == physmem_ram) ? BOOT_MEM_RAM : + BOOT_MEM_RESERVED); + } +} + +/* + * init_one_resource - set up resources for one preallocation + * @plat_res: Pointer to &struct resource that we be set up + * @dma_res: Pointer to &struct dma_resource holding the data + * + * On success, returns the number of bytes in the resources. Otherwise, + * returns zero. + */ +int __init init_one_resource(struct resource *plat_res, + const struct dma_resource *dma_res) +{ + struct resource *root_res; + size_t size; + int conflict; + + if (platform_lookup_resource_entry(dma_res->name) != NULL) { + pr_err("resource %s has already been allocated\n", + dma_res->name); + return 0; + } + + if (!set_resource_addresses(plat_res, dma_res)) + return 0; + + plat_res->name = kstrdup(dma_res->name, GFP_KERNEL); + plat_res->flags = dma_res->flags; + size = (plat_res->end - plat_res->start + 1); + + root_res = lookup_root_resource(plat_res->start, size); + + /* If there is no highmem extent root_res_p might be NULL */ + if (root_res) + conflict = request_resource(root_res, plat_res); + else + conflict = -1; + + if (conflict) { + if (request_resource(&iomem_resource, plat_res) != 0) { + pr_err("PTV resource request conflict " + "%s: 0x%x-0x%x\n", + plat_res->name, + plat_res->start, + plat_res->end); + plat_res->start = 0; + plat_res->end = 0; + } + return 0; + } + + plat_res->flags |= IORESOURCE_BUSY; + pr_info("Reserved resource at 0x%0*x for %s (%u bytes)\n", + 2 * sizeof(plat_res->start), plat_res->start, + plat_res->name, size); + return size; +} + +/** + * resource_request_prealloc - reserve resources for a list of preallocs + * @n: Number of resources to request + * @dma_resources: Pointer of DMA resources which are to be requested + * + * Called when we can allocate memory. Requests resources corresponding + * to both statically and dynamically assigned addreses. + * + * Recall that memory for resources at constant addresses was not passed + * to the boot memory allocator, so it is already reserved. Such memory still + * has still has no resource associated with it. We don't have addresses + * for memory whose address can be dynamically defined and will have to + * get them. + * + * Returns the number of bytes of resources successfully requested. + */ +size_t __init resource_request_prealloc(size_t n, + const struct dma_resource *dma_resources) +{ + struct resource *plat_resources; + size_t alloc_size; + size_t total; + int i; + + if (n == 0) + return 0; + + /* Allocate an array for the result */ + alloc_size = sizeof(*plat_resources) * n; + plat_resources = kmalloc(alloc_size, GFP_KERNEL | __GFP_ZERO); + + if (plat_resources == NULL) { + pr_err("could not allocate %d bytes for platform resource " + "structs\n", alloc_size); + return 0; + } + + total = 0; + + /* Populate the array */ + for (i = 0; i < n; i++) { + const struct dma_resource *dma_res; + struct resource *plat_res; + size_t size; + + dma_res = &dma_resources[i]; + plat_res = &plat_resources[i]; + + size = init_one_resource(plat_res, dma_res); + if (size > 0) + total += size; + } + + return total; +} + +/** + * platform_lookup_resource - provides start and end physical addresses + * for preallocated and reserved resources for drivers. + * + * @name: pointer to string containing name of resource + * @bres_p: pointer to callers struct that addrs are copied to + * Returns 0 on success, a negative errno value on failure + * + */ +int platform_lookup_resource(const char *name, struct bus_resource *bres_p) +{ + struct resource *p; + + p = platform_lookup_resource_entry(name); + + if (p == NULL) + return -ENODEV; + + bres_p->start = p->start; + bres_p->end = p->end; + return 0; +} +EXPORT_SYMBOL(platform_lookup_resource); + +/** + * platform_release_memory - release pre-allocated memory + * @ptr: pointer to memory to release + * @size: size of resource + * @baddr: Bus address of memory to release + * @size: size of resource, in bytes + * + * This must only be called for memory allocated or reserved via the boot + * or buddy memory allocators. + * Returns the number of bytes actually released. This must only be called + * for memory allocated or reserved via the boot memory allocator. + */ +unsigned long platform_release_memory(unsigned long baddr, int size) +{ + unsigned long paddr = dma_to_phys(baddr); + unsigned long pfn; + unsigned long end_pfn; + unsigned long pgs = 0; + + pr_info("Platform_release_memory:\n"); + pfn = PFN_UP(paddr); + end_pfn = PFN_DOWN(paddr + size); + + for (; pfn < end_pfn; pfn++) { + struct page *page = pfn_to_page(pfn); + + if (!pfn_valid(pfn)) { + pr_err("Trying to release invalid pfn:0x%lx\n", pfn); + BUG(); + break; + } + + if (!PageReserved(page)) { + pr_err("Trying to release page that is not" + " currently \"reserved\":0x%lx\n", pfn); + BUG(); + break; + } + + ClearPageReserved(page); + init_page_count(page); + __free_page(page); + + totalram_pages++; + num_physpages++; + pgs++; + } + + return pgs << PAGE_SHIFT; +} +EXPORT_SYMBOL(platform_release_memory); diff --git a/arch/mips/powertv/asic/prealloc.h b/arch/mips/powertv/asic/prealloc.h deleted file mode 100644 index 8e682df..0000000 --- a/arch/mips/powertv/asic/prealloc.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Definitions for memory preallocations - * - * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. - * - * This program 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 2 of the License, or - * (at your option) any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _ARCH_MIPS_POWERTV_ASIC_PREALLOC_H -#define _ARCH_MIPS_POWERTV_ASIC_PREALLOC_H - -#define KIBIBYTE(n) ((n) * 1024) /* Number of kibibytes */ -#define MEBIBYTE(n) ((n) * KIBIBYTE(1024)) /* Number of mebibytes */ - -/* "struct resource" array element definition */ -#define PREALLOC(NAME, START, END, FLAGS) { \ - .name = (NAME), \ - .start = (START), \ - .end = (END), \ - .flags = (FLAGS) \ - }, - -/* Individual resources in the preallocated resource arrays are defined using - * macros. These macros are conditionally defined based on their - * corresponding kernel configuration flag: - * - CONFIG_PREALLOC_NORMAL: preallocate resources for a normal settop box - * - CONFIG_PREALLOC_TFTP: preallocate the TFTP download resource - * - CONFIG_PREALLOC_DOCSIS: preallocate the DOCSIS resource - * - CONFIG_PREALLOC_PMEM: reserve space for persistent memory - */ -#ifdef CONFIG_PREALLOC_NORMAL -#define PREALLOC_NORMAL(name, start, end, flags) \ - PREALLOC(name, start, end, flags) -#else -#define PREALLOC_NORMAL(name, start, end, flags) -#endif - -#ifdef CONFIG_PREALLOC_TFTP -#define PREALLOC_TFTP(name, start, end, flags) \ - PREALLOC(name, start, end, flags) -#else -#define PREALLOC_TFTP(name, start, end, flags) -#endif - -#ifdef CONFIG_PREALLOC_DOCSIS -#define PREALLOC_DOCSIS(name, start, end, flags) \ - PREALLOC(name, start, end, flags) -#else -#define PREALLOC_DOCSIS(name, start, end, flags) -#endif - -#ifdef CONFIG_PREALLOC_PMEM -#define PREALLOC_PMEM(name, start, end, flags) \ - PREALLOC(name, start, end, flags) -#else -#define PREALLOC_PMEM(name, start, end, flags) -#endif -#endif diff --git a/arch/mips/powertv/init.c b/arch/mips/powertv/init.c index 0aac039..6ee3145 100644 --- a/arch/mips/powertv/init.c +++ b/arch/mips/powertv/init.c @@ -3,7 +3,7 @@ * All rights reserved. * Authors: Carsten Langgaard <carstenl@xxxxxxxx> * Maciej W. Rozycki <macro@xxxxxxxx> - * Portions copyright (C) 2009 Cisco Systems, Inc. + * Portions copyright (C) 2009-2010 Cisco Systems, Inc. * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as @@ -122,7 +122,7 @@ void __init prom_init(void) strlcat(arcs_cmdline, prom_argv, COMMAND_LINE_SIZE); } - configure_platform(); + powertv_platform_init(); prom_meminit(); #ifndef CONFIG_BOOTLOADER_DRIVER diff --git a/arch/mips/powertv/ioremap.c b/arch/mips/powertv/ioremap.c index a77c6f6..22a5c29 100644 --- a/arch/mips/powertv/ioremap.c +++ b/arch/mips/powertv/ioremap.c @@ -4,6 +4,7 @@ * Support for mapping between dma_addr_t values a phys_addr_t values. * * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009-2010 Cisco Sysems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -80,8 +81,17 @@ static void setup_dma_to_phys(dma_addr_t dma, phys_addr_t delta, dma_addr_t s) first_idx = first >> IOR_LSBITS; /* Convert to indices */ last_idx = last >> IOR_LSBITS; - for (dma_idx = first_idx; dma_idx <= last_idx; dma_idx++) - _ior_dma_to_phys[dma_idx].offset = delta >> IOR_DMA_SHIFT; + for (dma_idx = first_idx; dma_idx <= last_idx; dma_idx++) { + dma_addr_t offset; + offset = delta >> IOR_DMA_SHIFT; + + if (_ior_dma_to_phys[dma_idx].offset != 0 && + _ior_dma_to_phys[dma_idx].offset != offset) + panic("Memory remapped: DMA %x physical %x size %d\n", + dma, dma + delta, s); + + _ior_dma_to_phys[dma_idx].offset = offset; + } } /** @@ -104,11 +114,21 @@ static void setup_phys_to_dma(phys_addr_t phys, dma_addr_t delta, phys_addr_t s) */ first = phys & ~IOR_PHYS_GRAIN_MASK; last = (phys + s - 1) & ~IOR_PHYS_GRAIN_MASK; - first_idx = first >> IOR_LSBITS; /* Convert to indices */ + first_idx = first >> IOR_LSBITS; /* Convert to indices */ last_idx = last >> IOR_LSBITS; - for (phys_idx = first_idx; phys_idx <= last_idx; phys_idx++) - _ior_phys_to_dma[phys_idx].offset = delta >> IOR_PHYS_SHIFT; + for (phys_idx = first_idx; phys_idx <= last_idx; phys_idx++) { + dma_addr_t offset; + + offset = delta >> IOR_PHYS_SHIFT; + + if (_ior_phys_to_dma[phys_idx].offset != 0 && + _ior_phys_to_dma[phys_idx].offset != offset) + panic("Memory remapped: physical %x DMA %x size %d\n", + phys, phys + delta, s); + + _ior_phys_to_dma[phys_idx].offset = offset; + } } /** @@ -120,17 +140,11 @@ static void setup_phys_to_dma(phys_addr_t phys, dma_addr_t delta, phys_addr_t s) * NOTE: It might be obvious, but the assumption is that all @size bytes have * the same offset between the physical address and the DMA address. */ -void ioremap_add_map(phys_addr_t phys, phys_addr_t dma, phys_addr_t size) +void ioremap_add_map(phys_addr_t phys, dma_addr_t dma, size_t size) { if (size == 0) return; - if ((dma & IOR_DMA_GRAIN_MASK) != 0 || - (phys & IOR_PHYS_GRAIN_MASK) != 0 || - (size & IOR_PHYS_GRAIN_MASK) != 0) - pr_crit("Memory allocation must be in chunks of 0x%x bytes\n", - IOR_PHYS_GRAIN); - setup_dma_to_phys(dma, phys - dma, size); setup_phys_to_dma(phys, dma - phys, size); } diff --git a/arch/mips/powertv/memory.c b/arch/mips/powertv/memory.c index c463cd3..6b0c10e 100644 --- a/arch/mips/powertv/memory.c +++ b/arch/mips/powertv/memory.c @@ -1,7 +1,7 @@ /* * Carsten Langgaard, carstenl@xxxxxxxx * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * Portions copyright (C) 2009 Cisco Systems, Inc. + * Portions copyright (C) 2009-2010 Cisco Systems, Inc. * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as @@ -25,28 +25,38 @@ #include <linux/pfn.h> #include <linux/string.h> -#include <asm/bootinfo.h> #include <asm/page.h> #include <asm/sections.h> +#include <asm/setup.h> +#include <asm/bootinfo.h> #include <asm/mips-boards/prom.h> #include <asm/mach-powertv/asic.h> #include <asm/mach-powertv/ioremap.h> +#include <asm/mach-powertv/powertv-prealloc.h> #include "init.h" /* Memory constants */ #define KIBIBYTE(n) ((n) * 1024) /* Number of kibibytes */ #define MEBIBYTE(n) ((n) * KIBIBYTE(1024)) /* Number of mebibytes */ +#define GIBIBYTE(n) ((n) * MEBIBYTE(1024)) /* Number of mebibytes */ #define DEFAULT_MEMSIZE MEBIBYTE(128) /* If no memsize provided */ #define BLDR_SIZE KIBIBYTE(256) /* Memory reserved for bldr */ #define RV_SIZE MEBIBYTE(4) /* Size of reset vector */ -#define LOW_MEM_END 0x20000000 /* Highest low memory address */ -#define BLDR_ALIAS 0x10000000 /* Bootloader address */ -#define RV_PHYS 0x1fc00000 /* Reset vector address */ -#define LOW_RAM_END RV_PHYS /* End of real RAM in low mem */ +/* Predefined physical memory types */ +const char physmem_bootloader[] = "bootloader"; +const char physmem_buddy_high[] = "buddy allocator (high)"; +const char physmem_buddy_low[] = "buddy allocator (low)"; +const char physmem_mem_map[] = "page descriptors"; +const char physmem_ram[] = "RAM"; +const char physmem_reserved[] = "reserved"; +const char physmem_reset_vector[] = "reset vector"; +const char physmem_rom_data[] = "ROM data"; +const char physmem_unknown[] = "unknown type"; +const char physmem_zero_page[] = "zero page"; /* * Very low-level conversion from processor physical address to device @@ -57,30 +67,8 @@ unsigned long ptv_memsize; /* - * struct low_mem_reserved - Items in low memmory that are reserved - * @start: Physical address of item - * @size: Size, in bytes, of this item - * @is_aliased: True if this is RAM aliased from another location. If false, - * it is something other than aliased RAM and the RAM in the - * unaliased address is still visible outside of low memory. - */ -struct low_mem_reserved { - phys_addr_t start; - phys_addr_t size; - bool is_aliased; -}; - -/* - * Must be in ascending address order - */ -struct low_mem_reserved low_mem_reserved[] = { - {BLDR_ALIAS, BLDR_SIZE, true}, /* Bootloader RAM */ - {RV_PHYS, RV_SIZE, false}, /* Reset vector */ -}; - -/* * struct mem_layout - layout of a piece of the system RAM - * @phys: Physical address of the start of this piece of RAM. This is the + * @dma: Physical address of the start of this piece of RAM. This is the * address at which both the processor and I/O devices see the * RAM. * @alias: Alias of this piece of memory in order to make it appear in @@ -89,9 +77,9 @@ struct low_mem_reserved low_mem_reserved[] = { * @size: Size, in bytes, of this piece of RAM */ struct mem_layout { - phys_addr_t phys; + dma_addr_t dma; phys_addr_t alias; - phys_addr_t size; + size_t size; }; /* @@ -106,27 +94,32 @@ struct mem_layout_list { struct mem_layout *layout; }; -static struct mem_layout f1500_layout[] = { +static struct mem_layout f1500_layout[] __initdata = { {0x20000000, 0x10000000, MEBIBYTE(256)}, }; -static struct mem_layout f4500_layout[] = { +static struct mem_layout f4500_layout[] __initdata = { {0x40000000, 0x10000000, MEBIBYTE(256)}, {0x20000000, 0x20000000, MEBIBYTE(32)}, }; -static struct mem_layout f8500_layout[] = { +static struct mem_layout f8500_layout[] __initdata = { {0x40000000, 0x10000000, MEBIBYTE(256)}, {0x20000000, 0x20000000, MEBIBYTE(32)}, {0x30000000, 0x30000000, MEBIBYTE(32)}, }; -static struct mem_layout fx600_layout[] = { +static struct mem_layout fx600_layout[] __initdata = { {0x20000000, 0x10000000, MEBIBYTE(256)}, {0x60000000, 0x60000000, MEBIBYTE(128)}, }; -static struct mem_layout_list layout_list[] = { +static struct mem_layout fx700_layout[] __initdata = { + {0x20000000, 0x10000000, GIBIBYTE(1)}, + {0x60000000, 0x60000000, GIBIBYTE(1)}, +}; + +static struct mem_layout_list layout_list[] __initdata = { {FAMILY_1500, ARRAY_SIZE(f1500_layout), f1500_layout}, {FAMILY_1500VZE, ARRAY_SIZE(f1500_layout), f1500_layout}, {FAMILY_1500VZF, ARRAY_SIZE(f1500_layout), f1500_layout}, @@ -137,26 +130,15 @@ static struct mem_layout_list layout_list[] = { {FAMILY_4600VZA, ARRAY_SIZE(fx600_layout), fx600_layout}, {FAMILY_8600, ARRAY_SIZE(fx600_layout), fx600_layout}, {FAMILY_8600VZB, ARRAY_SIZE(fx600_layout), fx600_layout}, + {FAMILY_8700, ARRAY_SIZE(fx600_layout), fx700_layout}, }; /* If we can't determine the layout, use this */ -static struct mem_layout default_layout[] = { +static struct mem_layout default_layout[] __initdata = { {0x20000000, 0x10000000, MEBIBYTE(128)}, }; /** - * register_non_ram - register low memory not available for RAM usage - */ -static __init void register_non_ram(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(low_mem_reserved); i++) - add_memory_region(low_mem_reserved[i].start, - low_mem_reserved[i].size, BOOT_MEM_RESERVED); -} - -/** * get_memsize - get the size of memory as a single bank */ static phys_addr_t get_memsize(void) @@ -201,91 +183,7 @@ static phys_addr_t get_memsize(void) } /** - * register_low_ram - register an aliased section of RAM - * @p: Alias address of memory - * @n: Number of bytes in this section of memory - * - * Returns the number of bytes registered - * - */ -static __init phys_addr_t register_low_ram(phys_addr_t p, phys_addr_t n) -{ - phys_addr_t s; - int i; - phys_addr_t orig_n; - - orig_n = n; - - BUG_ON(p + n > RV_PHYS); - - for (i = 0; n != 0 && i < ARRAY_SIZE(low_mem_reserved); i++) { - phys_addr_t start; - phys_addr_t size; - - start = low_mem_reserved[i].start; - size = low_mem_reserved[i].size; - - /* Handle memory before this low memory section */ - if (p < start) { - phys_addr_t s; - s = min(n, start - p); - add_memory_region(p, s, BOOT_MEM_RAM); - p += s; - n -= s; - } - - /* Handle the low memory section itself. If it's aliased, - * we reduce the number of byes left, but if not, the RAM - * is available elsewhere and we don't reduce the number of - * bytes remaining. */ - if (p == start) { - if (low_mem_reserved[i].is_aliased) { - s = min(n, size); - n -= s; - p += s; - } else - p += n; - } - } - - return orig_n - n; -} - -/* - * register_ram - register real RAM - * @p: Address of memory as seen by devices - * @alias: If the memory is seen at an additional address by the processor, - * this will be the address, otherwise it is the same as @p. - * @n: Number of bytes in this section of memory - */ -static __init void register_ram(phys_addr_t p, phys_addr_t alias, - phys_addr_t n) -{ - /* - * If some or all of this memory has an alias, break it into the - * aliased and non-aliased portion. - */ - if (p != alias) { - phys_addr_t alias_size; - phys_addr_t registered; - - alias_size = min(n, LOW_RAM_END - alias); - registered = register_low_ram(alias, alias_size); - ioremap_add_map(alias, p, n); - n -= registered; - p += registered; - } - -#ifdef CONFIG_HIGHMEM - if (n != 0) { - add_memory_region(p, n, BOOT_MEM_RAM); - ioremap_add_map(p, p, n); - } -#endif -} - -/** - * register_address_space - register things in the address space + * register_raw_ram - register things in the address space * @memsize: Number of bytes of RAM installed * * Takes the given number of bytes of RAM and registers as many of the regions, @@ -294,19 +192,13 @@ static __init void register_ram(phys_addr_t p, phys_addr_t alias, * is 384 MiB, it will register the first region with 256 MiB and the second * with 128 MiB. */ -static __init void register_address_space(phys_addr_t memsize) +static void __init register_raw_ram(phys_addr_t memsize) { - int i; - phys_addr_t size; - size_t n; struct mem_layout *layout; + int num_layouts; enum family_type family; - - /* - * Register all of the things that aren't available to the kernel as - * memory. - */ - register_non_ram(); + int res; + int i; /* Find the appropriate memory description */ family = platform_get_family(); @@ -317,16 +209,27 @@ static __init void register_address_space(phys_addr_t memsize) } if (i == ARRAY_SIZE(layout_list)) { - n = ARRAY_SIZE(default_layout); + num_layouts = ARRAY_SIZE(default_layout); layout = default_layout; } else { - n = layout_list[i].n; + num_layouts = layout_list[i].n; layout = layout_list[i].layout; } - for (i = 0; memsize != 0 && i < n; i++) { + /* Add all possible RAM */ + for (i = 0; memsize != 0 && i < num_layouts; i++) { + dma_addr_t dma; + phys_addr_t alias; + size_t size; + + dma = layout[i].dma; + alias = layout[i].alias; size = min(memsize, layout[i].size); - register_ram(layout[i].phys, layout[i].alias, size); + + ioremap_add_map(alias, dma, size); + res = resource_add_ram(alias, alias + size - 1); + if (res != 0) + break; memsize -= size; } } @@ -334,7 +237,9 @@ static __init void register_address_space(phys_addr_t memsize) void __init prom_meminit(void) { ptv_memsize = get_memsize(); - register_address_space(ptv_memsize); + register_raw_ram(ptv_memsize); + register_available_ram(); + } void __init prom_free_prom_memory(void) diff --git a/arch/mips/powertv/powertv_setup.c b/arch/mips/powertv/powertv_setup.c index af2cae0..f430156 100644 --- a/arch/mips/powertv/powertv_setup.c +++ b/arch/mips/powertv/powertv_setup.c @@ -1,7 +1,7 @@ /* * Carsten Langgaard, carstenl@xxxxxxxx * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * Portions copyright (C) 2009 Cisco Systems, Inc. + * Portions copyright (C) 2009-2010 Cisco Systems, Inc. * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as @@ -36,6 +36,8 @@ #include <asm/asm.h> #include <asm/traps.h> #include <asm/asm-offsets.h> +#include <asm/mach-powertv/asic.h> +#include <asm/mach-powertv/prealloc.h> #include "reset.h" #define VAL(n) STR(n)