LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: PowerBook5,8 - TrackPad update
From: Michael Hanselmann @ 2005-11-29  7:50 UTC (permalink / raw)
  To: Parag Warudkar; +Cc: linuxppc-dev, debian-powerpc, linux-kernel
In-Reply-To: <68465DDA-053F-4A85-9204-549E830B2269@comcast.net>

[-- Attachment #1: Type: text/plain, Size: 1184 bytes --]

Hello Parag

On Tue, Nov 29, 2005 at 01:11:00AM -0500, Parag Warudkar wrote:
> Is yours the 15" model or the 17"? Mine is 15" and the product id is  
> 0x0214.

It's the 15" one.

> I haven't looked at your changes completely yet but are you saying it
> works? Meaning mouse moves properly?

The mouse moves, but slowly. Maybe something isn't correct yet, but it
works basically.

> Also I find it strange that your model requires 80 bytes ATP_DATASIZE
> - mine isn't happy at all with anything less than 256. The less number
> of sensors you  defined is again a puzzle.

That are points I need to investigate further.

> If the format of the data is same (which looks like it is with your
> model) then yes, but in my case the data arrives is 64 byte blocks -
> there are 4 of them in one  transfer, each a reading on it's own.

I get 256 bytes in each transfer as well, but didn't look at the bytes
behind 40. Maybe that'll help to make it more responsive.

> Hmm. More confusion.

Oh yes. Why does Apple ship the basically same PowerBook with different
Touchpads?

Greets,
Michael

-- 
Gentoo Linux Developer using m0n0wall | http://hansmi.ch/

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* SPI and USB on MPC8272
From: Mike Rapoport @ 2005-11-29  6:42 UTC (permalink / raw)
  To: linuxppc-embedded list

Hi list,
I have a custom board based on MPC8272. I have a problem enabling the 
SPI and USB interfaces of the MPC8272 at the same time.
I'm running linux 2.6.12.3 with "custom" USB host driver. I tried to add 
the SPI driver present in denx linuxppc_2.4_devel git tree. When I 
enable the SPI driver first the USB host does not pass USB devices 
enumeration. When I enable the SPI driver after the USB, it hangs on 
while writing to CPCR.
Each driver works when used separately.
Does anybody have a clue why could it happen?
<http://source.denx.net/cgi-bin/gitweb.cgi?p=linuxppc_2_4_devel.git;a=summary> 


-- 
Sincerely yours,
Mike Rapoport

^ permalink raw reply

* Re: do_initcalls
From: Gil Madar @ 2005-11-29  6:27 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: Jaap de Jong
In-Reply-To: <6915D0AE8B9047438F320B466AE30FDD152557@nvs0003.nedap.local>

On Friday 25 November 2005 09:41, Jaap de Jong wrote:
>Hi,
>
>In linux-2.4.25/init/main.c this function is called:
>        
>        static void __init do_initcalls(void)
>        {
>                initcall_t *call;
>        
>                call = &__initcall_start;
>                do {
>                        (*call)();
>                        call++
>                } while (call < &__initcall_end);
>
>                /* Make sure there is no pending stuff from the initcall sequence */
>                flush_scheduled_tasks();
>        }
>
>What is supposed to be in the section __initcall_start ..
>__initcall_end?
>Mine is empty and therefore causing trouble...
>System.map:
>        //
>        //
>        c00ad880 A __initcall_end
>        c00ad880 A __initcall_start
>        //
>        //
>
>The fix is obvious... But I guess I've missed something else?
>
>Thanks in advance,
>        Jaap de Jong
Hi Jaap,

This is what I got on kernel 2.4.25:

c016a890 A __initcall_start
c016a890 A __setup_end
c016a890 t __initcall_abi_register_sysctl
c016a894 t __initcall_spawn_ksoftirqd
c016a898 t __initcall_uid_cache_init
c016a89c t __initcall_kmem_cpucache_init
c016a8a0 t __initcall_kswapd_init
c016a8a4 t __initcall_init_tmpfs
c016a8a8 t __initcall_bdflush_init
c016a8ac t __initcall_init_pipe_fs
c016a8b0 t __initcall_fasync_init
c016a8b4 t __initcall_filelock_init
c016a8b8 t __initcall_dnotify_init
c016a8bc t __initcall_init_script_binfmt
c016a8c0 t __initcall_init_elf_binfmt
c016a8c4 t __initcall_init_ramfs_fs
c016a8c8 t __initcall_init_devfs_fs
c016a8cc t __initcall_init_nfs_fs
c016a8d0 t __initcall_nfsd_init
c016a8d4 t __initcall_init_smb_fs
c016a8d8 t __initcall_init_devpts_fs
c016a8dc t __initcall_chr_dev_init
c016a8e0 t __initcall_raw_init
c016a8e4 t __initcall_device_init
c016a8e8 t __initcall_rd_init
c016a8ec t __initcall_loop_init
c016a8f0 t __initcall_ppp_init
c016a8f4 t __initcall_ppp_async_init
c016a8f8 t __initcall_deflate_init
c016a8fc t __initcall_netlink_proto_init
c016a900 t __initcall_inet_init
c016a904 t __initcall_ip_auto_config
c016a908 t __initcall_af_unix_init
c016a90c t __initcall_packet_init
c016a910 t __initcall_init_sunrpc
c016a914 A __initcall_end

HTH,
Gil

^ permalink raw reply

* Re: PowerBook5,8 - TrackPad update
From: Parag Warudkar @ 2005-11-29  6:11 UTC (permalink / raw)
  To: Michael Hanselmann; +Cc: linuxppc-dev, debian-powerpc, linux-kernel
In-Reply-To: <20051129000615.GA20843@hansmi.ch>

[-- Attachment #1: Type: text/plain, Size: 1055 bytes --]


On Nov 28, 2005, at 7:06 PM, Michael Hanselmann wrote:

> The product ID I have, 0x0215, was in none of the
> available drivers and the data format is somewhat different

Hi Michael

Is yours the 15" model or the 17"? Mine is 15" and the product id is  
0x0214.

> You find my hacked version attached -- be aware that in its current  
> form
> it will not work with any touchpad except 0x0215.

I haven't looked at your changes completely yet but are you saying it  
works? Meaning mouse
moves properly?

Also I find it strange that your model requires 80 bytes ATP_DATASIZE  
- mine isn't happy
at all with anything less than 256. The less number of sensors you  
defined is again a puzzle.

> As far as I see it, all methods can be built into one driver. Is there
> already someone working on combining them?

If the format of the data is same (which looks like it is with your  
model) then yes, but in my case
the data arrives is 64 byte blocks - there are 4 of them in one  
transfer, each a reading on it's own.

Hmm. More confusion.

Thanks

Parag

[-- Attachment #2: Type: text/html, Size: 2386 bytes --]

^ permalink raw reply

* Re: [PATCH] 3/3 Generic sys_rt_sigsuspend
From: Mika Penttilä @ 2005-11-29  5:18 UTC (permalink / raw)
  To: David Woodhouse; +Cc: akpm, linuxppc-dev, linux-kernel, drepper
In-Reply-To: <1133225852.31573.115.camel@baythorne.infradead.org>

David Woodhouse wrote:

>The TIF_RESTORE_SIGMASK flag allows us to have a generic implementation
>of sys_rt_sigsuspend() instead of duplicating it for each architecture.
>This provides such an implementation and makes arch/powerpc use it.
>
>It also tidies up the ppc32 sys_sigsuspend() to use TIF_RESTORE_SIGMASK.
>
>Signed-off-by: David Woodhouse <dwmw2@infradead.org>
>  
>
> 
>+#ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
>+long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
>+{
>+	sigset_t saveset, newset;
>+
>+	/* XXX: Don't preclude handling different sized sigset_t's.  */
>+	if (sigsetsize != sizeof(sigset_t))
>+		return -EINVAL;
>+
>+	if (copy_from_user(&newset, unewset, sizeof(newset)))
>+		return -EFAULT;
>+	sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
>+
>+	spin_lock_irq(&current->sighand->siglock);
>+	saveset = current->blocked;
>+	current->blocked = newset;
>+	recalc_sigpending();
>+	spin_unlock_irq(&current->sighand->siglock);
>+
>+	current->state = TASK_INTERRUPTIBLE;
>+	schedule();
>+	set_thread_flag(TIF_RESTORE_SIGMASK);
>+	return -ERESTARTNOHAND;
>+}
>+#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
>+
>  
>
You are not setting saved_sigmask here. And shouldn't it return -EINTR?

Thanks,
Mika

^ permalink raw reply

* Re: [PATCH] ppc32 8xx: Added setbitsXX/clrbitsXX macro for read-modify-write operations
From: Paul Mackerras @ 2005-11-29  4:56 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-devel list, linuxppc-embedded list
In-Reply-To: <438B238F.9070804@ru.mvista.com>

Vitaly Bordug writes:

> This adds setbitsXX/clrbitsXX macro for read-modify-write operations
> and converts the 8xx core and drivers to use it.

Your mailer has munged the whitespace in the patch, unfortunately.

> +	clrbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr,(1 << cpm_vec));

This needs a space after the comma.

Regards,
Paul.

^ permalink raw reply

* RE: Booting hangs after "Calibrating delay loop..."
From: Nguyen Thanh Binh @ 2005-11-29  3:20 UTC (permalink / raw)
  To: Autran, Guillaume, 'linuxppc-embedded@ozlabs.org'
In-Reply-To: <19EE6EC66973A5408FBE4CB7772F6F0A2105B2@ltnmail.xyplex.com>

[-- Attachment #1: Type: text/plain, Size: 1478 bytes --]

Hi Guillaume,

I have tried with your suggestions. But I did not find
arch/ppc/syslib/m8xx_setup.c as you said, instead I
found arch/ppc/kernel/m8xx_setup.c.
I have modified as you showed me, but the result was
always the same.
It means that boot hangs after printing "Calibrating
delay loop...".

You can find what I have modified in the attached
files 
(time.c in arch/ppc/kernel, m8xx_setup.c in
arch/ppc/kernel).

Do you have any idea?

Thank you very much.

Binh Nguyen

--- "Autran, Guillaume" <gautran@mrv.com> wrote:

> Hi,
> 
> I remember there is some race condition before
> calling set_dec(..) in time.c
> Basically, what happens is that the external
> decrementer is set way before
> the interrupt gets enabled. When we get to enable
> the interrupt, the
> decrementer value already reached 0 and wrapped
> arround (at least in our
> case). 
> The fix was to comment the line in:
> arch/ppc/kernel/time.c:330:
> set_dec(tb_ticks_per_jiffy);
> 
> And move it to:
> arch/ppc/syslib/m8xx_setup.c
> inside m8xx_calibrate_decr() just before setting up
> the interrupt for the
> decrementer.
> 
> In time.c, you may also need to initialize stamp =
> get_native_tbl(); as this
> variable may not have been initialized since you are
> using an external
> decrementer.
> 
> Try that...
> 
> Guillaume.
> 


		
___________________________________________________________ 
WIN ONE OF THREE YAHOO! VESPAS - Enter now! - http://uk.cars.yahoo.com/features/competitions/vespa.html

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 2251979003-time.c --]
[-- Type: text/x-c; name="time.c", Size: 16570 bytes --]

/*
 * Common time routines among all ppc machines.
 *
 * Written by Cort Dougan (cort@cs.nmt.edu) to merge
 * Paul Mackerras' version and mine for PReP and Pmac.
 * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net).
 *
 * First round of bugfixes by Gabriel Paubert (paubert@iram.es)
 * to make clock more stable (2.4.0-test5). The only thing
 * that this code assumes is that the timebases have been synchronized
 * by firmware on SMP and are never stopped (never do sleep
 * on SMP then, nap and doze are OK).
 *
 * TODO (not necessarily in this file):
 * - improve precision and reproducibility of timebase frequency
 * measurement at boot time.
 * - get rid of xtime_lock for gettimeofday (generic kernel problem
 * to be implemented on all architectures for SMP scalability and
 * eventually implementing gettimeofday without entering the kernel).
 * - put all time/clock related variables in a single structure
 * to minimize number of cache lines touched by gettimeofday()
 * - for astronomical applications: add a new function to get
 * non ambiguous timestamps even around leap seconds. This needs
 * a new timestamp format and a good name.
 *
 *
 * The following comment is partially obsolete (at least the long wait
 * is no more a valid reason):
 * Since the MPC8xx has a programmable interrupt timer, I decided to
 * use that rather than the decrementer.  Two reasons: 1.) the clock
 * frequency is low, causing 2.) a long wait in the timer interrupt
 *		while ((d = get_dec()) == dval)
 * loop.  The MPC8xx can be driven from a variety of input clocks,
 * so a number of assumptions have been made here because the kernel
 * parameter HZ is a constant.  We assume (correctly, today :-) that
 * the MPC8xx on the MBX board is driven from a 32.768 kHz crystal.
 * This is then divided by 4, providing a 8192 Hz clock into the PIT.
 * Since it is not possible to get a nice 100 Hz clock out of this, without
 * creating a software PLL, I have set HZ to 128.  -- Dan
 *
 * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
 *             "A Kernel Model for Precision Timekeeping" by Dave Mills
 */

#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/time.h>
#include <linux/init.h>

#include <linux/trace.h>

#include <asm/segment.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/nvram.h>
#include <asm/cache.h>
#include <asm/8xx_immap.h>
#include <asm/machdep.h>

#include <asm/time.h>

#ifdef CONFIG_HIGH_RES_TIMERS
#include <linux/hrtime.h>
int hr_time_resolution = CONFIG_HIGH_RES_RESOLUTION;
int arch_to_nsec;
int nsec_to_arch;
unsigned volatile jiffies_seq = 0;
#endif

unsigned long disarm_decr[NR_CPUS];

extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);

/* keep track of when we need to update the rtc */
time_t last_rtc_update;
extern rwlock_t xtime_lock;

/* The decrementer counts down by 128 every 128ns on a 601. */
#define DECREMENTER_COUNT_601	(1000000000 / HZ)

unsigned tb_ticks_per_jiffy;
unsigned tb_to_us;
unsigned tb_last_stamp;
extern unsigned long wall_jiffies;

static long time_offset;

spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;

EXPORT_SYMBOL(rtc_lock);

/* Timer interrupt helper function */
static inline int tb_delta(unsigned *jiffy_stamp) {
	int delta;
	if (__USE_RTC()) {
		delta = get_rtcl();
		if (delta < *jiffy_stamp) *jiffy_stamp -= 1000000000;
		delta -= *jiffy_stamp;
	} else {
		delta = get_tbl() - *jiffy_stamp;
	}
	return delta;
}

extern unsigned long prof_cpu_mask;
extern unsigned int * prof_buffer;
extern unsigned long prof_len;
extern unsigned long prof_shift;
extern char _stext;

static inline void ppc_do_profile (unsigned long nip)
{
	if (!prof_buffer)
		return;

	/*
	 * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
	 * (default is all CPUs.)
	 */
	if (!((1<<smp_processor_id()) & prof_cpu_mask))
		return;

	nip -= (unsigned long) &_stext;
	nip >>= prof_shift;
	/*
	 * Don't ignore out-of-bounds EIP values silently,
	 * put them into the last histogram slot, so if
	 * present, they will show up as a sharp peak.
	 */
	if (nip > prof_len-1)
		nip = prof_len-1;
	atomic_inc((atomic_t *)&prof_buffer[nip]);
}

#ifdef CONFIG_HIGH_RES_TIMERS
int hr_set_dec(unsigned count) {

	if (time_before(count, get_tbl()))
		/* missed it */
		return 1;

	/* ok, we've got a shot */
	set_dec(count - get_tbl());

	if (time_before_eq(get_tbl(), count))
		/* made it */
		return 0;

	/*
	 * Ohh, just missed it. If we were slow enough to have loaded the
	 * decrementer with a negative value, we're going to have to wait
	 * an awfully long time for another decrementer interrupt. So, we'll
	 * trigger an interrupt right now and let timer_interrupt recover and
	 * re-schedule the next jiffie to make up for our mistake.
	 */
	set_dec(1);
	return 1;

}
int schedule_hr_timer_int(unsigned ref_jiffies, int cycles) {

	unsigned temp_jiffies, seq;
	unsigned req_tb, next_jiffy_tb;
	int flags, ret;

	while (unlikely(cycles >= tb_ticks_per_jiffy)) {
		ref_jiffies++;
		cycles -= tb_ticks_per_jiffy;
	}

	do {
		int jiffies_diff;

		seq = jiffies_seq;
		temp_jiffies = jiffies;
		barrier();

		req_tb = tb_last_stamp + cycles;
		if (unlikely(jiffies_diff = ref_jiffies - temp_jiffies))
			req_tb += (jiffies_diff) * tb_ticks_per_jiffy;

		next_jiffy_tb = tb_last_stamp + tb_ticks_per_jiffy;

		barrier();
	} while (unlikely((seq != jiffies_seq) || (seq & 1)));

	if (time_before(ref_jiffies, temp_jiffies))
		return 1;

	/* paranoia */
	if (time_after(ref_jiffies, temp_jiffies) ||
	    time_after(req_tb, next_jiffy_tb))
		BUG();

	local_irq_save(flags);
	ret = hr_set_dec(req_tb);
	local_irq_restore(flags);

	return ret;
}
void __init hr_time_init(void)
{
	unsigned tb_ticks_per_sec;

	/*
	 * Use mulhwu_scale_factor to find the number ticks needed to equal
	 * 1,000,000 uSecs (1 Sec).
	 */
	tb_ticks_per_sec = mulhwu_scale_factor(tb_to_us, USEC_PER_SEC);

	arch_to_nsec = div_sc_n(HR_TIME_SCALE_NSEC, NSEC_PER_SEC,
				tb_ticks_per_sec);
	nsec_to_arch = div_sc_n(HR_TIME_SCALE_CYCLES, tb_ticks_per_sec,
				NSEC_PER_SEC);

	printk("hr_time_init: arch_to_nsec = %u, nsec_to_arch = %u\n",
		arch_to_nsec, nsec_to_arch);
}
#endif
/*
 * timer_interrupt - gets called when the decrementer overflows,
 * with interrupts disabled.
 * We set it up to overflow again in 1/HZ seconds.
 */
int timer_interrupt(struct pt_regs * regs)
{
	int next_dec;
	unsigned long cpu = smp_processor_id();
	unsigned jiffy_stamp = last_jiffy_stamp(cpu);
#ifdef CONFIG_HIGH_RES_TIMERS
	int hr_tick = 1;
#endif
	extern void do_IRQ(struct pt_regs *);

	if (atomic_read(&ppc_n_lost_interrupts) != 0)
		do_IRQ(regs);

	TRACE_TRAP_ENTRY(regs->trap, instruction_pointer(regs));

	hardirq_enter(cpu);
	
	while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0) {
		jiffy_stamp += tb_ticks_per_jiffy;
		if (!user_mode(regs))
			ppc_do_profile(instruction_pointer(regs));
		if (unlikely(!heartbeat_count(cpu)--) 
				&& heartbeat_reset(cpu)) {
			ppc_md.heartbeat();
			heartbeat_count(cpu) = heartbeat_reset(cpu);
		}
#ifdef CONFIG_HIGH_RES_TIMERS
		hr_tick = 0;
#endif
	  	if (cpu)
			continue;

		/* We are in an interrupt, no need to save/restore flags */
		write_lock(&xtime_lock);
		tb_last_stamp = jiffy_stamp;
#ifdef CONFIG_HIGH_RES_TIMERS
		jiffies_seq++;
#endif
		do_timer(regs);
#ifdef CONFIG_HIGH_RES_TIMERS
		jiffies_seq++;
#endif

		/*
		 * update the rtc when needed, this should be performed on the
		 * right fraction of a second. Half or full second ?
		 * Full second works on mk48t59 clocks, others need testing.
		 * Note that this update is basically only used through
		 * the adjtimex system calls. Setting the HW clock in
		 * any other way is a /dev/rtc and userland business.
		 * This is still wrong by -0.5/+1.5 jiffies because of the
		 * timer interrupt resolution and possible delay, but here we
		 * hit a quantization limit which can only be solved by higher
		 * resolution timers and decoupling time management from timer
		 * interrupts. This is also wrong on the clocks
		 * which require being written at the half second boundary.
		 * We should have an rtc call that only sets the minutes and
		 * seconds like on Intel to avoid problems with non UTC clocks.
		 */
		if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 &&
		     xtime.tv_sec - last_rtc_update >= 659 &&
		     abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ &&
		     jiffies - wall_jiffies == 1) {
		  	if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0)
				last_rtc_update = xtime.tv_sec+1;
			else
				/* Try again one minute later */
				last_rtc_update += 60;
		}
		write_unlock(&xtime_lock);
	}
	if (!disarm_decr[cpu])
		set_dec(next_dec);
#ifdef CONFIG_HIGH_RES_TIMERS
	if (hr_tick)
		do_hr_timer_int();
#endif
	last_jiffy_stamp(cpu) = jiffy_stamp;

#ifdef CONFIG_SMP
	smp_local_timer_interrupt(regs);
#endif /* CONFIG_SMP */

	hardirq_exit(cpu);

	if (softirq_pending(cpu))
		do_softirq();

	TRACE_TRAP_EXIT();

	return 1; /* lets ret_from_int know we can do checks */
}

/*
 * This version of gettimeofday has microsecond resolution.
 */
void do_gettimeofday(struct timeval *tv)
{
	unsigned long flags;
	unsigned delta, lost_ticks, usec, sec;

	read_lock_irqsave(&xtime_lock, flags);
	sec = xtime.tv_sec;
	usec = xtime.tv_usec;
	delta = tb_ticks_since(tb_last_stamp);
#ifdef CONFIG_SMP
	/* As long as timebases are not in sync, gettimeofday can only
	 * have jiffy resolution on SMP.
	 */
	if (!smp_tb_synchronized)
		delta = 0;
#endif /* CONFIG_SMP */
	lost_ticks = jiffies - wall_jiffies;
	read_unlock_irqrestore(&xtime_lock, flags);

	usec += mulhwu(tb_to_us, tb_ticks_per_jiffy * lost_ticks + delta);
	while (usec >= 1000000) {
	  	sec++;
		usec -= 1000000;
	}
	tv->tv_sec = sec;
	tv->tv_usec = usec;
}

