Example #1
0
void __init
ia64_init_itm (void)
{
	unsigned long platform_base_freq, itc_freq, drift;
	struct pal_freq_ratio itc_ratio, proc_ratio;
	long status;

	/*
	 * According to SAL v2.6, we need to use a SAL call to determine the platform base
	 * frequency and then a PAL call to determine the frequency ratio between the ITC
	 * and the base frequency.
	 */
	status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, &platform_base_freq, &drift);
	if (status != 0) {
		printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status));
	} else {
		status = ia64_pal_freq_ratios(&proc_ratio, 0, &itc_ratio);
		if (status != 0)
			printk(KERN_ERR "PAL_FREQ_RATIOS failed with status=%ld\n", status);
	}
	if (status != 0) {
		/* invent "random" values */
		printk(KERN_ERR
		       "SAL/PAL failed to obtain frequency info---inventing reasonably values\n");
		platform_base_freq = 100000000;
		itc_ratio.num = 3;
		itc_ratio.den = 1;
	}
	if (platform_base_freq < 40000000) {
		printk(KERN_ERR "Platform base frequency %lu bogus---resetting to 75MHz!\n",
		       platform_base_freq);
		platform_base_freq = 75000000;
	}
	if (!proc_ratio.den)
		proc_ratio.den = 1;	/* avoid division by zero */
	if (!itc_ratio.den)
		itc_ratio.den = 1;	/* avoid division by zero */

	itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;
	local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ;
	printk(KERN_INFO "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, "
	       "ITC freq=%lu.%03luMHz\n", smp_processor_id(),
	       platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
	       itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);

	local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
	local_cpu_data->itc_freq = itc_freq;
	local_cpu_data->cyc_per_usec = (itc_freq + 500000) / 1000000;
	local_cpu_data->usec_per_cyc = ((1000000UL<<IA64_USEC_PER_CYC_SHIFT)
					+ itc_freq/2)/itc_freq;

	/* Setup the CPU local timer tick */
	ia64_cpu_local_tick();
}
Example #2
0
/*
 * On the SGI SN2, the ITC isn't stable. Emulation backed by the SN2
 * RTC is used instead. This function patches the ratios from SAL
 * to match the RTC before providing them to the guest.
 */
static void sn2_patch_itc_freq_ratios(struct ia64_pal_retval *result)
{
	struct pal_freq_ratio *ratio;
	unsigned long sal_freq, sal_drift, factor;

	result->status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
					    &sal_freq, &sal_drift);
	ratio = (struct pal_freq_ratio *)&result->v2;
	factor = ((sal_freq * 3) + (sn_rtc_cycles_per_second / 2)) /
		sn_rtc_cycles_per_second;

	ratio->num = 3;
	ratio->den = factor;
}
Example #3
0
static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu)
{

	struct ia64_pal_retval result;

	PAL_CALL(result, PAL_FREQ_BASE, 0, 0, 0);

	/*
	 * PAL_FREQ_BASE may not be implemented in some platforms,
	 * call SAL instead.
	 */
	if (result.v0 == 0) {
		result.status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
							&result.v0,
							&result.v1);
		result.v2 = 0;
	}

	return result;
}
Example #4
0
void __devinit
ia64_init_itm (void)
{
    unsigned long platform_base_freq, itc_freq;
    struct pal_freq_ratio itc_ratio, proc_ratio;
    long status, platform_base_drift, itc_drift;

    /*
     * According to SAL v2.6, we need to use a SAL call to determine the platform base
     * frequency and then a PAL call to determine the frequency ratio between the ITC
     * and the base frequency.
     */
    status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
                                &platform_base_freq, &platform_base_drift);
    if (status != 0) {
        printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status));
    } else {
        status = ia64_pal_freq_ratios(&proc_ratio, NULL, &itc_ratio);
        if (status != 0)
            printk(KERN_ERR "PAL_FREQ_RATIOS failed with status=%ld\n", status);
    }
    if (status != 0) {
        /* invent "random" values */
        printk(KERN_ERR
               "SAL/PAL failed to obtain frequency info---inventing reasonable values\n");
        platform_base_freq = 100000000;
        platform_base_drift = -1;	/* no drift info */
        itc_ratio.num = 3;
        itc_ratio.den = 1;
    }
    if (platform_base_freq < 40000000) {
        printk(KERN_ERR "Platform base frequency %lu bogus---resetting to 75MHz!\n",
               platform_base_freq);
        platform_base_freq = 75000000;
        platform_base_drift = -1;
    }
    if (!proc_ratio.den)
        proc_ratio.den = 1;	/* avoid division by zero */
    if (!itc_ratio.den)
        itc_ratio.den = 1;	/* avoid division by zero */

    itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;

    local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ;
    printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%u/%u, "
           "ITC freq=%lu.%03luMHz", smp_processor_id(),
           platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
           itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);

    if (platform_base_drift != -1) {
        itc_drift = platform_base_drift*itc_ratio.num/itc_ratio.den;
        printk("+/-%ldppm\n", itc_drift);
    } else {
        itc_drift = -1;
        printk("\n");
    }

    local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
    local_cpu_data->itc_freq = itc_freq;
    local_cpu_data->cyc_per_usec = (itc_freq + USEC_PER_SEC/2) / USEC_PER_SEC;
    local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<<IA64_NSEC_PER_CYC_SHIFT)
                                    + itc_freq/2)/itc_freq;

    if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
