diff options
author | Eric Biederman <ebiederm@xmission.com> | 2003-10-11 06:20:25 +0000 |
---|---|---|
committer | Eric Biederman <ebiederm@xmission.com> | 2003-10-11 06:20:25 +0000 |
commit | 83b991afff40e12a8b6756af06a472842edb1a66 (patch) | |
tree | a441ff0d88afcb0a07cf22dc3653db3e07a05c98 | |
parent | 080038bfbd8fdf08bac12476a3789495e6f705ca (diff) |
- O2, enums, and switch statements work in romcc
- Support for compiling romcc on non x86 platforms
- new romc options -msse and -mmmx for specifying extra registers to use
- Bug fixes to device the device disable/enable framework and an amd8111 implementation
- Move the link specification to the chip specification instead of the path
- Allow specifying devices with internal bridges.
- Initial via epia support
- Opteron errata fixes
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1200 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
90 files changed, 8018 insertions, 1956 deletions
@@ -1,3 +1,12 @@ +- 1.1.5 + - O2, enums, and switch statements work in romcc + - Support for compiling romcc on non x86 platforms + - new romc options -msse and -mmmx for specifying extra registers to use + - Bug fixes to device the device disable/enable framework and an amd8111 implementation + - Move the link specification to the chip specification instead of the path + - Allow specifying devices with internal bridges. + - Initial via epia support + - Opteron errata fixes - 1.1.4 Major restructuring of hypertransport handling. Major rewerite of superio/NSC/pc87360 as a proof of concept for handling superio resources dynamically diff --git a/src/arch/i386/lib/console.inc b/src/arch/i386/lib/console.inc index 2f031e5d10..b617b8c1d0 100644 --- a/src/arch/i386/lib/console.inc +++ b/src/arch/i386/lib/console.inc @@ -526,5 +526,7 @@ console_tx_string: jmp console_tx_string console0: +#if 0 CONSOLE_INFO_TX_STRING($console_test) +#endif diff --git a/src/arch/i386/lib/cpu.c b/src/arch/i386/lib/cpu.c index baa029c02c..ad982dbc6c 100644 --- a/src/arch/i386/lib/cpu.c +++ b/src/arch/i386/lib/cpu.c @@ -125,7 +125,7 @@ unsigned long cpu_initialize(struct mem_range *mem) */ unsigned long processor_id = this_processors_id(); printk_notice("Initializing CPU #%d\n", processor_id); - + /* some cpus need a fixup done. This is the hook for doing that. */ cpufixup(mem); diff --git a/src/boot/hardwaremain.c b/src/boot/hardwaremain.c index 687b102bbe..6231d1167e 100644 --- a/src/boot/hardwaremain.c +++ b/src/boot/hardwaremain.c @@ -160,7 +160,6 @@ void hardwaremain(int boot_complete) /* If we have already booted attempt a hard reboot */ if (boot_complete) { - printk_spew("calling hard_reset\n"); hard_reset(); } CONFIGURE(CONF_PASS_PRE_PCI); diff --git a/src/config/Config.lb b/src/config/Config.lb index ee617c9a60..822f76906c 100644 --- a/src/config/Config.lb +++ b/src/config/Config.lb @@ -7,7 +7,7 @@ makedefine LIBGCC_FILE_NAME := $(shell $(CC) -print-libgcc-file-name) makedefine GCC_INC_DIR := $(shell $(CC) -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp") makedefine CPPFLAGS := -I$(TOP)/src/include -I$(TOP)/src/arch/$(ARCH)/include -I$(GCC_INC_DIR) $(CPUFLAGS) -makedefine ROMCCPPFLAGS := -D__ROMCC__=0 -D__ROMCC_MINOR__=34 +makedefine ROMCCPPFLAGS := -D__ROMCC__=0 -D__ROMCC_MINOR__=36 makedefine CFLAGS := $(CPU_OPT) $(CPPFLAGS) -Os -nostdinc -nostdlib -fno-builtin -Wall makedefine HOSTCFLAGS:= -Os -Wall @@ -116,7 +116,7 @@ end makerule ./romcc depends "$(TOP)/util/romcc/romcc.c" - action "$(HOSTCC) -g $(HOSTCFLAGS) -DVERSION='\"0.34\"' -DRELEASE_DATE='\"4 July 2003\"' $< -o $@" + action "$(HOSTCC) -g $(HOSTCFLAGS) -DVERSION='\"0.36\"' -DRELEASE_DATE='\"10 October 2003\"' $< -o $@" end makerule build_opt_tbl diff --git a/src/config/Options.lb b/src/config/Options.lb index 98d9e8a3bd..1a12e76dbe 100644 --- a/src/config/Options.lb +++ b/src/config/Options.lb @@ -117,7 +117,7 @@ define OBJCOPY comment "Objcopy command" end define LINUXBIOS_VERSION - default "1.1.4" + default "1.1.5" export always comment "LinuxBIOS version" end diff --git a/src/cpu/k8/cpufixup.c b/src/cpu/k8/cpufixup.c index d5ccfc299d..6aa6722579 100644 --- a/src/cpu/k8/cpufixup.c +++ b/src/cpu/k8/cpufixup.c @@ -4,15 +4,67 @@ #include <cpu/p6/msr.h> #include <cpu/k8/mtrr.h> #include <device/device.h> +#include "../../northbridge/amd/amdk8/cpu_rev.c" #include <device/chip.h> - #include "chip.h" +#define MCI_STATUS 0x401 + +static inline void disable_cache(void) +{ + unsigned int tmp; + /* Disable cache */ + /* Write back the cache and flush TLB */ + asm volatile ( + "movl %%cr0, %0\n\t" + "orl $0x40000000, %0\n\t" + "wbinvd\n\t" + "movl %0, %%cr0\n\t" + "wbinvd\n\t" + :"=r" (tmp) + ::"memory"); +} + +static inline void enable_cache(void) +{ + unsigned int tmp; + // turn cache back on. + asm volatile ( + "movl %%cr0, %0\n\t" + "andl $0x9fffffff, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (tmp) + ::"memory"); +} + +static inline msr_t rdmsr_amd(unsigned index) +{ + msr_t result; + __asm__ __volatile__ ( + "rdmsr" + : "=a" (result.lo), "=d" (result.hi) + : "c" (index), "D" (0x9c5a203a) + ); + return result; +} + +static inline void wrmsr_amd(unsigned index, msr_t msr) +{ + __asm__ __volatile__ ( + "wrmsr" + : /* No outputs */ + : "c" (index), "a" (msr.lo), "d" (msr.hi), "D" (0x9c5a203a) + ); +} + void k8_cpufixup(struct mem_range *mem) { unsigned long mmio_basek, tomk; unsigned long i; msr_t msr; + + disable_cache(); + /* Except for the PCI MMIO hold just before 4GB there are no * significant holes in the address space, so just account * for those two and move on. @@ -32,28 +84,15 @@ void k8_cpufixup(struct mem_range *mem) mmio_basek = tomk; } -#if 1 - /* Report the amount of memory. */ - print_debug("cpufixup RAM: 0x"); - print_debug_hex32(tomk); - print_debug(" KB\r\n"); -#endif - - /* Now set top of memory */ - msr.lo = (tomk & 0x003fffff) << 10; - msr.hi = (tomk & 0xffc00000) >> 22; - wrmsr(TOP_MEM2, msr); - - /* Leave a 64M hole between TOP_MEM and TOP_MEM2 - * so I can see my rom chip and other I/O devices. - */ - if (tomk >= 0x003f0000) { - tomk = 0x3f0000; - } // tom_k = 0x3c0000; - msr.lo = (tomk & 0x003fffff) << 10; - msr.hi = (tomk & 0xffc00000) >> 22; - wrmsr(TOP_MEM, msr); + /* Setup TOP_MEM */ + msr.hi = mmio_basek >> 22; + msr.lo = mmio_basek << 10; + wrmsr(TOP_MEM, msr); + /* Setup TOP_MEM2 */ + msr.hi = tomk >> 22; + msr.lo = tomk << 10; + wrmsr(TOP_MEM2, msr); /* zero the IORR's before we enable to prevent * undefined side effects. @@ -66,6 +105,64 @@ void k8_cpufixup(struct mem_range *mem) msr = rdmsr(SYSCFG_MSR); msr.lo |= SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_TOM2En; wrmsr(SYSCFG_MSR, msr); + + /* zero the machine check error status registers */ + msr.lo = 0; + msr.hi = 0; + for(i=0; i<5; i++) { + wrmsr(MCI_STATUS + (i*4),msr); + } + + if (is_cpu_pre_c0()) { + /* Erratum 63... */ + msr = rdmsr(HWCR_MSR); + msr.lo |= (1 << 6); + wrmsr(HWCR_MSR, msr); + /* Erratum 69... */ +#if 1 + msr = rdmsr_amd(BU_CFG_MSR); + msr.hi |= (1 << (45 - 32)); + wrmsr_amd(BU_CFG_MSR, msr); +#endif + /* Erratum 81... */ +#if 1 + msr = rdmsr_amd(DC_CFG_MSR); + msr.lo |= (1 << 10); + wrmsr_amd(DC_CFG_MSR, msr); +#endif + + } + /* Erratum 89 ... */ + msr = rdmsr(NB_CFG_MSR); + msr.lo |= 1 << 3; + + if (!is_cpu_pre_c0()) { + /* Erratum 86 Disable data masking on C0 and + * later processor revs. + * FIXME this is only needed if ECC is enabled. + */ + msr.hi |= 1 << (36 - 32); + } + wrmsr(NB_CFG_MSR, msr); +#if 1 /* The following erratum fixes reset the cpu ???? */ + + /* Erratum 97 ... */ + if (!is_cpu_pre_c0()) { + msr = rdmsr_amd(DC_CFG_MSR); + msr.lo |= 1 << 3; + wrmsr_amd(DC_CFG_MSR, msr); + } + + /* Erratum 94 ... */ + msr = rdmsr_amd(IC_CFG_MSR); + msr.lo |= 1 << 11; + wrmsr_amd(IC_CFG_MSR, msr); + +#endif + + /* Erratum 91 prefetch miss is handled in the kernel */ + + enable_cache(); } static @@ -87,10 +184,6 @@ void k8_enable(struct chip *chip, enum chip_pass pass) } struct chip_control cpu_k8_control = { - enable: k8_enable, - name: "AMD K8" + .enable = k8_enable, + .name = "AMD K8", }; - - - - diff --git a/src/cpu/p6/mtrr.c b/src/cpu/p6/mtrr.c index b067883316..1225fafe08 100644 --- a/src/cpu/p6/mtrr.c +++ b/src/cpu/p6/mtrr.c @@ -92,7 +92,7 @@ static void intel_set_var_mtrr(unsigned int reg, unsigned long basek, unsigned l base.lo = basek << 10; if (sizek < 4*1024*1024) { - mask.hi = 0x0F; + mask.hi = 0x0FF; mask.lo = ~((sizek << 10) -1); } else { diff --git a/src/devices/chip.c b/src/devices/chip.c index b7eace38f0..c9e1ac5643 100644 --- a/src/devices/chip.c +++ b/src/devices/chip.c @@ -46,16 +46,33 @@ void chip_enumerate(struct chip *chip) int identical_paths; identical_paths = (i > 0) && - (path_eq(&chip->path[i - 1].path, &chip->path[i].path)) && - (chip->path[i - 1].channel == chip->path[i].channel); + (path_eq(&chip->path[i - 1].path, &chip->path[i].path)); if (!identical_paths) { + struct bus *parent; + int bus; link = 0; dev = 0; + parent = chip->bus; switch(chip->path[i].path.type) { case DEVICE_PATH_NONE: break; + case DEVICE_PATH_PCI: + bus = chip->path[i].path.u.pci.bus; + if (bus != 0) { + device_t dev; + int i = 1; + dev = chip->dev; + while(dev && (i != bus)) { + dev = dev->next; + i++; + } + if ((i == bus) && dev) { + parent = &dev->link[0]; + } + } + /* Fall through */ default: - dev = alloc_dev(chip->bus, &chip->path[i].path); + dev = alloc_dev(parent, &chip->path[i].path); break; } } @@ -63,12 +80,13 @@ void chip_enumerate(struct chip *chip) link += 1; } if (dev) { - printk_spew("path %s %s\n", dev_path(dev), identical_paths?"identical":""); + printk_spew("path (%p) %s %s", dev, dev_path(dev), identical_paths?"identical":""); + printk_spew(" parent: (%p) %s\n",dev->bus->dev, dev_path(dev->bus->dev)); + dev->chip = chip; dev->enable = chip->path[i].enable; dev->links = link + 1; for(child = chip->children; child; child = child->next) { - if (!child->bus && - child->path[0].channel == i) { + if (!child->bus && child->link == i) { child->bus = &dev->link[link]; } } diff --git a/src/devices/device.c b/src/devices/device.c index 289c0766ea..c6dd5fc4ad 100644 --- a/src/devices/device.c +++ b/src/devices/device.c @@ -115,6 +115,9 @@ static void read_resources(struct bus *bus) dev_path(curdev)); continue; } + if (!curdev->enable) { + continue; + } curdev->ops->read_resources(curdev); /* Read in subtractive resources behind the current device */ links = 0; @@ -251,16 +254,12 @@ void compute_allocate_resource( min_align = 0; base = bridge->base; - printk_spew("%s: bus %p, bridge %p, type_mask 0x%x, type 0x%x\n", - __FUNCTION__, - bus, bridge, type_mask, type); - printk_spew("vendor 0x%x device 0x%x class 0x%x \n", - bus->dev->vendor, bus->dev->device, bus->dev->class); - printk_spew("%s compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n", - dev_path(bus->dev), - (bridge->flags & IORESOURCE_IO)? "io": - (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", - base, bridge->size, bridge->align, bridge->gran); + printk_spew("%s compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n", + dev_path(bus->dev), + (bridge->flags & IORESOURCE_IO)? "io": + (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", + base, bridge->size, bridge->align, bridge->gran); + /* We want different minimum alignments for different kinds of * resources. These minimums are not device type specific @@ -406,6 +405,9 @@ void assign_resources(struct bus *bus) dev_path(curdev)); continue; } + if (!curdev->enable) { + continue; + } curdev->ops->set_resources(curdev); } printk_debug("ASSIGNED RESOURCES, bus %d\n", bus->secondary); @@ -422,6 +424,9 @@ void enable_resources(struct device *dev) dev_path(dev)); return; } + if (!dev->enable) { + return; + } dev->ops->enable_resources(dev); } @@ -444,13 +449,12 @@ void dev_enumerate(void) void dev_configure(void) { struct device *root = &dev_root; - printk_info("%s: Allocating resources...", __FUNCTION__); + printk_info("Allocating resources..."); printk_debug("\n"); root->ops->read_resources(root); - printk_spew("%s: done reading resources...\n", __FUNCTION__); /* Make certain the io devices are allocated somewhere * safe. */ @@ -465,10 +469,8 @@ void dev_configure(void) root->resource[1].flags |= IORESOURCE_SET; // now just set things into registers ... we hope ... root->ops->set_resources(root); - printk_spew("%s: done setting resources...\n", __FUNCTION__); allocate_vga_resource(); - printk_spew("%s: done vga resources...\n", __FUNCTION__); printk_info("done.\n"); } @@ -494,7 +496,7 @@ void dev_initialize(void) printk_info("Initializing devices...\n"); for (dev = all_devices; dev; dev = dev->next) { - if (dev->ops && dev->ops->init) { + if (dev->enable && dev->ops && dev->ops->init) { printk_debug("%s init\n", dev_path(dev)); dev->ops->init(dev); } diff --git a/src/devices/device_util.c b/src/devices/device_util.c index 384a3be8e0..6652c86ea0 100644 --- a/src/devices/device_util.c +++ b/src/devices/device_util.c @@ -30,15 +30,17 @@ device_t alloc_find_dev(struct bus *parent, struct device_path *path) */ struct device *dev_find_slot(unsigned int bus, unsigned int devfn) { - struct device *dev; + struct device *dev, *result; + result = 0; for (dev = all_devices; dev; dev = dev->next) { if ((dev->bus->secondary == bus) && (dev->path.u.pci.devfn == devfn)) { + result = dev; break; } } - return dev; + return result; } /** Find a device of a given vendor and type @@ -88,6 +90,9 @@ const char *dev_path(device_t dev) } else { switch(dev->path.type) { + case DEVICE_PATH_ROOT: + memcpy(buffer, "Root Device", 12); + break; case DEVICE_PATH_PCI: sprintf(buffer, "PCI: %02x:%02x.%01x", dev->bus->secondary, @@ -116,8 +121,12 @@ int path_eq(struct device_path *path1, struct device_path *path2) switch(path1->type) { case DEVICE_PATH_NONE: break; + case DEVICE_PATH_ROOT: + equal = 1; + break; case DEVICE_PATH_PCI: - equal = path1->u.pci.devfn == path2->u.pci.devfn; + equal = (path1->u.pci.bus == path2->u.pci.bus) && + (path1->u.pci.devfn == path2->u.pci.devfn); break; case DEVICE_PATH_PNP: equal = (path1->u.pnp.port == path2->u.pnp.port) && diff --git a/src/devices/hypertransport.c b/src/devices/hypertransport.c index 0c1dc3959a..326f343662 100644 --- a/src/devices/hypertransport.c +++ b/src/devices/hypertransport.c @@ -4,6 +4,7 @@ #include <device/path.h> #include <device/pci.h> #include <device/hypertransport.h> +#include <device/chip.h> #include <part/hard_reset.h> #include <part/fallback_boot.h> @@ -243,11 +244,19 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max) /* Add this device to the pci bus chain */ *chain_last = dev; /* Run the magice enable/disable sequence for the device */ - if (dev->ops && dev->ops->enable) { - dev->ops->enable(dev); + if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + dev->chip->control->enable_dev(dev); } /* Now read the vendor and device id */ id = pci_read_config32(dev, PCI_VENDOR_ID); + + /* If the chain is fully enumerated quit */ + if (id == 0xffffffff || id == 0x00000000 || + id == 0x0000ffff || id == 0xffff0000) { + printk_err("Missing static device: %s\n", + dev_path(dev)); + break; + } } /* Update the device chain tail */ for(func = dev; func; func = func->sibling) { @@ -268,7 +277,8 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max) /* Find the hypertransport link capability */ pos = ht_lookup_slave_capability(dev); if (pos == 0) { - printk_err("Hypertransport link capability not found"); + printk_err("%s Hypertransport link capability not found", + dev_path(dev)); break; } diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index 806734c18b..031d855fbf 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -18,6 +18,7 @@ #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> +#include <device/chip.h> #include <part/hard_reset.h> #include <part/fallback_boot.h> @@ -175,7 +176,6 @@ static void pci_bridge_read_bases(struct device *dev) /* FIXME handle bridges without some of the optional resources */ - printk_spew("%s: path %s\n", __FUNCTION__, dev_path(dev)); /* Initialize the io space constraints on the current bus */ dev->resource[reg].base = 0; dev->resource[reg].size = 0; @@ -215,7 +215,6 @@ static void pci_bridge_read_bases(struct device *dev) reg++; dev->resources = reg; - printk_spew("DONE %s: path %s\n", __FUNCTION__, dev_path(dev)); } @@ -455,11 +454,13 @@ static void set_pci_ops(struct device *dev) break; default: bad: - printk_err("%s [%04x/%04x/%06x] has unknown header " - "type %02x, ignoring.\n", - dev_path(dev), - dev->vendor, dev->device, - dev->class >> 8, dev->hdr_type); + if (dev->enable) { + printk_err("%s [%04x/%04x/%06x] has unknown header " + "type %02x, ignoring.\n", + dev_path(dev), + dev->vendor, dev->device, + dev->class >> 8, dev->hdr_type); + } } return; } @@ -556,17 +557,16 @@ unsigned int pci_scan_bus(struct bus *bus, } else { /* Run the magic enable/disable sequence for the device */ - if (dev->ops && dev->ops->enable) { - dev->ops->enable(dev); + if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + dev->chip->control->enable_dev(dev); } /* Now read the vendor and device id */ id = pci_read_config32(dev, PCI_VENDOR_ID); } - /* Read the rest of the pci configuration information */ hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); class = pci_read_config32(dev, PCI_CLASS_REVISION); - + /* Store the interesting information in the device structure */ dev->vendor = id & 0xffff; dev->device = (id >> 16) & 0xffff; @@ -576,20 +576,19 @@ unsigned int pci_scan_bus(struct bus *bus, /* Look at the vendor and device id, or at least the * header type and class and figure out which set of configuration - * methods to use. + * methods to use. Unless we already have some pci ops. */ - if (!dev->ops) { - set_pci_ops(dev); - /* Error if we don't have some pci operations for it */ - if (!dev->ops) { - printk_err("%s No device operations\n", - dev_path(dev)); - continue; - } - /* Now run the magic enable/disable sequence for the device */ - if (dev->ops && dev->ops->enable) { - dev->ops->enable(dev); - } + set_pci_ops(dev); + /* Error if we don't have some pci operations for it */ + if (dev->enable && !dev->ops) { + printk_err("%s No device operations\n", + dev_path(dev)); + continue; + } + + /* Now run the magic enable/disable sequence for the device */ + if (dev->ops && dev->ops->enable) { + dev->ops->enable(dev); } printk_debug("%s [%04x/%04x] %s\n", @@ -632,8 +631,7 @@ unsigned int pci_scan_bridge(struct device *dev, unsigned int max) struct bus *bus; uint32_t buses; uint16_t cr; - - printk_spew("%s: dev %p, max %d\n", __FUNCTION__, dev, max); + bus = &dev->link[0]; dev->links = 1; @@ -707,7 +705,6 @@ static void pci_level_irq(unsigned char intNum) } } - /* This function assigns IRQs for all functions contained within the indicated device address. If the device does not exist or does diff --git a/src/devices/root_device.c b/src/devices/root_device.c index ae02277363..4a076a1bb3 100644 --- a/src/devices/root_device.c +++ b/src/devices/root_device.c @@ -123,6 +123,8 @@ struct device_operations default_dev_ops_root = { struct device dev_root = { .ops = &default_dev_ops_root, .bus = &dev_root.link[0], + .path = { .type = DEVICE_PATH_ROOT }, + .enable = 1, .links = 1, .link = { [0] = { diff --git a/src/include/cpu/k8/mtrr.h b/src/include/cpu/k8/mtrr.h index 5f08a51215..5a965eebb8 100644 --- a/src/include/cpu/k8/mtrr.h +++ b/src/include/cpu/k8/mtrr.h @@ -30,5 +30,9 @@ #define TOP_MEM 0xC001001A #define TOP_MEM2 0xC001001D #define HWCR_MSR 0xC0010015 +#define NB_CFG_MSR 0xC001001f +#define IC_CFG_MSR 0xC0011021 +#define DC_CFG_MSR 0xC0011022 +#define BU_CFG_MSR 0xC0011023 #endif /* CPU_K8_MTRR_H */ diff --git a/src/include/device/chip.h b/src/include/device/chip.h index a98625a7ab..dc078a96b7 100644 --- a/src/include/device/chip.h +++ b/src/include/device/chip.h @@ -49,6 +49,7 @@ enum chip_pass { */ struct chip; +struct device; /* there is one of these for each TYPE of chip */ struct chip_control { @@ -56,6 +57,7 @@ struct chip_control { char *name; void (*enable)(struct chip *, enum chip_pass); void (*enumerate)(struct chip *chip); + void (*enable_dev)(struct device *dev); }; @@ -72,6 +74,7 @@ struct bus; #define MAX_CHIP_PATHS 16 #endif struct chip { + unsigned link; struct chip_control *control; /* for this device */ struct chip_device_path path[MAX_CHIP_PATHS]; /* can be 0, in which case the default is taken */ char *configuration; /* can be 0. */ diff --git a/src/include/device/device.h b/src/include/device/device.h index e7b0317db3..1b2b0169dc 100644 --- a/src/include/device/device.h +++ b/src/include/device/device.h @@ -35,6 +35,7 @@ struct bus { * combination: */ +struct chip; struct device { struct bus * bus; /* bus this device is on */ device_t sibling; /* next device on this bus */ @@ -72,6 +73,7 @@ struct device { unsigned long rom_address; struct device_operations *ops; + struct chip *chip; }; extern struct device dev_root; /* root bus */ @@ -94,7 +96,7 @@ extern void enumerate_static_device(void); extern const char *dev_path(device_t dev); /* Helper functions */ -device_t alloc_find_dev(struct bus *bus, struct device_path *path); +device_t alloc_find_dev(struct bus *parent, struct device_path *path); device_t dev_find_device (unsigned int vendor, unsigned int device, device_t from); device_t dev_find_class (unsigned int class, device_t from); device_t dev_find_slot (unsigned int bus, unsigned int devfn); diff --git a/src/include/device/path.h b/src/include/device/path.h index cf89a68466..20d76d1bbe 100644 --- a/src/include/device/path.h +++ b/src/include/device/path.h @@ -3,6 +3,7 @@ enum device_path_type { DEVICE_PATH_NONE = 0, + DEVICE_PATH_ROOT, DEVICE_PATH_PCI, DEVICE_PATH_PNP, DEVICE_PATH_I2C, @@ -10,6 +11,7 @@ enum device_path_type { struct pci_path { + unsigned bus; unsigned devfn; }; diff --git a/src/mainboard/amd/quartet/mptable.c b/src/mainboard/amd/quartet/mptable.c index 94ac735744..6c29589a81 100644 --- a/src/mainboard/amd/quartet/mptable.c +++ b/src/mainboard/amd/quartet/mptable.c @@ -7,8 +7,8 @@ void *smp_write_config_table(void *v, unsigned long * processor_map) { static const char sig[4] = "PCMP"; - static const char oem[8] = "LNXI "; - static const char productid[12] = "HDAMA "; + static const char oem[8] = "AMD "; + static const char productid[12] = "QUARTET "; struct mp_config_table *mc; unsigned char bus_num; unsigned char bus_isa; diff --git a/src/mainboard/arima/hdama/Config.lb b/src/mainboard/arima/hdama/Config.lb index b056124b74..2604021cc7 100644 --- a/src/mainboard/arima/hdama/Config.lb +++ b/src/mainboard/arima/hdama/Config.lb @@ -161,7 +161,7 @@ makerule ./auto.E end makerule ./auto.inc depends "./auto.E ./romcc" - action "./romcc -mcpu=k8 -O ./auto.E > auto.inc" + action "./romcc -mcpu=k8 -O2 ./auto.E > auto.inc" end ## @@ -231,32 +231,36 @@ northbridge amd/amdk8 "mc0" pci 0:18.1 pci 0:18.2 pci 0:18.3 - southbridge amd/amd8131 "amd8131" + southbridge amd/amd8131 "amd8131" link 0 pci 0:0.0 pci 0:0.1 pci 0:1.0 pci 0:1.1 end - southbridge amd/amd8111 "amd8111" + southbridge amd/amd8111 "amd8111" link 0 pci 0:0.0 - pci 0:1.0 - pci 0:1.1 - pci 0:1.2 - pci 0:1.3 - pci 0:1.5 - pci 0:1.6 - superio NSC/pc87360 - pnp 1:2e.0 - pnp 1:2e.1 - pnp 1:2e.2 - pnp 1:2e.3 - pnp 1:2e.4 - pnp 1:2e.5 - pnp 1:2e.6 - pnp 1:2e.7 - pnp 1:2e.8 - pnp 1:2e.9 - pnp 1:2e.a + pci 0:1.0 on + pci 0:1.1 on + pci 0:1.2 on + pci 0:1.3 on + pci 0:1.5 off + pci 0:1.6 off + pci 1:0.0 on + pci 1:0.1 on + pci 1:0.2 on + pci 1:1.0 off + superio NSC/pc87360 link 1 + pnp 2e.0 + pnp 2e.1 + pnp 2e.2 + pnp 2e.3 + pnp 2e.4 + pnp 2e.5 + pnp 2e.6 + pnp 2e.7 + pnp 2e.8 + pnp 2e.9 + pnp 2e.a register "com1" = "{1, 0, 0x3f8, 4}" register "lpt" = "{1}" end diff --git a/src/mainboard/arima/hdama/auto.c b/src/mainboard/arima/hdama/auto.c index f0651d1b09..244d0ea305 100644 --- a/src/mainboard/arima/hdama/auto.c +++ b/src/mainboard/arima/hdama/auto.c @@ -1,5 +1,4 @@ #define ASSEMBLY 1 - #include <stdint.h> #include <device/pci_def.h> #include <cpu/p6/apic.h> @@ -17,25 +16,32 @@ #include "cpu/p6/boot_cpu.c" #include "northbridge/amd/amdk8/reset_test.c" #include "debug.c" +#include "northbridge/amd/amdk8/cpu_rev.c" #define SIO_BASE 0x2e -#define MAXIMUM_CONSOLE_LOGLEVEL 9 -#define DEFAULT_CONSOLE_LOGLEVEL 9 static void memreset_setup(void) { - /* Set the memreset low */ - outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), SMBUS_IO_BASE + 0xc0 + 28); - /* Ensure the BIOS has control of the memory lines */ - outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), SMBUS_IO_BASE + 0xc0 + 29); + if (is_cpu_pre_c0()) { + /* Set the memreset low */ + outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), SMBUS_IO_BASE + 0xc0 + 28); + /* Ensure the BIOS has control of the memory lines */ + outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), SMBUS_IO_BASE + 0xc0 + 29); + } + else { + /* Ensure the CPU has controll of the memory lines */ + outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), SMBUS_IO_BASE + 0xc0 + 29); + } } static void memreset(int controllers, const struct mem_controller *ctrl) { - udelay(800); - /* Set memreset_high */ - outb((0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), SMBUS_IO_BASE + 0xc0 + 28); - udelay(90); + if (is_cpu_pre_c0()) { + udelay(800); + /* Set memreset_high */ + outb((0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), SMBUS_IO_BASE + 0xc0 + 28); + udelay(90); + } } static unsigned int generate_row(uint8_t node, uint8_t row, uint8_t maxnodes) @@ -92,9 +98,6 @@ static void coherent_ht_mainboard(unsigned cpus) { } -#include "northbridge/amd/amdk8/cpu_ldtstop.c" -#include "southbridge/amd/amd8111/amd8111_ldtstop.c" - #include "northbridge/amd/amdk8/raminit.c" #include "northbridge/amd/amdk8/coherent_ht.c" #include "sdram/generic_sdram.c" @@ -201,7 +204,7 @@ static void main(void) enumerate_ht_chain(0); distinguish_cpu_resets(0); -#if 1 +#if 0 print_pci_devices(); #endif enable_smbus(); @@ -211,10 +214,10 @@ static void main(void) memreset_setup(); sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu); -#if 1 +#if 0 dump_pci_devices(); #endif -#if 1 +#if 0 dump_pci_device(PCI_DEV(0, 0x18, 2)); #endif diff --git a/src/mainboard/arima/hdama/failover.c b/src/mainboard/arima/hdama/failover.c index 8eeeaef7e1..bd9c17020e 100644 --- a/src/mainboard/arima/hdama/failover.c +++ b/src/mainboard/arima/hdama/failover.c @@ -27,6 +27,10 @@ static void main(void) asm("jmp __cpu_reset"); } } + /* Is this a deliberate reset by the bios */ + else if (bios_reset_detected() && last_boot_normal()) { + asm("jmp __normal_image"); + } /* Is this a secondary cpu? */ else if (!boot_cpu() && last_boot_normal()) { asm("jmp __normal_image"); diff --git a/src/mainboard/arima/hdama/irq_tables.c b/src/mainboard/arima/hdama/irq_tables.c index 2c0095c177..142864fbb1 100644 --- a/src/mainboard/arima/hdama/irq_tables.c +++ b/src/mainboard/arima/hdama/irq_tables.c @@ -1,43 +1,34 @@ -/* This file was generated by getpir.c, do not modify! - (but if you do, please run checkpir on it to verify) - Contains the IRQ Routing Table dumped directly from your memory , wich BIOS sets up - - Documentation at : http://www.microsoft.com/hwdev/busbios/PCIIRQ.HTM -*/ - #include <arch/pirq_routing.h> - const struct irq_routing_table intel_irq_routing_table = { PIRQ_SIGNATURE, /* u32 signature */ PIRQ_VERSION, /* u16 version */ - 32+16*18, /* there can be total 18 devices on the bus */ - 1, /* Where the interrupt router lies (bus) */ - 0x23, /* Where the interrupt router lies (dev) */ - 0, /* IRQs devoted exclusively to PCI usage */ + 32+16*9, /* there can be total 9 devices on the bus */ + 1, /* Where the interrupt router lies (bus) */ + (4<<3)|3, /* Where the interrupt router lies (dev) */ + 0x0, /* IRQs devoted exclusively to PCI usage */ 0x1022, /* Vendor */ 0x746b, /* Device */ - 0, /* Crap (miniport) */ + 0, /* Crap (miniport) */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ - 0x35, /* u8 checksum , this hase to set to some value that would give 0 after the sum of all bytes for this structure (including checksum) */ - { - {0,0xc0, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, - {0,0x50, {{0x1, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, - {0x2,0x8, {{0x2, 0xdef8}, {0x3, 0xdef8}, {0x4, 0xdef8}, {0x1, 0xdef8}}, 0x3, 0}, - {0x2,0x10, {{0x3, 0xdef8}, {0x4, 0xdef8}, {0x1, 0xdef8}, {0x2, 0xdef8}}, 0x4, 0}, - {0x2,0x18, {{0x4, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0x0, 0}, - {0x2,0x20, {{0x4, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0x0, 0}, - {0x2,0x28, {{0x2, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0xa, 0}, - {0,0x58, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, - {0x3,0x8, {{0x2, 0xdef8}, {0x3, 0xdef8}, {0x4, 0xdef8}, {0x1, 0xdef8}}, 0x1, 0}, - {0x3,0x10, {{0x3, 0xdef8}, {0x4, 0xdef8}, {0x1, 0xdef8}, {0x2, 0xdef8}}, 0x2, 0}, - {0x3,0x18, {{0x4, 0xdef8}, {0x1, 0xdef8}, {0x2, 0xdef8}, {0x3, 0xdef8}}, 0x9, 0}, - {0,0x30, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, - {0x1,0, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0x4, 0xdef8}}, 0, 0}, - {0x1,0x28, {{0x2, 0xdef8}, {0x3, 0xdef8}, {0x4, 0xdef8}, {0x1, 0xdef8}}, 0x5, 0}, - {0x1,0x20, {{0x1, 0xdef8}, {0x2, 0xdef8}, {0x3, 0xdef8}, {0x4, 0xdef8}}, 0x6, 0}, - {0x1,0x30, {{0x3, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0xb, 0}, - {0,0x38, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, - {0,0xc8, {{0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}, {0, 0xdef8}}, 0, 0}, + 0xb0, /* u8 checksum , mod 256 checksum must give zero */ + { /* bus, devfn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */ + /* PCI Slot 1 */ + {0x03, (0x01<<3)|0, {{0x02, 0xdef8}, {0x03, 0xdef8}, {0x04, 0xdef8}, {0x01, 0xdef8}}, 0x01, 0}, + /* PCI Slot 2 */ + {0x03, (0x02<<3)|0, {{0x03, 0xdef8}, {0x04, 0xdef8}, {0x01, 0xdef8}, {0x02, 0xdef8}}, 0x02, 0}, + /* PCI Slot 3 */ + {0x02, (0x01<<3)|0, {{0x02, 0xdef8}, {0x03, 0xdef8}, {0x04, 0xdef8}, {0x01, 0xdef8}}, 0x03, 0}, + /* PCI Slot 4 */ + {0x02, (0x02<<3)|0, {{0x03, 0xdef8}, {0x04, 0xdef8}, {0x01, 0xdef8}, {0x02, 0xdef8}}, 0x04, 0}, + /* PCI Slot 5 */ + {0x04, (0x05<<3)|0, {{0x02, 0xdef8}, {0x03, 0xdef8}, {0x04, 0xdef8}, {0x01, 0xdef8}}, 0x05, 0}, + /* PCI Slot 6 */ + {0x04, (0x04<<3)|0, {{0x01, 0xdef8}, {0x02, 0xdef8}, {0x03, 0xdef8}, {0x04, 0xdef8}}, 0x06, 0}, + /* Onboard NICS */ + {0x02, (0x03<<3)|0, {{0x04, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x00, 0}, + {0x02, (0x04<<3)|0, {{0x04, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x00, 0}, + /* Let Linux know about bus 1 */ + {0x01, (0x04<<3)|3, {{0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x00, 0}, } }; diff --git a/src/mainboard/arima/hdama/mainboard.c b/src/mainboard/arima/hdama/mainboard.c index c5812ece3f..82041282f6 100644 --- a/src/mainboard/arima/hdama/mainboard.c +++ b/src/mainboard/arima/hdama/mainboard.c @@ -1,4 +1,3 @@ - #include <console/console.h> #include <device/device.h> #include <device/pci.h> diff --git a/src/mainboard/arima/hdama/mptable.c b/src/mainboard/arima/hdama/mptable.c index 94ac735744..bd9df2e3ac 100644 --- a/src/mainboard/arima/hdama/mptable.c +++ b/src/mainboard/arima/hdama/mptable.c @@ -48,8 +48,8 @@ void *smp_write_config_table(void *v, unsigned long * processor_map) else { printk_debug("ERROR - could not find PCI 1:03.0, using defaults\n"); - bus_8111_1 = 3; - bus_isa = 4; + bus_8111_1 = 4; + bus_isa = 5; } /* 8131-1 */ dev = dev_find_slot(1, PCI_DEVFN(0x01,0)); @@ -60,7 +60,7 @@ void *smp_write_config_table(void *v, unsigned long * processor_map) else { printk_debug("ERROR - could not find PCI 1:01.0, using defaults\n"); - bus_8131_1 = 1; + bus_8131_1 = 2; } /* 8131-2 */ dev = dev_find_slot(1, PCI_DEVFN(0x02,0)); @@ -71,7 +71,7 @@ void *smp_write_config_table(void *v, unsigned long * processor_map) else { printk_debug("ERROR - could not find PCI 1:02.0, using defaults\n"); - bus_8131_2 = 2; + bus_8131_2 = 3; } } @@ -144,10 +144,6 @@ void *smp_write_config_table(void *v, unsigned long * processor_map) bus_isa, 0x00, MP_APIC_ALL, 0x01); - /* AGP Slot */ - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - 0x03, (6<<2)|0, 0x02, 0x12); - /* PCI Slot 1 */ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, bus_8131_2, (1<<2)|0, 0x02, 0x11); diff --git a/src/northbridge/amd/amdk8/Config.lb b/src/northbridge/amd/amdk8/Config.lb index 6112ed18c8..0110e218ce 100644 --- a/src/northbridge/amd/amdk8/Config.lb +++ b/src/northbridge/amd/amdk8/Config.lb @@ -1,3 +1,4 @@ config chip.h object northbridge.o driver misc_control.o +driver mcf0_control.o diff --git a/src/northbridge/amd/amdk8/coherent_ht.c b/src/northbridge/amd/amdk8/coherent_ht.c index b2839159c7..f05ee3d22d 100644 --- a/src/northbridge/amd/amdk8/coherent_ht.c +++ b/src/northbridge/amd/amdk8/coherent_ht.c @@ -100,43 +100,6 @@ static void disable_probes(void) print_debug("done.\r\n"); } -//BY LYH -#define WAIT_TIMES 1000 -static void wait_ap_stop(u8 node) -{ - unsigned long reg; - unsigned long i; - for(i=0;i<WAIT_TIMES;i++) { - unsigned long regx; - regx = pci_read_config32(NODE_HT(node),0x6c); - if((regx & (1<<4))==1) break; - } - reg = pci_read_config32(NODE_HT(node),0x6c); - reg &= ~(1<<4); // clear it - pci_write_config32(NODE_HT(node), 0x6c, reg); - -} -static void notify_bsp_ap_is_stopped(void) -{ - unsigned long reg; - unsigned long apic_id; - apic_id = *((volatile unsigned long *)(APIC_DEFAULT_BASE+APIC_ID)); - apic_id >>= 24; -#if 0 - print_debug("applicaton cpu apic_id: "); - print_debug_hex32(apic_id); - print_debug("\r\n"); -#endif - /* AP apic_id == node_id ? */ - if(apic_id != 0) { - /* set the ColdResetbit to notify BSP that AP is stopped */ - reg = pci_read_config32(NODE_HT(apic_id), 0x6C); - reg |= 1<<4; - pci_write_config32(NODE_HT(apic_id), 0x6C, reg); - } - -} -//BY LYH END static void enable_routing(u8 node) { @@ -169,15 +132,8 @@ static void enable_routing(u8 node) print_debug_hex32(node); val=pci_read_config32(NODE_HT(node), 0x6c); - val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)); - pci_write_config32(NODE_HT(node), 0x6c, val); -//BY LYH -#if 1 - if(node!=0) { - wait_ap_stop(node); - } -#endif -//BY LYH END + val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)); + pci_write_config32(NODE_HT(node), 0x6c, val); print_debug(" done.\r\n"); } @@ -225,6 +181,62 @@ static bool check_connection(u8 src, u8 dest, u8 link) return 1; } +static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2) +{ + static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 }; + static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 }; + uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask; + uint8_t width_cap1, width_cap2, width_cap, width, ln_width1, ln_width2; + uint8_t freq; + /* Set link width and frequency */ + + /* Get the frequency capabilities */ + freq_cap1 = pci_read_config16(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ_CAP); + freq_cap2 = pci_read_config16(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ_CAP); + + /* Calculate the highest possible frequency */ +#if 1 + /* FIXME!!!!!!! + * This method of computing the fastes frequency is broken. + * Because the frequencies (i.e. 100Mhz) are not ordered. + */ + freq = log2(freq_cap1 & freq_cap2 & 0xff); +#else + /* Only allow supported frequencies 800Mhz and below */ + freq = log2(freq_cap1 & freq_cap2 & 0x3f); +#endif + + /* Set the Calulcated link frequency */ + pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ, freq); + pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ, freq); + + /* Get the width capabilities */ + width_cap1 = pci_read_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_WIDTH); + width_cap2 = pci_read_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_WIDTH); + + /* Calculate node1's input width */ + ln_width1 = link_width_to_pow2[width_cap1 & 7]; + ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7]; + if (ln_width1 > ln_width2) { + ln_width1 = ln_width2; + } + width = pow2_to_link_width[ln_width1]; + /* Calculate node1's output width */ + ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7]; + ln_width2 = link_width_to_pow2[width_cap2 & 7]; + if (ln_width1 > ln_width2) { + ln_width1 = ln_width2; + } + width |= pow2_to_link_width[ln_width1] << 4; + + /* Set node1's widths */ + pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_WIDTH + 1, width); + + /* Set node2's widths */ + width = ((width & 0x70) >> 4) | ((width & 0x7) << 4); + pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_WIDTH + 1, width); +} + static void fill_row(u8 node, u8 row, u32 value) { #if 0 @@ -346,6 +358,7 @@ static u8 setup_smp(void) } /* We found 2 nodes so far */ + optimize_connection(0, ACROSS, 7, ACROSS); setup_node(0, cpus); /* Node 1 is there. Setup Node 0 correctly */ setup_remote_node(1, cpus); /* Setup the routes on the remote node */ rename_temp_node(1); /* Rename Node 7 to Node 1 */ @@ -444,17 +457,6 @@ static unsigned detect_mp_capabilities(unsigned cpus) #endif -/* this is a shrunken cpuid. */ - -static unsigned int cpuid(unsigned int op) -{ - unsigned int ret; - - asm volatile ( "cpuid" : "=a" (ret) : "a" (op)); - - return ret; -} - static void coherent_ht_finalize(unsigned cpus) { int node; @@ -469,7 +471,7 @@ static void coherent_ht_finalize(unsigned cpus) #if 1 print_debug("coherent_ht_finalize\r\n"); #endif - rev_a0=((cpuid(1)&0xffff)==0x0f10); + rev_a0= is_cpu_rev_a0(); for (node=0; node<cpus; node++) { u32 val; @@ -479,7 +481,11 @@ static void coherent_ht_finalize(unsigned cpus) pci_write_config32(NODE_HT(node),0x60,val); val=pci_read_config32(NODE_HT(node), 0x68); +#if 1 + val |= 0x00008000; +#else val |= 0x0f00c800; // 0x00008000->0f00c800 BY LYH +#endif pci_write_config32(NODE_HT(node),0x68,val); if (rev_a0) { @@ -508,7 +514,7 @@ static int setup_coherent_ht_domain(void) #endif coherent_ht_finalize(cpus); - /* this should probably go away again. */ + /* FIXME this should probably go away again. */ coherent_ht_mainboard(cpus); return reset_needed; } diff --git a/src/northbridge/amd/amdk8/cpu_rev.c b/src/northbridge/amd/amdk8/cpu_rev.c new file mode 100644 index 0000000000..51f235905e --- /dev/null +++ b/src/northbridge/amd/amdk8/cpu_rev.c @@ -0,0 +1,25 @@ +/* this is a shrunken cpuid. */ + +static unsigned int cpuid(unsigned int op) +{ + unsigned int ret; + unsigned dummy2,dummy3,dummy4; + + asm volatile ( + "cpuid" + : "=a" (ret), "=b" (dummy2), "=c" (dummy3), "=d" (dummy4) + : "a" (op) + ); + + return ret; +} + +static int is_cpu_rev_a0(void) +{ + return (cpuid(1) & 0xffff) == 0x0f10; +} + +static int is_cpu_pre_c0(void) +{ + return (cpuid(1) & 0xffef) < 0x0f48; +} diff --git a/src/northbridge/amd/amdk8/misc_control.c b/src/northbridge/amd/amdk8/misc_control.c index 639e34fbaf..045f5cef06 100644 --- a/src/northbridge/amd/amdk8/misc_control.c +++ b/src/northbridge/amd/amdk8/misc_control.c @@ -8,6 +8,7 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include "./cpu_rev.c" static void misc_control_init(struct device *dev) { @@ -17,7 +18,48 @@ static void misc_control_init(struct device *dev) cmd = pci_read_config32(dev, 0x44); cmd |= (1<<6) | (1<<25); pci_write_config32(dev, 0x44, cmd ); + if (is_cpu_pre_c0()) { + /* errata 58 */ + cmd = pci_read_config32(dev, 0x80); + cmd &= ~(1<<0); + pci_write_config32(dev, 0x80, cmd ); + cmd = pci_read_config32(dev, 0x84); + cmd &= ~(1<<24); + cmd &= ~(1<<8); + pci_write_config32(dev, 0x84, cmd ); + /* errata 66 */ + cmd = pci_read_config32(dev, 0x70); + cmd &= ~(1<<0); + cmd |= (1<<1); + pci_write_config32(dev, 0x70, cmd ); + cmd = pci_read_config32(dev, 0x7c); + cmd &= ~(3<<4); + pci_write_config32(dev, 0x7c, cmd ); + } + else { + /* errata 98 */ +#if 0 + cmd = pci_read_config32(dev, 0xd4); + if(cmd != 0x04e20707) { + cmd = 0x04e20707; + pci_write_config32(dev, 0xd4, cmd ); + hard_reset(); + } +#endif + cmd = 0x04e20707; + pci_write_config32(dev, 0xd4, cmd ); + } +#if 1 + cmd = pci_read_config32(dev, 0xdc); + if((cmd & 0x0000ff00) != 0x02500) { + cmd &= 0xffff00ff; + cmd |= 0x00002500; + pci_write_config32(dev, 0xdc, cmd ); + printk_debug("resetting cpu\n"); + hard_reset(); + } +#endif printk_debug("done.\n"); } diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c index 7bcb1567ba..13845c5a70 100644 --- a/src/northbridge/amd/amdk8/northbridge.c +++ b/src/northbridge/amd/amdk8/northbridge.c @@ -475,6 +475,6 @@ static void enumerate(struct chip *chip) } struct chip_control northbridge_amd_amdk8_control = { - .enumerate = enumerate, .name = "AMD K8 Northbridge", + .enumerate = enumerate, }; diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c index 802e4318b4..437ef2655d 100644 --- a/src/northbridge/amd/amdk8/raminit.c +++ b/src/northbridge/amd/amdk8/raminit.c @@ -124,6 +124,9 @@ #define DCH_MEMCLK_EN3 (1 << 29) /* Function 3 */ +#define MCA_NB_CONFIG 0x44 +#define MNC_ECC_EN (1 << 22) +#define MNC_CHIPKILL_EN (1 << 23) #define SCRUB_CONTROL 0x58 #define SCRUB_NONE 0 #define SCRUB_40ns 1 @@ -1127,23 +1130,6 @@ static void spd_set_ram_size(const struct mem_controller *ctrl) } } -//BY LYH //Fill next base reg with right value -static void fill_last(unsigned long node_id,unsigned long base) -{ - unsigned i; - unsigned base_reg; - base &=0xffff0000; - device_t device; - for(device = PCI_DEV(0, 0x18, 1); device <= PCI_DEV(0, 0x1f, 1); device -+= PCI_DEV(0, 1, 0)) { - for(i=node_id+1;i<=7;i++) { - base_reg=0x40+(i<<3); - pci_write_config32(device,base_reg,base); - } - } -} -//BY LYH END - static void route_dram_accesses(const struct mem_controller *ctrl, unsigned long base_k, unsigned long limit_k) { @@ -1177,7 +1163,12 @@ static void set_top_mem(unsigned tom_k) { /* Error if I don't have memory */ if (!tom_k) { - die("No memory"); + set_bios_reset(); + print_debug("No memory - reset"); + /* enable cf9 */ + pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1); + /* reset */ + outb(0x0e, 0x0cf9); } #if 1 @@ -1204,15 +1195,102 @@ static void set_top_mem(unsigned tom_k) wrmsr(TOP_MEM, msr); } -static void order_dimms(const struct mem_controller *ctrl) +static unsigned long interleave_chip_selects(const struct mem_controller *ctrl) { - unsigned long tom, tom_k, base_k; - unsigned node_id; + /* 35 - 25 */ + static const uint32_t csbase_low[] = { + /* 32MB */ (1 << (13 - 4)), + /* 64MB */ (1 << (14 - 4)), + /* 128MB */ (1 << (14 - 4)), + /* 256MB */ (1 << (15 - 4)), + /* 512MB */ (1 << (15 - 4)), + /* 1GB */ (1 << (16 - 4)), + /* 2GB */ (1 << (16 - 4)), + }; + uint32_t csbase_inc; + int chip_selects, index; + int bits; + int dual_channel; + unsigned common_size; + uint32_t csbase, csmask; + + /* See if all of the memory chip selects are the same size + * and if so count them. + */ + chip_selects = 0; + common_size = 0; + for(index = 0; index < 8; index++) { + unsigned size; + uint32_t value; + + value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2)); + + /* Is it enabled? */ + if (!(value & 1)) { + continue; + } + chip_selects++; + size = value >> 21; + if (common_size == 0) { + common_size = size; + } + /* The size differed fail */ + if (common_size != size) { + return 0; + } + } + /* Chip selects can only be interleaved when there is + * more than one and their is a power of two of them. + */ + bits = log2(chip_selects); + if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) { + return 0; + + } + /* Also we run out of address mask bits if we try and interleave 8 4GB dimms */ + if ((bits == 3) && (common_size == (1 << (32 - 3)))) { + print_debug("8 4GB chip selects cannot be interleaved\r\n"); + return 0; + } + /* Find the bits of csbase that we need to interleave on */ + if (is_dual_channel(ctrl)) { + csbase_inc = csbase_low[log2(common_size) - 1] << 1; + } else { + csbase_inc = csbase_low[log2(common_size)]; + } + /* Compute the initial values for csbase and csbask. + * In csbase just set the enable bit and the base to zero. + * In csmask set the mask bits for the size and page level interleave. + */ + csbase = 0 | 1; + csmask = (((common_size << bits) - 1) << 21); + csmask |= 0xfe00 & ~((csbase_inc << bits) - csbase_inc); + for(index = 0; index < 8; index++) { + uint32_t value; + + value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2)); + /* Is it enabled? */ + if (!(value & 1)) { + continue; + } + pci_write_config32(ctrl->f2, DRAM_CSBASE + (index << 2), csbase); + pci_write_config32(ctrl->f2, DRAM_CSMASK + (index << 2), csmask); + csbase += csbase_inc; + } + +#if 1 + print_debug("Interleaved\r\n"); +#endif + /* Return the memory size in K */ + return common_size << (15 + bits); +} - /* Compute the memory base address address */ - base_k = 0; +static unsigned long order_chip_selects(const struct mem_controller *ctrl) +{ + unsigned long tom; + /* Remember which registers we have used in the high 8 bits of tom */ - tom = base_k >> 15; + tom = 0; for(;;) { /* Find the largest remaining canidate */ unsigned index, canidate; @@ -1270,8 +1348,19 @@ static void order_dimms(const struct mem_controller *ctrl) pci_write_config32(ctrl->f2, DRAM_CSMASK + (canidate << 2), csmask); } - tom_k = (tom & ~0xff000000) << 15; + /* Return the memory size in K */ + return (tom & ~0xff000000) << 15; +} + +static void order_dimms(const struct mem_controller *ctrl) +{ + unsigned long tom, tom_k, base_k; + unsigned node_id; + tom_k = interleave_chip_selects(ctrl); + if (!tom_k) { + tom_k = order_chip_selects(ctrl); + } /* Compute the memory base address */ base_k = 0; for(node_id = 0; node_id < ctrl->node_id; node_id++) { @@ -1287,18 +1376,13 @@ static void order_dimms(const struct mem_controller *ctrl) } tom_k += base_k; #if 0 - print_debug("tom: "); - print_debug_hex32(tom); - print_debug(" base_k: "); + print_debug("base_k: "); print_debug_hex32(base_k); print_debug(" tom_k: "); print_debug_hex32(tom_k); print_debug("\r\n"); #endif route_dram_accesses(ctrl, base_k, tom_k); -//BY LYH - fill_last(ctrl->node_id, tom_k<<2); -//BY LYH END set_top_mem(tom_k); } @@ -2063,6 +2147,10 @@ static void set_read_preamble(const struct mem_controller *ctrl, const struct me /* 166Mhz, 7.5ns */ rdpreamble = ((7 << 1)+1); } + else if (divisor == ((5 << 1)+0)) { + /* 200Mhz, 7ns */ + rdpreamble = ((7 << 1)+0); + } } else { int slots; @@ -2175,6 +2263,8 @@ static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct { int dimms; int i; + int rc; + init_Tref(ctrl, param); for(i = 0; (i < 4) && ctrl->channel0[i]; i++) { int rc; @@ -2247,13 +2337,16 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl) print_debug_hex32(dcl); print_debug("\r\n"); #endif -#warning "FIXME set the ECC type to perform" -#warning "FIXME initialize the scrub registers" -#if 1 if (dcl & DCL_DimmEccEn) { + uint32_t mnc; print_debug("ECC enabled\r\n"); + mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG); + mnc |= MNC_ECC_EN; + if (dcl & DCL_128BitEn) { + mnc |= MNC_CHIPKILL_EN; + } + pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc); } -#endif dcl |= DCL_DisDqsHys; pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); dcl &= ~DCL_DisDqsHys; @@ -2280,29 +2373,148 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl) } else { print_debug(" done\r\n"); } -#if 0 if (dcl & DCL_DimmEccEn) { print_debug("Clearing memory: "); - loops = 0; - dcl &= ~DCL_MemClrStatus; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); + if (!is_cpu_pre_c0()) { + /* Wait until the automatic ram scrubber is finished */ + dcl &= ~(DCL_MemClrStatus | DCL_DramEnable); + pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); + do { + dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); + } while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) ); + } + uint32_t base, last_scrub_k, scrub_k; + uint32_t cnt,zstart,zend; + msr_t msr,msr_201; + + /* First make certain the scrubber is disabled */ + pci_write_config32(ctrl[i].f3, SCRUB_CONTROL, + (SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0)); + + /* load the start and end for the memory block to clear */ + msr_201 = rdmsr(0x201); + zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8)); + zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8)); + zstart >>= 16; + zend >>=16; +#if 1 + print_debug("addr "); + print_debug_hex32(zstart); + print_debug("-"); + print_debug_hex32(zend); + print_debug("\r\n"); +#endif - do { - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - loops += 1; - if ((loops & 1023) == 0) { - print_debug(" "); - print_debug_hex32(loops); - } - } while(((dcl & DCL_MemClrStatus) == 0) && (loops < TIMEOUT_LOOPS)); - if (loops >= TIMEOUT_LOOPS) { - print_debug("failed\r\n"); - } else { - print_debug("done\r\n"); + /* Disable fixed mtrrs */ + msr = rdmsr(MTRRdefType_MSR); + msr.lo &= ~(1<<10); + wrmsr(MTRRdefType_MSR, msr); + + /* turn on the wrap 32 disable */ + msr = rdmsr(0xc0010015); + msr.lo |= (1<<17); + wrmsr(0xc0010015,msr); + + for(;zstart<zend;zstart+=4) { + + /* test for the last 64 meg of 4 gig space */ + if(zstart == 0x0fc) + continue; + + /* disable cache */ + __asm__ volatile( + "movl %%cr0, %0\n\t" + "orl $0x40000000, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + /* Set the variable mtrrs to write combine */ + msr.lo = 1 + ((zstart&0x0ff)<<24); + msr.hi = (zstart&0x0ff00)>>8; + wrmsr(0x200,msr); + + /* Set the limit to 64 meg of ram */ + msr.hi = 0x000000ff; + msr.lo = 0xfc000800; + wrmsr(0x201,msr); + + /* enable cache */ + __asm__ volatile( + "movl %%cr0, %0\n\t" + "andl $0x9fffffff, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + /* Set fs base address */ + msr.lo = (zstart&0xff) << 24; + msr.hi = (zstart&0xff00) >> 8; + wrmsr(0xc0000100,msr); + + print_debug_char((zstart > 0x0ff)?'+':'-'); + + /* clear memory 64meg */ + __asm__ volatile( + "1: \n\t" + "movl %0, %%fs:(%1)\n\t" + "addl $4,%1\n\t" + "subl $1,%2\n\t" + "jnz 1b\n\t" + : + : "a" (0), "D" (0), "c" (0x01000000) + ); } - pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, 0); - pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, 0); + + /* disable cache */ + __asm__ volatile( + "movl %%cr0, %0\n\t" + "orl $0x40000000, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + /* restore msr registers */ + msr = rdmsr(MTRRdefType_MSR); + msr.lo |= 0x0400; + wrmsr(MTRRdefType_MSR, msr); + + /* Restore the variable mtrrs */ + msr.lo = 6; + msr.hi = 0; + wrmsr(0x200,msr); + wrmsr(0x201,msr_201); + + /* Set fs base to 0 */ + msr.lo = 0; + msr.hi = 0; + wrmsr(0xc0000100,msr); + + /* enable cache */ + __asm__ volatile( + "movl %%cr0, %0\n\t" + "andl $0x9fffffff, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + /* turn off the wrap 32 disable */ + msr = rdmsr(0xc0010015); + msr.lo &= ~(1<<17); + wrmsr(0xc0010015,msr); + + /* Find the Srub base address for this cpu */ + base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3)); + base &= 0xffff0000; + + /* Set the scrub base address registers */ + pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, base << 8); + pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, base >> 24); + + /* Enable scrubbing at the lowest possible rate */ + pci_write_config32(ctrl[i].f3, SCRUB_CONTROL, + (SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0)); + + print_debug("done\r\n"); } -#endif } } diff --git a/src/northbridge/via/vt8601/northbridge.c b/src/northbridge/via/vt8601/northbridge.c index 3b655cbdb5..5f5e5d9dd8 100644 --- a/src/northbridge/via/vt8601/northbridge.c +++ b/src/northbridge/via/vt8601/northbridge.c @@ -38,21 +38,21 @@ struct mem_range *sizeram(void) idx++; } for(rambits = 0, i = 0; i < sizeof(ramregs)/sizeof(ramregs[0]); i++) { - unsigned char reg; - reg = pci_read_config8(dev, ramregs[i]); - /* these are ENDING addresses, not sizes. - * if there is memory in this slot, then reg will be > rambits. - * So we just take the max, that gives us total. - * We take the highest one to cover for once and future linuxbios - * bugs. We warn about bugs. - */ - if (reg > rambits) - rambits = reg; - if (reg < rambits) - printk_err("ERROR! register 0x%x is not set!\n", - ramregs[i]); + unsigned char reg; + reg = pci_read_config8(dev, ramregs[i]); + /* these are ENDING addresses, not sizes. + * if there is memory in this slot, then reg will be > rambits. + * So we just take the max, that gives us total. + * We take the highest one to cover for once and future linuxbios + * bugs. We warn about bugs. + */ + if (reg > rambits) + rambits = reg; + if (reg < rambits) + printk_err("ERROR! register 0x%x is not set!\n", + ramregs[i]); } - + printk_debug("I would set ram size to 0x%x Kbytes\n", (rambits)*8*1024); mem[0].sizek = rambits*8*1024; #if 1 @@ -77,48 +77,46 @@ static void enumerate(struct chip *chip) * slower than normal, ethernet drops packets). * Apparently these registers govern some sort of bus master behavior. */ -static void -random_fixup() { - device_t pcidev = dev_find_slot(0, 0); +static void random_fixup() { + device_t pcidev = dev_find_slot(0, 0); - printk_spew("VT8601 random fixup ...\n"); - if (pcidev) { - pci_write_config8(pcidev, 0x70, 0xc0); - pci_write_config8(pcidev, 0x71, 0x88); - pci_write_config8(pcidev, 0x72, 0xec); - pci_write_config8(pcidev, 0x73, 0x0c); - pci_write_config8(pcidev, 0x74, 0x0e); - pci_write_config8(pcidev, 0x75, 0x81); - pci_write_config8(pcidev, 0x76, 0x52); - } + printk_spew("VT8601 random fixup ...\n"); + if (pcidev) { + pci_write_config8(pcidev, 0x70, 0xc0); + pci_write_config8(pcidev, 0x71, 0x88); + pci_write_config8(pcidev, 0x72, 0xec); + pci_write_config8(pcidev, 0x73, 0x0c); + pci_write_config8(pcidev, 0x74, 0x0e); + pci_write_config8(pcidev, 0x75, 0x81); + pci_write_config8(pcidev, 0x76, 0x52); + } } -static void -northbridge_init(struct chip *chip, enum chip_pass pass) +static void northbridge_init(struct chip *chip, enum chip_pass pass) { - struct northbridge_via_vt8601_config *conf = - (struct northbridge_via_vt8601_config *)chip->chip_info; - - switch (pass) { - case CONF_PASS_PRE_PCI: - break; + struct northbridge_via_vt8601_config *conf = + (struct northbridge_via_vt8601_config *)chip->chip_info; - case CONF_PASS_POST_PCI: - break; - - case CONF_PASS_PRE_BOOT: - random_fixup(); - break; - - default: - /* nothing yet */ - break; - } + switch (pass) { + case CONF_PASS_PRE_PCI: + break; + + case CONF_PASS_POST_PCI: + break; + + case CONF_PASS_PRE_BOOT: + random_fixup(); + break; + + default: + /* nothing yet */ + break; + } } struct chip_control northbridge_via_vt8601_control = { .enumerate = enumerate, - enable: northbridge_init, - .name = "VIA vt8601 Northbridge", + .enable = northbridge_init, + .name = "VIA vt8601 Northbridge", }; diff --git a/src/pc80/vgabios.c b/src/pc80/vgabios.c index 05e3ce33ed..9aebf1d35c 100644 --- a/src/pc80/vgabios.c +++ b/src/pc80/vgabios.c @@ -66,86 +66,86 @@ /* The address arguments to this function are PHYSICAL ADDRESSES */ static void real_mode_switch_call_vga(unsigned long devfn) { - __asm__ __volatile__ - ( - // paranoia -- does ecx get saved? not sure. This is - // the easiest safe thing to do. - "pushal\n" - /* save the stack */ - "mov %esp, __stack\n" - "jmp 1f\n" - "__stack: .long 0\n" - "1:\n" - /* get devfn into %ecx */ - "movl %esp, %ebp\n" - "movl 8(%ebp), %ecx\n" - /* This configures CS properly for real mode. */ - " ljmp $0x28, $__rms_16bit\n" - "__rms_16bit: \n" - ".code16 \n" /* 16 bit code from here on... */ - - /* Load the segment registers w/ properly configured segment - * descriptors. They will retain these configurations (limits, - * writability, etc.) once protected mode is turned off. */ - " mov $0x30, %ax \n" - " mov %ax, %ds \n" - " mov %ax, %es \n" - " mov %ax, %fs \n" - " mov %ax, %gs \n" - " mov %ax, %ss \n" - - /* Turn off protection (bit 0 in CR0) */ - " movl %cr0, %eax \n" - " andl $0xFFFFFFFE, %eax \n" - " movl %eax, %cr0 \n" - - /* Now really going into real mode */ - " ljmp $0, $__rms_real \n" - "__rms_real: \n" - - // put the stack at the end of page zero. - // that way we can easily share it between real and protected, - // since the 16-bit ESP at segment 0 will work for any case. - /* Setup a stack */ - " mov $0x0, %ax \n" - " mov %ax, %ss \n" - " movl $0x1000, %eax \n" - " movl %eax, %esp \n" - /* debugging for RGM */ - " mov $0x11, %al \n" - " outb %al, $0x80\n" - - /* Dump zeros in the other segregs */ - " xor %ax, %ax \n" - " mov %ax, %ds \n" - " mov %ax, %es \n" - " mov %ax, %fs \n" - " mov %ax, %gs \n" - " mov %cx, %ax \n" - " .byte 0x9a, 0x03, 0, 0, 0xc0 \n" - " movb $0x55, %al\noutb %al, $0x80\n" - /* if we got here, just about done. - * Need to get back to protected mode */ - "movl %cr0, %eax\n" - // "andl $0x7FFAFFD1, %eax\n" /* PG,AM,WP,NE,TS,EM,MP = 0 */ - // "orl $0x60000001, %eax\n" /* CD, NW, PE = 1 */ - "orl $0x0000001, %eax\n" /* PE = 1 */ - "movl %eax, %cr0\n" - /* Now that we are in protected mode jump to a 32 bit code segment. */ - "data32 ljmp $0x10, $vgarestart\n" - "vgarestart:\n" - ".code32\n" - " movw $0x18, %ax \n" - " mov %ax, %ds \n" - " mov %ax, %es \n" - " mov %ax, %fs \n" - " mov %ax, %gs \n" - " mov %ax, %ss \n" - ".globl vga_exit\n" - "vga_exit:\n" - " mov __stack, %esp\n" - " popal\n" - ); + __asm__ __volatile__ + ( + // paranoia -- does ecx get saved? not sure. This is + // the easiest safe thing to do. + "pushal\n" + /* save the stack */ + "mov %esp, __stack\n" + "jmp 1f\n" + "__stack: .long 0\n" + "1:\n" + /* get devfn into %ecx */ + "movl %esp, %ebp\n" + "movl 8(%ebp), %ecx\n" + /* This configures CS properly for real mode. */ + " ljmp $0x28, $__rms_16bit\n" + "__rms_16bit: \n" + ".code16 \n" /* 16 bit code from here on... */ + + /* Load the segment registers w/ properly configured segment + * descriptors. They will retain these configurations (limits, + * writability, etc.) once protected mode is turned off. */ + " mov $0x30, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + + /* Turn off protection (bit 0 in CR0) */ + " movl %cr0, %eax \n" + " andl $0xFFFFFFFE, %eax \n" + " movl %eax, %cr0 \n" + + /* Now really going into real mode */ + " ljmp $0, $__rms_real \n" + "__rms_real: \n" + + // put the stack at the end of page zero. + // that way we can easily share it between real and protected, + // since the 16-bit ESP at segment 0 will work for any case. + /* Setup a stack */ + " mov $0x0, %ax \n" + " mov %ax, %ss \n" + " movl $0x1000, %eax \n" + " movl %eax, %esp \n" + /* debugging for RGM */ + " mov $0x11, %al \n" + " outb %al, $0x80\n" + + /* Dump zeros in the other segregs */ + " xor %ax, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %cx, %ax \n" + " .byte 0x9a, 0x03, 0, 0, 0xc0 \n" + " movb $0x55, %al\noutb %al, $0x80\n" + /* if we got here, just about done. + * Need to get back to protected mode */ + "movl %cr0, %eax\n" + // "andl $0x7FFAFFD1, %eax\n" /* PG,AM,WP,NE,TS,EM,MP = 0 */ + // "orl $0x60000001, %eax\n" /* CD, NW, PE = 1 */ + "orl $0x0000001, %eax\n" /* PE = 1 */ + "movl %eax, %cr0\n" + /* Now that we are in protected mode jump to a 32 bit code segment. */ + "data32 ljmp $0x10, $vgarestart\n" + "vgarestart:\n" + ".code32\n" + " movw $0x18, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + ".globl vga_exit\n" + "vga_exit:\n" + " mov __stack, %esp\n" + " popal\n" + ); } __asm__ (".text\n""real_mode_switch_end:\n"); extern char real_mode_switch_end[]; @@ -153,53 +153,53 @@ extern char real_mode_switch_end[]; void do_vgabios(void) { - struct pci_dev *dev; - unsigned long busdevfn; - unsigned int rom = 0; - unsigned char *buf; - unsigned int size = 64*1024; - int i; - - for (i=0x400; i<0x500; i++) { - printk_debug("%02x%c", *(unsigned char *)i, i%16==15 ? '\n' : ' '); - *(unsigned char *) i = 0; - } - - for (i=0x400; i<0x500; i++) { - printk_debug("%02x%c", *(unsigned char *)i, i%16==15 ? '\n' : ' '); - } - - dev = pci_find_class(PCI_CLASS_DISPLAY_VGA <<8, NULL); - - if (! dev) { - printk_debug("NO VGA FOUND\n"); - return; - } - printk_debug("found VGA: vid=%x, did=%x\n", dev->vendor, dev->device); - + struct pci_dev *dev; + unsigned long busdevfn; + unsigned int rom = 0; + unsigned char *buf; + unsigned int size = 64*1024; + int i; + + for (i=0x400; i<0x500; i++) { + printk_debug("%02x%c", *(unsigned char *)i, i%16==15 ? '\n' : ' '); + *(unsigned char *) i = 0; + } + + for (i=0x400; i<0x500; i++) { + printk_debug("%02x%c", *(unsigned char *)i, i%16==15 ? '\n' : ' '); + } + + dev = pci_find_class(PCI_CLASS_DISPLAY_VGA <<8, NULL); + + if (! dev) { + printk_debug("NO VGA FOUND\n"); + return; + } + printk_debug("found VGA: vid=%x, did=%x\n", dev->vendor, dev->device); + #ifdef VGABIOS_START - // Use VGA BIOS blob at specified address - rom = VGABIOS_START; + // Use VGA BIOS blob at specified address + rom = VGABIOS_START; #else - pci_read_config32(dev, PCI_ROM_ADDRESS, &rom); - // paranoia - rom = 0xf0000000; - pci_write_config32(dev, PCI_ROM_ADDRESS, rom|1); - printk_debug("rom base, size: %x\n", rom); + pci_read_config32(dev, PCI_ROM_ADDRESS, &rom); + // paranoia + rom = 0xf0000000; + pci_write_config32(dev, PCI_ROM_ADDRESS, rom|1); + printk_debug("rom base, size: %x\n", rom); #endif - buf = (unsigned char *) rom; - if ((buf[0] == 0x55) && (buf[1] = 0xaa)) { - memcpy((void *) 0xc0000, buf, size); - - for(i = 0; i < 16; i++) - printk_debug("0x%x ", buf[i]); - // check signature here later! - busdevfn = (dev->bus->secondary << 8) | dev->devfn; - real_mode_switch_call_vga(busdevfn); - } else - printk_debug("BAD SIGNATURE 0x%x 0x%x\n", buf[0], buf[1]); + buf = (unsigned char *) rom; + if ((buf[0] == 0x55) && (buf[1] = 0xaa)) { + memcpy((void *) 0xc0000, buf, size); + + for(i = 0; i < 16; i++) + printk_debug("0x%x ", buf[i]); + // check signature here later! + busdevfn = (dev->bus->secondary << 8) | dev->devfn; + real_mode_switch_call_vga(busdevfn); + } else + printk_debug("BAD SIGNATURE 0x%x 0x%x\n", buf[0], buf[1]); #ifndef VGABIOS_START - pci_write_config32(dev, PCI_ROM_ADDRESS, 0); + pci_write_config32(dev, PCI_ROM_ADDRESS, 0); #endif } @@ -209,7 +209,7 @@ do_vgabios(void) // to the BIOS. // no longer. Dammit. We have to respond to these. struct realidt { - unsigned short offset, cs; + unsigned short offset, cs; }; // from a handy writeup that andrey found. @@ -228,15 +228,15 @@ struct realidt { // have to do address fixup in this little stub, and calls are absolute // so the handler is relocatable. void handler(void) { - __asm__ __volatile__ ( - ".code16\n" - "idthandle:\n" - " pushal\n" - " movb $0, %al\n" - " ljmp $0, $callbiosint16\n" - "end_idthandle:\n" - ".code32\n" - ); + __asm__ __volatile__ ( + ".code16\n" + "idthandle:\n" + " pushal\n" + " movb $0, %al\n" + " ljmp $0, $callbiosint16\n" + "end_idthandle:\n" + ".code32\n" + ); } @@ -247,79 +247,79 @@ void handler(void) { // REFERENCE parameters. In this way, we can easily get // returns back to the INTx caller (i.e. vgabios) void callbiosint(void) { - __asm__ __volatile__ ( - ".code16\n" - "callbiosint16:\n" - // clean up the int #. To save space we put it in the lower - // byte. But the top 24 bits are junk. - "andl $0xff, %eax\n" - // this push does two things: - // - put the INT # on the stack as a parameter - // - provides us with a temp for the %cr0 mods. - "pushl %eax\n" - "movl %cr0, %eax\n" - //"andl $0x7FFAFFD1, %eax\n" /* PG,AM,WP,NE,TS,EM,MP = 0 */ - //"orl $0x60000001, %eax\n" /* CD, NW, PE = 1 */ - "orl $0x00000001, %eax\n" /* PE = 1 */ - "movl %eax, %cr0\n" - /* Now that we are in protected mode jump to a 32 bit code segment. */ - "data32 ljmp $0x10, $biosprotect\n" - "biosprotect:\n" - ".code32\n" - " movw $0x18, %ax \n" - " mov %ax, %ds \n" - " mov %ax, %es \n" - " mov %ax, %fs \n" - " mov %ax, %gs \n" - " mov %ax, %ss \n" - " call biosint \n" - // back to real mode ... - " ljmp $0x28, $__rms_16bit\n" - "__rms_16bit: \n" - ".code16 \n" /* 16 bit code from here on... */ - - /* Load the segment registers w/ properly configured segment - * descriptors. They will retain these configurations (limits, - * writability, etc.) once protected mode is turned off. */ - " mov $0x30, %ax \n" - " mov %ax, %ds \n" - " mov %ax, %es \n" - " mov %ax, %fs \n" - " mov %ax, %gs \n" - " mov %ax, %ss \n" - - /* Turn off protection (bit 0 in CR0) */ - " movl %cr0, %eax \n" - " andl $0xFFFFFFFE, %eax \n" - " movl %eax, %cr0 \n" - - /* Now really going into real mode */ - " ljmp $0, $__rms_real \n" - "__rms_real: \n" - - /* Setup a stack */ - " mov $0x0, %ax \n" - " mov %ax, %ss \n" - /* ebugging for RGM */ - " mov $0x11, %al \n" - " outb %al, $0x80\n" - " xor %ax, %ax \n" - " mov %ax, %ds \n" - " mov %ax, %es \n" - " mov %ax, %fs \n" - " mov %ax, %gs \n" - // pop the INT # that you pushed earlier - " popl %eax\n" - " popal\n" - " iret\n" - ".code32\n" - ); + __asm__ __volatile__ ( + ".code16\n" + "callbiosint16:\n" + // clean up the int #. To save space we put it in the lower + // byte. But the top 24 bits are junk. + "andl $0xff, %eax\n" + // this push does two things: + // - put the INT # on the stack as a parameter + // - provides us with a temp for the %cr0 mods. + "pushl %eax\n" + "movl %cr0, %eax\n" + //"andl $0x7FFAFFD1, %eax\n" /* PG,AM,WP,NE,TS,EM,MP = 0 */ + //"orl $0x60000001, %eax\n" /* CD, NW, PE = 1 */ + "orl $0x00000001, %eax\n" /* PE = 1 */ + "movl %eax, %cr0\n" + /* Now that we are in protected mode jump to a 32 bit code segment. */ + "data32 ljmp $0x10, $biosprotect\n" + "biosprotect:\n" + ".code32\n" + " movw $0x18, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + " call biosint \n" + // back to real mode ... + " ljmp $0x28, $__rms_16bit\n" + "__rms_16bit: \n" + ".code16 \n" /* 16 bit code from here on... */ + + /* Load the segment registers w/ properly configured segment + * descriptors. They will retain these configurations (limits, + * writability, etc.) once protected mode is turned off. */ + " mov $0x30, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + " mov %ax, %ss \n" + + /* Turn off protection (bit 0 in CR0) */ + " movl %cr0, %eax \n" + " andl $0xFFFFFFFE, %eax \n" + " movl %eax, %cr0 \n" + + /* Now really going into real mode */ + " ljmp $0, $__rms_real \n" + "__rms_real: \n" + + /* Setup a stack */ + " mov $0x0, %ax \n" + " mov %ax, %ss \n" + /* ebugging for RGM */ + " mov $0x11, %al \n" + " outb %al, $0x80\n" + " xor %ax, %ax \n" + " mov %ax, %ds \n" + " mov %ax, %es \n" + " mov %ax, %fs \n" + " mov %ax, %gs \n" + // pop the INT # that you pushed earlier + " popl %eax\n" + " popal\n" + " iret\n" + ".code32\n" + ); } enum { - PCIBIOS = 0x1a, - MEMSIZE = 0x12 + PCIBIOS = 0x1a, + MEMSIZE = 0x12 }; int pcibios( @@ -350,116 +350,116 @@ biosint( unsigned long cs_ip, unsigned short stackflags ) { - unsigned long ip; - unsigned long cs; - unsigned long flags; - int ret = -1; - - ip = cs_ip & 0xffff; - cs = cs_ip >> 16; - flags = stackflags; - - printk_debug("biosint: # 0x%lx, eax 0x%lx ebx 0x%lx ecx 0x%lx edx 0x%lx\n", - intnumber, eax, ebx, ecx, edx); - printk_debug("biosint: ebp 0x%lx esp 0x%lx edi 0x%lx esi 0x%lx\n", ebp, esp, edi, esi); - printk_debug("biosint: ip 0x%x cs 0x%x flags 0x%x\n", ip, cs, flags); - // cases in a good compiler are just as good as your own tables. - switch (intnumber) { - case 0 ... 15: - // These are not BIOS service, but the CPU-generated exceptions - printk_info("biosint: Oops, exception %u\n", intnumber); - if (esp < 0x1000) { - printk_debug("Stack contents: "); - while (esp < 0x1000) { - printk_debug("0x%04x ", *(unsigned short *) esp); - esp += 2; - } - printk_debug("\n"); - } - printk_debug("biosint: Bailing out\n"); - // "longjmp" - vga_exit(); - break; - - case PCIBIOS: - ret = pcibios( &edi, &esi, &ebp, &esp, - &ebx, &edx, &ecx, &eax, &flags); - break; - case MEMSIZE: - // who cares. - eax = 64 * 1024; - ret = 0; - break; - default: - printk_info(__FUNCTION__ ": Unsupport int #0x%x\n", - intnumber); - break; - } - if (ret) - flags |= 1; // carry flags - else - flags &= ~1; - stackflags = flags; - return ret; + unsigned long ip; + unsigned long cs; + unsigned long flags; + int ret = -1; + + ip = cs_ip & 0xffff; + cs = cs_ip >> 16; + flags = stackflags; + + printk_debug("biosint: # 0x%lx, eax 0x%lx ebx 0x%lx ecx 0x%lx edx 0x%lx\n", + intnumber, eax, ebx, ecx, edx); + printk_debug("biosint: ebp 0x%lx esp 0x%lx edi 0x%lx esi 0x%lx\n", ebp, esp, edi, esi); + printk_debug("biosint: ip 0x%x cs 0x%x flags 0x%x\n", ip, cs, flags); + // cases in a good compiler are just as good as your own tables. + switch (intnumber) { + case 0 ... 15: + // These are not BIOS service, but the CPU-generated exceptions + printk_info("biosint: Oops, exception %u\n", intnumber); + if (esp < 0x1000) { + printk_debug("Stack contents: "); + while (esp < 0x1000) { + printk_debug("0x%04x ", *(unsigned short *) esp); + esp += 2; + } + printk_debug("\n"); + } + printk_debug("biosint: Bailing out\n"); + // "longjmp" + vga_exit(); + break; + + case PCIBIOS: + ret = pcibios( &edi, &esi, &ebp, &esp, + &ebx, &edx, &ecx, &eax, &flags); + break; + case MEMSIZE: + // who cares. + eax = 64 * 1024; + ret = 0; + break; + default: + printk_info(__FUNCTION__ ": Unsupport int #0x%x\n", + intnumber); + break; + } + if (ret) + flags |= 1; // carry flags + else + flags &= ~1; + stackflags = flags; + return ret; } -void -setup_realmode_idt(void) { - extern unsigned char idthandle, end_idthandle; - int i; - struct realidt *idts = (struct realidt *) 0; - int codesize = &end_idthandle - &idthandle; - unsigned char *intbyte, *codeptr; - - // for each int, we create a customized little handler - // that just pushes %ax, puts the int # in %al, - // then calls the common interrupt handler. - // this necessitated because intel didn't know much about - // architecture when they did the 8086 (it shows) - // (hmm do they know anymore even now :-) - // obviously you can see I don't really care about memory - // efficiency. If I did I would probe back through the stack - // and get it that way. But that's really disgusting. - for (i = 0; i < 256; i++) { - idts[i].cs = 0; - codeptr = (char*) 4096 + i * codesize; - idts[i].offset = (unsigned) codeptr; - memcpy(codeptr, &idthandle, codesize); - intbyte = codeptr + 3; - *intbyte = i; - } - - // fixed entry points - - // VGA BIOSes tend to hardcode f000:f065 as the previous handler of - // int10. - // calling convention here is the same as INTs, we can reuse - // the int entry code. - codeptr = (char*) 0xff065; - memcpy(codeptr, &idthandle, codesize); - intbyte = codeptr + 3; - *intbyte = 0x42; /* int42 is the relocated int10 */ +void setup_realmode_idt(void) +{ + extern unsigned char idthandle, end_idthandle; + int i; + struct realidt *idts = (struct realidt *) 0; + int codesize = &end_idthandle - &idthandle; + unsigned char *intbyte, *codeptr; + + // for each int, we create a customized little handler + // that just pushes %ax, puts the int # in %al, + // then calls the common interrupt handler. + // this necessitated because intel didn't know much about + // architecture when they did the 8086 (it shows) + // (hmm do they know anymore even now :-) + // obviously you can see I don't really care about memory + // efficiency. If I did I would probe back through the stack + // and get it that way. But that's really disgusting. + for (i = 0; i < 256; i++) { + idts[i].cs = 0; + codeptr = (char*) 4096 + i * codesize; + idts[i].offset = (unsigned) codeptr; + memcpy(codeptr, &idthandle, codesize); + intbyte = codeptr + 3; + *intbyte = i; + } + + // fixed entry points + + // VGA BIOSes tend to hardcode f000:f065 as the previous handler of + // int10. + // calling convention here is the same as INTs, we can reuse + // the int entry code. + codeptr = (char*) 0xff065; + memcpy(codeptr, &idthandle, codesize); + intbyte = codeptr + 3; + *intbyte = 0x42; /* int42 is the relocated int10 */ } enum { - CHECK = 0xb001, - FINDDEV = 0xb102, - READCONFBYTE = 0xb108, - READCONFWORD = 0xb109, - READCONFDWORD = 0xb10a, - WRITECONFBYTE = 0xb10b, - WRITECONFWORD = 0xb10c, - WRITECONFDWORD = 0xb10d + CHECK = 0xb001, + FINDDEV = 0xb102, + READCONFBYTE = 0xb108, + READCONFWORD = 0xb109, + READCONFDWORD = 0xb10a, + WRITECONFBYTE = 0xb10b, + WRITECONFWORD = 0xb10c, + WRITECONFDWORD = 0xb10d }; // errors go in AH. Just set these up so that word assigns // will work. KISS. enum { - PCIBIOS_NODEV = 0x8600, - PCIBIOS_BADREG = 0x8700 + PCIBIOS_NODEV = 0x8600, + PCIBIOS_BADREG = 0x8700 }; int @@ -474,145 +474,144 @@ pcibios( unsigned long *peax, unsigned long *pflags ) { - unsigned long edi = *pedi; - unsigned long esi = *pesi; - unsigned long ebp = *pebp; - unsigned long esp = *pesp; - unsigned long ebx = *pebx; - unsigned long edx = *pedx; - unsigned long ecx = *pecx; - unsigned long eax = *peax; - unsigned long flags = *pflags; - unsigned short func = (unsigned short) eax; - int retval = 0; - unsigned short devid, vendorid, devfn; - short devindex; /* Use short to get rid of gabage in upper half of 32-bit register */ - unsigned char bus; - struct pci_dev *dev; - - switch(func) { - case CHECK: - *pedx = 0x4350; - *pecx = 0x2049; - retval = 0; - break; - case FINDDEV: - { - devid = *pecx; - vendorid = *pedx; - devindex = *pesi; - dev = 0; - while ((dev = pci_find_device(vendorid, devid, dev))) { - if (devindex <= 0) - break; - devindex--; - } - if (dev) { - unsigned short busdevfn; - *peax = 0; - // busnum is an unsigned char; - // devfn is an int, so we mask it off. - busdevfn = (dev->bus->secondary << 8) - | (dev->devfn & 0xff); - printk_debug("0x%x: return 0x%x\n", func, busdevfn); - *pebx = busdevfn; - retval = 0; - } else { - *peax = PCIBIOS_NODEV; - retval = -1; - } - } - break; - case READCONFDWORD: - case READCONFWORD: - case READCONFBYTE: - case WRITECONFDWORD: - case WRITECONFWORD: - case WRITECONFBYTE: - { - unsigned long dword; - unsigned short word; - unsigned char byte; - unsigned char reg; - - devfn = *pebx & 0xff; - bus = *pebx >> 8; - reg = *pedi; - dev = pci_find_slot(bus, devfn); - if (! dev) { - printk_debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn); - // idiots. the pcibios guys assumed you'd never pass a bad bus/devfn! - *peax = PCIBIOS_BADREG; - retval = -1; - } - switch(func) { - case READCONFBYTE: - byte = pci_read_config8(dev, reg); - *pecx = byte; - break; - case READCONFWORD: - word = pci_read_config16(dev, reg); - *pecx = word; - break; - case READCONFDWORD: - dword = pci_read_config32(dev, reg); - *pecx = dword; + unsigned long edi = *pedi; + unsigned long esi = *pesi; + unsigned long ebp = *pebp; + unsigned long esp = *pesp; + unsigned long ebx = *pebx; + unsigned long edx = *pedx; + unsigned long ecx = *pecx; + unsigned long eax = *peax; + unsigned long flags = *pflags; + unsigned short func = (unsigned short) eax; + int retval = 0; + unsigned short devid, vendorid, devfn; + short devindex; /* Use short to get rid of gabage in upper half of 32-bit register */ + unsigned char bus; + struct pci_dev *dev; + + switch(func) { + case CHECK: + *pedx = 0x4350; + *pecx = 0x2049; + retval = 0; + break; + case FINDDEV: + { + devid = *pecx; + vendorid = *pedx; + devindex = *pesi; + dev = 0; + while ((dev = pci_find_device(vendorid, devid, dev))) { + if (devindex <= 0) + break; + devindex--; + } + if (dev) { + unsigned short busdevfn; + *peax = 0; + // busnum is an unsigned char; + // devfn is an int, so we mask it off. + busdevfn = (dev->bus->secondary << 8) + | (dev->devfn & 0xff); + printk_debug("0x%x: return 0x%x\n", func, busdevfn); + *pebx = busdevfn; + retval = 0; + } else { + *peax = PCIBIOS_NODEV; + retval = -1; + } + } break; - case WRITECONFBYTE: - byte = *pecx; - write_config8(dev, reg, byte); - break; - case WRITECONFWORD: - word = *pecx; - write_config16(dev, reg, word); - break; - case WRITECONFDWORD: - word = *pecx; - write_config32(dev, reg, dword); + case READCONFDWORD: + case READCONFWORD: + case READCONFBYTE: + case WRITECONFDWORD: + case WRITECONFWORD: + case WRITECONFBYTE: + { + unsigned long dword; + unsigned short word; + unsigned char byte; + unsigned char reg; + + devfn = *pebx & 0xff; + bus = *pebx >> 8; + reg = *pedi; + dev = pci_find_slot(bus, devfn); + if (! dev) { + printk_debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn); + // idiots. the pcibios guys assumed you'd never pass a bad bus/devfn! + *peax = PCIBIOS_BADREG; + retval = -1; + } + switch(func) { + case READCONFBYTE: + byte = pci_read_config8(dev, reg); + *pecx = byte; + break; + case READCONFWORD: + word = pci_read_config16(dev, reg); + *pecx = word; + break; + case READCONFDWORD: + dword = pci_read_config32(dev, reg); + *pecx = dword; + break; + case WRITECONFBYTE: + byte = *pecx; + write_config8(dev, reg, byte); + break; + case WRITECONFWORD: + word = *pecx; + write_config16(dev, reg, word); + break; + case WRITECONFDWORD: + word = *pecx; + write_config32(dev, reg, dword); + break; + } + + if (retval) + retval = PCIBIOS_BADREG; + printk_debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n", func, bus, devfn, reg, *pecx); + *peax = 0; + retval = 0; + } break; - } - - if (retval) - retval = PCIBIOS_BADREG; - printk_debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n", func, bus, devfn, reg, *pecx); - *peax = 0; - retval = 0; - } - break; - default: - printk_err("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func); - break; - } - - return retval; + default: + printk_err("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func); + break; + } + + return retval; } -static void -vga_init(struct chip *chip, enum chip_pass pass) +static void vga_init(struct chip *chip, enum chip_pass pass) { - struct pc80_vgabios_config *conf = - (struct pc80_vgabios_config *)chip->chip_info; - - switch (pass) { - case CONF_PASS_PRE_BOOT: - - break; - - default: - /* nothing yet */ - break; - } + struct pc80_vgabios_config *conf = + (struct pc80_vgabios_config *)chip->chip_info; + + switch (pass) { + case CONF_PASS_PRE_BOOT: + + break; + + default: + /* nothing yet */ + break; + } } static void enumerate(struct chip *chip) { - /* don't really need to do anything */ + /* don't really need to do anything */ } struct chip_control southbridge_via_vt8231_control = { - .enumerate = enumerate, - enable: vga_init, - name: "Legacy VGA bios" + .enumerate = enumerate, + .enable = vga_init, + .name = "Legacy VGA bios" }; diff --git a/src/pc80/vgachip.h b/src/pc80/vgachip.h index 02124b3df3..d43788cd66 100644 --- a/src/pc80/vgachip.h +++ b/src/pc80/vgachip.h @@ -4,7 +4,7 @@ extern struct chip_control pc80_vgabios_control; struct pc80_vgabios_config { - int nothing; + int nothing; }; #endif /* _PC80_VGABIOS */ diff --git a/src/southbridge/amd/amd8111/Config.lb b/src/southbridge/amd/amd8111/Config.lb index f8f38a9964..904b0995b5 100644 --- a/src/southbridge/amd/amd8111/Config.lb +++ b/src/southbridge/amd/amd8111/Config.lb @@ -1,5 +1,9 @@ +config amd8111.h +driver amd8111.o driver amd8111_usb.o driver amd8111_lpc.o driver amd8111_ide.o driver amd8111_acpi.o driver amd8111_usb2.o +#driver amd8111_ac97.o +#driver amd8111_nic.o diff --git a/src/southbridge/amd/amd8111/amd8111.c b/src/southbridge/amd/amd8111/amd8111.c new file mode 100644 index 0000000000..8dde5f13c6 --- /dev/null +++ b/src/southbridge/amd/amd8111/amd8111.c @@ -0,0 +1,56 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/chip.h> +#include "amd8111.h" + +void amd8111_enable(device_t dev) +{ + device_t lpc_dev; + device_t bus_dev; + unsigned index; + uint16_t reg_old, reg; + + /* See if we are on the behind the amd8111 pci bridge */ + bus_dev = dev->bus->dev; + if ((bus_dev->vendor == PCI_VENDOR_ID_AMD) && + (bus_dev->device == PCI_DEVICE_ID_AMD_8111_PCI)) { + unsigned devfn; + devfn = bus_dev->path.u.pci.devfn + (1 << 3); + lpc_dev = dev_find_slot(bus_dev->bus->secondary, devfn); + index = ((dev->path.u.pci.devfn & ~7) >> 3) + 8; + } else { + unsigned devfn; + devfn = (dev->path.u.pci.devfn) & ~7; + lpc_dev = dev_find_slot(dev->bus->secondary, devfn); + index = dev->path.u.pci.devfn & 7; + } + if ((!lpc_dev) || (index >= 16) || + (lpc_dev->vendor != PCI_VENDOR_ID_AMD) || + (lpc_dev->device != PCI_DEVICE_ID_AMD_8111_ISA)) { + return; + } + + reg = reg_old = pci_read_config16(lpc_dev, 0x48); + reg &= ~(1 << index); + if (dev->enable) { + reg |= (1 << index); + } + if (reg != reg_old) { +#if 1 + printk_warning("amd8111_enable dev: %s", dev_path(dev)); + printk_warning(" lpc_dev: %s index: %d reg: %04x -> %04x ", + dev_path(lpc_dev), index, reg_old, reg); +#endif + pci_write_config16(lpc_dev, 0x48, reg); +#if 1 + printk_warning("done\n"); +#endif + } +} + +struct chip_control southbridge_amd_amd8111_control = { + .name = "AMD 8111", + .enable_dev = amd8111_enable, +}; diff --git a/src/southbridge/amd/amd8111/amd8111.h b/src/southbridge/amd/amd8111/amd8111.h new file mode 100644 index 0000000000..10e152954f --- /dev/null +++ b/src/southbridge/amd/amd8111/amd8111.h @@ -0,0 +1,12 @@ +#ifndef AMD8111_H +#define AMD8111_H + +struct southbridge_amd_amd8111_config +{ +}; +struct chip_control; +extern struct chip_control southbridge_amd_amd8111_control; + +void amd8111_enable(device_t dev); + +#endif /* AMD8111_H */ diff --git a/src/southbridge/amd/amd8111/amd8111_ac97.c b/src/southbridge/amd/amd8111/amd8111_ac97.c new file mode 100644 index 0000000000..63a0e1264e --- /dev/null +++ b/src/southbridge/amd/amd8111/amd8111_ac97.c @@ -0,0 +1,41 @@ +/* + * (C) 2003 Linux Networx + */ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "amd8111.h" + + +static struct device_operations ac97audio_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .enable = amd8111_enable, + .init = 0, + .scan_bus = 0, +}; + +static struct pci_driver ac97audio_driver __pci_driver = { + .ops = &ac97audio_ops, + .vendor = PCI_VENDOR_ID_AMD, + .device = 0x746D, +}; + + +static struct device_operations ac97modem_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .enable = amd8111_enable, + .init = 0, + .scan_bus = 0, +}; + +static struct pci_driver ac97modem_driver __pci_driver = { + .ops = &ac97modem_ops, + .vendor = PCI_VENDOR_ID_AMD, + .device = 0x746E, +}; diff --git a/src/southbridge/amd/amd8111/amd8111_acpi.c b/src/southbridge/amd/amd8111/amd8111_acpi.c index 5fa6fdce29..3a5a594f57 100644 --- a/src/southbridge/amd/amd8111/amd8111_acpi.c +++ b/src/southbridge/amd/amd8111/amd8111_acpi.c @@ -3,11 +3,23 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include <pc80/mc146818rtc.h> +#include "amd8111.h" + +#define PREVIOUS_POWER_STATE 0x43 +#define MAINBOARD_POWER_OFF 0 +#define MAINBOARD_POWER_ON 1 + +#ifndef MAINBOARD_POWER_ON_AFTER_POWER_FAIL +#define MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON +#endif + static void acpi_init(struct device *dev) { uint8_t byte; uint16_t word; + int on; #if 0 printk_debug("ACPI: disabling NMI watchdog.. "); @@ -35,6 +47,15 @@ static void acpi_init(struct device *dev) pci_write_config_dword(dev, 0x60, 0x06800000); printk_debug("done.\n"); #endif + on = MAINBOARD_POWER_ON_AFTER_POWER_FAIL; + get_option(&on, "power_on_after_fail"); + byte = pci_read_config8(dev, PREVIOUS_POWER_STATE); + byte &= ~0x40; + if (!on) { + byte |= 0x40; + } + pci_write_config8(dev, PREVIOUS_POWER_STATE, byte); + printk_info("set power %s after power fail\n", on?"on":"off"); } @@ -42,8 +63,9 @@ static struct device_operations acpi_ops = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, .enable_resources = pci_dev_enable_resources, - .init = acpi_init, - .scan_bus = 0, + .init = acpi_init, + .scan_bus = 0, + .enable = amd8111_enable, }; static struct pci_driver acpi_driver __pci_driver = { diff --git a/src/southbridge/amd/amd8111/amd8111_early_smbus.c b/src/southbridge/amd/amd8111/amd8111_early_smbus.c index e0aaa05ff4..b9f142dc8e 100644 --- a/src/southbridge/amd/amd8111/amd8111_early_smbus.c +++ b/src/southbridge/amd/amd8111/amd8111_early_smbus.c @@ -21,6 +21,8 @@ static void enable_smbus(void) pci_write_config32(dev, 0x58, SMBUS_IO_BASE | 1); enable = pci_read_config8(dev, 0x41); pci_write_config8(dev, 0x41, enable | (1 << 7)); + /* clear any lingering errors, so the transaction will run */ + outw(inw(SMBUS_IO_BASE + SMBGSTATUS), SMBUS_IO_BASE + SMBGSTATUS); } @@ -40,8 +42,12 @@ static int smbus_wait_until_ready(void) if ((val & 0x800) == 0) { break; } + if(loops == (SMBUS_TIMEOUT / 2)) { + outw(inw(SMBUS_IO_BASE + SMBGSTATUS), + SMBUS_IO_BASE + SMBGSTATUS); + } } while(--loops); - return loops?0:-1; + return loops?0:-2; } static int smbus_wait_until_done(void) @@ -57,7 +63,7 @@ static int smbus_wait_until_done(void) break; } } while(--loops); - return loops?0:-1; + return loops?0:-3; } static int smbus_read_byte(unsigned device, unsigned address) @@ -67,7 +73,7 @@ static int smbus_read_byte(unsigned device, unsigned address) unsigned char byte; if (smbus_wait_until_ready() < 0) { - return -1; + return -2; } /* setup transaction */ @@ -93,7 +99,7 @@ static int smbus_read_byte(unsigned device, unsigned address) /* poll for transaction completion */ if (smbus_wait_until_done() < 0) { - return -1; + return -3; } global_status_register = inw(SMBUS_IO_BASE + SMBGSTATUS); diff --git a/src/southbridge/amd/amd8111/amd8111_ide.c b/src/southbridge/amd/amd8111/amd8111_ide.c index 11f795b0bb..4502bb3c45 100644 --- a/src/southbridge/amd/amd8111/amd8111_ide.c +++ b/src/southbridge/amd/amd8111/amd8111_ide.c @@ -3,6 +3,7 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include "amd8111.h" static void ide_init(struct device *dev) { diff --git a/src/southbridge/amd/amd8111/amd8111_lpc.c b/src/southbridge/amd/amd8111/amd8111_lpc.c index b0c1672f5d..437ed2e877 100644 --- a/src/southbridge/amd/amd8111/amd8111_lpc.c +++ b/src/southbridge/amd/amd8111/amd8111_lpc.c @@ -6,6 +6,8 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include <device/chip.h> +#include "amd8111.h" struct ioapicreg { @@ -87,7 +89,6 @@ static void setup_ioapic(void) static void lpc_init(struct device *dev) { uint8_t byte; - uint16_t word; int pwr_on=-1; printk_debug("lpc_init\n"); @@ -100,14 +101,7 @@ static void lpc_init(struct device *dev) /* posted memory write enable */ byte = pci_read_config8(dev, 0x46); - pci_write_config8(dev, 0x46, byte | (1<<0)); - -//BY LYH - /* Disable AC97 and Ethernet */ - word = pci_read_config16(dev, 0x48); - pci_write_config16(dev, 0x48, word & ~((1<<5)|(1<<6)|(1<<9))); -//BY LYH END - + pci_write_config8(dev, 0x46, byte | (1<<0)); /* power after power fail */ byte = pci_read_config8(dev, 0x43); @@ -118,6 +112,10 @@ static void lpc_init(struct device *dev) } pci_write_config8(dev, 0x43, byte); + /* Enable Port 92 fast reset */ + byte = pci_read_config8(dev, 0x41); + byte |= (1 << 5); + pci_write_config8(dev, 0x41, byte); } @@ -159,6 +157,7 @@ static struct device_operations lpc_ops = { .enable_resources = pci_dev_enable_resources, .init = lpc_init, .scan_bus = walk_static_devices, + .enable = amd8111_enable, }; static struct pci_driver lpc_driver __pci_driver = { @@ -166,3 +165,4 @@ static struct pci_driver lpc_driver __pci_driver = { .vendor = PCI_VENDOR_ID_AMD, .device = PCI_DEVICE_ID_AMD_8111_ISA, }; + diff --git a/src/southbridge/amd/amd8111/amd8111_nic.c b/src/southbridge/amd/amd8111/amd8111_nic.c new file mode 100644 index 0000000000..b3792086a5 --- /dev/null +++ b/src/southbridge/amd/amd8111/amd8111_nic.c @@ -0,0 +1,25 @@ +/* + * (C) 2003 Linux Networx + */ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "amd8111.h" + + +static struct device_operations nic_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .enable = amd8111_enable, + .init = 0, + .scan_bus = 0, +}; + +static struct pci_driver nic_driver __pci_driver = { + .ops = &nic_ops, + .vendor = PCI_VENDOR_ID_AMD, + .device = 0x7462, +}; diff --git a/src/southbridge/amd/amd8111/amd8111_usb.c b/src/southbridge/amd/amd8111/amd8111_usb.c index cfef06dee2..46cfabbcda 100644 --- a/src/southbridge/amd/amd8111/amd8111_usb.c +++ b/src/southbridge/amd/amd8111/amd8111_usb.c @@ -3,6 +3,7 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include "amd8111.h" static void usb_init(struct device *dev) { @@ -25,6 +26,7 @@ static struct device_operations usb_ops = { .enable_resources = pci_dev_enable_resources, .init = usb_init, .scan_bus = 0, + .enable = amd8111_enable, }; static struct pci_driver usb_driver __pci_driver = { diff --git a/src/southbridge/amd/amd8111/amd8111_usb2.c b/src/southbridge/amd/amd8111/amd8111_usb2.c index 924e0e6109..15ed69b0f1 100644 --- a/src/southbridge/amd/amd8111/amd8111_usb2.c +++ b/src/southbridge/amd/amd8111/amd8111_usb2.c @@ -7,6 +7,7 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include "amd8111.h" static void usb2_init(struct device *dev) { @@ -23,17 +24,17 @@ static void usb2_init(struct device *dev) } -static struct device_operations usb_ops = { +static struct device_operations usb2_ops = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, .enable_resources = pci_dev_enable_resources, .init = usb2_init, .scan_bus = 0, + .enable = amd8111_enable, }; static struct pci_driver usb2_driver __pci_driver = { - .ops = &usb_ops, + .ops = &usb2_ops, .vendor = PCI_VENDOR_ID_AMD, .device = PCI_DEVICE_ID_AMD_8111_USB2, }; - diff --git a/src/southbridge/amd/amd8131/amd8131_bridge.c b/src/southbridge/amd/amd8131/amd8131_bridge.c index dccf962fbd..9d28de4f32 100644 --- a/src/southbridge/amd/amd8131/amd8131_bridge.c +++ b/src/southbridge/amd/amd8131/amd8131_bridge.c @@ -29,6 +29,17 @@ static void pcix_init(device_t dev) word = pci_read_config16(dev, 0xe8); word = 0x0404; pci_write_config16(dev, 0xe8, word); + + /* Set discard unrequested prefetch data */ + word = pci_read_config16(dev, 0x4c); + word |= 1; + pci_write_config16(dev, 0x4c, word); + + /* Set split transaction limits */ + word = pci_read_config16(dev, 0xa8); + pci_write_config16(dev, 0xaa, word); + word = pci_read_config16(dev, 0xac); + pci_write_config16(dev, 0xae, word); return; } @@ -58,14 +69,6 @@ static void ioapic_enable(device_t dev) value &= ~((1 << 1) | (1 << 0)); } pci_write_config32(dev, 0x44, value); - -//BY LYH - value = pci_read_config32(dev, 0x4); - value |= 6; - pci_write_config32(dev, 0x4, value); -//BY LYH END - - } static struct device_operations ioapic_ops = { diff --git a/src/southbridge/via/vt8231/chip.h b/src/southbridge/via/vt8231/chip.h index 0ae3b98c63..fe3d332675 100644 --- a/src/southbridge/via/vt8231/chip.h +++ b/src/southbridge/via/vt8231/chip.h @@ -9,13 +9,13 @@ struct southbridge_via_vt8231_config { /* I am putting in IDE as an example but obviously this needs * to be more complete! */ - int enable_ide; - /* enables of functions of devices */ - int enable_usb; - int enable_native_ide; - int enable_com_ports; - int enable_keyboard; - int enable_nvram; + int enable_ide; + /* enables of functions of devices */ + int enable_usb; + int enable_native_ide; + int enable_com_ports; + int enable_keyboard; + int enable_nvram; }; #endif /* _SOUTHBRIDGE_VIA_VT8231 */ diff --git a/src/southbridge/via/vt8231/vt8231.c b/src/southbridge/via/vt8231/vt8231.c index 470ab5acf1..ea1f488f3e 100644 --- a/src/southbridge/via/vt8231/vt8231.c +++ b/src/southbridge/via/vt8231/vt8231.c @@ -11,101 +11,94 @@ void pc_keyboard_init(void); -void -hard_reset() { - printk_err("NO HARD RESET ON VT8231! FIX ME!\n"); +void hard_reset(void) +{ + printk_err("NO HARD RESET ON VT8231! FIX ME!\n"); } + static void usb_on(int enable) { - - unsigned char regval; - - /* Base 8231 controller */ - device_t dev0 = dev_find_device(PCI_VENDOR_ID_VIA, \ - PCI_DEVICE_ID_VIA_8231, 0); - /* USB controller 1 */ - device_t dev2 = dev_find_device(PCI_VENDOR_ID_VIA, \ - PCI_DEVICE_ID_VIA_82C586_2, 0); - /* USB controller 2 */ - device_t dev3 = dev_find_device(PCI_VENDOR_ID_VIA, \ - PCI_DEVICE_ID_VIA_82C586_2, \ - dev2); - - /* enable USB1 */ - if(dev2) { - if (enable) { - pci_write_config8(dev2, 0x3c, 0x05); - pci_write_config8(dev2, 0x04, 0x07); - } else { - pci_write_config8(dev2, 0x3c, 0x00); - pci_write_config8(dev2, 0x04, 0x00); - } - } - - if(dev0) { - regval = pci_read_config8(dev0, 0x50); - if (enable) - regval &= ~(0x10); - else - regval |= 0x10; - pci_write_config8(dev0, 0x50, regval); - } - - /* enable USB2 */ - if(dev3) { - if (enable) { - pci_write_config8(dev3, 0x3c, 0x05); - pci_write_config8(dev3, 0x04, 0x07); - } else { - pci_write_config8(dev3, 0x3c, 0x00); - pci_write_config8(dev3, 0x04, 0x00); - } - } - - if(dev0) { - regval = pci_read_config8(dev0, 0x50); - if (enable) - regval &= ~(0x20); - else - regval |= 0x20; - pci_write_config8(dev0, 0x50, regval); - } - + unsigned char regval; + + /* Base 8231 controller */ + device_t dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0); + /* USB controller 1 */ + device_t dev2 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, 0); + /* USB controller 2 */ + device_t dev3 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, dev2); + + /* enable USB1 */ + if(dev2) { + if (enable) { + pci_write_config8(dev2, 0x3c, 0x05); + pci_write_config8(dev2, 0x04, 0x07); + } else { + pci_write_config8(dev2, 0x3c, 0x00); + pci_write_config8(dev2, 0x04, 0x00); + } + } + + if(dev0) { + regval = pci_read_config8(dev0, 0x50); + if (enable) + regval &= ~(0x10); + else + regval |= 0x10; + pci_write_config8(dev0, 0x50, regval); + } + + /* enable USB2 */ + if(dev3) { + if (enable) { + pci_write_config8(dev3, 0x3c, 0x05); + pci_write_config8(dev3, 0x04, 0x07); + } else { + pci_write_config8(dev3, 0x3c, 0x00); + pci_write_config8(dev3, 0x04, 0x00); + } + } + + if(dev0) { + regval = pci_read_config8(dev0, 0x50); + if (enable) + regval &= ~(0x20); + else + regval |= 0x20; + pci_write_config8(dev0, 0x50, regval); + } } -static void keyboard_on() +static void keyboard_on(void) { - unsigned char regval; - - /* Base 8231 controller */ - device_t dev0 = dev_find_device(PCI_VENDOR_ID_VIA, \ - PCI_DEVICE_ID_VIA_8231, 0); - - /* kevinh/Ispiri - update entire function to use - new pci_write_config8 */ - - if (dev0) { - regval = pci_read_config8(dev0, 0x51); - regval |= 0x0f; - pci_write_config8(dev0, 0x51, regval); - } - pc_keyboard_init(); + unsigned char regval; + + /* Base 8231 controller */ + device_t dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0); + + /* kevinh/Ispiri - update entire function to use + new pci_write_config8 */ + if (dev0) { + regval = pci_read_config8(dev0, 0x51); + regval |= 0x0f; + pci_write_config8(dev0, 0x51, regval); + } + pc_keyboard_init(); } -static void nvram_on() +static void nvram_on(void) { - /* - * the VIA 8231 South has a very different nvram setup than the - * piix4e ... - * turn on ProMedia nvram. - * TO DO: use the PciWriteByte function here. - */ - - /* - * kevinh/Ispiri - I don't think this is the correct address/value - * intel_conf_writeb(0x80008841, 0xFF); - */ + /* + * the VIA 8231 South has a very different nvram setup than the + * piix4e ... + * turn on ProMedia nvram. + * TO DO: use the PciWriteByte function here. + */ + + /* + * kevinh/Ispiri - I don't think this is the correct address/value + * intel_conf_writeb(0x80008841, 0xFF); + */ } @@ -115,22 +108,22 @@ static void nvram_on() */ static void ethernet_fixup() { - device_t edev; - uint8_t byte; - - printk_info("Ethernet fixup\n"); - - edev = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_7, 0); - if (edev) { - printk_debug("Configuring VIA LAN\n"); - - /* We don't need stepping - though the device supports it */ - byte = pci_read_config8(edev, PCI_COMMAND); - byte &= ~PCI_COMMAND_WAIT; - pci_write_config8(edev, PCI_COMMAND, byte); - } else { - printk_debug("VIA LAN not found\n"); - } + device_t edev; + uint8_t byte; + + printk_info("Ethernet fixup\n"); + + edev = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_7, 0); + if (edev) { + printk_debug("Configuring VIA LAN\n"); + + /* We don't need stepping - though the device supports it */ + byte = pci_read_config8(edev, PCI_COMMAND); + byte &= ~PCI_COMMAND_WAIT; + pci_write_config8(edev, PCI_COMMAND, byte); + } else { + printk_debug("VIA LAN not found\n"); + } } @@ -145,13 +138,14 @@ static void ethernet_fixup() * (e.g. device_t). This needs to get fixed. We need low-level pci scans * in the C code. */ -static void vt8231_pci_enable(struct southbridge_via_vt8231_config *conf) { - /* - unsigned long busdevfn = 0x8000; - if (conf->enable_ide) { - printk_debug("%s: enabling IDE function\n", __FUNCTION__); - } - */ +static void vt8231_pci_enable(struct southbridge_via_vt8231_config *conf) +{ + /* + unsigned long busdevfn = 0x8000; + if (conf->enable_ide) { + printk_debug("%s: enabling IDE function\n", __FUNCTION__); + } + */ } /* PIRQ init @@ -170,7 +164,7 @@ static const unsigned char slotIrqs[4] = { 5, 10, 12, 11 }; */ static void pci_routing_fixup(void) { - device_t dev; + device_t dev; dev = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0); printk_info("%s: dev is %p\n", __FUNCTION__, dev); @@ -204,260 +198,258 @@ static void pci_routing_fixup(void) void -dump_south(void){ - device_t dev0; - dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0); - int i,j; - - for(i = 0; i < 256; i += 16) { - printk_debug("0x%x: ", i); - for(j = 0; j < 16; j++) { - printk_debug("%02x ", pci_read_config8(dev0, i+j)); - } - printk_debug("\n"); - } +dump_south(void) +{ + device_t dev0; + dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0); + int i,j; + + for(i = 0; i < 256; i += 16) { + printk_debug("0x%x: ", i); + for(j = 0; j < 16; j++) { + printk_debug("%02x ", pci_read_config8(dev0, i+j)); + } + printk_debug("\n"); + } } static void vt8231_init(struct southbridge_via_vt8231_config *conf) { - unsigned char enables; - device_t dev0; - device_t dev1; - device_t devpwr; - - // to do: use the pcibios_find function here, instead of - // hard coding the devfn. - // done - kevinh/Ispiri - printk_debug("vt8231 init\n"); - /* Base 8231 controller */ - dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0); - /* IDE controller */ - dev1 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, \ - 0); - /* Power management controller */ - devpwr = dev_find_device(PCI_VENDOR_ID_VIA, \ - PCI_DEVICE_ID_VIA_8231_4, 0); - - // enable the internal I/O decode - enables = pci_read_config8(dev0, 0x6C); - enables |= 0x80; - pci_write_config8(dev0, 0x6C, enables); - - // Map 4MB of FLASH into the address space - pci_write_config8(dev0, 0x41, 0x7f); - - // Set bit 6 of 0x40, because Award does it (IO recovery time) - // IMPORTANT FIX - EISA 0x4d0 decoding must be on so that PCI - // interrupts can be properly marked as level triggered. - enables = pci_read_config8(dev0, 0x40); - pci_write_config8(dev0, 0x40, enables); - - // Set 0x42 to 0xf0 to match Award bios - enables = pci_read_config8(dev0, 0x42); - enables |= 0xf0; - pci_write_config8(dev0, 0x42, enables); - - // Set bit 3 of 0x4a, to match award (dummy pci request) - enables = pci_read_config8(dev0, 0x4a); - enables |= 0x08; - pci_write_config8(dev0, 0x4a, enables); - - // Set bit 3 of 0x4f to match award (use INIT# as cpu reset) - enables = pci_read_config8(dev0, 0x4f); - enables |= 0x08; - pci_write_config8(dev0, 0x4f, enables); - - // Set 0x58 to 0x03 to match Award - pci_write_config8(dev0, 0x58, 0x03); - - // enable the ethernet/RTC - if(dev0) { - enables = pci_read_config8(dev0, 0x51); - enables |= 0x18; - pci_write_config8(dev0, 0x51, enables); - } - - - // enable com1 and com2. - if (conf->enable_com_ports) { - enables = pci_read_config8(dev0, 0x6e); - - /* 0x80 is enable com port b, 0x10 is to make it com2, 0x8 - * is enable com port a as com1 kevinh/Ispiri - Old code - * thought 0x01 would make it com1, that was wrong enables = - * 0x80 | 0x10 | 0x8 ; pci_write_config8(dev0, 0x6e, - * enables); // note: this is also a redo of some port of - * assembly, but we want everything up. - */ - - /* set com1 to 115 kbaud not clear how to do this yet. - * forget it; done in assembly. - */ - - } - // enable IDE, since Linux won't do it. - // First do some more things to devfn (17,0) - // note: this should already be cleared, according to the book. - enables = pci_read_config8(dev0, 0x50); - printk_debug("IDE enable in reg. 50 is 0x%x\n", enables); - enables &= ~8; // need manifest constant here! - printk_debug("set IDE reg. 50 to 0x%x\n", enables); - pci_write_config8(dev0, 0x50, enables); - - // set default interrupt values (IDE) - enables = pci_read_config8(dev0, 0x4c); - printk_debug("IRQs in reg. 4c are 0x%x\n", enables & 0xf); - // clear out whatever was there. - enables &= ~0xf; - enables |= 4; - printk_debug("setting reg. 4c to 0x%x\n", enables); - pci_write_config8(dev0, 0x4c, enables); - - // set up the serial port interrupts. - // com2 to 3, com1 to 4 - pci_write_config8(dev0, 0x46, 0x04); - pci_write_config8(dev0, 0x47, 0x03); - pci_write_config8(dev0, 0x6e, 0x98); - // - // Power management setup - // - // Set ACPI base address to IO 0x4000 - pci_write_config32(devpwr, 0x48, 0x4001); - - // Enable ACPI access (and setup like award) - pci_write_config8(devpwr, 0x41, 0x84); - - // Set hardware monitor base address to IO 0x6000 - pci_write_config32(devpwr, 0x70, 0x6001); - - // Enable hardware monitor (and setup like award) - pci_write_config8(devpwr, 0x74, 0x01); - - // set IO base address to 0x5000 - pci_write_config32(devpwr, 0x90, 0x5001); - - // Enable SMBus - pci_write_config8(devpwr, 0xd2, 0x01); - - // - // IDE setup - // - if (conf->enable_native_ide) { - // Run the IDE controller in 'compatiblity mode - i.e. don't use PCI - // interrupts. Using PCI ints confuses linux for some reason. - - printk_info("%s: enabling native IDE addresses\n", __FUNCTION__); - enables = pci_read_config8(dev1, 0x42); - printk_debug("enables in reg 0x42 0x%x\n", enables); - enables &= ~0xc0; // compatability mode - pci_write_config8(dev1, 0x42, enables); - enables = pci_read_config8(dev1, 0x42); - printk_debug("enables in reg 0x42 read back as 0x%x\n", enables); - } - - enables = pci_read_config8(dev1, 0x40); - printk_debug("enables in reg 0x40 0x%x\n", enables); - enables |= 3; - pci_write_config8(dev1, 0x40, enables); - enables = pci_read_config8(dev1, 0x40); - printk_debug("enables in reg 0x40 read back as 0x%x\n", enables); - - // Enable prefetch buffers - enables = pci_read_config8(dev1, 0x41); - enables |= 0xf0; - pci_write_config8(dev1, 0x41, enables); - - // Lower thresholds (cause award does it) - enables = pci_read_config8(dev1, 0x43); - enables &= ~0x0f; - enables |= 0x05; - pci_write_config8(dev1, 0x43, enables); - - // PIO read prefetch counter (cause award does it) - pci_write_config8(dev1, 0x44, 0x18); - - // Use memory read multiple - pci_write_config8(dev1, 0x45, 0x1c); - - // address decoding. - // we want "flexible", i.e. 1f0-1f7 etc. or native PCI - // kevinh@ispiri.com - the standard linux drivers seem ass slow when - // used in native mode - I've changed back to classic - enables = pci_read_config8(dev1, 0x9); - printk_debug("enables in reg 0x9 0x%x\n", enables); - // by the book, set the low-order nibble to 0xa. - if (conf->enable_native_ide) { - enables &= ~0xf; - // cf/cg silicon needs an 'f' here. - enables |= 0xf; - } else { - enables &= ~0x5; - } - - pci_write_config8(dev1, 0x9, enables); - enables = pci_read_config8(dev1, 0x9); - printk_debug("enables in reg 0x9 read back as 0x%x\n", enables); - - // standard bios sets master bit. - enables = pci_read_config8(dev1, 0x4); - printk_debug("command in reg 0x4 0x%x\n", enables); - enables |= 7; - - // No need for stepping - kevinh@ispiri.com - enables &= ~0x80; - - pci_write_config8(dev1, 0x4, enables); - enables = pci_read_config8(dev1, 0x4); - printk_debug("command in reg 0x4 reads back as 0x%x\n", enables); - - if (! conf->enable_native_ide) { - // Use compatability mode - per award bios - pci_write_config32(dev1, 0x10, 0x0); - pci_write_config32(dev1, 0x14, 0x0); - pci_write_config32(dev1, 0x18, 0x0); - pci_write_config32(dev1, 0x1c, 0x0); - - // Force interrupts to use compat mode - just like Award bios - pci_write_config8(dev1, 0x3d, 00); - pci_write_config8(dev1, 0x3c, 0xff); - } - - - /* set up isa bus -- i/o recovery time, rom write enable, extend-ale */ - pci_write_config8(dev0, 0x40, 0x54); - ethernet_fixup(); - - // Start the rtc - rtc_init(0); + unsigned char enables; + device_t dev0; + device_t dev1; + device_t devpwr; + + // to do: use the pcibios_find function here, instead of + // hard coding the devfn. + // done - kevinh/Ispiri + printk_debug("vt8231 init\n"); + /* Base 8231 controller */ + dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0); + /* IDE controller */ + dev1 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, 0); + /* Power management controller */ + devpwr = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4, 0); + + // enable the internal I/O decode + enables = pci_read_config8(dev0, 0x6C); + enables |= 0x80; + pci_write_config8(dev0, 0x6C, enables); + + // Map 4MB of FLASH into the address space + pci_write_config8(dev0, 0x41, 0x7f); + + // Set bit 6 of 0x40, because Award does it (IO recovery time) + // IMPORTANT FIX - EISA 0x4d0 decoding must be on so that PCI + // interrupts can be properly marked as level triggered. + enables = pci_read_config8(dev0, 0x40); + pci_write_config8(dev0, 0x40, enables); + + // Set 0x42 to 0xf0 to match Award bios + enables = pci_read_config8(dev0, 0x42); + enables |= 0xf0; + pci_write_config8(dev0, 0x42, enables); + + // Set bit 3 of 0x4a, to match award (dummy pci request) + enables = pci_read_config8(dev0, 0x4a); + enables |= 0x08; + pci_write_config8(dev0, 0x4a, enables); + + // Set bit 3 of 0x4f to match award (use INIT# as cpu reset) + enables = pci_read_config8(dev0, 0x4f); + enables |= 0x08; + pci_write_config8(dev0, 0x4f, enables); + + // Set 0x58 to 0x03 to match Award + pci_write_config8(dev0, 0x58, 0x03); + + // enable the ethernet/RTC + if(dev0) { + enables = pci_read_config8(dev0, 0x51); + enables |= 0x18; + pci_write_config8(dev0, 0x51, enables); + } + + + // enable com1 and com2. + if (conf->enable_com_ports) { + enables = pci_read_config8(dev0, 0x6e); + + /* 0x80 is enable com port b, 0x10 is to make it com2, 0x8 + * is enable com port a as com1 kevinh/Ispiri - Old code + * thought 0x01 would make it com1, that was wrong enables = + * 0x80 | 0x10 | 0x8 ; pci_write_config8(dev0, 0x6e, + * enables); // note: this is also a redo of some port of + * assembly, but we want everything up. + */ + + /* set com1 to 115 kbaud not clear how to do this yet. + * forget it; done in assembly. + */ + + } + // enable IDE, since Linux won't do it. + // First do some more things to devfn (17,0) + // note: this should already be cleared, according to the book. + enables = pci_read_config8(dev0, 0x50); + printk_debug("IDE enable in reg. 50 is 0x%x\n", enables); + enables &= ~8; // need manifest constant here! + printk_debug("set IDE reg. 50 to 0x%x\n", enables); + pci_write_config8(dev0, 0x50, enables); + + // set default interrupt values (IDE) + enables = pci_read_config8(dev0, 0x4c); + printk_debug("IRQs in reg. 4c are 0x%x\n", enables & 0xf); + // clear out whatever was there. + enables &= ~0xf; + enables |= 4; + printk_debug("setting reg. 4c to 0x%x\n", enables); + pci_write_config8(dev0, 0x4c, enables); + + // set up the serial port interrupts. + // com2 to 3, com1 to 4 + pci_write_config8(dev0, 0x46, 0x04); + pci_write_config8(dev0, 0x47, 0x03); + pci_write_config8(dev0, 0x6e, 0x98); + // + // Power management setup + // + // Set ACPI base address to IO 0x4000 + pci_write_config32(devpwr, 0x48, 0x4001); + + // Enable ACPI access (and setup like award) + pci_write_config8(devpwr, 0x41, 0x84); + + // Set hardware monitor base address to IO 0x6000 + pci_write_config32(devpwr, 0x70, 0x6001); + + // Enable hardware monitor (and setup like award) + pci_write_config8(devpwr, 0x74, 0x01); + + // set IO base address to 0x5000 + pci_write_config32(devpwr, 0x90, 0x5001); + + // Enable SMBus + pci_write_config8(devpwr, 0xd2, 0x01); + + // + // IDE setup + // + if (conf->enable_native_ide) { + // Run the IDE controller in 'compatiblity mode - i.e. don't use PCI + // interrupts. Using PCI ints confuses linux for some reason. + + printk_info("%s: enabling native IDE addresses\n", __FUNCTION__); + enables = pci_read_config8(dev1, 0x42); + printk_debug("enables in reg 0x42 0x%x\n", enables); + enables &= ~0xc0; // compatability mode + pci_write_config8(dev1, 0x42, enables); + enables = pci_read_config8(dev1, 0x42); + printk_debug("enables in reg 0x42 read back as 0x%x\n", enables); + } + + enables = pci_read_config8(dev1, 0x40); + printk_debug("enables in reg 0x40 0x%x\n", enables); + enables |= 3; + pci_write_config8(dev1, 0x40, enables); + enables = pci_read_config8(dev1, 0x40); + printk_debug("enables in reg 0x40 read back as 0x%x\n", enables); + + // Enable prefetch buffers + enables = pci_read_config8(dev1, 0x41); + enables |= 0xf0; + pci_write_config8(dev1, 0x41, enables); + + // Lower thresholds (cause award does it) + enables = pci_read_config8(dev1, 0x43); + enables &= ~0x0f; + enables |= 0x05; + pci_write_config8(dev1, 0x43, enables); + + // PIO read prefetch counter (cause award does it) + pci_write_config8(dev1, 0x44, 0x18); + + // Use memory read multiple + pci_write_config8(dev1, 0x45, 0x1c); + + // address decoding. + // we want "flexible", i.e. 1f0-1f7 etc. or native PCI + // kevinh@ispiri.com - the standard linux drivers seem ass slow when + // used in native mode - I've changed back to classic + enables = pci_read_config8(dev1, 0x9); + printk_debug("enables in reg 0x9 0x%x\n", enables); + // by the book, set the low-order nibble to 0xa. + if (conf->enable_native_ide) { + enables &= ~0xf; + // cf/cg silicon needs an 'f' here. + enables |= 0xf; + } else { + enables &= ~0x5; + } + + pci_write_config8(dev1, 0x9, enables); + enables = pci_read_config8(dev1, 0x9); + printk_debug("enables in reg 0x9 read back as 0x%x\n", enables); + + // standard bios sets master bit. + enables = pci_read_config8(dev1, 0x4); + printk_debug("command in reg 0x4 0x%x\n", enables); + enables |= 7; + + // No need for stepping - kevinh@ispiri.com + enables &= ~0x80; + + pci_write_config8(dev1, 0x4, enables); + enables = pci_read_config8(dev1, 0x4); + printk_debug("command in reg 0x4 reads back as 0x%x\n", enables); + + if (! conf->enable_native_ide) { + // Use compatability mode - per award bios + pci_write_config32(dev1, 0x10, 0x0); + pci_write_config32(dev1, 0x14, 0x0); + pci_write_config32(dev1, 0x18, 0x0); + pci_write_config32(dev1, 0x1c, 0x0); + + // Force interrupts to use compat mode - just like Award bios + pci_write_config8(dev1, 0x3d, 00); + pci_write_config8(dev1, 0x3c, 0xff); + } + + + /* set up isa bus -- i/o recovery time, rom write enable, extend-ale */ + pci_write_config8(dev0, 0x40, 0x54); + ethernet_fixup(); + + // Start the rtc + rtc_init(0); } -static void -southbridge_init(struct chip *chip, enum chip_pass pass) +static void southbridge_init(struct chip *chip, enum chip_pass pass) { - struct southbridge_via_vt8231_config *conf = - (struct southbridge_via_vt8231_config *)chip->chip_info; - - switch (pass) { - case CONF_PASS_PRE_PCI: - vt8231_pci_enable(conf); - break; - - case CONF_PASS_POST_PCI: - vt8231_init(conf); - printk_err("FUCK! ROUTING FIXUP!\n"); - pci_routing_fixup(); - - break; - case CONF_PASS_PRE_BOOT: - pci_routing_fixup(); - dump_south(); - break; - - default: - /* nothing yet */ - break; - } + struct southbridge_via_vt8231_config *conf = + (struct southbridge_via_vt8231_config *)chip->chip_info; + + switch (pass) { + case CONF_PASS_PRE_PCI: + vt8231_pci_enable(conf); + break; + + case CONF_PASS_POST_PCI: + vt8231_init(conf); + printk_err("FUCK! ROUTING FIXUP!\n"); + pci_routing_fixup(); + + break; + case CONF_PASS_PRE_BOOT: + pci_routing_fixup(); + dump_south(); + break; + + default: + /* nothing yet */ + break; + } } static void enumerate(struct chip *chip) @@ -468,7 +460,7 @@ static void enumerate(struct chip *chip) } struct chip_control southbridge_via_vt8231_control = { - .enumerate = enumerate, - enable: southbridge_init, - name: "VIA vt8231" + .enumerate = enumerate, + .enable = southbridge_init, + .name = "VIA vt8231" }; diff --git a/src/southbridge/via/vt8231/vt8231_early_serial.c b/src/southbridge/via/vt8231/vt8231_early_serial.c index ca7831df42..1bfffed7f5 100644 --- a/src/southbridge/via/vt8231/vt8231_early_serial.c +++ b/src/southbridge/via/vt8231/vt8231_early_serial.c @@ -8,20 +8,20 @@ #define SIO_BASE 0x3f0 #define SIO_DATA SIO_BASE+1 -static void -vt8231_writesuper(uint8_t reg, uint8_t val) { - outb(reg, SIO_BASE); - outb(val, SIO_DATA); +static void vt8231_writesuper(uint8_t reg, uint8_t val) +{ + outb(reg, SIO_BASE); + outb(val, SIO_DATA); } -static void -vt8231_writesiobyte(uint16_t reg, uint8_t val) { - outb(val, reg); +static void vt8231_writesiobyte(uint16_t reg, uint8_t val) +{ + outb(val, reg); } -static void -vt8231_writesioword(uint16_t reg, uint16_t val) { - outw(val, reg); +static void vt8231_writesioword(uint16_t reg, uint16_t val) +{ + outw(val, reg); } @@ -29,48 +29,47 @@ vt8231_writesioword(uint16_t reg, uint16_t val) { mainboard */ -static void -enable_vt8231_serial(void) { - unsigned long x; - uint8_t c; - device_t dev; - outb(6, 0x80); - dev = pci_locate_device(PCI_ID(0x1106,0x8231), 0); - - if (dev == PCI_DEV_INVALID) { - outb(7, 0x80); - die("Serial controller not found\r\n"); - } - - /* first, you have to enable the superio and superio config. - put a 6 reg 80 - */ - c = pci_read_config8(dev, 0x50); - c |= 6; - pci_write_config8(dev, 0x50, c); - outb(2, 0x80); - // now go ahead and set up com1. - // set address - vt8231_writesuper(0xf4, 0xfe); - // enable serial out - vt8231_writesuper(0xf2, 7); - // That's it for the sio stuff. - // movl $SUPERIOCONFIG, %eax - // movb $9, %dl - // PCI_WRITE_CONFIG_BYTE - // set up reg to set baud rate. - vt8231_writesiobyte(0x3fb, 0x80); - // Set 115 kb - vt8231_writesioword(0x3f8, 1); - // Set 9.6 kb - // WRITESIOWORD(0x3f8, 12) - // now set no parity, one stop, 8 bits - vt8231_writesiobyte(0x3fb, 3); - // now turn on RTS, DRT - vt8231_writesiobyte(0x3fc, 3); - // Enable interrupts - vt8231_writesiobyte(0x3f9, 0xf); - // should be done. Dump a char for fun. - vt8231_writesiobyte(0x3f8, 48); - +static void enable_vt8231_serial(void) +{ + unsigned long x; + uint8_t c; + device_t dev; + outb(6, 0x80); + dev = pci_locate_device(PCI_ID(0x1106,0x8231), 0); + + if (dev == PCI_DEV_INVALID) { + outb(7, 0x80); + die("Serial controller not found\r\n"); + } + + /* first, you have to enable the superio and superio config. + put a 6 reg 80 + */ + c = pci_read_config8(dev, 0x50); + c |= 6; + pci_write_config8(dev, 0x50, c); + outb(2, 0x80); + // now go ahead and set up com1. + // set address + vt8231_writesuper(0xf4, 0xfe); + // enable serial out + vt8231_writesuper(0xf2, 7); + // That's it for the sio stuff. + // movl $SUPERIOCONFIG, %eax + // movb $9, %dl + // PCI_WRITE_CONFIG_BYTE + // set up reg to set baud rate. + vt8231_writesiobyte(0x3fb, 0x80); + // Set 115 kb + vt8231_writesioword(0x3f8, 1); + // Set 9.6 kb + // WRITESIOWORD(0x3f8, 12) + // now set no parity, one stop, 8 bits + vt8231_writesiobyte(0x3fb, 3); + // now turn on RTS, DRT + vt8231_writesiobyte(0x3fc, 3); + // Enable interrupts + vt8231_writesiobyte(0x3f9, 0xf); + // should be done. Dump a char for fun. + vt8231_writesiobyte(0x3f8, 48); } diff --git a/src/southbridge/via/vt8231/vt8231_early_smbus.c b/src/southbridge/via/vt8231/vt8231_early_smbus.c index 49b942cb23..e419d59b63 100644 --- a/src/southbridge/via/vt8231/vt8231_early_smbus.c +++ b/src/southbridge/via/vt8231/vt8231_early_smbus.c @@ -24,115 +24,115 @@ static void enable_smbus(void) { - device_t dev; - unsigned char c; - /* Power management controller */ - dev = pci_locate_device(PCI_ID(0x1106,0x8235), 0); - - if (dev == PCI_DEV_INVALID) { - die("SMBUS controller not found\r\n"); - } - - // set IO base address to SMBUS_IO_BASE - pci_write_config32(dev, 0x90, SMBUS_IO_BASE|1); - - // Enable SMBus - c = pci_read_config8(dev, 0xd2); - c |= 5; - pci_write_config8(dev, 0xd2, c); - - /* make it work for I/O ... - */ - dev = pci_locate_device(PCI_ID(0x1106,0x8231), 0); - c = pci_read_config8(dev, 4); - c |= 1; - pci_write_config8(dev, 4, c); - print_err_hex8(c); - print_err(" is the comm register\n"); - - print_debug("SMBus controller enabled\r\n"); + device_t dev; + unsigned char c; + /* Power management controller */ + dev = pci_locate_device(PCI_ID(0x1106,0x8235), 0); + + if (dev == PCI_DEV_INVALID) { + die("SMBUS controller not found\r\n"); + } + + // set IO base address to SMBUS_IO_BASE + pci_write_config32(dev, 0x90, SMBUS_IO_BASE|1); + + // Enable SMBus + c = pci_read_config8(dev, 0xd2); + c |= 5; + pci_write_config8(dev, 0xd2, c); + + /* make it work for I/O ... + */ + dev = pci_locate_device(PCI_ID(0x1106,0x8231), 0); + c = pci_read_config8(dev, 4); + c |= 1; + pci_write_config8(dev, 4, c); + print_err_hex8(c); + print_err(" is the comm register\n"); + + print_debug("SMBus controller enabled\r\n"); } static inline void smbus_delay(void) { - outb(0x80, 0x80); + outb(0x80, 0x80); } static int smbus_wait_until_ready(void) { unsigned char c; - unsigned long loops; - loops = SMBUS_TIMEOUT; - do { - unsigned char val; - smbus_delay(); - c = inb(SMBUS_IO_BASE + SMBHSTSTAT); - while((c & 1) == 1) { - print_err("c is "); - print_err_hex8(c); - print_err("\n"); - c = inb(SMBUS_IO_BASE + SMBHSTSTAT); - /* nop */ - } - - } while(--loops); - return loops?0:-1; + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned char val; + smbus_delay(); + c = inb(SMBUS_IO_BASE + SMBHSTSTAT); + while((c & 1) == 1) { + print_err("c is "); + print_err_hex8(c); + print_err("\n"); + c = inb(SMBUS_IO_BASE + SMBHSTSTAT); + /* nop */ + } + + } while(--loops); + return loops?0:-1; } void smbus_reset(void) { - outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT); - outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT); - outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT); - outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT); - - smbus_wait_until_ready(); - print_err("After reset status "); - print_err_hex8( inb(SMBUS_IO_BASE + SMBHSTSTAT)); - print_err("\n"); + outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT); + outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT); + outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT); + outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT); + + smbus_wait_until_ready(); + print_err("After reset status "); + print_err_hex8( inb(SMBUS_IO_BASE + SMBHSTSTAT)); + print_err("\n"); } static int smbus_wait_until_done(void) { - unsigned long loops; - unsigned char byte; - loops = SMBUS_TIMEOUT; - do { - unsigned char val; - smbus_delay(); + unsigned long loops; + unsigned char byte; + loops = SMBUS_TIMEOUT; + do { + unsigned char val; + smbus_delay(); - byte = inb(SMBUS_IO_BASE + SMBHSTSTAT); - if (byte & 1) - break; - - } while(--loops); - return loops?0:-1; + byte = inb(SMBUS_IO_BASE + SMBHSTSTAT); + if (byte & 1) + break; + + } while(--loops); + return loops?0:-1; } static void smbus_print_error(unsigned char host_status_register) { - print_err("smbus_error: "); - print_err_hex8(host_status_register); - print_err("\n"); - if (host_status_register & (1 << 4)) { - print_err("Interrup/SMI# was Failed Bus Transaction\n"); - } - if (host_status_register & (1 << 3)) { - print_err("Bus Error\n"); - } - if (host_status_register & (1 << 2)) { - print_err("Device Error\n"); - } - if (host_status_register & (1 << 1)) { - print_err("Interrupt/SMI# was Successful Completion\n"); - } - if (host_status_register & (1 << 0)) { - print_err("Host Busy\n"); - } + print_err("smbus_error: "); + print_err_hex8(host_status_register); + print_err("\n"); + if (host_status_register & (1 << 4)) { + print_err("Interrup/SMI# was Failed Bus Transaction\n"); + } + if (host_status_register & (1 << 3)) { + print_err("Bus Error\n"); + } + if (host_status_register & (1 << 2)) { + print_err("Device Error\n"); + } + if (host_status_register & (1 << 1)) { + print_err("Interrupt/SMI# was Successful Completion\n"); + } + if (host_status_register & (1 << 0)) { + print_err("Host Busy\n"); + } } @@ -141,39 +141,39 @@ static void smbus_print_error(unsigned char host_status_register) static unsigned char smbus_read_byte(unsigned char devAdr, unsigned char bIndex) { - unsigned short i; - unsigned char bData; - unsigned char sts = 0; - - /* clear host status */ - outb(0xff, SMBUS_IO_BASE); - - /* check SMBUS ready */ - for ( i = 0; i < 0xFFFF; i++ ) - if ( (inb(SMBUS_IO_BASE) & 0x01) == 0 ) - break; - - /* set host command */ - outb(bIndex, SMBUS_IO_BASE+3); - - /* set slave address */ - outb(devAdr | 0x01, SMBUS_IO_BASE+4); - - /* start */ - outb(0x48, SMBUS_IO_BASE+2); - - /* SMBUS Wait Ready */ - for ( i = 0; i < 0xFFFF; i++ ) - if ( ((sts = inb(SMBUS_IO_BASE)) & 0x01) == 0 ) - break; - if ((sts & ~3) != 0) { - smbus_print_error(sts); - return 0; - } - bData=inb(SMBUS_IO_BASE+5); - - return bData; - + unsigned short i; + unsigned char bData; + unsigned char sts = 0; + + /* clear host status */ + outb(0xff, SMBUS_IO_BASE); + + /* check SMBUS ready */ + for ( i = 0; i < 0xFFFF; i++ ) + if ( (inb(SMBUS_IO_BASE) & 0x01) == 0 ) + break; + + /* set host command */ + outb(bIndex, SMBUS_IO_BASE+3); + + /* set slave address */ + outb(devAdr | 0x01, SMBUS_IO_BASE+4); + + /* start */ + outb(0x48, SMBUS_IO_BASE+2); + + /* SMBUS Wait Ready */ + for ( i = 0; i < 0xFFFF; i++ ) + if ( ((sts = inb(SMBUS_IO_BASE)) & 0x01) == 0 ) + break; + if ((sts & ~3) != 0) { + smbus_print_error(sts); + return 0; + } + bData=inb(SMBUS_IO_BASE+5); + + return bData; + } /* for reference, here is the fancier version which we will use at some @@ -182,48 +182,48 @@ static unsigned char smbus_read_byte(unsigned char devAdr, # if 0 int smbus_read_byte(unsigned device, unsigned address, unsigned char *result) { - unsigned char host_status_register; - unsigned char byte; - - reset(); - - smbus_wait_until_ready(); - - /* setup transaction */ - /* disable interrupts */ - outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL); - /* set the device I'm talking too */ - outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD); - /* set the command/address... */ - outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD); - /* set up for a byte data read */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), - SMBUS_IO_BASE + SMBHSTCTL); - - /* clear any lingering errors, so the transaction will run */ - outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); - - /* clear the data byte...*/ - outb(0, SMBUS_IO_BASE + SMBHSTDAT0); - - /* start the command */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), - SMBUS_IO_BASE + SMBHSTCTL); - - /* poll for transaction completion */ - smbus_wait_until_done(); - - host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT); - - /* Ignore the In Use Status... */ - host_status_register &= ~(1 << 6); - - /* read results of transaction */ - byte = inb(SMBUS_IO_BASE + SMBHSTDAT0); - smbus_print_error(byte); - - *result = byte; - return host_status_register != 0x02; + unsigned char host_status_register; + unsigned char byte; + + reset(); + + smbus_wait_until_ready(); + + /* setup transaction */ + /* disable interrupts */ + outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL); + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD); + /* set the command/address... */ + outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD); + /* set up for a byte data read */ + outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), + SMBUS_IO_BASE + SMBHSTCTL); + + /* clear any lingering errors, so the transaction will run */ + outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); + + /* clear the data byte...*/ + outb(0, SMBUS_IO_BASE + SMBHSTDAT0); + + /* start the command */ + outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), + SMBUS_IO_BASE + SMBHSTCTL); + + /* poll for transaction completion */ + smbus_wait_until_done(); + + host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT); + + /* Ignore the In Use Status... */ + host_status_register &= ~(1 << 6); + + /* read results of transaction */ + byte = inb(SMBUS_IO_BASE + SMBHSTDAT0); + smbus_print_error(byte); + + *result = byte; + return host_status_register != 0x02; } diff --git a/src/superio/NSC/pc87360/chip.h b/src/superio/NSC/pc87360/chip.h index 24bf65061f..55787566fc 100644 --- a/src/superio/NSC/pc87360/chip.h +++ b/src/superio/NSC/pc87360/chip.h @@ -14,7 +14,7 @@ extern struct chip_control superio_NSC_pc87360_control; struct superio_NSC_pc87360_config { - struct com_ports com1; - struct lpt_ports lpt; - int port; + struct com_ports com1; + struct lpt_ports lpt; + int port; }; diff --git a/src/superio/NSC/pc87360/superio.c b/src/superio/NSC/pc87360/superio.c index 0ec41c3346..8765eb35cc 100644 --- a/src/superio/NSC/pc87360/superio.c +++ b/src/superio/NSC/pc87360/superio.c @@ -305,7 +305,16 @@ static void enumerate(struct chip *chip) resource->base = conf->com1.irq; resource->flags = IORESOURCE_IRQ | IORESOURCE_FIXED | IORESOURCE_SET; } - + + /* Process the hard codes for the keyboard controller */ + path.u.pnp.device = KBC_DEVICE; + dev = alloc_find_dev(dev, &path); + resource = get_resource(dev, 0x60); + resource->base = 0x60; + resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET; + resource = get_resource(dev, 0x62); + resource->base = 0x64; + resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET; } struct chip_control superio_NSC_pc87360_control = { diff --git a/targets/arima/hdama/Config.lb b/targets/arima/hdama/Config.lb index 6c74ee6207..51d00fb3c4 100644 --- a/targets/arima/hdama/Config.lb +++ b/targets/arima/hdama/Config.lb @@ -93,9 +93,7 @@ romimage "normal" option ROM_IMAGE_SIZE=0x10000 option LINUXBIOS_EXTRA_VERSION=".0Normal" mainboard arima/hdama - payload /usr/share/etherboot/5.1.9pre2-lnxi-lb/tg3--ide_disk.zelf -# use this to test a build if you don't have the etherboot -# payload /etc/hosts + payload /usr/share/etherboot/5.2.1eb1-lnxi-lb/tg3--ide_disk.zelf end romimage "fallback" @@ -103,7 +101,7 @@ romimage "fallback" option ROM_IMAGE_SIZE=0x10000 option LINUXBIOS_EXTRA_VERSION=".0Fallback" mainboard arima/hdama - payload /usr/share/etherboot/5.1.9pre2-lnxi-lb/tg3--ide_disk.zelf + payload /usr/share/etherboot/5.2.1eb1-lnxi-lb/tg3--ide_disk.zelf # use this to test a build if you don't have the etherboot # payload /etc/hosts end diff --git a/targets/buildtarget b/targets/buildtarget index 9f8cb31619..88d09b7c88 100755 --- a/targets/buildtarget +++ b/targets/buildtarget @@ -1,5 +1,5 @@ #!/bin/sh - +PYTHON=python # Target build script if [ $# -lt 1 ]; then @@ -17,7 +17,9 @@ fi target_dir=$lbpath/targets config_lb=$1 config_dir=$lbpath/util/newconfig -config_py=$config_dir/config.py +yapps2_py=$config_dir/yapps2.py +config_g=$config_dir/config.g +config_py=$config_lb/config.py if [ ! -d $target_dir ]; then echo "Target directory not found" @@ -38,18 +40,12 @@ fi if [ ! -f $config_py ]; then echo "No linuxbios config script found. Rebuilding it.." - ( - cd $config_dir - make config.py - ) - echo "done." - # exit 1 + $PYTHON $yapps2_py $config_g $config_py fi # make sure config.py is up-to-date -(cd $config_dir && make config.py) - -python $config_py $config_lb $lbpath +export PYTHONPATH=$config_dir +$PYTHON $config_py $config_lb $lbpath exit $? diff --git a/util/newconfig/Makefile b/util/newconfig/Makefile index 374148254e..3328380569 100644 --- a/util/newconfig/Makefile +++ b/util/newconfig/Makefile @@ -26,7 +26,6 @@ manual/index.html: yapps2.aux yapps2.tex DISTRIB: cd ..; zip -u yapps2.zip yapps2/{LICENSE,yapps2.py,yappsrt.py,parsedesc.g,examples/*.g,NOTES,yapps2.tex,Makefile,manual/*.html,manual/*.css,manual/*.png} - + clean: rm -f config.py yappsrt.pyc parsedesc.py - diff --git a/util/newconfig/config.g b/util/newconfig/config.g index 23bdea9a79..5bec889092 100644 --- a/util/newconfig/config.g +++ b/util/newconfig/config.g @@ -580,7 +580,7 @@ class option_value: class partobj: """A configuration part""" - def __init__ (self, image, dir, parent, part, type_name, instance_name): + def __init__ (self, image, dir, parent, part, type_name, instance_name, link): debug.info(debug.object, "partobj dir %s parent %s part %s" \ % (dir, parent, part)) @@ -626,6 +626,11 @@ class partobj: # Path to the device self.path = "" + + # Link from parent device + if ((link < 0) or (link > 2)): + fatal("Invalid link") + self.link = link # If no instance name is supplied then generate # a unique name @@ -704,6 +709,7 @@ class partobj: else: file.write("struct chip static_root = {\n") file.write("\t/* %s %s */\n" % (self.part, self.dir)) + file.write("\t.link = %d,\n" % (self.link)) if (self.path != ""): file.write("\t.path = { %s\n\t},\n" % (self.path) ); if (self.siblings): @@ -749,33 +755,29 @@ class partobj: value = dequote(value) setdict(self.registercode, field, value) - def addpcipath(self, enable, channel, slot, function): + def addpcipath(self, enable, bus, slot, function): """ Add a relative pci style path from our parent to this device """ - if (channel < 0): - fatal("Invalid channel") + if ((bus < 0) or (bus > 255)): + fatal("Invalid bus") if ((slot < 0) or (slot > 0x1f)): fatal("Invalid device id") if ((function < 0) or (function > 7)): fatal("Invalid function") - self.path = "%s\n\t\t{ .channel = %d, .enable = %d, .path = {.type=DEVICE_PATH_PCI,.u={.pci={ .devfn = PCI_DEVFN(0x%x,%d) }}}}," % (self.path, channel, enable, slot, function) + self.path = "%s\n\t\t{ .enable = %d, .path = {.type=DEVICE_PATH_PCI,.u={.pci={ .bus = 0x%x, .devfn = PCI_DEVFN(0x%x,%d) }}}}," % (self.path, enable, bus, slot, function) - def addpnppath(self, enable, channel, port, device): + def addpnppath(self, enable, port, device): """ Add a relative path to a pnp device hanging off our parent """ - if (channel < 0): - fatal("Invalid channel") if ((port < 0) or (port > 65536)): fatal("Invalid port") if ((device < 0) or (device > 0xff)): fatal("Invalid device") - self.path = "%s\n\t\t{ .channel = %d, .enable = %d, .path={.type=DEVICE_PATH_PNP,.u={.pnp={ .port = 0x%x, .device = 0x%x }}}}," % (self.path, channel, enable, port, device) + self.path = "%s\n\t\t{ .enable = %d, .path={.type=DEVICE_PATH_PNP,.u={.pnp={ .port = 0x%x, .device = 0x%x }}}}," % (self.path, enable, port, device) - def addi2cpath(self, enable, channel, device): + def addi2cpath(self, enable, device): """ Add a relative path to a i2c device hanging off our parent """ - if (channel < 0): - fatal("Invalid channel") if ((device < 0) or (device > 0x7f)): fatal("Invalid device") - self.path = "%s\n\t\t{ .channel = %d, .enable = %d, .path = {.type=DEVICE_PATH_I2C,.u={.i2c={ .device = 0x%x }}}}, " % (self.path, channel, enable, device) + self.path = "%s\n\t\t{ .enable = %d, .path = {.type=DEVICE_PATH_I2C,.u={.i2c={ .device = 0x%x }}}}, " % (self.path, enable, device) def usesoption(self, name): """Declare option that can be used by this part""" @@ -1076,7 +1078,7 @@ def mainboard(path): setoption('MAINBOARD_VENDOR', vendor) setoption('MAINBOARD_PART_NUMBER', part_number) dodir('/config', 'Config.lb') - part('mainboard', path, 'Config.lb', 0) + part('mainboard', path, 'Config.lb', 0, 0) curimage.setroot(partstack.tos()) partpop() @@ -1117,14 +1119,14 @@ def cpudir(path): dodir(srcdir, "Config.lb") cpu_type = path -def part(type, path, file, name): +def part(type, path, file, name, link): global curimage, dirstack, partstack partdir = os.path.join(type, path) srcdir = os.path.join(treetop, 'src') fulldir = os.path.join(srcdir, partdir) type_name = flatten_name(os.path.join(type, path)) newpart = partobj(curimage, fulldir, partstack.tos(), type, \ - type_name, name) + type_name, name, link) print "Configuring PART %s, path %s" % (type, path) partstack.push(newpart) dirstack.push(fulldir) @@ -1196,7 +1198,7 @@ def setarch(my_arch): global curimage curimage.setarch(my_arch) setoption('ARCH', my_arch) - part('arch', my_arch, 'Config.lb', 0) + part('arch', my_arch, 'Config.lb', 0, 0) def doconfigfile(path, confdir, file, rule): rname = os.path.join(confdir, file) @@ -1328,6 +1330,7 @@ parser Config: token PCI: 'pci' token PNP: 'pnp' token I2C: 'i2c' + token LINK: 'link' rule expr: logical {{ l = logical }} @@ -1371,11 +1374,12 @@ parser Config: | SOUTHBRIDGE {{ return 'southbridge' }} | CPU {{ return 'cpu' }} - rule partdef<<C>>: {{ name = 0 }} + rule partdef<<C>>: {{ name = 0 }} {{ link = 0 }} parttype partid [ STR {{ name = dequote(STR) }} - ] {{ if (C): part(parttype, partid, 'Config.lb', name) }} - partend<<C>> + ][ LINK NUM {{ link = long(NUM, 10) }} + ] {{ if (C): part(parttype, partid, 'Config.lb', name, link) }} + partend<<C>> rule arch<<C>>: ARCH ID {{ if (C): setarch(ID) }} partend<<C>> @@ -1430,22 +1434,20 @@ parser Config: | OFF {{ val = 0 }} ) ] {{ return val }} - rule pci<<C>>: PCI HEX_NUM {{ channel = int(HEX_NUM,16) }} + rule pci<<C>>: PCI HEX_NUM {{ bus = int(HEX_NUM,16) }} ':' HEX_NUM {{ slot = int(HEX_NUM,16) }} '.' HEX_NUM {{ function = int(HEX_NUM, 16) }} enable - {{ if (C): partstack.tos().addpcipath(enable, channel, slot, function) }} + {{ if (C): partstack.tos().addpcipath(enable, bus, slot, function) }} - rule pnp<<C>>: PNP HEX_NUM {{ channel = int(HEX_NUM,16) }} - ':' HEX_NUM {{ port = int(HEX_NUM,16) }} + rule pnp<<C>>: PNP HEX_NUM {{ port = int(HEX_NUM,16) }} '.' HEX_NUM {{ device = int(HEX_NUM, 16) }} enable - {{ if (C): partstack.tos().addpnppath(enable, channel, port, device) }} + {{ if (C): partstack.tos().addpnppath(enable, port, device) }} - rule i2c<<C>>: I2C HEX_NUM {{ channel = int(HEX_NUM, 16) }} - ':' HEX_NUM {{ device = int(HEX_NUM, 16) }} + rule i2c<<C>>: I2C HEX_NUM {{ device = int(HEX_NUM, 16) }} enable - {{ if (C): partstatck.tos().addi2cpath(enable, channel, device) }} + {{ if (C): partstatck.tos().addi2cpath(enable, device) }} rule prtval: expr {{ return str(expr) }} | STR {{ return STR }} diff --git a/util/options/build_opt_tbl.c b/util/options/build_opt_tbl.c index 982e01b136..183aeab1bd 100644 --- a/util/options/build_opt_tbl.c +++ b/util/options/build_opt_tbl.c @@ -23,9 +23,10 @@ static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff}; output none if there is an overlap, the routine exits, other wise it returns. */ -void test_for_entry_overlaps(int entry_start,int entry_end) +void test_for_entry_overlaps(void *entry_start, void *entry_end) { - long ptr; + int ptr; + char *cptr; int buffer_bit_size; int offset; int byte; @@ -37,11 +38,12 @@ void test_for_entry_overlaps(int entry_start,int entry_end) /* calculate the size of the cmos buffer in bits */ buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8); /* clear the temporary test buffer */ - for(ptr=0;ptr<CMOS_IMAGE_BUFFER_SIZE;ptr++) + for(ptr=0; ptr < CMOS_IMAGE_BUFFER_SIZE; ptr++) test[ptr]=0; + /* loop through each entry in the table testing for errors */ - for(ptr=entry_start;ptr<entry_end;ptr+=ce->size) { - ce=(struct cmos_entries *)ptr; + for(cptr = entry_start; cptr < (char *)entry_end; cptr += ce->size) { + ce=(struct cmos_entries *)cptr; /* test if entry goes past the end of the buffer */ if((ce->bit+ce->length)>buffer_bit_size) { printf("Error - Entry %s start bit + length must be less than %d\n", @@ -66,16 +68,17 @@ void test_for_entry_overlaps(int entry_start,int entry_end) /* test if any of the bits have been previously used */ for(;byte_length;byte_length--,byte++) { if(test[byte]) { - printf("Error - Entry %s uses same bits previously used\n", + printf("Error - Entry %s uses same bits previously used\n", ce->name); - exit(1); + exit(1); } test[byte]=clip[8]; /* set the bits defined in test */ } } else { /* test if bits overlap byte boundaries */ if(ce->length>(8-offset)) { - printf("Error - Entry %s length overlaps a byte boundry\n", ce->name); + printf("Error - Entry %s length overlaps a byte boundry\n", + ce->name); exit(1); } /* test for bits previously used */ @@ -158,8 +161,7 @@ int main(int argc, char **argv) long ptr; int cnt; char *cptr; - long offset; - int entry_start; + void *entry_start, *entry_end; int entries_length; int enum_length; int len; @@ -268,21 +270,19 @@ int main(int argc, char **argv) len+=(4-(len%4)); ce->size=sizeof(struct cmos_entries)-32+len; cptr = (char*)ce; - cptr+=ce->size; /* increment to the next table position */ + cptr += ce->size; /* increment to the next table position */ ce = (struct cmos_entries*) cptr; } /* put the length of the entries into the header section */ - entries_length=(long)cptr; - entries_length-=(long)(cmos_table+ct->header_length); + entries_length = (cptr - (char *)&cmos_table) - ct->header_length; /* compute the start of the enumerations section */ - entry_start=(int)cmos_table; - entry_start+=ct->header_length; - offset=entry_start+entries_length; - c_enums_start=c_enums=(struct cmos_enums*)offset; + entry_start = ((char*)&cmos_table) + ct->header_length; + entry_end = ((char *)entry_start) + entries_length; + c_enums_start = c_enums = (struct cmos_enums*)entry_end; /* test for overlaps in the entry records */ - test_for_entry_overlaps(entry_start,offset); + test_for_entry_overlaps(entry_start, entry_end); for(;enum_mode;){ /* loop to build the enumerations section */ if(fgets(line,INPUT_LINE_MAX,fp)==NULL) @@ -315,14 +315,14 @@ int main(int argc, char **argv) if(cnt%4) cnt+=4-(cnt%4); /* store the record length */ - c_enums->size=((long)&c_enums->text[cnt])-(long)c_enums; + c_enums->size=((char *)&c_enums->text[cnt]) - (char *)c_enums; /* store the record type */ c_enums->tag=LB_TAG_OPTION_ENUM; /* increment to the next record */ c_enums=(struct cmos_enums*)&c_enums->text[cnt]; } /* save the enumerations length */ - enum_length=(long)c_enums-(long)c_enums_start; + enum_length= (char *)c_enums - (char *)c_enums_start; ct->size=ct->header_length+enum_length+entries_length; /* Get the checksum records */ diff --git a/util/romcc/Makefile b/util/romcc/Makefile index 71a97d1f25..62df48d434 100644 --- a/util/romcc/Makefile +++ b/util/romcc/Makefile @@ -1,5 +1,5 @@ -VERSION:=0.34 -RELEASE_DATE:=4 July 2003 +VERSION:=0.36 +RELEASE_DATE:=10 October 2003 PACKAGE:=romcc @@ -17,6 +17,15 @@ romcc: romcc.c Makefile romcc_pg: romcc.c Makefile $(CC) $(CFLAGS) $(CPROF_FLAGS) -o $@ $< +LINUX_TESTS=\ + linux_test1.c \ + linux_test2.c \ + linux_test3.c \ + linux_test4.c \ + linux_test5.c \ + linux_test6.c \ + linux_test7.c \ + TESTS=\ hello_world.c \ hello_world2.c \ @@ -41,7 +50,6 @@ TESTS=\ simple_test19.c \ simple_test20.c \ simple_test21.c \ - simple_test22.c \ simple_test23.c \ simple_test24.c \ simple_test25.c \ @@ -49,7 +57,6 @@ TESTS=\ simple_test27.c \ simple_test28.c \ simple_test29.c \ - simple_test30.c \ simple_test31.c \ simple_test32.c \ simple_test33.c \ @@ -57,8 +64,6 @@ TESTS=\ simple_test35.c \ simple_test36.c \ simple_test37.c \ - simple_test38.c \ - simple_test39.c \ simple_test40.c \ simple_test41.c \ simple_test43.c \ @@ -71,43 +76,113 @@ TESTS=\ simple_test51.c \ simple_test52.c \ simple_test53.c \ - simple_test54.c \ simple_test55.c \ simple_test56.c \ - simple_test59.c \ + simple_test57.c \ + simple_test58.c \ + simple_test60.c \ + simple_test61.c \ + simple_test62.c \ + simple_test63.c \ + simple_test64.c \ + simple_test65.c \ + simple_test66.c \ + simple_test67.c \ + simple_test68.c \ raminit_test.c \ raminit_test2.c \ raminit_test3.c \ raminit_test4.c \ - raminit_test5.c + raminit_test5.c \ + raminit_test6.c \ + $(LINUX_TESTS) FAIL_TESTS = \ fail_test1.c \ fail_test2.c \ - fail_test3.c + fail_test3.c \ + fail_test4.c \ + fail_test5.c \ TEST_SRCS:=$(patsubst %, tests/%, $(TESTS)) TEST_ASM:=$(patsubst %.c, tests/%.S, $(TESTS)) +TEST_ASM_O:=$(patsubst %.c, tests/%.S-O, $(TESTS)) +TEST_ASM_O2:=$(patsubst %.c, tests/%.S-O2, $(TESTS)) +TEST_ASM_mmmx :=$(patsubst %.c, tests/%.S-mmmx, $(TESTS)) +TEST_ASM_msse :=$(patsubst %.c, tests/%.S-msse, $(TESTS)) +TEST_ASM_mmmx_msse:=$(patsubst %.c, tests/%.S-mmmx-msse, $(TESTS)) +TEST_ASM_O_mmmx :=$(patsubst %.c, tests/%.S-O-mmmx, $(TESTS)) +TEST_ASM_O_msse :=$(patsubst %.c, tests/%.S-O-msse, $(TESTS)) +TEST_ASM_O_mmmx_msse:=$(patsubst %.c, tests/%.S-O-mmmx-msse, $(TESTS)) +TEST_ASM_O2_mmmx :=$(patsubst %.c, tests/%.S-O2-mmmx, $(TESTS)) +TEST_ASM_O2_msse :=$(patsubst %.c, tests/%.S-O2-msse, $(TESTS)) +TEST_ASM_O2_mmmx_msse:=$(patsubst %.c, tests/%.S-O2-mmmx-msse, $(TESTS)) +TEST_ASM_ALL:= $(TEST_ASM) $(TEST_ASM_O) $(TEST_ASM_O2) $(TEST_ASM_mmmx) $(TEST_ASM_msse) $(TEST_ASM_mmmx_msse) $(TEST_ASM_O_mmmx) $(TEST_ASM_O_msse) $(TEST_ASM_O_mmmx_msse) $(TEST_ASM_O2_mmmx) $(TEST_ASM_O2_msse) $(TEST_ASM_O2_mmmx_msse) +TEST_ASM_MOST:= $(TEST_ASM_O) $(TEST_ASM_O_mmmx) $(TEST_ASM_O_msse) $(TEST_ASM_O_mmmx_msse) $(TEST_ASM_O2) $(TEST_ASM_O2_mmmx) $(TEST_ASM_O2_msse) $(TEST_ASM_O2_mmmx_msse) TEST_OBJ:=$(patsubst %.c, tests/%.o, $(TESTS)) TEST_ELF:=$(patsubst %.c, tests/%.elf, $(TESTS)) +LINUX_ELF:=$(patsubst %.c, tests/%.elf, $(LINUX_TESTS)) +LINUX_OUT:=$(patsubst %.c, tests/%.out, $(LINUX_TESTS)) FAIL_SRCS:=$(patsubst %, tests/%, $(FAIL_TESTS)) FAIL_OUT:=$(patsubst %.c, tests/%.out, $(FAIL_TESTS)) $(TEST_ASM): %.S: %.c romcc - export ALLOC_CHECK_=2; ./romcc -O -mcpu=k8 -o $@ $< > $*.debug + export ALLOC_CHECK_=2; ./romcc -o $@ $< > $*.debug + +$(TEST_ASM_O): %.S-O: %.c romcc + export ALLOC_CHECK_=2; ./romcc -O -o $@ $< > $*.debug + +$(TEST_ASM_O2): %.S-O2: %.c romcc + export ALLOC_CHECK_=2; ./romcc -O2 -o $@ $< > $*.debug + + +$(TEST_ASM_mmmx): %.S-mmmx: %.c romcc + export ALLOC_CHECK_=2; ./romcc -mmmx -o $@ $< > $*.debug + +$(TEST_ASM_msse): %.S-msse: %.c romcc + export ALLOC_CHECK_=2; ./romcc -msse -o $@ $< > $*.debug + +$(TEST_ASM_mmmx_msse): %.S-mmmx-msse: %.c romcc + export ALLOC_CHECK_=2; ./romcc -mmmx -msse -o $@ $< > $*.debug + + +$(TEST_ASM_O_mmmx): %.S-O-mmmx: %.c romcc + export ALLOC_CHECK_=2; ./romcc -O -mmmx -o $@ $< > $*.debug + +$(TEST_ASM_O_msse): %.S-O-msse: %.c romcc + export ALLOC_CHECK_=2; ./romcc -O -msse -o $@ $< > $*.debug + +$(TEST_ASM_O_mmmx_msse): %.S-O-mmmx-msse: %.c romcc + export ALLOC_CHECK_=2; ./romcc -O -mmmx -msse -o $@ $< > $*.debug + + +$(TEST_ASM_O2_mmmx): %.S-O2-mmmx: %.c romcc + export ALLOC_CHECK_=2; ./romcc -O2 -mmmx -o $@ $< > $*.debug + +$(TEST_ASM_O2_msse): %.S-O2-msse: %.c romcc + export ALLOC_CHECK_=2; ./romcc -O2 -msse -o $@ $< > $*.debug + +$(TEST_ASM_O2_mmmx_msse): %.S-O2-mmmx-msse: %.c romcc + export ALLOC_CHECK_=2; ./romcc -O2 -mmmx -msse -o $@ $< > $*.debug + $(FAIL_OUT): %.out: %.c romcc - export ALLOC_CHECK_=2; if ./romcc -O -o $*.S $< > $*.debug 2> $@ ; then exit 1 ; else exit 0 ; fi + export ALLOC_CHECK_=2; if ./romcc -O2 -o $*.S $< > $*.debug 2> $@ ; then exit 1 ; else exit 0 ; fi -$(TEST_OBJ): %.o: %.S +$(TEST_OBJ): %.o: %.S-O2-mmmx as $< -o $@ $(TEST_ELF): %.elf: %.o tests/ldscript.ld ld -T tests/ldscript.ld $< -o $@ -test: $(TEST_ELF) $(FAIL_OUT) +$(LINUX_OUT): %.out: %.elf + ./$< > $@ + +test: $(TEST_ELF) $(FAIL_OUT) $(TEST_ASM_MOST) + +run_linux: $(LINUX_OUT) echo: echo "TEST_SRCS=$(TEST_SRCS)" @@ -119,5 +194,5 @@ echo: echo "FAIL_ASM=$(FAIL_ASM)" clean: - rm -f romcc romcc_pg core $(TEST_ASM) $(TEST_OBJ) $(TEST_ELF) tests/*.debug tests/*.debug2 tests/*.gmon.out tests/*.out + rm -f romcc romcc_pg core $(TEST_ASM_ALL) $(TEST_OBJ) $(TEST_ELF) tests/*.debug tests/*.debug2 tests/*.gmon.out tests/*.out diff --git a/util/romcc/results/linux_test1.out b/util/romcc/results/linux_test1.out Binary files differnew file mode 100644 index 0000000000..e139c33ef9 --- /dev/null +++ b/util/romcc/results/linux_test1.out diff --git a/util/romcc/results/linux_test2.out b/util/romcc/results/linux_test2.out new file mode 100644 index 0000000000..ce61c099d2 --- /dev/null +++ b/util/romcc/results/linux_test2.out @@ -0,0 +1,59 @@ +setting up coherent ht domain.... +0000c040 <-00010101 +0000c044 <-00010101 +0000c048 <-00010101 +0000c04c <-00010101 +0000c050 <-00010101 +0000c054 <-00010101 +0000c058 <-00010101 +0000c05c <-00010101 +0000c068 <-0f00840f +0000c06c <-00000070 +0000c084 <-11110020 +0000c088 <-00000200 +0000c094 <-00ff0000 +0000c144 <-003f0000 +0000c14c <-00000001 +0000c154 <-00000002 +0000c15c <-00000003 +0000c164 <-00000004 +0000c16c <-00000005 +0000c174 <-00000006 +0000c17c <-00000007 +0000c140 <-00000003 +0000c148 <-00400000 +0000c150 <-00400000 +0000c158 <-00400000 +0000c160 <-00400000 +0000c168 <-00400000 +0000c170 <-00400000 +0000c178 <-00400000 +0000c184 <-00e1ff00 +0000c18c <-00dfff00 +0000c194 <-00e3ff00 +0000c19c <-00000000 +0000c1a4 <-00000000 +0000c1ac <-00000000 +0000c1b4 <-00000b00 +0000c1bc <-00fe0b00 +0000c180 <-00e00003 +0000c188 <-00d80003 +0000c190 <-00e20003 +0000c198 <-00000000 +0000c1a0 <-00000000 +0000c1a8 <-00000000 +0000c1b0 <-00000a03 +0000c1b8 <-00400003 +0000c1c4 <-0000d000 +0000c1cc <-000ff000 +0000c1d4 <-00000000 +0000c1dc <-00000000 +0000c1c0 <-0000d003 +0000c1c8 <-00001013 +0000c1d0 <-00000000 +0000c1d8 <-00000000 +0000c1e0 <-ff000003 +0000c1e4 <-00000000 +0000c1e8 <-00000000 +0000c1ec <-00000000 +done. diff --git a/util/romcc/results/linux_test3.out b/util/romcc/results/linux_test3.out new file mode 100644 index 0000000000..06b38ce9d8 --- /dev/null +++ b/util/romcc/results/linux_test3.out @@ -0,0 +1,11 @@ +goto_test +i = 00 +i = 01 +i = 02 +i = 03 +i = 04 +i = 05 +i = 06 +i = 07 +i = 08 +i = 09 diff --git a/util/romcc/results/linux_test4.out b/util/romcc/results/linux_test4.out new file mode 100644 index 0000000000..5d69fe667c --- /dev/null +++ b/util/romcc/results/linux_test4.out @@ -0,0 +1,11 @@ +cpu_socketA +.up=0002 .down=ffff .across=0001 +.up=0003 .down=ffff .across=0000 +.up=ffff .down=0000 .across=0003 +.up=ffff .down=0001 .across=0002 + +cpu_socketB +.up=0002 .down=ffff .across=0001 +.up=0003 .down=ffff .across=0000 +.up=ffff .down=0000 .across=0003 +.up=ffff .down=0001 .across=0002 diff --git a/util/romcc/results/linux_test5.out b/util/romcc/results/linux_test5.out new file mode 100644 index 0000000000..0c94914228 --- /dev/null +++ b/util/romcc/results/linux_test5.out @@ -0,0 +1,34 @@ +min_cycle_time: 75 min_latency: 02 +A +B +C +C +D +E +device: 00 new_cycle_time: 75 new_latency: 02 +G +C +D +E +G +H +device: 00 new_cycle_time: 75 new_latency: 02 +I +device: 00 min_cycle_time: 75 min_latency: 02 +A +B +C +C +D +E +device: 01 new_cycle_time: 75 new_latency: 02 +G +C +D +E +G +H +device: 01 new_cycle_time: 75 new_latency: 02 +I +device: 01 min_cycle_time: 75 min_latency: 02 +min_cycle_time: 75 min_latency: 02 diff --git a/util/romcc/results/linux_test6.out b/util/romcc/results/linux_test6.out new file mode 100644 index 0000000000..5978e19e4a --- /dev/null +++ b/util/romcc/results/linux_test6.out @@ -0,0 +1,2 @@ +B +Registered diff --git a/util/romcc/results/linux_test7.out b/util/romcc/results/linux_test7.out new file mode 100644 index 0000000000..9d76d82734 --- /dev/null +++ b/util/romcc/results/linux_test7.out @@ -0,0 +1,32 @@ +val[00]: 0000c144 0000f8f8 00000000 +val[03]: 0000c14c 0000f8f8 00000001 +val[06]: 0000c154 0000f8f8 00000002 +val[09]: 0000c15c 0000f8f8 00000003 +val[0c]: 0000c164 0000f8f8 00000004 +val[0f]: 0000c16c 0000f8f8 00000005 +val[12]: 0000c174 0000f8f8 00000006 +val[15]: 0000c17c 0000f8f8 00000007 +val[00]: 0000c144 0000f8f8 00000000 +val[03]: 0000c14c 0000f8f8 00000001 +val[06]: 0000c154 0000f8f8 00000002 +val[09]: 0000c15c 0000f8f8 00000003 +val[0c]: 0000c164 0000f8f8 00000004 +val[0f]: 0000c16c 0000f8f8 00000005 +val[12]: 0000c174 0000f8f8 00000006 +val[15]: 0000c17c 0000f8f8 00000007 +val[00]: 0000c144 0000f8f8 00000000 +val[03]: 0000c14c 0000f8f8 00000001 +val[06]: 0000c154 0000f8f8 00000002 +val[09]: 0000c15c 0000f8f8 00000003 +val[0c]: 0000c164 0000f8f8 00000004 +val[0f]: 0000c16c 0000f8f8 00000005 +val[12]: 0000c174 0000f8f8 00000006 +val[15]: 0000c17c 0000f8f8 00000007 +val[00]: 0000c144 0000f8f8 00000000 +val[03]: 0000c14c 0000f8f8 00000001 +val[06]: 0000c154 0000f8f8 00000002 +val[09]: 0000c15c 0000f8f8 00000003 +val[0c]: 0000c164 0000f8f8 00000004 +val[0f]: 0000c16c 0000f8f8 00000005 +val[12]: 0000c174 0000f8f8 00000006 +val[15]: 0000c17c 0000f8f8 00000007 diff --git a/util/romcc/romcc.c b/util/romcc/romcc.c index 2b14506c50..db7d61131e 100644 --- a/util/romcc/romcc.c +++ b/util/romcc/romcc.c @@ -19,6 +19,7 @@ #define DEBUG_COALESCING 0 #define DEBUG_SDP_BLOCKS 0 #define DEBUG_TRIPLE_COLOR 0 +#define DEBUG_SIMPLIFY 0 #warning "FIXME boundary cases with small types in larger registers" #warning "FIXME give clear error messages about unused variables" @@ -207,14 +208,32 @@ static char *slurp_file(const char *dirname, const char *filename, off_t *r_size return buf; } -/* Long on the destination platform */ -#ifdef __x86_64__ -typedef unsigned int ulong_t; -typedef int long_t; -#else -typedef unsigned long ulong_t; -typedef long long_t; -#endif +/* Types on the destination platform */ +#warning "FIXME this assumes 32bit x86 is the destination" +typedef int8_t schar_t; +typedef uint8_t uchar_t; +typedef int8_t char_t; +typedef int16_t short_t; +typedef uint16_t ushort_t; +typedef int32_t int_t; +typedef uint32_t uint_t; +typedef int32_t long_t; +typedef uint32_t ulong_t; + +#define SCHAR_T_MIN (-128) +#define SCHAR_T_MAX 127 +#define UCHAR_T_MAX 255 +#define CHAR_T_MIN SCHAR_T_MIN +#define CHAR_T_MAX SCHAR_T_MAX +#define SHRT_T_MIN (-32768) +#define SHRT_T_MAX 32767 +#define USHRT_T_MAX 65535 +#define INT_T_MIN (-LONG_T_MAX - 1) +#define INT_T_MAX 2147483647 +#define UINT_T_MAX 4294967295U +#define LONG_T_MIN (-LONG_T_MAX - 1) +#define LONG_T_MAX 2147483647 +#define ULONG_T_MAX 4294967295U struct file_state { struct file_state *prev; @@ -506,11 +525,12 @@ struct token { struct op_info { const char *name; unsigned flags; -#define PURE 1 -#define IMPURE 2 +#define PURE 1 /* Triple has no side effects */ +#define IMPURE 2 /* Triple has side effects */ #define PURE_BITS(FLAGS) ((FLAGS) & 0x3) -#define DEF 4 +#define DEF 4 /* Triple is a variable definition */ #define BLOCK 8 /* Triple stores the current block */ +#define STRUCTURAL 16 /* Triple does not generate a machine instruction */ unsigned char lhs, rhs, misc, targ; }; @@ -559,16 +579,16 @@ static const struct op_info table_ops[] = { [OP_LOAD ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "load"), [OP_STORE ] = OP( 0, 2, 0, 0, IMPURE | BLOCK , "store"), -[OP_NOOP ] = OP( 0, 0, 0, 0, PURE | BLOCK, "noop"), +[OP_NOOP ] = OP( 0, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "noop"), [OP_INTCONST ] = OP( 0, 0, 0, 0, PURE | DEF, "intconst"), -[OP_BLOBCONST ] = OP( 0, 0, 0, 0, PURE, "blobconst"), +[OP_BLOBCONST ] = OP( 0, 0, 0, 0, PURE , "blobconst"), [OP_ADDRCONST ] = OP( 0, 0, 1, 0, PURE | DEF, "addrconst"), [OP_WRITE ] = OP( 0, 2, 0, 0, PURE | BLOCK, "write"), [OP_READ ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "read"), [OP_COPY ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "copy"), -[OP_PIECE ] = OP( 0, 0, 1, 0, PURE | DEF, "piece"), +[OP_PIECE ] = OP( 0, 0, 1, 0, PURE | DEF | STRUCTURAL, "piece"), [OP_ASM ] = OP(-1, -1, 0, 0, IMPURE, "asm"), [OP_DEREF ] = OP( 0, 1, 0, 0, 0 | DEF | BLOCK, "deref"), [OP_DOT ] = OP( 0, 1, 0, 0, 0 | DEF | BLOCK, "dot"), @@ -581,14 +601,14 @@ static const struct op_info table_ops[] = { /* Call is special most it can stand in for anything so it depends on context */ [OP_CALL ] = OP(-1, -1, 1, 0, 0 | BLOCK, "call"), /* The sizes of OP_CALL and OP_VAL_VEC depend upon context */ -[OP_VAL_VEC ] = OP( 0, -1, 0, 0, 0 | BLOCK, "valvec"), +[OP_VAL_VEC ] = OP( 0, -1, 0, 0, 0 | BLOCK | STRUCTURAL, "valvec"), -[OP_LIST ] = OP( 0, 1, 1, 0, 0 | DEF, "list"), +[OP_LIST ] = OP( 0, 1, 1, 0, 0 | DEF | STRUCTURAL, "list"), /* The number of targets for OP_BRANCH depends on context */ [OP_BRANCH ] = OP( 0, -1, 0, 1, PURE | BLOCK, "branch"), -[OP_LABEL ] = OP( 0, 0, 0, 0, PURE | BLOCK, "label"), -[OP_ADECL ] = OP( 0, 0, 0, 0, PURE | BLOCK, "adecl"), -[OP_SDECL ] = OP( 0, 0, 1, 0, PURE | BLOCK, "sdecl"), +[OP_LABEL ] = OP( 0, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "label"), +[OP_ADECL ] = OP( 0, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "adecl"), +[OP_SDECL ] = OP( 0, 0, 1, 0, PURE | BLOCK | STRUCTURAL, "sdecl"), /* The number of RHS elements of OP_PHI depend upon context */ [OP_PHI ] = OP( 0, -1, 1, 0, PURE | DEF | BLOCK, "phi"), @@ -697,6 +717,8 @@ struct triple { #define TRIPLE_FLAG_FLATTENED (1 << 31) #define TRIPLE_FLAG_PRE_SPLIT (1 << 30) #define TRIPLE_FLAG_POST_SPLIT (1 << 29) +#define TRIPLE_FLAG_VOLATILE (1 << 28) +#define TRIPLE_FLAG_LOCAL (1 << 27) struct occurance *occurance; union { ulong_t cval; @@ -762,7 +784,7 @@ struct hash_entry { int tok; struct macro *sym_define; struct symbol *sym_label; - struct symbol *sym_struct; + struct symbol *sym_tag; struct symbol *sym_ident; }; @@ -777,16 +799,20 @@ struct compile_state { const char *function; struct token token[4]; struct hash_entry *hash_table[HASH_TABLE_SIZE]; + struct hash_entry *i_switch; + struct hash_entry *i_case; struct hash_entry *i_continue; struct hash_entry *i_break; + struct hash_entry *i_default; int scope_depth; int if_depth, if_value; int macro_line; struct file_state *macro_file; struct triple *main_function; + struct triple *first; struct block *first_block, *last_block; int last_vertex; - int cpu; + unsigned long features; int debug; int optimize; }; @@ -817,12 +843,12 @@ struct compile_state { #define TYPE_SHIFT 8 #define TYPE_MASK 0x1f00 -#define TYPE_INTEGER(TYPE) (((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_ULLONG)) -#define TYPE_ARITHMETIC(TYPE) (((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_LDOUBLE)) +#define TYPE_INTEGER(TYPE) ((((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_ULLONG)) || ((TYPE) == TYPE_ENUM)) +#define TYPE_ARITHMETIC(TYPE) ((((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_LDOUBLE)) || ((TYPE) == TYPE_ENUM)) #define TYPE_UNSIGNED(TYPE) ((TYPE) & 0x0100) #define TYPE_SIGNED(TYPE) (!TYPE_UNSIGNED(TYPE)) -#define TYPE_MKUNSIGNED(TYPE) ((TYPE) | 0x0100) -#define TYPE_RANK(TYPE) ((TYPE) & ~0x0100) +#define TYPE_MKUNSIGNED(TYPE) (((TYPE) & ~0xF000) | 0x0100) +#define TYPE_RANK(TYPE) ((TYPE) & ~0xF1FF) #define TYPE_PTR(TYPE) (((TYPE) & TYPE_MASK) == TYPE_POINTER) #define TYPE_DEFAULT 0x0000 #define TYPE_VOID 0x0100 @@ -839,8 +865,17 @@ struct compile_state { #define TYPE_FLOAT 0x0c00 #define TYPE_DOUBLE 0x0d00 #define TYPE_LDOUBLE 0x0e00 /* long double */ + +/* Note: TYPE_ENUM is chosen very carefully so TYPE_RANK works */ +#define TYPE_ENUM 0x1600 +#define TYPE_LIST 0x1700 +/* TYPE_LIST is a basic building block when defining enumerations + * type->field_ident holds the name of this enumeration entry. + * type->right holds the entry in the list. + */ + #define TYPE_STRUCT 0x1000 -#define TYPE_ENUM 0x1100 +#define TYPE_UNION 0x1100 #define TYPE_POINTER 0x1200 /* For TYPE_POINTER: * type->left holds the type pointed to. @@ -860,17 +895,13 @@ struct compile_state { * type->left and type->right holds to types that overlap * each other in memory. */ -#define TYPE_ARRAY 0x1600 +#define TYPE_ARRAY 0x1800 /* TYPE_ARRAY is a basic building block when definitng arrays. * type->left holds the type we are an array of. * type-> holds the number of elements. */ -#ifdef __x86_64__ -#define ELEMENT_COUNT_UNSPECIFIED (~0U) -#else -#define ELEMENT_COUNT_UNSPECIFIED (~0UL) -#endif +#define ELEMENT_COUNT_UNSPECIFIED ULONG_T_MAX struct type { unsigned int type; @@ -880,13 +911,13 @@ struct type { struct hash_entry *type_ident; }; -#define MAX_REGISTERS 75 -#define MAX_REG_EQUIVS 16 -#define REGISTER_BITS 16 -#define MAX_VIRT_REGISTERS (1<<REGISTER_BITS) #define TEMPLATE_BITS 7 #define MAX_TEMPLATES (1<<TEMPLATE_BITS) +#define MAX_REG_EQUIVS 16 #define MAX_REGC 14 +#define MAX_REGISTERS 75 +#define REGISTER_BITS 7 +#define MAX_VIRT_REGISTERS (1<<REGISTER_BITS) #define REG_UNSET 0 #define REG_UNNEEDED 1 #define REG_VIRT0 (MAX_REGISTERS + 0) @@ -895,10 +926,17 @@ struct type { #define REG_VIRT3 (MAX_REGISTERS + 3) #define REG_VIRT4 (MAX_REGISTERS + 4) #define REG_VIRT5 (MAX_REGISTERS + 5) -#define REG_VIRT6 (MAX_REGISTERS + 5) -#define REG_VIRT7 (MAX_REGISTERS + 5) -#define REG_VIRT8 (MAX_REGISTERS + 5) -#define REG_VIRT9 (MAX_REGISTERS + 5) +#define REG_VIRT6 (MAX_REGISTERS + 6) +#define REG_VIRT7 (MAX_REGISTERS + 7) +#define REG_VIRT8 (MAX_REGISTERS + 8) +#define REG_VIRT9 (MAX_REGISTERS + 9) + +#if (MAX_REGISTERS + 9) > MAX_VIRT_REGISTERS +#error "MAX_VIRT_REGISTERS to small" +#endif +#if (MAX_REGC + REGISTER_BITS) > 27 +#error "Too many id bits used" +#endif /* Provision for 8 register classes */ #define REG_SHIFT 0 @@ -999,7 +1037,7 @@ static void loc(FILE *fp, struct compile_state *state, struct triple *triple) state->file->report_name, state->file->report_line, col); } -static void __internal_error(struct compile_state *state, struct triple *ptr, +static void romcc_internal_error(struct compile_state *state, struct triple *ptr, char *fmt, ...) { va_list args; @@ -1017,7 +1055,7 @@ static void __internal_error(struct compile_state *state, struct triple *ptr, } -static void __internal_warning(struct compile_state *state, struct triple *ptr, +static void romcc_internal_warning(struct compile_state *state, struct triple *ptr, char *fmt, ...) { va_list args; @@ -1034,12 +1072,15 @@ static void __internal_warning(struct compile_state *state, struct triple *ptr, -static void __error(struct compile_state *state, struct triple *ptr, +static void romcc_error(struct compile_state *state, struct triple *ptr, char *fmt, ...) { va_list args; va_start(args, fmt); loc(stderr, state, ptr); + if (ptr && (state->debug & DEBUG_ABORT_ON_ERROR)) { + fprintf(stderr, "%p %s ", ptr, tops(ptr->op)); + } vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); @@ -1050,7 +1091,7 @@ static void __error(struct compile_state *state, struct triple *ptr, exit(1); } -static void __warning(struct compile_state *state, struct triple *ptr, +static void romcc_warning(struct compile_state *state, struct triple *ptr, char *fmt, ...) { va_list args; @@ -1063,15 +1104,15 @@ static void __warning(struct compile_state *state, struct triple *ptr, } #if DEBUG_ERROR_MESSAGES -# define internal_error fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),__internal_error -# define internal_warning fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),__internal_warning -# define error fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),__error -# define warning fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),__warning +# define internal_error fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),romcc_internal_error +# define internal_warning fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),romcc_internal_warning +# define error fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),romcc_error +# define warning fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),romcc_warning #else -# define internal_error __internal_error -# define internal_warning __internal_warning -# define error __error -# define warning __warning +# define internal_error romcc_internal_error +# define internal_warning romcc_internal_warning +# define error romcc_error +# define warning romcc_warning #endif #define FINISHME() warning(state, 0, "FINISHME @ %s.%s:%d", __FILE__, __func__, __LINE__) @@ -1236,7 +1277,9 @@ static struct occurance *new_occurance(struct compile_state *state) (last->col == col) && (last->line == line) && (last->function == function) && - (strcmp(last->filename, filename) == 0)) { + ((last->filename == filename) || + (strcmp(last->filename, filename) == 0))) + { get_occurance(last); return last; } @@ -1501,7 +1544,10 @@ static struct block *block_of_triple(struct compile_state *state, struct triple *ins) { struct triple *first; - first = RHS(state->main_function, 0); + if (!ins) { + return 0; + } + first = state->first; while(ins != first && !triple_stores_block(state, ins)) { if (ins == ins->prev) { internal_error(state, 0, "ins == ins->prev?"); @@ -1591,12 +1637,12 @@ static void display_triple(FILE *fp, struct triple *ins) if (ins->op == OP_INTCONST) { fprintf(fp, "(%p) %c%c %-7s %-2d %-10s <0x%08lx> ", ins, pre, post, reg, ins->template_id, tops(ins->op), - ins->u.cval); + (unsigned long)(ins->u.cval)); } else if (ins->op == OP_ADDRCONST) { fprintf(fp, "(%p) %c%c %-7s %-2d %-10s %-10p <0x%08lx>", ins, pre, post, reg, ins->template_id, tops(ins->op), - MISC(ins, 0), ins->u.cval); + MISC(ins, 0), (unsigned long)(ins->u.cval)); } else { int i, count; @@ -1630,7 +1676,17 @@ static void display_triple(FILE *fp, struct triple *ins) fflush(fp); } -static int triple_is_pure(struct compile_state *state, struct triple *ins) +static void display_func(FILE *fp, struct triple *func) +{ + struct triple *first, *ins; + first = ins = RHS(func, 0); + do { + display_triple(fp, ins); + ins = ins->next; + } while(ins != first); +} + +static int triple_is_pure(struct compile_state *state, struct triple *ins, unsigned id) { /* Does the triple have no side effects. * I.e. Rexecuting the triple with the same arguments @@ -1643,7 +1699,7 @@ static int triple_is_pure(struct compile_state *state, struct triple *ins) internal_error(state, 0, "Purity of %s not known\n", tops(ins->op)); } - return pure == PURE; + return (pure == PURE) && !(id & TRIPLE_FLAG_VOLATILE); } static int triple_is_branch(struct compile_state *state, struct triple *ins) @@ -1685,6 +1741,14 @@ static int triple_is_def(struct compile_state *state, struct triple *ins) return is_def; } +static int triple_is_structural(struct compile_state *state, struct triple *ins) +{ + int is_structural; + valid_ins(state, ins); + is_structural = (table_ops[ins->op].flags & STRUCTURAL) == STRUCTURAL; + return is_structural; +} + static struct triple **triple_iter(struct compile_state *state, size_t count, struct triple **vector, struct triple *ins, struct triple **last) @@ -1807,11 +1871,16 @@ static void release_triple(struct compile_state *state, struct triple *ptr) struct block *block; /* Make certain the we are not the first or last element of a block */ block = block_of_triple(state, ptr); - if (block && (block->last == ptr)) { - block->last = ptr->prev; - } - if (block && (block->first == ptr)) { - block->first = ptr->next; + if (block) { + if ((block->last == ptr) && (block->first == ptr)) { + block->last = block->first = 0; + } + else if (block->last == ptr) { + block->last = ptr->prev; + } + else if (block->first == ptr) { + block->first = ptr->next; + } } /* Remove ptr from use chains where it is the user */ expr = triple_rhs(state, ptr, 0); @@ -2240,9 +2309,9 @@ static void end_scope(struct compile_state *state) struct hash_entry *entry; entry = state->hash_table[i]; while(entry) { - end_scope_syms(&entry->sym_label, depth); - end_scope_syms(&entry->sym_struct, depth); - end_scope_syms(&entry->sym_ident, depth); + end_scope_syms(&entry->sym_label, depth); + end_scope_syms(&entry->sym_tag, depth); + end_scope_syms(&entry->sym_ident, depth); entry = entry->next; } } @@ -2957,19 +3026,17 @@ static long_t mprimary_expr(struct compile_state *state, int index) break; case TOK_LIT_INT: { + long lval; char *end; meat(state, index, TOK_LIT_INT); errno = 0; - val = strtol(state->token[index].val.str, &end, 0); -#ifdef __x86_64__ - if (((val == INT_MIN) || (val == INT_MAX)) && - (errno == ERANGE)) { -#else - if (((val == LONG_MIN) || (val == LONG_MAX)) && - (errno == ERANGE)) { -#endif + lval = strtol(state->token[index].val.str, &end, 0); + if ((lval > LONG_T_MAX) || (lval < LONG_T_MIN) || + (((lval == LONG_MIN) || (lval == LONG_MAX)) && + (errno == ERANGE))) { error(state, 0, "Integer constant to large"); } + val = lval; break; } default: @@ -3779,6 +3846,12 @@ static struct type uint_type = { .type = TYPE_UINT }; static struct type long_type = { .type = TYPE_LONG }; static struct type ulong_type = { .type = TYPE_ULONG }; +static struct type void_func = { + .type = TYPE_FUNCTION, + .left = &void_type, + .right = &void_type, +}; + static struct triple *variable(struct compile_state *state, struct type *type) { struct triple *result; @@ -3913,7 +3986,7 @@ static void name_of(FILE *fp, struct type *type) } case TYPE_ARRAY: name_of(fp, type->left); - fprintf(fp, " [%ld]", type->elements); + fprintf(fp, " [%ld]", (long)(type->elements)); break; default: fprintf(fp, "????: %x", type->type & TYPE_MASK); @@ -4174,8 +4247,8 @@ static void arrays_complete(struct compile_state *state, struct type *type) static unsigned int do_integral_promotion(unsigned int type) { type &= TYPE_MASK; - if (TYPE_INTEGER(type) && - TYPE_RANK(type) < TYPE_RANK(TYPE_INT)) { + if (type == TYPE_ENUM) type = TYPE_INT; + if (TYPE_INTEGER(type) && (TYPE_RANK(type) < TYPE_RANK(TYPE_INT))) { type = TYPE_INT; } return type; @@ -4186,6 +4259,9 @@ static unsigned int do_arithmetic_conversion( { left &= TYPE_MASK; right &= TYPE_MASK; + /* Convert enums to ints */ + if (left == TYPE_ENUM) left = TYPE_INT; + if (right == TYPE_ENUM) right = TYPE_INT; if ((left == TYPE_LDOUBLE) || (right == TYPE_LDOUBLE)) { return TYPE_LDOUBLE; } @@ -4522,6 +4598,8 @@ static struct triple *int_const( } +static struct triple *read_expr(struct compile_state *state, struct triple *def); + static struct triple *do_mk_addr_expr(struct compile_state *state, struct triple *expr, struct type *type, ulong_t offset) { @@ -4544,6 +4622,9 @@ static struct triple *do_mk_addr_expr(struct compile_state *state, RHS(expr, 0), int_const(state, &ulong_type, offset)); } + if (!result) { + internal_error(state, expr, "cannot take address of expression"); + } return result; } @@ -4633,6 +4714,10 @@ static struct triple *read_expr(struct compile_state *state, struct triple *def) if (is_in_reg(state, def)) { op = OP_READ; } else { + if (def->op == OP_SDECL) { + def = mk_addr_expr(state, def, 0); + def = mk_deref_expr(state, def); + } op = OP_LOAD; } return triple(state, op, def->type, def, 0); @@ -5040,6 +5125,19 @@ static struct triple *flatten_cond( return read_expr(state, val); } +static int local_triple(struct compile_state *state, + struct triple *func, struct triple *ins) +{ + int local = (ins->id & TRIPLE_FLAG_LOCAL); +#if 0 + if (!local) { + fprintf(stderr, "global: "); + display_triple(stderr, ins); + } +#endif + return local; +} + struct triple *copy_func(struct compile_state *state, struct triple *ofunc, struct occurance *base_occurance) { @@ -5051,7 +5149,7 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc, fprintf(stdout, "\n"); loc(stdout, state, 0); fprintf(stdout, "\n__________ copy_func _________\n"); - print_triple(state, ofunc); + display_func(stdout, ofunc); fprintf(stdout, "__________ copy_func _________ done\n\n"); #endif @@ -5086,6 +5184,8 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc, if (old == MISC(ofunc, 0)) { MISC(nfunc, 0) = new; } + /* Remember which instructions are local */ + old->id |= TRIPLE_FLAG_LOCAL; old = old->next; } while(old != ofirst); @@ -5100,8 +5200,13 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc, for(i = 0; i < count; i++) { oexpr = &old->param[i]; nexpr = &new->param[i]; - if (!*nexpr && *oexpr && (*oexpr)->use) { - *nexpr = (*oexpr)->use->member; + if (*oexpr && !*nexpr) { + if (!local_triple(state, ofunc, *oexpr)) { + *nexpr = *oexpr; + } + else if ((*oexpr)->use) { + *nexpr = (*oexpr)->use->member; + } if (*nexpr == old) { internal_error(state, 0, "new == old?"); } @@ -5120,6 +5225,8 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc, new = nfirst; do { unuse_triple(old, new); + /* Forget which instructions are local */ + old->id &= ~TRIPLE_FLAG_LOCAL; old = old->next; new = new->next; } while ((old != ofirst) && (new != nfirst)); @@ -5169,7 +5276,7 @@ static struct triple *flatten_call( fprintf(stdout, "\n"); loc(stdout, state, 0); fprintf(stdout, "\n__________ flatten_call _________\n"); - print_triple(state, nfunc); + display_func(stdout, nfunc); fprintf(stdout, "__________ flatten_call _________ done\n\n"); #endif @@ -5238,8 +5345,9 @@ static struct triple *flatten( } break; case OP_BLOBCONST: - insert_triple(state, first, ptr); + insert_triple(state, state->first, ptr); ptr->id |= TRIPLE_FLAG_FLATTENED; + ptr->id &= ~TRIPLE_FLAG_LOCAL; ptr = triple(state, OP_SDECL, ptr->type, ptr, 0); use_triple(MISC(ptr, 0), ptr); break; @@ -5275,10 +5383,17 @@ static struct triple *flatten( use_triple(ptr, MISC(ptr, 0)); break; case OP_ADDRCONST: - case OP_SDECL: MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0)); use_triple(MISC(ptr, 0), ptr); break; + case OP_SDECL: + first = state->first; + MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0)); + use_triple(MISC(ptr, 0), ptr); + insert_triple(state, first, ptr); + ptr->id |= TRIPLE_FLAG_FLATTENED; + ptr->id &= ~TRIPLE_FLAG_LOCAL; + return ptr; case OP_ADECL: break; default: @@ -5290,6 +5405,7 @@ static struct triple *flatten( if (ptr) { insert_triple(state, first, ptr); ptr->id |= TRIPLE_FLAG_FLATTENED; + ptr->id &= ~TRIPLE_FLAG_LOCAL; } return ptr; } @@ -5489,6 +5605,11 @@ static int is_const(struct triple *ins) return IS_CONST_OP(ins->op); } +static int is_simple_const(struct triple *ins) +{ + return IS_CONST_OP(ins->op) && (ins->op != OP_ADDRCONST); +} + static int constants_equal(struct compile_state *state, struct triple *left, struct triple *right) { @@ -5638,6 +5759,9 @@ static ulong_t read_const(struct compile_state *state, internal_error(state, rhs, "bad type to read_const\n"); break; } + if (!is_simple_const(rhs)) { + internal_error(state, rhs, "bad op to read_const\n"); + } return rhs->u.cval; } @@ -5702,9 +5826,12 @@ static void wipe_ins(struct compile_state *state, struct triple *ins) static void mkcopy(struct compile_state *state, struct triple *ins, struct triple *rhs) { + struct block *block; + block = block_of_triple(state, ins); wipe_ins(state, ins); ins->op = OP_COPY; ins->sizes = TRIPLE_SIZES(0, 1, 0, 0); + ins->u.block = block; RHS(ins, 0) = rhs; use_triple(RHS(ins, 0), ins); } @@ -5739,7 +5866,7 @@ static void mkaddr_const(struct compile_state *state, static void flatten_structures(struct compile_state *state) { struct triple *ins, *first; - first = RHS(state->main_function, 0); + first = state->first; ins = first; /* Pass one expand structure values into valvecs. */ @@ -6004,6 +6131,7 @@ static void simplify_smod(struct compile_state *state, struct triple *ins) RHS(ins, 1) = val; } } + static void simplify_umod(struct compile_state *state, struct triple *ins) { if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) { @@ -6354,7 +6482,8 @@ static void simplify_lfalse(struct compile_state *state, struct triple *ins) mkconst(state, ins, left == 0); } /* Otherwise if I am the only user... */ - else if ((RHS(ins, 0)->use->member == ins) && (RHS(ins, 0)->use->next == 0)) { + else if ((RHS(ins, 0)->use) && + (RHS(ins, 0)->use->member == ins) && (RHS(ins, 0)->use->next == 0)) { int need_copy = 1; /* Invert a boolean operation */ switch(RHS(ins, 0)->op) { @@ -6423,22 +6552,88 @@ static void simplify_copy(struct compile_state *state, struct triple *ins) } } +static int phi_present(struct block *block) +{ + struct triple *ptr; + if (!block) { + return 0; + } + ptr = block->first; + do { + if (ptr->op == OP_PHI) { + return 1; + } + ptr = ptr->next; + } while(ptr != block->last); + return 0; +} + +static int phi_dependency(struct block *block) +{ + /* A block has a phi dependency if a phi function + * depends on that block to exist, and makes a block + * that is otherwise useless unsafe to remove. + */ + if (block && ( + phi_present(block->left) || + phi_present(block->right))) { + return 1; + } + return 0; +} + +static struct triple *branch_target(struct compile_state *state, struct triple *ins) +{ + struct triple *targ; + targ = TARG(ins, 0); + /* During scc_transform temporary triples are allocated that + * loop back onto themselves. If I see one don't advance the + * target. + */ + while(triple_is_structural(state, targ) && (targ->next != targ)) { + targ = targ->next; + } + return targ; +} + + static void simplify_branch(struct compile_state *state, struct triple *ins) { - struct block *block; + int simplified; if (ins->op != OP_BRANCH) { internal_error(state, ins, "not branch"); } if (ins->use != 0) { internal_error(state, ins, "branch use"); } -#warning "FIXME implement simplify branch." /* The challenge here with simplify branch is that I need to * make modifications to the control flow graph as well - * as to the branch instruction itself. + * as to the branch instruction itself. That is handled + * by rebuilding the basic blocks after simplify all is called. + */ + + /* If we have a branch to an unconditional branch update + * our target. But watch out for dependencies from phi + * functions. + */ + do { + struct triple *targ; + simplified = 0; + targ = branch_target(state, ins); + if ((targ != ins) && triple_is_uncond_branch(state, targ)) { + if (!phi_dependency(targ->u.block)) + { + unuse_triple(TARG(ins, 0), ins); + TARG(ins, 0) = TARG(targ, 0); + use_triple(TARG(ins, 0), ins); + simplified = 1; + } + } + } while(simplified); + + /* If we have a conditional branch with a constant condition + * make it an unconditional branch. */ - block = ins->u.block; - if (TRIPLE_RHS(ins->sizes) && is_const(RHS(ins, 0))) { struct triple *targ; ulong_t value; @@ -6454,8 +6649,11 @@ static void simplify_branch(struct compile_state *state, struct triple *ins) unuse_triple(targ, ins); TARG(ins, 0) = ins->next; } -#warning "FIXME handle the case of making a branch unconditional" } + + /* If we have an unconditional branch to the next instruction + * make it a noop. + */ if (TARG(ins, 0) == ins->next) { unuse_triple(ins->next, ins); if (TRIPLE_RHS(ins->sizes)) { @@ -6467,50 +6665,26 @@ static void simplify_branch(struct compile_state *state, struct triple *ins) if (ins->use) { internal_error(state, ins, "noop use != 0"); } -#warning "FIXME handle the case of killing a branch" } } -int phi_present(struct block *block) -{ - struct triple *ptr; - if (!block) { - return 0; - } - ptr = block->first; - do { - if (ptr->op == OP_PHI) { - return 1; - } - ptr = ptr->next; - } while(ptr != block->last); - return 0; -} - static void simplify_label(struct compile_state *state, struct triple *ins) { -#warning "FIXME enable simplify_label" - struct triple *first, *last; - first = RHS(state->main_function, 0); - last = first->prev; - /* Ignore the first and last instructions */ - if ((ins == first) || (ins == last)) { + struct triple *first; + first = state->first; + /* Ignore volatile labels */ + if (!triple_is_pure(state, ins, ins->id)) { return; } if (ins->use == 0) { ins->op = OP_NOOP; } else if (ins->prev->op == OP_LABEL) { - struct block *block; - block = ins->prev->u.block; /* In general it is not safe to merge one label that * imediately follows another. The problem is that the empty * looking block may have phi functions that depend on it. */ - if (!block || - (!phi_present(block->left) && - !phi_present(block->right))) - { + if (!phi_dependency(ins->prev->u.block)) { struct triple_set *user, *next; ins->op = OP_NOOP; for(user = ins->use; user; user = next) { @@ -6532,22 +6706,43 @@ static void simplify_label(struct compile_state *state, struct triple *ins) static void simplify_phi(struct compile_state *state, struct triple *ins) { - struct triple **expr; - ulong_t value; - expr = triple_rhs(state, ins, 0); - if (!*expr || !is_const(*expr)) { + struct triple **slot; + struct triple *value; + int zrhs, i; + ulong_t cvalue; + slot = &RHS(ins, 0); + zrhs = TRIPLE_RHS(ins->sizes); + if (zrhs == 0) { return; } - value = read_const(state, ins, expr); - for(;expr;expr = triple_rhs(state, ins, expr)) { - if (!*expr || !is_const(*expr)) { - return; + /* See if all of the rhs members of a phi have the same value */ + if (slot[0] && is_simple_const(slot[0])) { + cvalue = read_const(state, ins, &slot[0]); + for(i = 1; i < zrhs; i++) { + if ( !slot[i] || + !is_simple_const(slot[i]) || + (cvalue != read_const(state, ins, &slot[i]))) { + break; + } } - if (value != read_const(state, ins, expr)) { + if (i == zrhs) { + mkconst(state, ins, cvalue); return; } } - mkconst(state, ins, value); + + /* See if all of rhs members of a phi are the same */ + value = slot[0]; + for(i = 1; i < zrhs; i++) { + if (slot[i] != value) { + break; + } + } + if (i == zrhs) { + /* If the phi has a single value just copy it */ + mkcopy(state, ins, value); + return; + } } @@ -6634,7 +6829,7 @@ static const simplify_t table_simplify[] = { #if 0 #define simplify_branch simplify_noop #endif -#if 1 +#if 0 #define simplify_label simplify_noop #endif @@ -6647,6 +6842,10 @@ static const simplify_t table_simplify[] = { #define simplify_bsr simplify_noop #endif +#if 1 +#define simplify_piece simplify_noop +#endif + [OP_SDIVT ] = simplify_sdivt, [OP_UDIVT ] = simplify_udivt, [OP_SMUL ] = simplify_smul, @@ -6692,7 +6891,7 @@ static const simplify_t table_simplify[] = { [OP_WRITE ] = simplify_noop, [OP_READ ] = simplify_noop, [OP_COPY ] = simplify_copy, -[OP_PIECE ] = simplify_noop, +[OP_PIECE ] = simplify_piece, [OP_ASM ] = simplify_noop, [OP_DOT ] = simplify_noop, @@ -6736,14 +6935,66 @@ static void simplify(struct compile_state *state, struct triple *ins) op, tops(op)); return; } +#if !DEBUG_SIMPLIFY do_simplify(state, ins); +#else + { + struct triple *dup; + int ins_count, dup_count; + dup = dup_triple(state, ins); + do_simplify(state, ins); + ins_count = TRIPLE_SIZE(ins->sizes); + dup_count = TRIPLE_SIZE(dup->sizes); + if ((dup->op != ins->op) || + (ins_count != dup_count) || + (memcmp(dup->param, ins->param, + dup_count * sizeof(dup->param[0])) != 0) || + (memcmp(&dup->u, &ins->u, sizeof(ins->u)) != 0)) + { + int i, min_count; + fprintf(stderr, "simplify: %11p", ins); + if (dup->op == ins->op) { + fprintf(stderr, " %-11s", tops(ins->op)); + } else { + fprintf(stderr, " [%-10s %-10s]", + tops(dup->op), tops(ins->op)); + } + min_count = dup_count; + if (min_count > ins_count) { + min_count = ins_count; + } + for(i = 0; i < min_count; i++) { + if (dup->param[i] == ins->param[i]) { + fprintf(stderr, " %-11p", ins->param[i]); + } else { + fprintf(stderr, " [%-10p %-10p]", + dup->param[i], ins->param[i]); + } + } + for(; i < ins_count; i++) { + fprintf(stderr, " [%-9p]", ins->param[i]); + } + for(; i < dup_count; i++) { + fprintf(stderr, " [%-9p]", dup->param[i]); + } + fprintf(stderr, "\n"); + fflush(stderr); + } + xfree(dup); + } +#endif } while(ins->op != op); } static void simplify_all(struct compile_state *state) { struct triple *ins, *first; - first = RHS(state->main_function, 0); + first = state->first; + ins = first->prev; + do { + simplify(state, ins); + ins = ins->prev; + } while(ins != first->prev); ins = first; do { simplify(state, ins); @@ -6913,7 +7164,7 @@ static struct type *register_builtin_type(struct compile_state *state, field = field->right; } elements++; - symbol(state, ident, &ident->sym_struct, 0, type); + symbol(state, ident, &ident->sym_tag, 0, type); type->type_ident = ident; type->elements = elements; } @@ -7115,11 +7366,7 @@ static struct triple *integer_constant(struct compile_state *state) errno = 0; decimal = (tk->val.str[0] != '0'); val = strtoul(tk->val.str, &end, 0); -#ifdef __x86_64__ - if ((val == UINT_MAX) && (errno == ERANGE)) { -#else - if ((val == ULONG_MAX) && (errno == ERANGE)) { -#endif + if ((val > ULONG_T_MAX) || ((val == ULONG_MAX) && (errno == ERANGE))) { error(state, 0, "Integer constant to large"); } u = l = 0; @@ -7143,33 +7390,25 @@ static struct triple *integer_constant(struct compile_state *state) } else if (l) { type = &long_type; -#ifdef __x86_64__ - if (!decimal && (val > INT_MAX)) { -#else - if (!decimal && (val > LONG_MAX)) { -#endif + if (!decimal && (val > LONG_T_MAX)) { type = &ulong_type; } } else if (u) { type = &uint_type; - if (val > UINT_MAX) { + if (val > UINT_T_MAX) { type = &ulong_type; } } else { type = &int_type; - if (!decimal && (val > INT_MAX) && (val <= UINT_MAX)) { + if (!decimal && (val > INT_T_MAX) && (val <= UINT_T_MAX)) { type = &uint_type; } -#ifdef __x86_64__ - else if (!decimal && (val > INT_MAX)) { -#else - else if (!decimal && (val > LONG_MAX)) { -#endif + else if (!decimal && (val > LONG_T_MAX)) { type = &ulong_type; } - else if (val > INT_MAX) { + else if (val > INT_T_MAX) { type = &long_type; } } @@ -7189,7 +7428,6 @@ static struct triple *primary_expr(struct compile_state *state) /* Here ident is either: * a varable name * a function name - * an enumeration constant. */ eat(state, TOK_IDENT); ident = state->token[0].ident; @@ -7200,11 +7438,17 @@ static struct triple *primary_expr(struct compile_state *state) break; } case TOK_ENUM_CONST: + { + struct hash_entry *ident; /* Here ident is an enumeration constant */ eat(state, TOK_ENUM_CONST); - def = 0; - FINISHME(); + ident = state->token[0].ident; + if (!ident->sym_ident) { + error(state, 0, "%s undeclared", ident->name); + } + def = ident->sym_ident->def; break; + } case TOK_LPAREN: eat(state, TOK_LPAREN); def = expr(state); @@ -8106,35 +8350,113 @@ static void labeled_statement(struct compile_state *state, struct triple *first) static void switch_statement(struct compile_state *state, struct triple *first) { - FINISHME(); + struct triple *value, *top, *end, *dbranch; + struct hash_entry *ident; + + /* See if we have a valid switch statement */ eat(state, TOK_SWITCH); eat(state, TOK_LPAREN); - expr(state); + value = expr(state); + integral(state, value); + value = read_expr(state, value); eat(state, TOK_RPAREN); + /* Generate the needed pieces */ + top = label(state); + end = label(state); + dbranch = branch(state, end, 0); + /* Remember where case branches and break goes */ + start_scope(state); + ident = state->i_switch; + symbol(state, ident, &ident->sym_ident, value, value->type); + ident = state->i_case; + symbol(state, ident, &ident->sym_ident, top, top->type); + ident = state->i_break; + symbol(state, ident, &ident->sym_ident, end, end->type); + ident = state->i_default; + symbol(state, ident, &ident->sym_ident, dbranch, dbranch->type); + /* Thread them together */ + flatten(state, first, value); + flatten(state, first, top); + flatten(state, first, dbranch); statement(state, first); - error(state, 0, "switch statements are not implemented"); - FINISHME(); + flatten(state, first, end); + /* Cleanup the switch scope */ + end_scope(state); } static void case_statement(struct compile_state *state, struct triple *first) { - FINISHME(); + struct triple *cvalue, *dest, *test, *jmp; + struct triple *ptr, *value, *top, *dbranch; + + /* See if w have a valid case statement */ eat(state, TOK_CASE); - constant_expr(state); + cvalue = constant_expr(state); + integral(state, cvalue); + if (cvalue->op != OP_INTCONST) { + error(state, 0, "integer constant expected"); + } eat(state, TOK_COLON); + if (!state->i_case->sym_ident) { + error(state, 0, "case statement not within a switch"); + } + + /* Lookup the interesting pieces */ + top = state->i_case->sym_ident->def; + value = state->i_switch->sym_ident->def; + dbranch = state->i_default->sym_ident->def; + + /* See if this case label has already been used */ + for(ptr = top; ptr != dbranch; ptr = ptr->next) { + if (ptr->op != OP_EQ) { + continue; + } + if (RHS(ptr, 1)->u.cval == cvalue->u.cval) { + error(state, 0, "duplicate case %d statement", + cvalue->u.cval); + } + } + /* Generate the needed pieces */ + dest = label(state); + test = triple(state, OP_EQ, &int_type, value, cvalue); + jmp = branch(state, dest, test); + /* Thread the pieces together */ + flatten(state, dbranch, test); + flatten(state, dbranch, jmp); + flatten(state, dbranch, label(state)); + flatten(state, first, dest); statement(state, first); - error(state, 0, "case statements are not implemented"); - FINISHME(); } static void default_statement(struct compile_state *state, struct triple *first) { - FINISHME(); + struct triple *dest; + struct triple *dbranch, *end; + + /* See if we have a valid default statement */ eat(state, TOK_DEFAULT); eat(state, TOK_COLON); + + if (!state->i_case->sym_ident) { + error(state, 0, "default statement not within a switch"); + } + + /* Lookup the interesting pieces */ + dbranch = state->i_default->sym_ident->def; + end = state->i_break->sym_ident->def; + + /* See if a default statement has already happened */ + if (TARG(dbranch, 0) != end) { + error(state, 0, "duplicate default statement"); + } + + /* Generate the needed pieces */ + dest = label(state); + + /* Thread the pieces together */ + TARG(dbranch, 0) = dest; + flatten(state, first, dest); statement(state, first); - error(state, 0, "default statements are not implemented"); - FINISHME(); } static void asm_statement(struct compile_state *state, struct triple *first) @@ -8577,33 +8899,71 @@ static struct type *typedef_name( } static struct type *enum_specifier( - struct compile_state *state, unsigned int specifiers) + struct compile_state *state, unsigned int spec) { + struct hash_entry *ident; + ulong_t base; int tok; - struct type *type; - type = 0; - FINISHME(); + struct type *enum_type; + enum_type = 0; + ident = 0; eat(state, TOK_ENUM); tok = peek(state); - if (tok == TOK_IDENT) { - eat(state, TOK_IDENT); + if ((tok == TOK_IDENT) || (tok == TOK_ENUM_CONST) || (tok == TOK_TYPE_NAME)) { + eat(state, tok); + ident = state->token[0].ident; + } - if ((tok != TOK_IDENT) || (peek(state) == TOK_LBRACE)) { + base = 0; + if (!ident || (peek(state) == TOK_LBRACE)) { + struct type **next; eat(state, TOK_LBRACE); + enum_type = new_type(TYPE_ENUM | spec, 0, 0); + enum_type->type_ident = ident; + next = &enum_type->right; do { + struct hash_entry *eident; + struct triple *value; + struct type *entry; eat(state, TOK_IDENT); + eident = state->token[0].ident; + if (eident->sym_ident) { + error(state, 0, "%s already declared", + eident->name); + } + eident->tok = TOK_ENUM_CONST; if (peek(state) == TOK_EQ) { + struct triple *val; eat(state, TOK_EQ); - constant_expr(state); - } + val = constant_expr(state); + integral(state, val); + base = val->u.cval; + } + value = int_const(state, &int_type, base); + symbol(state, eident, &eident->sym_ident, value, &int_type); + entry = new_type(TYPE_LIST, 0, 0); + entry->field_ident = eident; + *next = entry; + next = &entry->right; + base += 1; if (peek(state) == TOK_COMMA) { eat(state, TOK_COMMA); } } while(peek(state) != TOK_RBRACE); eat(state, TOK_RBRACE); + if (ident) { + symbol(state, ident, &ident->sym_tag, 0, enum_type); + } } - FINISHME(); - return type; + if (ident && ident->sym_tag && + ident->sym_tag->type && + ((ident->sym_tag->type->type & TYPE_MASK) == TYPE_ENUM)) { + enum_type = clone_type(spec, ident->sym_tag->type); + } + else if (ident && !enum_type) { + error(state, 0, "enum %s undeclared", ident->name); + } + return enum_type; } static struct type *struct_declarator( @@ -8649,7 +9009,7 @@ static struct type *struct_or_union_specifier( break; } tok = peek(state); - if ((tok == TOK_IDENT) || (tok == TOK_TYPE_NAME)) { + if ((tok == TOK_IDENT) || (tok == TOK_ENUM_CONST) || (tok == TOK_TYPE_NAME)) { eat(state, tok); ident = state->token[0].ident; } @@ -8689,13 +9049,15 @@ static struct type *struct_or_union_specifier( struct_type->type_ident = ident; struct_type->elements = elements; if (ident) { - symbol(state, ident, &ident->sym_struct, 0, struct_type); + symbol(state, ident, &ident->sym_tag, 0, struct_type); } } - if (ident && ident->sym_struct) { - struct_type = clone_type(spec, ident->sym_struct->type); + if (ident && ident->sym_tag && + ident->sym_tag->type && + ((ident->sym_tag->type->type & TYPE_MASK) == TYPE_STRUCT)) { + struct_type = clone_type(spec, ident->sym_tag->type); } - else if (ident && !ident->sym_struct) { + else if (ident && !struct_type) { error(state, 0, "struct %s undeclared", ident->name); } return struct_type; @@ -9078,7 +9440,6 @@ static struct triple *initializer( struct compile_state *state, struct type *type) { struct triple *result; -#warning "FIXME handle string pointer initializers " #warning "FIXME more consistent initializer handling (where should eval_const_expr go?" if (peek(state) != TOK_LBRACE) { result = assignment_expr(state); @@ -9089,6 +9450,12 @@ static struct triple *initializer( (equiv_types(type->left, result->type->left))) { type->elements = result->type->elements; } + if (is_stable(state, result) && + ((result->type->type & TYPE_MASK) == TYPE_ARRAY) && + (type->type & TYPE_MASK) != TYPE_ARRAY) + { + result = array_to_pointer(state, result); + } if (!is_init_compatible(state, type, result->type)) { error(state, 0, "Incompatible types in initializer"); } @@ -9423,19 +9790,19 @@ static void decls(struct compile_state *state) * Data structurs for optimation. */ -static void do_use_block( +static int do_use_block( struct block *used, struct block_set **head, struct block *user, int front) { struct block_set **ptr, *new; if (!used) - return; + return 0; if (!user) - return; + return 0; ptr = head; while(*ptr) { if ((*ptr)->member == user) { - return; + return 0; } ptr = &(*ptr)->next; } @@ -9449,11 +9816,14 @@ static void do_use_block( new->next = 0; *ptr = new; } + return 1; } -static void do_unuse_block( +static int do_unuse_block( struct block *used, struct block_set **head, struct block *unuser) { struct block_set *use, **ptr; + int count; + count = 0; ptr = head; while(*ptr) { use = *ptr; @@ -9461,25 +9831,29 @@ static void do_unuse_block( *ptr = use->next; memset(use, -1, sizeof(*use)); xfree(use); + count += 1; } else { ptr = &use->next; } } + return count; } static void use_block(struct block *used, struct block *user) { + int count; /* Append new to the head of the list, print_block * depends on this. */ - do_use_block(used, &used->use, user, 1); - used->users++; + count = do_use_block(used, &used->use, user, 1); + used->users += count; } static void unuse_block(struct block *used, struct block *unuser) { - do_unuse_block(used, &used->use, unuser); - used->users--; + int count; + count = do_unuse_block(used, &used->use, unuser); + used->users -= count; } static void idom_block(struct block *idom, struct block *user) @@ -9522,48 +9896,25 @@ static void unipdomf_block(struct block *block, struct block *unipdomf) do_unuse_block(block, &block->ipdomfrontier, unipdomf); } - - -static int do_walk_triple(struct compile_state *state, - struct triple *ptr, int depth, - int (*cb)(struct compile_state *state, struct triple *ptr, int depth)) +static int walk_triples( + struct compile_state *state, + int (*cb)(struct compile_state *state, struct triple *ptr)) { + struct triple *ptr; int result; - result = cb(state, ptr, depth); - if ((result == 0) && (ptr->op == OP_LIST)) { - struct triple *list; - list = ptr; - ptr = RHS(list, 0); - do { - result = do_walk_triple(state, ptr, depth + 1, cb); - if (ptr->next->prev != ptr) { - internal_error(state, ptr->next, "bad prev"); - } - ptr = ptr->next; - - } while((result == 0) && (ptr != RHS(list, 0))); - } + ptr = state->first; + do { + result = cb(state, ptr); + if (ptr->next->prev != ptr) { + internal_error(state, ptr->next, "bad prev"); + } + ptr = ptr->next; + } while((result == 0) && (ptr != state->first)); return result; } -static int walk_triple( - struct compile_state *state, - struct triple *ptr, - int (*cb)(struct compile_state *state, struct triple *ptr, int depth)) -{ - return do_walk_triple(state, ptr, 0, cb); -} - -static void do_print_prefix(int depth) -{ - int i; - for(i = 0; i < depth; i++) { - printf(" "); - } -} - #define PRINT_LIST 1 -static int do_print_triple(struct compile_state *state, struct triple *ins, int depth) +static int do_print_triple(struct compile_state *state, struct triple *ins) { int op; op = ins->op; @@ -9575,7 +9926,6 @@ static int do_print_triple(struct compile_state *state, struct triple *ins, int if ((op == OP_LABEL) && (ins->use)) { printf("\n%p:\n", ins); } - do_print_prefix(depth); display_triple(stdout, ins); if ((ins->op == OP_BRANCH) && ins->use) { @@ -9587,14 +9937,9 @@ static int do_print_triple(struct compile_state *state, struct triple *ins, int return 0; } -static void print_triple(struct compile_state *state, struct triple *ins) -{ - walk_triple(state, ins, do_print_triple); -} - static void print_triples(struct compile_state *state) { - print_triple(state, state->main_function); + walk_triples(state, do_print_triple); } struct cf_block { @@ -9641,8 +9986,7 @@ static struct block *basic_block(struct compile_state *state, struct triple *first) { struct block *block; - struct triple *ptr, *final; - int op; + struct triple *ptr; if (first->op != OP_LABEL) { internal_error(state, 0, "block does not start with a label"); } @@ -9650,11 +9994,6 @@ static struct block *basic_block(struct compile_state *state, if (first->u.block != 0) { return first->u.block; } - /* Lookup the final instruction. - * It is important that the final instruction has it's own - * basic block. - */ - final = RHS(state->main_function, 0)->prev; /* Allocate another basic block structure */ state->last_vertex += 1; block = xcmalloc(sizeof(*block), "block"); @@ -9662,8 +10001,7 @@ static struct block *basic_block(struct compile_state *state, block->vertex = state->last_vertex; ptr = first; do { - if ((ptr != first) && (ptr->op == OP_LABEL) && - ((ptr->use) || ptr == final)) { + if ((ptr != first) && (ptr->op == OP_LABEL) && (ptr->use)) { break; } block->last = ptr; @@ -9671,20 +10009,20 @@ static struct block *basic_block(struct compile_state *state, if (triple_stores_block(state, ptr)) { ptr->u.block = block; } - if (ptr->op == OP_BRANCH) { + if (triple_is_branch(state, ptr)) { break; } ptr = ptr->next; - } while (ptr != RHS(state->main_function, 0)); - if (ptr == RHS(state->main_function, 0)) - return block; - op = ptr->op; - if (op == OP_LABEL) { + } while (ptr != state->first); + if (ptr == state->first) { + /* The block has no outflowing edges */ + } + else if (ptr->op == OP_LABEL) { block->left = basic_block(state, ptr); block->right = 0; use_block(block->left, block); } - else if (op == OP_BRANCH) { + else if (triple_is_branch(state, ptr)) { block->left = 0; /* Trace the branch target */ block->right = basic_block(state, TARG(ptr, 0)); @@ -9698,6 +10036,15 @@ static struct block *basic_block(struct compile_state *state, else { internal_error(state, 0, "Bad basic block split"); } +#if 0 + fprintf(stderr, "basic_block: %10p [%2d] ( %10p - %10p ) %10p [%2d] %10p [%2d] \n", + block, block->vertex, + block->first, block->last, + block->left ? block->left->first : 0, + block->left ? block->left->vertex : -1, + block->left ? block->left->first : 0, + block->left ? block->left->vertex : -1); +#endif return block; } @@ -9709,7 +10056,7 @@ static void walk_blocks(struct compile_state *state, struct triple *ptr, *first; struct block *last_block; last_block = 0; - first = RHS(state->main_function, 0); + first = state->first; ptr = first; do { struct block *block; @@ -9770,7 +10117,7 @@ static void prune_nonblock_triples(struct compile_state *state) struct block *block; struct triple *first, *ins, *next; /* Delete the triples not in a basic block */ - first = RHS(state->main_function, 0); + first = state->first; block = 0; ins = first; do { @@ -9790,20 +10137,43 @@ static void prune_nonblock_triples(struct compile_state *state) static void setup_basic_blocks(struct compile_state *state) { - if (!triple_stores_block(state, RHS(state->main_function, 0)) || - !triple_stores_block(state, RHS(state->main_function,0)->prev)) { + if (!triple_stores_block(state, state->first)) { internal_error(state, 0, "ins will not store block?"); } /* Find the basic blocks */ state->last_vertex = 0; - state->first_block = basic_block(state, RHS(state->main_function,0)); + state->first_block = basic_block(state, state->first); /* Delete the triples not in a basic block */ prune_nonblock_triples(state); - /* Find the last basic block */ - state->last_block = RHS(state->main_function, 0)->prev->u.block; - if (!state->last_block) { - internal_error(state, 0, "end not used?"); + + /* Find the last basic block. + * + * For purposes of reverse flow computation it is + * important that the last basic block is empty. + * This allows the control flow graph to be modified to + * have one unique starting block and one unique final block. + * With the insertion of a few extra edges. + * + * If the final block contained instructions it could contain + * phi functions from edges that would never contribute a + * value. Which for now at least I consider a compile error. + */ + state->last_block = block_of_triple(state, state->first->prev); + if ((state->last_block->first != state->last_block->last) || + (state->last_block->last->op != OP_LABEL)) + { + struct block *block, *prev_block; + struct triple *final; + prev_block = state->last_block; + final = label(state); + flatten(state, state->first, final); + use_triple(final, final); + block = basic_block(state, final); + state->last_block = block; + prev_block->left = block; + use_block(prev_block->left, prev_block); } + /* If we are debugging print what I have just done */ if (state->debug & DEBUG_BASIC_BLOCKS) { print_blocks(state, stdout); @@ -9886,7 +10256,7 @@ static void free_basic_blocks(struct compile_state *state) free_basic_block(state, state->first_block); state->last_vertex = 0; state->first_block = state->last_block = 0; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { if (triple_stores_block(state, ins)) { @@ -9955,7 +10325,7 @@ static int initialize_sdblock(struct sdom_block *sd, return vertex; } -static int initialize_sdpblock( +static int initialize_spdblock( struct compile_state *state, struct sdom_block *sd, struct block *parent, struct block *block, int vertex) { @@ -9973,24 +10343,24 @@ static int initialize_sdpblock( sd[vertex].ancestor = 0; sd[vertex].vertex = vertex; for(user = block->use; user; user = user->next) { - vertex = initialize_sdpblock(state, sd, block, user->member, vertex); + vertex = initialize_spdblock(state, sd, block, user->member, vertex); } return vertex; } -static int setup_sdpblocks(struct compile_state *state, struct sdom_block *sd) +static int setup_spdblocks(struct compile_state *state, struct sdom_block *sd) { struct block *block; int vertex; /* Setup as many sdpblocks as possible without using fake edges */ - vertex = initialize_sdpblock(state, sd, 0, state->last_block, 0); + vertex = initialize_spdblock(state, sd, 0, state->last_block, 0); /* Walk through the graph and find unconnected blocks. If * we can, add a fake edge from the unconnected blocks to the * end of the graph. */ block = state->first_block->last->next->u.block; - for(; block && block != state->first_block; block = block->last->next->u.block) { + for(; block && block != state->first_block; block = block->last->next->u.block) { if (sd[block->vertex].block == block) { continue; } @@ -10004,7 +10374,7 @@ static int setup_sdpblocks(struct compile_state *state, struct sdom_block *sd) block->left = state->last_block; use_block(block->left, block); - vertex = initialize_sdpblock(state, sd, state->last_block, block, vertex); + vertex = initialize_spdblock(state, sd, state->last_block, block, vertex); } return vertex; } @@ -10248,7 +10618,7 @@ static void find_post_dominators(struct compile_state *state) /* Step 1 initialize the basic block information */ sd = xcmalloc(sizeof(*sd) * (state->last_vertex + 1), "sdom_state"); - vertex = setup_sdpblocks(state, sd); + vertex = setup_spdblocks(state, sd); if (vertex != state->last_vertex) { internal_error(state, 0, "missing %d blocks\n", state->last_vertex - vertex); @@ -10309,13 +10679,12 @@ static void find_block_ipdomf(struct compile_state *state, struct block *block) } find_block_ipdomf(state, child); } - if (block->left && block->left->ipdom != block) { - ipdomf_block(block, block->left); - } - if (block->right && block->right->ipdom != block) { - ipdomf_block(block, block->right); + for(user = block->use; user; user = user->next) { + if (user->member->ipdom != block) { + ipdomf_block(block, user->member); + } } - for(user = block->idominates; user; user = user->next) { + for(user = block->ipdominates; user; user = user->next) { struct block_set *frontier; child = user->member; for(frontier = child->ipdomfrontier; frontier; frontier = frontier->next) { @@ -10485,6 +10854,13 @@ static int tdominates(struct compile_state *state, return result; } +static void analyze_basic_blocks(struct compile_state *state) +{ + setup_basic_blocks(state); + analyze_idominators(state); + analyze_ipdominators(state); +} + static void insert_phi_operations(struct compile_state *state) { size_t size; @@ -10499,7 +10875,7 @@ static void insert_phi_operations(struct compile_state *state) work = xcmalloc(size, "work"); iter = 0; - first = RHS(state->main_function, 0); + first = state->first; for(var = first->next; var != first ; var = vnext) { struct block *block; struct triple_set *user, *unext; @@ -10560,6 +10936,7 @@ static void insert_phi_operations(struct compile_state *state) front->last = front->first->next; } has_already[front->vertex] = iter; + transform_to_arch_instruction(state, phi); /* If necessary plan to visit the basic block */ if (work[front->vertex] >= iter) { @@ -10577,35 +10954,68 @@ static void insert_phi_operations(struct compile_state *state) } -static int count_and_number_adecls(struct compile_state *state) +struct stack { + struct triple_set *top; + unsigned orig_id; +}; + +static int count_adecls(struct compile_state *state) +{ + struct triple *first, *ins; + int adecls = 0; + first = state->first; + ins = first; + do { + if (ins->op == OP_ADECL) { + adecls += 1; + } + ins = ins->next; + } while(ins != first); + return adecls; +} + +static void number_adecls(struct compile_state *state, struct stack *stacks) { struct triple *first, *ins; int adecls = 0; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { if (ins->op == OP_ADECL) { adecls += 1; + stacks[adecls].orig_id = ins->id; ins->id = adecls; } ins = ins->next; } while(ins != first); - return adecls; } -static struct triple *peek_triple(struct triple_set **stacks, struct triple *var) +static void restore_adecls(struct compile_state *state, struct stack *stacks) +{ + struct triple *first, *ins; + first = state->first; + ins = first; + do { + if (ins->op == OP_ADECL) { + ins->id = stacks[ins->id].orig_id; + } + ins = ins->next; + } while(ins != first); +} + +static struct triple *peek_triple(struct stack *stacks, struct triple *var) { struct triple_set *head; struct triple *top_val; top_val = 0; - head = stacks[var->id]; + head = stacks[var->id].top; if (head) { top_val = head->member; } return top_val; } -static void push_triple(struct triple_set **stacks, struct triple *var, struct triple *val) +static void push_triple(struct stack *stacks, struct triple *var, struct triple *val) { struct triple_set *new; /* Append new to the head of the list, @@ -10613,14 +11023,14 @@ static void push_triple(struct triple_set **stacks, struct triple *var, struct t */ new = xcmalloc(sizeof(*new), "triple_set"); new->member = val; - new->next = stacks[var->id]; - stacks[var->id] = new; + new->next = stacks[var->id].top; + stacks[var->id].top = new; } -static void pop_triple(struct triple_set **stacks, struct triple *var, struct triple *oldval) +static void pop_triple(struct stack *stacks, struct triple *var, struct triple *oldval) { struct triple_set *set, **ptr; - ptr = &stacks[var->id]; + ptr = &stacks[var->id].top; while(*ptr) { set = *ptr; if (set->member == oldval) { @@ -10640,7 +11050,7 @@ static void pop_triple(struct triple_set **stacks, struct triple *var, struct tr * S(V) */ static void fixup_block_phi_variables( - struct compile_state *state, struct triple_set **stacks, struct block *parent, struct block *block) + struct compile_state *state, struct stack *stacks, struct block *parent, struct block *block) { struct block_set *set; struct triple *ptr; @@ -10687,7 +11097,7 @@ static void fixup_block_phi_variables( static void rename_block_variables( - struct compile_state *state, struct triple_set **stacks, struct block *block) + struct compile_state *state, struct stack *stacks, struct block *block) { struct block_set *user; struct triple *ptr, *next, *last; @@ -10736,6 +11146,7 @@ static void rename_block_variables( tval = pre_triple(state, ptr, OP_COPY, ptr->type, val, 0); use_triple(val, tval); } + transform_to_arch_instruction(state, tval); unuse_triple(val, ptr); RHS(ptr, 1) = tval; use_triple(tval, ptr); @@ -10789,6 +11200,26 @@ static void rename_block_variables( block->last = last; } +static void rename_variables(struct compile_state *state) +{ + struct stack *stacks; + int adecls; + + /* Allocate stacks for the Variables */ + adecls = count_adecls(state); + stacks = xcmalloc(sizeof(stacks[0])*(adecls + 1), "adecl stacks"); + + /* Give each adecl a stack */ + number_adecls(state, stacks); + + /* Rename the variables */ + rename_block_variables(state, stacks, state->first_block); + + /* Remove the stacks from the adecls */ + restore_adecls(state, stacks); + xfree(stacks); +} + static void prune_block_variables(struct compile_state *state, struct block *block) { @@ -10859,9 +11290,8 @@ static void prune_unused_phis(struct compile_state *state) struct phi_triple *live; int phis, i; - /* Find the first instruction */ - first = RHS(state->main_function, 0); + first = state->first; /* Count how many phi functions I need to process */ phis = 0; @@ -10916,36 +11346,34 @@ static void prune_unused_phis(struct compile_state *state) xfree(live); } - static void transform_to_ssa_form(struct compile_state *state) { - struct triple_set **stacks; - int adecls; insert_phi_operations(state); -#if 0 - printf("@%s:%d\n", __FILE__, __LINE__); - print_blocks(state, stdout); -#endif - - /* Allocate stacks for the Variables */ - adecls = count_and_number_adecls(state); - stacks = xcmalloc(sizeof(stacks[0])*(adecls + 1), "adecl stacks"); - rename_block_variables(state, stacks, state->first_block); - xfree(stacks); + rename_variables(state); prune_block_variables(state, state->first_block); - -#if 1 prune_unused_phis(state); -#endif - } static void clear_vertex( struct compile_state *state, struct block *block, void *arg) { + /* Clear the current blocks vertex and the vertex of all + * of the current blocks neighbors in case there are malformed + * blocks with now instructions at this point. + */ + struct block_set *user; block->vertex = 0; + if (block->left) { + block->left->vertex = 0; + } + if (block->right) { + block->right->vertex = 0; + } + for(user = block->use; user; user = user->next) { + user->member->vertex = 0; + } } static void mark_live_block( @@ -10970,7 +11398,7 @@ static void mark_live_block( mark_live_block(state, (*targ)->u.block, next_vertex); } } - else if (block->last->next != RHS(state->main_function, 0)) { + else if (block->last->next != state->first) { struct triple *ins; ins = block->last->next; if (!triple_stores_block(state, ins)) { @@ -10986,7 +11414,7 @@ static void transform_from_ssa_form(struct compile_state *state) * edges to blocks containting phi functions. */ struct triple *first; - struct triple *phi, *next; + struct triple *phi, *var, *next; int next_vertex; /* Walk the control flow to see which blocks remain alive */ @@ -10994,22 +11422,34 @@ static void transform_from_ssa_form(struct compile_state *state) next_vertex = 1; mark_live_block(state, state->first_block, &next_vertex); +#if 0 + fprintf(stderr, "@ %s:%d\n", __FILE__, __LINE__); + print_blocks(state, stderr); +#endif + /* Walk all of the operations to find the phi functions */ - first = RHS(state->main_function, 0); + first = state->first; for(phi = first->next; phi != first ; phi = next) { struct block_set *set; struct block *block; struct triple **slot; - struct triple *var, *read; + struct triple *var; struct triple_set *use, *use_next; int edge, used; next = phi->next; if (phi->op != OP_PHI) { continue; } + block = phi->u.block; slot = &RHS(phi, 0); + /* If this phi is in a dead block just forget it */ + if (block->vertex == 0) { + release_triple(state, phi); + continue; + } + /* Forget uses from code in dead blocks */ for(use = phi->use; use; use = use_next) { struct block *ublock; @@ -11027,55 +11467,61 @@ static void transform_from_ssa_form(struct compile_state *state) } unuse_triple(phi, use->member); } - -#warning "CHECK_ME does the OP_ADECL need to be placed somewhere that dominates all of the incoming phi edges?" /* A variable to replace the phi function */ var = post_triple(state, phi, OP_ADECL, phi->type, 0,0); - /* A read of the single value that is set into the variable */ - read = post_triple(state, var, OP_READ, phi->type, var, 0); - use_triple(var, read); - /* Replaces uses of the phi with variable reads */ - propogate_use(state, phi, read); + /* Replaces use of phi with var */ + propogate_use(state, phi, var); /* Walk all of the incoming edges/blocks and insert moves. */ + used = 0; for(edge = 0, set = block->use; set; set = set->next, edge++) { - struct block *eblock; + struct block *eblock, *vblock; struct triple *move; struct triple *val, *base; eblock = set->member; val = slot[edge]; slot[edge] = 0; unuse_triple(val, phi); + vblock = block_of_triple(state, val); - if (!val || (val == &zero_triple) || - (block->vertex == 0) || (eblock->vertex == 0) || - (val == phi) || (val == read)) { + /* If we don't have a value that belongs in an OP_WRITE + * continue on. + */ + if (!val || (val == &zero_triple) || (val == phi) || + (!vblock) || (vblock->vertex == 0)) { + continue; + } + + /* If the value occurs in a dead block see if a replacement + * block can be found. + */ + while(eblock && (eblock->vertex == 0)) { + eblock = eblock->idom; + } + /* If not continue on with the next value. */ + if (!eblock || (eblock->vertex == 0)) { continue; } + + /* If we have an empty incoming block ignore it. */ + if (!eblock->first) { + internal_error(state, 0, "empty block?"); + } /* Make certain the write is placed in the edge block... */ base = eblock->first; if (block_of_triple(state, val) == eblock) { base = val; } - move = post_triple(state, base, OP_WRITE, phi->type, var, val); + move = post_triple(state, base, OP_WRITE, var->type, var, val); use_triple(val, move); use_triple(var, move); + used = 1; } - /* See if there are any writers of var */ - used = 0; - for(use = var->use; use; use = use->next) { - if ((use->member->op == OP_WRITE) && - (RHS(use->member, 0) == var)) { - used = 1; - } - } /* If var is not used free it */ if (!used) { - unuse_triple(var, read); - free_triple(state, read); free_triple(state, var); } @@ -11083,8 +11529,76 @@ static void transform_from_ssa_form(struct compile_state *state) release_triple(state, phi); } + /* Walk all of the operations to find the adecls */ + for(var = first->next; var != first ; var = var->next) { + struct triple_set *use, *use_next; + if (var->op != OP_ADECL) { + continue; + } + + /* Walk through all of the rhs uses of var and + * replace them with read of var. + */ + for(use = var->use; use; use = use_next) { + struct triple *read, *user; + struct triple **slot; + int zrhs, i, used; + use_next = use->next; + user = use->member; + + /* Generate a read of var */ + read = pre_triple(state, user, OP_READ, var->type, var, 0); + use_triple(var, read); + + /* Find the rhs uses and see if they need to be replaced */ + used = 0; + zrhs = TRIPLE_RHS(user->sizes); + slot = &RHS(user, 0); + for(i = 0; i < zrhs; i++) { + if ((slot[i] == var) && + ((i != 0) || (user->op != OP_WRITE))) + { + slot[i] = read; + used = 1; + } + } + /* If we did use it cleanup the uses */ + if (used) { + unuse_triple(var, user); + use_triple(read, user); + } + /* If we didn't use it release the extra triple */ + else { + release_triple(state, read); + } + } + } } +#if 0 +#define HI() do { fprintf(stderr, "@ %s:%d\n", __FILE__, __LINE__); print_blocks(state, stderr); } while (0) +#else +#define HI() +#endif +static void rebuild_ssa_form(struct compile_state *state) +{ +HI(); + transform_from_ssa_form(state); +HI(); + free_basic_blocks(state); + analyze_basic_blocks(state); +HI(); + insert_phi_operations(state); +HI(); + rename_variables(state); +HI(); + + prune_block_variables(state, state->first_block); +HI(); + prune_unused_phis(state); +HI(); +} +#undef HI /* * Register conflict resolution @@ -11376,7 +11890,7 @@ static void insert_copies_to_phi(struct compile_state *state) struct triple *phi; /* Walk all of the operations to find the phi functions */ - first = RHS(state->main_function, 0); + first = state->first; for(phi = first->next; phi != first ; phi = phi->next) { struct block_set *set; struct block *block; @@ -11812,7 +12326,7 @@ static int count_triples(struct compile_state *state) { struct triple *first, *ins; int triples = 0; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { triples++; @@ -11826,7 +12340,7 @@ struct dead_triple { struct triple *triple; struct dead_triple *work_next; struct block *block; - int color; + int old_id; int flags; #define TRIPLE_FLAG_ALIVE 1 }; @@ -11851,7 +12365,7 @@ static void awaken( triple->id); } if (triple->op == OP_NOOP) { - internal_warning(state, triple, "awakening noop?"); + internal_error(state, triple, "awakening noop?"); return; } dt = &dtriple[triple->id]; @@ -11869,13 +12383,14 @@ static void eliminate_inefectual_code(struct compile_state *state) struct block *block; struct dead_triple *dtriple, *work_list, **work_list_tail, *dt; int triples, i; - struct triple *first, *ins; + struct triple *first, *final, *ins; /* Setup the work list */ work_list = 0; work_list_tail = &work_list; - first = RHS(state->main_function, 0); + first = state->first; + final = state->first->prev; /* Count how many triples I have */ triples = count_triples(state); @@ -11887,29 +12402,20 @@ static void eliminate_inefectual_code(struct compile_state *state) i = 1; block = 0; do { - if (ins->op == OP_LABEL) { - block = ins->u.block; - } dtriple[i].triple = ins; - dtriple[i].block = block; + dtriple[i].block = block_of_triple(state, ins); dtriple[i].flags = 0; - dtriple[i].color = ins->id; + dtriple[i].old_id = ins->id; ins->id = i; /* See if it is an operation we always keep */ -#warning "FIXME handle the case of killing a branch instruction" - if (!triple_is_pure(state, ins) || triple_is_branch(state, ins)) { - awaken(state, dtriple, &ins, &work_list_tail); - } -#if 1 - /* Unconditionally keep the very last instruction */ - else if (ins->next == first) { + if (!triple_is_pure(state, ins, dtriple[i].old_id)) { awaken(state, dtriple, &ins, &work_list_tail); } -#endif i++; ins = ins->next; } while(ins != first); while(work_list) { + struct block *block; struct dead_triple *dt; struct block_set *user; struct triple **expr; @@ -11918,6 +12424,13 @@ static void eliminate_inefectual_code(struct compile_state *state) if (!work_list) { work_list_tail = &work_list; } + /* Make certain the block the current instruction is in lives */ + block = block_of_triple(state, dt->triple); + awaken(state, dtriple, &block->first, &work_list_tail); + if (triple_is_branch(state, block->last)) { + awaken(state, dtriple, &block->last, &work_list_tail); + } + /* Wake up the data depencencies of this triple */ expr = 0; do { @@ -11940,6 +12453,11 @@ static void eliminate_inefectual_code(struct compile_state *state) /* Wake up the reverse control dependencies of this triple */ for(user = dt->block->ipdomfrontier; user; user = user->next) { awaken(state, dtriple, &user->member->last, &work_list_tail); + if ((user->member->left != state->last_block) && + !triple_is_cond_branch(state, user->member->last)) { + internal_error(state, dt->triple, + "conditional branch missing"); + } } } for(dt = &dtriple[1]; dt <= &dtriple[triples]; dt++) { @@ -11947,15 +12465,8 @@ static void eliminate_inefectual_code(struct compile_state *state) (dt->flags & TRIPLE_FLAG_ALIVE)) { internal_error(state, dt->triple, "noop effective?"); } - dt->triple->id = dt->color; /* Restore the color */ + dt->triple->id = dt->old_id; /* Restore the color */ if (!(dt->flags & TRIPLE_FLAG_ALIVE)) { -#warning "FIXME handle the case of killing a basic block" - if (dt->block->first == dt->triple) { - continue; - } - if (dt->block->last == dt->triple) { - dt->block->last = dt->triple->prev; - } release_triple(state, dt->triple); } } @@ -11974,7 +12485,7 @@ static void insert_mandatory_copies(struct compile_state *state) * are inserting copies before instructions but that * case should be rare. */ - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { struct triple_set *entry, *next; @@ -12746,7 +13257,7 @@ static void initialize_live_ranges( size_t count, size; int i, j; - first = RHS(state->main_function, 0); + first = state->first; /* First count how many instructions I have. */ count = count_triples(state); @@ -12978,23 +13489,6 @@ static void verify_graph_ins( return; } -#if DEBUG_CONSISTENCY > 1 -static void verify_interference_graph( - struct compile_state *state, struct reg_state *rstate) -{ -#if 0 - fprintf(stderr, "verify_interference_graph...\n"); -#endif - - walk_variable_lifetimes(state, rstate->blocks, verify_graph_ins, rstate); -#if 0 - fprintf(stderr, "verify_interference_graph done\n"); -#endif -} -#else -static inline void verify_interference_graph( - struct compile_state *state, struct reg_state *rstate) {} -#endif static void print_interference_ins( struct compile_state *state, @@ -13241,7 +13735,7 @@ static void replace_block_use(struct compile_state *state, static void color_instructions(struct compile_state *state) { struct triple *ins, *first; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { if (triple_is_def(state, ins)) { @@ -13808,14 +14302,13 @@ static int color_graph(struct compile_state *state, struct reg_state *rstate) return colored; } -#if DEBUG_CONSISTENCY static void verify_colors(struct compile_state *state, struct reg_state *rstate) { struct live_range *lr; struct live_range_edge *edge; struct triple *ins, *first; char used[MAX_REGISTERS]; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { if (triple_is_def(state, ins)) { @@ -13845,15 +14338,12 @@ static void verify_colors(struct compile_state *state, struct reg_state *rstate) ins = ins->next; } while(ins != first); } -#else -static inline void verify_colors(struct compile_state *state, struct reg_state *rstate) {} -#endif static void color_triples(struct compile_state *state, struct reg_state *rstate) { struct live_range *lr; struct triple *first, *ins; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { if ((ins->id < 0) || (ins->id > rstate->defs)) { @@ -13930,7 +14420,7 @@ static void ids_from_rstate(struct compile_state *state, print_blocks(state, stdout); print_control_flow(state); } - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { if (ins->id) { @@ -14052,8 +14542,17 @@ static void allocate_registers(struct compile_state *state) #endif } while(coalesced); +#if DEBUG_CONSISTENCY > 1 +# if 0 + fprintf(stderr, "verify_graph_ins...\n"); +# endif /* Verify the interference graph */ - verify_interference_graph(state, &rstate); + walk_variable_lifetimes( + state, rstate.blocks, verify_graph_ins, &rstate); +# if 0 + fprintf(stderr, "verify_graph_ins done\n"); +#endif +#endif /* Build the groups low and high. But with the nodes * first sorted by degree order. @@ -14169,6 +14668,11 @@ struct scc_state { static void scc_add_fedge(struct compile_state *state, struct scc_state *scc, struct flow_edge *fedge) { + if ((fedge == scc->flow_work_list) || + (fedge->work_next != fedge) || + (fedge->work_prev != fedge)) { + return; + } if (!scc->flow_work_list) { scc->flow_work_list = fedge; fedge->work_next = fedge->work_prev = fedge; @@ -14196,6 +14700,7 @@ static struct flow_edge *scc_next_fedge( } else { scc->flow_work_list = 0; } + fedge->work_next = fedge->work_prev = fedge; } return fedge; } @@ -14203,6 +14708,21 @@ static struct flow_edge *scc_next_fedge( static void scc_add_sedge(struct compile_state *state, struct scc_state *scc, struct ssa_edge *sedge) { +#if DEBUG_SCC > 1 + fprintf(stderr, "adding sedge: %5d (%4d -> %5d)\n", + sedge - scc->ssa_edges, + sedge->src->def->id, + sedge->dst->def->id); +#endif + if ((sedge == scc->ssa_work_list) || + (sedge->work_next != sedge) || + (sedge->work_prev != sedge)) { +#if DEBUG_SCC > 1 + fprintf(stderr, "dupped sedge: %5d\n", + sedge - scc->ssa_edges); +#endif + return; + } if (!scc->ssa_work_list) { scc->ssa_work_list = sedge; sedge->work_next = sedge->work_prev = sedge; @@ -14230,6 +14750,7 @@ static struct ssa_edge *scc_next_sedge( } else { scc->ssa_work_list = 0; } + sedge->work_next = sedge->work_prev = sedge; } return sedge; } @@ -14246,7 +14767,7 @@ static void initialize_scc_state( memset(scc, 0, sizeof(*scc)); /* Inialize pass zero find out how much memory we need */ - first = RHS(state->main_function, 0); + first = state->first; ins = first; ins_count = ssa_edge_count = 0; do { @@ -14472,6 +14993,7 @@ static void scc_visit_phi(struct compile_state *state, struct scc_state *scc, struct lattice_node *tmp; struct triple **slot, *old; struct flow_edge *fedge; + int changed; int index; if (lnode->def->op != OP_PHI) { internal_error(state, lnode->def, "not phi"); @@ -14484,6 +15006,13 @@ static void scc_visit_phi(struct compile_state *state, struct scc_state *scc, slot = &RHS(lnode->def, 0); index = 0; for(fedge = lnode->fblock->in; fedge; index++, fedge = fedge->in_next) { +#if DEBUG_SCC + fprintf(stderr, "Examining edge: %d vertex: %d executable: %d\n", + index, + fedge->dst->block->vertex, + fedge->executable + ); +#endif if (!fedge->executable) { continue; } @@ -14512,13 +15041,17 @@ static void scc_visit_phi(struct compile_state *state, struct scc_state *scc, break; } } + changed = lval_changed(state, old, lnode); #if DEBUG_SCC - fprintf(stderr, "phi: %d -> %s\n", + fprintf(stderr, "%p phi: %d -> %s %s\n", + lnode->def, lnode->def->id, - (!lnode->val)? "lo": is_const(lnode->val)? "const": "hi"); + ((!lnode->val)? "lo": is_const(lnode->val)? "const": "hi"), + changed? "changed" : "" + ); #endif /* If the lattice value has changed update the work lists. */ - if (lval_changed(state, old, lnode)) { + if (changed) { struct ssa_edge *sedge; for(sedge = lnode->out; sedge; sedge = sedge->out_next) { scc_add_sedge(state, scc, sedge); @@ -14608,16 +15141,23 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc, /* Find the cases that are always lattice lo */ if (lnode->val && triple_is_def(state, lnode->val) && - !triple_is_pure(state, lnode->val)) { + !triple_is_pure(state, lnode->val, lnode->old_id)) { lnode->val = 0; } - if (lnode->val && - (lnode->val->op == OP_SDECL) && - (lnode->val != lnode->def)) { - internal_error(state, lnode->def, "bad sdecl"); - } /* See if the lattice value has changed */ changed = lval_changed(state, old, lnode); + /* See if this value should not change */ + if (lnode->val && + (( !triple_is_def(state, lnode->def) && + !triple_is_cond_branch(state, lnode->def)) || + (lnode->def->op == OP_PIECE))) { +#warning "FIXME constant propogate through expressions with multiple left hand sides" + if (changed) { + internal_warning(state, lnode->def, "non def changes value?"); + } + lnode->val = 0; + } + /* See if we need to free the scratch value */ if (lnode->val != scratch) { xfree(scratch); } @@ -14708,19 +15248,35 @@ static void scc_writeback_values( struct compile_state *state, struct scc_state *scc) { struct triple *first, *ins; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { struct lattice_node *lnode; lnode = triple_to_lattice(state, scc, ins); - /* Restore id */ - ins->id = lnode->old_id; #if DEBUG_SCC - if (lnode->val && !is_const(lnode->val)) { - warning(state, lnode->def, - "lattice node still high?"); + if (lnode->val && + !is_const(lnode->val) && + !triple_is_uncond_branch(state, lnode->val) && + (lnode->val->op != OP_NOOP)) + { + struct flow_edge *fedge; + int executable; + executable = 0; + for(fedge = lnode->fblock->in; + !executable && fedge; fedge = fedge->in_next) { + executable |= fedge->executable; + } + if (executable) { + internal_warning(state, lnode->val, + "lattice node %d %s->%s still high?", + ins->id, + tops(lnode->def->op), + tops(lnode->val->op)); + } } #endif + /* Restore id */ + ins->id = lnode->old_id; if (lnode->val && (lnode->val != ins)) { /* See if it something I know how to write back */ switch(lnode->val->op) { @@ -14764,7 +15320,7 @@ static void scc_transform(struct compile_state *state) struct block *block; struct triple *ptr; struct flow_block *fblock; - int time; + int reps; int done; if (fedge->executable) { continue; @@ -14778,15 +15334,15 @@ static void scc_transform(struct compile_state *state) fedge->executable = 1; fblock = fedge->dst; block = fblock->block; - time = 0; + reps = 0; for(fptr = fblock->in; fptr; fptr = fptr->in_next) { if (fptr->executable) { - time++; + reps++; } } #if DEBUG_SCC - fprintf(stderr, "vertex: %d time: %d\n", - block->vertex, time); + fprintf(stderr, "vertex: %d reps: %d\n", + block->vertex, reps); #endif done = 0; @@ -14797,7 +15353,7 @@ static void scc_transform(struct compile_state *state) if (ptr->op == OP_PHI) { scc_visit_phi(state, &scc, lnode); } - else if (time == 1) { + else if (reps == 1) { scc_visit_expr(state, &scc, lnode); } } @@ -14840,7 +15396,7 @@ static void scc_transform(struct compile_state *state) static void transform_to_arch_instructions(struct compile_state *state) { struct triple *ins, *first; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { ins = transform_to_arch_instruction(state, ins); @@ -14852,7 +15408,7 @@ static void verify_uses(struct compile_state *state) { struct triple *first, *ins; struct triple_set *set; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { struct triple **expr; @@ -14892,7 +15448,7 @@ static void verify_blocks_present(struct compile_state *state) if (!state->first_block) { return; } - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { valid_ins(state, ins); @@ -14930,6 +15486,9 @@ static void verify_blocks(struct compile_state *state) users = 0; for(user = block->use; user; user = user->next) { users++; + if (!user->member->first) { + internal_error(state, block->first, "user is empty"); + } if ((block == state->last_block) && (user->member == state->first_block)) { continue; @@ -14961,6 +15520,9 @@ static void verify_blocks(struct compile_state *state) internal_error(state, block->first, "block does not use left"); } + if (!block->left->first) { + internal_error(state, block->first, "left block is empty"); + } } if (block->right) { for(user = block->right->use; user; user = user->next) { @@ -14972,12 +15534,22 @@ static void verify_blocks(struct compile_state *state) internal_error(state, block->first, "block does not use right"); } + if (!block->right->first) { + internal_error(state, block->first, "right block is empty"); + } } if (block->users != users) { internal_error(state, block->first, "computed users %d != stored users %d\n", users, block->users); } + for(user = block->ipdomfrontier; user; user = user->next) { + if ((user->member->left != state->last_block) && + !triple_is_cond_branch(state, user->member->last)) { + internal_error(state, user->member->last, + "conditional branch missing"); + } + } if (!triple_stores_block(state, block->last->next)) { internal_error(state, block->last->next, "cannot find next block"); @@ -15002,7 +15574,7 @@ static void verify_domination(struct compile_state *state) return; } - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { for(set = ins->use; set; set = set->next) { @@ -15046,10 +15618,36 @@ static void verify_domination(struct compile_state *state) } while(ins != first); } +static void verify_rhs(struct compile_state *state) +{ + struct triple *first, *ins; + first = state->first; + ins = first; + do { + struct triple **slot; + int zrhs, i; + zrhs = TRIPLE_RHS(ins->sizes); + slot = &RHS(ins, 0); + for(i = 0; i < zrhs; i++) { + if (slot[i] == 0) { + internal_error(state, ins, + "missing rhs %d on %s", + i, tops(ins->op)); + } + if ((ins->op != OP_PHI) && (slot[i] == ins)) { + internal_error(state, ins, + "ins == rhs[%d] on %s", + i, tops(ins->op)); + } + } + ins = ins->next; + } while(ins != first); +} + static void verify_piece(struct compile_state *state) { struct triple *first, *ins; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { struct triple *ptr; @@ -15072,11 +15670,12 @@ static void verify_piece(struct compile_state *state) ins = ins->next; } while(ins != first); } + static void verify_ins_colors(struct compile_state *state) { struct triple *first, *ins; - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { ins = ins->next; @@ -15088,12 +15687,13 @@ static void verify_consistency(struct compile_state *state) verify_blocks_present(state); verify_blocks(state); verify_domination(state); + verify_rhs(state); verify_piece(state); verify_ins_colors(state); } #else static void verify_consistency(struct compile_state *state) {} -#endif /* DEBUG_USES */ +#endif /* DEBUG_CONSISTENCY */ static void optimize(struct compile_state *state) { @@ -15107,9 +15707,7 @@ static void optimize(struct compile_state *state) } verify_consistency(state); /* Analize the intermediate code */ - setup_basic_blocks(state); - analyze_idominators(state); - analyze_ipdominators(state); + analyze_basic_blocks(state); /* Transform the code to ssa form. */ /* @@ -15121,23 +15719,21 @@ static void optimize(struct compile_state *state) * phi functions early and I kill them often. */ transform_to_ssa_form(state); - eliminate_inefectual_code(state); verify_consistency(state); if (state->debug & DEBUG_CODE_ELIMINATION) { fprintf(stdout, "After transform_to_ssa_form\n"); print_blocks(state, stdout); } + /* Remove dead code */ + eliminate_inefectual_code(state); + rebuild_ssa_form(state); + verify_consistency(state); + /* Do strength reduction and simple constant optimizations */ if (state->optimize >= 1) { simplify_all(state); - transform_from_ssa_form(state); - free_basic_blocks(state); - setup_basic_blocks(state); - analyze_idominators(state); - analyze_ipdominators(state); - transform_to_ssa_form(state); - eliminate_inefectual_code(state); + rebuild_ssa_form(state); } if (state->debug & DEBUG_CODE_ELIMINATION) { fprintf(stdout, "After simplify_all\n"); @@ -15147,13 +15743,7 @@ static void optimize(struct compile_state *state) /* Propogate constants throughout the code */ if (state->optimize >= 2) { scc_transform(state); - transform_from_ssa_form(state); - free_basic_blocks(state); - setup_basic_blocks(state); - analyze_idominators(state); - analyze_ipdominators(state); - transform_to_ssa_form(state); - eliminate_inefectual_code(state); + rebuild_ssa_form(state); } verify_consistency(state); #warning "WISHLIST implement single use constants (least possible register pressure)" @@ -15168,7 +15758,9 @@ static void optimize(struct compile_state *state) print_blocks(state, stdout); print_control_flow(state); } + /* Remove dead code */ eliminate_inefectual_code(state); + rebuild_ssa_form(state); verify_consistency(state); if (state->debug & DEBUG_CODE_ELIMINATION) { printf("After eliminate_inefectual_code\n"); @@ -15258,15 +15850,9 @@ static void print_op_asm(struct compile_state *state, */ #define X86_4_8BIT_GPRS 1 -/* Recognized x86 cpu variants */ -#define BAD_CPU 0 -#define CPU_I386 1 -#define CPU_P3 2 -#define CPU_P4 3 -#define CPU_K7 4 -#define CPU_K8 5 - -#define CPU_DEFAULT CPU_I386 +/* x86 featrues */ +#define X86_MMX_REGS (1<<0) +#define X86_XMM_REGS (1<<1) /* The x86 register classes */ #define REGC_FLAGS 0 @@ -15423,26 +16009,48 @@ static const struct { [REGC_IMM8] = { REGC_IMM8_FIRST, REGC_IMM8_LAST }, }; -static int arch_encode_cpu(const char *cpu) +static int arch_encode_feature(const char *feature, unsigned long *features) { struct cpu { const char *name; int cpu; } cpus[] = { - { "i386", CPU_I386 }, - { "p3", CPU_P3 }, - { "p4", CPU_P4 }, - { "k7", CPU_K7 }, - { "k8", CPU_K8 }, - { 0, BAD_CPU } + { "i386", 0 }, + { "p2", X86_MMX_REGS }, + { "p3", X86_MMX_REGS | X86_XMM_REGS }, + { "p4", X86_MMX_REGS | X86_XMM_REGS }, + { "k7", X86_MMX_REGS }, + { "k8", X86_MMX_REGS | X86_XMM_REGS }, + { "c3", X86_MMX_REGS }, + { "c3-2", X86_MMX_REGS | X86_XMM_REGS }, /* Nehemiah */ + { 0, 0 } }; struct cpu *ptr; - for(ptr = cpus; ptr->name; ptr++) { - if (strcmp(ptr->name, cpu) == 0) { - break; + int result = 0; + if (strcmp(feature, "mmx") == 0) { + *features |= X86_MMX_REGS; + } + else if (strcmp(feature, "sse") == 0) { + *features |= X86_XMM_REGS; + } + else if (strncmp(feature, "cpu=", 4) == 0) { + const char *cpu = feature + 4; + for(ptr = cpus; ptr->name; ptr++) { + if (strcmp(ptr->name, cpu) == 0) { + break; + } + } + if (ptr->name) { + *features |= ptr->cpu; + } + else { + result = -1; } } - return ptr->cpu; + else { + result = -1; + } + return result; } static unsigned arch_regc_size(struct compile_state *state, int class) @@ -15651,15 +16259,11 @@ static unsigned arch_avail_mask(struct compile_state *state) REGCM_GPR32 | REGCM_GPR32_8 | REGCM_DIVIDEND32 | REGCM_DIVIDEND64 | REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8 | REGCM_FLAGS; - switch(state->cpu) { - case CPU_P3: - case CPU_K7: + if (state->features & X86_MMX_REGS) { avail_mask |= REGCM_MMX; - break; - case CPU_P4: - case CPU_K8: - avail_mask |= REGCM_MMX | REGCM_XMM; - break; + } + if (state->features & X86_XMM_REGS) { + avail_mask |= REGCM_XMM; } return avail_mask; } @@ -16475,6 +17079,32 @@ static struct ins_template templates[] = { }, }; +static void fixup_branch(struct compile_state *state, + struct triple *branch, int jmp_op, int cmp_op, struct type *cmp_type, + struct triple *left, struct triple *right) +{ + struct triple *test; + if (!left) { + internal_error(state, branch, "no branch test?"); + } + test = pre_triple(state, branch, + cmp_op, cmp_type, left, right); + test->template_id = TEMPLATE_TEST32; + if (cmp_op == OP_CMP) { + test->template_id = TEMPLATE_CMP32_REG; + if (get_imm32(test, &RHS(test, 1))) { + test->template_id = TEMPLATE_CMP32_IMM; + } + } + use_triple(RHS(test, 0), test); + use_triple(RHS(test, 1), test); + unuse_triple(RHS(branch, 0), branch); + RHS(branch, 0) = test; + branch->op = jmp_op; + branch->template_id = TEMPLATE_JMP; + use_triple(RHS(branch, 0), branch); +} + static void fixup_branches(struct compile_state *state, struct triple *cmp, struct triple *use, int jmp_op) { @@ -16485,7 +17115,7 @@ static void fixup_branches(struct compile_state *state, fixup_branches(state, cmp, entry->member, jmp_op); } else if (entry->member->op == OP_BRANCH) { - struct triple *branch, *test; + struct triple *branch; struct triple *left, *right; left = right = 0; left = RHS(cmp, 0); @@ -16493,22 +17123,8 @@ static void fixup_branches(struct compile_state *state, right = RHS(cmp, 1); } branch = entry->member; - test = pre_triple(state, branch, + fixup_branch(state, branch, jmp_op, cmp->op, cmp->type, left, right); - test->template_id = TEMPLATE_TEST32; - if (cmp->op == OP_CMP) { - test->template_id = TEMPLATE_CMP32_REG; - if (get_imm32(test, &RHS(test, 1))) { - test->template_id = TEMPLATE_CMP32_IMM; - } - } - use_triple(RHS(test, 0), test); - use_triple(RHS(test, 1), test); - unuse_triple(RHS(branch, 0), branch); - RHS(branch, 0) = test; - branch->op = jmp_op; - branch->template_id = TEMPLATE_JMP; - use_triple(RHS(branch, 0), branch); } } } @@ -16875,10 +17491,14 @@ static struct triple *transform_to_arch_instruction( break; case OP_BRANCH: if (TRIPLE_RHS(ins->sizes) > 0) { - internal_error(state, ins, "bad branch test"); + struct triple *left = RHS(ins, 0); + fixup_branch(state, ins, OP_JMP_NOTEQ, OP_TEST, + left->type, left, 0); + } + else { + ins->op = OP_JMP; + ins->template_id = TEMPLATE_NOP; } - ins->op = OP_JMP; - ins->template_id = TEMPLATE_NOP; break; case OP_INB: case OP_INW: @@ -16932,6 +17552,9 @@ static struct triple *transform_to_arch_instruction( ins->template_id = TEMPLATE_CMP32_IMM; } break; + case OP_JMP: + ins->template_id = TEMPLATE_NOP; + break; case OP_JMP_EQ: case OP_JMP_NOTEQ: case OP_JMP_SLESS: case OP_JMP_ULESS: case OP_JMP_SMORE: case OP_JMP_UMORE: @@ -16964,7 +17587,7 @@ static long next_label(struct compile_state *state) static void generate_local_labels(struct compile_state *state) { struct triple *first, *label; - first = RHS(state->main_function, 0); + first = state->first; label = first; do { if ((label->op == OP_LABEL) || @@ -17051,7 +17674,7 @@ static void print_const_val( switch(ins->op) { case OP_INTCONST: fprintf(fp, " $%ld ", - (long_t)(ins->u.cval)); + (long)(ins->u.cval)); break; case OP_ADDRCONST: if (MISC(ins, 0)->op != OP_SDECL) { @@ -17062,8 +17685,8 @@ static void print_const_val( } fprintf(fp, " $L%s%lu+%lu ", state->label_prefix, - MISC(ins, 0)->u.cval, - ins->u.cval); + (unsigned long)(MISC(ins, 0)->u.cval), + (unsigned long)(ins->u.cval)); break; default: internal_error(state, ins, "unknown constant type"); @@ -17079,17 +17702,20 @@ static void print_const(struct compile_state *state, switch(ins->type->type & TYPE_MASK) { case TYPE_CHAR: case TYPE_UCHAR: - fprintf(fp, ".byte 0x%02lx\n", ins->u.cval); + fprintf(fp, ".byte 0x%02lx\n", + (unsigned long)(ins->u.cval)); break; case TYPE_SHORT: case TYPE_USHORT: - fprintf(fp, ".short 0x%04lx\n", ins->u.cval); + fprintf(fp, ".short 0x%04lx\n", + (unsigned long)(ins->u.cval)); break; case TYPE_INT: case TYPE_UINT: case TYPE_LONG: case TYPE_ULONG: - fprintf(fp, ".int %lu\n", ins->u.cval); + fprintf(fp, ".int %lu\n", + (unsigned long)(ins->u.cval)); break; default: internal_error(state, ins, "Unknown constant type"); @@ -17104,8 +17730,8 @@ static void print_const(struct compile_state *state, } fprintf(fp, ".int L%s%lu+%lu\n", state->label_prefix, - MISC(ins, 0)->u.cval, - ins->u.cval); + (unsigned long)(MISC(ins, 0)->u.cval), + (unsigned long)(ins->u.cval)); break; case OP_BLOBCONST: { @@ -17146,7 +17772,7 @@ static void print_binary_op(struct compile_state *state, { unsigned mask; mask = REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO; - if (RHS(ins, 0)->id != ins->id) { + if (ID_REG(RHS(ins, 0)->id) != ID_REG(ins->id)) { internal_error(state, ins, "invalid register assignment"); } if (is_const(RHS(ins, 1))) { @@ -17184,7 +17810,7 @@ static void print_op_shift(struct compile_state *state, { unsigned mask; mask = REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO; - if (RHS(ins, 0)->id != ins->id) { + if (ID_REG(RHS(ins, 0)->id) != ID_REG(ins->id)) { internal_error(state, ins, "invalid register assignment"); } if (is_const(RHS(ins, 1))) { @@ -17577,14 +18203,14 @@ static void print_op_store(struct compile_state *state, value = (long_t)(src->u.cval); fprintf(fp, "\tmov%s $%ld, (%s)\n", type_suffix(state, src->type), - value, + (long)(value), reg(state, dst, REGCM_GPR32)); } else if (is_const(dst) && (dst->op == OP_INTCONST)) { fprintf(fp, "\tmov%s %s, 0x%08lx\n", type_suffix(state, src->type), reg(state, src, REGCM_GPR8_LO | REGCM_GPR16 | REGCM_GPR32), - dst->u.cval); + (unsigned long)(dst->u.cval)); } else { if (is_const(src) || is_const(dst)) { @@ -17700,7 +18326,7 @@ static void print_op_branch(struct compile_state *state, fprintf(fp, "\t%s L%s%lu\n", bop, state->label_prefix, - TARG(branch, 0)->u.cval); + (unsigned long)(TARG(branch, 0)->u.cval)); } static void print_op_set(struct compile_state *state, @@ -17766,7 +18392,8 @@ static void print_sdecl(struct compile_state *state, { fprintf(fp, ".section \"" DATA_SECTION "\"\n"); fprintf(fp, ".balign %d\n", align_of(state, ins->type)); - fprintf(fp, "L%s%lu:\n", state->label_prefix, ins->u.cval); + fprintf(fp, "L%s%lu:\n", + state->label_prefix, (unsigned long)(ins->u.cval)); print_const(state, MISC(ins, 0), fp); fprintf(fp, ".section \"" TEXT_SECTION "\"\n"); @@ -17865,7 +18492,8 @@ static void print_instruction(struct compile_state *state, if (!ins->use) { return; } - fprintf(fp, "L%s%lu:\n", state->label_prefix, ins->u.cval); + fprintf(fp, "L%s%lu:\n", + state->label_prefix, (unsigned long)(ins->u.cval)); break; /* Ignore OP_PIECE */ case OP_PIECE: @@ -17895,7 +18523,7 @@ static void print_instructions(struct compile_state *state) last_occurance = 0; fp = state->output; fprintf(fp, ".section \"" TEXT_SECTION "\"\n"); - first = RHS(state->main_function, 0); + first = state->first; ins = first; do { if (print_location && @@ -17967,11 +18595,21 @@ static void print_tokens(struct compile_state *state) } while(tk->tok != TOK_EOF); } +static void call_main(struct compile_state *state) +{ + struct triple *call; + call = new_triple(state, OP_CALL, &void_func, -1, -1); + call->type = &void_type; + MISC(call, 0) = state->main_function; + flatten(state, state->first, call); +} + static void compile(const char *filename, const char *ofilename, - int cpu, int debug, int opt, const char *label_prefix) + unsigned long features, int debug, int opt, const char *label_prefix) { int i; struct compile_state state; + struct triple *ptr; memset(&state, 0, sizeof(state)); state.file = 0; for(i = 0; i < sizeof(state.token)/sizeof(state.token[0]); i++) { @@ -17979,7 +18617,7 @@ static void compile(const char *filename, const char *ofilename, state.token[i].tok = -1; } /* Remember the debug settings */ - state.cpu = cpu; + state.features = features; state.debug = debug; state.optimize = opt; /* Remember the output filename */ @@ -17999,8 +18637,21 @@ static void compile(const char *filename, const char *ofilename, /* register the keywords the macro preprocessor knows */ register_macro_keywords(&state); /* Memorize where some special keywords are. */ + state.i_switch = lookup(&state, "switch", 6); + state.i_case = lookup(&state, "case", 4); state.i_continue = lookup(&state, "continue", 8); state.i_break = lookup(&state, "break", 5); + state.i_default = lookup(&state, "default", 7); + + /* Allocate beginning bounding labels for the function list */ + state.first = label(&state); + state.first->id |= TRIPLE_FLAG_VOLATILE; + use_triple(state.first, state.first); + ptr = label(&state); + ptr->id |= TRIPLE_FLAG_VOLATILE; + use_triple(ptr, ptr); + flatten(&state, state.first, ptr); + /* Enter the globl definition scope */ start_scope(&state); register_builtins(&state); @@ -18012,6 +18663,9 @@ static void compile(const char *filename, const char *ofilename, /* Exit the global definition scope */ end_scope(&state); + /* Call the main function */ + call_main(&state); + /* Now that basic compilation has happened * optimize the intermediate code */ @@ -18052,11 +18706,11 @@ int main(int argc, char **argv) const char *filename; const char *ofilename; const char *label_prefix; - int cpu; + unsigned long features; int last_argc; int debug; int optimize; - cpu = CPU_DEFAULT; + features = 0; label_prefix = ""; ofilename = "auto.inc"; optimize = 0; @@ -18090,11 +18744,12 @@ int main(int argc, char **argv) argv += 2; argc -= 2; } - else if (strncmp(argv[1], "-mcpu=", 6) == 0) { - cpu = arch_encode_cpu(argv[1] + 6); - if (cpu == BAD_CPU) { - arg_error("Invalid cpu specified: %s\n", - argv[1] + 6); + else if (strncmp(argv[1], "-m", 2) == 0) { + int result; + result = arch_encode_feature(argv[1] + 2, &features); + if (result < 0) { + arg_error("Invalid feature specified: %s\n", + argv[1] + 2); } argv++; argc--; @@ -18104,7 +18759,7 @@ int main(int argc, char **argv) arg_error("Wrong argument count %d\n", argc); } filename = argv[1]; - compile(filename, ofilename, cpu, debug, optimize, label_prefix); + compile(filename, ofilename, features, debug, optimize, label_prefix); return 0; } diff --git a/util/romcc/tests/fail_test4.c b/util/romcc/tests/fail_test4.c new file mode 100644 index 0000000000..a2d3bece66 --- /dev/null +++ b/util/romcc/tests/fail_test4.c @@ -0,0 +1,14 @@ +static void main(void) +{ + static const int foo = 2; + switch(foo) { + case 1: + break; + case 2: + break; + case 1: + break; + default: + break; + } +} diff --git a/util/romcc/tests/fail_test5.c b/util/romcc/tests/fail_test5.c new file mode 100644 index 0000000000..efa4e76d91 --- /dev/null +++ b/util/romcc/tests/fail_test5.c @@ -0,0 +1,14 @@ +static void main(void) +{ + static const int foo = 2; + switch(foo) { + case 1: + break; + default: + break; + case 2: + break; + default: + break; + } +} diff --git a/util/romcc/tests/linux_console.h b/util/romcc/tests/linux_console.h new file mode 100644 index 0000000000..0837dfc577 --- /dev/null +++ b/util/romcc/tests/linux_console.h @@ -0,0 +1,136 @@ +#ifndef LINUX_CONSOLE_H +#define LINUX_CONSOLE_H + +#include "linux_syscall.h" + +static const char *addr_of_char(unsigned char ch) +{ + static const char byte[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + }; + return byte + ch; +} + +static void console_tx_byte(unsigned char ch) +{ + write(STDOUT_FILENO, addr_of_char(ch), 1); +} + +static void console_tx_nibble(unsigned nibble) +{ + unsigned char digit; + digit = nibble + '0'; + if (digit > '9') { + digit += 39; + } + console_tx_byte(digit); +} + +static void console_tx_char(unsigned char byte) +{ + console_tx_byte(byte); +} + +static void console_tx_hex8(unsigned char value) +{ + console_tx_nibble((value >> 4U) & 0x0fU); + console_tx_nibble(value & 0x0fU); +} + +static void console_tx_hex16(unsigned short value) +{ + console_tx_nibble((value >> 12U) & 0x0FU); + console_tx_nibble((value >> 8U) & 0x0FU); + console_tx_nibble((value >> 4U) & 0x0FU); + console_tx_nibble(value & 0x0FU); +} + +static void console_tx_hex32(unsigned short value) +{ + console_tx_nibble((value >> 28U) & 0x0FU); + console_tx_nibble((value >> 24U) & 0x0FU); + console_tx_nibble((value >> 20U) & 0x0FU); + console_tx_nibble((value >> 16U) & 0x0FU); + console_tx_nibble((value >> 12U) & 0x0FU); + console_tx_nibble((value >> 8U) & 0x0FU); + console_tx_nibble((value >> 4U) & 0x0FU); + console_tx_nibble(value & 0x0FU); +} + +static void console_tx_string(const char *str) +{ + unsigned char ch; + while((ch = *str++) != '\0') { + console_tx_byte(ch); + } +} + +static void print_emerg_char(unsigned char byte) { console_tx_char(byte); } +static void print_emerg_hex8(unsigned char value) { console_tx_hex8(value); } +static void print_emerg_hex16(unsigned short value){ console_tx_hex16(value); } +static void print_emerg_hex32(unsigned int value) { console_tx_hex32(value); } +static void print_emerg(const char *str) { console_tx_string(str); } + +static void print_warn_char(unsigned char byte) { console_tx_char(byte); } +static void print_warn_hex8(unsigned char value) { console_tx_hex8(value); } +static void print_warn_hex16(unsigned short value){ console_tx_hex16(value); } +static void print_warn_hex32(unsigned int value) { console_tx_hex32(value); } +static void print_warn(const char *str) { console_tx_string(str); } + +static void print_info_char(unsigned char byte) { console_tx_char(byte); } +static void print_info_hex8(unsigned char value) { console_tx_hex8(value); } +static void print_info_hex16(unsigned short value){ console_tx_hex16(value); } +static void print_info_hex32(unsigned int value) { console_tx_hex32(value); } +static void print_info(const char *str) { console_tx_string(str); } + +static void print_debug_char(unsigned char byte) { console_tx_char(byte); } +static void print_debug_hex8(unsigned char value) { console_tx_hex8(value); } +static void print_debug_hex16(unsigned short value){ console_tx_hex16(value); } +static void print_debug_hex32(unsigned int value) { console_tx_hex32(value); } +static void print_debug(const char *str) { console_tx_string(str); } + +static void print_spew_char(unsigned char byte) { console_tx_char(byte); } +static void print_spew_hex8(unsigned char value) { console_tx_hex8(value); } +static void print_spew_hex16(unsigned short value){ console_tx_hex16(value); } +static void print_spew_hex32(unsigned int value) { console_tx_hex32(value); } +static void print_spew(const char *str) { console_tx_string(str); } + +static void die(const char *str) +{ + print_emerg(str); + do { + asm volatile (" "); + } while(1); +} +#endif /* LINUX_CONSOLE_H */ diff --git a/util/romcc/tests/linux_syscall.h b/util/romcc/tests/linux_syscall.h new file mode 100644 index 0000000000..487095f712 --- /dev/null +++ b/util/romcc/tests/linux_syscall.h @@ -0,0 +1,7 @@ +#ifndef LINUX_SYSCALL_H +#define LINUX_SYSCALL_H + +/* When I support other platforms use #ifdefs here */ +#include "linuxi386_syscall.h" + +#endif /* LINUX_SYSCALL_H */ diff --git a/util/romcc/tests/linux_test1.c b/util/romcc/tests/linux_test1.c new file mode 100644 index 0000000000..ee82148031 --- /dev/null +++ b/util/romcc/tests/linux_test1.c @@ -0,0 +1,8 @@ +#include "linux_syscall.h" + +static void main(void) +{ + static const char msg[] = "hello world\r\n"; + write(STDOUT_FILENO, msg, sizeof(msg)); + _exit(0); +} diff --git a/util/romcc/tests/linux_test2.c b/util/romcc/tests/linux_test2.c new file mode 100644 index 0000000000..8f40fa0d47 --- /dev/null +++ b/util/romcc/tests/linux_test2.c @@ -0,0 +1,673 @@ +#include "linux_syscall.h" +#include "linux_console.h" + + +static void setup_coherent_ht_domain(void) +{ + static const unsigned int register_values[] = { +#if 1 + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x40) & 0xFF)), 0xfff0f0f0, 0x00010101, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x44) & 0xFF)), 0xfff0f0f0, 0x00010101, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x48) & 0xFF)), 0xfff0f0f0, 0x00010101, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x4c) & 0xFF)), 0xfff0f0f0, 0x00010101, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x50) & 0xFF)), 0xfff0f0f0, 0x00010101, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x54) & 0xFF)), 0xfff0f0f0, 0x00010101, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x58) & 0xFF)), 0xfff0f0f0, 0x00010101, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x5c) & 0xFF)), 0xfff0f0f0, 0x00010101, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x68) & 0xFF)), 0x00800000, 0x0f00840f, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x6C) & 0xFF)), 0xffffff8c, 0x00000000 | (1 << 6) |(1 << 5)| (1 << 4), + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x84) & 0xFF)), 0x00009c05, 0x11110020, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x88) & 0xFF)), 0xfffff0ff, 0x00000200, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x94) & 0xFF)), 0xff000000, 0x00ff0000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x44) & 0xFF)), 0x0000f8f8, 0x003f0000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x4C) & 0xFF)), 0x0000f8f8, 0x00000001, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x54) & 0xFF)), 0x0000f8f8, 0x00000002, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x5C) & 0xFF)), 0x0000f8f8, 0x00000003, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x64) & 0xFF)), 0x0000f8f8, 0x00000004, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x6C) & 0xFF)), 0x0000f8f8, 0x00000005, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x74) & 0xFF)), 0x0000f8f8, 0x00000006, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x7C) & 0xFF)), 0x0000f8f8, 0x00000007, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x40) & 0xFF)), 0x0000f8fc, 0x00000003, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x48) & 0xFF)), 0x0000f8fc, 0x00400000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x50) & 0xFF)), 0x0000f8fc, 0x00400000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x58) & 0xFF)), 0x0000f8fc, 0x00400000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x60) & 0xFF)), 0x0000f8fc, 0x00400000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x68) & 0xFF)), 0x0000f8fc, 0x00400000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x70) & 0xFF)), 0x0000f8fc, 0x00400000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x78) & 0xFF)), 0x0000f8fc, 0x00400000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x84) & 0xFF)), 0x00000048, 0x00e1ff00, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x8C) & 0xFF)), 0x00000048, 0x00dfff00, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x94) & 0xFF)), 0x00000048, 0x00e3ff00, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x9C) & 0xFF)), 0x00000048, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA4) & 0xFF)), 0x00000048, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xAC) & 0xFF)), 0x00000048, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB4) & 0xFF)), 0x00000048, 0x00000b00, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xBC) & 0xFF)), 0x00000048, 0x00fe0b00, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x80) & 0xFF)), 0x000000f0, 0x00e00003, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x88) & 0xFF)), 0x000000f0, 0x00d80003, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x90) & 0xFF)), 0x000000f0, 0x00e20003, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x98) & 0xFF)), 0x000000f0, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA0) & 0xFF)), 0x000000f0, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA8) & 0xFF)), 0x000000f0, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB0) & 0xFF)), 0x000000f0, 0x00000a03, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB8) & 0xFF)), 0x000000f0, 0x00400003, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC4) & 0xFF)), 0xFE000FC8, 0x0000d000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xCC) & 0xFF)), 0xFE000FC8, 0x000ff000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD4) & 0xFF)), 0xFE000FC8, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xDC) & 0xFF)), 0xFE000FC8, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC0) & 0xFF)), 0xFE000FCC, 0x0000d003, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC8) & 0xFF)), 0xFE000FCC, 0x00001013, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD0) & 0xFF)), 0xFE000FCC, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD8) & 0xFF)), 0xFE000FCC, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE0) & 0xFF)), 0x0000FC88, 0xff000003, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE4) & 0xFF)), 0x0000FC88, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE8) & 0xFF)), 0x0000FC88, 0x00000000, + ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xEC) & 0xFF)), 0x0000FC88, 0x00000000, +#else +#define PCI_ADDR(BUS, DEV, FN, WHERE) ( \ + (((BUS) & 0xFF) << 16) | \ + (((DEV) & 0x1f) << 11) | \ + (((FN) & 0x07) << 8) | \ + ((WHERE) & 0xFF)) + + /* Routing Table Node i + * F0:0x40 i = 0, + * F0:0x44 i = 1, + * F0:0x48 i = 2, + * F0:0x4c i = 3, + * F0:0x50 i = 4, + * F0:0x54 i = 5, + * F0:0x58 i = 6, + * F0:0x5c i = 7 + * [ 0: 3] Request Route + * [0] Route to this node + * [1] Route to Link 0 + * [2] Route to Link 1 + * [3] Route to Link 2 + * [11: 8] Response Route + * [0] Route to this node + * [1] Route to Link 0 + * [2] Route to Link 1 + * [3] Route to Link 2 + * [19:16] Broadcast route + * [0] Route to this node + * [1] Route to Link 0 + * [2] Route to Link 1 + * [3] Route to Link 2 + */ + PCI_ADDR(0, 0x18, 0, 0x40), 0xfff0f0f0, 0x00010101, + PCI_ADDR(0, 0x18, 0, 0x44), 0xfff0f0f0, 0x00010101, + PCI_ADDR(0, 0x18, 0, 0x48), 0xfff0f0f0, 0x00010101, + PCI_ADDR(0, 0x18, 0, 0x4c), 0xfff0f0f0, 0x00010101, + PCI_ADDR(0, 0x18, 0, 0x50), 0xfff0f0f0, 0x00010101, + PCI_ADDR(0, 0x18, 0, 0x54), 0xfff0f0f0, 0x00010101, + PCI_ADDR(0, 0x18, 0, 0x58), 0xfff0f0f0, 0x00010101, + PCI_ADDR(0, 0x18, 0, 0x5c), 0xfff0f0f0, 0x00010101, + + /* Hypetransport Transaction Control Register + * F0:0x68 + * [ 0: 0] Disable read byte probe + * 0 = Probes issues + * 1 = Probes not issued + * [ 1: 1] Disable Read Doubleword probe + * 0 = Probes issued + * 1 = Probes not issued + * [ 2: 2] Disable write byte probes + * 0 = Probes issued + * 1 = Probes not issued + * [ 3: 3] Disable Write Doubleword Probes + * 0 = Probes issued + * 1 = Probes not issued. + * [ 4: 4] Disable Memroy Controller Target Start + * 0 = TgtStart packets are generated + * 1 = TgtStart packets are not generated. + * [ 5: 5] CPU1 Enable + * 0 = Second CPU disabled or not present + * 1 = Second CPU enabled. + * [ 6: 6] CPU Request PassPW + * 0 = CPU requests do not pass posted writes + * 1 = CPU requests pass posted writes. + * [ 7: 7] CPU read Respons PassPW + * 0 = CPU Responses do not pass posted writes + * 1 = CPU responses pass posted writes. + * [ 8: 8] Disable Probe Memory Cancel + * 0 = Probes may generate MemCancels + * 1 = Probes may not generate MemCancels + * [ 9: 9] Disable Remote Probe Memory Cancel. + * 0 = Probes hitting dirty blocks generate memory cancel packets + * 1 = Only probed caches on the same node as the memory controller + * generate cancel packets. + * [10:10] Disable Fill Probe + * 0 = Probes issued for cache fills + * 1 = Probes not issued for cache fills. + * [11:11] Response PassPw + * 0 = Downstream response PassPW based on original request + * 1 = Downstream response PassPW set to 1 + * [12:12] Change ISOC to Ordered + * 0 = Bit 1 of coherent HT RdSz/WrSz command used for iosynchronous prioritization + * 1 = Bit 1 of coherent HT RdSz/WrSz command used for ordering. + * [14:13] Buffer Release Priority select + * 00 = 64 + * 01 = 16 + * 10 = 8 + * 11 = 2 + * [15:15] Limit Coherent HT Configuration Space Range + * 0 = No coherent HT configuration space restrictions + * 1 = Limit coherent HT configuration space based on node count + * [16:16] Local Interrupt Conversion Enable. + * 0 = ExtInt/NMI interrups unaffected. + * 1 = ExtInt/NMI broadcat interrupts converted to LINT0/1 + * [17:17] APIC Extended Broadcast Enable. + * 0 = APIC broadcast is 0F + * 1 = APIC broadcast is FF + * [18:18] APIC Extended ID Enable + * 0 = APIC ID is 4 bits. + * 1 = APIC ID is 8 bits. + * [19:19] APIC Extended Spurious Vector Enable + * 0 = Lower 4 bits of spurious vector are read-only 1111 + * 1 = Lower 4 bits of spurious vecotr are writeable. + * [20:20] Sequence ID Source Node Enable + * 0 = Normal operation + * 1 = Keep SeqID on routed packets for debugging. + * [22:21] Downstream non-posted request limit + * 00 = No limit + * 01 = Limited to 1 + * 10 = Limited to 4 + * 11 = Limited to 8 + * [23:23] RESERVED + * [25:24] Medium-Priority Bypass Count + * - Maximum # of times a medium priority access can pass a low + * priority access before Medium-Priority mode is disabled for one access. + * [27:26] High-Priority Bypass Count + * - Maximum # of times a high prioirty access can pass a medium or low + * priority access before High-prioirty mode is disabled for one access. + * [28:28] Enable High Priority CPU Reads + * 0 = Cpu reads are medium prioirty + * 1 = Cpu reads are high prioirty + * [29:29] Disable Low Priority Writes + * 0 = Non-isochronous writes are low priority + * 1 = Non-isochronous writes are medium prioirty + * [30:30] Disable High Priority Isochronous writes + * 0 = Isochronous writes are high priority + * 1 = Isochronous writes are medium priority + * [31:31] Disable Medium Priority Isochronous writes + * 0 = Isochronous writes are medium are high + * 1 = With bit 30 set makes Isochrouns writes low priority. + */ + PCI_ADDR(0, 0x18, 0, 0x68), 0x00800000, 0x0f00840f, + /* HT Initialization Control Register + * F0:0x6C + * [ 0: 0] Routing Table Disable + * 0 = Packets are routed according to routing tables + * 1 = Packets are routed according to the default link field + * [ 1: 1] Request Disable (BSP should clear this) + * 0 = Request packets may be generated + * 1 = Request packets may not be generated. + * [ 3: 2] Default Link (Read-only) + * 00 = LDT0 + * 01 = LDT1 + * 10 = LDT2 + * 11 = CPU on same node + * [ 4: 4] Cold Reset + * - Scratch bit cleared by a cold reset + * [ 5: 5] BIOS Reset Detect + * - Scratch bit cleared by a cold reset + * [ 6: 6] INIT Detect + * - Scratch bit cleared by a warm or cold reset not by an INIT + * + */ + PCI_ADDR(0, 0x18, 0, 0x6C), 0xffffff8c, 0x00000000 | (1 << 6) |(1 << 5)| (1 << 4), + /* LDTi Capabilities Registers + * F0:0x80 i = 0, + * F0:0xA0 i = 1, + * F0:0xC0 i = 2, + */ + /* LDTi Link Control Registrs + * F0:0x84 i = 0, + * F0:0xA4 i = 1, + * F0:0xC4 i = 2, + * [ 1: 1] CRC Flood Enable + * 0 = Do not generate sync packets on CRC error + * 1 = Generate sync packets on CRC error + * [ 2: 2] CRC Start Test (Read-Only) + * [ 3: 3] CRC Force Frame Error + * 0 = Do not generate bad CRC + * 1 = Generate bad CRC + * [ 4: 4] Link Failure + * 0 = No link failure detected + * 1 = Link failure detected + * [ 5: 5] Initialization Complete + * 0 = Initialization not complete + * 1 = Initialization complete + * [ 6: 6] Receiver off + * 0 = Recevier on + * 1 = Receiver off + * [ 7: 7] Transmitter Off + * 0 = Transmitter on + * 1 = Transmitter off + * [ 9: 8] CRC_Error + * 00 = No error + * [0] = 1 Error on byte lane 0 + * [1] = 1 Error on byte lane 1 + * [12:12] Isochrnous Enable (Read-Only) + * [13:13] HT Stop Tristate Enable + * 0 = Driven during an LDTSTOP_L + * 1 = Tristated during and LDTSTOP_L + * [14:14] Extended CTL Time + * 0 = CTL is asserted for 16 bit times during link initialization + * 1 = CTL is asserted for 50us during link initialization + * [18:16] Max Link Width In (Read-Only?) + * 000 = 8 bit link + * 001 = 16bit link + * [19:19] Doubleword Flow Control in (Read-Only) + * 0 = This link does not support doubleword flow control + * 1 = This link supports doubleword flow control + * [22:20] Max Link Width Out (Read-Only?) + * 000 = 8 bit link + * 001 = 16bit link + * [23:23] Doubleworld Flow Control out (Read-Only) + * 0 = This link does not support doubleword flow control + * 1 = This link supports doubleworkd flow control + * [26:24] Link Width In + * 000 = Use 8 bits + * 001 = Use 16 bits + * 010 = reserved + * 011 = Use 32 bits + * 100 = Use 2 bits + * 101 = Use 4 bits + * 110 = reserved + * 111 = Link physically not connected + * [27:27] Doubleword Flow Control In Enable + * 0 = Doubleword flow control disabled + * 1 = Doubleword flow control enabled (Not currently supported) + * [30:28] Link Width Out + * 000 = Use 8 bits + * 001 = Use 16 bits + * 010 = reserved + * 011 = Use 32 bits + * 100 = Use 2 bits + * 101 = Use 4 bits + * 110 = reserved + * 111 = Link physically not connected + * [31:31] Doubleworld Flow Control Out Enable + * 0 = Doubleworld flow control disabled + * 1 = Doubleword flow control enabled (Not currently supported) + */ + PCI_ADDR(0, 0x18, 0, 0x84), 0x00009c05, 0x11110020, + /* LDTi Frequency/Revision Registers + * F0:0x88 i = 0, + * F0:0xA8 i = 1, + * F0:0xC8 i = 2, + * [ 4: 0] Minor Revision + * Contains the HT Minor revision + * [ 7: 5] Major Revision + * Contains the HT Major revision + * [11: 8] Link Frequency (Takes effect the next time the link is reconnected) + * 0000 = 200Mhz + * 0001 = reserved + * 0010 = 400Mhz + * 0011 = reserved + * 0100 = 600Mhz + * 0101 = 800Mhz + * 0110 = 1000Mhz + * 0111 = reserved + * 1000 = reserved + * 1001 = reserved + * 1010 = reserved + * 1011 = reserved + * 1100 = reserved + * 1101 = reserved + * 1110 = reserved + * 1111 = 100 Mhz + * [15:12] Error (Not currently Implemented) + * [31:16] Indicates the frequency capabilities of the link + * [16] = 1 encoding 0000 of freq supported + * [17] = 1 encoding 0001 of freq supported + * [18] = 1 encoding 0010 of freq supported + * [19] = 1 encoding 0011 of freq supported + * [20] = 1 encoding 0100 of freq supported + * [21] = 1 encoding 0101 of freq supported + * [22] = 1 encoding 0110 of freq supported + * [23] = 1 encoding 0111 of freq supported + * [24] = 1 encoding 1000 of freq supported + * [25] = 1 encoding 1001 of freq supported + * [26] = 1 encoding 1010 of freq supported + * [27] = 1 encoding 1011 of freq supported + * [28] = 1 encoding 1100 of freq supported + * [29] = 1 encoding 1101 of freq supported + * [30] = 1 encoding 1110 of freq supported + * [31] = 1 encoding 1111 of freq supported + */ + PCI_ADDR(0, 0x18, 0, 0x88), 0xfffff0ff, 0x00000200, + /* LDTi Feature Capability + * F0:0x8C i = 0, + * F0:0xAC i = 1, + * F0:0xCC i = 2, + */ + /* LDTi Buffer Count Registers + * F0:0x90 i = 0, + * F0:0xB0 i = 1, + * F0:0xD0 i = 2, + */ + /* LDTi Bus Number Registers + * F0:0x94 i = 0, + * F0:0xB4 i = 1, + * F0:0xD4 i = 2, + * For NonCoherent HT specifies the bus number downstream (behind the host bridge) + * [ 0: 7] Primary Bus Number + * [15: 8] Secondary Bus Number + * [23:15] Subordiante Bus Number + * [31:24] reserved + */ + PCI_ADDR(0, 0x18, 0, 0x94), 0xff000000, 0x00ff0000, + /* LDTi Type Registers + * F0:0x98 i = 0, + * F0:0xB8 i = 1, + * F0:0xD8 i = 2, + */ + /* Careful set limit registers before base registers which contain the enables */ + /* DRAM Limit i Registers + * F1:0x44 i = 0 + * F1:0x4C i = 1 + * F1:0x54 i = 2 + * F1:0x5C i = 3 + * F1:0x64 i = 4 + * F1:0x6C i = 5 + * F1:0x74 i = 6 + * F1:0x7C i = 7 + * [ 2: 0] Destination Node ID + * 000 = Node 0 + * 001 = Node 1 + * 010 = Node 2 + * 011 = Node 3 + * 100 = Node 4 + * 101 = Node 5 + * 110 = Node 6 + * 111 = Node 7 + * [ 7: 3] Reserved + * [10: 8] Interleave select + * specifies the values of A[14:12] to use with interleave enable. + * [15:11] Reserved + * [31:16] DRAM Limit Address i Bits 39-24 + * This field defines the upper address bits of a 40 bit address + * that define the end of the DRAM region. + */ +#if MEMORY_1024MB + PCI_ADDR(0, 0x18, 1, 0x44), 0x0000f8f8, 0x003f0000, +#endif +#if MEMORY_512MB + PCI_ADDR(0, 0x18, 1, 0x44), 0x0000f8f8, 0x001f0000, +#endif + PCI_ADDR(0, 0x18, 1, 0x4C), 0x0000f8f8, 0x00000001, + PCI_ADDR(0, 0x18, 1, 0x54), 0x0000f8f8, 0x00000002, + PCI_ADDR(0, 0x18, 1, 0x5C), 0x0000f8f8, 0x00000003, + PCI_ADDR(0, 0x18, 1, 0x64), 0x0000f8f8, 0x00000004, + PCI_ADDR(0, 0x18, 1, 0x6C), 0x0000f8f8, 0x00000005, + PCI_ADDR(0, 0x18, 1, 0x74), 0x0000f8f8, 0x00000006, + PCI_ADDR(0, 0x18, 1, 0x7C), 0x0000f8f8, 0x00000007, + /* DRAM Base i Registers + * F1:0x40 i = 0 + * F1:0x48 i = 1 + * F1:0x50 i = 2 + * F1:0x58 i = 3 + * F1:0x60 i = 4 + * F1:0x68 i = 5 + * F1:0x70 i = 6 + * F1:0x78 i = 7 + * [ 0: 0] Read Enable + * 0 = Reads Disabled + * 1 = Reads Enabled + * [ 1: 1] Write Enable + * 0 = Writes Disabled + * 1 = Writes Enabled + * [ 7: 2] Reserved + * [10: 8] Interleave Enable + * 000 = No interleave + * 001 = Interleave on A[12] (2 nodes) + * 010 = reserved + * 011 = Interleave on A[12] and A[14] (4 nodes) + * 100 = reserved + * 101 = reserved + * 110 = reserved + * 111 = Interleve on A[12] and A[13] and A[14] (8 nodes) + * [15:11] Reserved + * [13:16] DRAM Base Address i Bits 39-24 + * This field defines the upper address bits of a 40-bit address + * that define the start of the DRAM region. + */ + PCI_ADDR(0, 0x18, 1, 0x40), 0x0000f8fc, 0x00000003, +#if MEMORY_1024MB + PCI_ADDR(0, 0x18, 1, 0x48), 0x0000f8fc, 0x00400000, + PCI_ADDR(0, 0x18, 1, 0x50), 0x0000f8fc, 0x00400000, + PCI_ADDR(0, 0x18, 1, 0x58), 0x0000f8fc, 0x00400000, + PCI_ADDR(0, 0x18, 1, 0x60), 0x0000f8fc, 0x00400000, + PCI_ADDR(0, 0x18, 1, 0x68), 0x0000f8fc, 0x00400000, + PCI_ADDR(0, 0x18, 1, 0x70), 0x0000f8fc, 0x00400000, + PCI_ADDR(0, 0x18, 1, 0x78), 0x0000f8fc, 0x00400000, +#endif +#if MEMORY_512MB + PCI_ADDR(0, 0x18, 1, 0x48), 0x0000f8fc, 0x00200000, + PCI_ADDR(0, 0x18, 1, 0x50), 0x0000f8fc, 0x00200000, + PCI_ADDR(0, 0x18, 1, 0x58), 0x0000f8fc, 0x00200000, + PCI_ADDR(0, 0x18, 1, 0x60), 0x0000f8fc, 0x00200000, + PCI_ADDR(0, 0x18, 1, 0x68), 0x0000f8fc, 0x00200000, + PCI_ADDR(0, 0x18, 1, 0x70), 0x0000f8fc, 0x00200000, + PCI_ADDR(0, 0x18, 1, 0x78), 0x0000f8fc, 0x00200000, +#endif + + /* Memory-Mapped I/O Limit i Registers + * F1:0x84 i = 0 + * F1:0x8C i = 1 + * F1:0x94 i = 2 + * F1:0x9C i = 3 + * F1:0xA4 i = 4 + * F1:0xAC i = 5 + * F1:0xB4 i = 6 + * F1:0xBC i = 7 + * [ 2: 0] Destination Node ID + * 000 = Node 0 + * 001 = Node 1 + * 010 = Node 2 + * 011 = Node 3 + * 100 = Node 4 + * 101 = Node 5 + * 110 = Node 6 + * 111 = Node 7 + * [ 3: 3] Reserved + * [ 5: 4] Destination Link ID + * 00 = Link 0 + * 01 = Link 1 + * 10 = Link 2 + * 11 = Reserved + * [ 6: 6] Reserved + * [ 7: 7] Non-Posted + * 0 = CPU writes may be posted + * 1 = CPU writes must be non-posted + * [31: 8] Memory-Mapped I/O Limit Address i (39-16) + * This field defines the upp adddress bits of a 40-bit address that + * defines the end of a memory-mapped I/O region n + */ + PCI_ADDR(0, 0x18, 1, 0x84), 0x00000048, 0x00e1ff00, + PCI_ADDR(0, 0x18, 1, 0x8C), 0x00000048, 0x00dfff00, + PCI_ADDR(0, 0x18, 1, 0x94), 0x00000048, 0x00e3ff00, + PCI_ADDR(0, 0x18, 1, 0x9C), 0x00000048, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xA4), 0x00000048, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xAC), 0x00000048, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xB4), 0x00000048, 0x00000b00, + PCI_ADDR(0, 0x18, 1, 0xBC), 0x00000048, 0x00fe0b00, + + /* Memory-Mapped I/O Base i Registers + * F1:0x80 i = 0 + * F1:0x88 i = 1 + * F1:0x90 i = 2 + * F1:0x98 i = 3 + * F1:0xA0 i = 4 + * F1:0xA8 i = 5 + * F1:0xB0 i = 6 + * F1:0xB8 i = 7 + * [ 0: 0] Read Enable + * 0 = Reads disabled + * 1 = Reads Enabled + * [ 1: 1] Write Enable + * 0 = Writes disabled + * 1 = Writes Enabled + * [ 2: 2] Cpu Disable + * 0 = Cpu can use this I/O range + * 1 = Cpu requests do not use this I/O range + * [ 3: 3] Lock + * 0 = base/limit registers i are read/write + * 1 = base/limit registers i are read-only + * [ 7: 4] Reserved + * [31: 8] Memory-Mapped I/O Base Address i (39-16) + * This field defines the upper address bits of a 40bit address + * that defines the start of memory-mapped I/O region i + */ + PCI_ADDR(0, 0x18, 1, 0x80), 0x000000f0, 0x00e00003, + PCI_ADDR(0, 0x18, 1, 0x88), 0x000000f0, 0x00d80003, + PCI_ADDR(0, 0x18, 1, 0x90), 0x000000f0, 0x00e20003, + PCI_ADDR(0, 0x18, 1, 0x98), 0x000000f0, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xA0), 0x000000f0, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xA8), 0x000000f0, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xB0), 0x000000f0, 0x00000a03, +#if MEMORY_1024MB + PCI_ADDR(0, 0x18, 1, 0xB8), 0x000000f0, 0x00400003, +#endif +#if MEMORY_512MB + PCI_ADDR(0, 0x18, 1, 0xB8), 0x000000f0, 0x00200003, +#endif + + /* PCI I/O Limit i Registers + * F1:0xC4 i = 0 + * F1:0xCC i = 1 + * F1:0xD4 i = 2 + * F1:0xDC i = 3 + * [ 2: 0] Destination Node ID + * 000 = Node 0 + * 001 = Node 1 + * 010 = Node 2 + * 011 = Node 3 + * 100 = Node 4 + * 101 = Node 5 + * 110 = Node 6 + * 111 = Node 7 + * [ 3: 3] Reserved + * [ 5: 4] Destination Link ID + * 00 = Link 0 + * 01 = Link 1 + * 10 = Link 2 + * 11 = reserved + * [11: 6] Reserved + * [24:12] PCI I/O Limit Address i + * This field defines the end of PCI I/O region n + * [31:25] Reserved + */ + PCI_ADDR(0, 0x18, 1, 0xC4), 0xFE000FC8, 0x0000d000, + PCI_ADDR(0, 0x18, 1, 0xCC), 0xFE000FC8, 0x000ff000, + PCI_ADDR(0, 0x18, 1, 0xD4), 0xFE000FC8, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xDC), 0xFE000FC8, 0x00000000, + + /* PCI I/O Base i Registers + * F1:0xC0 i = 0 + * F1:0xC8 i = 1 + * F1:0xD0 i = 2 + * F1:0xD8 i = 3 + * [ 0: 0] Read Enable + * 0 = Reads Disabled + * 1 = Reads Enabled + * [ 1: 1] Write Enable + * 0 = Writes Disabled + * 1 = Writes Enabled + * [ 3: 2] Reserved + * [ 4: 4] VGA Enable + * 0 = VGA matches Disabled + * 1 = matches all address < 64K and where A[9:0] is in the + * range 3B0-3BB or 3C0-3DF independen of the base & limit registers + * [ 5: 5] ISA Enable + * 0 = ISA matches Disabled + * 1 = Blocks address < 64K and in the last 768 bytes of eack 1K block + * from matching agains this base/limit pair + * [11: 6] Reserved + * [24:12] PCI I/O Base i + * This field defines the start of PCI I/O region n + * [31:25] Reserved + */ + PCI_ADDR(0, 0x18, 1, 0xC0), 0xFE000FCC, 0x0000d003, + PCI_ADDR(0, 0x18, 1, 0xC8), 0xFE000FCC, 0x00001013, + PCI_ADDR(0, 0x18, 1, 0xD0), 0xFE000FCC, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xD8), 0xFE000FCC, 0x00000000, + + /* Config Base and Limit i Registers + * F1:0xE0 i = 0 + * F1:0xE4 i = 1 + * F1:0xE8 i = 2 + * F1:0xEC i = 3 + * [ 0: 0] Read Enable + * 0 = Reads Disabled + * 1 = Reads Enabled + * [ 1: 1] Write Enable + * 0 = Writes Disabled + * 1 = Writes Enabled + * [ 2: 2] Device Number Compare Enable + * 0 = The ranges are based on bus number + * 1 = The ranges are ranges of devices on bus 0 + * [ 3: 3] Reserved + * [ 6: 4] Destination Node + * 000 = Node 0 + * 001 = Node 1 + * 010 = Node 2 + * 011 = Node 3 + * 100 = Node 4 + * 101 = Node 5 + * 110 = Node 6 + * 111 = Node 7 + * [ 7: 7] Reserved + * [ 9: 8] Destination Link + * 00 = Link 0 + * 01 = Link 1 + * 10 = Link 2 + * 11 - Reserved + * [15:10] Reserved + * [23:16] Bus Number Base i + * This field defines the lowest bus number in configuration region i + * [31:24] Bus Number Limit i + * This field defines the highest bus number in configuration regin i + */ + PCI_ADDR(0, 0x18, 1, 0xE0), 0x0000FC88, 0xff000003, + PCI_ADDR(0, 0x18, 1, 0xE4), 0x0000FC88, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xE8), 0x0000FC88, 0x00000000, + PCI_ADDR(0, 0x18, 1, 0xEC), 0x0000FC88, 0x00000000, +#endif + }; + int i; + int max; + print_debug("setting up coherent ht domain....\r\n"); + max = sizeof(register_values)/sizeof(register_values[0]); + for(i = 0; i < max; i += 3) { + unsigned long reg; +#if 1 + print_debug_hex32(register_values[i]); + print_debug(" <-"); + print_debug_hex32(register_values[i+2]); + print_debug("\r\n"); +#endif +#if 0 + reg = pci_read_config32(register_values[i]); + reg &= register_values[i+1]; + reg |= register_values[i+2] & ~register_values[i+1]; + pci_write_config32(register_values[i], reg); +#endif + } + print_debug("done.\r\n"); +} + +static void main(void) +{ + static const char msg[] = "hello world\r\n"; +#if 0 + write(STDOUT_FILENO, msg, sizeof(msg)); +#endif +#if 1 + setup_coherent_ht_domain(); +#endif + _exit(0); +} diff --git a/util/romcc/tests/linux_test3.c b/util/romcc/tests/linux_test3.c new file mode 100644 index 0000000000..97187ae5e6 --- /dev/null +++ b/util/romcc/tests/linux_test3.c @@ -0,0 +1,28 @@ +#include "linux_syscall.h" +#include "linux_console.h" +static void goto_test(void) +{ + int i; + print_debug("goto_test\n"); + + i = 0; + goto bottom; + { + top: + print_debug("i = "); + print_debug_hex8(i); + print_debug("\n"); + + i = i + 1; + } + bottom: + if (i < 10) { + goto top; + } +} + +static void main(void) +{ + goto_test(); + _exit(0); +} diff --git a/util/romcc/tests/linux_test4.c b/util/romcc/tests/linux_test4.c new file mode 100644 index 0000000000..1f09918362 --- /dev/null +++ b/util/romcc/tests/linux_test4.c @@ -0,0 +1,46 @@ +#include "linux_syscall.h" +#include "linux_console.h" + +struct socket_desc { + short up; + short down; + short across; +}; + +static void main(void) +{ + static const struct socket_desc cpu_socketsA[] = { + { .up = 2, .down = -1, .across = 1 }, /* Node 0 */ + { .up = 3, .down = -1, .across = 0 }, /* Node 1 */ + { .up = -1, .down = 0, .across = 3 }, /* Node 2 */ + { .up = -1, .down = 1, .across = 2 } /* Node 3 */ + }; + static const struct socket_desc cpu_socketsB[4] = { + { 2, -1, 1 }, /* Node 0 */ + { 3, -1, 0 }, /* Node 1 */ + { -1, 0, 3 }, /* Node 2 */ + { -1, 1, 2 } /* Node 3 */ + }; + int i; + print_debug("cpu_socketA\n"); + for(i = 0; i < sizeof(cpu_socketsA)/sizeof(cpu_socketsA[0]); i++) { + print_debug(".up="); + print_debug_hex16(cpu_socketsA[i].up); + print_debug(" .down="); + print_debug_hex16(cpu_socketsA[i].down); + print_debug(" .across="); + print_debug_hex16(cpu_socketsA[i].across); + print_debug("\n"); + } + print_debug("\ncpu_socketB\n"); + for(i = 0; i < sizeof(cpu_socketsB)/sizeof(cpu_socketsB[0]); i++) { + print_debug(".up="); + print_debug_hex16(cpu_socketsB[i].up); + print_debug(" .down="); + print_debug_hex16(cpu_socketsB[i].down); + print_debug(" .across="); + print_debug_hex16(cpu_socketsB[i].across); + print_debug("\n"); + } + _exit(0); +} diff --git a/util/romcc/tests/linux_test5.c b/util/romcc/tests/linux_test5.c new file mode 100644 index 0000000000..55613c21b0 --- /dev/null +++ b/util/romcc/tests/linux_test5.c @@ -0,0 +1,359 @@ +#include "linux_syscall.h" +#include "linux_console.h" + +int log2(int value) +{ + /* __builtin_bsr is a exactly equivalent to the x86 machine + * instruction with the exception that it returns -1 + * when the value presented to it is zero. + * Otherwise __builtin_bsr returns the zero based index of + * the highest bit set. + */ + return __builtin_bsr(value); +} + + +static int smbus_read_byte(unsigned device, unsigned address) +{ + static const unsigned char dimm[] = { +0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01, +0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40, +0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + +0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01, +0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40, +0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }; + return dimm[(device << 8) + address]; +} + +#define SMBUS_MEM_DEVICE_START 0x00 +#define SMBUS_MEM_DEVICE_END 0x01 +#define SMBUS_MEM_DEVICE_INC 1 + +/* Function 2 */ +#define DRAM_CONFIG_HIGH 0x94 +#define DCH_MEMCLK_SHIFT 20 +#define DCH_MEMCLK_MASK 7 +#define DCH_MEMCLK_100MHZ 0 +#define DCH_MEMCLK_133MHZ 2 +#define DCH_MEMCLK_166MHZ 5 +#define DCH_MEMCLK_200MHZ 7 + +/* Function 3 */ +#define NORTHBRIDGE_CAP 0xE8 +#define NBCAP_128Bit 0x0001 +#define NBCAP_MP 0x0002 +#define NBCAP_BIG_MP 0x0004 +#define NBCAP_ECC 0x0004 +#define NBCAP_CHIPKILL_ECC 0x0010 +#define NBCAP_MEMCLK_SHIFT 5 +#define NBCAP_MEMCLK_MASK 3 +#define NBCAP_MEMCLK_100MHZ 3 +#define NBCAP_MEMCLK_133MHZ 2 +#define NBCAP_MEMCLK_166MHZ 1 +#define NBCAP_MEMCLK_200MHZ 0 +#define NBCAP_MEMCTRL 0x0100 + +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; + +static unsigned spd_to_dimm(unsigned device) +{ + return (device - SMBUS_MEM_DEVICE_START); +} + +static void disable_dimm(unsigned index) +{ + print_debug("disabling dimm"); + print_debug_hex8(index); + print_debug("\r\n"); +#if 0 + pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CSBASE + (((index << 1)+0)<<2), 0); + pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CSBASE + (((index << 1)+1)<<2), 0); +#endif +} + + +struct mem_param { + uint8_t cycle_time; + uint32_t dch_memclk; +}; + +static const struct mem_param *get_mem_param(unsigned min_cycle_time) +{ + static const struct mem_param speed[] = { + { + .cycle_time = 0xa0, + .dch_memclk = DCH_MEMCLK_100MHZ << DCH_MEMCLK_SHIFT, + }, + { + .cycle_time = 0x75, + .dch_memclk = DCH_MEMCLK_133MHZ << DCH_MEMCLK_SHIFT, + }, + { + .cycle_time = 0x60, + .dch_memclk = DCH_MEMCLK_166MHZ << DCH_MEMCLK_SHIFT, + }, + { + .cycle_time = 0x50, + .dch_memclk = DCH_MEMCLK_200MHZ << DCH_MEMCLK_SHIFT, + }, + { + .cycle_time = 0x00, + }, + }; + const struct mem_param *param; + for(param = &speed[0]; param->cycle_time ; param++) { + if (min_cycle_time > (param+1)->cycle_time) { + break; + } + } + if (!param->cycle_time) { + die("min_cycle_time to low"); + } + return param; +} + +#if 1 +static void debug(int c) +{ + print_debug_char(c); + print_debug_char('\r'); + print_debug_char('\n'); +} +#endif +static const struct mem_param *spd_set_memclk(void) +{ + /* Compute the minimum cycle time for these dimms */ + const struct mem_param *param; + unsigned min_cycle_time, min_latency; + unsigned device; + uint32_t value; + + static const int latency_indicies[] = { 26, 23, 9 }; + static const unsigned char min_cycle_times[] = { + [NBCAP_MEMCLK_200MHZ] = 0x50, /* 5ns */ + [NBCAP_MEMCLK_166MHZ] = 0x60, /* 6ns */ + [NBCAP_MEMCLK_133MHZ] = 0x75, /* 7.5ns */ + [NBCAP_MEMCLK_100MHZ] = 0xa0, /* 10ns */ + }; + + +#if 0 + value = pci_read_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP); +#else + value = 0x50; +#endif + min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK]; + min_latency = 2; + +#if 1 + print_debug("min_cycle_time: "); + print_debug_hex8(min_cycle_time); + print_debug(" min_latency: "); + print_debug_hex8(min_latency); + print_debug("\r\n"); +#endif + + /* Compute the least latency with the fastest clock supported + * by both the memory controller and the dimms. + */ + for(device = SMBUS_MEM_DEVICE_START; + device <= SMBUS_MEM_DEVICE_END; + device += SMBUS_MEM_DEVICE_INC) + { + int new_cycle_time, new_latency; + int index; + int latencies; + int latency; + + debug('A'); + /* First find the supported CAS latencies + * Byte 18 for DDR SDRAM is interpreted: + * bit 0 == CAS Latency = 1.0 + * bit 1 == CAS Latency = 1.5 + * bit 2 == CAS Latency = 2.0 + * bit 3 == CAS Latency = 2.5 + * bit 4 == CAS Latency = 3.0 + * bit 5 == CAS Latency = 3.5 + * bit 6 == TBD + * bit 7 == TBD + */ + new_cycle_time = 0xa0; + new_latency = 5; + + latencies = smbus_read_byte(device, 18); + if (latencies <= 0) continue; + + debug('B'); + /* Compute the lowest cas latency supported */ + latency = log2(latencies) -2; + + /* Loop through and find a fast clock with a low latency */ + for(index = 0; index < 3; index++, latency++) { + int value; + debug('C'); + if ((latency < 2) || (latency > 4) || + (!(latencies & (1 << latency)))) { + continue; + } + debug('D'); + value = smbus_read_byte(device, latency_indicies[index]); + if (value < 0) continue; + + debug('E'); + /* Only increase the latency if we decreas the clock */ + if ((value >= min_cycle_time) && (value < new_cycle_time)) { + new_cycle_time = value; + new_latency = latency; +#if 1 + print_debug("device: "); + print_debug_hex8(device); + print_debug(" new_cycle_time: "); + print_debug_hex8(new_cycle_time); + print_debug(" new_latency: "); + print_debug_hex8(new_latency); + print_debug("\r\n"); +#endif + } + debug('G'); + } + debug('H'); +#if 1 + print_debug("device: "); + print_debug_hex8(device); + print_debug(" new_cycle_time: "); + print_debug_hex8(new_cycle_time); + print_debug(" new_latency: "); + print_debug_hex8(new_latency); + print_debug("\r\n"); +#endif + if (new_latency > 4){ + continue; + } + debug('I'); + /* Does min_latency need to be increased? */ + if (new_cycle_time > min_cycle_time) { + min_cycle_time = new_cycle_time; + } + /* Does min_cycle_time need to be increased? */ + if (new_latency > min_latency) { + min_latency = new_latency; + } +#if 1 + print_debug("device: "); + print_debug_hex8(device); + print_debug(" min_cycle_time: "); + print_debug_hex8(min_cycle_time); + print_debug(" min_latency: "); + print_debug_hex8(min_latency); + print_debug("\r\n"); +#endif + } + /* Make a second pass through the dimms and disable + * any that cannot support the selected memclk and cas latency. + */ + for(device = SMBUS_MEM_DEVICE_START; + device <= SMBUS_MEM_DEVICE_END; + device += SMBUS_MEM_DEVICE_INC) + { + int latencies; + int latency; + int index; + int value; + int dimm; + latencies = smbus_read_byte(device, 18); + if (latencies <= 0) { + goto dimm_err; + } + + /* Compute the lowest cas latency supported */ + latency = log2(latencies) -2; + + /* Walk through searching for the selected latency */ + for(index = 0; index < 3; index++, latency++) { + if (!(latencies & (1 << latency))) { + continue; + } + if (latency == min_latency) + break; + } + /* If I can't find the latency or my index is bad error */ + if ((latency != min_latency) || (index >= 3)) { + goto dimm_err; + } + + /* Read the min_cycle_time for this latency */ + value = smbus_read_byte(device, latency_indicies[index]); + + /* All is good if the selected clock speed + * is what I need or slower. + */ + if (value <= min_cycle_time) { + continue; + } + /* Otherwise I have an error, disable the dimm */ + dimm_err: + disable_dimm(spd_to_dimm(device)); + } +#if 1 + print_debug("min_cycle_time: "); + print_debug_hex8(min_cycle_time); + print_debug(" min_latency: "); + print_debug_hex8(min_latency); + print_debug("\r\n"); +#endif + /* Now that I know the minimum cycle time lookup the memory parameters */ + param = get_mem_param(min_cycle_time); + +#if 0 + /* Update DRAM Config High with our selected memory speed */ + value = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_HIGH); + value &= ~(DCH_MEMCLK_MASK << DCH_MEMCLK_SHIFT); + value |= param->dch_memclk; + pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_HIGH, value); + + static const unsigned latencies[] = { 1, 5, 2 }; + /* Update DRAM Timing Low wiht our selected cas latency */ + value = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW); + value &= ~7; + value |= latencies[min_latency - 2]; + pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW, value); +#endif + + return param; +} + +static void main(void) +{ + const struct mem_param *param; + param = spd_set_memclk(); + _exit(0); +} diff --git a/util/romcc/tests/linux_test6.c b/util/romcc/tests/linux_test6.c new file mode 100644 index 0000000000..f93ab9273d --- /dev/null +++ b/util/romcc/tests/linux_test6.c @@ -0,0 +1,17 @@ +#include "linux_syscall.h" +#include "linux_console.h" + +static void main(void) +{ + static const int value[] = { 1, 0 }; + const char *str; + if (value[1]) { + print_debug("A\r\n"); + str = "Unbuffered\r\n"; + } else { + print_debug("B\r\n"); + str = "Registered\r\n"; + } + print_debug(str); + _exit(0); +} diff --git a/util/romcc/tests/linux_test7.c b/util/romcc/tests/linux_test7.c new file mode 100644 index 0000000000..409b6cbb44 --- /dev/null +++ b/util/romcc/tests/linux_test7.c @@ -0,0 +1,35 @@ +#include "linux_syscall.h" +#include "linux_console.h" + + +static void main(void) +{ + static const int cpu[] = { 0, 1, 2, 3 }; + int i; + for(i = 0; i < sizeof(cpu)/sizeof(cpu[0]); i++) { + static const unsigned int register_values[] = { + 0x0000c144, 0x0000f8f8, 0x00000000, + 0x0000c14C, 0x0000f8f8, 0x00000001, + 0x0000c154, 0x0000f8f8, 0x00000002, + 0x0000c15C, 0x0000f8f8, 0x00000003, + 0x0000c164, 0x0000f8f8, 0x00000004, + 0x0000c16C, 0x0000f8f8, 0x00000005, + 0x0000c174, 0x0000f8f8, 0x00000006, + 0x0000c17C, 0x0000f8f8, 0x00000007, + }; + int j; + int max = sizeof(register_values)/sizeof(register_values[0]); + for(j = 0; j < max; j += 3) { + print_debug("val["); + print_debug_hex8(j); + print_debug("]: "); + print_debug_hex32(register_values[j]); + print_debug_char(' '); + print_debug_hex32(register_values[j+1]); + print_debug_char(' '); + print_debug_hex32(register_values[j+2]); + print_debug_char('\n'); + } + } + _exit(0); +} diff --git a/util/romcc/tests/linuxi386_syscall.h b/util/romcc/tests/linuxi386_syscall.h new file mode 100644 index 0000000000..7eb513db36 --- /dev/null +++ b/util/romcc/tests/linuxi386_syscall.h @@ -0,0 +1,299 @@ +struct syscall_result { + long val; + int errno; +}; + +static struct syscall_result syscall_return(long result) +{ + struct syscall_result res; + if (((unsigned long)result) >= ((unsigned long)-125)) { + res.errno = - result; + res.val = -1; + } else { + res.errno = 0; + res.val = result; + } + return res; +} + +static struct syscall_result syscall0(unsigned long nr) +{ + long res; + asm volatile( + "int $0x80" + : "=a" (res) + : "a" (nr)); + return syscall_return(res); +} + +static struct syscall_result syscall1(unsigned long nr, unsigned long arg1) +{ + long res; + asm volatile( + "int $0x80" + : "=a" (res) + : "a" (nr), "b" (arg1)); + return syscall_return(res); + +} + +static struct syscall_result syscall2(unsigned long nr, unsigned long arg1, unsigned long arg2) +{ + long res; + asm volatile( + "int $0x80" + : "=a" (res) + : "a" (nr), "b" (arg1), "c" (arg2)); + return syscall_return(res); + +} + + +static struct syscall_result syscall3(unsigned long nr, unsigned long arg1, unsigned long arg2, + unsigned long arg3) +{ + long res; + asm volatile( + "int $0x80" + : "=a" (res) + : "a" (nr), "b" (arg1), "c" (arg2), "d" (arg3)); + return syscall_return(res); + +} + +static struct syscall_result syscall4(unsigned long nr, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4) +{ + long res; + asm volatile( + "int $0x80" + : "=a" (res) + : "a" (nr), "b" (arg1), "c" (arg2), "d" (arg3), "S" (arg4)); + return syscall_return(res); + +} + +static struct syscall_result syscall5(unsigned long nr, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5) +{ + long res; + asm volatile( + "int $0x80" + : "=a" (res) + : "a" (nr), "b" (arg1), "c" (arg2), "d" (arg3), + "S" (arg4), "D" (arg5)); + return syscall_return(res); + +} + +#define NR_exit 1 +#define NR_fork 2 +#define NR_read 3 +#define NR_write 4 +#define NR_open 5 +#define NR_close 6 +#define NR_waitpid 7 +#define NR_creat 8 +#define NR_link 9 +#define NR_unlink 10 +#define NR_execve 11 +#define NR_chdir 12 +#define NR_time 13 +#define NR_mknod 14 +#define NR_chmod 15 +#define NR_lchown 16 +#define NR_break 17 +#define NR_oldstat 18 +#define NR_lseek 19 +#define NR_getpid 20 +#define NR_mount 21 +#define NR_umount 22 +#define NR_setuid 23 +#define NR_getuid 24 +#define NR_stime 25 +#define NR_ptrace 26 +#define NR_alarm 27 +#define NR_oldfstat 28 +#define NR_pause 29 +#define NR_utime 30 +#define NR_stty 31 +#define NR_gtty 32 +#define NR_access 33 +#define NR_nice 34 +#define NR_ftime 35 +#define NR_sync 36 +#define NR_kill 37 +#define NR_rename 38 +#define NR_mkdir 39 +#define NR_rmdir 40 +#define NR_dup 41 +#define NR_pipe 42 +#define NR_times 43 +#define NR_prof 44 +#define NR_brk 45 +#define NR_setgid 46 +#define NR_getgid 47 +#define NR_signal 48 +#define NR_geteuid 49 +#define NR_getegid 50 +#define NR_acct 51 +#define NR_umount2 52 +#define NR_lock 53 +#define NR_ioctl 54 +#define NR_fcntl 55 +#define NR_mpx 56 +#define NR_setpgid 57 +#define NR_ulimit 58 +#define NR_oldolduname 59 +#define NR_umask 60 +#define NR_chroot 61 +#define NR_ustat 62 +#define NR_dup2 63 +#define NR_getppid 64 +#define NR_getpgrp 65 +#define NR_setsid 66 +#define NR_sigaction 67 +#define NR_sgetmask 68 +#define NR_ssetmask 69 +#define NR_setreuid 70 +#define NR_setregid 71 +#define NR_sigsuspend 72 +#define NR_sigpending 73 +#define NR_sethostname 74 +#define NR_setrlimit 75 +#define NR_getrlimit 76 +#define NR_getrusage 77 +#define NR_gettimeofday 78 +#define NR_settimeofday 79 +#define NR_getgroups 80 +#define NR_setgroups 81 +#define NR_select 82 +#define NR_symlink 83 +#define NR_oldlstat 84 +#define NR_readlink 85 +#define NR_uselib 86 +#define NR_swapon 87 +#define NR_reboot 88 +#define NR_readdir 89 +#define NR_mmap 90 +#define NR_munmap 91 +#define NR_truncate 92 +#define NR_ftruncate 93 +#define NR_fchmod 94 +#define NR_fchown 95 +#define NR_getpriority 96 +#define NR_setpriority 97 +#define NR_profil 98 +#define NR_statfs 99 +#define NR_fstatfs 100 +#define NR_ioperm 101 +#define NR_socketcall 102 +#define NR_syslog 103 +#define NR_setitimer 104 +#define NR_getitimer 105 +#define NR_stat 106 +#define NR_lstat 107 +#define NR_fstat 108 +#define NR_olduname 109 +#define NR_iopl 110 +#define NR_vhangup 111 +#define NR_idle 112 +#define NR_vm86old 113 +#define NR_wait4 114 +#define NR_swapoff 115 +#define NR_sysinfo 116 +#define NR_ipc 117 +#define NR_fsync 118 +#define NR_sigreturn 119 +#define NR_clone 120 +#define NR_setdomainname 121 +#define NR_uname 122 +#define NR_modify_ldt 123 +#define NR_adjtimex 124 +#define NR_mprotect 125 +#define NR_sigprocmask 126 +#define NR_create_module 127 +#define NR_init_module 128 +#define NR_delete_module 129 +#define NR_get_kernel_syms 130 +#define NR_quotactl 131 +#define NR_getpgid 132 +#define NR_fchdir 133 +#define NR_bdflush 134 +#define NR_sysfs 135 +#define NR_personality 136 +#define NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define NR_setfsuid 138 +#define NR_setfsgid 139 +#define NR__llseek 140 +#define NR_getdents 141 +#define NR__newselect 142 +#define NR_flock 143 +#define NR_msync 144 +#define NR_readv 145 +#define NR_writev 146 +#define NR_getsid 147 +#define NR_fdatasync 148 +#define NR__sysctl 149 +#define NR_mlock 150 +#define NR_munlock 151 +#define NR_mlockall 152 +#define NR_munlockall 153 +#define NR_sched_setparam 154 +#define NR_sched_getparam 155 +#define NR_sched_setscheduler 156 +#define NR_sched_getscheduler 157 +#define NR_sched_yield 158 +#define NR_sched_get_priority_max 159 +#define NR_sched_get_priority_min 160 +#define NR_sched_rr_get_interval 161 +#define NR_nanosleep 162 +#define NR_mremap 163 +#define NR_setresuid 164 +#define NR_getresuid 165 +#define NR_vm86 166 +#define NR_query_module 167 +#define NR_poll 168 +#define NR_nfsservctl 169 +#define NR_setresgid 170 +#define NR_getresgid 171 +#define NR_prctl 172 +#define NR_rt_sigreturn 173 +#define NR_rt_sigaction 174 +#define NR_rt_sigprocmask 175 +#define NR_rt_sigpending 176 +#define NR_rt_sigtimedwait 177 +#define NR_rt_sigqueueinfo 178 +#define NR_rt_sigsuspend 179 +#define NR_pread 180 +#define NR_pwrite 181 +#define NR_chown 182 +#define NR_getcwd 183 +#define NR_capget 184 +#define NR_capset 185 +#define NR_sigaltstack 186 +#define NR_sendfile 187 +#define NR_getpmsg 188 /* some people actually want streams */ +#define NR_putpmsg 189 /* some people actually want streams */ +#define NR_vfork 190 + +/* Standard file descriptors */ +#define STDIN_FILENO 0 /* Standard input */ +#define STDOUT_FILENO 1 /* Standard output */ +#define STDERR_FILENO 2 /* Standard error output */ + +typedef long ssize_t; +typedef unsigned long size_t; + +static ssize_t write(int fd, const void *buf, size_t count) +{ + struct syscall_result res; + res = syscall3(NR_write, fd, (unsigned long)buf, count); + return res.val; +} + +static void _exit(int status) +{ + struct syscall_result res; + res = syscall1(NR_exit, status); +} diff --git a/util/romcc/tests/raminit_test6.c b/util/romcc/tests/raminit_test6.c new file mode 100644 index 0000000000..a0c3f055be --- /dev/null +++ b/util/romcc/tests/raminit_test6.c @@ -0,0 +1,2800 @@ +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned int uint32_t; +typedef signed int int32_t; + +typedef unsigned char uint_least8_t; +typedef signed char int_least8_t; +typedef unsigned short uint_least16_t; +typedef signed short int_least16_t; +typedef unsigned int uint_least32_t; +typedef signed int int_least32_t; + +typedef unsigned char uint_fast8_t; +typedef signed char int_fast8_t; +typedef unsigned int uint_fast16_t; +typedef signed int int_fast16_t; +typedef unsigned int uint_fast32_t; +typedef signed int int_fast32_t; + +typedef int intptr_t; +typedef unsigned int uintptr_t; + +typedef long int intmax_t; +typedef unsigned long int uintmax_t; + +static inline unsigned long apic_read(unsigned long reg) +{ + return *((volatile unsigned long *)(0xfee00000 +reg)); +} +static inline void apic_write(unsigned long reg, unsigned long v) +{ + *((volatile unsigned long *)(0xfee00000 +reg)) = v; +} +static inline void apic_wait_icr_idle(void) +{ + do { } while ( apic_read( 0x300 ) & 0x01000 ); +} + +static void outb(unsigned char value, unsigned short port) +{ + __builtin_outb(value, port); +} +static void outw(unsigned short value, unsigned short port) +{ + __builtin_outw(value, port); +} +static void outl(unsigned int value, unsigned short port) +{ + __builtin_outl(value, port); +} +static unsigned char inb(unsigned short port) +{ + return __builtin_inb(port); +} +static unsigned char inw(unsigned short port) +{ + return __builtin_inw(port); +} +static unsigned char inl(unsigned short port) +{ + return __builtin_inl(port); +} +static inline void outsb(uint16_t port, const void *addr, unsigned long count) +{ + __asm__ __volatile__ ( + "cld ; rep ; outsb " + : "=S" (addr), "=c" (count) + : "d"(port), "0"(addr), "1" (count) + ); +} +static inline void outsw(uint16_t port, const void *addr, unsigned long count) +{ + __asm__ __volatile__ ( + "cld ; rep ; outsw " + : "=S" (addr), "=c" (count) + : "d"(port), "0"(addr), "1" (count) + ); +} +static inline void outsl(uint16_t port, const void *addr, unsigned long count) +{ + __asm__ __volatile__ ( + "cld ; rep ; outsl " + : "=S" (addr), "=c" (count) + : "d"(port), "0"(addr), "1" (count) + ); +} +static inline void insb(uint16_t port, void *addr, unsigned long count) +{ + __asm__ __volatile__ ( + "cld ; rep ; insb " + : "=D" (addr), "=c" (count) + : "d"(port), "0"(addr), "1" (count) + ); +} +static inline void insw(uint16_t port, void *addr, unsigned long count) +{ + __asm__ __volatile__ ( + "cld ; rep ; insw " + : "=D" (addr), "=c" (count) + : "d"(port), "0"(addr), "1" (count) + ); +} +static inline void insl(uint16_t port, void *addr, unsigned long count) +{ + __asm__ __volatile__ ( + "cld ; rep ; insl " + : "=D" (addr), "=c" (count) + : "d"(port), "0"(addr), "1" (count) + ); +} +static inline void pnp_write_config(unsigned char port, unsigned char value, unsigned char reg) +{ + outb(reg, port); + outb(value, port +1); +} +static inline unsigned char pnp_read_config(unsigned char port, unsigned char reg) +{ + outb(reg, port); + return inb(port +1); +} +static inline void pnp_set_logical_device(unsigned char port, int device) +{ + pnp_write_config(port, device, 0x07); +} +static inline void pnp_set_enable(unsigned char port, int enable) +{ + pnp_write_config(port, enable?0x1:0x0, 0x30); +} +static inline int pnp_read_enable(unsigned char port) +{ + return !!pnp_read_config(port, 0x30); +} +static inline void pnp_set_iobase0(unsigned char port, unsigned iobase) +{ + pnp_write_config(port, (iobase >> 8) & 0xff, 0x60); + pnp_write_config(port, iobase & 0xff, 0x61); +} +static inline void pnp_set_iobase1(unsigned char port, unsigned iobase) +{ + pnp_write_config(port, (iobase >> 8) & 0xff, 0x62); + pnp_write_config(port, iobase & 0xff, 0x63); +} +static inline void pnp_set_irq0(unsigned char port, unsigned irq) +{ + pnp_write_config(port, irq, 0x70); +} +static inline void pnp_set_irq1(unsigned char port, unsigned irq) +{ + pnp_write_config(port, irq, 0x72); +} +static inline void pnp_set_drq(unsigned char port, unsigned drq) +{ + pnp_write_config(port, drq & 0xff, 0x74); +} +static void hlt(void) +{ + __builtin_hlt(); +} +typedef __builtin_div_t div_t; +typedef __builtin_ldiv_t ldiv_t; +typedef __builtin_udiv_t udiv_t; +typedef __builtin_uldiv_t uldiv_t; +static div_t div(int numer, int denom) +{ + return __builtin_div(numer, denom); +} +static ldiv_t ldiv(long numer, long denom) +{ + return __builtin_ldiv(numer, denom); +} +static udiv_t udiv(unsigned numer, unsigned denom) +{ + return __builtin_udiv(numer, denom); +} +static uldiv_t uldiv(unsigned long numer, unsigned long denom) +{ + return __builtin_uldiv(numer, denom); +} +int log2(int value) +{ + + return __builtin_bsr(value); +} +typedef unsigned device_t; +static unsigned char pci_read_config8(device_t dev, unsigned where) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + return inb(0xCFC + (addr & 3)); +} +static unsigned short pci_read_config16(device_t dev, unsigned where) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + return inw(0xCFC + (addr & 2)); +} +static unsigned int pci_read_config32(device_t dev, unsigned where) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + return inl(0xCFC); +} +static void pci_write_config8(device_t dev, unsigned where, unsigned char value) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + outb(value, 0xCFC + (addr & 3)); +} +static void pci_write_config16(device_t dev, unsigned where, unsigned short value) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + outw(value, 0xCFC + (addr & 2)); +} +static void pci_write_config32(device_t dev, unsigned where, unsigned int value) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + outl(value, 0xCFC); +} +static device_t pci_locate_device(unsigned pci_id, device_t dev) +{ + for(; dev <= ( ((( 255 ) & 0xFF) << 16) | ((( 31 ) & 0x1f) << 11) | ((( 7 ) & 0x7) << 8)) ; dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) { + unsigned int id; + id = pci_read_config32(dev, 0); + if (id == pci_id) { + return dev; + } + } + return (0xffffffffU) ; +} + + + + + +static int uart_can_tx_byte(void) +{ + return inb(1016 + 0x05 ) & 0x20; +} +static void uart_wait_to_tx_byte(void) +{ + while(!uart_can_tx_byte()) + ; +} +static void uart_wait_until_sent(void) +{ + while(!(inb(1016 + 0x05 ) & 0x40)) + ; +} +static void uart_tx_byte(unsigned char data) +{ + uart_wait_to_tx_byte(); + outb(data, 1016 + 0x00 ); + + uart_wait_until_sent(); +} +static void uart_init(void) +{ + + outb(0x0, 1016 + 0x01 ); + + outb(0x01, 1016 + 0x02 ); + + outb(0x80 | 3 , 1016 + 0x03 ); + outb((115200/ 115200 ) & 0xFF, 1016 + 0x00 ); + outb(((115200/ 115200 ) >> 8) & 0xFF, 1016 + 0x01 ); + outb(3 , 1016 + 0x03 ); +} + +static void __console_tx_byte(unsigned char byte) +{ + uart_tx_byte(byte); +} +static void __console_tx_nibble(unsigned nibble) +{ + unsigned char digit; + digit = nibble + '0'; + if (digit > '9') { + digit += 39; + } + __console_tx_byte(digit); +} +static void __console_tx_char(int loglevel, unsigned char byte) +{ + if (8 > loglevel) { + uart_tx_byte(byte); + } +} +static void __console_tx_hex8(int loglevel, unsigned char value) +{ + if (8 > loglevel) { + __console_tx_nibble((value >> 4U) & 0x0fU); + __console_tx_nibble(value & 0x0fU); + } +} +static void __console_tx_hex16(int loglevel, unsigned short value) +{ + if (8 > loglevel) { + __console_tx_nibble((value >> 12U) & 0x0fU); + __console_tx_nibble((value >> 8U) & 0x0fU); + __console_tx_nibble((value >> 4U) & 0x0fU); + __console_tx_nibble(value & 0x0fU); + } +} +static void __console_tx_hex32(int loglevel, unsigned int value) +{ + if (8 > loglevel) { + __console_tx_nibble((value >> 28U) & 0x0fU); + __console_tx_nibble((value >> 24U) & 0x0fU); + __console_tx_nibble((value >> 20U) & 0x0fU); + __console_tx_nibble((value >> 16U) & 0x0fU); + __console_tx_nibble((value >> 12U) & 0x0fU); + __console_tx_nibble((value >> 8U) & 0x0fU); + __console_tx_nibble((value >> 4U) & 0x0fU); + __console_tx_nibble(value & 0x0fU); + } +} +static void __console_tx_string(int loglevel, const char *str) +{ + if (8 > loglevel) { + unsigned char ch; + while((ch = *str++) != '\0') { + __console_tx_byte(ch); + } + } +} +static void print_emerg_char(unsigned char byte) { __console_tx_char(0 , byte); } +static void print_emerg_hex8(unsigned char value){ __console_tx_hex8(0 , value); } +static void print_emerg_hex16(unsigned short value){ __console_tx_hex16(0 , value); } +static void print_emerg_hex32(unsigned int value) { __console_tx_hex32(0 , value); } +static void print_emerg(const char *str) { __console_tx_string(0 , str); } +static void print_alert_char(unsigned char byte) { __console_tx_char(1 , byte); } +static void print_alert_hex8(unsigned char value) { __console_tx_hex8(1 , value); } +static void print_alert_hex16(unsigned short value){ __console_tx_hex16(1 , value); } +static void print_alert_hex32(unsigned int value) { __console_tx_hex32(1 , value); } +static void print_alert(const char *str) { __console_tx_string(1 , str); } +static void print_crit_char(unsigned char byte) { __console_tx_char(2 , byte); } +static void print_crit_hex8(unsigned char value) { __console_tx_hex8(2 , value); } +static void print_crit_hex16(unsigned short value){ __console_tx_hex16(2 , value); } +static void print_crit_hex32(unsigned int value) { __console_tx_hex32(2 , value); } +static void print_crit(const char *str) { __console_tx_string(2 , str); } +static void print_err_char(unsigned char byte) { __console_tx_char(3 , byte); } +static void print_err_hex8(unsigned char value) { __console_tx_hex8(3 , value); } +static void print_err_hex16(unsigned short value){ __console_tx_hex16(3 , value); } +static void print_err_hex32(unsigned int value) { __console_tx_hex32(3 , value); } +static void print_err(const char *str) { __console_tx_string(3 , str); } +static void print_warning_char(unsigned char byte) { __console_tx_char(4 , byte); } +static void print_warning_hex8(unsigned char value) { __console_tx_hex8(4 , value); } +static void print_warning_hex16(unsigned short value){ __console_tx_hex16(4 , value); } +static void print_warning_hex32(unsigned int value) { __console_tx_hex32(4 , value); } +static void print_warning(const char *str) { __console_tx_string(4 , str); } +static void print_notice_char(unsigned char byte) { __console_tx_char(5 , byte); } +static void print_notice_hex8(unsigned char value) { __console_tx_hex8(5 , value); } +static void print_notice_hex16(unsigned short value){ __console_tx_hex16(5 , value); } +static void print_notice_hex32(unsigned int value) { __console_tx_hex32(5 , value); } +static void print_notice(const char *str) { __console_tx_string(5 , str); } +static void print_info_char(unsigned char byte) { __console_tx_char(6 , byte); } +static void print_info_hex8(unsigned char value) { __console_tx_hex8(6 , value); } +static void print_info_hex16(unsigned short value){ __console_tx_hex16(6 , value); } +static void print_info_hex32(unsigned int value) { __console_tx_hex32(6 , value); } +static void print_info(const char *str) { __console_tx_string(6 , str); } +static void print_debug_char(unsigned char byte) { __console_tx_char(7 , byte); } +static void print_debug_hex8(unsigned char value) { __console_tx_hex8(7 , value); } +static void print_debug_hex16(unsigned short value){ __console_tx_hex16(7 , value); } +static void print_debug_hex32(unsigned int value) { __console_tx_hex32(7 , value); } +static void print_debug(const char *str) { __console_tx_string(7 , str); } +static void print_spew_char(unsigned char byte) { __console_tx_char(8 , byte); } +static void print_spew_hex8(unsigned char value) { __console_tx_hex8(8 , value); } +static void print_spew_hex16(unsigned short value){ __console_tx_hex16(8 , value); } +static void print_spew_hex32(unsigned int value) { __console_tx_hex32(8 , value); } +static void print_spew(const char *str) { __console_tx_string(8 , str); } +static void console_init(void) +{ + static const char console_test[] = + "\r\n\r\nLinuxBIOS-" + "1.1.4" + ".0Fallback" + " " + "Thu Oct 9 20:29:48 MDT 2003" + " starting...\r\n"; + print_info(console_test); +} +static void die(const char *str) +{ + print_emerg(str); + do { + hlt(); + } while(1); +} +static void write_phys(unsigned long addr, unsigned long value) +{ + asm volatile( + "movnti %1, (%0)" + : + : "r" (addr), "r" (value) + : + ); +} +static unsigned long read_phys(unsigned long addr) +{ + volatile unsigned long *ptr; + ptr = (void *)addr; + return *ptr; +} +static void ram_fill(unsigned long start, unsigned long stop) +{ + unsigned long addr; + + print_debug("DRAM fill: "); + print_debug_hex32(start); + print_debug("-"); + print_debug_hex32(stop); + print_debug("\r\n"); + for(addr = start; addr < stop ; addr += 4) { + + if (!(addr & 0xffff)) { + print_debug_hex32(addr); + print_debug("\r"); + } + write_phys(addr, addr); + }; + + print_debug_hex32(addr); + print_debug("\r\nDRAM filled\r\n"); +} +static void ram_verify(unsigned long start, unsigned long stop) +{ + unsigned long addr; + + print_debug("DRAM verify: "); + print_debug_hex32(start); + print_debug_char('-'); + print_debug_hex32(stop); + print_debug("\r\n"); + for(addr = start; addr < stop ; addr += 4) { + unsigned long value; + + if (!(addr & 0xffff)) { + print_debug_hex32(addr); + print_debug("\r"); + } + value = read_phys(addr); + if (value != addr) { + + print_err_hex32(addr); + print_err_char(':'); + print_err_hex32(value); + print_err("\r\n"); + } + } + + print_debug_hex32(addr); + print_debug("\r\nDRAM verified\r\n"); +} +void ram_check(unsigned long start, unsigned long stop) +{ + int result; + + print_debug("Testing DRAM : "); + print_debug_hex32(start); + print_debug("-"); + print_debug_hex32(stop); + print_debug("\r\n"); + ram_fill(start, stop); + ram_verify(start, stop); + print_debug("Done.\r\n"); +} +static int enumerate_ht_chain(unsigned link) +{ + + unsigned next_unitid, last_unitid; + int reset_needed = 0; + next_unitid = 1; + do { + uint32_t id; + uint8_t hdr_type, pos; + last_unitid = next_unitid; + id = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x00 ); + + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0x0000)) { + break; + } + hdr_type = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x0e ); + pos = 0; + hdr_type &= 0x7f; + if ((hdr_type == 0 ) || + (hdr_type == 1 )) { + pos = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x34 ); + } + while(pos != 0) { + uint8_t cap; + cap = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 0 ); + if (cap == 0x08 ) { + uint16_t flags; + flags = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 2 ); + if ((flags >> 13) == 0) { + unsigned count; + flags &= ~0x1f; + flags |= next_unitid & 0x1f; + count = (flags >> 5) & 0x1f; + pci_write_config16(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 2 , flags); + next_unitid += count; + break; + } + } + pos = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 1 ); + } + } while((last_unitid != next_unitid) && (next_unitid <= 0x1f)); + return reset_needed; +} +static void enable_smbus(void) +{ + device_t dev; + dev = pci_locate_device((((( 0x746b ) & 0xFFFF) << 16) | (( 0x1022 ) & 0xFFFF)) , 0); + if (dev == (0xffffffffU) ) { + die("SMBUS controller not found\r\n"); + } + uint8_t enable; + print_debug("SMBus controller enabled\r\n"); + pci_write_config32(dev, 0x58, 0x0f00 | 1); + enable = pci_read_config8(dev, 0x41); + pci_write_config8(dev, 0x41, enable | (1 << 7)); + + outw(inw(0x0f00 + 0xe0 ), 0x0f00 + 0xe0 ); +} +static inline void smbus_delay(void) +{ + outb(0x80, 0x80); +} +static int smbus_wait_until_ready(void) +{ + unsigned long loops; + loops = (100*1000*10) ; + do { + unsigned short val; + smbus_delay(); + val = inw(0x0f00 + 0xe0 ); + if ((val & 0x800) == 0) { + break; + } + if(loops == ((100*1000*10) / 2)) { + outw(inw(0x0f00 + 0xe0 ), + 0x0f00 + 0xe0 ); + } + } while(--loops); + return loops?0:-2; +} +static int smbus_wait_until_done(void) +{ + unsigned long loops; + loops = (100*1000*10) ; + do { + unsigned short val; + smbus_delay(); + + val = inw(0x0f00 + 0xe0 ); + if (((val & 0x8) == 0) | ((val & 0x437) != 0)) { + break; + } + } while(--loops); + return loops?0:-3; +} +static int smbus_read_byte(unsigned device, unsigned address) +{ + unsigned char global_control_register; + unsigned char global_status_register; + unsigned char byte; + if (smbus_wait_until_ready() < 0) { + return -2; + } + + + + outw(inw(0x0f00 + 0xe2 ) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), 0x0f00 + 0xe2 ); + + outw(((device & 0x7f) << 1) | 1, 0x0f00 + 0xe4 ); + + outb(address & 0xFF, 0x0f00 + 0xe8 ); + + outw((inw(0x0f00 + 0xe2 ) & ~7) | (0x2), 0x0f00 + 0xe2 ); + + + outw(inw(0x0f00 + 0xe0 ), 0x0f00 + 0xe0 ); + + outw(0, 0x0f00 + 0xe6 ); + + outw((inw(0x0f00 + 0xe2 ) | (1 << 3)), 0x0f00 + 0xe2 ); + + if (smbus_wait_until_done() < 0) { + return -3; + } + global_status_register = inw(0x0f00 + 0xe0 ); + + byte = inw(0x0f00 + 0xe6 ) & 0xff; + if (global_status_register != (1 << 4)) { + return -1; + } + return byte; +} +static void smbus_write_byte(unsigned device, unsigned address, unsigned char val) +{ + return; +} +struct mem_controller { + unsigned node_id; + device_t f0, f1, f2, f3; + uint8_t channel0[4]; + uint8_t channel1[4]; +}; +typedef __builtin_msr_t msr_t; +static msr_t rdmsr(unsigned long index) +{ + return __builtin_rdmsr(index); +} +static void wrmsr(unsigned long index, msr_t msr) +{ + __builtin_wrmsr(index, msr.lo, msr.hi); +} +struct tsc_struct { + unsigned lo; + unsigned hi; +}; +typedef struct tsc_struct tsc_t; +static tsc_t rdtsc(void) +{ + tsc_t res; + asm ("rdtsc" + : "=a" (res.lo), "=d"(res.hi) + : + : + ); + return res; +} +void init_timer(void) +{ + + apic_write(0x320 , (1 << 17)|(1<< 16)|(0 << 12)|(0 << 0)); + + apic_write(0x3E0 , 0xB ); + + apic_write(0x380 , 0xffffffff); +} +void udelay(unsigned usecs) +{ + uint32_t start, value, ticks; + + ticks = usecs * 200; + start = apic_read(0x390 ); + do { + value = apic_read(0x390 ); + } while((start - value) < ticks); + +} +void mdelay(unsigned msecs) +{ + unsigned i; + for(i = 0; i < msecs; i++) { + udelay(1000); + } +} +void delay(unsigned secs) +{ + unsigned i; + for(i = 0; i < secs; i++) { + mdelay(1000); + } +} +int boot_cpu(void) +{ + volatile unsigned long *local_apic; + unsigned long apic_id; + int bsp; + msr_t msr; + msr = rdmsr(0x1b); + bsp = !!(msr.lo & (1 << 8)); + return bsp; +} +static int cpu_init_detected(void) +{ + unsigned long htic; + htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c ); + return !!(htic & (1<<6) ); +} +static int bios_reset_detected(void) +{ + unsigned long htic; + htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c ); + return (htic & (1<<4) ) && !(htic & (1<<5) ); +} +static int cold_reset_detected(void) +{ + unsigned long htic; + htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c ); + return !(htic & (1<<4) ); +} +static void distinguish_cpu_resets(unsigned node_id) +{ + uint32_t htic; + device_t device; + device = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 + node_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ; + htic = pci_read_config32(device, 0x6c ); + htic |= (1<<4) | (1<<5) | (1<<6) ; + pci_write_config32(device, 0x6c , htic); +} +static void set_bios_reset(void) +{ + unsigned long htic; + htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c ); + htic &= ~(1<<5) ; + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c , htic); +} +static void print_debug_pci_dev(unsigned dev) +{ + print_debug("PCI: "); + print_debug_hex8((dev >> 16) & 0xff); + print_debug_char(':'); + print_debug_hex8((dev >> 11) & 0x1f); + print_debug_char('.'); + print_debug_hex8((dev >> 8) & 7); +} +static void print_pci_devices(void) +{ + device_t dev; + for(dev = ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ; + dev <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 0x7 ) & 0x7) << 8)) ; + dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) { + uint32_t id; + id = pci_read_config32(dev, 0x00 ); + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0x0000)) { + continue; + } + print_debug_pci_dev(dev); + print_debug("\r\n"); + } +} +static void dump_pci_device(unsigned dev) +{ + int i; + print_debug_pci_dev(dev); + print_debug("\r\n"); + + for(i = 0; i <= 255; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = pci_read_config8(dev, i); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\r\n"); + } + } +} +static void dump_pci_devices(void) +{ + device_t dev; + for(dev = ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ; + dev <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 0x7 ) & 0x7) << 8)) ; + dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) { + uint32_t id; + id = pci_read_config32(dev, 0x00 ); + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0x0000)) { + continue; + } + dump_pci_device(dev); + } +} +static void dump_spd_registers(const struct mem_controller *ctrl) +{ + int i; + print_debug("\r\n"); + for(i = 0; i < 4; i++) { + unsigned device; + device = ctrl->channel0[i]; + if (device) { + int j; + print_debug("dimm: "); + print_debug_hex8(i); + print_debug(".0: "); + print_debug_hex8(device); + for(j = 0; j < 256; j++) { + int status; + unsigned char byte; + if ((j & 0xf) == 0) { + print_debug("\r\n"); + print_debug_hex8(j); + print_debug(": "); + } + status = smbus_read_byte(device, j); + if (status < 0) { + print_debug("bad device\r\n"); + break; + } + byte = status & 0xff; + print_debug_hex8(byte); + print_debug_char(' '); + } + print_debug("\r\n"); + } + device = ctrl->channel1[i]; + if (device) { + int j; + print_debug("dimm: "); + print_debug_hex8(i); + print_debug(".1: "); + print_debug_hex8(device); + for(j = 0; j < 256; j++) { + int status; + unsigned char byte; + if ((j & 0xf) == 0) { + print_debug("\r\n"); + print_debug_hex8(j); + print_debug(": "); + } + status = smbus_read_byte(device, j); + if (status < 0) { + print_debug("bad device\r\n"); + break; + } + byte = status & 0xff; + print_debug_hex8(byte); + print_debug_char(' '); + } + print_debug("\r\n"); + } + } +} + +static unsigned int cpuid(unsigned int op) +{ + unsigned int ret; + unsigned dummy2,dummy3,dummy4; + asm volatile ( + "cpuid" + : "=a" (ret), "=b" (dummy2), "=c" (dummy3), "=d" (dummy4) + : "a" (op) + ); + return ret; +} +static int is_cpu_rev_a0(void) +{ + return (cpuid(1) & 0xffff) == 0x0f10; +} +static int is_cpu_pre_c0(void) +{ + return (cpuid(1) & 0xffef) < 0x0f48; +} +static void memreset_setup(void) +{ + if (is_cpu_pre_c0()) { + + outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), 0x0f00 + 0xc0 + 28); + + outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), 0x0f00 + 0xc0 + 29); + } + else { + + outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), 0x0f00 + 0xc0 + 29); + } +} +static void memreset(int controllers, const struct mem_controller *ctrl) +{ + if (is_cpu_pre_c0()) { + udelay(800); + + outb((0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), 0x0f00 + 0xc0 + 28); + udelay(90); + } +} +static unsigned int generate_row(uint8_t node, uint8_t row, uint8_t maxnodes) +{ + + uint32_t ret=0x00010101; + static const unsigned int rows_2p[2][2] = { + { 0x00050101, 0x00010404 }, + { 0x00010404, 0x00050101 } + }; + if(maxnodes>2) { + print_debug("this mainboard is only designed for 2 cpus\r\n"); + maxnodes=2; + } + if (!(node>=maxnodes || row>=maxnodes)) { + ret=rows_2p[node][row]; + } + return ret; +} +static inline int spd_read_byte(unsigned device, unsigned address) +{ + return smbus_read_byte(device, address); +} + +static void coherent_ht_mainboard(unsigned cpus) +{ +} + +void cpu_ldtstop(unsigned cpus) +{ + uint32_t tmp; + device_t dev; + unsigned cnt; + for(cnt=0; cnt<cpus; cnt++) { + + pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0x81,0x23); + + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0xd4,0x00000701); + + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0xd8,0x00000000); + + tmp=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,0x90); + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,0x90, tmp | (1<<24) ); + } +} + + + + + +static void setup_resource_map(const unsigned int *register_values, int max) +{ + int i; + print_debug("setting up resource map....\r\n"); + for(i = 0; i < max; i += 3) { + device_t dev; + unsigned where; + unsigned long reg; + dev = register_values[i] & ~0xff; + where = register_values[i] & 0xff; + reg = pci_read_config32(dev, where); + reg &= register_values[i+1]; + reg |= register_values[i+2]; + pci_write_config32(dev, where, reg); + } + print_debug("done.\r\n"); +} +static void setup_default_resource_map(void) +{ + static const unsigned int register_values[] = { + + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x0000f8f8, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x0000f8f8, 0x00000001, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x54 ) & 0xFF)) , 0x0000f8f8, 0x00000002, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x0000f8f8, 0x00000003, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0x0000f8f8, 0x00000004, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0x0000f8f8, 0x00000005, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x74 ) & 0xFF)) , 0x0000f8f8, 0x00000006, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x7C ) & 0xFF)) , 0x0000f8f8, 0x00000007, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x84 ) & 0xFF)) , 0x00000048, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x8C ) & 0xFF)) , 0x00000048, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0x00000048, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x9C ) & 0xFF)) , 0x00000048, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xA4 ) & 0xFF)) , 0x00000048, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xAC ) & 0xFF)) , 0x00000048, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB4 ) & 0xFF)) , 0x00000048, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xBC ) & 0xFF)) , 0x00000048, 0x00ffff00, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x80 ) & 0xFF)) , 0x000000f0, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x88 ) & 0xFF)) , 0x000000f0, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0x000000f0, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0x000000f0, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xA0 ) & 0xFF)) , 0x000000f0, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xA8 ) & 0xFF)) , 0x000000f0, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB0 ) & 0xFF)) , 0x000000f0, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB8 ) & 0xFF)) , 0x000000f0, 0x00fc0003, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC4 ) & 0xFF)) , 0xFE000FC8, 0x01fff000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xCC ) & 0xFF)) , 0xFE000FC8, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xD4 ) & 0xFF)) , 0xFE000FC8, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xDC ) & 0xFF)) , 0xFE000FC8, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC0 ) & 0xFF)) , 0xFE000FCC, 0x00000003, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC8 ) & 0xFF)) , 0xFE000FCC, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xD0 ) & 0xFF)) , 0xFE000FCC, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xD8 ) & 0xFF)) , 0xFE000FCC, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xE0 ) & 0xFF)) , 0x0000FC88, 0xff000003, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xE4 ) & 0xFF)) , 0x0000FC88, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xE8 ) & 0xFF)) , 0x0000FC88, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xEC ) & 0xFF)) , 0x0000FC88, 0x00000000, + }; + int max; + max = sizeof(register_values)/sizeof(register_values[0]); + setup_resource_map(register_values, max); +} +static void sdram_set_registers(const struct mem_controller *ctrl) +{ + static const unsigned int register_values[] = { + + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x0000f8f8, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x0000f8f8, 0x00000001, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x54 ) & 0xFF)) , 0x0000f8f8, 0x00000002, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x0000f8f8, 0x00000003, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0x0000f8f8, 0x00000004, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0x0000f8f8, 0x00000005, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x74 ) & 0xFF)) , 0x0000f8f8, 0x00000006, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x7C ) & 0xFF)) , 0x0000f8f8, 0x00000007, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0x0000f8fc, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x001f01fe, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x001f01fe, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x001f01fe, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x001f01fe, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x001f01fe, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x54 ) & 0xFF)) , 0x001f01fe, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x001f01fe, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x001f01fe, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0xC01f01ff, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0xC01f01ff, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0xC01f01ff, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0xC01f01ff, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0xC01f01ff, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x74 ) & 0xFF)) , 0xC01f01ff, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0xC01f01ff, 0x00000000, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x7C ) & 0xFF)) , 0xC01f01ff, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x80 ) & 0xFF)) , 0xffff8888, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x88 ) & 0xFF)) , 0xe8088008, 0x02522001 , + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x8c ) & 0xFF)) , 0xff8fe08e, (0 << 20)|(0 << 8)|(0 << 4)|(0 << 0), + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0xf0000000, + (4 << 25)|(0 << 24)| + (0 << 23)|(0 << 22)|(0 << 21)|(0 << 20)| + (1 << 19)|(0 << 18)|(1 << 17)|(0 << 16)| + (2 << 14)|(0 << 13)|(0 << 12)| + (0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)| + (0 << 3) |(0 << 1) |(0 << 0), + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0xc180f0f0, + (0 << 29)|(0 << 28)|(0 << 27)|(0 << 26)|(0 << 25)| + (0 << 20)|(0 << 19)|(3 << 16)|(0 << 8)|(0 << 0), + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0xfc00ffff, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0xffe0e0e0, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x0000003e, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0xffffff00, 0x00000000, + + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0xffff8000, 0x00000f70, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0xffffff80, 0x00000002, + ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0x0000000f, 0x00068300, + }; + int i; + int max; + print_debug("setting up CPU"); + print_debug_hex8(ctrl->node_id); + print_debug(" northbridge registers\r\n"); + max = sizeof(register_values)/sizeof(register_values[0]); + for(i = 0; i < max; i += 3) { + device_t dev; + unsigned where; + unsigned long reg; + dev = (register_values[i] & ~0xff) - ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) + ctrl->f0; + where = register_values[i] & 0xff; + reg = pci_read_config32(dev, where); + reg &= register_values[i+1]; + reg |= register_values[i+2]; + pci_write_config32(dev, where, reg); + } + print_debug("done.\r\n"); +} +static int is_dual_channel(const struct mem_controller *ctrl) +{ + uint32_t dcl; + dcl = pci_read_config32(ctrl->f2, 0x90 ); + return dcl & (1<<16) ; +} +static int is_opteron(const struct mem_controller *ctrl) +{ + + uint32_t nbcap; + nbcap = pci_read_config32(ctrl->f3, 0xE8 ); + return !!(nbcap & 0x0001 ); +} +static int is_registered(const struct mem_controller *ctrl) +{ + + uint32_t dcl; + dcl = pci_read_config32(ctrl->f2, 0x90 ); + return !(dcl & (1<<18) ); +} +struct dimm_size { + unsigned long side1; + unsigned long side2; +}; +static struct dimm_size spd_get_dimm_size(unsigned device) +{ + + struct dimm_size sz; + int value, low; + sz.side1 = 0; + sz.side2 = 0; + + value = spd_read_byte(device, 3); + if (value < 0) goto out; + sz.side1 += value & 0xf; + value = spd_read_byte(device, 4); + if (value < 0) goto out; + sz.side1 += value & 0xf; + value = spd_read_byte(device, 17); + if (value < 0) goto out; + sz.side1 += log2(value & 0xff); + + value = spd_read_byte(device, 7); + if (value < 0) goto out; + value &= 0xff; + value <<= 8; + + low = spd_read_byte(device, 6); + if (low < 0) goto out; + value = value | (low & 0xff); + sz.side1 += log2(value); + + value = spd_read_byte(device, 5); + if (value <= 1) goto out; + + sz.side2 = sz.side1; + value = spd_read_byte(device, 3); + if (value < 0) goto out; + if ((value & 0xf0) == 0) goto out; + sz.side2 -= (value & 0x0f); + sz.side2 += ((value >> 4) & 0x0f); + value = spd_read_byte(device, 4); + if (value < 0) goto out; + sz.side2 -= (value & 0x0f); + sz.side2 += ((value >> 4) & 0x0f); + out: + return sz; +} +static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz, unsigned index) +{ + uint32_t base0, base1, map; + uint32_t dch; + if (sz.side1 != sz.side2) { + sz.side2 = 0; + } + map = pci_read_config32(ctrl->f2, 0x80 ); + map &= ~(0xf << (index + 4)); + + + base0 = base1 = 0; + + if (sz.side1 >= (25 +3)) { + map |= (sz.side1 - (25 + 3)) << (index *4); + base0 = (1 << ((sz.side1 - (25 + 3)) + 21)) | 1; + } + + if (sz.side2 >= (25 + 3)) { + base1 = (1 << ((sz.side2 - (25 + 3)) + 21)) | 1; + } + + if (is_dual_channel(ctrl)) { + base0 = (base0 << 1) | (base0 & 1); + base1 = (base1 << 1) | (base1 & 1); + } + + base0 &= ~0x001ffffe; + base1 &= ~0x001ffffe; + + pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+0)<<2), base0); + pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+1)<<2), base1); + pci_write_config32(ctrl->f2, 0x80 , map); + + + if (base0) { + dch = pci_read_config32(ctrl->f2, 0x94 ); + dch |= (1 << 26) << index; + pci_write_config32(ctrl->f2, 0x94 , dch); + } +} +static void spd_set_ram_size(const struct mem_controller *ctrl) +{ + int i; + + for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { + struct dimm_size sz; + sz = spd_get_dimm_size(ctrl->channel0[i]); + set_dimm_size(ctrl, sz, i); + } +} +static void route_dram_accesses(const struct mem_controller *ctrl, + unsigned long base_k, unsigned long limit_k) +{ + + unsigned node_id; + unsigned limit; + unsigned base; + unsigned index; + unsigned limit_reg, base_reg; + device_t device; + node_id = ctrl->node_id; + index = (node_id << 3); + limit = (limit_k << 2); + limit &= 0xffff0000; + limit -= 0x00010000; + limit |= ( 0 << 8) | (node_id << 0); + base = (base_k << 2); + base &= 0xffff0000; + base |= (0 << 8) | (1<<1) | (1<<0); + limit_reg = 0x44 + index; + base_reg = 0x40 + index; + for(device = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ; device <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ; device += ( ((( 0 ) & 0xFF) << 16) | ((( 1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ) { + pci_write_config32(device, limit_reg, limit); + pci_write_config32(device, base_reg, base); + } +} +static void set_top_mem(unsigned tom_k) +{ + + if (!tom_k) { + set_bios_reset(); + print_debug("No memory - reset"); + + pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0x04 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , 0x41, 0xf1); + + outb(0x0e, 0x0cf9); + } + + print_debug("RAM: 0x"); + print_debug_hex32(tom_k); + print_debug(" KB\r\n"); + + msr_t msr; + msr.lo = (tom_k & 0x003fffff) << 10; + msr.hi = (tom_k & 0xffc00000) >> 22; + wrmsr(0xC001001D , msr); + + if (tom_k >= 0x003f0000) { + tom_k = 0x3f0000; + } + msr.lo = (tom_k & 0x003fffff) << 10; + msr.hi = (tom_k & 0xffc00000) >> 22; + wrmsr(0xC001001A , msr); +} +static unsigned long interleave_chip_selects(const struct mem_controller *ctrl) +{ + + static const uint32_t csbase_low[] = { + (1 << (13 - 4)), + (1 << (14 - 4)), + (1 << (14 - 4)), + (1 << (15 - 4)), + (1 << (15 - 4)), + (1 << (16 - 4)), + (1 << (16 - 4)), + }; + uint32_t csbase_inc; + int chip_selects, index; + int bits; + int dual_channel; + unsigned common_size; + uint32_t csbase, csmask; + + chip_selects = 0; + common_size = 0; + for(index = 0; index < 8; index++) { + unsigned size; + uint32_t value; + + value = pci_read_config32(ctrl->f2, 0x40 + (index << 2)); + + + if (!(value & 1)) { + continue; + } + chip_selects++; + size = value >> 21; + if (common_size == 0) { + common_size = size; + } + + if (common_size != size) { + return 0; + } + } + + bits = log2(chip_selects); + if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) { + return 0; + + } + + if ((bits == 3) && (common_size == (1 << (32 - 3)))) { + print_debug("8 4GB chip selects cannot be interleaved\r\n"); + return 0; + } + + if (is_dual_channel(ctrl)) { + csbase_inc = csbase_low[log2(common_size) - 1] << 1; + } else { + csbase_inc = csbase_low[log2(common_size)]; + } + + csbase = 0 | 1; + csmask = (((common_size << bits) - 1) << 21); + csmask |= 0xfe00 & ~((csbase_inc << bits) - csbase_inc); + for(index = 0; index < 8; index++) { + uint32_t value; + value = pci_read_config32(ctrl->f2, 0x40 + (index << 2)); + + if (!(value & 1)) { + continue; + } + pci_write_config32(ctrl->f2, 0x40 + (index << 2), csbase); + pci_write_config32(ctrl->f2, 0x60 + (index << 2), csmask); + csbase += csbase_inc; + } + + print_debug("Interleaved\r\n"); + + return common_size << (15 + bits); +} +static unsigned long order_chip_selects(const struct mem_controller *ctrl) +{ + unsigned long tom; + + + tom = 0; + for(;;) { + + unsigned index, canidate; + uint32_t csbase, csmask; + unsigned size; + csbase = 0; + canidate = 0; + for(index = 0; index < 8; index++) { + uint32_t value; + value = pci_read_config32(ctrl->f2, 0x40 + (index << 2)); + + if (!(value & 1)) { + continue; + } + + + if (value <= csbase) { + continue; + } + + + if (tom & (1 << (index + 24))) { + continue; + } + + csbase = value; + canidate = index; + } + + if (csbase == 0) { + break; + } + + size = csbase >> 21; + + tom |= (1 << (canidate + 24)); + + csbase = (tom << 21) | 1; + + tom += size; + + csmask = ((size -1) << 21); + csmask |= 0xfe00; + + pci_write_config32(ctrl->f2, 0x40 + (canidate << 2), csbase); + + pci_write_config32(ctrl->f2, 0x60 + (canidate << 2), csmask); + + } + + return (tom & ~0xff000000) << 15; +} +static void order_dimms(const struct mem_controller *ctrl) +{ + unsigned long tom, tom_k, base_k; + unsigned node_id; + tom_k = interleave_chip_selects(ctrl); + if (!tom_k) { + tom_k = order_chip_selects(ctrl); + } + + base_k = 0; + for(node_id = 0; node_id < ctrl->node_id; node_id++) { + uint32_t limit, base; + unsigned index; + index = node_id << 3; + base = pci_read_config32(ctrl->f1, 0x40 + index); + + if ((base & 3) == 3) { + limit = pci_read_config32(ctrl->f1, 0x44 + index); + base_k = ((limit + 0x00010000) & 0xffff0000) >> 2; + } + } + tom_k += base_k; + route_dram_accesses(ctrl, base_k, tom_k); + set_top_mem(tom_k); +} +static void disable_dimm(const struct mem_controller *ctrl, unsigned index) +{ + print_debug("disabling dimm"); + print_debug_hex8(index); + print_debug("\r\n"); + pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+0)<<2), 0); + pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+1)<<2), 0); +} +static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl) +{ + int i; + int registered; + int unbuffered; + uint32_t dcl; + unbuffered = 0; + registered = 0; + for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { + int value; + value = spd_read_byte(ctrl->channel0[i], 21); + if (value < 0) { + disable_dimm(ctrl, i); + continue; + } + + if (value & (1 << 1)) { + registered = 1; + } + + else { + unbuffered = 1; + } + } + if (unbuffered && registered) { + die("Mixed buffered and registered dimms not supported"); + } + if (unbuffered && is_opteron(ctrl)) { + die("Unbuffered Dimms not supported on Opteron"); + } + dcl = pci_read_config32(ctrl->f2, 0x90 ); + dcl &= ~(1<<18) ; + if (unbuffered) { + dcl |= (1<<18) ; + } + pci_write_config32(ctrl->f2, 0x90 , dcl); +} +static void spd_enable_2channels(const struct mem_controller *ctrl) +{ + int i; + uint32_t nbcap; + + + static const unsigned addresses[] = { + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 11, + 13, + 17, + 18, + 21, + 23, + 26, + 27, + 28, + 29, + 30, + 41, + 42, + }; + nbcap = pci_read_config32(ctrl->f3, 0xE8 ); + if (!(nbcap & 0x0001 )) { + return; + } + for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { + unsigned device0, device1; + int value0, value1; + int j; + device0 = ctrl->channel0[i]; + device1 = ctrl->channel1[i]; + if (!device1) + return; + for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) { + unsigned addr; + addr = addresses[j]; + value0 = spd_read_byte(device0, addr); + if (value0 < 0) { + break; + } + value1 = spd_read_byte(device1, addr); + if (value1 < 0) { + return; + } + if (value0 != value1) { + return; + } + } + } + print_debug("Enabling dual channel memory\r\n"); + uint32_t dcl; + dcl = pci_read_config32(ctrl->f2, 0x90 ); + dcl &= ~(1<<19) ; + dcl |= (1<<16) ; + pci_write_config32(ctrl->f2, 0x90 , dcl); +} +struct mem_param { + uint8_t cycle_time; + uint8_t divisor; + uint8_t tRC; + uint8_t tRFC; + uint32_t dch_memclk; + uint16_t dch_tref4k, dch_tref8k; + uint8_t dtl_twr; + char name[9]; +}; +static const struct mem_param *get_mem_param(unsigned min_cycle_time) +{ + static const struct mem_param speed[] = { + { + .name = "100Mhz\r\n", + .cycle_time = 0xa0, + .divisor = (10 <<1), + .tRC = 0x46, + .tRFC = 0x50, + .dch_memclk = 0 << 20 , + .dch_tref4k = 0x00 , + .dch_tref8k = 0x08 , + .dtl_twr = 2, + }, + { + .name = "133Mhz\r\n", + .cycle_time = 0x75, + .divisor = (7<<1)+1, + .tRC = 0x41, + .tRFC = 0x4B, + .dch_memclk = 2 << 20 , + .dch_tref4k = 0x01 , + .dch_tref8k = 0x09 , + .dtl_twr = 2, + }, + { + .name = "166Mhz\r\n", + .cycle_time = 0x60, + .divisor = (6<<1), + .tRC = 0x3C, + .tRFC = 0x48, + .dch_memclk = 5 << 20 , + .dch_tref4k = 0x02 , + .dch_tref8k = 0x0A , + .dtl_twr = 3, + }, + { + .name = "200Mhz\r\n", + .cycle_time = 0x50, + .divisor = (5<<1), + .tRC = 0x37, + .tRFC = 0x46, + .dch_memclk = 7 << 20 , + .dch_tref4k = 0x03 , + .dch_tref8k = 0x0B , + .dtl_twr = 3, + }, + { + .cycle_time = 0x00, + }, + }; + const struct mem_param *param; + for(param = &speed[0]; param->cycle_time ; param++) { + if (min_cycle_time > (param+1)->cycle_time) { + break; + } + } + if (!param->cycle_time) { + die("min_cycle_time to low"); + } + print_debug(param->name); + return param; +} +static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) +{ + + const struct mem_param *param; + unsigned min_cycle_time, min_latency; + int i; + uint32_t value; + static const int latency_indicies[] = { 26, 23, 9 }; + static const unsigned char min_cycle_times[] = { + [0 ] = 0x50, + [1 ] = 0x60, + [2 ] = 0x75, + [3 ] = 0xa0, + }; + value = pci_read_config32(ctrl->f3, 0xE8 ); + min_cycle_time = min_cycle_times[(value >> 5 ) & 3 ]; + min_latency = 2; + + for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { + int new_cycle_time, new_latency; + int index; + int latencies; + int latency; + + new_cycle_time = 0xa0; + new_latency = 5; + latencies = spd_read_byte(ctrl->channel0[i], 18); + if (latencies <= 0) continue; + + latency = log2(latencies) -2; + + for(index = 0; index < 3; index++, latency++) { + int value; + if ((latency < 2) || (latency > 4) || + (!(latencies & (1 << latency)))) { + continue; + } + value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); + if (value < 0) { + continue; + } + + if ((value >= min_cycle_time) && (value < new_cycle_time)) { + new_cycle_time = value; + new_latency = latency; + } + } + if (new_latency > 4){ + continue; + } + + if (new_cycle_time > min_cycle_time) { + min_cycle_time = new_cycle_time; + } + + if (new_latency > min_latency) { + min_latency = new_latency; + } + } + + + for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { + int latencies; + int latency; + int index; + int value; + int dimm; + latencies = spd_read_byte(ctrl->channel0[i], 18); + if (latencies <= 0) { + goto dimm_err; + } + + latency = log2(latencies) -2; + + for(index = 0; index < 3; index++, latency++) { + if (!(latencies & (1 << latency))) { + continue; + } + if (latency == min_latency) + break; + } + + if ((latency != min_latency) || (index >= 3)) { + goto dimm_err; + } + + + value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); + + + if (value <= min_cycle_time) { + continue; + } + + dimm_err: + disable_dimm(ctrl, i); + } + + param = get_mem_param(min_cycle_time); + + value = pci_read_config32(ctrl->f2, 0x94 ); + value &= ~(0x7 << 20 ); + value |= param->dch_memclk; + pci_write_config32(ctrl->f2, 0x94 , value); + static const unsigned latencies[] = { 1 , 5 , 2 }; + + value = pci_read_config32(ctrl->f2, 0x88 ); + value &= ~(0x7 << 0 ); + value |= latencies[min_latency - 2] << 0 ; + pci_write_config32(ctrl->f2, 0x88 , value); + + return param; +} +static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_param *param, int i) +{ + unsigned clocks, old_clocks; + uint32_t dtl; + int value; + value = spd_read_byte(ctrl->channel0[i], 41); + if (value < 0) return -1; + if ((value == 0) || (value == 0xff)) { + value = param->tRC; + } + clocks = ((value << 1) + param->divisor - 1)/param->divisor; + if (clocks < 7 ) { + clocks = 7 ; + } + if (clocks > 22 ) { + return -1; + } + dtl = pci_read_config32(ctrl->f2, 0x88 ); + old_clocks = ((dtl >> 4 ) & 0xf ) + 7 ; + if (old_clocks > clocks) { + clocks = old_clocks; + } + dtl &= ~(0xf << 4 ); + dtl |= ((clocks - 7 ) << 4 ); + pci_write_config32(ctrl->f2, 0x88 , dtl); + return 0; +} +static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i) +{ + unsigned clocks, old_clocks; + uint32_t dtl; + int value; + value = spd_read_byte(ctrl->channel0[i], 42); + if (value < 0) return -1; + if ((value == 0) || (value == 0xff)) { + value = param->tRFC; + } + clocks = ((value << 1) + param->divisor - 1)/param->divisor; + if (clocks < 9 ) { + clocks = 9 ; + } + if (clocks > 24 ) { + return -1; + } + dtl = pci_read_config32(ctrl->f2, 0x88 ); + old_clocks = ((dtl >> 8 ) & 0xf ) + 9 ; + if (old_clocks > clocks) { + clocks = old_clocks; + } + dtl &= ~(0xf << 8 ); + dtl |= ((clocks - 9 ) << 8 ); + pci_write_config32(ctrl->f2, 0x88 , dtl); + return 0; +} +static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_param *param, int i) +{ + unsigned clocks, old_clocks; + uint32_t dtl; + int value; + value = spd_read_byte(ctrl->channel0[i], 29); + if (value < 0) return -1; + clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1); + if (clocks < 2 ) { + clocks = 2 ; + } + if (clocks > 6 ) { + return -1; + } + dtl = pci_read_config32(ctrl->f2, 0x88 ); + old_clocks = ((dtl >> 12 ) & 0x7 ) + 0 ; + if (old_clocks > clocks) { + clocks = old_clocks; + } + dtl &= ~(0x7 << 12 ); + dtl |= ((clocks - 0 ) << 12 ); + pci_write_config32(ctrl->f2, 0x88 , dtl); + return 0; +} +static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i) +{ + unsigned clocks, old_clocks; + uint32_t dtl; + int value; + value = spd_read_byte(ctrl->channel0[i], 28); + if (value < 0) return -1; + clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1); + if (clocks < 2 ) { + clocks = 2 ; + } + if (clocks > 4 ) { + return -1; + } + dtl = pci_read_config32(ctrl->f2, 0x88 ); + old_clocks = ((dtl >> 16 ) & 0x7 ) + 0 ; + if (old_clocks > clocks) { + clocks = old_clocks; + } + dtl &= ~(0x7 << 16 ); + dtl |= ((clocks - 0 ) << 16 ); + pci_write_config32(ctrl->f2, 0x88 , dtl); + return 0; +} +static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i) +{ + unsigned clocks, old_clocks; + uint32_t dtl; + int value; + value = spd_read_byte(ctrl->channel0[i], 30); + if (value < 0) return -1; + clocks = ((value << 1) + param->divisor - 1)/param->divisor; + if (clocks < 5 ) { + clocks = 5 ; + } + if (clocks > 15 ) { + return -1; + } + dtl = pci_read_config32(ctrl->f2, 0x88 ); + old_clocks = ((dtl >> 20 ) & 0xf ) + 0 ; + if (old_clocks > clocks) { + clocks = old_clocks; + } + dtl &= ~(0xf << 20 ); + dtl |= ((clocks - 0 ) << 20 ); + pci_write_config32(ctrl->f2, 0x88 , dtl); + return 0; +} +static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i) +{ + unsigned clocks, old_clocks; + uint32_t dtl; + int value; + value = spd_read_byte(ctrl->channel0[i], 27); + if (value < 0) return -1; + clocks = (value + ((param->divisor & 0xff) << 1) - 1)/((param->divisor & 0xff) << 1); + if (clocks < 2 ) { + clocks = 2 ; + } + if (clocks > 6 ) { + return -1; + } + dtl = pci_read_config32(ctrl->f2, 0x88 ); + old_clocks = ((dtl >> 24 ) & 0x7 ) + 0 ; + if (old_clocks > clocks) { + clocks = old_clocks; + } + dtl &= ~(0x7 << 24 ); + dtl |= ((clocks - 0 ) << 24 ); + pci_write_config32(ctrl->f2, 0x88 , dtl); + return 0; +} +static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param) +{ + uint32_t dtl; + dtl = pci_read_config32(ctrl->f2, 0x88 ); + dtl &= ~(0x1 << 28 ); + dtl |= (param->dtl_twr - 2 ) << 28 ; + pci_write_config32(ctrl->f2, 0x88 , dtl); +} +static void init_Tref(const struct mem_controller *ctrl, const struct mem_param *param) +{ + uint32_t dth; + dth = pci_read_config32(ctrl->f2, 0x8c ); + dth &= ~(0x1f << 8 ); + dth |= (param->dch_tref4k << 8 ); + pci_write_config32(ctrl->f2, 0x8c , dth); +} +static int update_dimm_Tref(const struct mem_controller *ctrl, const struct mem_param *param, int i) +{ + uint32_t dth; + int value; + unsigned tref, old_tref; + value = spd_read_byte(ctrl->channel0[i], 3); + if (value < 0) return -1; + value &= 0xf; + tref = param->dch_tref8k; + if (value == 12) { + tref = param->dch_tref4k; + } + dth = pci_read_config32(ctrl->f2, 0x8c ); + old_tref = (dth >> 8 ) & 0x1f ; + if ((value == 12) && (old_tref == param->dch_tref4k)) { + tref = param->dch_tref4k; + } else { + tref = param->dch_tref8k; + } + dth &= ~(0x1f << 8 ); + dth |= (tref << 8 ); + pci_write_config32(ctrl->f2, 0x8c , dth); + return 0; +} +static int update_dimm_x4(const struct mem_controller *ctrl, const struct mem_param *param, int i) +{ + uint32_t dcl; + int value; + int dimm; + value = spd_read_byte(ctrl->channel0[i], 13); + if (value < 0) { + return -1; + } + dimm = i; + dimm += 20 ; + dcl = pci_read_config32(ctrl->f2, 0x90 ); + dcl &= ~(1 << dimm); + if (value == 4) { + dcl |= (1 << dimm); + } + pci_write_config32(ctrl->f2, 0x90 , dcl); + return 0; +} +static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i) +{ + uint32_t dcl; + int value; + value = spd_read_byte(ctrl->channel0[i], 11); + if (value < 0) { + return -1; + } + if (value != 2) { + dcl = pci_read_config32(ctrl->f2, 0x90 ); + dcl &= ~(1<<17) ; + pci_write_config32(ctrl->f2, 0x90 , dcl); + } + return 0; +} +static int count_dimms(const struct mem_controller *ctrl) +{ + int dimms; + unsigned index; + dimms = 0; + for(index = 0; index < 8; index += 2) { + uint32_t csbase; + csbase = pci_read_config32(ctrl->f2, (0x40 + index << 2)); + if (csbase & 1) { + dimms += 1; + } + } + return dimms; +} +static void set_Twtr(const struct mem_controller *ctrl, const struct mem_param *param) +{ + uint32_t dth; + unsigned clocks; + clocks = 1; + dth = pci_read_config32(ctrl->f2, 0x8c ); + dth &= ~(0x1 << 0 ); + dth |= ((clocks - 1 ) << 0 ); + pci_write_config32(ctrl->f2, 0x8c , dth); +} +static void set_Trwt(const struct mem_controller *ctrl, const struct mem_param *param) +{ + uint32_t dth, dtl; + unsigned divisor; + unsigned latency; + unsigned clocks; + clocks = 0; + dtl = pci_read_config32(ctrl->f2, 0x88 ); + latency = (dtl >> 0 ) & 0x7 ; + divisor = param->divisor; + if (is_opteron(ctrl)) { + if (latency == 1 ) { + if (divisor == ((6 << 0) + 0)) { + + clocks = 3; + } + else if (divisor > ((6 << 0)+0)) { + + clocks = 2; + } + } + else if (latency == 5 ) { + clocks = 3; + } + else if (latency == 2 ) { + if (divisor == ((6 << 0)+0)) { + + clocks = 4; + } + else if (divisor > ((6 << 0)+0)) { + + clocks = 3; + } + } + } + else { + if (is_registered(ctrl)) { + if (latency == 1 ) { + clocks = 2; + } + else if (latency == 5 ) { + clocks = 3; + } + else if (latency == 2 ) { + clocks = 3; + } + } + else { + if (latency == 1 ) { + clocks = 3; + } + else if (latency == 5 ) { + clocks = 4; + } + else if (latency == 2 ) { + clocks = 4; + } + } + } + if ((clocks < 1 ) || (clocks > 6 )) { + die("Unknown Trwt"); + } + + dth = pci_read_config32(ctrl->f2, 0x8c ); + dth &= ~(0x7 << 4 ); + dth |= ((clocks - 1 ) << 4 ); + pci_write_config32(ctrl->f2, 0x8c , dth); + return; +} +static void set_Twcl(const struct mem_controller *ctrl, const struct mem_param *param) +{ + + uint32_t dth; + unsigned clocks; + if (is_registered(ctrl)) { + clocks = 2; + } else { + clocks = 1; + } + dth = pci_read_config32(ctrl->f2, 0x8c ); + dth &= ~(0x7 << 20 ); + dth |= ((clocks - 1 ) << 20 ); + pci_write_config32(ctrl->f2, 0x8c , dth); +} +static void set_read_preamble(const struct mem_controller *ctrl, const struct mem_param *param) +{ + uint32_t dch; + unsigned divisor; + unsigned rdpreamble; + divisor = param->divisor; + dch = pci_read_config32(ctrl->f2, 0x94 ); + dch &= ~(0xf << 8 ); + rdpreamble = 0; + if (is_registered(ctrl)) { + if (divisor == ((10 << 1)+0)) { + + rdpreamble = ((9 << 1)+ 0); + } + else if (divisor == ((7 << 1)+1)) { + + rdpreamble = ((8 << 1)+0); + } + else if (divisor == ((6 << 1)+0)) { + + rdpreamble = ((7 << 1)+1); + } + else if (divisor == ((5 << 1)+0)) { + + rdpreamble = ((7 << 1)+0); + } + } + else { + int slots; + int i; + slots = 0; + for(i = 0; i < 4; i++) { + if (ctrl->channel0[i]) { + slots += 1; + } + } + if (divisor == ((10 << 1)+0)) { + + if (slots <= 2) { + + rdpreamble = ((9 << 1)+0); + } else { + + rdpreamble = ((14 << 1)+0); + } + } + else if (divisor == ((7 << 1)+1)) { + + if (slots <= 2) { + + rdpreamble = ((7 << 1)+0); + } else { + + rdpreamble = ((11 << 1)+0); + } + } + else if (divisor == ((6 << 1)+0)) { + + if (slots <= 2) { + + rdpreamble = ((7 << 1)+0); + } else { + + rdpreamble = ((9 << 1)+0); + } + } + else if (divisor == ((5 << 1)+0)) { + + if (slots <= 2) { + + rdpreamble = ((5 << 1)+0); + } else { + + rdpreamble = ((7 << 1)+0); + } + } + } + if ((rdpreamble < ((2<<1)+0) ) || (rdpreamble > ((9<<1)+1) )) { + die("Unknown rdpreamble"); + } + dch |= (rdpreamble - ((2<<1)+0) ) << 8 ; + pci_write_config32(ctrl->f2, 0x94 , dch); +} +static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param) +{ + uint32_t dch; + int i; + unsigned async_lat; + int dimms; + dimms = count_dimms(ctrl); + dch = pci_read_config32(ctrl->f2, 0x94 ); + dch &= ~(0xf << 0 ); + async_lat = 0; + if (is_registered(ctrl)) { + if (dimms == 4) { + + async_lat = 9; + } + else { + + async_lat = 8; + } + } + else { + if (dimms > 3) { + die("Too many unbuffered dimms"); + } + else if (dimms == 3) { + + async_lat = 7; + } + else { + + async_lat = 6; + } + } + dch |= ((async_lat - 0 ) << 0 ); + pci_write_config32(ctrl->f2, 0x94 , dch); +} +static void set_idle_cycle_limit(const struct mem_controller *ctrl, const struct mem_param *param) +{ + uint32_t dch; + + dch = pci_read_config32(ctrl->f2, 0x94 ); + dch &= ~(0x7 << 16 ); + dch |= 3 << 16 ; + dch |= (1 << 19) ; + pci_write_config32(ctrl->f2, 0x94 , dch); +} +static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param) +{ + int dimms; + int i; + int rc; + + init_Tref(ctrl, param); + for(i = 0; (i < 4) && ctrl->channel0[i]; i++) { + int rc; + + if (update_dimm_Trc (ctrl, param, i) < 0) goto dimm_err; + if (update_dimm_Trfc(ctrl, param, i) < 0) goto dimm_err; + if (update_dimm_Trcd(ctrl, param, i) < 0) goto dimm_err; + if (update_dimm_Trrd(ctrl, param, i) < 0) goto dimm_err; + if (update_dimm_Tras(ctrl, param, i) < 0) goto dimm_err; + if (update_dimm_Trp (ctrl, param, i) < 0) goto dimm_err; + + if (update_dimm_Tref(ctrl, param, i) < 0) goto dimm_err; + + if (update_dimm_x4 (ctrl, param, i) < 0) goto dimm_err; + if (update_dimm_ecc(ctrl, param, i) < 0) goto dimm_err; + continue; + dimm_err: + disable_dimm(ctrl, i); + + } + + set_Twr(ctrl, param); + + set_Twtr(ctrl, param); + set_Trwt(ctrl, param); + set_Twcl(ctrl, param); + + set_read_preamble(ctrl, param); + set_max_async_latency(ctrl, param); + set_idle_cycle_limit(ctrl, param); +} +static void sdram_set_spd_registers(const struct mem_controller *ctrl) +{ + const struct mem_param *param; + spd_enable_2channels(ctrl); + spd_set_ram_size(ctrl); + spd_handle_unbuffered_dimms(ctrl); + param = spd_set_memclk(ctrl); + spd_set_dram_timing(ctrl, param); + order_dimms(ctrl); +} +static void sdram_enable(int controllers, const struct mem_controller *ctrl) +{ + int i; + + for(i = 0; i < controllers; i++) { + uint32_t dch; + dch = pci_read_config32(ctrl[i].f2, 0x94 ); + dch |= (1 << 25) ; + pci_write_config32(ctrl[i].f2, 0x94 , dch); + } + + memreset(controllers, ctrl); + for(i = 0; i < controllers; i++) { + uint32_t dcl; + + dcl = pci_read_config32(ctrl[i].f2, 0x90 ); + if (dcl & (1<<17) ) { + uint32_t mnc; + print_debug("ECC enabled\r\n"); + mnc = pci_read_config32(ctrl[i].f3, 0x44 ); + mnc |= (1 << 22) ; + if (dcl & (1<<16) ) { + mnc |= (1 << 23) ; + } + pci_write_config32(ctrl[i].f3, 0x44 , mnc); + } + dcl |= (1<<3) ; + pci_write_config32(ctrl[i].f2, 0x90 , dcl); + dcl &= ~(1<<3) ; + dcl &= ~(1<<0) ; + dcl &= ~(1<<1) ; + dcl &= ~(1<<2) ; + dcl |= (1<<8) ; + pci_write_config32(ctrl[i].f2, 0x90 , dcl); + } + for(i = 0; i < controllers; i++) { + uint32_t dcl; + print_debug("Initializing memory: "); + int loops = 0; + do { + dcl = pci_read_config32(ctrl[i].f2, 0x90 ); + loops += 1; + if ((loops & 1023) == 0) { + print_debug("."); + } + } while(((dcl & (1<<8) ) != 0) && (loops < 300000 )); + if (loops >= 300000 ) { + print_debug(" failed\r\n"); + } else { + print_debug(" done\r\n"); + } + if (dcl & (1<<17) ) { + print_debug("Clearing memory: "); + if (!is_cpu_pre_c0()) { + + dcl &= ~((1<<11) | (1<<10) ); + pci_write_config32(ctrl[i].f2, 0x90 , dcl); + do { + dcl = pci_read_config32(ctrl[i].f2, 0x90 ); + } while(((dcl & (1<<11) ) == 0) || ((dcl & (1<<10) ) == 0) ); + } + uint32_t base, last_scrub_k, scrub_k; + uint32_t cnt,zstart,zend; + msr_t msr,msr_201; + + pci_write_config32(ctrl[i].f3, 0x58 , + (0 << 16) | (0 << 8) | (0 << 0)); + + msr_201 = rdmsr(0x201); + zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8)); + zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8)); + zstart >>= 16; + zend >>=16; + print_debug("addr "); + print_debug_hex32(zstart); + print_debug("-"); + print_debug_hex32(zend); + print_debug("\r\n"); + + + msr = rdmsr(0x2ff ); + msr.lo &= ~(1<<10); + wrmsr(0x2ff , msr); + + msr = rdmsr(0xc0010015); + msr.lo |= (1<<17); + wrmsr(0xc0010015,msr); + for(;zstart<zend;zstart+=4) { + + if(zstart == 0x0fc) + continue; + + + __asm__ volatile( + "movl %%cr0, %0\n\t" + "orl $0x40000000, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + + msr.lo = 1 + ((zstart&0x0ff)<<24); + msr.hi = (zstart&0x0ff00)>>8; + wrmsr(0x200,msr); + + msr.hi = 0x000000ff; + msr.lo = 0xfc000800; + wrmsr(0x201,msr); + + __asm__ volatile( + "movl %%cr0, %0\n\t" + "andl $0x9fffffff, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + msr.lo = (zstart&0xff) << 24; + msr.hi = (zstart&0xff00) >> 8; + wrmsr(0xc0000100,msr); + print_debug_char((zstart > 0x0ff)?'+':'-'); + + + __asm__ volatile( + "1: \n\t" + "movl %0, %%fs:(%1)\n\t" + "addl $4,%1\n\t" + "subl $1,%2\n\t" + "jnz 1b\n\t" + : + : "a" (0), "D" (0), "c" (0x01000000) + ); + } + + + __asm__ volatile( + "movl %%cr0, %0\n\t" + "orl $0x40000000, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + + msr = rdmsr(0x2ff ); + msr.lo |= 0x0400; + wrmsr(0x2ff , msr); + + msr.lo = 6; + msr.hi = 0; + wrmsr(0x200,msr); + wrmsr(0x201,msr_201); + + msr.lo = 0; + msr.hi = 0; + wrmsr(0xc0000100,msr); + + __asm__ volatile( + "movl %%cr0, %0\n\t" + "andl $0x9fffffff, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (cnt) + ); + + + msr = rdmsr(0xc0010015); + msr.lo &= ~(1<<17); + wrmsr(0xc0010015,msr); + + base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3)); + base &= 0xffff0000; + + pci_write_config32(ctrl[i].f3, 0x5C , base << 8); + pci_write_config32(ctrl[i].f3, 0x60 , base >> 24); + + pci_write_config32(ctrl[i].f3, 0x58 , + (22 << 16) | (22 << 8) | (22 << 0)); + print_debug("done\r\n"); + } + } +} + + + + + +typedef uint8_t u8; +typedef uint32_t u32; +typedef int8_t bool; +static void disable_probes(void) +{ + + + u32 val; + print_debug("Disabling read/write/fill probes for UP... "); + val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68); + val |= (1<<10)|(1<<9)|(1<<8)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1 << 0); + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68, val); + print_debug("done.\r\n"); +} + +static void wait_ap_stop(u8 node) +{ + unsigned long reg; + unsigned long i; + for(i=0;i< 1000 ;i++) { + unsigned long regx; + regx = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x6c); + if((regx & (1<<4))==1) break; + } + reg = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x6c); + reg &= ~(1<<4); + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c, reg); +} +static void notify_bsp_ap_is_stopped(void) +{ + unsigned long reg; + unsigned long apic_id; + apic_id = *((volatile unsigned long *)(0xfee00000 + 0x020 )); + apic_id >>= 24; + + if(apic_id != 0) { + + reg = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ apic_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6C); + reg |= 1<<4; + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ apic_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6C, reg); + } + +} + +static void enable_routing(u8 node) +{ + u32 val; + + + print_debug("Enabling routing table for node "); + print_debug_hex32(node); + val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c); + val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)); + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c, val); + + if(node!=0) { + wait_ap_stop(node); + } + + print_debug(" done.\r\n"); +} +static void rename_temp_node(u8 node) +{ + uint32_t val; + print_debug("Renaming current temp node to "); + print_debug_hex32(node); + val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60); + val &= (~7); + val |= node; + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60, val); + print_debug(" done.\r\n"); +} +static bool check_connection(u8 src, u8 dest, u8 link) +{ + + u32 val; + + + val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ src ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x98+link); + if ( (val&0x17) != 0x03) + return 0; + + val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ dest ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0); + if(val != 0x11001022) + return 0; + return 1; +} +static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2) +{ + static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 }; + static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 }; + uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask; + uint8_t width_cap1, width_cap2, width_cap, width, ln_width1, ln_width2; + uint8_t freq; + + + freq_cap1 = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 0x0a ); + freq_cap2 = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 0x0a ); + + + freq = log2(freq_cap1 & freq_cap2 & 0xff); + + pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 0x09 , freq); + pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 0x09 , freq); + + width_cap1 = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 6 ); + width_cap2 = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 6 ); + + ln_width1 = link_width_to_pow2[width_cap1 & 7]; + ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7]; + if (ln_width1 > ln_width2) { + ln_width1 = ln_width2; + } + width = pow2_to_link_width[ln_width1]; + + ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7]; + ln_width2 = link_width_to_pow2[width_cap2 & 7]; + if (ln_width1 > ln_width2) { + ln_width1 = ln_width2; + } + width |= pow2_to_link_width[ln_width1] << 4; + + + pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 6 + 1, width); + + width = ((width & 0x70) >> 4) | ((width & 0x7) << 4); + pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 6 + 1, width); +} +static void fill_row(u8 node, u8 row, u32 value) +{ + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x40+(row<<2), value); +} +static void setup_row(u8 source, u8 dest, u8 cpus) +{ + fill_row(source,dest,generate_row(source,dest,cpus)); +} +static void setup_temp_row(u8 source, u8 dest, u8 cpus) +{ + fill_row(source,7,((generate_row( source,dest,cpus )&(~0x0f0000))|0x010000) ); +} +static void setup_node(u8 node, u8 cpus) +{ + u8 row; + for(row=0; row<cpus; row++) + setup_row(node, row, cpus); +} +static void setup_remote_row(u8 source, u8 dest, u8 cpus) +{ + fill_row(7, dest, generate_row(source, dest, cpus)); +} +static void setup_remote_node(u8 node, u8 cpus) +{ + static const uint8_t pci_reg[] = { + 0x44, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x7c, + 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, + 0x84, 0x8c, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbc, + 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, + 0xc4, 0xcc, 0xd4, 0xdc, + 0xc0, 0xc8, 0xd0, 0xd8, + 0xe0, 0xe4, 0xe8, 0xec, + }; + uint8_t row; + int i; + print_debug("setup_remote_node\r\n"); + for(row=0; row<cpus; row++) + setup_remote_row(node, row, cpus); + + for(i = 0; i < sizeof(pci_reg)/sizeof(pci_reg[0]); i++) { + uint32_t value; + uint8_t reg; + reg = pci_reg[i]; + value = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , reg); + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , reg, value); + } + print_debug("setup_remote_done\r\n"); +} +static u8 setup_uniprocessor(void) +{ + print_debug("Enabling UP settings\r\n"); + disable_probes(); + return 1; +} +static u8 setup_smp(void) +{ + u8 cpus=2; + print_debug("Enabling SMP settings\r\n"); + setup_row(0,0,cpus); + + setup_temp_row(0,1,cpus); + + if (!check_connection(0, 7, 0x20 )) { + print_debug("No connection to Node 1.\r\n"); + fill_row( 0 ,7,0x00010101 ) ; + setup_uniprocessor(); + return 1; + } + + optimize_connection(0, 0x20 , 7, 0x20 ); + setup_node(0, cpus); + setup_remote_node(1, cpus); + rename_temp_node(1); + enable_routing(1); + + fill_row( 0 ,7,0x00010101 ) ; + + print_debug_hex32(cpus); + print_debug(" nodes initialized.\r\n"); + return cpus; +} +static unsigned detect_mp_capabilities(unsigned cpus) +{ + unsigned node, row, mask; + bool mp_cap= (-1) ; + print_debug("detect_mp_capabilities: "); + print_debug_hex32(cpus); + print_debug("\r\n"); + if (cpus>2) + mask=0x06; + else + mask=0x02; + for (node=0; node<cpus; node++) { + if ((pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , 0xe8) & mask)!=mask) + mp_cap= (0) ; + } + if (mp_cap) + return cpus; + + print_debug("One of the CPUs is not MP capable. Going back to UP\r\n"); + for (node=cpus; node>0; node--) + for (row=cpus; row>0; row--) + fill_row(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node-1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , row-1, 0x00010101 ); + + return setup_uniprocessor(); +} +static void coherent_ht_finalize(unsigned cpus) +{ + int node; + bool rev_a0; + + + print_debug("coherent_ht_finalize\r\n"); + rev_a0= is_cpu_rev_a0(); + for (node=0; node<cpus; node++) { + u32 val; + val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60); + val &= (~0x000F0070); + val |= ((cpus-1)<<16)|((cpus-1)<<4); + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x60,val); + val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68); + val |= 0x00008000; + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x68,val); + if (rev_a0) { + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x94,0); + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0xb4,0); + pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0xd4,0); + } + } + print_debug("done\r\n"); +} +static int setup_coherent_ht_domain(void) +{ + unsigned cpus; + int reset_needed = 0; + enable_routing(0) ; + cpus=setup_smp(); + cpus=detect_mp_capabilities(cpus); + coherent_ht_finalize(cpus); + + coherent_ht_mainboard(cpus); + return reset_needed; +} +void sdram_no_memory(void) +{ + print_err("No memory!!\r\n"); + while(1) { + hlt(); + } +} + +void sdram_initialize(int controllers, const struct mem_controller *ctrl) +{ + int i; + + for(i = 0; i < controllers; i++) { + print_debug("Ram1."); + print_debug_hex8(i); + print_debug("\r\n"); + sdram_set_registers(ctrl + i); + } + + for(i = 0; i < controllers; i++) { + print_debug("Ram2."); + print_debug_hex8(i); + print_debug("\r\n"); + sdram_set_spd_registers(ctrl + i); + } + + print_debug("Ram3\r\n"); + sdram_enable(controllers, ctrl); + print_debug("Ram4\r\n"); +} +static void enable_lapic(void) +{ + msr_t msr; + msr = rdmsr(0x1b); + msr.hi &= 0xffffff00; + msr.lo &= 0x000007ff; + msr.lo |= 0xfee00000 | (1 << 11); + wrmsr(0x1b, msr); +} +static void stop_this_cpu(void) +{ + unsigned apicid; + apicid = apic_read(0x020 ) >> 24; + + apic_write(0x310 , (( apicid )<<24) ); + apic_write(0x300 , 0x08000 | 0x04000 | 0x00500 ); + + apic_wait_icr_idle(); + + apic_write(0x310 , (( apicid )<<24) ); + apic_write(0x300 , 0x08000 | 0x00500 ); + + apic_wait_icr_idle(); + + for(;;) { + hlt(); + } +} +static void pc87360_enable_serial(void) +{ + pnp_set_logical_device(0x2e , 0x03 ); + pnp_set_enable(0x2e , 1); + pnp_set_iobase0(0x2e , 0x3f8); +} +static void main(void) +{ + + static const struct mem_controller cpu[] = { + { + .node_id = 0, + .f0 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , + .f1 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , + .f2 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) , + .f3 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , + .channel0 = { (0xa<<3)|0, (0xa<<3)|2, 0, 0 }, + .channel1 = { (0xa<<3)|1, (0xa<<3)|3, 0, 0 }, + }, + { + .node_id = 1, + .f0 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , + .f1 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , + .f2 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) , + .f3 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , + .channel0 = { (0xa<<3)|4, (0xa<<3)|6, 0, 0 }, + .channel1 = { (0xa<<3)|5, (0xa<<3)|7, 0, 0 }, + }, + }; + if (cpu_init_detected()) { + asm("jmp __cpu_reset"); + } + enable_lapic(); + init_timer(); + if (!boot_cpu()) { + stop_this_cpu(); + } + pc87360_enable_serial(); + uart_init(); + console_init(); + setup_default_resource_map(); + setup_coherent_ht_domain(); + enumerate_ht_chain(0); + distinguish_cpu_resets(0); + + enable_smbus(); + memreset_setup(); + sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu); + +} diff --git a/util/romcc/tests/simple_test57.c b/util/romcc/tests/simple_test57.c new file mode 100644 index 0000000000..47e2397f17 --- /dev/null +++ b/util/romcc/tests/simple_test57.c @@ -0,0 +1,5 @@ +static void main(void) +{ + for(;;) { + } +} diff --git a/util/romcc/tests/simple_test58.c b/util/romcc/tests/simple_test58.c new file mode 100644 index 0000000000..a5cd52171c --- /dev/null +++ b/util/romcc/tests/simple_test58.c @@ -0,0 +1,9 @@ +static void main(void) +{ + const char *str; + unsigned char ch; + str = "one\r\n"; + while((ch = *str++) != '\0') { + __builtin_outb(ch, 0x3f0); + } +} diff --git a/util/romcc/tests/simple_test60.c b/util/romcc/tests/simple_test60.c index 55a5f19389..d277c94dd3 100644 --- a/util/romcc/tests/simple_test60.c +++ b/util/romcc/tests/simple_test60.c @@ -3,7 +3,7 @@ struct mem_param { unsigned char divisor; unsigned char tRC; unsigned char tRFC; - unsigned dch_memclk; + unsigned dch_memclk; unsigned short dch_tref4k, dch_tref8k; unsigned char dtl_twr; char name[9]; diff --git a/util/romcc/tests/simple_test61.c b/util/romcc/tests/simple_test61.c new file mode 100644 index 0000000000..583a9db36b --- /dev/null +++ b/util/romcc/tests/simple_test61.c @@ -0,0 +1,26 @@ +static void spd_set_nbxcfg(void) +{ + /* + * Effects: Uses serial presence detect to set the + * ECC support flags in the NBXCFG register + * FIXME: Check for illegal/unsupported ram configurations and abort + */ + unsigned device; + + for(device = 0x50; device <= 0x53; device += 1) { + int byte; + + byte = 0; /* Disable ECC */ + /* 0 == None, 1 == Parity, 2 == ECC */ + if (byte != 2) continue; + + /* set the device I'm talking too */ + __builtin_outb(device, 0x1004); + + /* poll for transaction completion */ + byte = __builtin_inb(0x10); + while(byte == 0) { + byte = __builtin_inb(0x10); + } + } +} diff --git a/util/romcc/tests/simple_test62.c b/util/romcc/tests/simple_test62.c new file mode 100644 index 0000000000..8fed660c5a --- /dev/null +++ b/util/romcc/tests/simple_test62.c @@ -0,0 +1,7 @@ +static const int foo = 1; + +static void main(void) +{ + int x; + x = foo; +} diff --git a/util/romcc/tests/simple_test63.c b/util/romcc/tests/simple_test63.c new file mode 100644 index 0000000000..b7df0808a7 --- /dev/null +++ b/util/romcc/tests/simple_test63.c @@ -0,0 +1,8 @@ +static const int foo[] = { 1, 2 }; + +static void main(void) +{ + int x, y; + x = foo[0]; + y = foo[1]; +} diff --git a/util/romcc/tests/simple_test64.c b/util/romcc/tests/simple_test64.c new file mode 100644 index 0000000000..389b1c1e32 --- /dev/null +++ b/util/romcc/tests/simple_test64.c @@ -0,0 +1,12 @@ +static void main(void) +{ + static const int foo = 2; + switch(foo) { + case 1: + break; + case 2: + break; + default: + break; + } +} diff --git a/util/romcc/tests/simple_test65.c b/util/romcc/tests/simple_test65.c new file mode 100644 index 0000000000..642882c2a2 --- /dev/null +++ b/util/romcc/tests/simple_test65.c @@ -0,0 +1,10 @@ +enum tag { + X=1, + Y=2, +}; +static void main(void) +{ + enum tag foo; + foo = Y; + +} diff --git a/util/romcc/tests/simple_test66.c b/util/romcc/tests/simple_test66.c new file mode 100644 index 0000000000..5857855700 --- /dev/null +++ b/util/romcc/tests/simple_test66.c @@ -0,0 +1,25 @@ +typedef unsigned char uint8_t; +static unsigned int generate_row(uint8_t row, uint8_t maxnodes) +{ + + unsigned int ret=0x00010101; + static const unsigned int rows_2p[2][2] = { + { 0x00050101, 0x00010404 }, + { 0x00010404, 0x00050101 } + }; + if(maxnodes>2) { + maxnodes=2; + } + if (row < maxnodes) { + ret=rows_2p[0][row]; + } + return ret; +} + +static void setup_node(void) +{ + unsigned char row; + for(row=0; row< 2; row++) { + __builtin_outl(generate_row(row, 2), 0x1234); + } +} diff --git a/util/romcc/tests/simple_test67.c b/util/romcc/tests/simple_test67.c new file mode 100644 index 0000000000..3bfdc5a072 --- /dev/null +++ b/util/romcc/tests/simple_test67.c @@ -0,0 +1,24 @@ +static void main(void) +{ + unsigned int dch, dcl; +/* HERE I AM async_lat */ + unsigned async_lat; + int dimms; + dimms = 1; + async_lat = 0; + dch = 0x1234; + dcl = __builtin_inl(0x5678); + if (!(dcl & (1 << 8))) { + if (dimms == 4) { + async_lat = 9; + } + else { + async_lat = 8; + } + } + else { + async_lat = 6; + } + dch |= async_lat; + __builtin_outl(dch, 0x9abc); +} diff --git a/util/romcc/tests/simple_test68.c b/util/romcc/tests/simple_test68.c new file mode 100644 index 0000000000..dd29658fdc --- /dev/null +++ b/util/romcc/tests/simple_test68.c @@ -0,0 +1,21 @@ +static void main(void) +{ + static const int cpu[] = { 0, 1, 2, 3 }; + int i; + for(i = 0; i < sizeof(cpu)/sizeof(cpu[0]); i++) { + static const unsigned int register_values[] = { + 0x0000c144, 0x0000f8f8, 0x00000000, + 0x0000c14C, 0x0000f8f8, 0x00000001, + 0x0000c154, 0x0000f8f8, 0x00000002, + 0x0000c15C, 0x0000f8f8, 0x00000003, + 0x0000c164, 0x0000f8f8, 0x00000004, + 0x0000c16C, 0x0000f8f8, 0x00000005, + 0x0000c174, 0x0000f8f8, 0x00000006, + 0x0000c17C, 0x0000f8f8, 0x00000007, + }; + int j; + int max = sizeof(register_values)/sizeof(register_values[0]); + for(j = 0; j < max; j += 3) { + } + } +} |