void do_settimeofday(struct timeval *tv)
{
	unsigned long flags;
	int tb_delta, new_usec, new_sec;

	write_lock_irqsave(&xtime_lock, flags);
	/* Updating the RTC is not the job of this code. If the time is
	 * stepped under NTP, the RTC will be update after STA_UNSYNC
	 * is cleared. Tool like clock/hwclock either copy the RTC
	 * to the system time, in which case there is no point in writing
	 * to the RTC again, or write to the RTC but then they don't call
	 * settimeofday to perform this operation. Note also that
	 * we don't touch the decrementer since:
	 * a) it would lose timer interrupt synchronization on SMP
	 * (if it is working one day)
	 * b) it could make one jiffy spuriously shorter or longer
	 * which would introduce another source of uncertainty potentially
	 * harmful to relatively short timers.
	 */

	/* This works perfectly on SMP only if the tb are in sync but 
	 * guarantees an error < 1 jiffy even if they are off by eons,
	 * still reasonable when gettimeofday resolution is 1 jiffy.
	 */
	tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id()));
	tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
	new_sec = tv->tv_sec;
	new_usec = tv->tv_usec - mulhwu(tb_to_us, tb_delta);
	while (new_usec <0) {
		new_sec--; 
		new_usec += 1000000;
	}
	xtime.tv_usec = new_usec;
	xtime.tv_sec = new_sec;

	wall_to_monotonic.tv_sec += xtime.tv_sec - tv->tv_sec;
	wall_to_monotonic.tv_nsec += (xtime.tv_usec - tv->tv_usec) * 
		NSEC_PER_USEC;

	if (wall_to_monotonic.tv_nsec > NSEC_PER_SEC) {
		wall_to_monotonic.tv_nsec -= NSEC_PER_SEC;
		wall_to_monotonic.tv_sec++;
	}
	if (wall_to_monotonic.tv_nsec < 0) {
		wall_to_monotonic.tv_nsec += NSEC_PER_SEC;
		wall_to_monotonic.tv_sec--;
	}

	/* In case of a large backwards jump in time with NTP, we want the 
	 * clock to be updated as soon as the PLL is again in lock.
	 */
	last_rtc_update = new_sec - 658;

	time_adjust = 0;                /* stop active adjtime() */
	time_status |= STA_UNSYNC;
	time_state = TIME_ERROR;        /* p. 24, (a) */
	time_maxerror = NTP_PHASE_LIMIT;
	time_esterror = NTP_PHASE_LIMIT;
	write_unlock_irqrestore(&xtime_lock, flags);
	clock_was_set();
}

/* This function is only called on the boot processor */
void __init time_init(void)
{
	time_t sec, old_sec;
	unsigned old_stamp, stamp, elapsed;

	stamp = get_native_tbl(); /* Binh 25/11/05 */


        if (ppc_md.time_init != NULL)
                time_offset = ppc_md.time_init();

	if (__USE_RTC()) {
		/* 601 processor: dec counts down by 128 every 128ns */
		tb_ticks_per_jiffy = DECREMENTER_COUNT_601;
		/* mulhwu_scale_factor(1000000000, 1000000) is 0x418937 */
		tb_to_us = 0x418937;
        } else {
                ppc_md.calibrate_decr();
	}
#ifdef CONFIG_HIGH_RES_TIMERS
	hr_time_init();
#endif

	/* Now that the decrementer is calibrated, it can be used in case the 
	 * clock is stuck, but the fact that we have to handle the 601
	 * makes things more complex. Repeatedly read the RTC until the
	 * next second boundary to try to achieve some precision.  If there
	 * is no RTC, we still need to set tb_last_stamp and
	 * last_jiffy_stamp(cpu 0) to the current stamp.
	 */
	stamp = get_native_tbl();
	if (ppc_md.get_rtc_time) {
		sec = ppc_md.get_rtc_time();
		elapsed = 0;
		do {
			old_stamp = stamp; 
			old_sec = sec;
			stamp = get_native_tbl();
			if (__USE_RTC() && stamp < old_stamp)
				old_stamp -= 1000000000;
			elapsed += stamp - old_stamp;
			sec = ppc_md.get_rtc_time();
		} while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy);
		if (sec == old_sec)
			printk("Warning: real time clock seems stuck!\n");
		xtime.tv_sec = sec;
		wall_to_monotonic.tv_sec = -sec;
		xtime.tv_usec = 0;
		wall_to_monotonic.tv_nsec = 0;

		/* No update now, we just read the time from the RTC ! */
		last_rtc_update = xtime.tv_sec;
	}

	last_jiffy_stamp(0) = tb_last_stamp = stamp;

	/* Not exact, but the timer interrupt takes care of this */
	/* set_dec(tb_ticks_per_jiffy); Binh 25/11/05 */

	/* If platform provided a timezone (pmac), we correct the time
	 * using do_sys_settimeofday() which in turn calls warp_clock()
	 */
        if (time_offset) {
        	struct timezone tz;
        	tz.tz_minuteswest = -time_offset / 60;
        	tz.tz_dsttime = 0;
        	do_sys_settimeofday(NULL, &tz);
        }
}

#define FEBRUARY		2
#define	STARTOFTIME		1970
#define SECDAY			86400L
#define SECYR			(SECDAY * 365)
#define	leapyear(y)		((!(y % 4) && (y % 100)) || !(y % 400))
#define	days_in_year(a) 	(leapyear(a) ? 366 : 365)
#define	days_in_month(a) 	(month_days[(a) - 1])

static int month_days[12] = {
	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

void to_tm(int tim, struct rtc_time * tm)
{
	register int i;
	register long hms, day, gday;

	gday = day = tim / SECDAY;
	hms = tim % SECDAY;

	/* Hours, minutes, seconds are easy */
	tm->tm_hour = hms / 3600;
	tm->tm_min = (hms % 3600) / 60;
	tm->tm_sec = (hms % 3600) % 60;

	/* Number of years in days */
	for (i = STARTOFTIME; day >= days_in_year(i); i++)
		day -= days_in_year(i);
	tm->tm_year = i;

	/* Number of months in days left */
	if (leapyear(tm->tm_year))
		days_in_month(FEBRUARY) = 29;
	for (i = 1; day >= days_in_month(i); i++)
		day -= days_in_month(i);
	days_in_month(FEBRUARY) = 28;
	tm->tm_mon = i;

	/* Days are what is left over (+1) from all that. */
	tm->tm_mday = day + 1;

	/*
	 * Determine the day of week. Jan. 1, 1970 was a Thursday.
	 */
	tm->tm_wday = (gday + 4) % 7;
}

/* Auxiliary function to compute scaling factors */
/* Actually the choice of a timebase running at 1/4 the of the bus
 * frequency giving resolution of a few tens of nanoseconds is quite nice.
 * It makes this computation very precise (27-28 bits typically) which
 * is optimistic considering the stability of most processor clock
 * oscillators and the precision with which the timebase frequency
 * is measured but does not harm.
 */
unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) {
	unsigned mlt=0, tmp, err;
	/* No concern for performance, it's done once: use a stupid
	 * but safe and compact method to find the multiplier.
	 */
	for (tmp = 1U<<31; tmp != 0; tmp >>= 1) {
		if (mulhwu(inscale, mlt|tmp) < outscale) mlt|=tmp;
	}
	/* We might still be off by 1 for the best approximation.
	 * A side effect of this is that if outscale is too large
	 * the returned value will be zero.
	 * Many corner cases have been checked and seem to work,
	 * some might have been forgotten in the test however.
	 */
	err = inscale*(mlt+1);
	if (err <= inscale/2) mlt++;
	return mlt;
}


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 980338913-m8xx_setup.c --]
[-- Type: text/x-c; name="m8xx_setup.c", Size: 13503 bytes --]

/*
 *  linux/arch/ppc/kernel/setup.c
 *
 *  Copyright (C) 1995  Linus Torvalds
 *  Adapted from 'alpha' version by Gary Thomas
 *  Modified by Cort Dougan (cort@cs.nmt.edu)
 *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
 *  Further modified for generic 8xx by Dan.
 */

/*
 * bootup setup stuff..
 */

#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/major.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/blk.h>
#include <linux/ioport.h>
#include <linux/console.h>
#include <linux/bootmem.h>
#include <linux/ide.h>
#include <linux/seq_file.h>

#include <asm/mmu.h>
#include <asm/processor.h>
#include <asm/residual.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/mpc8xx.h>
#include <asm/8xx_immap.h>
#include <asm/machdep.h>
#include <asm/bootinfo.h>
#include <asm/time.h>
#include <asm/i8259.h>

#include "ppc8xx_pic.h"

extern int i8259_pic_irq_offset; /* defined in arch/ppc/kernel/i8259.c */

static int m8xx_set_rtc_time(unsigned long time);
static unsigned long m8xx_get_rtc_time(void);
void m8xx_calibrate_decr(void);

unsigned char __res[sizeof(bd_t)];

extern void m8xx_ide_init(void);
extern void m8xx_find_bridges(void);

extern unsigned long find_available_memory(void);
extern void m8xx_cpm_reset(uint);
extern void rpxfb_alloc_pages(void);

void __init
m8xx_setup_arch(void)
{
	int	cpm_page;

	cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);

	/* Reset the Communication Processor Module.
	*/
	m8xx_cpm_reset(cpm_page);

#ifdef CONFIG_FB_RPX
	rpxfb_alloc_pages();
#endif

#ifdef notdef
	ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
#endif

#ifdef CONFIG_BLK_DEV_INITRD
#if 0
	ROOT_DEV = to_kdev_t(0x0200); /* floppy */
	rd_prompt = 1;
	rd_doload = 1;
	rd_image_start = 0;
#endif
#if 0	/* XXX this may need to be updated for the new bootmem stuff,
	   or possibly just deleted (see set_phys_avail() in init.c).
	   - paulus. */
	/* initrd_start and size are setup by boot/head.S and kernel/head.S */
	if ( initrd_start )
	{
		if (initrd_end > *memory_end_p)
		{
			printk("initrd extends beyond end of memory "
			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
			       initrd_end,*memory_end_p);
			initrd_start = 0;
		}
	}
#endif
#endif

#ifdef CONFIG_PCI
	m8xx_find_bridges();
#endif
}

void
abort(void)
{
#ifdef CONFIG_XMON
	xmon(0);
#endif
	machine_restart(NULL);

	/* not reached */
	for (;;);
}

/* A place holder for time base interrupts, if they are ever enabled. */
void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
{
	printk ("timebase_interrupt()\n");
}

/* The decrementer counts at the system (internal) clock frequency divided by
 * sixteen, or external oscillator divided by four.  We force the processor
 * to use system clock divided by sixteen.
 */
void __init m8xx_calibrate_decr(void)
{
	bd_t	*binfo = (bd_t *)__res;
	int freq, fp, divisor;

	/* Unlock the SCCR. */
	((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = ~KAPWR_KEY;
	((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = KAPWR_KEY;

	/* Force all 8xx processors to use divide by 16 processor clock. */
	((volatile immap_t *)IMAP_ADDR)->im_clkrst.car_sccr |= 0x02000000;

	/* Processor frequency is MHz.
	 * The value 'fp' is the number of decrementer ticks per second.
	 */
	fp = binfo->bi_intfreq / 16;
	freq = fp*60;	/* try to make freq/1e6 an integer */
        divisor = 60;
        printk("Decrementer Frequency = %d/%d\n", freq, divisor);
        tb_ticks_per_jiffy = freq / HZ / divisor;
	tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
#ifdef CONFIG_ILATENCY
	{
		extern long ticks_per_usec;
		ticks_per_usec = freq / divisor / 1000000;
	}
#endif

	/* Perform some more timer/timebase initialization.  This used
	 * to be done elsewhere, but other changes caused it to get
	 * called more than once....that is a bad thing.
	 *
	 * First, unlock all of the registers we are going to modify.
	 * To protect them from corruption during power down, registers
	 * that are maintained by keep alive power are "locked".  To
	 * modify these registers we have to write the key value to
	 * the key location associated with the register.
	 * Some boards power up with these unlocked, while others
	 * are locked.  Writing anything (including the unlock code?)
	 * to the unlocked registers will lock them again.  So, here
	 * we guarantee the registers are locked, then we unlock them
	 * for our use.
	 */
	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = ~KAPWR_KEY;
	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = ~KAPWR_KEY;
	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk    = ~KAPWR_KEY;
	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk =  KAPWR_KEY;
	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck =  KAPWR_KEY;
	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk    =  KAPWR_KEY;

	/* Disable the RTC one second and alarm interrupts. */
	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
						~(RTCSC_SIE | RTCSC_ALE);
	/* Enable the RTC */
	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc |=
						(RTCSC_RTF | RTCSC_RTE);

	/* Binh 25/11/05 */
	   set_dec(tb_ticks_per_jiffy); 
	

	/* Enabling the decrementer also enables the timebase interrupts
	 * (or from the other point of view, to get decrementer interrupts
	 * we have to enable the timebase).  The decrementer interrupt
	 * is wired into the vector table, nothing to do here for that.
	 */
	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
					 (TBSCR_TBF | TBSCR_TBE));

	if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint",
				NULL) != 0)
		panic("Could not allocate timer IRQ!");
}

/* The RTC on the MPC8xx is an internal register.
 * We want to protect this during power down, so we need to unlock,
 * modify, and re-lock.
 */
static int
m8xx_set_rtc_time(unsigned long time)
{
	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
	return(0);
}

static unsigned long
m8xx_get_rtc_time(void)
{
	/* Get time from the RTC. */
	return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc));
}

static void
m8xx_restart(char *cmd)
{
	__volatile__ unsigned char dummy;
	uint	msr;

	cli();
	((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080;

	/* Clear the ME bit in MSR to cause checkstop on machine check
	*/
	__asm__("mfmsr %0" : "=r" (msr) );
	msr &= ~0x1000;
	__asm__("mtmsr %0" : : "r" (msr) );

	dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0];
	printk("Restart failed\n");
	while(1);
}

static void
m8xx_power_off(void)
{
   m8xx_restart(NULL);
}

static void
m8xx_halt(void)
{
   m8xx_restart(NULL);
}


static int
m8xx_show_percpuinfo(struct seq_file *m, int i)
{
	bd_t	*bp;

	bp = (bd_t *)__res;

	seq_printf(m, "clock\t\t: %dMHz\n"
		   "bus clock\t: %dMHz\n",
		   bp->bi_intfreq / 1000000,
		   bp->bi_busfreq / 1000000);

	return 0;
}

/* Initialize the internal interrupt controller.  The number of
 * interrupts supported can vary with the processor type, and the
 * 82xx family can have up to 64.
 * External interrupts can be either edge or level triggered, and
 * need to be initialized by the appropriate driver.
 */
static void __init
m8xx_init_IRQ(void)
{
	int i;
	void cpm_interrupt_init(void);

	for (i = SIU_IRQ_OFFSET ; i < SIU_IRQ_OFFSET + NR_SIU_INTS ; i++)
		irq_desc[i].handler = &ppc8xx_pic;

	cpm_interrupt_init();

#if defined(CONFIG_PCI)
	for (i = I8259_IRQ_OFFSET ; i < I8259_IRQ_OFFSET + NR_8259_INTS ; i++)
		irq_desc[i].handler = &i8259_pic;

	i8259_pic_irq_offset = I8259_IRQ_OFFSET;
	i8259_init(0);

	/* The i8259 cascade interrupt must be level sensitive. */
	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel &= 
		~(0x80000000 >> ISA_BRIDGE_INT);

	if (request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "i8259 cascade",
				NULL) != 0)
		panic("Could not allocate 8259 IRQ!");
#endif	/* CONFIG_PCI */
}

/* -------------------------------------------------------------------- */

/*
 * This is a big hack right now, but it may turn into something real
 * someday.
 *
 * For the 8xx boards (at this time anyway), there is nothing to initialize
 * associated the PROM.  Rather than include all of the prom.c
 * functions in the image just to get prom_init, all we really need right
 * now is the initialization of the physical memory region.
 */
static unsigned long __init
m8xx_find_end_of_memory(void)
{
	bd_t	*binfo;
	extern unsigned char __res[];

	binfo = (bd_t *)__res;

	return binfo->bi_memsize;
}

#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
#if !defined(CONFIG_BLK_DEV_MPC8xx_IDE)
/*
 * IDE stuff.
 * These functions are to support an IDE device on the mpc8xx pcmcia interface
 * when using the pcmcia-cs module to manage the pcmcia interface.
 */
static int
m8xx_ide_check_region(ide_ioreg_t from, unsigned int extent)
{
	return check_region(from, extent);
}

static void
m8xx_ide_request_region(ide_ioreg_t from, unsigned int extent, const char *name)
{
	request_region(from, extent, name);
	return;
}

static void
m8xx_ide_release_region(ide_ioreg_t from, unsigned int extent)
{
	release_region(from, extent);
	return;
}

static int
m8xx_ide_default_irq(ide_ioreg_t base)
{
	return SIU_LEVEL4;
}

static ide_ioreg_t
m8xx_ide_default_io_base(int index)
{
	return index;
}
#endif	/* if !defined(CONFIG_BLK_DEV_MPC8xx_IDE) */
#endif	/* if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */

/*
 * Now map in some of the I/O space that is generically needed
 * or shared with multiple devices.
 * All of this fits into the same 4Mbyte region, so it only
 * requires one page table page.  (or at least it used to  -- paulus)
 */
static void __init
m8xx_map_io(void)
{
        io_block_mapping(IMAP_ADDR, IMAP_ADDR, IMAP_SIZE, _PAGE_IO);
#ifdef CONFIG_MBX
        io_block_mapping(NVRAM_ADDR, NVRAM_ADDR, NVRAM_SIZE, _PAGE_IO);
        io_block_mapping(MBX_CSR_ADDR, MBX_CSR_ADDR, MBX_CSR_SIZE, _PAGE_IO);
        io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);

#if !defined(CONFIG_PCI)
	/* Map some of the PCI/ISA I/O space to get the IDE interface.
	*/
        io_block_mapping(PCI_ISA_IO_ADDR, PCI_ISA_IO_ADDR, 0x4000, _PAGE_IO);
        io_block_mapping(PCI_IDE_ADDR, PCI_IDE_ADDR, 0x4000, _PAGE_IO);
#endif
#endif
#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
	io_block_mapping(RPX_CSR_ADDR, RPX_CSR_ADDR, RPX_CSR_SIZE, _PAGE_IO);
#if !defined(CONFIG_PCI)
	io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
#endif
#endif
#if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
	io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
#endif
#ifdef CONFIG_FADS
	io_block_mapping(BCSR_ADDR, BCSR_ADDR, BCSR_SIZE, _PAGE_IO);
	io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
#endif
#ifdef CONFIG_PCI
        io_block_mapping(PCI_ISA_IO_ADDR, PCI_ISA_IO_ADDR, PCI_ISA_IO_SIZE,
			 _PAGE_IO);
        io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
#endif
}

void __init
platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
		unsigned long r6, unsigned long r7)
{
	parse_bootinfo(find_bootinfo());

	if ( r3 )
		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );

#ifdef CONFIG_BLK_DEV_INITRD
	/* take care of initrd if we have one */
	if ( r4 )
	{
		initrd_start = r4 + KERNELBASE;
		initrd_end = r5 + KERNELBASE;
	}
#endif /* CONFIG_BLK_DEV_INITRD */
	/* take care of cmd line */
	if ( r6 )
	{
		*(char *)(r7+KERNELBASE) = 0;
		strcpy(cmd_line, (char *)(r6+KERNELBASE));
	}

#ifdef CONFIG_PCI
	isa_io_base = _IO_BASE;
	isa_mem_base = _ISA_MEM_BASE;
	pci_dram_offset = PCI_DRAM_OFFSET;
#endif

	ppc_md.setup_arch		= m8xx_setup_arch;
	ppc_md.show_percpuinfo		= m8xx_show_percpuinfo;
	ppc_md.irq_cannonicalize	= NULL;
	ppc_md.init_IRQ			= m8xx_init_IRQ;
	ppc_md.get_irq			= m8xx_get_irq;
	ppc_md.init			= NULL;

	ppc_md.restart			= m8xx_restart;
	ppc_md.power_off		= m8xx_power_off;
	ppc_md.halt			= m8xx_halt;

	ppc_md.time_init		= NULL;
	ppc_md.set_rtc_time		= m8xx_set_rtc_time;
	ppc_md.get_rtc_time		= m8xx_get_rtc_time;
	ppc_md.calibrate_decr		= m8xx_calibrate_decr;

	ppc_md.find_end_of_memory	= m8xx_find_end_of_memory;
	ppc_md.setup_io_mappings	= m8xx_map_io;

	ppc_md.kbd_setkeycode		= NULL;
	ppc_md.kbd_getkeycode		= NULL;
	ppc_md.kbd_translate		= NULL;
	ppc_md.kbd_unexpected_up	= NULL;
	ppc_md.kbd_leds			= NULL;
	ppc_md.kbd_init_hw		= NULL;
	ppc_md.ppc_kbd_sysrq_xlate	= NULL;

#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
#if defined(CONFIG_BLK_DEV_MPC8xx_IDE)
	m8xx_ide_init();
#else
	ppc_ide_md.ide_request_region 	= m8xx_ide_request_region;
	ppc_ide_md.ide_release_region 	= m8xx_ide_release_region;
	ppc_ide_md.ide_check_region 	= m8xx_ide_check_region;
	ppc_ide_md.default_irq		= m8xx_ide_default_irq;
	ppc_ide_md.default_io_base	= m8xx_ide_default_io_base;
	/* The default ppc_ide_md.ide_init_hwif function is sufficient. */
#endif	/* if defined(CONFIG_BLK_DEV_MPC8xx_IDE) */
#endif	/* if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */

#ifdef CONFIG_DUMMY_CONSOLE
	conswitchp = &dummy_con;
#endif
}

^ permalink raw reply

* Re: PPC32 memory models
From: Paul Mackerras @ 2005-11-29  1:58 UTC (permalink / raw)
  To: Andy Whitcroft; +Cc: linuxppc-dev, Anton Blanchard
In-Reply-To: <438B5523.40903@shadowen.org>

Andy Whitcroft writes:

> Attached is a patch to enable FLATMEM and disable SPARSEMEM for PPC32
> which seems to be the working combinations.  It may well not be what is
> intended.  But I offer it to start discussions.

Sounds right.