#ifdef CONFIG_SMP
        /* On IA64 in an SMP configuration ITCs are never accurately synchronized.
         * Jitter compensation requires a cmpxchg which may limit
         * the scalability of the syscalls for retrieving time.
         * The ITC synchronization is usually successful to within a few
         * ITC ticks but this is not a sure thing. If you need to improve
         * timer performance in SMP situations then boot the kernel with the
         * "nojitter" option. However, doing so may result in time fluctuating (maybe
         * even going backward) if the ITC offsets between the individual CPUs
         * are too large.
         */
        if (!nojitter)
            itc_jitter_data.itc_jitter = 1;
#endif
    } else
        /*
         * ITC is drifty and we have not synchronized the ITCs in smpboot.c.
         * ITC values may fluctuate significantly between processors.
         * Clock should not be used for hrtimers. Mark itc as only
         * useful for boot and testing.
         *
         * Note that jitter compensation is off! There is no point of
         * synchronizing ITCs since they may be large differentials
         * that change over time.
         *
         * The only way to fix this would be to repeatedly sync the
         * ITCs. Until that time we have to avoid ITC.
         */
        clocksource_itc.rating = 50;

    paravirt_init_missing_ticks_accounting(smp_processor_id());

    /* avoid softlock up message when cpu is unplug and plugged again. */
    touch_softlockup_watchdog();

    /* Setup the CPU local timer tick */
    ia64_cpu_local_tick();

    if (!itc_clocksource) {
        /* Sort out mult/shift values: */
        clocksource_itc.mult =
            clocksource_hz2mult(local_cpu_data->itc_freq,
                                clocksource_itc.shift);
        clocksource_register(&clocksource_itc);
        itc_clocksource = &clocksource_itc;
    }
}
Example #5
0
/**
 * sn_setup - SN platform setup routine
 * @cmdline_p: kernel command line
 *
 * Handles platform setup for SN machines.  This includes determining
 * the RTC frequency (via a SAL call), initializing secondary CPUs, and
 * setting up per-node data areas.  The console is also initialized here.
 */
