summaryrefslogtreecommitdiffstats
path: root/sys/i386/i386
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2014-12-23 12:13:31 +0000
committernyan <nyan@FreeBSD.org>2014-12-23 12:13:31 +0000
commitf42424055bf04cd63fa5d8967611d1952483f85b (patch)
tree667d7dcf82775262ec01ea944a2bb432f685d5a7 /sys/i386/i386
parentd2f5d57eaa22cbf92de3880cbe4408244cb36439 (diff)
downloadFreeBSD-src-f42424055bf04cd63fa5d8967611d1952483f85b.zip
FreeBSD-src-f42424055bf04cd63fa5d8967611d1952483f85b.tar.gz
MFC: r272492
Merge pc98's machdep.c into i386/i386/machdep.c.
Diffstat (limited to 'sys/i386/i386')
-rw-r--r--sys/i386/i386/machdep.c309
1 files changed, 305 insertions, 4 deletions
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 48a7e62..05ea4e0 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -112,7 +112,11 @@ __FBSDID("$FreeBSD$");
#include <ddb/db_sym.h>
#endif
+#ifdef PC98
+#include <pc98/pc98/pc98_machdep.h>
+#else
#include <isa/rtc.h>
+#endif
#include <net/netisr.h>
@@ -212,6 +216,14 @@ extern vm_offset_t ksym_start, ksym_end;
int _udatasel, _ucodesel;
u_int basemem;
+#ifdef PC98
+int need_pre_dma_flush; /* If 1, use wbinvd befor DMA transfer. */
+int need_post_dma_flush; /* If 1, use invd after DMA transfer. */
+
+static int ispc98 = 1;
+SYSCTL_INT(_machdep, OID_AUTO, ispc98, CTLFLAG_RD, &ispc98, 0, "");
+#endif
+
int cold = 1;
#ifdef COMPAT_43
@@ -258,7 +270,8 @@ cpu_startup(dummy)
{
uintmax_t memsize;
char *sysenv;
-
+
+#ifndef PC98
/*
* On MacBooks, we need to disallow the legacy USB circuit to
* generate an SMI# because this can cause several problems,
@@ -284,6 +297,7 @@ cpu_startup(dummy)
}
freeenv(sysenv);
}
+#endif /* !PC98 */
/*
* Good {morning,afternoon,evening,night}.
@@ -1290,6 +1304,7 @@ SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RW, &idle_mwait,
#define STATE_MWAIT 0x1
#define STATE_SLEEPING 0x2
+#ifndef PC98
static void
cpu_idle_acpi(sbintime_t sbt)
{
@@ -1308,6 +1323,7 @@ cpu_idle_acpi(sbintime_t sbt)
__asm __volatile("sti; hlt");
*state = STATE_RUNNING;
}
+#endif /* !PC98 */
#ifndef XEN
static void
@@ -1425,7 +1441,7 @@ cpu_probe_amdc1e(void)
}
}
-#ifdef XEN
+#if defined(PC98) || defined(XEN)
void (*cpu_idle_fn)(sbintime_t) = cpu_idle_hlt;
#else
void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi;
@@ -1513,7 +1529,9 @@ struct {
{ cpu_idle_spin, "spin" },
{ cpu_idle_mwait, "mwait" },
{ cpu_idle_hlt, "hlt" },
+#ifndef PC98
{ cpu_idle_acpi, "acpi" },
+#endif
{ NULL, NULL }
};
@@ -1530,9 +1548,11 @@ idle_sysctl_available(SYSCTL_HANDLER_ARGS)
if (strstr(idle_tbl[i].id_name, "mwait") &&
(cpu_feature2 & CPUID2_MON) == 0)
continue;
+#ifndef PC98
if (strcmp(idle_tbl[i].id_name, "acpi") == 0 &&
cpu_idle_hook == NULL)
continue;
+#endif
p += sprintf(p, "%s%s", p != avail ? ", " : "",
idle_tbl[i].id_name);
}
@@ -1567,9 +1587,11 @@ idle_sysctl(SYSCTL_HANDLER_ARGS)
if (strstr(idle_tbl[i].id_name, "mwait") &&
(cpu_feature2 & CPUID2_MON) == 0)
continue;
+#ifndef PC98
if (strcmp(idle_tbl[i].id_name, "acpi") == 0 &&
cpu_idle_hook == NULL)
continue;
+#endif
if (strcmp(idle_tbl[i].id_name, buf))
continue;
cpu_idle_fn = idle_tbl[i].id_fn;
@@ -2047,7 +2069,7 @@ sdtossd(sd, ssd)
ssd->ssd_gran = sd->sd_gran;
}
-#ifndef XEN
+#if !defined(PC98) && !defined(XEN)
static int
add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp)
{
@@ -2126,7 +2148,9 @@ add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp)
physmap[insert_idx + 1] = smap->base + smap->length;
return (1);
}
+#endif /* !PC98 && !XEN */
+#ifndef XEN
static void
basemem_setup(void)
{
@@ -2174,7 +2198,7 @@ basemem_setup(void)
for (i = basemem / 4; i < 160; i++)
pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
}
-#endif
+#endif /* !XEN */
/*
* Populate the (physmap) array with base/bound pairs describing the
@@ -2189,6 +2213,271 @@ basemem_setup(void)
*
* XXX first should be vm_paddr_t.
*/
+#ifdef PC98
+static void
+getmemsize(int first)
+{
+ int off, physmap_idx, pa_indx, da_indx;
+ u_long physmem_tunable, memtest;
+ vm_paddr_t physmap[PHYSMAP_SIZE];
+ pt_entry_t *pte;
+ quad_t dcons_addr, dcons_size;
+ int i;
+ int pg_n;
+ u_int extmem;
+ u_int under16;
+ vm_paddr_t pa;
+
+ bzero(physmap, sizeof(physmap));
+
+ /* XXX - some of EPSON machines can't use PG_N */
+ pg_n = PG_N;
+ if (pc98_machine_type & M_EPSON_PC98) {
+ switch (epson_machine_id) {
+#ifdef WB_CACHE
+ default:
+#endif
+ case EPSON_PC486_HX:
+ case EPSON_PC486_HG:
+ case EPSON_PC486_HA:
+ pg_n = 0;
+ break;
+ }
+ }
+
+ under16 = pc98_getmemsize(&basemem, &extmem);
+ basemem_setup();
+
+ physmap[0] = 0;
+ physmap[1] = basemem * 1024;
+ physmap_idx = 2;
+ physmap[physmap_idx] = 0x100000;
+ physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024;
+
+ /*
+ * Now, physmap contains a map of physical memory.
+ */
+
+#ifdef SMP
+ /* make hole for AP bootstrap code */
+ physmap[1] = mp_bootaddress(physmap[1]);
+#endif
+
+ /*
+ * Maxmem isn't the "maximum memory", it's one larger than the
+ * highest page of the physical address space. It should be
+ * called something like "Maxphyspage". We may adjust this
+ * based on ``hw.physmem'' and the results of the memory test.
+ */
+ Maxmem = atop(physmap[physmap_idx + 1]);
+
+#ifdef MAXMEM
+ Maxmem = MAXMEM / 4;
+#endif
+
+ if (TUNABLE_ULONG_FETCH("hw.physmem", &physmem_tunable))
+ Maxmem = atop(physmem_tunable);
+
+ /*
+ * By default keep the memtest enabled. Use a general name so that
+ * one could eventually do more with the code than just disable it.
+ */
+ memtest = 1;
+ TUNABLE_ULONG_FETCH("hw.memtest.tests", &memtest);
+
+ if (atop(physmap[physmap_idx + 1]) != Maxmem &&
+ (boothowto & RB_VERBOSE))
+ printf("Physical memory use set to %ldK\n", Maxmem * 4);
+
+ /*
+ * If Maxmem has been increased beyond what the system has detected,
+ * extend the last memory segment to the new limit.
+ */
+ if (atop(physmap[physmap_idx + 1]) < Maxmem)
+ physmap[physmap_idx + 1] = ptoa((vm_paddr_t)Maxmem);
+
+ /*
+ * We need to divide chunk if Maxmem is larger than 16MB and
+ * under 16MB area is not full of memory.
+ * (1) system area (15-16MB region) is cut off
+ * (2) extended memory is only over 16MB area (ex. Melco "HYPERMEMORY")
+ */
+ if ((under16 != 16 * 1024) && (extmem > 15 * 1024)) {
+ /* 15M - 16M region is cut off, so need to divide chunk */
+ physmap[physmap_idx + 1] = under16 * 1024;
+ physmap_idx += 2;
+ physmap[physmap_idx] = 0x1000000;
+ physmap[physmap_idx + 1] = physmap[2] + extmem * 1024;
+ }
+
+ /* call pmap initialization to make new kernel address space */
+ pmap_bootstrap(first);
+
+ /*
+ * Size up each available chunk of physical memory.
+ */
+ physmap[0] = PAGE_SIZE; /* mask off page 0 */
+ pa_indx = 0;
+ da_indx = 1;
+ phys_avail[pa_indx++] = physmap[0];
+ phys_avail[pa_indx] = physmap[0];
+ dump_avail[da_indx] = physmap[0];
+ pte = CMAP3;
+
+ /*
+ * Get dcons buffer address
+ */
+ if (getenv_quad("dcons.addr", &dcons_addr) == 0 ||
+ getenv_quad("dcons.size", &dcons_size) == 0)
+ dcons_addr = 0;
+
+ /*
+ * physmap is in bytes, so when converting to page boundaries,
+ * round up the start address and round down the end address.
+ */
+ for (i = 0; i <= physmap_idx; i += 2) {
+ vm_paddr_t end;
+
+ end = ptoa((vm_paddr_t)Maxmem);
+ if (physmap[i + 1] < end)
+ end = trunc_page(physmap[i + 1]);
+ for (pa = round_page(physmap[i]); pa < end; pa += PAGE_SIZE) {
+ int tmp, page_bad, full;
+ int *ptr = (int *)CADDR3;
+
+ full = FALSE;
+ /*
+ * block out kernel memory as not available.
+ */
+ if (pa >= KERNLOAD && pa < first)
+ goto do_dump_avail;
+
+ /*
+ * block out dcons buffer
+ */
+ if (dcons_addr > 0
+ && pa >= trunc_page(dcons_addr)
+ && pa < dcons_addr + dcons_size)
+ goto do_dump_avail;
+
+ page_bad = FALSE;
+ if (memtest == 0)
+ goto skip_memtest;
+
+ /*
+ * map page into kernel: valid, read/write,non-cacheable
+ */
+ *pte = pa | PG_V | PG_RW | pg_n;
+ invltlb();
+
+ tmp = *(int *)ptr;
+ /*
+ * Test for alternating 1's and 0's
+ */
+ *(volatile int *)ptr = 0xaaaaaaaa;
+ if (*(volatile int *)ptr != 0xaaaaaaaa)
+ page_bad = TRUE;
+ /*
+ * Test for alternating 0's and 1's
+ */
+ *(volatile int *)ptr = 0x55555555;
+ if (*(volatile int *)ptr != 0x55555555)
+ page_bad = TRUE;
+ /*
+ * Test for all 1's
+ */
+ *(volatile int *)ptr = 0xffffffff;
+ if (*(volatile int *)ptr != 0xffffffff)
+ page_bad = TRUE;
+ /*
+ * Test for all 0's
+ */
+ *(volatile int *)ptr = 0x0;
+ if (*(volatile int *)ptr != 0x0)
+ page_bad = TRUE;
+ /*
+ * Restore original value.
+ */
+ *(int *)ptr = tmp;
+
+skip_memtest:
+ /*
+ * Adjust array of valid/good pages.
+ */
+ if (page_bad == TRUE)
+ continue;
+ /*
+ * If this good page is a continuation of the
+ * previous set of good pages, then just increase
+ * the end pointer. Otherwise start a new chunk.
+ * Note that "end" points one higher than end,
+ * making the range >= start and < end.
+ * If we're also doing a speculative memory
+ * test and we at or past the end, bump up Maxmem
+ * so that we keep going. The first bad page
+ * will terminate the loop.
+ */
+ if (phys_avail[pa_indx] == pa) {
+ phys_avail[pa_indx] += PAGE_SIZE;
+ } else {
+ pa_indx++;
+ if (pa_indx == PHYS_AVAIL_ARRAY_END) {
+ printf(
+ "Too many holes in the physical address space, giving up\n");
+ pa_indx--;
+ full = TRUE;
+ goto do_dump_avail;
+ }
+ phys_avail[pa_indx++] = pa; /* start */
+ phys_avail[pa_indx] = pa + PAGE_SIZE; /* end */
+ }
+ physmem++;
+do_dump_avail:
+ if (dump_avail[da_indx] == pa) {
+ dump_avail[da_indx] += PAGE_SIZE;
+ } else {
+ da_indx++;
+ if (da_indx == DUMP_AVAIL_ARRAY_END) {
+ da_indx--;
+ goto do_next;
+ }
+ dump_avail[da_indx++] = pa; /* start */
+ dump_avail[da_indx] = pa + PAGE_SIZE; /* end */
+ }
+do_next:
+ if (full)
+ break;
+ }
+ }
+ *pte = 0;
+ invltlb();
+
+ /*
+ * XXX
+ * The last chunk must contain at least one page plus the message
+ * buffer to avoid complicating other code (message buffer address
+ * calculation, etc.).
+ */
+ while (phys_avail[pa_indx - 1] + PAGE_SIZE +
+ round_page(msgbufsize) >= phys_avail[pa_indx]) {
+ physmem -= atop(phys_avail[pa_indx] - phys_avail[pa_indx - 1]);
+ phys_avail[pa_indx--] = 0;
+ phys_avail[pa_indx--] = 0;
+ }
+
+ Maxmem = atop(phys_avail[pa_indx]);
+
+ /* Trim off space for the message buffer. */
+ phys_avail[pa_indx] -= round_page(msgbufsize);
+
+ /* Map the message buffer. */
+ for (off = 0; off < round_page(msgbufsize); off += PAGE_SIZE)
+ pmap_kenter((vm_offset_t)msgbufp + off, phys_avail[pa_indx] +
+ off);
+
+ PT_UPDATES_FLUSH();
+}
+#else /* PC98 */
static void
getmemsize(int first)
{
@@ -2597,6 +2886,7 @@ do_next:
PT_UPDATES_FLUSH();
}
+#endif /* PC98 */
#ifdef XEN
#define MTOPSIZE (1<<(14 + PAGE_SHIFT))
@@ -2880,6 +3170,13 @@ init386(first)
*/
proc_linkup0(&proc0, &thread0);
+#ifdef PC98
+ /*
+ * Initialize DMAC
+ */
+ pc98_init_dmac();
+#endif
+
metadata_missing = 0;
if (bootinfo.bi_modulep) {
preload_metadata = (caddr_t)bootinfo.bi_modulep + KERNBASE;
@@ -3042,7 +3339,9 @@ init386(first)
#ifdef DEV_ISA
#ifdef DEV_ATPIC
+#ifndef PC98
elcr_probe();
+#endif
atpic_startup();
#else
/* Reset and mask the atpics and leave them shut down. */
@@ -3184,6 +3483,7 @@ cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
pcpu->pc_acpi_id = 0xffffffff;
}
+#ifndef PC98
static int
smap_sysctl_handler(SYSCTL_HANDLER_ARGS)
{
@@ -3221,6 +3521,7 @@ smap_sysctl_handler(SYSCTL_HANDLER_ARGS)
}
SYSCTL_PROC(_machdep, OID_AUTO, smap, CTLTYPE_OPAQUE|CTLFLAG_RD, NULL, 0,
smap_sysctl_handler, "S,bios_smap_xattr", "Raw BIOS SMAP data");
+#endif /* !PC98 */
void
spinlock_enter(void)
OpenPOWER on IntegriCloud