>  config ARCH_SPARSEMEM_DEFAULT
>  	def_bool y
> -	depends on SMP && PPC_PSERIES
> +	depends on SMP && PPC_PSERIES && NUMA

Shouldn't this depend on ARCH_SPARSEMEM_ENABLE?

Paul.

^ permalink raw reply

* Re: Which way to store log in flash on mpc8xx?
From: David Ho @ 2005-11-29  1:06 UTC (permalink / raw)
  To: Wolfgang Denk; +Cc: David Jander, linuxppc-embedded
In-Reply-To: <20050920180758.9020C353AB3@atlas.denx.de>

Hi, just catching up on this problem as I have another unit that
showed the same symptom.
My system looks like this

MPC852T
128Mbytes SDRAM
64Mbytes Flash

Flash partitions
2*1.25Mbytes partitions for Kernel
61.5Mbytes for rootfs and applications.
Remaining 1Mbyte for U-boot, u-boot env and spare.

I get that same problem as well.  kernel BUG at gc.c: 139

I have compiled Perl, Openssl, Openssh, etc running NFS so SDRAM is
definitely not the issue.

David: have you gotten any new insights since?

Regards,
David Ho


On 9/20/05, Wolfgang Denk <wd@denx.de> wrote:
> In message <200509201117.40454.david.jander@protonic.nl> you wrote:
> >
> > Is there something like memtest86 for linux-ppc (i.e. written in portab=
le C)?
>
> Yes, there is. Run the system with root file system mounted over NFS,
> and then put some load on the system, like  by  compiling  the  linux
> kernel  on  the  target.  Anything  else which adds DMA load does not
> hurt, either. In such a situation, with a lots of  context  switches,
> stress  on  the  memory  management  system  and having a lots of DMA
> traffic going on you may see some memory problems. Unfortunately none
> of the standard memory tests will catch thse, as  the  tests  usually
> provide  only plain read / write accesses, while the problems show up
> only in burst mode, i. e. when filling the caches and/or doing DMA.
>
> There is an attempt of a burst mode memory test in the  U-Boot  code,
> but  I  have to admit that I didn't work to show the exact problem on
> the system it was written for.
>
> > Hmm, but.... there is no data corruption. I have not seen one file on f=
lash
> > that had other data than intended, and that inspite of the GC freaking =
out.
>
> Maybe there is no corruption of the data in flash. But are  you  sure
> that  correct  data are loaded to and read from RAM? We had a similar
> problem on a board where data got corrupted only when doing a lot  of
> transfers flash->RAM.
>
> > That commit only changed 3 files, non of them directly related to jffs2=
 code,
>
> This is correct.
>
> > and only seemed to add support for FUJITSU flash chips. What am I missi=
ng?
> > MTD developers say that cvs from march-2005 _is_ broken, so there must =
be some
>
> Yes, of course it's broken. Like  all  computer  code.  There  are  a
> couple  of  known  issues  (especially  with NAND flash), but I don't
> think they could explain the type of problems you are seeing.
>
> Best regards,
>
> Wolfgang Denk
>
> --
> Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
> Einstein argued that there must be simplified explanations of nature,
> because God is not capricious or arbitrary. No  such  faith  comforts
> the software engineer.                             - Fred Brooks, Jr.
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>

^ permalink raw reply

* [PATCH] 3/3 Generic sys_rt_sigsuspend
From: David Woodhouse @ 2005-11-29  0:57 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, linuxppc-dev, drepper
In-Reply-To: <1133225007.31573.86.camel@baythorne.infradead.org>

The TIF_RESTORE_SIGMASK flag allows us to have a generic implementation
of sys_rt_sigsuspend() instead of duplicating it for each architecture.
This provides such an implementation and makes arch/powerpc use it.

It also tidies up the ppc32 sys_sigsuspend() to use TIF_RESTORE_SIGMASK.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>

--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -252,8 +252,7 @@ int do_signal(sigset_t *oldset, struct p
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
-	       struct pt_regs *regs)
+long sys_sigsuspend(old_sigset_t mask)
 {
 	sigset_t saveset;
 
@@ -264,55 +263,10 @@ long sys_sigsuspend(old_sigset_t mask, i
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	regs->result = -EINTR;
-	regs->gpr[3] = EINTR;
-	regs->ccr |= 0x10000000;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&saveset, regs)) {
-			set_thread_flag(TIF_RESTOREALL);
-			return 0;
-		}
-	}
-}
-
-long sys_rt_sigsuspend(
-#ifdef CONFIG_PPC64
-		compat_sigset_t __user *unewset,
-#else
-		sigset_t __user *unewset,
-#endif
-		size_t sigsetsize, int p3, int p4,
-		int p6, int p7, struct pt_regs *regs)
-{
-	sigset_t saveset, newset;
-
-	/* XXX: Don't preclude handling different sized sigset_t's.  */
-	if (sigsetsize != sizeof(sigset_t))
-		return -EINVAL;
-
-	if (get_sigset_t(&newset, unewset))
-		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs->result = -EINTR;
-	regs->gpr[3] = EINTR;
-	regs->ccr |= 0x10000000;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&saveset, regs)) {
-			set_thread_flag(TIF_RESTOREALL);
-			return 0;
-		}
-	}
+ 	current->state = TASK_INTERRUPTIBLE;
+ 	schedule();
+ 	set_thread_flag(TIF_RESTORE_SIGMASK);
+ 	return -ERESTARTNOHAND;
 }
 
 #ifdef CONFIG_PPC32
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 5462bef..7a6f0f7 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -67,42 +67,6 @@ struct rt_sigframe {
 	char abigap[288];
 } __attribute__ ((aligned (16)));
 
-
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4,
-		       int p6, int p7, struct pt_regs *regs)
-{
-	sigset_t saveset, newset;
-
-	/* XXX: Don't preclude handling different sized sigset_t's.  */
-	if (sigsetsize != sizeof(sigset_t))
-		return -EINVAL;
-
-	if (copy_from_user(&newset, unewset, sizeof(newset)))
-		return -EFAULT;
-	sigdelsetmask(&newset, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs->result = -EINTR;
-	regs->gpr[3] = EINTR;
-	regs->ccr |= 0x10000000;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&saveset, regs)) {
-			set_thread_flag(TIF_RESTOREALL);
-			return 0;
-		}
-	}
-}
-
 long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5,
 		     unsigned long r6, unsigned long r7, unsigned long r8,
 		     struct pt_regs *regs)
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -444,11 +446,13 @@ type name(type1 arg1, type2 arg2, type3 
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #ifdef CONFIG_PPC32
 #define __ARCH_WANT_OLD_STAT
 #endif
 #ifdef CONFIG_PPC64
 #define __ARCH_WANT_COMPAT_SYS_TIME
+#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 #endif
 
 /*
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -855,3 +855,31 @@ asmlinkage long compat_sys_stime(compat_
 }
 
 #endif /* __ARCH_WANT_COMPAT_SYS_TIME */
+
+#ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
+long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize)
+{
+	sigset_t saveset, newset;
+	compat_sigset_t newset32;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t)))
+		return -EFAULT;
+	sigset_from_compat(&newset, &newset32);
+	sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
+
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
+}
+#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
diff --git a/kernel/signal.c b/kernel/signal.c
index d7611f1..5e4c240 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2623,6 +2623,32 @@ sys_pause(void)
 
 #endif
 
+#ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
+long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
+{
+	sigset_t saveset, newset;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
+
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
+}
+#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
+
 void __init signals_init(void)
 {
 	sigqueue_cachep =

-- 
dwmw2

^ permalink raw reply related

* [PATCH] 2/3 Add TIF_RESTORE_SIGMASK support for arch/powerpc
From: David Woodhouse @ 2005-11-29  0:57 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, linuxppc-dev, drepper
In-Reply-To: <1133225007.31573.86.camel@baythorne.infradead.org>

This patch implements the TIF_RESTORE_SIGMASK flag in the new
arch/powerpc kernel, for both 32-bit and 64-bit system call paths.

Mostly tested on 32-bit so far.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>

diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 036b71d..6aa7386 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -227,7 +227,7 @@ ret_from_syscall:
 	MTMSRD(r10)
 	lwz	r9,TI_FLAGS(r12)
 	li	r8,-_LAST_ERRNO
-	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_RESTORE_SIGMASK)
 	bne-	syscall_exit_work
 	cmplw	0,r3,r8
 	blt+	syscall_exit_cont
@@ -357,7 +357,7 @@ save_user_nvgprs_cont:
 	lwz	r5,_MSR(r1)
 	andi.	r5,r5,MSR_PR
 	beq	ret_from_except
-	andi.	r0,r9,_TIF_SIGPENDING
+	andi.	r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK
 	beq	ret_from_except
 	b	do_user_signal
 8:
@@ -683,7 +683,7 @@ user_exc_return:		/* r10 contains MSR_KE
 	/* Check current_thread_info()->flags */
 	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
 	lwz	r9,TI_FLAGS(r9)
-	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
+	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_RESTORE_SIGMASK)
 	bne	do_work
 
 restore_user:
@@ -917,7 +917,7 @@ recheck:
 	lwz	r9,TI_FLAGS(r9)
 	andi.	r0,r9,_TIF_NEED_RESCHED
 	bne-	do_resched
-	andi.	r0,r9,_TIF_SIGPENDING
+	andi.	r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK
 	beq	restore_user
 do_user_signal:			/* r10 contains MSR_KERNEL here */
 	ori	r10,r10,MSR_EE
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 2eb6f54..22e592d 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -160,7 +160,7 @@ syscall_exit:
 	mtmsrd	r10,1
 	ld	r9,TI_FLAGS(r12)
 	li	r11,-_LAST_ERRNO
-	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR)
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR|_TIF_RESTORE_SIGMASK)
 	bne-	syscall_exit_work
 	cmpld	r3,r11
 	ld	r5,_CCR(r1)
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -1177,7 +1131,7 @@ int do_signal(sigset_t *oldset, struct p
 {
 	siginfo_t info;
 	struct k_sigaction ka;
-	unsigned int frame, newsp;
+	unsigned int newsp;
 	int signr, ret;
 
 #ifdef CONFIG_PPC32
@@ -1188,11 +1142,11 @@ int do_signal(sigset_t *oldset, struct p
 	}
 #endif
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else if (!oldset)
 		oldset = &current->blocked;
 
-	newsp = frame = 0;
-
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 #ifdef CONFIG_PPC32
 no_signal:
@@ -1222,8 +1176,14 @@ no_signal:
 		}
 	}
 
-	if (signr == 0)
+	if (signr == 0) {
+		/* No signal to deliver -- put the saved sigmask back */
+		if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+			clear_thread_flag(TIF_RESTORE_SIGMASK);
+			sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+		}
 		return 0;		/* no signals delivered */
+	}
 
 	if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
 	    && !on_sig_stack(regs->gpr[1]))
@@ -1256,6 +1216,10 @@ no_signal:
 			sigaddset(&current->blocked, signr);
 		recalc_sigpending();
 		spin_unlock_irq(&current->sighand->siglock);
+		/* A signal was successfully delivered; the saved sigmask is in
+		   its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
+		if (test_thread_flag(TIF_RESTORE_SIGMASK))
+			clear_thread_flag(TIF_RESTORE_SIGMASK);
 	}
 
 	return ret;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 5462bef..7a6f0f7 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -554,11 +518,15 @@ int do_signal(sigset_t *oldset, struct p
 	if (test_thread_flag(TIF_32BIT))
 		return do_signal32(oldset, regs);
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else if (!oldset)
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
+		int ret;
+
 		/* Whee!  Actually deliver the signal.  */
 		if (TRAP(regs) == 0x0C00)
 			syscall_restart(regs, &ka);
@@ -571,7 +539,14 @@ int do_signal(sigset_t *oldset, struct p
 		if (current->thread.dabr)
 			set_dabr(current->thread.dabr);
 
-		return handle_signal(signr, &ka, &info, oldset, regs);
+		ret = handle_signal(signr, &ka, &info, oldset, regs);
+
+		/* If a signal was successfully delivered, the saved sigmask is in
+		   its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
+		if (ret && test_thread_flag(TIF_RESTORE_SIGMASK))
+			clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+		return ret;
 	}
 
 	if (TRAP(regs) == 0x0C00) {	/* System Call! */
@@ -587,6 +562,11 @@ int do_signal(sigset_t *oldset, struct p
 			regs->result = 0;
 		}
 	}
+	/* No signal to deliver -- put the saved sigmask back */
+	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+		clear_thread_flag(TIF_RESTORE_SIGMASK);
+		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+	}
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S
index 989f628..70bfff2 100644
--- a/arch/powerpc/kernel/systbl.S
+++ b/arch/powerpc/kernel/systbl.S
@@ -321,3 +321,5 @@ SYSCALL(inotify_add_watch)
 SYSCALL(inotify_rm_watch)
 SYSCALL(spu_run)
 SYSCALL(spu_create)
+COMPAT_SYS(pselect6)
+COMPAT_SYS(ppoll)	
diff --git a/fs/compat.c b/fs/compat.c
index 8186341..51747b9 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -125,6 +125,7 @@ static inline struct thread_info *curren
 #define TIF_RESTOREALL		12	/* Restore all regs (implies NOERROR) */
 #define TIF_SAVE_NVGPRS		13	/* Save r14-r31 in signal frame */
 #define TIF_NOERROR		14	/* Force successful syscall return */
+#define TIF_RESTORE_SIGMASK	15	/* Restore signal mask in do_signal */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -141,10 +142,12 @@ static inline struct thread_info *curren
 #define _TIF_RESTOREALL		(1<<TIF_RESTOREALL)
 #define _TIF_SAVE_NVGPRS	(1<<TIF_SAVE_NVGPRS)
 #define _TIF_NOERROR		(1<<TIF_NOERROR)
+#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
 
 #define _TIF_USER_WORK_MASK	(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
-				 _TIF_NEED_RESCHED | _TIF_RESTOREALL)
+				 _TIF_NEED_RESCHED | _TIF_RESTOREALL | \
+				 _TIF_RESTORE_SIGMASK)
 #define _TIF_PERSYSCALL_MASK	(_TIF_RESTOREALL|_TIF_NOERROR|_TIF_SAVE_NVGPRS)
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index 19eaac3..a40cdff 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -298,8 +298,10 @@
 #define __NR_inotify_rm_watch	277
 #define __NR_spu_run		278
 #define __NR_spu_create		279
+#define __NR_pselect6		280
+#define __NR_ppoll		281
 
-#define __NR_syscalls		280
+#define __NR_syscalls		282
 
 #ifdef __KERNEL__
 #define __NR__exit __NR_exit

-- 
dwmw2

^ permalink raw reply related

* [PATCH] 1/3 Add pselect/ppoll() system calls
From: David Woodhouse @ 2005-11-29  0:57 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, linuxppc-dev, drepper
In-Reply-To: <1133225007.31573.86.camel@baythorne.infradead.org>

This patch adds the pselect() and ppoll() system calls. Most of this
implementation is as it was in the -mm kernel for a period of time
already before the difficulties with signal delivery became apparent.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>

diff --git a/fs/select.c b/fs/select.c
index f10a103..4e0da96 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -179,12 +179,11 @@ get_max:
 #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
 #define POLLEX_SET (POLLPRI)
 
-int do_select(int n, fd_set_bits *fds, long *timeout)
+int do_select(int n, fd_set_bits *fds, int64_t *timeout)
 {
 	struct poll_wqueues table;
 	poll_table *wait;
 	int retval, i;
-	long __timeout = *timeout;
 
 	rcu_read_lock();
 	retval = max_select_fd(n, fds);
@@ -196,11 +195,12 @@ int do_select(int n, fd_set_bits *fds, l
 
 	poll_initwait(&table);
 	wait = &table.pt;
-	if (!__timeout)
+	if (!*timeout)
 		wait = NULL;
 	retval = 0;
 	for (;;) {
 		unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
+		long __timeout;
 
 		set_current_state(TASK_INTERRUPTIBLE);
 
@@ -255,22 +255,32 @@ int do_select(int n, fd_set_bits *fds, l
 				*rexp = res_ex;
 		}
 		wait = NULL;
-		if (retval || !__timeout || signal_pending(current))
+		if (retval || !*timeout || signal_pending(current))
 			break;
 		if(table.error) {
 			retval = table.error;
 			break;
 		}
+
+		if (*timeout < 0) {
+			/* Wait indefinitely */
+			__timeout = MAX_SCHEDULE_TIMEOUT;
+		} else if (unlikely(*timeout >= (int64_t)MAX_SCHEDULE_TIMEOUT - 1)) {
+			/* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in a loop */
+			__timeout = MAX_SCHEDULE_TIMEOUT - 1;
+			*timeout -= __timeout;
+		} else {
+			__timeout = *timeout;
+			*timeout = 0;
+		}
 		__timeout = schedule_timeout(__timeout);
+		if (*timeout >= 0)
+			*timeout += __timeout;
 	}
 	__set_current_state(TASK_RUNNING);
 
 	poll_freewait(&table);
 
-	/*
-	 * Up-to-date the caller timeout.
-	 */
-	*timeout = __timeout;
 	return retval;
 }
 
@@ -295,36 +305,14 @@ static void select_bits_free(void *bits,
 #define MAX_SELECT_SECONDS \
 	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 
-asmlinkage long
-sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp)
+static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+			   fd_set __user *exp, int64_t *timeout)
 {
 	fd_set_bits fds;
 	char *bits;
-	long timeout;
 	int ret, size, max_fdset;
 	struct fdtable *fdt;
 
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp) {
-		time_t sec, usec;
-
-		if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
-		    || __get_user(sec, &tvp->tv_sec)
-		    || __get_user(usec, &tvp->tv_usec)) {
-			ret = -EFAULT;
-			goto out_nofds;
-		}
-
-		ret = -EINVAL;
-		if (sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = ROUND_UP(usec, 1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
 	ret = -EINVAL;
 	if (n < 0)
 		goto out_nofds;
@@ -362,18 +350,7 @@ sys_select(int n, fd_set __user *inp, fd
 	zero_fd_set(n, fds.res_out);
 	zero_fd_set(n, fds.res_ex);
 
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		put_user(sec, &tvp->tv_sec);
-		put_user(usec, &tvp->tv_usec);
-	}
+	ret = do_select(n, &fds, timeout);
 
 	if (ret < 0)
 		goto out;
@@ -395,6 +372,150 @@ out_nofds:
 	return ret;
 }
 
+asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+			fd_set __user *exp, struct timeval __user *tvp)
+{
+	int64_t timeout = -1;
+	struct timeval tv;
+	int ret;
+
+	if (tvp) {
+		if (copy_from_user(&tv, tvp, sizeof(tv)))
+			return -EFAULT;
+
+		if (tv.tv_sec < 0 || tv.tv_usec < 0)
+			return -EINVAL;
+
+		/* Cast to uint64_t to make GCC stop complaining */
+		if ((uint64_t)tv.tv_sec >= (uint64_t)MAX_INT64_SECONDS)
+			timeout = -1;	/* infinite */
+		else {
+			timeout = ROUND_UP(tv.tv_sec, 1000000/HZ);
+			timeout += tv.tv_sec * HZ;
+		}
+	}
+
+	ret = core_sys_select(n, inp, outp, exp, &timeout);
+
+	if (tvp) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		tv.tv_usec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ));
+		tv.tv_sec = timeout;
+		if (copy_to_user(tvp, &tv, sizeof(tv))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND)
+				ret = -EINTR;
+		}
+	}
+
+	return ret;
+}
+
+#ifdef TIF_RESTORE_SIGMASK
+asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp,
+		fd_set __user *exp, struct timespec __user *tsp,
+		const sigset_t __user *sigmask, size_t sigsetsize)
+{
+	int64_t timeout = MAX_SCHEDULE_TIMEOUT;
+	sigset_t ksigmask, sigsaved;
+	struct timespec ts;
+	int ret;
+
+	if (tsp) {
+		if (copy_from_user(&ts, tsp, sizeof(ts)))
+			return -EFAULT;
+
+		if (ts.tv_sec < 0 || ts.tv_nsec < 0)
+			return -EINVAL;
+
+		/* Cast to uint64_t to make GCC stop complaining */
+		if ((uint64_t)ts.tv_sec >= (uint64_t)MAX_INT64_SECONDS)
+			timeout = -1;	/* infinite */
+		else {
+			timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ);
+			timeout += ts.tv_sec * HZ;
+		}
+	}
+
+	if (sigmask) {
+		/* XXX: Don't preclude handling different sized sigset_t's.  */
+		if (sigsetsize != sizeof(sigset_t))
+			return -EINVAL;
+		if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
+			return -EFAULT;
+
+		sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+	}
+
+	ret = core_sys_select(n, inp, outp, exp, &timeout);
+
+	if (tsp) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		ts.tv_nsec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ)) * 1000;
+		ts.tv_sec = timeout;
+		if (copy_to_user(tsp, &ts, sizeof(ts))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND)
+				ret = -EINTR;
+		}
+	}
+
+	if (ret == -ERESTARTNOHAND) {
+		/* Don't restore the signal mask yet. Let do_signal() deliver the signal
+		   on the way back to userspace, before the signal mask is restored. */
+		if (sigmask) {
+			memcpy(&current->saved_sigmask, &sigsaved, sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+	} else if (sigmask)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+	return ret;
+}
+
+/*
+ * Most architectures can't handle 7-argument syscalls. So we provide a
+ * 6-argument version where the sixth argument is a pointer to a structure
+ * which has a pointer to the sigset_t itself followed by a size_t containing
+ * the sigset size.
+ */
+asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp,
+	fd_set __user *exp, struct timespec __user *tsp, void __user *sig)
+{
+	size_t sigsetsize = 0;
+	sigset_t __user *up = NULL;
+
+	if (sig) {
+		if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t))
+		    || __get_user(up, (sigset_t * __user *)sig)
+		    || __get_user(sigsetsize,
+				(size_t * __user)(sig+sizeof(void *))))
+			return -EFAULT;
+	}
+
+	return sys_pselect7(n, inp, outp, exp, tsp, up, sigsetsize);
+}
+#endif /* TIF_RESTORE_SIGMASK */
+
 struct poll_list {
 	struct poll_list *next;
 	int len;
@@ -436,16 +557,19 @@ static void do_pollfd(unsigned int num, 
 }
 
 static int do_poll(unsigned int nfds,  struct poll_list *list,
-			struct poll_wqueues *wait, long timeout)
+		   struct poll_wqueues *wait, int64_t *timeout)
 {
 	int count = 0;
 	poll_table* pt = &wait->pt;
 
-	if (!timeout)
+	/* Optimise the no-wait case */
+	if (!(*timeout))
 		pt = NULL;
  
 	for (;;) {
 		struct poll_list *walk;
+		long __timeout;
+
 		set_current_state(TASK_INTERRUPTIBLE);
 		walk = list;
 		while(walk != NULL) {
@@ -453,18 +577,33 @@ static int do_poll(unsigned int nfds,  s
 			walk = walk->next;
 		}
 		pt = NULL;
-		if (count || !timeout || signal_pending(current))
+		if (count || !*timeout || signal_pending(current))
 			break;
 		count = wait->error;
 		if (count)
 			break;
-		timeout = schedule_timeout(timeout);
+
+		if (*timeout < 0) {
+			/* Wait indefinitely */
+			__timeout = MAX_SCHEDULE_TIMEOUT;
+		} else if (unlikely(*timeout >= (int64_t)MAX_SCHEDULE_TIMEOUT - 1)) {
+			/* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in a loop */
+			__timeout = MAX_SCHEDULE_TIMEOUT - 1;
+			*timeout -= __timeout;
+		} else {
+			__timeout = *timeout;
+			*timeout = 0;
+		}
+
+		__timeout = schedule_timeout(__timeout);
+		if (*timeout >= 0)
+			*timeout += __timeout;
 	}
 	__set_current_state(TASK_RUNNING);
 	return count;
 }
 
-asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long timeout)
+int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, int64_t *timeout)
 {
 	struct poll_wqueues table;
  	int fdcount, err;
@@ -482,14 +621,6 @@ asmlinkage long sys_poll(struct pollfd _
 	if (nfds > max_fdset && nfds > OPEN_MAX)
 		return -EINVAL;
 
-	if (timeout) {
-		/* Careful about overflow in the intermediate values */
-		if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ)
-			timeout = (unsigned long)(timeout*HZ+999)/1000+1;
-		else /* Negative or overflow */
-			timeout = MAX_SCHEDULE_TIMEOUT;
-	}
-
 	poll_initwait(&table);
 
 	head = NULL;
@@ -519,6 +650,7 @@ asmlinkage long sys_poll(struct pollfd _
 		}
 		i -= pp->len;
 	}