void __init sn_setup(char **cmdline_p)
{
	long status, ticks_per_sec, drift;
	u32 version = sn_sal_rev();
	extern void sn_cpu_init(void);

	sn2_rtc_initial = rtc_time();
	ia64_sn_plat_set_error_handling_features();	// obsolete
	ia64_sn_set_os_feature(OSF_MCA_SLV_TO_OS_INIT_SLV);
	ia64_sn_set_os_feature(OSF_FEAT_LOG_SBES);


#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
	/*
	 * Handle SN vga console.
	 *
	 * SN systems do not have enough ACPI table information
	 * being passed from prom to identify VGA adapters and the legacy
	 * addresses to access them.  Until that is done, SN systems rely
	 * on the PCDP table to identify the primary VGA console if one
	 * exists.
	 *
	 * However, kernel PCDP support is optional, and even if it is built
	 * into the kernel, it will not be used if the boot cmdline contains
	 * console= directives.
	 *
	 * So, to work around this mess, we duplicate some of the PCDP code
	 * here so that the primary VGA console (as defined by PCDP) will
	 * work on SN systems even if a different console (e.g. serial) is
	 * selected on the boot line (or CONFIG_EFI_PCDP is off).
	 */

	if (! vga_console_membase)
		sn_scan_pcdp();

	if (vga_console_membase) {
		/* usable vga ... make tty0 the preferred default console */
		if (!strstr(*cmdline_p, "console="))
			add_preferred_console("tty", 0, NULL);
	} else {
		printk(KERN_DEBUG "SGI: Disabling VGA console\n");
		if (!strstr(*cmdline_p, "console="))
			add_preferred_console("ttySG", 0, NULL);
#ifdef CONFIG_DUMMY_CONSOLE
		conswitchp = &dummy_con;
#else
		conswitchp = NULL;
#endif				/* CONFIG_DUMMY_CONSOLE */
	}
#endif				/* def(CONFIG_VT) && def(CONFIG_VGA_CONSOLE) */

	MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY;

	/*
	 * Build the tables for managing cnodes.
	 */
	build_cnode_tables();

	status =
	    ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec,
			       &drift);
	if (status != 0 || ticks_per_sec < 100000) {
		printk(KERN_WARNING
		       "unable to determine platform RTC clock frequency, guessing.\n");
		/* PROM gives wrong value for clock freq. so guess */
		sn_rtc_cycles_per_second = 1000000000000UL / 30000UL;
	} else
		sn_rtc_cycles_per_second = ticks_per_sec;

	platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_CPE_VECTOR;

	ia64_printk_clock = ia64_sn2_printk_clock;

	/*
	 * Old PROMs do not provide an ACPI FADT. Disable legacy keyboard
	 * support here so we don't have to listen to failed keyboard probe
	 * messages.
	 */
	if (is_shub1() && version <= 0x0209 && acpi_kbd_controller_present) {
		printk(KERN_INFO "Disabling legacy keyboard support as prom "
		       "is too old and doesn't provide FADT\n");
		acpi_kbd_controller_present = 0;
	}

	printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF);

	/*
	 * we set the default root device to /dev/hda
	 * to make simulation easy
	 */
	ROOT_DEV = Root_HDA1;

	/*
	 * Create the PDAs and NODEPDAs for all the cpus.
	 */
	sn_init_pdas(cmdline_p);

	ia64_mark_idle = &snidle;

	/*
	 * For the bootcpu, we do this here. All other cpus will make the
	 * call as part of cpu_init in slave cpu initialization.
	 */
	sn_cpu_init();

#ifdef CONFIG_SMP
	init_smp_config();
#endif
	screen_info = sn_screen_info;

	sn_timer_init();

	/*
	 * set pm_power_off to a SAL call to allow
	 * sn machines to power off. The SAL call can be replaced
	 * by an ACPI interface call when ACPI is fully implemented
	 * for sn.
	 */
	pm_power_off = ia64_sn_power_down;
	current->thread.flags |= IA64_THREAD_MIGRATION;
}
Example #6
0
/**
 * sn_setup - SN platform setup routine
 * @cmdline_p: kernel command line
 *
 * Handles platform setup for SN machines.  This includes determining
 * the RTC frequency (via a SAL call), initializing secondary CPUs, and
 * setting up per-node data areas.  The console is also initialized here.
 */
