Subject: Re: port-mips/31915: provide centralized wired_map logic
To: None <garrett_damore@tadpole.com>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-mips
Date: 10/27/2005 01:19:56
In article <20051025205402.7B93A63B8C2@narn.netbsd.org>
garrett_damore@tadpole.com wrote:

>  Here are the diffs.  Again, I've not conditionalized the inclusion of 
>  mips3_wired_map.c, but if folks feel strongly enough about it I can 
>  certainly do so.

IMO, currently only arc port uses wired map, so it might be better to
have some proper option (like options MIPS3_WIRED_MAP etc.).

>  Also, the ARC port could probably make use of my logic in 
>  mips3_wired_map.c, but I wanted to minimize change (and I don't have an 
>  ARC system to test against, anyway, so all I can do is verify the compile.)

I think the MI wired map function should also handle independent
(non-contiguous) PA ranges for TLB_LO0 and TLB_LO1.
arc port requires it to map PCI memory and I/O space at the early
bootstrap stage, and it could save wired TLB entries in other case.

I also have some more quick comments:

- VA region for wired map should be defined in machine dependent
  <machine/vmparam.h> and it should be managed by extent(9) etc.
- pagemask for wired maps should be defined in machine dependent headers,
  or maybe it should be passed from callers.

Currently I use the attached wired_map.[ch] for ews4800mips ports,
though it lacks some sanity checks and unmap (or remap) functions.

Maybe we should discuss more about APIs for these wired map functions.
---
Izumi Tsutsui


---
/*	$NetBSD$	*/

/*-
 * Copyright (C) 2005 Izumi Tsutsui.
 * Copyright (C) 2000 Shuichiro URATA.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/extent.h>

#include <uvm/uvm_extern.h>

#include <mips/pte.h>

#include <machine/locore.h>
#include <machine/vmparam.h>

#include <ews4800mips/ews4800mips/wired_map.h>

#define EWS4800MIPS_TLB_WIRED_ENTRIES	8	/* upper limit */

static int ews4800mips_enter_wired(vaddr_t va, paddr_t pa0, paddr_t pa1,
    uint32_t pg_size);

static struct wired_map_entry {
	paddr_t	pa0;
	paddr_t	pa1;
	vsize_t	size;
	vaddr_t	va;
} wired_map[EWS4800MIPS_TLB_WIRED_ENTRIES];

static int nwired;
static struct extent *wired_map_ex;
static long wired_map_ex_storage[EXTENT_FIXED_STORAGE_SIZE(8) / sizeof(long)];

void
ews4800mips_init_wired_map(void)
{

	nwired = 0;
	wired_map_ex = extent_create("wired_map",
	    VM_MIN_WIRED_MAP_ADDRESS, VM_MAX_WIRED_MAP_ADDRESS, M_DEVBUF,
	    (void *)wired_map_ex_storage, sizeof(wired_map_ex_storage),
	    EX_NOWAIT);
	if (wired_map_ex == NULL)
		panic("ews4800mips_init_wired_map: can't create extent");
}

static int
ews4800mips_enter_wired(vaddr_t va, paddr_t pa0, paddr_t pa1, uint32_t pg_size)
{
	struct tlb tlb;
	psize_t size;

	if (nwired >= EWS4800MIPS_TLB_WIRED_ENTRIES) {
#ifdef DIAGNOSTIC
		printf("ews4800mips_enter_wired: wired entry exausted.\n");
#endif
		return ENOMEM;
	}

	size = MIPS3_PG_SIZE_MASK_TO_SIZE(pg_size);
	va = (va + (size - 1)) & ~(size - 1);

	wired_map[nwired].va = va;
	wired_map[nwired].pa0 = pa0;
	wired_map[nwired].pa1 = pa1;
	wired_map[nwired].size = size;

	/* Allocate new wired entry */
	mips3_cp0_wired_write(MIPS3_TLB_WIRED_UPAGES + nwired + 1);

	/* Map to it */
	tlb.tlb_mask = pg_size;
	tlb.tlb_hi = mips3_vad_to_vpn(va);
	if (pa0 == 0)
		tlb.tlb_lo0 = MIPS3_PG_G;
	else
		tlb.tlb_lo0 = mips3_paddr_to_tlbpfn(pa0) | \
		    MIPS3_PG_IOPAGE(PMAP_CCA_FOR_PA(pa0));
	if (pa1 == 0)
		tlb.tlb_lo1 = MIPS3_PG_G;
	else
		tlb.tlb_lo1 = mips3_paddr_to_tlbpfn(pa1) | \
		    MIPS3_PG_IOPAGE(PMAP_CCA_FOR_PA(pa1));
	mips3_TLBWriteIndexedVPS(MIPS3_TLB_WIRED_UPAGES + nwired, &tlb);

	nwired++;

	return 0;
}