+
 	fdcount = do_poll(nfds, head, &table, timeout);
 
 	/* OK, now copy the revents fields back to user space. */
@@ -547,3 +679,94 @@ out_fds:
 	poll_freewait(&table);
 	return err;
 }
+
+asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
+			long timeout_msecs)
+{
+	int64_t timeout_jiffies = 0;
+
+	if (timeout_msecs) {
+#if HZ > 1000
+		/* We can only overflow if HZ > 1000 */
+		if (timeout_msecs / 1000 > (int64_t)0x7fffffffffffffffULL / (int64_t)HZ)
+			timeout_jiffies = -1;
+		else
+#endif
+			timeout_jiffies = msecs_to_jiffies(timeout_msecs);
+	}
+
+	return do_sys_poll(ufds, nfds, &timeout_jiffies);
+}
+
+#ifdef TIF_RESTORE_SIGMASK
+asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
+	struct timespec __user *tsp, const sigset_t __user *sigmask,
+	size_t sigsetsize)
+{
+	sigset_t ksigmask, sigsaved;
+	struct timespec ts;
+	int64_t timeout = -1;
+	int ret;
+
+	if (tsp) {
+		if (copy_from_user(&ts, tsp, sizeof(ts)))
+			return -EFAULT;
+
+		/* Cast to uint64_t to make GCC stop complaining */
+		if ((uint64_t)ts.tv_sec >= (uint64_t)MAX_INT64_SECONDS)
+			timeout = -1;	/* infinite */
+		else {
+			timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ);
+			timeout += ts.tv_sec * HZ;
+		}
+	}
+
+	if (sigmask) {
+		/* XXX: Don't preclude handling different sized sigset_t's.  */
+		if (sigsetsize != sizeof(sigset_t))
+			return -EINVAL;
+		if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
+			return -EFAULT;
+
+		sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+	}
+
+	ret = do_sys_poll(ufds, nfds, &timeout);
+
+	/* We can restart this syscall, usually */
+	if (ret == -EINTR) {
+		/* Don't restore the signal mask yet. Let do_signal() deliver the signal
+		   on the way back to userspace, before the signal mask is restored. */
+		if (sigmask) {
+			memcpy(&current->saved_sigmask, &sigsaved, sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+		ret = -ERESTARTNOHAND;
+	} else if (sigmask)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+	if (tsp && timeout >= 0) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		/* Yes, we know it's actually an int64_t, but it's also positive. */
+		ts.tv_nsec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ)) * 1000;
+		ts.tv_sec = timeout;
+		if (copy_to_user(tsp, &ts, sizeof(ts))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND && timeout >= 0)
+				ret = -EINTR;
+		}
+	}
+
+	return ret;
+}
+#endif /* TIF_RESTORE_SIGMASK */
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -53,6 +53,8 @@
 #include <asm/mmu_context.h>
 #include <asm/ioctls.h>
 
+extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
+
 /*
  * Not all architectures have sys_utime, so implement this in terms
  * of sys_utimes.
@@ -1607,36 +1609,14 @@ static void select_bits_free(void *bits,
 #define MAX_SELECT_SECONDS \
 	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 
-asmlinkage long
-compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp,
-		compat_ulong_t __user *exp, struct compat_timeval __user *tvp)
+int compat_core_sys_select(int n, compat_ulong_t __user *inp,
+	compat_ulong_t __user *outp, compat_ulong_t __user *exp, int64_t *timeout)
 {
 	fd_set_bits fds;
 	char *bits;
-	long timeout;
 	int size, max_fdset, ret = -EINVAL;
 	struct fdtable *fdt;
 
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp) {
-		time_t sec, usec;
-
-		if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
-		    || __get_user(sec, &tvp->tv_sec)
-		    || __get_user(usec, &tvp->tv_usec)) {
-			ret = -EFAULT;
-			goto out_nofds;
-		}
-
-		if (sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = ROUND_UP(usec, 1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
 	if (n < 0)
 		goto out_nofds;
 
@@ -1673,19 +1653,7 @@ compat_sys_select(int n, compat_ulong_t 
 	zero_fd_set(n, fds.res_out);
 	zero_fd_set(n, fds.res_ex);
 
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		if (put_user(sec, &tvp->tv_sec) ||
-		    put_user(usec, &tvp->tv_usec))
-			ret = -EFAULT;
-	}
+	ret = do_select(n, &fds, timeout);
 
 	if (ret < 0)
 		goto out;
@@ -1706,6 +1674,216 @@ out_nofds:
 	return ret;
 }
 
+asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
+	compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+	struct compat_timeval __user *tvp)
+{
+	int64_t timeout = -1;
+	struct compat_timeval tv;
+	int ret;
+
+	if (tvp) {
+		if (copy_from_user(&tv, tvp, sizeof(tv)))
+			return -EFAULT;
+
+		if (tv.tv_sec < 0 || tv.tv_usec < 0)
+			return -EINVAL;
+
+		/* Cast to uint64_t to make GCC stop complaining */
+		if ((uint64_t)tv.tv_sec >= (uint64_t)MAX_INT64_SECONDS)
+			timeout = -1;	/* infinite */
+		else {
+			timeout = ROUND_UP(tv.tv_sec, 1000000/HZ);
+			timeout += tv.tv_sec * HZ;
+		}
+	}
+
+	ret = compat_core_sys_select(n, inp, outp, exp, &timeout);
+
+	if (tvp) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		tv.tv_usec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ));
+		tv.tv_sec = timeout;
+		if (copy_to_user(tvp, &tv, sizeof(tv))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND)
+				ret = -EINTR;
+		}
+	}
+
+	return ret;
+}
+
+#ifdef TIF_RESTORE_SIGMASK
+asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp,
+	compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+	struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask,
+	compat_size_t sigsetsize)
+{
+	compat_sigset_t s32;
+	sigset_t ksigmask, sigsaved;
+	long timeout = MAX_SCHEDULE_TIMEOUT;
+	struct compat_timespec ts;
+	int ret;
+
+	if (tsp) {
+		if (copy_from_user(&ts, tsp, sizeof(ts)))
+			return -EFAULT;
+
+		if (ts.tv_sec < 0 || ts.tv_nsec < 0)
+			return -EINVAL;
+	}
+
+	if (sigmask) {
+		if (sigsetsize != sizeof(compat_sigset_t))
+			return -EINVAL;
+		if (copy_from_user(&s32, sigmask, sizeof(s32)))
+			return -EFAULT;
+		sigset_from_compat(&ksigmask, &s32);
+
+		sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+	}
+
+	do {
+		if (tsp) {
+			if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) {
+				timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ);
+				timeout += ts.tv_sec * (unsigned long)HZ;
+				ts.tv_sec = 0;
+				ts.tv_nsec = 0;
+			} else {
+				ts.tv_sec -= MAX_SELECT_SECONDS;
+				timeout = MAX_SELECT_SECONDS * HZ;
+			}
+		}
+
+		ret = compat_core_sys_select(n, inp, outp, exp, &timeout);
+
+	} while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec));
+
+	if (tsp && !(current->personality & STICKY_TIMEOUTS)) {
+		ts.tv_sec += timeout / HZ;
+		ts.tv_nsec += (timeout % HZ) * (1000000000/HZ);
+		if (ts.tv_nsec >= 1000000000) {
+			ts.tv_sec++;
+			ts.tv_nsec -= 1000000000;
+		}
+		(void)copy_to_user(tsp, &ts, sizeof(ts));
+	}
+
+	if (ret == -ERESTARTNOHAND) {
+		/* Don't restore the signal mask yet. Let do_signal() deliver the signal
+		   on the way back to userspace, before the signal mask is restored. */
+		if (sigmask) {
+			memcpy(&current->saved_sigmask, &sigsaved, sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+	} else if (sigmask)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+	return ret;
+}
+
+asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
+	compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+	struct compat_timespec __user *tsp, void __user *sig)
+{
+	compat_size_t sigsetsize = 0;
+	compat_uptr_t up = 0;
+
+	if (sig) {
+		if (!access_ok(VERIFY_READ, sig,
+				sizeof(compat_uptr_t)+sizeof(compat_size_t)) ||
+		    	__get_user(up, (compat_uptr_t __user *)sig) ||
+		    	__get_user(sigsetsize,
+				(compat_size_t __user *)(sig+sizeof(up))))
+			return -EFAULT;
+	}
+	return compat_sys_pselect7(n, inp, outp, exp, tsp, compat_ptr(up),
+					sigsetsize);
+}
+
+asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
+	unsigned int nfds, struct compat_timespec __user *tsp,
+	const compat_sigset_t __user *sigmask, compat_size_t sigsetsize)
+{
+	compat_sigset_t s32;
+	sigset_t ksigmask, sigsaved;
+	struct compat_timespec ts;
+	int64_t timeout = -1;
+	int ret;
+
+	if (tsp) {
+		if (copy_from_user(&ts, tsp, sizeof(ts)))
+			return -EFAULT;
+
+		/* We assume that ts.tv_sec is always lower than
+		   the number of seconds that can be expressed in
+		   an int64_t. Otherwise the compiler bitches at us */
+		timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ);
+		timeout += ts.tv_sec * HZ;
+	}
+
+	if (sigmask) {
+		if (sigsetsize |= sizeof(compat_sigset_t))
+			return -EINVAL;
+		if (copy_from_user(&s32, sigmask, sizeof(s32)))
+			return -EFAULT;
+		sigset_from_compat(&ksigmask, &s32);
+
+		sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+	}
+
+	ret = do_sys_poll(ufds, nfds, &timeout);
+
+	/* We can restart this syscall, usually */
+	if (ret == -EINTR) {
+		/* Don't restore the signal mask yet. Let do_signal() deliver the signal
+		   on the way back to userspace, before the signal mask is restored. */
+		if (sigmask) {
+			memcpy(&current->saved_sigmask, &sigsaved, sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		}
+		ret = -ERESTARTNOHAND;
+	} else if (sigmask)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+	if (tsp && timeout >= 0) {
+		if (current->personality & STICKY_TIMEOUTS)
+			goto sticky;
+		/* Yes, we know it's actually an int64_t, but it's also positive. */
+		ts.tv_nsec = jiffies_to_usecs(do_div((*(uint64_t*)&timeout), HZ)) * 1000;
+		ts.tv_sec = timeout;
+		if (copy_to_user(tsp, &ts, sizeof(ts))) {
+		sticky:
+			/*
+			 * If an application puts its timeval in read-only
+			 * memory, we don't want the Linux-specific update to
+			 * the timeval to cause a fault after the select has
+			 * completed successfully. However, because we're not
+			 * updating the timeval, we can't restart the system
+			 * call.
+			 */
+			if (ret == -ERESTARTNOHAND && timeout >= 0)
+				ret = -EINTR;
+		}
+	}
+
+	return ret;
+}
+#endif /* TIF_RESTORE_SIGMASK */
+
 #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
 /* Stuff for NFS server syscalls... */
 struct compat_nfsctl_svc {
diff --git a/include/linux/poll.h b/include/linux/poll.h
index f6da702..5b9c85c 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -92,7 +92,11 @@ void zero_fd_set(unsigned long nr, unsig
 	memset(fdset, 0, FDS_BYTES(nr));
 }
 
-extern int do_select(int n, fd_set_bits *fds, long *timeout);
+#define MAX_INT64_SECONDS (((int64_t)(~((uint64_t)0)>>1)/HZ)-1)
+
+extern int do_select(int n, fd_set_bits *fds, int64_t *timeout);
+extern int do_sys_poll(struct pollfd __user * ufds, unsigned int nfds,
+		       int64_t *timeout);
 
 #endif /* KERNEL */
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2038bd2..bf7db28 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -800,6 +800,7 @@ struct task_struct {
 	struct sighand_struct *sighand;
 
 	sigset_t blocked, real_blocked;
+	sigset_t saved_sigmask;		/* To be restored with TIF_RESTORE_SIGMASK */
 	struct sigpending pending;
 
 	unsigned long sas_ss_sp;



-- 
dwmw2

^ permalink raw reply related

* [PATCH] 0/3 Add pselect/ppoll()
From: David Woodhouse @ 2005-11-29  0:57 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, linuxppc-dev, drepper

The following implementation of ppoll() and pselect() system calls
depends on the architecture providing a TIF_RESTORE_SIGMASK flag in the
thread_info.

These system calls have to change the signal mask during their
operation, and signal handlers must be invoked using the new, temporary
signal mask. The old signal mask must be restored either upon successful
exit from the system call, or upon returning from the invoked signal
handler if the system call is interrupted. We can't simply restore the
original signal mask and return to userspace, since the restored signal
mask may actually block the signal which interrupted the system call.

The TIF_RESTORE_SIGMASK flag deals with this by causing the syscall exit
path to trap into do_signal() just as TIF_SIGPENDING does, and by
causing do_signal() to use the saved signal mask instead of the current
signal mask when setting up the stack frame for the signal handler -- or
by causing do_signal() to simply restore the saved signal mask in the
case where there is no handler to be invoked.

The first patch implements the sys_pselect() and sys_ppoll() system
calls, which are present only if TIF_RESTORE_SIGMASK is defined. That
#ifdef should go away in time when all architectures have implemented
it. The second patch implements TIF_RESTORE_SIGMASK for the PowerPC
kernel (in the -mm tree), and the third patch then removes the
arch-specific implementations of sys_rt_sigsuspend() and replaces them
with generic versions using the same trick.

-- 
dwmw2

^ permalink raw reply

* Problem running kernel 2.6.14 (DENX) on MPC866
From: Gil Madar @ 2005-11-28 23:47 UTC (permalink / raw)
  To: linuxppc-embedded

Hi All,

I load linux from u-boot, and manage to go all the way until the call to cpu_idle() from rest_init().
The system claims mounts a root file system over NFS. Sniffer logs and host logs support this claim.
If I do a while ( 1 ) printk( whatever ), just before cpu_idle(), the system continues to run.
If I let it call cpu_idle(), the system hangs.
If I powercycle the board, I see many occurences of exceptions in the log_buf. They all claim there has
been an access to an invalid address as in "<4>Oops: kernel access of bad area, sig: 11".

The exceptions are never printed and the 'bad address' is offset 0x1C from the IMMR. The access
is from m8xx_get_irq(). 
Has anybody else faced similar problems?
Note: I had to workaround the 
 ppc_md.set_rtc_time  = m8xx_set_rtc_time;
 ppc_md.get_rtc_time  = m8xx_get_rtc_time;
initialisations in m8xx_setup.c.
What additional modifications are needed for the MPC866?
Is there something broken in my setup?
Is there a need for additional information?
As I'm doing this without an emulator, I appreciate any ideas.

Thanks for your time. I appreciate any response,
Gil

Here is a log of the run.


U-Boot 1.1.3 (Nov 22 2005 - 00:26:43)

CPU:   unknown MPC86x (0x08010004) at 133 MHz: 16 kB I-Cache 8 kB D-Cache FEC present
         *** Warning: CPU Core has Silicon Bugs -- Check the Errata ***
Board: IDU()
DRAM:  16 MB
Using default environment

In:    serial
Out:   serial
Err:   serial
Net:   FEC ETHERNET
Monitor Command Prompt:>setenv gatewayip 10.0.0.138;setenv ethaddr 00:01:02:03:04:05; setenv console ttyCPM0,38400n8; setenv
 ipaddr 10.0.0.4;setenv serverip 10.0.0.2;setenv hostname idu;setenv netmask 255.0.0.0; setenv rootpath /mnt/iso1
Monitor Command Prompt:>setenv bootargs root=/dev/nfs  rw nfsroot=$(serverip):$(rootpath) console=$(console) ethaddr=$(ethad
dr)  ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask):$(hostname)::off
Monitor Command Prompt:>tftpboot 600000 uImage
Using FEC ETHERNET device
TFTP from server 10.0.0.2; our IP address is 10.0.0.4
Filename 'uImage'.
Load address: 0x600000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         ####
done
Bytes transferred = 1350694 (149c26 hex)
Monitor Command Prompt:>bootm 600000
## Booting image at 00600000 ...
   Image Name:   Linux-2.6.14
   Image Type:   PowerPC Linux Kernel Image (gzip compressed)
   Data Size:    1350630 Bytes =  1.3 MB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK
## Current stack ends at 0x00F9DBB0 => set upper limit to 0x00800000
## cmdline at 0x007FFF00 ... 0x007FFF90
memstart    = 0x00000000
memsize     = 0x01000000
flashstart  = 0x00000000
flashsize   = 0x00000000
flashoffset = 0x00000000
sramstart   = 0x00000000
sramsize    = 0x00000000
immr_base   = 0x0F000000
bootflags   = 0x00000001
intfreq     =    133 MHz
busfreq     = 66.500 MHz
ethaddr     = 00:01:02:03:04:05
IP addr     = 10.0.0.4
baudrate    =  38400 bps
No initrd
## Transferring control to Linux (at address 00000000) ...
Linux version 2.6.14 (xxxx@yyyy) (gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-10)) #44 Tue Nov 29 00:41:34 IST 2005
Built 1 zonelists
Kernel command line: root=/dev/nfs rw nfsroot=10.0.0.2:/mnt/iso1 console=ttyCPM0,38400n8 ethaddr=00:01:02:03:04:05 ip=10.0.0
.4:10.0.0.2:10.0.0.138:255.0.0.0:idu::off
PID hash table entries: 128 (order: 7, 2048 bytes)
Decrementer Frequency = 498750000/60
Dentry cache hash table entries: 4096 (order: 2, 16384 bytes)
Inode-cache hash table entries: 2048 (order: 1, 8192 bytes)
Memory: 13084k available (2364k kernel code, 656k data, 84k init, 0k highmem)
Mount-cache hash table entries: 512
NET: Registered protocol family 16
NTFS driver 2.1.24 [Flags: R/W].
JFS: nTxBlock = 102, nTxLock = 819
Initializing Cryptographic API
Serial: CPM driver $Revision: 0.01 $
ttyCPM0 at MMIO 0xf000a80 (irq = 20) is a CPM UART
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered
loop: loaded (max 8 devices)
eth0: FEC ENET Version 0.2, FEC irq 3, addr 00:01:02:03:04:05
NET: Registered protocol family 2
IP route cache hash table entries: 256 (order: -2, 1024 bytes)
TCP established hash table entries: 1024 (order: 0, 4096 bytes)
TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
TCP reno registered
TCP bic registered
NET: Registered protocol family 1
NET: Registered protocol family 17
IP-Config: Complete:
      device=eth0, addr=10.0.0.4, mask=255.0.0.0, gw=10.0.0.138,
     host=idu, domain=, nis-domain=(none),
     bootserver=10.0.0.2, rootserver=10.0.0.2, rootpath=
Looking up port of RPC 100003/2 on 10.0.0.2
Looking up port of RPC 100005/1 on 10.0.0.2
VFS: Mounted root (nfs filesystem).
Freeing unused kernel memory: 84k init

---------here the system hangs ----------------- 

^ permalink raw reply