void __init sn_setup(char **cmdline_p)
{
	long status, ticks_per_sec, drift;
	int pxm;
	int major = sn_sal_rev_major(), minor = sn_sal_rev_minor();
	extern void sn_cpu_init(void);

	/*
	 * If the generic code has enabled vga console support - lets
	 * get rid of it again. This is a kludge for the fact that ACPI
	 * currtently has no way of informing us if legacy VGA is available
	 * or not.
	 */
#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
	if (conswitchp == &vga_con) {
		printk(KERN_DEBUG "SGI: Disabling VGA console\n");
#ifdef CONFIG_DUMMY_CONSOLE
		conswitchp = &dummy_con;
#else
		conswitchp = NULL;
#endif				/* CONFIG_DUMMY_CONSOLE */
	}
#endif				/* def(CONFIG_VT) && def(CONFIG_VGA_CONSOLE) */

	MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY;

	memset(physical_node_map, -1, sizeof(physical_node_map));
	for (pxm = 0; pxm < MAX_PXM_DOMAINS; pxm++)
		if (pxm_to_nid_map[pxm] != -1)
			physical_node_map[pxm_to_nasid(pxm)] =
			    pxm_to_nid_map[pxm];

	/*
	 * Old PROMs do not provide an ACPI FADT. Disable legacy keyboard
	 * support here so we don't have to listen to failed keyboard probe
	 * messages.
	 */
	if ((major < 2 || (major == 2 && minor <= 9)) &&
	    acpi_kbd_controller_present) {
		printk(KERN_INFO "Disabling legacy keyboard support as prom "
		       "is too old and doesn't provide FADT\n");
		acpi_kbd_controller_present = 0;
	}

	printk("SGI SAL version %x.%02x\n", major, minor);

	/*
	 * Confirm the SAL we're running on is recent enough...
	 */
	if ((major < SN_SAL_MIN_MAJOR) || (major == SN_SAL_MIN_MAJOR &&
					   minor < SN_SAL_MIN_MINOR)) {
		printk(KERN_ERR "This kernel needs SGI SAL version >= "
		       "%x.%02x\n", SN_SAL_MIN_MAJOR, SN_SAL_MIN_MINOR);
		panic("PROM version too old\n");
	}

	master_nasid = boot_get_nasid();

	status =
	    ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec,
			       &drift);
	if (status != 0 || ticks_per_sec < 100000) {
		printk(KERN_WARNING
		       "unable to determine platform RTC clock frequency, guessing.\n");
		/* PROM gives wrong value for clock freq. so guess */
		sn_rtc_cycles_per_second = 1000000000000UL / 30000UL;
	} else
		sn_rtc_cycles_per_second = ticks_per_sec;

	platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_CPE_VECTOR;

	/*
	 * we set the default root device to /dev/hda
	 * to make simulation easy
	 */
	ROOT_DEV = Root_HDA1;

	/*
	 * Create the PDAs and NODEPDAs for all the cpus.
	 */
	sn_init_pdas(cmdline_p);

	ia64_mark_idle = &snidle;

	/* 
	 * For the bootcpu, we do this here. All other cpus will make the
	 * call as part of cpu_init in slave cpu initialization.
	 */
	sn_cpu_init();

#ifdef CONFIG_SMP
	init_smp_config();
