linux-stable/arch/mips/sgi-ip27/ip27-memory.c

435 lines
9.8 KiB
C
Raw Normal View History

/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2000, 05 by Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2000 by Silicon Graphics, Inc.
* Copyright (C) 2004 by Christoph Hellwig
*
* On SGI IP27 the ARC memory configuration data is completely bogus but
* alternate easier to use mechanisms are available.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
MIPS: Audit and remove any unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. In the case of some code where it is modular, we can extend that to also include files that are building basic support functionality but not related to loading or registering the final module; such files also have no need whatsoever for module.h The advantage in removing such instances is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h might have been the implicit source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each instance for the presence of either and replace/add as needed. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. Build coverage of all the mips defconfigs revealed the module.h header was masking a couple of implicit include instances, so we add the appropriate headers there. Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: David Daney <david.daney@cavium.com> Cc: John Crispin <john@phrozen.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: "Steven J. Hill" <steven.hill@cavium.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15131/ [james.hogan@imgtec.com: Preserve sort order where it already exists] Signed-off-by: James Hogan <james.hogan@imgtec.com>
2017-01-29 02:05:57 +00:00
#include <linux/export.h>
#include <linux/nodemask.h>
#include <linux/swap.h>
#include <linux/pfn.h>
#include <linux/highmem.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/sections.h>
#include <asm/sn/arch.h>
#include <asm/sn/agent.h>
#include <asm/sn/klconfig.h>
#include "ip27-common.h"
#define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT)
#define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT)
struct node_data *__node_data[MAX_NUMNODES];
EXPORT_SYMBOL(__node_data);
static u64 gen_region_mask(void)
{
int region_shift;
u64 region_mask;
nasid_t nasid;
region_shift = get_region_shift();
region_mask = 0;
for_each_online_node(nasid)
region_mask |= BIT_ULL(nasid >> region_shift);
return region_mask;
}
#define rou_rflag rou_flags
static int router_distance;
static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
{
klrou_t *router;
lboard_t *brd;
int port;
if (router_a->rou_rflag == 1)
return;
if (depth >= router_distance)
return;
router_a->rou_rflag = 1;
for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
if (router_a->rou_port[port].port_nasid == INVALID_NASID)
continue;
brd = (lboard_t *)NODE_OFFSET_TO_K0(
router_a->rou_port[port].port_nasid,
router_a->rou_port[port].port_offset);
if (brd->brd_type == KLTYPE_ROUTER) {
router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
if (router == router_b) {
if (depth < router_distance)
router_distance = depth;
}
else
router_recurse(router, router_b, depth + 1);
}
}
router_a->rou_rflag = 0;
}
unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
EXPORT_SYMBOL(__node_distances);
static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
{
klrou_t *router, *router_a = NULL, *router_b = NULL;
lboard_t *brd, *dest_brd;
nasid_t nasid;
int port;
/* Figure out which routers nodes in question are connected to */
for_each_online_node(nasid) {
brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
KLTYPE_ROUTER);
if (!brd)
continue;
do {
if (brd->brd_flags & DUPLICATE_BOARD)
continue;
router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
router->rou_rflag = 0;
for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
if (router->rou_port[port].port_nasid == INVALID_NASID)
continue;
dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
router->rou_port[port].port_nasid,
router->rou_port[port].port_offset);
if (dest_brd->brd_type == KLTYPE_IP27) {
if (dest_brd->brd_nasid == nasid_a)
router_a = router;
if (dest_brd->brd_nasid == nasid_b)
router_b = router;
}
}
} while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
}
if (nasid_a == nasid_b)
return LOCAL_DISTANCE;
if (router_a == router_b)
return LOCAL_DISTANCE + 1;
if (router_a == NULL) {
pr_info("node_distance: router_a NULL\n");
return 255;
}
if (router_b == NULL) {
pr_info("node_distance: router_b NULL\n");
return 255;
}
router_distance = 100;
router_recurse(router_a, router_b, 2);
return LOCAL_DISTANCE + router_distance;
}
static void __init init_topology_matrix(void)
{
nasid_t row, col;
for (row = 0; row < MAX_NUMNODES; row++)
for (col = 0; col < MAX_NUMNODES; col++)
__node_distances[row][col] = -1;
for_each_online_node(row) {
for_each_online_node(col) {
__node_distances[row][col] =
compute_node_distance(row, col);
}
}
}
static void __init dump_topology(void)
{
nasid_t nasid;
lboard_t *brd, *dest_brd;
int port;
int router_num = 0;
klrou_t *router;
nasid_t row, col;
pr_info("************** Topology ********************\n");
pr_info(" ");
for_each_online_node(col)
pr_cont("%02d ", col);
pr_cont("\n");
for_each_online_node(row) {
pr_info("%02d ", row);
for_each_online_node(col)
pr_cont("%2d ", node_distance(row, col));
pr_cont("\n");
}
for_each_online_node(nasid) {
brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
KLTYPE_ROUTER);
if (!brd)
continue;
do {
if (brd->brd_flags & DUPLICATE_BOARD)
continue;
pr_cont("Router %d:", router_num);
router_num++;
router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
if (router->rou_port[port].port_nasid == INVALID_NASID)
continue;
dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
router->rou_port[port].port_nasid,
router->rou_port[port].port_offset);
if (dest_brd->brd_type == KLTYPE_IP27)
pr_cont(" %d", dest_brd->brd_nasid);
if (dest_brd->brd_type == KLTYPE_ROUTER)
pr_cont(" r");
}
pr_cont("\n");
} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
}
}
static unsigned long __init slot_getbasepfn(nasid_t nasid, int slot)
{
return ((unsigned long)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT);
}
static unsigned long __init slot_psize_compute(nasid_t nasid, int slot)
{
lboard_t *brd;
klmembnk_t *banks;
unsigned long size;
/* Find the node board */
brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
if (!brd)
return 0;
/* Get the memory bank structure */
banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK);
if (!banks)
return 0;
/* Size in _Megabytes_ */
size = (unsigned long)banks->membnk_bnksz[slot/4];
/* hack for 128 dimm banks */
if (size <= 128) {
if (slot % 4 == 0) {
size <<= 20; /* size in bytes */
return size >> PAGE_SHIFT;
} else
return 0;
} else {
size /= 4;
size <<= 20;
return size >> PAGE_SHIFT;
}
}
static void __init mlreset(void)
{
u64 region_mask;
nasid_t nasid;
master_nasid = get_nasid();
/*
* Probe for all CPUs - this creates the cpumask and sets up the
* mapping tables. We need to do this as early as possible.
*/
#ifdef CONFIG_SMP
cpu_node_probe();
#endif
init_topology_matrix();
dump_topology();
region_mask = gen_region_mask();
setup_replication_mask();
/*
* Set all nodes' calias sizes to 8k
*/
for_each_online_node(nasid) {
/*
* Always have node 0 in the region mask, otherwise
* CALIAS accesses get exceptions since the hub
* thinks it is a node 0 address.
*/
REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
#ifdef LATER
/*
* Set up all hubs to have a big window pointing at
* widget 0. Memory mode, widget 0, offset 0
*/
REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
(0 << IIO_ITTE_WIDGET_SHIFT)));
#endif
}
}
static void __init szmem(void)
{
unsigned long slot_psize, slot0sz = 0, nodebytes; /* Hack to detect problem configs */
int slot;
nasid_t node;
for_each_online_node(node) {
nodebytes = 0;
for (slot = 0; slot < MAX_MEM_SLOTS; slot++) {
slot_psize = slot_psize_compute(node, slot);
if (slot == 0)
slot0sz = slot_psize;
/*
* We need to refine the hack when we have replicated
* kernel text.
*/
nodebytes += (1LL << SLOT_SHIFT);
if (!slot_psize)
continue;
if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
(slot0sz << PAGE_SHIFT)) {
pr_info("Ignoring slot %d onwards on node %d\n",
slot, node);
slot = MAX_MEM_SLOTS;
continue;
}
memblock_add_node(PFN_PHYS(slot_getbasepfn(node, slot)),
memblock: allow to specify flags with memblock_add_node() We want to specify flags when hotplugging memory. Let's prepare to pass flags to memblock_add_node() by adjusting all existing users. Note that when hotplugging memory the system is already up and running and we might have concurrent memblock users: for example, while we're hotplugging memory, kexec_file code might search for suitable memory regions to place kexec images. It's important to add the memory directly to memblock via a single call with the right flags, instead of adding the memory first and apply flags later: otherwise, concurrent memblock users might temporarily stumble over memblocks with wrong flags, which will be important in a follow-up patch that introduces a new flag to properly handle add_memory_driver_managed(). Link: https://lkml.kernel.org/r/20211004093605.5830-4-david@redhat.com Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Acked-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: David Hildenbrand <david@redhat.com> Acked-by: Shahab Vahedi <shahab@synopsys.com> [arch/arc] Reviewed-by: Mike Rapoport <rppt@linux.ibm.com> Cc: "Aneesh Kumar K . V" <aneesh.kumar@linux.ibm.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Christian Borntraeger <borntraeger@de.ibm.com> Cc: Eric Biederman <ebiederm@xmission.com> Cc: Huacai Chen <chenhuacai@kernel.org> Cc: Jianyong Wu <Jianyong.Wu@arm.com> Cc: Jiaxun Yang <jiaxun.yang@flygoat.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Oscar Salvador <osalvador@suse.de> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Cc: Vasily Gorbik <gor@linux.ibm.com> Cc: Vineet Gupta <vgupta@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2021-11-05 20:44:49 +00:00
PFN_PHYS(slot_psize), node,
MEMBLOCK_NONE);
}
}
}
static void __init node_mem_init(nasid_t node)
{
unsigned long slot_firstpfn = slot_getbasepfn(node, 0);
unsigned long slot_freepfn = node_getfirstfree(node);
unsigned long start_pfn, end_pfn;
get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
/*
* Allocate the node data structures on the node first.
*/
__node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
memset(__node_data[node], 0, PAGE_SIZE);
NODE_DATA(node)->node_start_pfn = start_pfn;
NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
cpumask_clear(&hub_data(node)->h_cpus);
slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
sizeof(struct hub_data));
memblock_reserve(slot_firstpfn << PAGE_SHIFT,
((slot_freepfn - slot_firstpfn) << PAGE_SHIFT));
}
/*
* A node with nothing. We use it to avoid any special casing in
* cpumask_of_node
*/
static struct node_data null_node = {
.hub = {
.h_cpus = CPU_MASK_NONE
}
};
/*
* Currently, the intranode memory hole support assumes that each slot
* contains at least 32 MBytes of memory. We assume all bootmem data
* fits on the first slot.
*/
void __init prom_meminit(void)
{
nasid_t node;
mlreset();
szmem();
max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
for (node = 0; node < MAX_NUMNODES; node++) {
if (node_online(node)) {
node_mem_init(node);
continue;
}
__node_data[node] = &null_node;
}
}
extern void setup_zero_pages(void);
void __init paging_init(void)
{
unsigned long zones_size[MAX_NR_ZONES] = {0, };
pagetable_init();
zones_size[ZONE_NORMAL] = max_low_pfn;
mm: use free_area_init() instead of free_area_init_nodes() free_area_init() has effectively became a wrapper for free_area_init_nodes() and there is no point of keeping it. Still free_area_init() name is shorter and more general as it does not imply necessity to initialize multiple nodes. Rename free_area_init_nodes() to free_area_init(), update the callers and drop old version of free_area_init(). Signed-off-by: Mike Rapoport <rppt@linux.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Tested-by: Hoan Tran <hoan@os.amperecomputing.com> [arm64] Reviewed-by: Baoquan He <bhe@redhat.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Brian Cain <bcain@codeaurora.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Greentime Hu <green.hu@gmail.com> Cc: Greg Ungerer <gerg@linux-m68k.org> Cc: Guan Xuetao <gxt@pku.edu.cn> Cc: Guo Ren <guoren@kernel.org> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Helge Deller <deller@gmx.de> Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Ley Foon Tan <ley.foon.tan@intel.com> Cc: Mark Salter <msalter@redhat.com> Cc: Matt Turner <mattst88@gmail.com> Cc: Max Filippov <jcmvbkbc@gmail.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Michal Hocko <mhocko@kernel.org> Cc: Michal Simek <monstr@monstr.eu> Cc: Nick Hu <nickhu@andestech.com> Cc: Paul Walmsley <paul.walmsley@sifive.com> Cc: Richard Weinberger <richard@nod.at> Cc: Rich Felker <dalias@libc.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Stafford Horne <shorne@gmail.com> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Cc: Tony Luck <tony.luck@intel.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Link: http://lkml.kernel.org/r/20200412194859.12663-6-rppt@kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-06-03 22:57:10 +00:00
free_area_init(zones_size);
}
void __init mem_init(void)
{
high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
memblock: rename free_all_bootmem to memblock_free_all The conversion is done using sed -i 's@free_all_bootmem@memblock_free_all@' \ $(git grep -l free_all_bootmem) Link: http://lkml.kernel.org/r/1536927045-23536-26-git-send-email-rppt@linux.vnet.ibm.com Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com> Acked-by: Michal Hocko <mhocko@suse.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chris Zankel <chris@zankel.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Greentime Hu <green.hu@gmail.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Guan Xuetao <gxt@pku.edu.cn> Cc: Ingo Molnar <mingo@redhat.com> Cc: "James E.J. Bottomley" <jejb@parisc-linux.org> Cc: Jonas Bonn <jonas@southpole.se> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Ley Foon Tan <lftan@altera.com> Cc: Mark Salter <msalter@redhat.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Matt Turner <mattst88@gmail.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Michal Simek <monstr@monstr.eu> Cc: Palmer Dabbelt <palmer@sifive.com> Cc: Paul Burton <paul.burton@mips.com> Cc: Richard Kuo <rkuo@codeaurora.org> Cc: Richard Weinberger <richard@nod.at> Cc: Rich Felker <dalias@libc.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Serge Semin <fancer.lancer@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-30 22:09:30 +00:00
memblock_free_all();
setup_zero_pages(); /* This comes from node 0 */
}
pg_data_t * __init arch_alloc_nodedata(int nid)
{
return memblock_alloc(sizeof(pg_data_t), SMP_CACHE_BYTES);
}
void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
{
__node_data[nid] = (struct node_data *)pgdat;
}