* [PATCH] powerpc: More serial probe fixes (#2)
From: Benjamin Herrenschmidt @ 2005-11-29  0:21 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc64-dev, linuxppc-dev list

This fixes the new serial probe code with some PCI MMIO UARTs, and fixes
CHRP build with ARCH=powerpc.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Index: linux-work/arch/powerpc/kernel/legacy_serial.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/legacy_serial.c	2005-11-29 11:02:28.000000000 +1100
+++ linux-work/arch/powerpc/kernel/legacy_serial.c	2005-11-29 11:21:52.000000000 +1100
@@ -38,15 +38,13 @@ static int __init add_legacy_port(struct
 				  int iotype, phys_addr_t base,
 				  phys_addr_t taddr, unsigned long irq)
 {
-	u32 *clk, *spd, clock;
+	u32 *clk, *spd, clock = BASE_BAUD * 16;
 	int index;
 
 	/* get clock freq. if present */
 	clk = (u32 *)get_property(np, "clock-frequency", NULL);
 	if (clk && *clk)
 		clock = *clk;
-	else
-		clock = BASE_BAUD * 16;
 
 	/* get default speed if present */
 	spd = (u32 *)get_property(np, "current-speed", NULL);
@@ -88,7 +86,7 @@ static int __init add_legacy_port(struct
 	if (iotype == UPIO_PORT)
 		legacy_serial_ports[index].iobase = base;
 	else
-		legacy_serial_ports[index].membase = (void __iomem *)base;
+		legacy_serial_ports[index].mapbase = base;
 	legacy_serial_ports[index].iotype = iotype;
 	legacy_serial_ports[index].uartclk = clock;
 	legacy_serial_ports[index].irq = irq;
@@ -148,17 +146,17 @@ static int __init add_legacy_pci_port(st
 {
 	phys_addr_t addr, base;
 	u32 *addrp;
-	int iotype, index = -1;
+	int iotype, index = -1, lindex = 0;
 
-#if 0
 	/* We only support ports that have a clock frequency properly
 	 * encoded in the device-tree (that is have an fcode). Anything
 	 * else can't be used that early and will be normally probed by
-	 * the generic 8250_pci driver later on.
+	 * the generic 8250_pci driver later on. The reason is that 8250
+	 * compatible UARTs on PCI need all sort of quirks (port offsets
+	 * etc...) that this code doesn't know about
 	 */
 	if (get_property(np, "clock-frequency", NULL) == NULL)
 		return -1;
-#endif
 
 	/* Get the PCI address. Assume BAR 0 */
 	addrp = of_get_pci_address(pci_dev, 0, NULL);
@@ -183,7 +181,23 @@ static int __init add_legacy_pci_port(st
 	if (np != pci_dev) {
 		u32 *reg = (u32 *)get_property(np, "reg", NULL);
 		if (reg && (*reg < 4))
-			index = legacy_serial_count + *reg;
+			index = lindex = *reg;
+	}
+
+	/* Local index means it's the Nth port in the PCI chip. Unfortunately
+	 * the offset to add here is device specific. We know about those
+	 * EXAR ports and we default to the most common case. If your UART
+	 * doesn't work for these settings, you'll have to add your own special
+	 * cases here
+	 */
+	if (device_is_compatible(pci_dev, "pci13a8,152") ||
+	    device_is_compatible(pci_dev, "pci13a8,154") ||
+	    device_is_compatible(pci_dev, "pci13a8,158")) {
+		addr += 0x200 * lindex;
+		base += 0x200 * lindex;
+	} else {
+		addr += 8 * lindex;
+		base += 8 * lindex;
 	}
 
 	/* Add port, irq will be dealt with later. We passed a translated
@@ -264,7 +278,6 @@ void __init find_legacy_serial_ports(voi
 	DBG("legacy_serial_console = %d\n", legacy_serial_console);
 
 	/* udbg is 64 bits only for now, that will change soon though ... */
-#ifdef CONFIG_PPC64
 	while (legacy_serial_console >= 0) {
 		struct legacy_serial_info *info =
 			&legacy_serial_infos[legacy_serial_console];
@@ -281,7 +294,6 @@ void __init find_legacy_serial_ports(voi
 		udbg_init_uart(addr, info->speed, info->clock);
 		break;
 	}
-#endif /* CONFIG_PPC64 */
 
 	DBG(" <- find_legacy_serial_port()\n");
 }
@@ -343,6 +355,15 @@ static void __init fixup_port_pio(int in
 	}
 }
 
+static void __init fixup_port_mmio(int index,
+				   struct device_node *np,
+				   struct plat_serial8250_port *port)
+{
+	DBG("fixup_port_mmio(%d)\n", index);
+
+	port->membase = ioremap(port->mapbase, 0x100);
+}
+
 /*
  * This is called as an arch initcall, hopefully before the PCI bus is
  * probed and/or the 8250 driver loaded since we need to register our
@@ -377,6 +398,8 @@ static int __init serial_dev_init(void)
 			fixup_port_irq(i, np, port);
 		if (port->iotype == UPIO_PORT)
 			fixup_port_pio(i, np, port);
+		if (port->iotype == UPIO_MEM)
+			fixup_port_mmio(i, np, port);
 	}
 
 	DBG("Registering platform serial ports\n");
Index: linux-work/arch/powerpc/platforms/chrp/setup.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/chrp/setup.c	2005-11-24 17:18:42.000000000 +1100
+++ linux-work/arch/powerpc/platforms/chrp/setup.c	2005-11-29 11:26:01.000000000 +1100
@@ -49,7 +49,6 @@
 #include <asm/hydra.h>
 #include <asm/sections.h>
 #include <asm/time.h>
-#include <asm/btext.h>
 #include <asm/i8259.h>
 #include <asm/mpic.h>
 #include <asm/rtas.h>
@@ -58,7 +57,6 @@
 #include "chrp.h"
 
 void rtas_indicator_progress(char *, unsigned short);
-void btext_progress(char *, unsigned short);
 
 int _chrp_type;
 EXPORT_SYMBOL(_chrp_type);
@@ -264,11 +262,6 @@ void __init chrp_setup_arch(void)
 		ppc_md.set_rtc_time	= rtas_set_rtc_time;
 	}
 
-#ifdef CONFIG_BOOTX_TEXT
-	if (ppc_md.progress == NULL && boot_text_mapped)
-		ppc_md.progress = btext_progress;
-#endif
-
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* this is fine for chrp */
 	initrd_below_start_ok = 1;
@@ -522,12 +515,3 @@ void __init chrp_init(void)
 	smp_ops = &chrp_smp_ops;
 #endif /* CONFIG_SMP */
 }
-
-#ifdef CONFIG_BOOTX_TEXT
-void
-btext_progress(char *s, unsigned short hex)
-{
-	btext_drawstring(s);
-	btext_drawstring("\n");
-}
-#endif /* CONFIG_BOOTX_TEXT */

^ permalink raw reply

* Re: PowerBook5,8 - TrackPad update
From: Michael Hanselmann @ 2005-11-29  0:06 UTC (permalink / raw)
  To: Parag Warudkar; +Cc: linuxppc-dev, debian-powerpc, linux-kernel
In-Reply-To: <70210ED5-37CA-40BC-8293-FF1DAA3E8BD5@comcast.net>


[-- Attachment #1.1: Type: text/plain, Size: 988 bytes --]

Hello Parag

> Attached is the code which takes care of above 3 - tested but it
> should be considered half baked for obvious reasons and

I hacked your code some more to make it work on my October 2005
PowerBook 1.67 GHz. The product ID I have, 0x0215, was in none of the
available drivers and the data format is somewhat different.

You find my hacked version attached -- be aware that in its current form
it will not work with any touchpad except 0x0215.

> in addition I added some relayfs write calls [...]

I wrapped them into #if's, so one is not required to have relayfs in the
kernel to use the driver.

> The code might break the existing (old) trackpads as the detection
> might not  be correct.

My changes do that definitively, but it's only a hack.

As far as I see it, all methods can be built into one driver. Is there
already someone working on combining them?

Greets,
Michael

-- 
Gentoo Linux Developer using m0n0wall | http://hansmi.ch/

[-- Attachment #1.2: appletouch.c --]
[-- Type: text/x-csrc, Size: 16927 bytes --]

/*
 * Apple USB Touchpad (for post-February 2005 PowerBooks) driver
 *
 * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
 * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
 * Copyright (C) 2005      Stelian Pop (stelian@popies.net)
 * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
 * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
 * Copyright (C) 2005      Parag Warudkar (parag.warudkar@gmail.com)
 *
 * Thanks to Alex Harper <basilisk@foobox.net> for his inputs.
 * Nov 2005 - Parag Warudkar 
 * 	o Add preliminary support for Oct 2005 Powerbooks 
 * 	  (Doesn't work fully yet)
 * 	o Converted to use input_device_allocate()
 * 	o Added ability to export data via relayfs
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/input.h>
#include <linux/usb_input.h>
#include <linux/debugfs.h>
#include <asm/prom.h>

#if defined(CONFIG_RELAYFS_FS) || defined(CONFIG_RELAYFS_FS_MODULE)
#include <linux/relayfs_fs.h>
#endif

#if !defined(PPC) && !defined(POWERPC)
#error "Module intended for PowerPC based PowerBooks!"
#endif

/* Apple has powerbooks which have the keyboard with different Product IDs */
#define APPLE_VENDOR_ID		0x05AC

#define ATP_DEVICE(prod)					\
	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |   		\
		       USB_DEVICE_ID_MATCH_INT_CLASS |		\
		       USB_DEVICE_ID_MATCH_INT_PROTOCOL,	\
	.idVendor = APPLE_VENDOR_ID,				\
	.idProduct = (prod),					\
	.bInterfaceClass = 0x03,				\
	.bInterfaceProtocol = 0x02

/* table of devices that work with this driver */
static struct usb_device_id atp_table [] = {
	/* Earlier PowerBooks */
	{ ATP_DEVICE(0x020E) },
	{ ATP_DEVICE(0x020F) },
	{ ATP_DEVICE(0x030A) },
	{ ATP_DEVICE(0x030B) },

	/* PowerBooks Late Oct 2005 */
	{ ATP_DEVICE(0x0214) },
	{ ATP_DEVICE(0x0215) },

	/* Terminating entry */
	{ }
};
MODULE_DEVICE_TABLE (usb, atp_table);

#if defined(CONFIG_RELAYFS_FS) || defined(CONFIG_RELAYFS_FS_MODULE)
struct rchan* rch = NULL;
struct rchan_callbacks* rcb = NULL;
#endif

/*
 * number of sensors. Note that only 16 instead of 26 X (horizontal)
 * sensors exist on 12" and 15" PowerBooks. All models have 16 Y
 * (vertical) sensors.
 */
#define ATP_MAX_XSENSORS	15
#define ATP_MAX_YSENSORS	7

/* amount of fuzz this touchpad generates */
#define ATP_FUZZ	16

/* maximum pressure this driver will report */
#define ATP_PRESSURE	300

/*
 * multiplication factor for the X and Y coordinates.
 * We try to keep the touchpad aspect ratio while still doing only simple
 * arithmetics.
 * The factors below give coordinates like:
 * 	0 <= x <  960 on 12" and 15" Powerbooks
 * 	0 <= x < 1600 on 17" Powerbooks
 * 	0 <= y <  646
 */
#define ATP_XFACT	64
#define ATP_YFACT	43

/*
 * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
 * ignored.
 */
#define ATP_THRESHOLD	 5

typedef enum PB_MAC_TYPE {
	PowerBook54,
	PowerBook56,
	PowerBook58,
	PowerBook59,
	Unknown
} PB_MAC_TYPE;


/* Structure to hold all of our device specific stuff */
struct atp {
	struct usb_device *	udev;		/* usb device */
	struct urb *		urb;		/* usb request block */
	signed char *		data;		/* transferred data */
	int			open;		/* non-zero if opened */
	struct input_dev	*input;		/* input dev */
	int			valid;		/* are the sensors valid ? */
	int			x_old;		/* last reported x/y, */
	int			y_old;		/* used for smoothing */
						/* current value of the sensors */
	signed char		xy_cur[ATP_MAX_XSENSORS + ATP_MAX_YSENSORS];
						/* last value of the sensors */
	signed char		xy_old[ATP_MAX_XSENSORS + ATP_MAX_YSENSORS];
						/* accumulated sensors */
	int			xy_acc[ATP_MAX_XSENSORS + ATP_MAX_YSENSORS];
	PB_MAC_TYPE		mtype;
};

#define dbg_dump(msg, tab) \
	if (debug > 1) {						\
		int i;							\
		printk("appletouch: %s %lld", msg, (long long)jiffies); \
		for (i = 0; i < ATP_MAX_XSENSORS + ATP_MAX_YSENSORS; i++)	\
			printk(" %02x", tab[i]); 			\
		printk("\n"); 						\
	}

#define dprintk(format, a...) 						\
	do {								\
		if (debug) printk(format, ##a);				\
	} while (0)

MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Parag Warudkar");
MODULE_DESCRIPTION("Apple Al PowerBook USB touchpad driver");
MODULE_LICENSE("GPL");

static int debug = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activate debugging output");

/* USB URB buffer length - 81 works on Feb 05 models.
 * Oct 05 models fail with EOVERFLOW, detected and corrected 
 * separately.
 */
//static int data_len = 81;
static int data_len = 80;
module_param(data_len, int, 0644);
MODULE_PARM_DESC(data_len, "Specify USB URB buffer length (auto-detected normally)");

PB_MAC_TYPE atp_machine_detect(void)
{
	if(machine_is_compatible("PowerBook5,9"))
		return PowerBook59;
	if(machine_is_compatible("PowerBook5,8"))
		return PowerBook58;
	if(machine_is_compatible("PowerBook5,6"))
		return PowerBook56;
	if (machine_is_compatible("PowerBook5,4"))
		return PowerBook54;
	return Unknown;
}

static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
			     int *z, int *fingers)
{
	int i;
	/* values to calculate mean */
	int pcum = 0, psum = 0;

	*fingers = 0;

	for (i = 0; i < nb_sensors; i++) {
		if (xy_sensors[i] < ATP_THRESHOLD)
			continue;
		if ((i - 1 < 0) || (xy_sensors[i - 1] < ATP_THRESHOLD))
			(*fingers)++;
		pcum += xy_sensors[i] * i;
		psum += xy_sensors[i];
	}

	if (psum > 0) {
		*z = psum;
		return pcum * fact / psum;
	}

	return 0;
}

static inline void atp_report_fingers(struct input_dev *input, int fingers)
{
	input_report_key(input, BTN_TOOL_FINGER, fingers == 1);
	input_report_key(input, BTN_TOOL_DOUBLETAP, fingers == 2);
	input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
}

static void atp_complete(struct urb* urb, struct pt_regs* regs)
{
	int x, y, x_z, y_z, x_f, y_f;
	int retval, i;
	struct atp *dev = urb->context;
	static int ctr = 1;

	switch (urb->status) {
	case 0:
		/* success */
		break;
	case -EOVERFLOW:
		if(ctr){
			printk("appletouch: OVERFLOW with data length %d\n", data_len);
			ctr = 0;
		}
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* This urb is terminated, clean up */
		dbg("%s - urb shutting down with status: %d",
		    __FUNCTION__, urb->status);
		return;
	default:
		goto exit;
	}

	/* drop incomplete datasets */
	if (dev->urb->actual_length != data_len) {
		printk(KERN_WARNING "appletouch: incomplete data package length %d\n", dev->urb->actual_length);
		goto exit;
	}

#if defined(CONFIG_RELAYFS_FS) || defined(CONFIG_RELAYFS_FS_MODULE)
	if ( dev->data ) {
		relay_write(rch, dev->data, dev->urb->actual_length);
	}
#endif

        dev->xy_cur[0] = dev->data[19];
        dev->xy_cur[1] = dev->data[20];
        dev->xy_cur[2] = dev->data[22];
        dev->xy_cur[3] = dev->data[23];
        dev->xy_cur[4] = dev->data[25];
        dev->xy_cur[5] = dev->data[26];
        dev->xy_cur[6] = dev->data[28];
        dev->xy_cur[7] = dev->data[29];
        dev->xy_cur[8] = dev->data[31];
        dev->xy_cur[9] = dev->data[32];
        dev->xy_cur[10] = dev->data[34];
        dev->xy_cur[11] = dev->data[35];
        dev->xy_cur[12] = dev->data[37];
        dev->xy_cur[13] = dev->data[38];
        dev->xy_cur[14] = dev->data[40];

        dev->xy_cur[15] = dev->data[1];
        dev->xy_cur[16] = dev->data[2];
        dev->xy_cur[17] = dev->data[4];
        dev->xy_cur[18] = dev->data[5];
        dev->xy_cur[19] = dev->data[7];
        dev->xy_cur[20] = dev->data[8];
        dev->xy_cur[21] = dev->data[10];

        /*
        for(i = 0; i < ATP_MAX_XSENSORS + ATP_MAX_YSENSORS; i++) {
            printk("%2x ", dev->xy_cur[i]);
        }
        printk("\n");
        */

	/* reorder the sensors values */
	//for (i = 0; i < 8; i++) {
		/* X values */
		/*dev->xy_cur[i     ] = dev->data[5 * i +  2];
		dev->xy_cur[i +  8] = dev->data[5 * i +  4];
		dev->xy_cur[i + 16] = dev->data[5 * i + 42];
		if (i < 2)
			dev->xy_cur[i + 24] = dev->data[5 * i + 44];*/

		/* Y values */
		/*dev->xy_cur[i + 26] = dev->data[5 * i +  1];
		dev->xy_cur[i + 34] = dev->data[5 * i +  3];
	}*/

        //dbg_dump("sample", dev->xy_cur);

	if (!dev->valid) {
		/* first sample */
		dev->valid = 1;
		dev->x_old = dev->y_old = -1;

		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));

		/* 17" Powerbooks have 10 extra X sensors */
		/*for (i = 16; i < ATP_MAX_XSENSORS; i++)
			if (dev->xy_cur[i]) {
				printk("appletouch: 17\" model detected.\n");
				input_set_abs_params(dev->input, ABS_X, 0,
				     		     ((ATP_MAX_XSENSORS - 1) * ATP_XFACT) - 1,
						     ATP_FUZZ, 0);
				break;
			}*/

		goto exit;
	}

	for (i = 0; i < ATP_MAX_XSENSORS + ATP_MAX_YSENSORS; i++) {
		/* accumulate the change */
		signed char change = dev->xy_old[i] - dev->xy_cur[i];
		dev->xy_acc[i] -= change;

		/* prevent down drifting */
		if (dev->xy_acc[i] < 0)
			dev->xy_acc[i] = 0;
	}

	memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));

	//dbg_dump("accumulator", dev->xy_acc);

	x = atp_calculate_abs(dev->xy_acc, ATP_MAX_XSENSORS,
			      ATP_XFACT, &x_z, &x_f);
	y = atp_calculate_abs(dev->xy_acc + ATP_MAX_XSENSORS, ATP_MAX_YSENSORS,
			      ATP_YFACT, &y_z, &y_f);

	if (x && y) {
		if (dev->x_old != -1) {
			x = (dev->x_old * 3 + x) >> 2;
			y = (dev->y_old * 3 + y) >> 2;
			dev->x_old = x;
			dev->y_old = y;

			if (debug > 1)
				printk("appletouch: X: %3d Y: %3d "
				       "Xz: %3d Yz: %3d\n",
				       x, y, x_z, y_z);

			input_report_key(dev->input, BTN_TOUCH, 1);
			input_report_abs(dev->input, ABS_X, x);
			input_report_abs(dev->input, ABS_Y, y);
			input_report_abs(dev->input, ABS_PRESSURE,
					 min(ATP_PRESSURE, x_z + y_z));
			atp_report_fingers(dev->input, max(x_f, y_f));
		}
		dev->x_old = x;
		dev->y_old = y;
	}
	else if (!x && !y) {

		dev->x_old = dev->y_old = -1;
		input_report_key(dev->input, BTN_TOUCH, 0);
		input_report_abs(dev->input, ABS_PRESSURE, 0);
		atp_report_fingers(dev->input, 0);

		/* reset the accumulator on release */
		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
	}

	input_report_key(dev->input, BTN_LEFT, !!dev->data[data_len-1]);

	input_sync(dev->input);

exit:
	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
	if (retval) {
		err("%s - usb_submit_urb failed with result %d",
		    __FUNCTION__, retval);
	}
}

static int atp_open(struct input_dev *input)
{
	struct atp *dev = input->private;
	if (usb_submit_urb(dev->urb, GFP_ATOMIC)) {
		printk("atp: usb_submit_urb Error\n");
		return -EIO;
	}

	dev->open = 1;
	return 0;
}

static void atp_close(struct input_dev *input)
{
	struct atp *dev = input->private;
	usb_kill_urb(dev->urb);
	dev->open = 0;
}

static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id)
{
	struct atp *dev = NULL;
	struct usb_host_interface *iface_desc;
	struct usb_endpoint_descriptor *endpoint;
	int int_in_endpointAddr = 0;
	int i, retval = -ENOMEM;
	int regret=0;
	printk(KERN_INFO "AppleTouch: Inside atp_probe\n");
	
	/* allocate memory for our device state and initialize it */
	dev = kmalloc(sizeof(struct atp), GFP_KERNEL);
	if (dev == NULL) {
		err("Out of memory");
		goto err_kmalloc;
	}
	
	memset(dev, 0, sizeof(struct atp));
	dev->mtype = atp_machine_detect();
	if(dev->mtype == Unknown)
	{
		printk(KERN_INFO "appletouch: Unknown machine type!\n");
		return -ENODEV;
	}
	if(dev->mtype > 1)
	{
		if(data_len < 256)
		{
			printk(KERN_INFO "appletouch: Setting URB buffer length to 256\n");
			data_len = 256;
		}
	}

	printk("appletouch: Machine type is: %d\n", dev->mtype);

	dev->udev = interface_to_usbdev(iface);

	/* set up the endpoint information */
	/* use only the first interrupt-in endpoint */
	iface_desc = iface->cur_altsetting;
	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
		endpoint = &iface_desc->endpoint[i].desc;
		if (!int_in_endpointAddr &&
		    (endpoint->bEndpointAddress & USB_DIR_IN) &&
		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
					== USB_ENDPOINT_XFER_INT)) {
			/* we found an interrupt in endpoint */
			int_in_endpointAddr = endpoint->bEndpointAddress;
			printk(KERN_INFO "AppleTouch: atp_probe found interrupt in endpoint: %d\n", int_in_endpointAddr);
			break;
		}
	}
	if (!int_in_endpointAddr) {
		retval = -EIO;
		err("Could not find int-in endpoint");
		goto err_endpoint;
	}

	/* save our data pointer in this interface device */
	usb_set_intfdata(iface, dev);

	dev->urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!dev->urb) {
		retval = -ENOMEM;
		goto err_usballoc;
	}
	dev->data = usb_buffer_alloc(dev->udev, data_len, GFP_KERNEL,
				     &dev->urb->transfer_dma);
	if (!dev->data) {
		retval = -ENOMEM;
		goto err_usbbufalloc;
	}
	usb_fill_int_urb(dev->urb, dev->udev,
			 usb_rcvintpipe(dev->udev, int_in_endpointAddr),
			 dev->data, data_len, atp_complete, dev, 1);

	dev->input = input_allocate_device();
	dev->input->name = "appletouch";
	dev->input->dev = &iface->dev;
	dev->input->private = dev;
	dev->input->open = atp_open;
	dev->input->close = atp_close;

	usb_to_input_id(dev->udev, &dev->input->id);

	set_bit(EV_ABS, dev->input->evbit);

	/*
	 * 12" and 15" Powerbooks only have 16 x sensors,
	 * 17" models are detected later.
	 */
	input_set_abs_params(dev->input, ABS_X, 0,
			     (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0);
	input_set_abs_params(dev->input, ABS_Y, 0,
			     (ATP_MAX_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0);
	input_set_abs_params(dev->input, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);

	set_bit(EV_KEY, dev->input->evbit);
	set_bit(BTN_TOUCH, dev->input->keybit);
	set_bit(BTN_TOOL_FINGER, dev->input->keybit);
	set_bit(BTN_TOOL_DOUBLETAP, dev->input->keybit);
	set_bit(BTN_TOOL_TRIPLETAP, dev->input->keybit);
	set_bit(BTN_LEFT, dev->input->keybit);

	regret = input_register_device(dev->input);

	printk(KERN_INFO "input: appletouch connected, Reg code: %d\n", regret);

	return 0;

err_usbbufalloc:
	usb_free_urb(dev->urb);
err_usballoc:
	usb_set_intfdata(iface, NULL);
err_endpoint:
	kfree(dev);
err_kmalloc:
	return retval;
}

static void atp_disconnect(struct usb_interface *iface)
{
	struct atp *dev = usb_get_intfdata(iface);

	usb_set_intfdata(iface, NULL);
	if (dev) {
		usb_kill_urb(dev->urb);
		input_unregister_device(dev->input);
		usb_free_urb(dev->urb);
		usb_buffer_free(dev->udev, data_len,
				dev->data, dev->urb->transfer_dma);
		kfree(dev);
	}
	printk(KERN_INFO "input: appletouch disconnected\n");
}

static int atp_suspend(struct usb_interface *iface, pm_message_t message)
{
	struct atp *dev = usb_get_intfdata(iface);
	usb_kill_urb(dev->urb);
	dev->valid = 0;
	return 0;
}

static int atp_resume(struct usb_interface *iface)
{
	struct atp *dev = usb_get_intfdata(iface);
	if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
		return -EIO;

	return 0;
}

static struct usb_driver atp_driver = {
	.owner		= THIS_MODULE,
	.name		= "appletouch",
	.probe		= atp_probe,
	.disconnect	= atp_disconnect,
	.suspend	= atp_suspend,
	.resume		= atp_resume,
	.id_table	= atp_table,
};


static int __init atp_init(void)
{
#if defined(CONFIG_RELAYFS_FS) || defined(CONFIG_RELAYFS_FS_MODULE)
	rcb  = kmalloc(sizeof(struct rchan_callbacks), GFP_KERNEL);
	rcb->subbuf_start = NULL;
	rcb->buf_mapped = NULL;
	rcb->buf_unmapped = NULL;
	rch = relay_open("atpdata", NULL, 256, 256, NULL);
	if (!rch) return -ENOMEM;
	printk("appletouch: Relayfs enabled.\n");
#endif
	return usb_register(&atp_driver);
}

static void __exit atp_exit(void)
{
#if defined(CONFIG_RELAYFS_FS) || defined(CONFIG_RELAYFS_FS_MODULE)
	relay_close(rch);
	kfree(rcb);
#endif
	usb_deregister(&atp_driver);
}

module_init(atp_init);
module_exit(atp_exit);

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: INTERACTIVE_CONSOLE for misc-embedded.c and watchdog issue
From: Tom Rini @ 2005-11-28 23:27 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linux-ppc-embedded
In-Reply-To: <20051117151730.GA10180@logos.cnet>

On Thu, Nov 17, 2005 at 01:17:30PM -0200, Marcelo Tosatti wrote:

> The following patch against misc-embedded.c adds an INTERACTIVE_CONSOLE
> #define to guard reading from console (causes unecessary delay in some
> situations).
> 
> Its an adaptation of misc.c's define, a difference being that platform
> headers define "NO_INTERACTIVE_CONSOLE" if required.
> 
> What do you think?