/* Allocate new wired entries */
int
ews4800mips_map_wired(vaddr_t va, paddr_t pa0, paddr_t pa1, uint32_t pg_size)
{
	psize_t size;
	int error;

	size = MIPS3_PG_SIZE_MASK_TO_SIZE(pg_size);
	va = (va + (size - 1)) & ~(size - 1);

	if (va < VM_MIN_WIRED_MAP_ADDRESS ||
	    va + size > VM_MAX_WIRED_MAP_ADDRESS) {
#ifdef DIAGNOSTIC
		printf("ews4800mips_enter_wired: invalid va range.\n");
#endif
		return EINVAL;
	}

	error = extent_alloc_region(wired_map_ex, va, size, EX_NOWAIT);
	if (error) {
#ifdef DIAGNOSTIC
		printf("ews4800mips_enter_wired: cannot allocate region.\n");
#endif
		return error;
	}

	error = ews4800mips_enter_wired(va, pa0, pa1, pg_size);

	return error;
}

vaddr_t
ews4800mips_map_wired_region(paddr_t pa, int size, uint32_t pg_mask)
{
	vaddr_t va, rva;
	vsize_t off;
	psize_t pg_size;
	int error;

	pg_size = MIPS3_PG_SIZE_MASK_TO_SIZE(pg_mask);
	off = pa & WIRED_ENTRY_OFFMASK(pg_size);
	pa &= ~(paddr_t)WIRED_ENTRY_OFFMASK(pg_size);
	size += off;

	if ((size + WIRED_ENTRY_SIZE(pg_size) - 1) / WIRED_ENTRY_SIZE(pg_size) >
	    EWS4800MIPS_TLB_WIRED_ENTRIES - nwired) {

#ifdef DIAGNOSTIC
		printf("ews4800mips_map_wired_region(0x%lx, 0x%lx)"
		    ": %d is not enough\n", pa + off, size - off,
		    EWS4800MIPS_TLB_WIRED_ENTRIES - nwired);
#endif
		return 0; /* free wired TLB is not enough */
	}

	error = extent_alloc(wired_map_ex, size, WIRED_ENTRY_SIZE(pg_size), 0,
	    EX_NOWAIT, &va);
	if (error) {
#ifdef DIAGNOSTIC
		printf("ews4800mips_map_wired_region: can't allocate region\n");
#endif
		return 0;
	}
	rva = va;

	while (size > 0) {
		ews4800mips_enter_wired(va, pa, pa + pg_size, pg_mask);
		pa += WIRED_ENTRY_SIZE(pg_size);
		va += WIRED_ENTRY_SIZE(pg_size);
		size -= WIRED_ENTRY_SIZE(pg_size);
	}

	return rva + off;
}
---

---
/*	$NetBSD$	*/

/*-
 * Copyright (C) 2005 Izumi Tsutsui.
 * Copyright (C) 2000 Shuichiro URATA.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#define WIRED_ENTRY_SIZE(pg_size)	((pg_size) * 2) 
#define WIRED_ENTRY_OFFMASK(pg_size)	(WIRED_ENTRY_SIZE(pg_size) - 1)

void	ews4800mips_init_wired_map(void);
int	ews4800mips_map_wired(vaddr_t va, paddr_t pa0, paddr_t pa1,
    uint32_t pg_size);
vaddr_t	ews4800mips_map_wired_region(paddr_t pa, int size, uint32_t pg_size);
---