#ifndef _ASM_SMP_BALANCE_H
#define _ASM_SMP_BALANCE_H

/*
 * We have an architecture-specific SMP load balancer to improve
 * scheduling behavior on hyperthreaded CPUs.  Since only P4s have
 * HT, maybe this should be conditional on CONFIG_MPENTIUM4...
 *
 */

/*
 * Find any idle processor package (i.e. both virtual processors are idle)
 */
static inline int find_idle_package(int this_cpu)
{
	int i;

	this_cpu = cpu_number_map(this_cpu);

	for (i = (this_cpu + 1) % smp_num_cpus;
	     i != this_cpu;
	     i = (i + 1) % smp_num_cpus) {
		int physical = cpu_logical_map(i);
		int sibling = cpu_sibling_map[physical];

		if (idle_cpu(physical) && idle_cpu(sibling))
			return physical;
	}
	return -1;	/* not found */
}

static inline int arch_reschedule_idle_override(task_t * p, int idle)
{
	if (unlikely(smp_num_siblings > 1) && !idle_cpu(cpu_sibling_map[idle])) {
		int true_idle = find_idle_package(idle);
		if (true_idle >= 0) {
			if (likely(p->cpus_allowed & (1UL << true_idle)))
				idle = true_idle;
			else {
				true_idle = cpu_sibling_map[true_idle];
				if (p->cpus_allowed & (1UL << true_idle))
					idle = true_idle;
			}
		}
	}

	return idle;
}

static inline int arch_load_balance(int this_cpu, int idle)
{
	/* Special hack for hyperthreading */
       if (unlikely(smp_num_siblings > 1 && idle == 2 && !idle_cpu(cpu_sibling_map[this_cpu]))) {
               int found;
               struct runqueue *rq_target;

               if ((found = find_idle_package(this_cpu)) >= 0 ) {
                       rq_target = cpu_rq(found);
                       resched_task(rq_target->idle);
                       return 1;
               }
       }
       return 0;
}

#endif /* _ASM_SMP_BALANCE_H */