#endif
	screen_info = sn_screen_info;

	sn_timer_init();
}
Example #7
0
void __devinit
ia64_init_itm (void)
{
    unsigned long platform_base_freq, itc_freq;
    struct pal_freq_ratio itc_ratio, proc_ratio;
    long status, platform_base_drift, itc_drift;

    /*
     * According to SAL v2.6, we need to use a SAL call to determine the platform base
     * frequency and then a PAL call to determine the frequency ratio between the ITC
     * and the base frequency.
     */
    status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
                                &platform_base_freq, &platform_base_drift);
    if (status != 0) {
        printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status));
    } else {
        status = ia64_pal_freq_ratios(&proc_ratio, NULL, &itc_ratio);
        if (status != 0)
            printk(KERN_ERR "PAL_FREQ_RATIOS failed with status=%ld\n", status);
    }
    if (status != 0) {
        /* invent "random" values */
        printk(KERN_ERR
               "SAL/PAL failed to obtain frequency info---inventing reasonable values\n");
        platform_base_freq = 100000000;
        platform_base_drift = -1;	/* no drift info */
        itc_ratio.num = 3;
        itc_ratio.den = 1;
    }
    if (platform_base_freq < 40000000) {
        printk(KERN_ERR "Platform base frequency %lu bogus---resetting to 75MHz!\n",
               platform_base_freq);
        platform_base_freq = 75000000;
        platform_base_drift = -1;
    }
    if (!proc_ratio.den)
        proc_ratio.den = 1;	/* avoid division by zero */
    if (!itc_ratio.den)
        itc_ratio.den = 1;	/* avoid division by zero */

    itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;

    local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ;
    printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%u/%u, "
           "ITC freq=%lu.%03luMHz", smp_processor_id(),
           platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
           itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);

    if (platform_base_drift != -1) {
        itc_drift = platform_base_drift*itc_ratio.num/itc_ratio.den;
        printk("+/-%ldppm\n", itc_drift);
    } else {
        itc_drift = -1;
        printk("\n");
    }

    local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
    local_cpu_data->itc_freq = itc_freq;
    local_cpu_data->cyc_per_usec = (itc_freq + USEC_PER_SEC/2) / USEC_PER_SEC;
    local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<<IA64_NSEC_PER_CYC_SHIFT)
                                    + itc_freq/2)/itc_freq;

    if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
        itc_interpolator.frequency = local_cpu_data->itc_freq;
        itc_interpolator.drift = itc_drift;
#ifdef CONFIG_SMP
        /* On IA64 in an SMP configuration ITCs are never accurately synchronized.
         * Jitter compensation requires a cmpxchg which may limit
         * the scalability of the syscalls for retrieving time.
         * The ITC synchronization is usually successful to within a few
         * ITC ticks but this is not a sure thing. If you need to improve
         * timer performance in SMP situations then boot the kernel with the
         * "nojitter" option. However, doing so may result in time fluctuating (maybe
         * even going backward) if the ITC offsets between the individual CPUs
         * are too large.
         */
        if (!nojitter) itc_interpolator.jitter = 1;