Please put a comment above the #ifndef stating where the define should
be.  But I have a feeling that's going to be somewhere under
arch/ppc/platforms/ or include/asm-ppc/ and I don't know if that's a
good idea...

I've got a vauge idea on how we can handle this a little bit more
cleanly, in the merge tree.

-- 
Tom Rini
http://gate.crashing.org/~trini/

^ permalink raw reply

* Re: [PATCH] ppc32: fix treeboot image entrypoint
From: Tom Rini @ 2005-11-28 22:34 UTC (permalink / raw)
  To: Andrew Morton, Matt Porter, linuxppc-embedded
In-Reply-To: <20051124213821.GA21929@gate.ebshome.net>

On Thu, Nov 24, 2005 at 01:38:21PM -0800, Eugene Surovegin wrote:

> Correctly specify treeboot based image entrypoint. Currently makefile 
> uses $(ENTRYPOINT) which isn't defined anywhere. Each board port sets 
> entrypoint-$(CONFIG_BOARD_NAME) instead.
> 
> Without this patch I cannot boot Ocotea (PPC440GX eval board) anymore. 
> I was getting random "OS panic" errors from OpenBIOS for a while, but 
> with current kernel I get them all the time (probably because image 
> became bigger).
> 
> Signed-off-by: Eugene Surovegin <ebs@ebshome.net>

I wonder how that got lost when I think ENTRYPOINT was changed to
entrypoint-$(board_name).  Maybe we should also think about changing the
default entry point in mktreeboot.c, what do you think Eugene? or Matt?

Acked-by: Tom Rini <trini@kernel.crashing.org>

-- 
Tom Rini
http://gate.crashing.org/~trini/

^ permalink raw reply

* Re: [RFC] add PHY support to AM79C874
From: Pantelis Antoniou @ 2005-11-28 21:00 UTC (permalink / raw)
  To: Aristeu Sergio Rozanski Filho; +Cc: linuxppc-embedded
In-Reply-To: <20051128141042.GR7163@cathedrallabs.org>

On Monday 28 November 2005 16:10, Aristeu Sergio Rozanski Filho wrote:
> This is a simple port from old fec driver to PHY layer to support AMD
> AM79C874 PHY.
> As I don't have the hardware to test this, all kinds of feedback are
> most welcome.
> Thanks,
> 
> -- 
> Aristeu
> 
> 

Looks fine to me...

Regards

Pantelis

^ permalink raw reply

* Re: [PATCH] ppc32: Adds MPC885ADS, MPC866ADS and MPC8272ADS-specific platform stuff for fs_enet
From: Marcelo Tosatti @ 2005-11-28 14:48 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: BLandau, linuxppc-embedded list
In-Reply-To: <438B379B.6090904@ru.mvista.com>

On Mon, Nov 28, 2005 at 08:00:11PM +0300, Vitaly Bordug wrote:
> Added proper ppc_sys identification and fs_platform_info's for MPC 885ADS, 
> 866ADS and 8272ADS. Assuming setbitsXX/clrbitsXX patch is applied.
> 
> 
> Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>

Looks great now for the parts I can comment on...

^ permalink raw reply

* PPC32 memory models
From: Andy Whitcroft @ 2005-11-28 19:06 UTC (permalink / raw)
  To: Anton Blanchard, Paul Mackerras; +Cc: linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 566 bytes --]

It seems that there is some confusion over what we should be supporting
memory model wise for PPC32 under powerpc architecture.  The current
Kconfig limits you to only SPARSEMEM which isn't parameterised for PPC32
at all.  Are we expecting to be able to support PPC32 as yet in this
architecture?  If so it seems we have a couple of issues with the Kconfig.

Attached is a patch to enable FLATMEM and disable SPARSEMEM for PPC32
which seems to be the working combinations.  It may well not be what is
intended.  But I offer it to start discussions.

Comments.

-apw

[-- Attachment #2: sparsemem-powerpc-allow-flatmem-on-32bit --]
[-- Type: text/plain, Size: 796 bytes --]

powerpc: ppc32 clean up available memory models

Clean up the currently available memory models for ppc32.  It seems
that we do need FLATMEM for ppc32 on non-NUMA.  It also seems that
SPARSEMEM is not parameterised yet so disable that.

Signed-off-by: Andy Whitcroft <apw@shadwen.org>
---
diff -upN reference/arch/powerpc/Kconfig current/arch/powerpc/Kconfig
--- reference/arch/powerpc/Kconfig
+++ current/arch/powerpc/Kconfig
@@ -584,14 +584,15 @@ config ARCH_SELECT_MEMORY_MODEL
 
 config ARCH_FLATMEM_ENABLE
        def_bool y
-       depends on PPC64 && !NUMA
+       depends on !NUMA
 
 config ARCH_SPARSEMEM_ENABLE
 	def_bool y
+	depends on PPC64
 
 config ARCH_SPARSEMEM_DEFAULT
 	def_bool y
-	depends on SMP && PPC_PSERIES
+	depends on SMP && PPC_PSERIES && NUMA
 
 source "mm/Kconfig"
 

^ permalink raw reply

* [PATCH] ppc32 8xx: Added setbitsXX/clrbitsXX macro for read-modify-write operations (resend)
From: Vitaly Bordug @ 2005-11-28 18:01 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-devel list, linuxppc-embedded list

This adds setbitsXX/clrbitsXX macro for read-modify-write operations
and converts the 8xx core and drivers to use them.

Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>


---

 arch/ppc/8xx_io/commproc.c   |    6 +++---
 arch/ppc/syslib/m8xx_setup.c |   12 +++++-------
 arch/ppc/syslib/m8xx_wdt.c   |    3 +--
 include/asm-ppc/io.h         |    7 +++++++
 4 files changed, 16 insertions(+), 12 deletions(-)

applies-to: 1e8504d2a91579756c89ef2d65ebd526f973cde8
d9135d1517154ad693ac15ee88a2408add6cd88b
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
index 579cd40..5cecb6e 100644
--- a/arch/ppc/8xx_io/commproc.c
+++ b/arch/ppc/8xx_io/commproc.c
@@ -73,7 +73,7 @@ cpm_mask_irq(unsigned int irq)
 {
 	int cpm_vec = irq - CPM_IRQ_OFFSET;
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, in_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr) & ~(1 << cpm_vec));
+	clrbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr,(1 << cpm_vec));
 }
 
 static void
@@ -81,7 +81,7 @@ cpm_unmask_irq(unsigned int irq)
 {
 	int cpm_vec = irq - CPM_IRQ_OFFSET;
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, in_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr) | (1 << cpm_vec));
+	setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr,(1 << cpm_vec));
 }
 
 static void
@@ -198,7 +198,7 @@ cpm_interrupt_init(void)
 	if (setup_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, &cpm_error_irqaction))
 		panic("Could not allocate CPM error IRQ!");
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, in_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr) | CICR_IEN);
+	setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, CICR_IEN);
 }
 
 /*
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 1cc3abe..ad7db45 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -149,8 +149,7 @@ void __init m8xx_calibrate_decr(void)
 	out_be32(&((immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk, KAPWR_KEY);
 
 	/* Force all 8xx processors to use divide by 16 processor clock. */
-	out_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr,
-		in_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr)|0x02000000);
+	setbits32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr, 0x02000000);
 	/* Processor frequency is MHz.
 	 * The value 'fp' is the number of decrementer ticks per second.
 	 */
@@ -184,10 +183,9 @@ void __init m8xx_calibrate_decr(void)
 	out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, KAPWR_KEY);
 
 	/* Disable the RTC one second and alarm interrupts. */
-	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE));
+	clrbits16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, (RTCSC_SIE | RTCSC_ALE));
 	/* Enable the RTC */
-	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE));
-
+	setbits16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, (RTCSC_RTF | RTCSC_RTE));
 	/* Enabling the decrementer also enables the timebase interrupts
 	 * (or from the other point of view, to get decrementer interrupts
 	 * we have to enable the timebase).  The decrementer interrupt
@@ -232,8 +230,8 @@ m8xx_restart(char *cmd)
 	__volatile__ unsigned char dummy;
 
 	local_irq_disable();
-	out_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr, in_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr) | 0x00000080);
 
+	setbits32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr, 0x00000080);
 	/* Clear the ME bit in MSR to cause checkstop on machine check
 	*/
 	mtmsr(mfmsr() & ~0x1000);
@@ -303,8 +301,8 @@ m8xx_init_IRQ(void)
 	i8259_init(0);
 
 	/* The i8259 cascade interrupt must be level sensitive. */
-	out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel, in_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel & ~(0x80000000 >> ISA_BRIDGE_INT)));
 