#endif
        register_time_interpolator(&itc_interpolator);
    }

    /* Setup the CPU local timer tick */
    ia64_cpu_local_tick();
}
Example #8
0
struct sal_ret_values
sal_emulator (long index, unsigned long in1, unsigned long in2,
	      unsigned long in3, unsigned long in4, unsigned long in5,
	      unsigned long in6, unsigned long in7)
{
	struct ia64_sal_retval ret_stuff;
	unsigned long r9  = 0;
	unsigned long r10 = 0;
	long r11 = 0;
	long status;

	debugger_event(XEN_IA64_DEBUG_ON_SAL);

	status = 0;
	switch (index) {
	    case SAL_FREQ_BASE:
		if (likely(!running_on_sim))
			status = ia64_sal_freq_base(in1,&r9,&r10);
		else switch (in1) {
		      case SAL_FREQ_BASE_PLATFORM:
			r9 = 200000000;
			break;

		      case SAL_FREQ_BASE_INTERVAL_TIMER:
			r9 = 700000000;
			break;

		      case SAL_FREQ_BASE_REALTIME_CLOCK:
			r9 = 1;
			break;

		      default:
			status = -1;
			break;
		}
		break;
	    case SAL_PCI_CONFIG_READ:
		if (current->domain == dom0) {
			u64 value;
			// note that args 2&3 are swapped!!
			status = ia64_sal_pci_config_read(in1,in3,in2,&value);
			r9 = value;
		}
		else
		     printk("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n");
		break;
	    case SAL_PCI_CONFIG_WRITE:
		if (current->domain == dom0) {
			if (((in1 & ~0xffffffffUL) && (in4 == 0)) ||
			    (in4 > 1) ||
			    (in2 > 8) || (in2 & (in2-1)))
				printk("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n",
					in1,in4,in2,in3);
			// note that args are in a different order!!
			status = ia64_sal_pci_config_write(in1,in4,in2,in3);
		}
		else
		     printk("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n");
		break;
	    case SAL_SET_VECTORS:
 		if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
 			if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
 				/* Sanity check: cs_length1 must be 0,
 				   second vector is reserved.  */
 				status = -2;
 			}
 			else {
				struct domain *d = current->domain;
				d->arch.sal_data->boot_rdv_ip = in2;
				d->arch.sal_data->boot_rdv_r1 = in3;
			}
 		}
 		else
		{
			if (in1 > sizeof(sal_vectors)/sizeof(sal_vectors[0])-1)
				BUG();
			sal_vectors[in1].vector_type	= in1;
			sal_vectors[in1].handler_addr1	= in2;
			sal_vectors[in1].gp1		= in3;
			sal_vectors[in1].handler_len1	= in4;
			sal_vectors[in1].handler_addr2	= in5;
			sal_vectors[in1].gp2		= in6;
			sal_vectors[in1].handler_len2	= in7;
		}
		break;
	    case SAL_GET_STATE_INFO:
		if (current->domain == dom0) {
			sal_queue_entry_t *e;
			unsigned long flags;
			struct smp_call_args_t arg;

			spin_lock_irqsave(&sal_queue_lock, flags);
			if (!sal_queue || list_empty(&sal_queue[in1])) {
				sal_log_record_header_t header;
				XEN_GUEST_HANDLE(void) handle =
					*(XEN_GUEST_HANDLE(void)*)&in3;

				IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) "
				               "no sal_queue entry found.\n",
				               rec_name[in1]);
				memset(&header, 0, sizeof(header));

				if (copy_to_guest(handle, &header, 1)) {
					printk("sal_emulator: "
					       "SAL_GET_STATE_INFO can't copy "
					       "empty header to user: 0x%lx\n",
					       in3);
				}
				status = IA64_SAL_NO_INFORMATION_AVAILABLE;
				r9 = 0;
				spin_unlock_irqrestore(&sal_queue_lock, flags);
				break;
			}
			e = list_entry(sal_queue[in1].next,
			               sal_queue_entry_t, list);

			list_del(&e->list);
			spin_unlock_irqrestore(&sal_queue_lock, flags);

			IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s <= %s) "
			               "on CPU#%d.\n",
			               rec_name[e->sal_info_type],
			               rec_name[in1], e->cpuid);

			arg.type = e->sal_info_type;
			arg.target = in3;
			arg.corrected = !!((in1 != e->sal_info_type) && 
			                (e->sal_info_type == SAL_INFO_TYPE_MCA));
			arg.domain = current->domain;
			arg.status = 0;

			if (e->cpuid == smp_processor_id()) {
				IA64_SAL_DEBUG("SAL_GET_STATE_INFO: local\n");
				get_state_info_on(&arg);
			} else {
				int ret;
				IA64_SAL_DEBUG("SAL_GET_STATE_INFO: remote\n");
				ret = smp_call_function_single(e->cpuid,
				                               get_state_info_on,
				                               &arg, 0, 1);
				if (ret < 0) {
					printk("SAL_GET_STATE_INFO "
					       "smp_call_function_single error:"
					       " %d\n", ret);
					arg.ret = 0;
					arg.status =
					     IA64_SAL_NO_INFORMATION_AVAILABLE;
				}
			}
			r9 = arg.ret;
			status = arg.status;
			if (r9 == 0) {
				xfree(e);
			} else {
				/* Re-add the entry to sal_queue */
				spin_lock_irqsave(&sal_queue_lock, flags);
				list_add(&e->list, &sal_queue[in1]);
				spin_unlock_irqrestore(&sal_queue_lock, flags);
			}
		} else {