+	clrbits32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel, (0x80000000 >> ISA_BRIDGE_INT));
 	if (setup_irq(ISA_BRIDGE_INT, &mbx_i8259_irqaction))
 		enable_irq(ISA_BRIDGE_INT);
 #endif	/* CONFIG_PCI */
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
index a21632d..57f8b9f 100644
--- a/arch/ppc/syslib/m8xx_wdt.c
+++ b/arch/ppc/syslib/m8xx_wdt.c
@@ -40,8 +40,7 @@ static irqreturn_t m8xx_wdt_interrupt(in
 
 	m8xx_wdt_reset();
 
-	out_be16(&imap->im_sit.sit_piscr, in_be16(&imap->im_sit.sit_piscr) | PISCR_PS);	/* clear irq */
-
+	setbits16(&imap->im_sit.sit_piscr, PISCR_PS);
 	return IRQ_HANDLED;
 }
 
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index 84ac6e2..9c2e3db 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -573,4 +573,11 @@ extern void pci_iounmap(struct pci_dev *
  */
 #define xlate_dev_kmem_ptr(p)	p
 
+/* access ports */
+#define setbits32(_addr, _v) out_be32((_addr), in_be32(_addr) |  (_v))
+#define clrbits32(_addr, _v) out_be32((_addr), in_be32(_addr) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16((_addr), in_be16(_addr) |  (_v))
+#define clrbits16(_addr, _v) out_be16((_addr), in_be16(_addr) & ~(_v))
+
 #endif /* __KERNEL__ */
---
Sincerely, 
Vitaly

^ permalink raw reply related

* [PATCH] ppc32: Adds MPC885ADS, MPC866ADS and MPC8272ADS-specific platform stuff for fs_enet
From: Vitaly Bordug @ 2005-11-28 17:00 UTC (permalink / raw)
  To: BLandau; +Cc: linuxppc-embedded list

[-- Attachment #1: Type: text/plain, Size: 223 bytes --]

Added proper ppc_sys identification and fs_platform_info's for MPC 885ADS, 866ADS and 
8272ADS. Assuming setbitsXX/clrbitsXX patch is applied.


Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>

---
Sincerely,
Vitaly



[-- Attachment #2: pre2.patch --]
[-- Type: text/x-patch, Size: 32010 bytes --]

diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 8fa51b0..8e6fcb2 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -506,6 +506,53 @@ config WINCEPT
 
 endchoice
 
+menu "Freescale Ethernet driver platform-specific options"
+	depends on FS_ENET
+
+	config MPC8xx_SECOND_ETH
+	bool "Second Ethernet channel"
+	depends on (MPC885ADS || MPC86XADS)
+	default y
+	help
+	  This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
+	  The latter will use SCC1, for 885ADS you can select it below.
+
+	choice
+		prompt "Second Ethernet channel"
+		depends on MPC8xx_SECOND_ETH
+		default MPC8xx_SECOND_ETH_FEC2
+
+		config MPC8xx_SECOND_ETH_FEC2
+		bool "FEC2"
+		depends on MPC885ADS
+		help
+		  Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
+		  (often 2-nd UART) will not work if this is enabled.
+
+		config MPC8xx_SECOND_ETH_SCC1
+		bool "SCC1"
+		depends on MPC86XADS
+		select MPC8xx_SCC_ENET_FIXED
+		help
+		  Enable SCC1 to serve as 2-nd Ethernet channel. Note that SMC1
+		  (often 1-nd UART) will not work if this is enabled.
+
+		config MPC8xx_SECOND_ETH_SCC3
+		bool "SCC3"
+		depends on MPC885ADS
+		help
+		  Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
+		  (often 1-nd UART) will not work if this is enabled.
+
+	endchoice
+
+	config MPC8xx_SCC_ENET_FIXED
+	depends on MPC8xx_SECOND_ETH_SCC
+	default n
+	bool "Use fixed MII-less mode for SCC Ethernet"
+
+endmenu
+
 choice
 	prompt "Machine Type"
 	depends on 6xx || POWER3 || POWER4
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
index 7c5cdab..ee50b0d 100644
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -22,6 +22,8 @@ ifeq ($(CONFIG_PPC_PMAC),y)
 obj-$(CONFIG_NVRAM)		+= pmac_nvram.o
 obj-$(CONFIG_CPU_FREQ_PMAC)	+= pmac_cpufreq.o
 endif
+
+obj-$(CONFIG_ADS8272)		+= mpc8272ads_setup.o
 obj-$(CONFIG_PMAC_BACKLIGHT)	+= pmac_backlight.o
 obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
 obj-$(CONFIG_PQ2ADS)		+= pq2ads.o
@@ -45,6 +47,8 @@ obj-$(CONFIG_SBC82xx)		+= sbc82xx.o
 obj-$(CONFIG_SPRUCE)		+= spruce.o
 obj-$(CONFIG_LITE5200)		+= lite5200.o
 obj-$(CONFIG_EV64360)		+= ev64360.o
+obj-$(CONFIG_MPC86XADS)		+= mpc866ads_setup.o
+obj-$(CONFIG_MPC885ADS)		+= mpc885ads_setup.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_PMAC)		+= pmac_smp.o
diff --git a/arch/ppc/platforms/fads.h b/arch/ppc/platforms/fads.h
index a48fb8d..e1c0b1b 100644
--- a/arch/ppc/platforms/fads.h
+++ b/arch/ppc/platforms/fads.h
@@ -112,7 +112,7 @@
 
 /* CPM Ethernet through SCC1 or SCC2 */
 
-#ifdef CONFIG_SCC1_ENET		/* Probably 860 variant */
+#if defined(CONFIG_SCC1_ENET) || defined(CONFIG_MPC8xx_SECOND_ETH_SCC1)		/* Probably 860 variant */
 /* Bits in parallel I/O port registers that have to be set/cleared
  * to configure the pins for SCC1 use.
  * TCLK - CLK1, RCLK - CLK2.
diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c
new file mode 100644
index 0000000..4f76b1b
--- /dev/null
+++ b/arch/ppc/platforms/mpc8272ads_setup.c
@@ -0,0 +1,253 @@
+/*
+ * arch/ppc/platforms/82xx/pq2ads_pd.c
+ *
+ * MPC82xx Board-specific PlatformDevice descriptions
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/fs_enet_pd.h>
+
+#include <asm/io.h>
+#include <asm/mpc8260.h>
+#include <asm/cpm2.h>
+#include <asm/immap_cpm2.h>
+#include <asm/irq.h>
+#include <asm/ppc_sys.h>
+#include <asm/ppcboot.h>
+
+#include "pq2ads_pd.h"
+
+static void init_fcc1_ioports(void);
+static void init_fcc2_ioports(void);
+
+static struct fs_mii_bus_info mii_bus_info = {
+	.method                 = fsmii_bitbang,
+	.id                     = 0,
+	.i.bitbang = {
+		.mdio_port	= fsiop_portc,
+		.mdio_bit	= 18,
+		.mdc_port	= fsiop_portc,
+		.mdc_bit	= 19,
+		.delay		= 1,
+	},
+};
+
+static struct fs_platform_info mpc82xx_fcc1_pdata = {
+	.fs_no		= fsid_fcc1,
+	.cp_page	= CPM_CR_FCC1_PAGE,
+	.cp_block 	= CPM_CR_FCC1_SBLOCK,
+	.clk_trx 	= (PC_F1RXCLK | PC_F1TXCLK),
+	.clk_route	= CMX1_CLK_ROUTE,
+	.clk_mask	= CMX1_CLK_MASK,
+	.init_ioports 	= init_fcc1_ioports,
+
+	.phy_addr	= 0,
+#ifdef PHY_INTERRUPT
+	.phy_irq	= PHY_INTERRUPT,
+#else
+	.phy_irq	= -1;
+#endif
+	.mem_offset	= FCC1_MEM_OFFSET,
+	.bus_info	= &mii_bus_info,
+	.rx_ring	= 32,
+	.tx_ring	= 32,
+	.rx_copybreak	= 240,
+	.use_napi	= 0,
+	.napi_weight	= 17,
+};
+
+static struct fs_platform_info mpc82xx_fcc2_pdata = {
+	.fs_no		= fsid_fcc2,
+	.cp_page	= CPM_CR_FCC2_PAGE,
+	.cp_block 	= CPM_CR_FCC2_SBLOCK,
+	.clk_trx 	= (PC_F2RXCLK | PC_F2TXCLK),
+	.clk_route	= CMX2_CLK_ROUTE,
+	.clk_mask	= CMX2_CLK_MASK,
+	.init_ioports	= init_fcc2_ioports,
+
+	.phy_addr	= 3,
+#ifdef PHY_INTERRUPT
+	.phy_irq	= PHY_INTERRUPT,
+#else
+	.phy_irq	= -1;
+#endif
+	.mem_offset	= FCC2_MEM_OFFSET,
+	.bus_info	= &mii_bus_info,
+	.rx_ring	= 32,
+	.tx_ring	= 32,
+	.rx_copybreak	= 240,
+	.use_napi	= 0,
+	.napi_weight	= 17,
+};
+
+static void init_fcc1_ioports(void)
+{
+	struct io_port *io;
+	u32 tempval;
+	int i=0;
+	cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
+	u32 *bcsr = ioremap(BCSR_ADDR+4, sizeof(u32));
+
+	io = &immap->im_ioport;
+
+	/* Enable the PHY */
+	clrbits32(bcsr, BCSR1_FETHIEN);
+	setbits32(bcsr, BCSR1_FETH_RST);
+
+	/* FCC1 pins are on port A/C. */
+	/* Configure port A and C pins for FCC1 Ethernet. */
+
+	tempval = in_be32(&io->iop_pdira);
+	tempval &= ~PA1_DIRA0;
+	tempval |= PA1_DIRA1;
+	out_be32(&io->iop_pdira, tempval);
+
+	tempval = in_be32(&io->iop_psora);
+	tempval &= ~PA1_PSORA0;
+	tempval |= PA1_PSORA1;
+	out_be32(&io->iop_psora, tempval);
+
+	setbits32(&io->iop_ppara,PA1_DIRA0 | PA1_DIRA1);
+
+	/* Alter clocks */
+	tempval = PC_F1TXCLK|PC_F1RXCLK;
+
+	clrbits32(&io->iop_psorc, tempval);
+	clrbits32(&io->iop_pdirc, tempval);
+	setbits32(&io->iop_pparc, tempval);
+
+	clrbits32(&immap->im_cpmux.cmx_fcr, CMX1_CLK_MASK);
+	setbits32(&immap->im_cpmux.cmx_fcr, CMX1_CLK_ROUTE);
+	iounmap(bcsr);
+	iounmap(immap);
+}
+
+static void init_fcc2_ioports(void)
+{
+	cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
+	u32 *bcsr = ioremap(BCSR_ADDR+12, sizeof(u32));
+
+	struct io_port *io;
+	u32 tempval;
+
+	immap = cpm2_immr;
+
+	io = &immap->im_ioport;
+
+	/* Enable the PHY */
+	clrbits32(bcsr, BCSR3_FETHIEN2);
+	setbits32(bcsr, BCSR3_FETH2_RST);
+
+	/* FCC2 are port B/C. */
+	/* Configure port A and C pins for FCC2 Ethernet. */
+
+	tempval = in_be32(&io->iop_pdirb);
+	tempval &= ~PB2_DIRB0;
+	tempval |= PB2_DIRB1;
+	out_be32(&io->iop_pdirb, tempval);
+
+	tempval = in_be32(&io->iop_psorb);
+	tempval &= ~PB2_PSORB0;
+	tempval |= PB2_PSORB1;
+	out_be32(&io->iop_psorb, tempval);
+
+	setbits32(&io->iop_pparb,PB2_DIRB0 | PB2_DIRB1);
+
+	tempval = PC_F2RXCLK|PC_F2TXCLK;
+
+	/* Alter clocks */
+	clrbits32(&io->iop_psorc,tempval);
+	clrbits32(&io->iop_pdirc,tempval);
+	setbits32(&io->iop_pparc,tempval);
+
+	clrbits32(&immap->im_cpmux.cmx_fcr, CMX2_CLK_MASK);
+	setbits32(&immap->im_cpmux.cmx_fcr, CMX2_CLK_ROUTE);
+
+	iounmap(bcsr);
+	iounmap(immap);
+}
+
+
+static void __init mpc8272ads_fixup_enet_pdata(struct platform_device *pdev,
+					      int idx)
+{
+	bd_t* bi = (void*)__res;
+	int fs_no = fsid_fcc1+pdev->id-1;
+
+	mpc82xx_fcc1_pdata.dpram_offset = mpc82xx_fcc2_pdata.dpram_offset = (u32)cpm2_immr->im_dprambase;
+	mpc82xx_fcc1_pdata.fcc_regs_c = mpc82xx_fcc2_pdata.fcc_regs_c = (u32)cpm2_immr->im_fcc_c;
+
+	switch(fs_no) {
+		case fsid_fcc1:
+			memcpy(&mpc82xx_fcc1_pdata.macaddr,bi->bi_enetaddr,6);
+			pdev->dev.platform_data = &mpc82xx_fcc1_pdata;
+		break;
+		case fsid_fcc2:
+			memcpy(&mpc82xx_fcc2_pdata.macaddr,bi->bi_enetaddr,6);
+			mpc82xx_fcc2_pdata.macaddr[5] ^= 1;
+			pdev->dev.platform_data = &mpc82xx_fcc2_pdata;
+		break;
+	}
+}
+
+static int __init mpc8272ads_platform_notify(struct device *dev)
+{
+	static struct {
+		const char *bus_id;
+		void (*rtn) (struct platform_device * pdev, int idx);
+	} dev_map[] = {
+		{"fsl-cpm-fcc", mpc8272ads_fixup_enet_pdata},
+	};
+	struct platform_device *pdev;
+	int i, j, idx;
+	const char *s;
+	if (dev && dev->bus_id)
+		for (i = 0; i < ARRAY_SIZE(dev_map); i++) {
+			idx = -1;
+
+			if ((s = strrchr(dev->bus_id, '.')) != NULL)
+				idx = (int)simple_strtol(s + 1, NULL, 10);
+			else
+				s = dev->bus_id;
+			j = s - dev->bus_id;
+			if (!strncmp(dev->bus_id, dev_map[i].bus_id, j)) {
+				pdev =
+				    container_of(dev, struct platform_device,
+						 dev);
+				dev_map[i].rtn(pdev, idx);
+			}
+		}
+	return 0;
+}
+
+int __init mpc8272ads_init(void)
+{
+	printk(KERN_NOTICE "mpc8272ads: Init\n");
+
+	platform_notify = mpc8272ads_platform_notify;
+
+	identify_ppc_sys_by_name_and_id(BOARD_CHIP_NAME, cpm2_immr->im_memctl.memc_immr);
+
+	/*Remove stuff does not utilized platform way*/
+	ppc_sys_device_remove(MPC82xx_CPM_SCC1);
+	ppc_sys_device_remove(MPC82xx_CPM_SCC2);
+	ppc_sys_device_remove(MPC82xx_CPM_SCC3);
+	ppc_sys_device_remove(MPC82xx_CPM_SCC4);
+	ppc_sys_device_remove(MPC82xx_CPM_SMC1);
+	ppc_sys_device_remove(MPC82xx_CPM_SMC2);
+
+	return 0;
+}
+
+arch_initcall(mpc8272ads_init);
diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c
new file mode 100644
index 0000000..0809cf3
--- /dev/null
+++ b/arch/ppc/platforms/mpc866ads_setup.c
@@ -0,0 +1,283 @@
+/*arch/ppc/platforms/mpc885ads-setup.c
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/ppc_sys.h>
+#include <asm/mpc8xx.h>
+
+extern unsigned char __res[];
+
+static struct fs_mii_bus_info fec_mii_bus_info = {
+	.method = fsmii_fec,
+	.id = 0,
+};
+
+static struct fs_mii_bus_info scc_mii_bus_info = {
+	.method = fsmii_fixed,
+	.id = 0,
+	.i.fixed.speed = 10,
+	.i.fixed.duplex = 0,
+};
+
+static struct fs_platform_info mpc8xx_fec_pdata[] = {
+	{
+	 .rx_ring = 128,
+	 .tx_ring = 16,
+	 .rx_copybreak = 240,
+
+	 .use_napi = 1,
+	 .napi_weight = 17,
+
+	 .phy_addr = 15,
+	 .phy_irq = -1,
+
+	 .use_rmii = 0,
+
+	 .bus_info = &fec_mii_bus_info,
+	 }
+};
+
+static struct fs_platform_info mpc8xx_scc_pdata = {
+	.rx_ring = 64,
+	.tx_ring = 8,
+	.rx_copybreak = 240,
+
+	.use_napi = 1,
+	.napi_weight = 17,
+
+	.phy_addr = -1,
+	.phy_irq = -1,
+
+	.bus_info = &scc_mii_bus_info,
+};
+
+void __init board_init(void)
+{
+	volatile cpm8xx_t *cp = cpmp;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR1\n");
+		return;
+	}
+#ifdef CONFIG_SERIAL_CPM_SMC1
+	cp->cp_simode &= ~(0xe0000000 >> 17);	/* brg1 */
+	clrbits32(bcsr_io,(0x80000000 >> 7));
+#else
+	setbits32(bcsr_io,(0x80000000 >> 7));
+
+	cp->cp_pbpar &= ~(0x000000c0);
+	cp->cp_pbdir |= 0x000000c0;
+	cp->cp_smc[0].smc_smcmr = 0;
+	cp->cp_smc[0].smc_smce = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+	cp->cp_simode &= ~(0xe0000000 >> 1);
+	cp->cp_simode |= (0x20000000 >> 1);	/* brg2 */
+	clrbits32(bcsr_io,(0x80000000 >> 13));
+#else
+	clrbits32(bcsr_io,(0x80000000 >> 13));
+	cp->cp_pbpar &= ~(0x00000c00);
+	cp->cp_pbdir |= 0x00000c00;
+	cp->cp_smc[1].smc_smcmr = 0;
+	cp->cp_smc[1].smc_smce = 0;
+#endif
+	iounmap(bcsr_io);
+}
+
+static void setup_fec1_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+
+	setbits16(&immap->im_ioport.iop_pdpar, 0x1fff);
+	setbits16(&immap->im_ioport.iop_pddir, 0x1fff);
+}
+
+static void setup_scc1_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR1\n");
+		return;
+	}
+
+	/* Enable the PHY.
+	 */
+	clrbits32(bcsr_io,BCSR1_ETHEN);
+
+	/* Configure port A pins for Txd and Rxd.
+	 */
+	/* Disable receive and transmit in case EPPC-Bug started it.
+	 */
+	setbits16(&immap->im_ioport.iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(&immap->im_ioport.iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(&immap->im_ioport.iop_paodr, PA_ENET_TXD);
+
+	/* Configure port C pins to enable CLSN and RENA.
+	 */
+	clrbits16(&immap->im_ioport.iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+	clrbits16(&immap->im_ioport.iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+	setbits16(&immap->im_ioport.iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+	/* Configure port A for TCLK and RCLK.
+	 */
+	setbits16(&immap->im_ioport.iop_papar, PA_ENET_TCLK | PA_ENET_RCLK);
+	clrbits16(&immap->im_ioport.iop_padir, PA_ENET_TCLK | PA_ENET_RCLK);
+	clrbits32(&immap->im_cpm.cp_pbpar, PB_ENET_TENA);
+	clrbits32(&immap->im_cpm.cp_pbdir, PB_ENET_TENA);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	clrbits32(&immap->im_cpm.cp_sicr, SICR_ENET_MASK);
+	setbits32(&immap->im_cpm.cp_sicr, SICR_ENET_CLKRT);
+
+	/* In the original SCC enet driver the following code is placed at
+	the end of the initialization */
+	setbits32(&immap->im_cpm.cp_pbpar, PB_ENET_TENA);
+	setbits32(&immap->im_cpm.cp_pbdir, PB_ENET_TENA);
+
+}
+
+static void mpc866ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
+{
+	struct fs_platform_info *fpi = pdev->dev.platform_data;
+
+	volatile cpm8xx_t *cp;
+	bd_t *bd = (bd_t *) __res;
+	char *e;
+	int i;
+
+	/* Get pointer to Communication Processor */
+	cp = cpmp;
+	switch (fs_no) {
+	case fsid_fec1:
+		fpi = &mpc8xx_fec_pdata[0];
+		fpi->init_ioports = &setup_fec1_ioports;
+
+		break;
+	case fsid_scc1:
+		fpi = &mpc8xx_scc_pdata;
+		fpi->init_ioports = &setup_scc1_ioports;
+
+		break;
+	default:
+		break;
+	}
+
+	pdev->dev.platform_data = fpi;
+	fpi->fs_no = fs_no;
+
+	e = (unsigned char *)&bd->bi_enetaddr;
+	for (i = 0; i < 6; i++)
+		fpi->macaddr[i] = *e++;
+
+	fpi->macaddr[5 - pdev->id]++;
+
+}
+
+static void mpc866ads_fixup_fec_enet_pdata(struct platform_device *pdev,
+					   int idx)
+{
+	/* This is for FEC devices only */
+	if (strcmp(pdev->name, "fsl-cpm-fec"))
+		return;
+	mpc866ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1);
+}
+
+static void mpc866ads_fixup_scc_enet_pdata(struct platform_device *pdev,
+					   int idx)
+{
+	/* This is for SCC devices only */
+	if (strcmp(pdev->name, "fsl-cpm-scc"))
+		return;
+
+	mpc866ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
+}
+
+static int mpc866ads_platform_notify(struct device *dev)
+{
+	static struct {
+		const char *bus_id;
+		void (*rtn) (struct platform_device * pdev, int idx);
+	} dev_map[] = {
+		{
+		"fsl-cpm-fec", mpc866ads_fixup_fec_enet_pdata}, {
+	"fsl-cpm-scc", mpc866ads_fixup_scc_enet_pdata},};
+	struct platform_device *pdev;
+	int i, j, idx;
+	const char *s;
+	if (dev && dev->bus_id)
+		for (i = 0; i < ARRAY_SIZE(dev_map); i++) {
+			idx = -1;
+
+			if ((s = strrchr(dev->bus_id, '.')) != NULL)
+				idx = (int)simple_strtol(s + 1, NULL, 10);
+			else
+				s = dev->bus_id;
+			j = s - dev->bus_id;
+			if (!strncmp(dev->bus_id, dev_map[i].bus_id, j)) {
+				pdev =
+				    container_of(dev, struct platform_device,
+						 dev);
+				dev_map[i].rtn(pdev, idx);
+			}
+		}
+	return 0;
+}
+
+int __init mpc866ads_init(void)
+{
+	printk(KERN_NOTICE "mpc866ads: Init\n");
+
+	platform_notify = mpc866ads_platform_notify;
+
+	identify_ppc_sys_by_name(BOARD_CHIP_NAME);
+
+	ppc_sys_device_remove(MPC8xx_CPM_FEC2);
+	ppc_sys_device_remove(MPC8xx_CPM_SCC3);
+	ppc_sys_device_remove(MPC8xx_CPM_SCC2);
+	ppc_sys_device_remove(MPC8xx_CPM_SCC4);
+	ppc_sys_device_remove(MPC8xx_CPM_SMC1);
+	ppc_sys_device_remove(MPC8xx_CPM_SMC2);
+
+	return 0;
+}
+
+arch_initcall(mpc866ads_init);
diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c
new file mode 100644
index 0000000..5e72f64
--- /dev/null
+++ b/arch/ppc/platforms/mpc885ads_setup.c
@@ -0,0 +1,400 @@
+/*arch/ppc/platforms/mpc885ads-setup.c
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/ppc_sys.h>
+
+extern unsigned char __res[];
+
+static void __init mpc885ads_scc_phy_init(char);
+
+static struct fs_mii_bus_info fec_mii_bus_info = {
+	.method = fsmii_fec,
+	.id = 0,
+};
+
+static struct fs_mii_bus_info scc_mii_bus_info = {
+#ifdef CONFIG_SCC_ENET_8xx_FIXED
+	.method = fsmii_fixed,
+#else
+	.method = fsmii_fec,
+#endif
+
+	.id = 0,
+};
+
+static struct fs_platform_info mpc8xx_fec_pdata[] = {
+	{
+	 .rx_ring = 128,
+	 .tx_ring = 16,
+	 .rx_copybreak = 240,
+
+	 .use_napi = 1,
+	 .napi_weight = 17,
+
+	 .phy_addr = 0,
+	 .phy_irq = SIU_IRQ7,
+
+	 .bus_info = &fec_mii_bus_info,
+	 }, {
+	     .rx_ring = 128,
+	     .tx_ring = 16,
+	     .rx_copybreak = 240,
+
+	     .use_napi = 1,
+	     .napi_weight = 17,
+
+	     .phy_addr = 1,
+	     .phy_irq = SIU_IRQ7,
+
+	     .bus_info = &fec_mii_bus_info,
+	     }
+};
+
+static struct fs_platform_info mpc8xx_scc_pdata = {
+	.rx_ring = 64,
+	.tx_ring = 8,
+	.rx_copybreak = 240,
+
+	.use_napi = 1,
+	.napi_weight = 17,
+
+	.phy_addr = 2,
+#ifdef CONFIG_MPC8xx_SCC_ENET_FIXED
+	.phy_irq = -1,
+#else
+	.phy_irq = SIU_IRQ7,
+#endif
+
+	.bus_info = &scc_mii_bus_info,
+};
+
+void __init board_init(void)
+{
+	volatile cpm8xx_t *cp = cpmp;
+	unsigned int *bcsr_io;
+
+#ifdef CONFIG_FS_ENET
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+#endif
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR\n");
+		return;
+	}
+#ifdef CONFIG_SERIAL_CPM_SMC1
+	cp->cp_simode &= ~(0xe0000000 >> 17);	/* brg1 */
+	clrbits32(bcsr_io, BCSR1_RS232EN_1);
+#else
+	setbits32(bcsr_io,BCSR1_RS232EN_1);
+	cp->cp_smc[0].smc_smcmr = 0;
+	cp->cp_smc[0].smc_smce = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+	cp->cp_simode &= ~(0xe0000000 >> 1);
+	cp->cp_simode |= (0x20000000 >> 1);	/* brg2 */
+	clrbits32(bcsr_io,BCSR1_RS232EN_2);
+#else
+	setbits32(bcsr_io,BCSR1_RS232EN_2);
+	cp->cp_smc[1].smc_smcmr = 0;
+	cp->cp_smc[1].smc_smce = 0;
+#endif
+	iounmap(bcsr_io);
+
+#ifdef CONFIG_FS_ENET
+	/* use MDC for MII (common) */
+	setbits16(&immap->im_ioport.iop_pdpar, 0x0080);
+	clrbits16(&immap->im_ioport.iop_pddir, 0x0080);
+#endif
+}
+
+static void setup_fec1_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+
+	/* configure FEC1 pins  */
+	setbits16(&immap->im_ioport.iop_papar, 0xf830);
+	setbits16(&immap->im_ioport.iop_padir, 0x0830);
+	clrbits16(&immap->im_ioport.iop_padir, 0xf000);
+	setbits32(&immap->im_cpm.cp_pbpar, 0x00001001);
+
+	clrbits32(&immap->im_cpm.cp_pbdir, 0x00001001);
+	setbits16(&immap->im_ioport.iop_pcpar, 0x000c);
+	clrbits16(&immap->im_ioport.iop_pcdir, 0x000c);
+	setbits32(&immap->im_cpm.cp_pepar, 0x00000003);
+
+	setbits32(&immap->im_cpm.cp_pedir, 0x00000003);
+	clrbits32(&immap->im_cpm.cp_peso, 0x00000003);
+	clrbits32(&immap->im_cpm.cp_cptr, 0x00000100);
+}
+
+static void setup_fec2_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+
+	/* configure FEC2 pins */
+	setbits32(&immap->im_cpm.cp_pepar, 0x0003fffc);
+	setbits32(&immap->im_cpm.cp_pedir, 0x0003fffc);
+	setbits32(&immap->im_cpm.cp_peso, 0x00037800);
+	clrbits32(&immap->im_cpm.cp_peso, 0x000087fc);
+	clrbits32(&immap->im_cpm.cp_cptr, 0x00000080);
+}
+
+static void setup_scc3_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR\n");
+		return;
+	}
+
+	/* Enable the PHY.
+	 */
+	setbits32(bcsr_io+4, BCSR4_ETH10_RST);
+	/* Configure port A pins for Txd and Rxd.
+	 */
+	setbits16(&immap->im_ioport.iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(&immap->im_ioport.iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+
+	/* Configure port C pins to enable CLSN and RENA.
+	 */
+	clrbits16(&immap->im_ioport.iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+	clrbits16(&immap->im_ioport.iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+	setbits16(&immap->im_ioport.iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+
+	/* Configure port E for TCLK and RCLK.
+	 */
+	setbits32(&immap->im_cpm.cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK);
+	clrbits32(&immap->im_cpm.cp_pepar, PE_ENET_TENA);
+	clrbits32(&immap->im_cpm.cp_pedir,
+		  PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
+	clrbits32(&immap->im_cpm.cp_peso, PE_ENET_TCLK | PE_ENET_RCLK);
+	setbits32(&immap->im_cpm.cp_peso, PE_ENET_TENA);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	clrbits32(&immap->im_cpm.cp_sicr, SICR_ENET_MASK);
+	setbits32(&immap->im_cpm.cp_sicr, SICR_ENET_CLKRT);
+
+	/* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used.
+	 */
+	immap->im_cpm.cp_smc[0].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+	/* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode
+	 * by H/W setting after reset. SCC ethernet controller support only half duplex.
+	 * This discrepancy of modes causes a lot of carrier lost errors.
+	 */
+
+	/* In the original SCC enet driver the following code is placed at
+	   the end of the initialization */
+	setbits32(&immap->im_cpm.cp_pepar, PE_ENET_TENA);
+	clrbits32(&immap->im_cpm.cp_pedir, PE_ENET_TENA);
+	setbits32(&immap->im_cpm.cp_peso, PE_ENET_TENA);
+
+	setbits32(bcsr_io+1, BCSR1_ETHEN);
+	iounmap(bcsr_io);
+}
+
+static void mpc885ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
+{
+	struct fs_platform_info *fpi = pdev->dev.platform_data;
+
+	volatile cpm8xx_t *cp;
+	bd_t *bd = (bd_t *) __res;
+	char *e;
+	int i;
+
+	/* Get pointer to Communication Processor */
+	cp = cpmp;
+	switch (fs_no) {
+	case fsid_fec1:
+		fpi = &mpc8xx_fec_pdata[0];
+		fpi->init_ioports = &setup_fec1_ioports;
+		break;
+	case fsid_fec2:
+		fpi = &mpc8xx_fec_pdata[1];
+		fpi->init_ioports = &setup_fec2_ioports;
+		break;
+	case fsid_scc3:
+		fpi = &mpc8xx_scc_pdata;
+		fpi->init_ioports = &setup_scc3_ioports;
+		mpc885ads_scc_phy_init(fpi->phy_addr);
+		break;
+	default:
+		break;
+	}
+
+	pdev->dev.platform_data = fpi;
+	fpi->fs_no = fs_no;
+
+	e = (unsigned char *)&bd->bi_enetaddr;
+	for (i = 0; i < 6; i++)
+		fpi->macaddr[i] = *e++;
+
+	fpi->macaddr[5 - pdev->id]++;
+
+}
+
+static void mpc885ads_fixup_fec_enet_pdata(struct platform_device *pdev,
+					   int idx)
+{
+	/* This is for FEC devices only */
+	if (!strstr(pdev->name, "fsl-cpm-fec"))
+		return;
+	mpc885ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1);
+}
+
+static void __init mpc885ads_fixup_scc_enet_pdata(struct platform_device *pdev,
+						  int idx)
+{
+	/* This is for SCC devices only */
+	if (!strstr(pdev->name, "fsl-cpm-scc"))
+		return;
+
+	mpc885ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
+}
+
+/* SCC ethernet controller does not have MII management channel. FEC1 MII
+ * channel is used to communicate with the 10Mbit PHY.
+ */
+
+#define MII_ECNTRL_PINMUX        0x4
+#define FEC_ECNTRL_PINMUX        0x00000004
+#define FEC_RCNTRL_MII_MODE        0x00000004
+
+/* Make MII read/write commands.
+ */
+#define mk_mii_write(REG, VAL, PHY_ADDR)    (0x50020000 | (((REG) & 0x1f) << 18) | \
+                ((VAL) & 0xffff) | ((PHY_ADDR) << 23))
+
+static void mpc885ads_scc_phy_init(char phy_addr)
+{
+	volatile immap_t *immap;
+	volatile fec_t *fecp;
+	bd_t *bd;
+
+	bd = (bd_t *) __res;
+	immap = (immap_t *) IMAP_ADDR;	/* pointer to internal registers */
+	fecp = &(immap->im_cpm.cp_fec);
+
+	/* Enable MII pins of the FEC1
+	 */
+	setbits16(&immap->im_ioport.iop_pdpar, 0x0080);
+	clrbits16(&immap->im_ioport.iop_pddir, 0x0080);
+	/* Set MII speed to 2.5 MHz
+	 */
+	out_be32(&fecp->fec_mii_speed,
+		 ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1);
+
+	/* Enable FEC pin MUX
+	 */
+	setbits32(&fecp->fec_ecntrl, MII_ECNTRL_PINMUX);
+	setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
+
+	out_be32(&fecp->fec_mii_data,
+		 mk_mii_write(MII_BMCR, BMCR_ISOLATE, phy_addr));
+	udelay(100);
+	out_be32(&fecp->fec_mii_data,
+		 mk_mii_write(MII_ADVERTISE,
+			      ADVERTISE_10HALF | ADVERTISE_CSMA, phy_addr));
+	udelay(100);
+
+	/* Disable FEC MII settings
+	 */
+	clrbits32(&fecp->fec_ecntrl, MII_ECNTRL_PINMUX);
+	clrbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
+	out_be32(&fecp->fec_mii_speed, 0);
+}
+
+static int mpc885ads_platform_notify(struct device *dev)
+{
+	static struct {
+		const char *bus_id;
+		void (*rtn) (struct platform_device * pdev, int idx);
+	} dev_map[] = {
+		{
+		"fsl-cpm-fec", mpc885ads_fixup_fec_enet_pdata}, {
+	"fsl-cpm-scc", mpc885ads_fixup_scc_enet_pdata},};
+	struct platform_device *pdev;
+	int i, j, idx;
+	const char *s;
+	if (dev && dev->bus_id)
+		for (i = 0; i < ARRAY_SIZE(dev_map); i++) {
+			idx = -1;
+
+			if ((s = strrchr(dev->bus_id, '.')) != NULL)
+				idx = (int)simple_strtol(s + 1, NULL, 10);
+			else
+				s = dev->bus_id;
+			j = s - dev->bus_id;
+			if (!strncmp(dev->bus_id, dev_map[i].bus_id, j)) {
+				pdev =
+				    container_of(dev, struct platform_device,
+						 dev);
+				dev_map[i].rtn(pdev, idx);
+			}
+		}
+	return 0;
+}
+
+int __init mpc885ads_init(void)
+{
+	printk(KERN_NOTICE "mpc885ads: Init\n");
+
+	platform_notify = mpc885ads_platform_notify;
+
+	identify_ppc_sys_by_name(BOARD_CHIP_NAME);
+
+#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
+	ppc_sys_device_remove(MPC8xx_CPM_FEC2);
+#endif
+#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
+	ppc_sys_device_remove(MPC8xx_CPM_SCC3);
+#endif
+
+	ppc_sys_device_remove(MPC8xx_CPM_SCC1);
+	ppc_sys_device_remove(MPC8xx_CPM_SCC2);
+	ppc_sys_device_remove(MPC8xx_CPM_SCC4);
+	ppc_sys_device_remove(MPC8xx_CPM_SMC1);
+	ppc_sys_device_remove(MPC8xx_CPM_SMC2);
+
+	return 0;
+}
+
+arch_initcall(mpc885ads_init);
diff --git a/arch/ppc/platforms/pq2ads.h b/arch/ppc/platforms/pq2ads.h
index 067d9a5..6b26dd3 100644
--- a/arch/ppc/platforms/pq2ads.h
+++ b/arch/ppc/platforms/pq2ads.h
@@ -13,6 +13,10 @@
 
 #include <asm/ppcboot.h>
 
+#if defined(CONFIG_ADS8272)
+#define BOARD_CHIP_NAME "8272"
+#endif
+
 /* Memory map is configured by the PROM startup.
  * We just map a few things we need.  The CSR is actually 4 byte-wide
  * registers that can be accessed as 8-, 16-, or 32-bit values.
diff --git a/arch/ppc/platforms/pq2ads_pd.h b/arch/ppc/platforms/pq2ads_pd.h
new file mode 100644
index 0000000..5b5e92d
--- /dev/null
+++ b/arch/ppc/platforms/pq2ads_pd.h
@@ -0,0 +1,114 @@
+#ifndef __PQ2ADS_PD_H
+#define __PQ2ADS_PD_H
+/*
+ * arch/ppc/platforms/82xx/pq2ads_pd.h
+ *
+ * Some defines for MPC82xx board-specific PlatformDevice descriptions
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/* FCC1 Clock Source Configuration.  These can be redefined in the board specific file.
+   Can only choose from CLK9-12 */
+
+#define F1_RXCLK	11
+#define F1_TXCLK	10
+
+/* FCC2 Clock Source Configuration.  These can be redefined in the board specific file.
+   Can only choose from CLK13-16 */
+#define F2_RXCLK	15
+#define F2_TXCLK	16
+
+/* FCC3 Clock Source Configuration.  These can be redefined in the board specific file.
+   Can only choose from CLK13-16 */
+#define F3_RXCLK	13
+#define F3_TXCLK	14
+
+/* Automatically generates register configurations */
+#define PC_CLK(x)	((uint)(1<<(x-1)))	/* FCC CLK I/O ports */
+
+#define CMXFCR_RF1CS(x)	((uint)((x-5)<<27))	/* FCC1 Receive Clock Source */
+#define CMXFCR_TF1CS(x)	((uint)((x-5)<<24))	/* FCC1 Transmit Clock Source */
+#define CMXFCR_RF2CS(x)	((uint)((x-9)<<19))	/* FCC2 Receive Clock Source */
+#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16))	/* FCC2 Transmit Clock Source */
+#define CMXFCR_RF3CS(x)	((uint)((x-9)<<11))	/* FCC3 Receive Clock Source */
+#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8))	/* FCC3 Transmit Clock Source */
+
+#define PC_F1RXCLK	PC_CLK(F1_RXCLK)
+#define PC_F1TXCLK	PC_CLK(F1_TXCLK)
+#define CMX1_CLK_ROUTE	(CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK))
+#define CMX1_CLK_MASK	((uint)0xff000000)
+
+#define PC_F2RXCLK	PC_CLK(F2_RXCLK)
+#define PC_F2TXCLK	PC_CLK(F2_TXCLK)
+#define CMX2_CLK_ROUTE	(CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK))
+#define CMX2_CLK_MASK	((uint)0x00ff0000)
+
+#define PC_F3RXCLK	PC_CLK(F3_RXCLK)
+#define PC_F3TXCLK	PC_CLK(F3_TXCLK)
+#define CMX3_CLK_ROUTE	(CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK))
+#define CMX3_CLK_MASK	((uint)0x0000ff00)
+
+/* I/O Pin assignment for FCC1.  I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PA1_COL		0x00000001U
+#define PA1_CRS		0x00000002U
+#define PA1_TXER	0x00000004U
+#define PA1_TXEN	0x00000008U
+#define PA1_RXDV	0x00000010U
+#define PA1_RXER	0x00000020U
+#define PA1_TXDAT	0x00003c00U
+#define PA1_RXDAT	0x0003c000U
+#define PA1_PSORA0	(PA1_RXDAT | PA1_TXDAT)
+#define PA1_PSORA1	(PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \
+		PA1_RXDV | PA1_RXER)
+#define PA1_DIRA0	(PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)
+#define PA1_DIRA1	(PA1_TXDAT | PA1_TXEN | PA1_TXER)
+
+
+/* I/O Pin assignment for FCC2.  I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PB2_TXER	0x00000001U
+#define PB2_RXDV	0x00000002U
+#define PB2_TXEN	0x00000004U
+#define PB2_RXER	0x00000008U
+#define PB2_COL		0x00000010U
+#define PB2_CRS		0x00000020U
+#define PB2_TXDAT	0x000003c0U
+#define PB2_RXDAT	0x00003c00U
+#define PB2_PSORB0	(PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \
+		PB2_RXER | PB2_RXDV | PB2_TXER)
+#define PB2_PSORB1	(PB2_TXEN)
+#define PB2_DIRB0	(PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV)
+#define PB2_DIRB1	(PB2_TXDAT | PB2_TXEN | PB2_TXER)
+
+
+/* I/O Pin assignment for FCC3.  I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PB3_RXDV	0x00004000U
+#define PB3_RXER	0x00008000U
+#define PB3_TXER	0x00010000U
+#define PB3_TXEN	0x00020000U
+#define PB3_COL		0x00040000U
+#define PB3_CRS		0x00080000U
+#define PB3_TXDAT	0x0f000000U
+#define PB3_RXDAT	0x00f00000U
+#define PB3_PSORB0	(PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \
+		PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN)
+#define PB3_PSORB1	0
+#define PB3_DIRB0	(PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV)
+#define PB3_DIRB1	(PB3_TXDAT | PB3_TXEN | PB3_TXER)
+
+#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
+#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
+#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
+
+#endif

^ permalink raw reply related

* [PATCH] ppc32 8xx: Added setbitsXX/clrbitsXX macro for read-modify-write operations
From: Vitaly Bordug @ 2005-11-28 15:34 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: linuxppc-devel list, linuxppc-embedded list

This adds setbitsXX/clrbitsXX macro for read-modify-write operations
and converts the 8xx core and drivers to use it.

Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>


---

  arch/ppc/8xx_io/commproc.c   |    6 +++---
  arch/ppc/syslib/m8xx_setup.c |   12 +++++-------
  arch/ppc/syslib/m8xx_wdt.c   |    3 +--
  include/asm-ppc/io.h         |    7 +++++++
  4 files changed, 16 insertions(+), 12 deletions(-)

applies-to: d2cd86c706af9e6ad47e2dda6b24df0d93f6f98f
055cb7782e10f214243c31522229173660cb24bc
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
index 579cd40..5cecb6e 100644
--- a/arch/ppc/8xx_io/commproc.c
+++ b/arch/ppc/8xx_io/commproc.c
@@ -73,7 +73,7 @@ cpm_mask_irq(unsigned int irq)
  {
  	int cpm_vec = irq - CPM_IRQ_OFFSET;

-	out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, in_be32(&((immap_t 
*)IMAP_ADDR)->im_cpic.cpic_cimr) & ~(1 << cpm_vec));
+	clrbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr,(1 << cpm_vec));
  }

  static void
@@ -81,7 +81,7 @@ cpm_unmask_irq(unsigned int irq)
  {
  	int cpm_vec = irq - CPM_IRQ_OFFSET;

-	out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, in_be32(&((immap_t 
*)IMAP_ADDR)->im_cpic.cpic_cimr) | (1 << cpm_vec));
+	setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr,(1 << cpm_vec));
  }

  static void
@@ -198,7 +198,7 @@ cpm_interrupt_init(void)
  	if (setup_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, &cpm_error_irqaction))
  		panic("Could not allocate CPM error IRQ!");

-	out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, in_be32(&((immap_t 
*)IMAP_ADDR)->im_cpic.cpic_cicr) | CICR_IEN);
+	setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, CICR_IEN);
  }

  /*
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 1cc3abe..ad7db45 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -149,8 +149,7 @@ void __init m8xx_calibrate_decr(void)
  	out_be32(&((immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk, KAPWR_KEY);

  	/* Force all 8xx processors to use divide by 16 processor clock. */
-	out_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr,
-		in_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr)|0x02000000);
+	setbits32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr, 0x02000000);
  	/* Processor frequency is MHz.
  	 * The value 'fp' is the number of decrementer ticks per second.
  	 */
@@ -184,10 +183,9 @@ void __init m8xx_calibrate_decr(void)
  	out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, KAPWR_KEY);

  	/* Disable the RTC one second and alarm interrupts. */
-	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t 
*)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE));
+	clrbits16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, (RTCSC_SIE | RTCSC_ALE));
  	/* Enable the RTC */
-	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t 
*)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE));
-
+	setbits16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, (RTCSC_RTF | RTCSC_RTE));
  	/* Enabling the decrementer also enables the timebase interrupts
  	 * (or from the other point of view, to get decrementer interrupts
  	 * we have to enable the timebase).  The decrementer interrupt
@@ -232,8 +230,8 @@ m8xx_restart(char *cmd)
  	__volatile__ unsigned char dummy;

  	local_irq_disable();
-	out_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr, in_be32(&((immap_t 
*)IMAP_ADDR)->im_clkrst.car_plprcr) | 0x00000080);

+	setbits32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr, 0x00000080);
  	/* Clear the ME bit in MSR to cause checkstop on machine check
  	*/
  	mtmsr(mfmsr() & ~0x1000);
@@ -303,8 +301,8 @@ m8xx_init_IRQ(void)
  	i8259_init(0);

  	/* The i8259 cascade interrupt must be level sensitive. */
-	out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel, in_be32(&((immap_t 
*)IMAP_ADDR)->im_siu_conf.sc_siel & ~(0x80000000 >> ISA_BRIDGE_INT)));

+	clrbits32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel, (0x80000000 >> ISA_BRIDGE_INT));
  	if (setup_irq(ISA_BRIDGE_INT, &mbx_i8259_irqaction))
  		enable_irq(ISA_BRIDGE_INT);
  #endif	/* CONFIG_PCI */
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
index a21632d..57f8b9f 100644
--- a/arch/ppc/syslib/m8xx_wdt.c
+++ b/arch/ppc/syslib/m8xx_wdt.c
@@ -40,8 +40,7 @@ static irqreturn_t m8xx_wdt_interrupt(in

  	m8xx_wdt_reset();

-	out_be16(&imap->im_sit.sit_piscr, in_be16(&imap->im_sit.sit_piscr) | PISCR_PS);	/* clear 
irq */
-
+	setbits16(&imap->im_sit.sit_piscr, PISCR_PS);
  	return IRQ_HANDLED;
  }

diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index 2bfdf9c..0ff4395 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -556,4 +556,11 @@ extern void pci_iounmap(struct pci_dev *
   */
  #define xlate_dev_kmem_ptr(p)	p

+/* access ports */
+#define setbits32(_addr, _v) out_be32((_addr), in_be32(_addr) |  (_v))
+#define clrbits32(_addr, _v) out_be32((_addr), in_be32(_addr) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16((_addr), in_be16(_addr) |  (_v))
+#define clrbits16(_addr, _v) out_be16((_addr), in_be16(_addr) & ~(_v))
+
  #endif /* __KERNEL__ */
---
Sincerely,
Vitaly

^ permalink raw reply related

* Joystick and Lite5200
From: Alan Carvalho @ 2005-11-28 15:27 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 6533 bytes --]

Hi all,
I am trying use Logitech WingMan Strike Force 3D on Lite5200 board. I am
using linux-2.6.14 Denx's tree, just selecting this options:

CONFIG_INPUT=y
CONFIG_INPUT_JOYDEV=y
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=y

and

CONFIG_USB_HID=y
CONFIG_USB_HIDINPUT=y
CONFIG_HID_FF=y
CONFIG_LOGITECH_FF=y

As my device ID is not listed in hid-ff.c and hid-lgff.c, then I mapped it:

drivers/usb/input/hid-ff.c :
{0x46d, 0xc285, hid_lgff_init}, // Logitech Wingman Strike Force 3d

drivers/usb/input/hid-lgff.c
{0x046d, 0xc285, ff_joystick},
(I need do it in the PC to force feedback work fine too)

But the problem is the driver is not working correctly, if I try open
/dev/input/event0 it return "No such device", but as you can see below
evbug.c show correctly all joystick events.

Suggestions?

Best regard,

Alan

/ # dmesg
...
usbmon: debugfs is not available
2005 April 22 USB 1.1 'Open' Host Controller (OHCI) Driver (PPC SOC)
block sizes: ed 64 td 64
initializing PPC-SOC USB Controller
ppc-soc-ohci ppc-soc-ohci: USB Host Controller
ppc-soc-ohci ppc-soc-ohci: new USB bus registered, assigned bus number 1
ppc-soc-ohci ppc-soc-ohci: irq 44, io mem 0xf0001000
ppc-soc-ohci ppc-soc-ohci: resetting from state 'reset', control = 0x0
ppc-soc-ohci ppc-soc-ohci: OHCI controller state
ppc-soc-ohci ppc-soc-ohci: OHCI 1.0, NO legacy support registers
ppc-soc-ohci ppc-soc-ohci: control 0x083 HCFS=operational CBSR=3
ppc-soc-ohci ppc-soc-ohci: cmdstatus 0x00000 SOC=0
ppc-soc-ohci ppc-soc-ohci: intrstatus 0x00000044 RHSC SF
ppc-soc-ohci ppc-soc-ohci: intrenable 0x8000001a MIE UE RD WDH
ppc-soc-ohci ppc-soc-ohci: hcca frame #0005
ppc-soc-ohci ppc-soc-ohci: roothub.a 02001202 POTPGT=2 NOCP NPS NDP=2(2)
ppc-soc-ohci ppc-soc-ohci: roothub.b 00000000 PPCM=0000 DR=0000
ppc-soc-ohci ppc-soc-ohci: roothub.status 00008000 DRWE
ppc-soc-ohci ppc-soc-ohci: roothub.portstatus [0] 0x00000100 PPS
ppc-soc-ohci ppc-soc-ohci: roothub.portstatus [1] 0x00000100 PPS
ppc-soc-ohci ppc-soc-ohci: created debug files
usb usb1: default language 0x0409
usb usb1: new device strings: Mfr=3, Product=2, SerialNumber=1
usb usb1: Product: USB Host Controller
usb usb1: Manufacturer: Linux 2.6.14 ohci_hcd
usb usb1: SerialNumber: PPC-SOC USB
usb usb1: adding 1-0:1.0 (config #1, interface 0)
hub 1-0:1.0: usb_probe_interface
hub 1-0:1.0: usb_probe_interface - got id
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
hub 1-0:1.0: standalone hub
hub 1-0:1.0: ganged power switching
hub 1-0:1.0: global over-current protection
hub 1-0:1.0: power on to power good time: 4ms
hub 1-0:1.0: local power source is good
hub 1-0:1.0: no over-current condition exists
hub 1-0:1.0: enabling power on all ports
ohci_hcd: 2005 April 22 USB 1.1 'Open' Host Controller (OHCI) Driver (PCI)
ohci_hcd: block sizes: ed 64 td 64
usbcore: registered new driver usbhid
drivers/usb/input/hid-core.c: v2.6:USB HID core driver
hub 1-0:1.0: state 5 ports 2 chg 0000 evt 0000
Serial: MPC52xx PSC driver
ttyS0 at MMIO 0xf0002000 (irq = 39) is a MPC52xx PSC
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered
RAMDISK driver initialized: 64 RAM disks of 4096K size 1024 blocksize
eth0: Phy @ 0x0, type LXT971 (0x001378e2)
Generic platform RAM MTD, (c) 2004 Simtec Electronics
mice: PS/2 mouse device common for all mice
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 4096 (order: 2, 16384 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP reno registered
TCP bic registered
NET: Registered protocol family 1
NET: Registered protocol family 17
RAMDISK: Compressed image found at block 0
VFS: Mounted root (romfs filesystem) readonly.
Freeing unused kernel memory: 108k init
hub 1-0:1.0: state 5 ports 2 chg 0000 evt 0002
ppc-soc-ohci ppc-soc-ohci: GetStatus roothub.portstatus [0] = 0x00010301 CSC
LSDA PPS CCS
hub 1-0:1.0: port 1, status 0301, change 0001, 1.5 Mb/s
hub 1-0:1.0: debounce: port 1: total 100ms stable 100ms status 0x301
ppc-soc-ohci ppc-soc-ohci: GetStatus roothub.portstatus [0] = 0x00100303
PRSC LSDA PPS PES CCS
usb 1-1: new low speed USB device using ppc-soc-ohci and address 2
ppc-soc-ohci ppc-soc-ohci: GetStatus roothub.portstatus [0] = 0x00100303
PRSC LSDA PPS PES CCS
usb 1-1: skipped 1 descriptor after interface
usb 1-1: default language 0x0409
usb 1-1: new device strings: Mfr=4, Product=32, SerialNumber=0
usb 1-1: Product: WingMan Strike Force 3D
usb 1-1: Manufacturer: Logitech Inc.
usb 1-1: adding 1-1:1.0 (config #1, interface 0)
usbhid 1-1:1.0: usb_probe_interface
usbhid 1-1:1.0: usb_probe_interface - got id
drivers/usb/input/hid-core.c: timeout initializing reports

Force feedback for Logitech force feedback devices by Johann Deneux <
johann.deneux@it.uu.se>
input: Logitech Inc. WingMan Strike Force 3D//class/input as input0
evbug.c: Connected device: "Logitech Inc. WingMan Strike Force 3D",
usb-PPC-SOC USB-1/input0
input<7>evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 3, Code: 0,
Value: 620
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 3, Code: 1, Value: 536
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 3, Code: 5, Value: 140
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 3, Code: 6, Value: 126
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 0, Code: 0, Value: 0
: USB HID v1.00 Joystick [Logitech Inc. WingMan Strike Force 3D] on
usb-PPC-SOC USB-1
hub 1-0:1.0: state 5 ports 2 chg 0000 evt 0002
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 3, Code: 0, Value: 619
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 0, Code: 0, Value: 0
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 3, Code: 5, Value: 141
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 0, Code: 0, Value: 0
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 3, Code: 0, Value: 618
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 0, Code: 0, Value: 0
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 3, Code: 0, Value: 624
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 0, Code: 0, Value: 0
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 3, Code: 0, Value: 618
evbug.c: Event. Dev: usb-PPC-SOC USB-1/input0, Type: 0, Code: 0, Value: 0
/ # cat /dev/input/event2
cat: /dev/input/event2: No such device

[-- Attachment #2: Type: text/html, Size: 7170 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox