From a58c9f3c1e929c3c323c26dbdafef46373a719d4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Feb 2007 04:16:21 -0800 Subject: [SPARC64]: Synchronize RTC clock via timer just like x86. Signed-off-by: David S. Miller --- arch/sparc64/kernel/time.c | 66 +++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index f84da4f1b70..d457079118d 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -435,22 +435,56 @@ static unsigned long timer_ticks_per_nsec_quotient __read_mostly; #define TICK_SIZE (tick_nsec / 1000) -static inline void timer_check_rtc(void) +#define USEC_AFTER 500000 +#define USEC_BEFORE 500000 + +static void sync_cmos_clock(unsigned long dummy); + +static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); + +static void sync_cmos_clock(unsigned long dummy) { - /* last time the cmos clock got updated */ - static long last_rtc_update; - - /* Determine when to update the Mostek clock. */ - if (ntp_synced() && - xtime.tv_sec > last_rtc_update + 660 && - (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && - (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - last_rtc_update = xtime.tv_sec - 600; - /* do it again in 60 s */ + struct timeval now, next; + int fail = 1; + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + * This code is run on a timer. If the clock is set, that timer + * may not expire at the correct time. Thus, we adjust... + */ + if (!ntp_synced()) + /* + * Not synced, exit, do not restart a timer (if one is + * running, let it run out). + */ + return; + + do_gettimeofday(&now); + if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 && + now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) + fail = set_rtc_mmss(now.tv_sec); + + next.tv_usec = USEC_AFTER - now.tv_usec; + if (next.tv_usec <= 0) + next.tv_usec += USEC_PER_SEC; + + if (!fail) + next.tv_sec = 659; + else + next.tv_sec = 0; + + if (next.tv_usec >= USEC_PER_SEC) { + next.tv_sec++; + next.tv_usec -= USEC_PER_SEC; } + mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next)); +} + +void notify_arch_cmos_timer(void) +{ + mod_timer(&sync_cmos_timer, jiffies + 1); } irqreturn_t timer_interrupt(int irq, void *dev_id) @@ -483,8 +517,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) : "r" (pstate)); } while (time_after_eq(ticks, compare)); - timer_check_rtc(); - write_sequnlock(&xtime_lock); return IRQ_HANDLED; @@ -497,8 +529,6 @@ void timer_tick_interrupt(struct pt_regs *regs) do_timer(1); - timer_check_rtc(); - write_sequnlock(&xtime_lock); } #endif -- cgit v1.2.3 From 777a447529ad138f5fceb9c9ad28bab19848f277 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Feb 2007 06:24:10 -0800 Subject: [SPARC64]: Unify timer interrupt handler. Things were scattered all over the place, split between SMP and non-SMP. Unify it all so that dyntick support is easier to add. Signed-off-by: David S. Miller --- arch/sparc64/kernel/irq.c | 26 ------------- arch/sparc64/kernel/smp.c | 87 +------------------------------------------ arch/sparc64/kernel/time.c | 43 +++++++++------------ arch/sparc64/kernel/ttable.S | 6 +-- include/asm-sparc64/cpudata.h | 4 +- include/asm-sparc64/smp.h | 4 +- include/asm-sparc64/ttable.h | 27 -------------- 7 files changed, 25 insertions(+), 172 deletions(-) diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index c443db18437..d1bb3b3f263 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -589,32 +589,6 @@ void ack_bad_irq(unsigned int virt_irq) ino, virt_irq); } -#ifndef CONFIG_SMP -extern irqreturn_t timer_interrupt(int, void *); - -void timer_irq(int irq, struct pt_regs *regs) -{ - unsigned long clr_mask = 1 << irq; - unsigned long tick_mask = tick_ops->softint_mask; - struct pt_regs *old_regs; - - if (get_softint() & tick_mask) { - irq = 0; - clr_mask = tick_mask; - } - clear_softint(clr_mask); - - old_regs = set_irq_regs(regs); - irq_enter(); - - kstat_this_cpu.irqs[0]++; - timer_interrupt(irq, NULL); - - irq_exit(); - set_irq_regs(old_regs); -} -#endif - void handler_irq(int irq, struct pt_regs *regs) { struct ino_bucket *bucket; diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index fc99f7b8012..39deb0346eb 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -45,7 +45,7 @@ extern void calibrate_delay(void); /* Please don't make this stuff initdata!!! --DaveM */ -static unsigned char boot_cpu_id; +unsigned char boot_cpu_id; cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; @@ -81,8 +81,6 @@ void __init smp_store_cpu_info(int id) struct device_node *dp; int def; - /* multiplier and counter set by - smp_setup_percpu_timer() */ cpu_data(id).udelay_val = loops_per_jiffy; cpu_find_by_mid(id, &dp); @@ -1180,75 +1178,10 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs) preempt_enable(); } -#define prof_multiplier(__cpu) cpu_data(__cpu).multiplier -#define prof_counter(__cpu) cpu_data(__cpu).counter - -void smp_percpu_timer_interrupt(struct pt_regs *regs) -{ - unsigned long compare, tick, pstate; - int cpu = smp_processor_id(); - int user = user_mode(regs); - struct pt_regs *old_regs; - - /* - * Check for level 14 softint. - */ - { - unsigned long tick_mask = tick_ops->softint_mask; - - if (!(get_softint() & tick_mask)) { - extern void handler_irq(int, struct pt_regs *); - - handler_irq(14, regs); - return; - } - clear_softint(tick_mask); - } - - old_regs = set_irq_regs(regs); - do { - profile_tick(CPU_PROFILING); - if (!--prof_counter(cpu)) { - irq_enter(); - - if (cpu == boot_cpu_id) { - kstat_this_cpu.irqs[0]++; - timer_tick_interrupt(regs); - } - - update_process_times(user); - - irq_exit(); - - prof_counter(cpu) = prof_multiplier(cpu); - } - - /* Guarantee that the following sequences execute - * uninterrupted. - */ - __asm__ __volatile__("rdpr %%pstate, %0\n\t" - "wrpr %0, %1, %%pstate" - : "=r" (pstate) - : "i" (PSTATE_IE)); - - compare = tick_ops->add_compare(current_tick_offset); - tick = tick_ops->get_tick(); - - /* Restore PSTATE_IE. */ - __asm__ __volatile__("wrpr %0, 0x0, %%pstate" - : /* no outputs */ - : "r" (pstate)); - } while (time_after_eq(tick, compare)); - set_irq_regs(old_regs); -} - static void __init smp_setup_percpu_timer(void) { - int cpu = smp_processor_id(); unsigned long pstate; - prof_counter(cpu) = prof_multiplier(cpu) = 1; - /* Guarantee that the following sequences execute * uninterrupted. */ @@ -1269,28 +1202,12 @@ void __init smp_tick_init(void) { boot_cpu_id = hard_smp_processor_id(); current_tick_offset = timer_tick_offset; - - prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1; } /* /proc/profile writes can call this, don't __init it please. */ -static DEFINE_SPINLOCK(prof_setup_lock); - int setup_profiling_timer(unsigned int multiplier) { - unsigned long flags; - int i; - - if ((!multiplier) || (timer_tick_offset / multiplier) < 1000) - return -EINVAL; - - spin_lock_irqsave(&prof_setup_lock, flags); - for_each_possible_cpu(i) - prof_multiplier(i) = multiplier; - current_tick_offset = (timer_tick_offset / multiplier); - spin_unlock_irqrestore(&prof_setup_lock, flags); - - return 0; + return -EINVAL; } static void __init smp_tune_scheduling(void) diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index d457079118d..48e1217c1e4 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -423,12 +424,6 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = { .softint_mask = 1UL << 0, }; -/* timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick - * - * NOTE: On SUN5 systems the ticker interrupt comes in using 2 - * interrupts, one at level14 and one with softint bit 0. - */ unsigned long timer_tick_offset __read_mostly; static unsigned long timer_ticks_per_nsec_quotient __read_mostly; @@ -487,18 +482,27 @@ void notify_arch_cmos_timer(void) mod_timer(&sync_cmos_timer, jiffies + 1); } -irqreturn_t timer_interrupt(int irq, void *dev_id) +void timer_interrupt(int irq, struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); unsigned long ticks, compare, pstate; + unsigned long tick_mask = tick_ops->softint_mask; + + clear_softint(tick_mask); + + irq_enter(); - write_seqlock(&xtime_lock); + kstat_this_cpu.irqs[0]++; do { -#ifndef CONFIG_SMP profile_tick(CPU_PROFILING); update_process_times(user_mode(get_irq_regs())); -#endif - do_timer(1); + + if (smp_processor_id() == boot_cpu_id) { + write_seqlock(&xtime_lock); + do_timer(1); + write_sequnlock(&xtime_lock); + } /* Guarantee that the following sequences execute * uninterrupted. @@ -515,24 +519,13 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : /* no outputs */ : "r" (pstate)); - } while (time_after_eq(ticks, compare)); + } while (unlikely(time_after_eq(ticks, compare))); - write_sequnlock(&xtime_lock); + irq_exit(); - return IRQ_HANDLED; + set_irq_regs(old_regs); } -#ifdef CONFIG_SMP -void timer_tick_interrupt(struct pt_regs *regs) -{ - write_seqlock(&xtime_lock); - - do_timer(1); - - write_sequnlock(&xtime_lock); -} -#endif - /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ static void __init kick_start_clock(void) { diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index d7d2a8bdc66..7575aa371da 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -60,11 +60,7 @@ tl0_irq4: BTRAP(0x44) tl0_irq5: TRAP_IRQ(handler_irq, 5) tl0_irq6: BTRAP(0x46) BTRAP(0x47) BTRAP(0x48) BTRAP(0x49) tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d) -#ifndef CONFIG_SMP -tl0_irq14: TRAP_IRQ(timer_irq, 14) -#else -tl0_irq14: TICK_SMP_IRQ -#endif +tl0_irq14: TRAP_IRQ(timer_interrupt, 14) tl0_irq15: TRAP_IRQ(handler_irq, 15) tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55) tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b) diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h index f2cc9411b4c..e89922d6718 100644 --- a/include/asm-sparc64/cpudata.h +++ b/include/asm-sparc64/cpudata.h @@ -17,8 +17,8 @@ typedef struct { /* Dcache line 1 */ unsigned int __softirq_pending; /* must be 1st, see rtrap.S */ - unsigned int multiplier; - unsigned int counter; + unsigned int __pad0_1; + unsigned int __pad0_2; unsigned int __pad1; unsigned long clock_tick; /* %tick's per second */ unsigned long udelay_val; diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index 388249b751c..cca54804b72 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -42,15 +42,15 @@ extern int hard_smp_processor_id(void); #define raw_smp_processor_id() (current_thread_info()->cpu) extern void smp_setup_cpu_possible_map(void); +extern unsigned char boot_cpu_id; #endif /* !(__ASSEMBLY__) */ #else #define smp_setup_cpu_possible_map() do { } while (0) +#define boot_cpu_id (0) #endif /* !(CONFIG_SMP) */ -#define NO_PROC_ID 0xFF - #endif /* !(_SPARC64_SMP_H) */ diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h index c2a16e18849..bbb9c8f13d6 100644 --- a/include/asm-sparc64/ttable.h +++ b/include/asm-sparc64/ttable.h @@ -157,23 +157,6 @@ ba,a,pt %xcc, rtrap_irq; \ .previous; -#define TICK_SMP_IRQ \ - rdpr %pil, %g2; \ - wrpr %g0, 15, %pil; \ - sethi %hi(1f-4), %g7; \ - ba,pt %xcc, etrap_irq; \ - or %g7, %lo(1f-4), %g7; \ - nop; \ - nop; \ - nop; \ - .subsection 2; \ -1: call trace_hardirqs_off; \ - nop; \ - call smp_percpu_timer_interrupt; \ - add %sp, PTREGS_OFF, %o0; \ - ba,a,pt %xcc, rtrap_irq; \ - .previous; - #else #define TRAP_IRQ(routine, level) \ @@ -186,16 +169,6 @@ add %sp, PTREGS_OFF, %o1; \ ba,a,pt %xcc, rtrap_irq; -#define TICK_SMP_IRQ \ - rdpr %pil, %g2; \ - wrpr %g0, 15, %pil; \ - sethi %hi(109f), %g7; \ - ba,pt %xcc, etrap_irq; \ -109: or %g7, %lo(109b), %g7; \ - call smp_percpu_timer_interrupt; \ - add %sp, PTREGS_OFF, %o0; \ - ba,a,pt %xcc, rtrap_irq; - #endif #define TRAP_IVEC TRAP_NOSAVE(do_ivec) -- cgit v1.2.3 From 038cb01ea69cb24ecf30e3ec882e429c84badbeb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Feb 2007 06:24:45 -0800 Subject: [SPARC64]: Add tick_nohz_{stop,restart}_sched_tick() calls to cpu_idle(). Signed-off-by: David S. Miller --- arch/sparc64/kernel/process.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index b291060c25a..a114151f9fb 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -88,12 +89,14 @@ void cpu_idle(void) set_thread_flag(TIF_POLLING_NRFLAG); while(1) { - if (need_resched()) { - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - } - sparc64_yield(); + tick_nohz_stop_sched_tick(); + while (!need_resched()) + sparc64_yield(); + tick_nohz_restart_sched_tick(); + + preempt_enable_no_resched(); + schedule(); + preempt_disable(); } } -- cgit v1.2.3 From 112f48716d9f292c92a033cff9e3ce7405ed4280 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 5 Mar 2007 15:28:37 -0800 Subject: [SPARC64]: Add clocksource/clockevents support. I'd like to thank John Stul and others for helping me along the way. A lot of cleanups fell out of this. For example, the get_compare() tick_op was totally unused, so was deleted. And the most often used tick_op members were grouped together for cache-friendlyness. The sparc64 TSC is given to the kernel as a one-shot timer. tick_ops->init_timer() simply turns off the privileged bit in the tick register (when possible), and disables the interrupt by setting bit 63 in the compare register. The ->disable_irq() op also sets this bit. tick_ops->add_compare() is changed to: 1) Add the given delta to "tick" not to "compare" 2) Return a boolean which, if true, means that the tick value read after writing the compare value was found to have incremented past the initial tick value. This mirrors logic used in the HPET driver's ->next_event() method. Each tick_ops implementation also now provides a name string. And we feed this into the clocksource and clockevents layers. Signed-off-by: David S. Miller --- arch/sparc64/Kconfig | 14 +- arch/sparc64/kernel/smp.c | 29 +--- arch/sparc64/kernel/time.c | 408 +++++++++++++++++++++++--------------------- include/asm-sparc64/timer.h | 17 +- 4 files changed, 238 insertions(+), 230 deletions(-) diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 1a6348b565f..51c87fdd998 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -19,6 +19,14 @@ config SPARC64 SPARC64 ports; its web page is available at . +config GENERIC_TIME + bool + default y + +config GENERIC_CLOCKEVENTS + bool + default y + config 64BIT def_bool y @@ -34,10 +42,6 @@ config LOCKDEP_SUPPORT bool default y -config TIME_INTERPOLATION - bool - default y - config ARCH_MAY_HAVE_PC_FDC bool default y @@ -113,6 +117,8 @@ config GENERIC_HARDIRQS menu "General machine setup" +source "kernel/time/Kconfig" + config SMP bool "Symmetric multi-processing support" ---help--- diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 39deb0346eb..d4f0a70f484 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -123,7 +123,7 @@ void __init smp_store_cpu_info(int id) cpu_data(id).ecache_size, cpu_data(id).ecache_line_size); } -static void smp_setup_percpu_timer(void); +extern void setup_sparc64_timer(void); static volatile unsigned long callin_flag = 0; @@ -138,7 +138,7 @@ void __init smp_callin(void) __flush_tlb_all(); - smp_setup_percpu_timer(); + setup_sparc64_timer(); if (cheetah_pcache_forced_on) cheetah_enable_pcache(); @@ -175,8 +175,6 @@ void cpu_panic(void) panic("SMP bolixed\n"); } -static unsigned long current_tick_offset __read_mostly; - /* This tick register synchronization scheme is taken entirely from * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit. * @@ -259,7 +257,7 @@ void smp_synchronize_tick_client(void) } else adj = -delta; - tick_ops->add_tick(adj, current_tick_offset); + tick_ops->add_tick(adj); } #if DEBUG_TICK_SYNC t[i].rt = rt; @@ -1178,30 +1176,9 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs) preempt_enable(); } -static void __init smp_setup_percpu_timer(void) -{ - unsigned long pstate; - - /* Guarantee that the following sequences execute - * uninterrupted. - */ - __asm__ __volatile__("rdpr %%pstate, %0\n\t" - "wrpr %0, %1, %%pstate" - : "=r" (pstate) - : "i" (PSTATE_IE)); - - tick_ops->init_tick(current_tick_offset); - - /* Restore PSTATE_IE. */ - __asm__ __volatile__("wrpr %0, 0x0, %%pstate" - : /* no outputs */ - : "r" (pstate)); -} - void __init smp_tick_init(void) { boot_cpu_id = hard_smp_processor_id(); - current_tick_offset = timer_tick_offset; } /* /proc/profile writes can call this, don't __init it please. */ diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 48e1217c1e4..21e3b0b9d9c 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -61,6 +63,7 @@ static void __iomem *mstk48t59_regs; static int set_rtc_mmss(unsigned long); #define TICK_PRIV_BIT (1UL << 63) +#define TICKCMP_IRQ_BIT (1UL << 63) #ifdef CONFIG_SMP unsigned long profile_pc(struct pt_regs *regs) @@ -94,21 +97,22 @@ static void tick_disable_protection(void) : "g2"); } -static void tick_init_tick(unsigned long offset) +static void tick_disable_irq(void) { - tick_disable_protection(); - __asm__ __volatile__( - " rd %%tick, %%g1\n" - " andn %%g1, %1, %%g1\n" " ba,pt %%xcc, 1f\n" - " add %%g1, %0, %%g1\n" + " nop\n" " .align 64\n" - "1: wr %%g1, 0x0, %%tick_cmpr\n" + "1: wr %0, 0x0, %%tick_cmpr\n" " rd %%tick_cmpr, %%g0" : /* no outputs */ - : "r" (offset), "r" (TICK_PRIV_BIT) - : "g1"); + : "r" (TICKCMP_IRQ_BIT)); +} + +static void tick_init_tick(void) +{ + tick_disable_protection(); + tick_disable_irq(); } static unsigned long tick_get_tick(void) @@ -122,20 +126,14 @@ static unsigned long tick_get_tick(void) return ret & ~TICK_PRIV_BIT; } -static unsigned long tick_get_compare(void) +static int tick_add_compare(unsigned long adj) { - unsigned long ret; + unsigned long orig_tick, new_tick, new_compare; - __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" - "mov %0, %0" - : "=r" (ret)); + __asm__ __volatile__("rd %%tick, %0" + : "=r" (orig_tick)); - return ret; -} - -static unsigned long tick_add_compare(unsigned long adj) -{ - unsigned long new_compare; + orig_tick &= ~TICKCMP_IRQ_BIT; /* Workaround for Spitfire Errata (#54 I think??), I discovered * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch @@ -146,44 +144,41 @@ static unsigned long tick_add_compare(unsigned long adj) * at the start of an I-cache line, and perform a dummy * read back from %tick_cmpr right after writing to it. -DaveM */ - __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" - "ba,pt %%xcc, 1f\n\t" - " add %0, %1, %0\n\t" + __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" + " add %1, %2, %0\n\t" ".align 64\n" "1:\n\t" "wr %0, 0, %%tick_cmpr\n\t" - "rd %%tick_cmpr, %%g0" - : "=&r" (new_compare) - : "r" (adj)); + "rd %%tick_cmpr, %%g0\n\t" + : "=r" (new_compare) + : "r" (orig_tick), "r" (adj)); + + __asm__ __volatile__("rd %%tick, %0" + : "=r" (new_tick)); + new_tick &= ~TICKCMP_IRQ_BIT; - return new_compare; + return ((long)(new_tick - (orig_tick+adj))) > 0L; } -static unsigned long tick_add_tick(unsigned long adj, unsigned long offset) +static unsigned long tick_add_tick(unsigned long adj) { - unsigned long new_tick, tmp; + unsigned long new_tick; /* Also need to handle Blackbird bug here too. */ __asm__ __volatile__("rd %%tick, %0\n\t" - "add %0, %2, %0\n\t" + "add %0, %1, %0\n\t" "wrpr %0, 0, %%tick\n\t" - "andn %0, %4, %1\n\t" - "ba,pt %%xcc, 1f\n\t" - " add %1, %3, %1\n\t" - ".align 64\n" - "1:\n\t" - "wr %1, 0, %%tick_cmpr\n\t" - "rd %%tick_cmpr, %%g0" - : "=&r" (new_tick), "=&r" (tmp) - : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT)); + : "=&r" (new_tick) + : "r" (adj)); return new_tick; } static struct sparc64_tick_ops tick_operations __read_mostly = { + .name = "tick", .init_tick = tick_init_tick, + .disable_irq = tick_disable_irq, .get_tick = tick_get_tick, - .get_compare = tick_get_compare, .add_tick = tick_add_tick, .add_compare = tick_add_compare, .softint_mask = 1UL << 0, @@ -191,7 +186,15 @@ static struct sparc64_tick_ops tick_operations __read_mostly = { struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations; -static void stick_init_tick(unsigned long offset) +static void stick_disable_irq(void) +{ + __asm__ __volatile__( + "wr %0, 0x0, %%asr25" + : /* no outputs */ + : "r" (TICKCMP_IRQ_BIT)); +} + +static void stick_init_tick(void) { /* Writes to the %tick and %stick register are not * allowed on sun4v. The Hypervisor controls that @@ -199,6 +202,7 @@ static void stick_init_tick(unsigned long offset) */ if (tlb_type != hypervisor) { tick_disable_protection(); + tick_disable_irq(); /* Let the user get at STICK too. */ __asm__ __volatile__( @@ -210,14 +214,7 @@ static void stick_init_tick(unsigned long offset) : "g1", "g2"); } - __asm__ __volatile__( - " rd %%asr24, %%g1\n" - " andn %%g1, %1, %%g1\n" - " add %%g1, %0, %%g1\n" - " wr %%g1, 0x0, %%asr25" - : /* no outputs */ - : "r" (offset), "r" (TICK_PRIV_BIT) - : "g1"); + stick_disable_irq(); } static unsigned long stick_get_tick(void) @@ -230,49 +227,43 @@ static unsigned long stick_get_tick(void) return ret & ~TICK_PRIV_BIT; } -static unsigned long stick_get_compare(void) -{ - unsigned long ret; - - __asm__ __volatile__("rd %%asr25, %0" - : "=r" (ret)); - - return ret; -} - -static unsigned long stick_add_tick(unsigned long adj, unsigned long offset) +static unsigned long stick_add_tick(unsigned long adj) { - unsigned long new_tick, tmp; + unsigned long new_tick; __asm__ __volatile__("rd %%asr24, %0\n\t" - "add %0, %2, %0\n\t" + "add %0, %1, %0\n\t" "wr %0, 0, %%asr24\n\t" - "andn %0, %4, %1\n\t" - "add %1, %3, %1\n\t" - "wr %1, 0, %%asr25" - : "=&r" (new_tick), "=&r" (tmp) - : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT)); + : "=&r" (new_tick) + : "r" (adj)); return new_tick; } -static unsigned long stick_add_compare(unsigned long adj) +static int stick_add_compare(unsigned long adj) { - unsigned long new_compare; + unsigned long orig_tick, new_tick; - __asm__ __volatile__("rd %%asr25, %0\n\t" - "add %0, %1, %0\n\t" - "wr %0, 0, %%asr25" - : "=&r" (new_compare) - : "r" (adj)); + __asm__ __volatile__("rd %%asr24, %0" + : "=r" (orig_tick)); + orig_tick &= ~TICKCMP_IRQ_BIT; + + __asm__ __volatile__("wr %0, 0, %%asr25" + : /* no outputs */ + : "r" (orig_tick + adj)); + + __asm__ __volatile__("rd %%asr24, %0" + : "=r" (new_tick)); + new_tick &= ~TICKCMP_IRQ_BIT; - return new_compare; + return ((long)(new_tick - (orig_tick+adj))) > 0L; } static struct sparc64_tick_ops stick_operations __read_mostly = { + .name = "stick", .init_tick = stick_init_tick, + .disable_irq = stick_disable_irq, .get_tick = stick_get_tick, - .get_compare = stick_get_compare, .add_tick = stick_add_tick, .add_compare = stick_add_compare, .softint_mask = 1UL << 16, @@ -321,20 +312,6 @@ static unsigned long __hbird_read_stick(void) return ret; } -static unsigned long __hbird_read_compare(void) -{ - unsigned long low, high; - unsigned long addr = HBIRD_STICKCMP_ADDR; - - __asm__ __volatile__("ldxa [%2] %3, %0\n\t" - "add %2, 0x8, %2\n\t" - "ldxa [%2] %3, %1" - : "=&r" (low), "=&r" (high), "=&r" (addr) - : "i" (ASI_PHYS_BYPASS_EC_E), "2" (addr)); - - return (high << 32UL) | low; -} - static void __hbird_write_stick(unsigned long val) { unsigned long low = (val & 0xffffffffUL); @@ -365,10 +342,13 @@ static void __hbird_write_compare(unsigned long val) "i" (ASI_PHYS_BYPASS_EC_E)); } -static void hbtick_init_tick(unsigned long offset) +static void hbtick_disable_irq(void) { - unsigned long val; + __hbird_write_compare(TICKCMP_IRQ_BIT); +} +static void hbtick_init_tick(void) +{ tick_disable_protection(); /* XXX This seems to be necessary to 'jumpstart' Hummingbird @@ -378,8 +358,7 @@ static void hbtick_init_tick(unsigned long offset) */ __hbird_write_stick(__hbird_read_stick()); - val = __hbird_read_stick() & ~TICK_PRIV_BIT; - __hbird_write_compare(val + offset); + hbtick_disable_irq(); } static unsigned long hbtick_get_tick(void) @@ -387,45 +366,40 @@ static unsigned long hbtick_get_tick(void) return __hbird_read_stick() & ~TICK_PRIV_BIT; } -static unsigned long hbtick_get_compare(void) -{ - return __hbird_read_compare(); -} - -static unsigned long hbtick_add_tick(unsigned long adj, unsigned long offset) +static unsigned long hbtick_add_tick(unsigned long adj) { unsigned long val; val = __hbird_read_stick() + adj; __hbird_write_stick(val); - val &= ~TICK_PRIV_BIT; - __hbird_write_compare(val + offset); - return val; } -static unsigned long hbtick_add_compare(unsigned long adj) +static int hbtick_add_compare(unsigned long adj) { - unsigned long val = __hbird_read_compare() + adj; + unsigned long val = __hbird_read_stick(); + unsigned long val2; - val &= ~TICK_PRIV_BIT; + val &= ~TICKCMP_IRQ_BIT; + val += adj; __hbird_write_compare(val); - return val; + val2 = __hbird_read_stick() & ~TICKCMP_IRQ_BIT; + + return ((long)(val2 - val)) > 0L; } static struct sparc64_tick_ops hbtick_operations __read_mostly = { + .name = "hbtick", .init_tick = hbtick_init_tick, + .disable_irq = hbtick_disable_irq, .get_tick = hbtick_get_tick, - .get_compare = hbtick_get_compare, .add_tick = hbtick_add_tick, .add_compare = hbtick_add_compare, .softint_mask = 1UL << 0, }; -unsigned long timer_tick_offset __read_mostly; - static unsigned long timer_ticks_per_nsec_quotient __read_mostly; #define TICK_SIZE (tick_nsec / 1000) @@ -482,50 +456,6 @@ void notify_arch_cmos_timer(void) mod_timer(&sync_cmos_timer, jiffies + 1); } -void timer_interrupt(int irq, struct pt_regs *regs) -{ - struct pt_regs *old_regs = set_irq_regs(regs); - unsigned long ticks, compare, pstate; - unsigned long tick_mask = tick_ops->softint_mask; - - clear_softint(tick_mask); - - irq_enter(); - - kstat_this_cpu.irqs[0]++; - - do { - profile_tick(CPU_PROFILING); - update_process_times(user_mode(get_irq_regs())); - - if (smp_processor_id() == boot_cpu_id) { - write_seqlock(&xtime_lock); - do_timer(1); - write_sequnlock(&xtime_lock); - } - - /* Guarantee that the following sequences execute - * uninterrupted. - */ - __asm__ __volatile__("rdpr %%pstate, %0\n\t" - "wrpr %0, %1, %%pstate" - : "=r" (pstate) - : "i" (PSTATE_IE)); - - compare = tick_ops->add_compare(timer_tick_offset); - ticks = tick_ops->get_tick(); - - /* Restore PSTATE_IE. */ - __asm__ __volatile__("wrpr %0, 0x0, %%pstate" - : /* no outputs */ - : "r" (pstate)); - } while (unlikely(time_after_eq(ticks, compare))); - - irq_exit(); - - set_irq_regs(old_regs); -} - /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ static void __init kick_start_clock(void) { @@ -923,7 +853,6 @@ static unsigned long sparc64_init_timers(void) prop = of_find_property(dp, "stick-frequency", NULL); } clock = *(unsigned int *) prop->value; - timer_tick_offset = clock / HZ; #ifdef CONFIG_SMP smp_tick_init(); @@ -932,26 +861,6 @@ static unsigned long sparc64_init_timers(void) return clock; } -static void sparc64_start_timers(void) -{ - unsigned long pstate; - - /* Guarantee that the following sequences execute - * uninterrupted. - */ - __asm__ __volatile__("rdpr %%pstate, %0\n\t" - "wrpr %0, %1, %%pstate" - : "=r" (pstate) - : "i" (PSTATE_IE)); - - tick_ops->init_tick(timer_tick_offset); - - /* Restore PSTATE_IE. */ - __asm__ __volatile__("wrpr %0, 0x0, %%pstate" - : /* no outputs */ - : "r" (pstate)); -} - struct freq_table { unsigned long clock_tick_ref; unsigned int ref_freq; @@ -998,29 +907,148 @@ static struct notifier_block sparc64_cpufreq_notifier_block = { #endif /* CONFIG_CPU_FREQ */ -static struct time_interpolator sparc64_cpu_interpolator = { - .source = TIME_SOURCE_CPU, - .shift = 16, - .mask = 0xffffffffffffffffLL +static int sparc64_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + return tick_ops->add_compare(delta); +} + +static void sparc64_timer_setup(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + break; + + case CLOCK_EVT_MODE_SHUTDOWN: + tick_ops->disable_irq(); + break; + + case CLOCK_EVT_MODE_PERIODIC: + case CLOCK_EVT_MODE_UNUSED: + WARN_ON(1); + break; + }; +} + +static struct clock_event_device sparc64_clockevent = { + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_mode = sparc64_timer_setup, + .set_next_event = sparc64_next_event, + .rating = 100, + .shift = 30, + .irq = -1, }; +static DEFINE_PER_CPU(struct clock_event_device, sparc64_events); -/* The quotient formula is taken from the IA64 port. */ -#define SPARC64_NSEC_PER_CYC_SHIFT 10UL -void __init time_init(void) +void timer_interrupt(int irq, struct pt_regs *regs) { - unsigned long clock = sparc64_init_timers(); + struct pt_regs *old_regs = set_irq_regs(regs); + unsigned long tick_mask = tick_ops->softint_mask; + int cpu = smp_processor_id(); + struct clock_event_device *evt = &per_cpu(sparc64_events, cpu); + + clear_softint(tick_mask); + + irq_enter(); + + kstat_this_cpu.irqs[0]++; + + if (unlikely(!evt->event_handler)) { + printk(KERN_WARNING + "Spurious SPARC64 timer interrupt on cpu %d\n", cpu); + } else + evt->event_handler(evt); + + irq_exit(); + + set_irq_regs(old_regs); +} - sparc64_cpu_interpolator.frequency = clock; - register_time_interpolator(&sparc64_cpu_interpolator); +void __devinit setup_sparc64_timer(void) +{ + struct clock_event_device *sevt; + unsigned long pstate; - /* Now that the interpolator is registered, it is - * safe to start the timer ticking. + /* Guarantee that the following sequences execute + * uninterrupted. */ - sparc64_start_timers(); + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); + + tick_ops->init_tick(); + + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : /* no outputs */ + : "r" (pstate)); + + sevt = &__get_cpu_var(sparc64_events); + + memcpy(sevt, &sparc64_clockevent, sizeof(*sevt)); + sevt->cpumask = cpumask_of_cpu(smp_processor_id()); + + clockevents_register_device(sevt); +} + +#define SPARC64_NSEC_PER_CYC_SHIFT 32UL + +static struct clocksource clocksource_tick = { + .rating = 100, + .mask = CLOCKSOURCE_MASK(64), + .shift = 16, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __init setup_clockevent_multiplier(unsigned long hz) +{ + unsigned long mult, shift = 32; + + while (1) { + mult = div_sc(hz, NSEC_PER_SEC, shift); + if (mult && (mult >> 32UL) == 0UL) + break; + + shift--; + } + + sparc64_clockevent.shift = shift; + sparc64_clockevent.mult = mult; +} + +void __init time_init(void) +{ + unsigned long clock = sparc64_init_timers(); timer_ticks_per_nsec_quotient = - (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) + - (clock / 2)) / clock); + clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT); + + clocksource_tick.name = tick_ops->name; + clocksource_tick.mult = + clocksource_hz2mult(clock, + clocksource_tick.shift); + clocksource_tick.read = tick_ops->get_tick; + + printk("clocksource: mult[%x] shift[%d]\n", + clocksource_tick.mult, clocksource_tick.shift); + + clocksource_register(&clocksource_tick); + + sparc64_clockevent.name = tick_ops->name; + + setup_clockevent_multiplier(clock); + + sparc64_clockevent.max_delta_ns = + clockevent_delta2ns(0x7fffffffffffffff, &sparc64_clockevent); + sparc64_clockevent.min_delta_ns = + clockevent_delta2ns(0xF, &sparc64_clockevent); + + printk("clockevent: mult[%lx] shift[%d]\n", + sparc64_clockevent.mult, sparc64_clockevent.shift); + + setup_sparc64_timer(); #ifdef CONFIG_CPU_FREQ cpufreq_register_notifier(&sparc64_cpufreq_notifier_block, diff --git a/include/asm-sparc64/timer.h b/include/asm-sparc64/timer.h index d435594df78..ccbd6944886 100644 --- a/include/asm-sparc64/timer.h +++ b/include/asm-sparc64/timer.h @@ -11,22 +11,19 @@ struct sparc64_tick_ops { - void (*init_tick)(unsigned long); unsigned long (*get_tick)(void); - unsigned long (*get_compare)(void); - unsigned long (*add_tick)(unsigned long, unsigned long); - unsigned long (*add_compare)(unsigned long); + int (*add_compare)(unsigned long); unsigned long softint_mask; + void (*disable_irq)(void); + + void (*init_tick)(void); + unsigned long (*add_tick)(unsigned long); + + char *name; }; extern struct sparc64_tick_ops *tick_ops; -#ifdef CONFIG_SMP -extern unsigned long timer_tick_offset; -struct pt_regs; -extern void timer_tick_interrupt(struct pt_regs *); -#endif - extern unsigned long sparc64_get_clock_tick(unsigned int cpu); #endif /* _SPARC64_TIMER_H */ -- cgit v1.2.3 From d62c6f093a1ef8fa5f8951e8da93c8ddd3ce193a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 27 Mar 2007 01:20:14 -0700 Subject: [SPARC64]: Fix sparc64_next_event() error return. It should return an error code not a boolean. Based upon an hpet timer fix by Thomas Gleixner. Signed-off-by: David S. Miller --- arch/sparc64/kernel/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 21e3b0b9d9c..0eb846534ff 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -910,7 +910,7 @@ static struct notifier_block sparc64_cpufreq_notifier_block = { static int sparc64_next_event(unsigned long delta, struct clock_event_device *evt) { - return tick_ops->add_compare(delta); + return tick_ops->add_compare(delta) ? -ETIME : 0; } static void sparc64_timer_setup(enum clock_event_mode mode, -- cgit v1.2.3 From 644923d4a5f117d437aefd47688d1141cc8361ed Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Wed, 28 Mar 2007 19:10:12 -0700 Subject: [SPARC64]: Small cleanups time.c - Removes days_in_mo[], as it's almost identical to month_days[] - Use the leapyear() macro - Line length wrapping. Signed-off-by: Tony Breeds Signed-off-by: David S. Miller --- arch/sparc64/kernel/time.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 0eb846534ff..3cb761ec895 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1177,10 +1177,6 @@ static int set_rtc_mmss(unsigned long nowtime) #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ static unsigned char mini_rtc_status; /* bitmapped status byte. */ -/* months start at 0 now */ -static unsigned char days_in_mo[] = -{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - #define FEBRUARY 2 #define STARTOFTIME 1970 #define SECDAY 86400L @@ -1329,8 +1325,7 @@ static int mini_rtc_ioctl(struct inode *inode, struct file *file, case RTC_SET_TIME: /* Set the RTC */ { - int year; - unsigned char leap_yr; + int year, days; if (!capable(CAP_SYS_TIME)) return -EACCES; @@ -1339,14 +1334,14 @@ static int mini_rtc_ioctl(struct inode *inode, struct file *file, return -EFAULT; year = wtime.tm_year + 1900; - leap_yr = ((!(year % 4) && (year % 100)) || - !(year % 400)); + days = month_days[wtime.tm_mon] + + ((wtime.tm_mon == 1) && leapyear(year)); - if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1)) + if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || + (wtime.tm_mday < 1)) return -EINVAL; - if (wtime.tm_mday < 0 || wtime.tm_mday > - (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr))) + if (wtime.tm_mday < 0 || wtime.tm_mday > days) return -EINVAL; if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 || -- cgit v1.2.3 From 8271f04242af8ddf8390f289cd6ef78fb3e3c6d9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Mar 2007 00:47:23 -0700 Subject: [SPARC]: constify of_get_property return: arch/sparc Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- arch/sparc/kernel/ebus.c | 10 +++++----- arch/sparc/kernel/of_device.c | 21 +++++++++++---------- arch/sparc/kernel/prom.c | 6 +++--- arch/sparc/kernel/time.c | 2 +- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c index ba58c3a061f..7724e206715 100644 --- a/arch/sparc/kernel/ebus.c +++ b/arch/sparc/kernel/ebus.c @@ -86,8 +86,8 @@ int __init ebus_blacklist_irq(char *name) void __init fill_ebus_child(struct device_node *dp, struct linux_ebus_child *dev) { - int *regs; - int *irqs; + const int *regs; + const int *irqs; int i, len; dev->prom_node = dp; @@ -146,9 +146,9 @@ void __init fill_ebus_child(struct device_node *dp, void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) { - struct linux_prom_registers *regs; + const struct linux_prom_registers *regs; struct linux_ebus_child *child; - int *irqs; + const int *irqs; int i, n, len; unsigned long baseaddr; @@ -269,7 +269,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d void __init ebus_init(void) { - struct linux_prom_pci_registers *regs; + const struct linux_prom_pci_registers *regs; struct linux_pbm_info *pbm; struct linux_ebus_device *dev; struct linux_ebus *ebus; diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index 48c24f7518c..fd7f8cb668a 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c @@ -210,7 +210,7 @@ struct of_bus { int *addrc, int *sizec); int (*map)(u32 *addr, const u32 *range, int na, int ns, int pna); - unsigned int (*get_flags)(u32 *addr); + unsigned int (*get_flags)(const u32 *addr); }; /* @@ -270,7 +270,7 @@ static int of_bus_default_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_default_get_flags(u32 *addr) +static unsigned int of_bus_default_get_flags(const u32 *addr) { return IORESOURCE_MEM; } @@ -334,7 +334,7 @@ static int of_bus_pci_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_pci_get_flags(u32 *addr) +static unsigned int of_bus_pci_get_flags(const u32 *addr) { unsigned int flags = 0; u32 w = addr[0]; @@ -375,7 +375,7 @@ static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna) return of_bus_default_map(addr, range, na, ns, pna); } -static unsigned int of_bus_sbus_get_flags(u32 *addr) +static unsigned int of_bus_sbus_get_flags(const u32 *addr) { return IORESOURCE_MEM; } @@ -432,7 +432,7 @@ static int __init build_one_resource(struct device_node *parent, u32 *addr, int na, int ns, int pna) { - u32 *ranges; + const u32 *ranges; unsigned int rlen; int rone; @@ -470,7 +470,7 @@ static void __init build_device_resources(struct of_device *op, struct of_bus *bus; int na, ns; int index, num_reg; - void *preg; + const void *preg; if (!parent) return; @@ -492,7 +492,7 @@ static void __init build_device_resources(struct of_device *op, for (index = 0; index < num_reg; index++) { struct resource *r = &op->resource[index]; u32 addr[OF_MAX_ADDR_CELLS]; - u32 *reg = (preg + (index * ((na + ns) * 4))); + const u32 *reg = (preg + (index * ((na + ns) * 4))); struct device_node *dp = op->node; struct device_node *pp = p_op->node; struct of_bus *pbus, *dbus; @@ -559,7 +559,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, struct device *parent) { struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); - struct linux_prom_irqs *intr; + const struct linux_prom_irqs *intr; int len, i; if (!op) @@ -579,7 +579,8 @@ static struct of_device * __init scan_one_device(struct device_node *dp, for (i = 0; i < op->num_irqs; i++) op->irqs[i] = intr[i].pri; } else { - unsigned int *irq = of_get_property(dp, "interrupts", &len); + const unsigned int *irq = + of_get_property(dp, "interrupts", &len); if (irq) { op->num_irqs = len / sizeof(unsigned int); @@ -594,7 +595,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0, }; struct device_node *io_unit, *sbi = dp->parent; - struct linux_prom_registers *regs; + const struct linux_prom_registers *regs; int board, slot; while (sbi) { diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 2cc302b6bec..8359d00a248 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -37,7 +37,7 @@ int of_device_is_compatible(struct device_node *device, const char *compat) const char* cp; int cplen, l; - cp = (char *) of_get_property(device, "compatible", &cplen); + cp = of_get_property(device, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { @@ -192,7 +192,7 @@ EXPORT_SYMBOL(of_getintprop_default); int of_n_addr_cells(struct device_node *np) { - int* ip; + const int* ip; do { if (np->parent) np = np->parent; @@ -207,7 +207,7 @@ EXPORT_SYMBOL(of_n_addr_cells); int of_n_size_cells(struct device_node *np) { - int* ip; + const int* ip; do { if (np->parent) np = np->parent; diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 9bb1240aaf8..f1401b57ccc 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -301,7 +301,7 @@ static __inline__ void sun4_clock_probe(void) static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; - char *model = of_get_property(dp, "model", NULL); + const char *model = of_get_property(dp, "model", NULL); if (!model) return -ENODEV; -- cgit v1.2.3 From 6a23acf3905287eb952a6f1dbbc8fb3e4eeae2f6 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 23 Apr 2007 15:53:27 -0700 Subject: [SPARC64]: constify of_get_property return: arch/sparc64 Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- arch/sparc64/kernel/central.c | 12 +++++++----- arch/sparc64/kernel/chmc.c | 4 ++-- arch/sparc64/kernel/ebus.c | 2 +- arch/sparc64/kernel/irq.c | 2 +- arch/sparc64/kernel/isa.c | 2 +- arch/sparc64/kernel/of_device.c | 24 ++++++++++++------------ arch/sparc64/kernel/pci_sun4v.c | 8 ++++---- arch/sparc64/kernel/prom.c | 24 ++++++++++++------------ arch/sparc64/kernel/sbus.c | 4 ++-- arch/sparc64/kernel/time.c | 4 ++-- arch/sparc64/solaris/misc.c | 3 ++- 11 files changed, 46 insertions(+), 43 deletions(-) diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c index e724c54af02..c65b2f9c98d 100644 --- a/arch/sparc64/kernel/central.c +++ b/arch/sparc64/kernel/central.c @@ -32,7 +32,7 @@ static void central_probe_failure(int line) static void central_ranges_init(struct linux_central *central) { struct device_node *dp = central->prom_node; - void *pval; + const void *pval; int len; central->num_central_ranges = 0; @@ -47,7 +47,7 @@ static void central_ranges_init(struct linux_central *central) static void fhc_ranges_init(struct linux_fhc *fhc) { struct device_node *dp = fhc->prom_node; - void *pval; + const void *pval; int len; fhc->num_fhc_ranges = 0; @@ -119,7 +119,7 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r) static void probe_other_fhcs(void) { struct device_node *dp; - struct linux_prom64_registers *fpregs; + const struct linux_prom64_registers *fpregs; for_each_node_by_name(dp, "fhc") { struct linux_fhc *fhc; @@ -190,7 +190,8 @@ static void probe_clock_board(struct linux_central *central, struct device_node *fp) { struct device_node *dp; - struct linux_prom_registers cregs[3], *pr; + struct linux_prom_registers cregs[3]; + const struct linux_prom_registers *pr; int nslots, tmp, nregs; dp = fp->child; @@ -299,7 +300,8 @@ static void init_all_fhc_hw(void) void central_probe(void) { - struct linux_prom_registers fpregs[6], *pr; + struct linux_prom_registers fpregs[6]; + const struct linux_prom_registers *pr; struct linux_fhc *fhc; struct device_node *dp, *fp; int err; diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c index 9699abeb990..777d3457704 100644 --- a/arch/sparc64/kernel/chmc.c +++ b/arch/sparc64/kernel/chmc.c @@ -343,8 +343,8 @@ static int init_one_mctrl(struct device_node *dp) { struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL); int portid = of_getintprop_default(dp, "portid", -1); - struct linux_prom64_registers *regs; - void *pval; + const struct linux_prom64_registers *regs; + const void *pval; int len; if (!mp) diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 35bf895fdee..1962bfa4ef3 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -285,7 +285,7 @@ static void __init fill_ebus_child(struct device_node *dp, int non_standard_regs) { struct of_device *op; - int *regs; + const int *regs; int i, len; dev->prom_node = dp; diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index d1bb3b3f263..6241e3dbbd5 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -627,7 +627,7 @@ static u64 prom_limit0, prom_limit1; static void map_prom_timers(void) { struct device_node *dp; - unsigned int *addr; + const unsigned int *addr; /* PROM timer node hangs out in the top level of device siblings... */ dp = of_find_node_by_path("/"); diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index 98721a8f861..791eeb7e387 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -24,7 +24,7 @@ static void __init report_dev(struct sparc_isa_device *isa_dev, int child) static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev) { - struct linux_prom_registers *pregs; + const struct linux_prom_registers *pregs; unsigned long base, len; int prop_len; diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index fb9bf1e4d03..6b8798141f2 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -245,7 +245,7 @@ struct of_bus { int *addrc, int *sizec); int (*map)(u32 *addr, const u32 *range, int na, int ns, int pna); - unsigned int (*get_flags)(u32 *addr); + unsigned int (*get_flags)(const u32 *addr); }; /* @@ -305,7 +305,7 @@ static int of_bus_default_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_default_get_flags(u32 *addr) +static unsigned int of_bus_default_get_flags(const u32 *addr) { return IORESOURCE_MEM; } @@ -369,7 +369,7 @@ static int of_bus_pci_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_pci_get_flags(u32 *addr) +static unsigned int of_bus_pci_get_flags(const u32 *addr) { unsigned int flags = 0; u32 w = addr[0]; @@ -482,7 +482,7 @@ static int __init build_one_resource(struct device_node *parent, u32 *addr, int na, int ns, int pna) { - u32 *ranges; + const u32 *ranges; unsigned int rlen; int rone; @@ -513,7 +513,7 @@ static int __init build_one_resource(struct device_node *parent, static int __init use_1to1_mapping(struct device_node *pp) { - char *model; + const char *model; /* If this is on the PMU bus, don't try to translate it even * if a ranges property exists. @@ -548,7 +548,7 @@ static void __init build_device_resources(struct of_device *op, struct of_bus *bus; int na, ns; int index, num_reg; - void *preg; + const void *preg; if (!parent) return; @@ -578,7 +578,7 @@ static void __init build_device_resources(struct of_device *op, for (index = 0; index < num_reg; index++) { struct resource *r = &op->resource[index]; u32 addr[OF_MAX_ADDR_CELLS]; - u32 *reg = (preg + (index * ((na + ns) * 4))); + const u32 *reg = (preg + (index * ((na + ns) * 4))); struct device_node *dp = op->node; struct device_node *pp = p_op->node; struct of_bus *pbus, *dbus; @@ -643,14 +643,14 @@ static void __init build_device_resources(struct of_device *op, static struct device_node * __init apply_interrupt_map(struct device_node *dp, struct device_node *pp, - u32 *imap, int imlen, u32 *imask, + const u32 *imap, int imlen, const u32 *imask, unsigned int *irq_p) { struct device_node *cp; unsigned int irq = *irq_p; struct of_bus *bus; phandle handle; - u32 *reg; + const u32 *reg; int na, num_reg, i; bus = of_match_bus(pp); @@ -705,7 +705,7 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp, struct device_node *pp, unsigned int irq) { - struct linux_prom_pci_registers *regs; + const struct linux_prom_pci_registers *regs; unsigned int bus, devfn, slot, ret; if (irq < 1 || irq > 4) @@ -794,7 +794,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op, pp = dp->parent; ip = NULL; while (pp) { - void *imap, *imsk; + const void *imap, *imsk; int imlen; imap = of_get_property(pp, "interrupt-map", &imlen); @@ -859,7 +859,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, struct device *parent) { struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); - unsigned int *irq; + const unsigned int *irq; int len, i; if (!op) diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index ec22cd61ec8..bd74c155519 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1281,7 +1281,7 @@ h_error: static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) { - u32 *val; + const u32 *val; int len; val = of_get_property(pbm->prom_node, "#msi-eqs", &len); @@ -1289,16 +1289,16 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) goto no_msi; pbm->msiq_num = *val; if (pbm->msiq_num) { - struct msiq_prop { + const struct msiq_prop { u32 first_msiq; u32 num_msiq; u32 first_devino; } *mqp; - struct msi_range_prop { + const struct msi_range_prop { u32 first_msi; u32 num_msi; } *mrng; - struct addr_range_prop { + const struct addr_range_prop { u32 msi32_high; u32 msi32_low; u32 msi32_len; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 0917c24c4f0..25b70368973 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -196,7 +196,7 @@ EXPORT_SYMBOL(of_getintprop_default); int of_n_addr_cells(struct device_node *np) { - int* ip; + const int* ip; do { if (np->parent) np = np->parent; @@ -211,7 +211,7 @@ EXPORT_SYMBOL(of_n_addr_cells); int of_n_size_cells(struct device_node *np) { - int* ip; + const int* ip; do { if (np->parent) np = np->parent; @@ -397,7 +397,7 @@ static unsigned int psycho_irq_build(struct device_node *dp, static void psycho_irq_trans_init(struct device_node *dp) { - struct linux_prom64_registers *regs; + const struct linux_prom64_registers *regs; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = psycho_irq_build; @@ -547,7 +547,7 @@ static unsigned long __sabre_onboard_imap_off[] = { static int sabre_device_needs_wsync(struct device_node *dp) { struct device_node *parent = dp->parent; - char *parent_model, *parent_compat; + const char *parent_model, *parent_compat; /* This traversal up towards the root is meant to * handle two cases: @@ -589,7 +589,7 @@ static unsigned int sabre_irq_build(struct device_node *dp, { struct sabre_irq_data *irq_data = _data; unsigned long controller_regs = irq_data->controller_regs; - struct linux_prom_pci_registers *regs; + const struct linux_prom_pci_registers *regs; unsigned long imap, iclr; unsigned long imap_off, iclr_off; int inofixup = 0; @@ -639,9 +639,9 @@ static unsigned int sabre_irq_build(struct device_node *dp, static void sabre_irq_trans_init(struct device_node *dp) { - struct linux_prom64_registers *regs; + const struct linux_prom64_registers *regs; struct sabre_irq_data *irq_data; - u32 *busrange; + const u32 *busrange; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = sabre_irq_build; @@ -795,7 +795,7 @@ static unsigned int schizo_irq_build(struct device_node *dp, static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo) { - struct linux_prom64_registers *regs; + const struct linux_prom64_registers *regs; struct schizo_irq_data *irq_data; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); @@ -836,7 +836,7 @@ static unsigned int pci_sun4v_irq_build(struct device_node *dp, static void pci_sun4v_irq_trans_init(struct device_node *dp) { - struct linux_prom64_registers *regs; + const struct linux_prom64_registers *regs; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = pci_sun4v_irq_build; @@ -940,7 +940,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp, void *_data) { unsigned long reg_base = (unsigned long) _data; - struct linux_prom_registers *regs; + const struct linux_prom_registers *regs; unsigned long imap, iclr; int sbus_slot = 0; int sbus_level = 0; @@ -994,7 +994,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp, static void sbus_irq_trans_init(struct device_node *dp) { - struct linux_prom64_registers *regs; + const struct linux_prom64_registers *regs; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = sbus_of_build_irq; @@ -1080,7 +1080,7 @@ static unsigned int sun4v_vdev_irq_build(struct device_node *dp, static void sun4v_vdev_irq_trans_init(struct device_node *dp) { - struct linux_prom64_registers *regs; + const struct linux_prom64_registers *regs; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = sun4v_vdev_irq_build; diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 14f78fb5e89..d403f3df2dc 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -1025,7 +1025,7 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus) /* Boot time initialization. */ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) { - struct linux_prom64_registers *pr; + const struct linux_prom64_registers *pr; struct device_node *dp; struct sbus_iommu *iommu; unsigned long regs; @@ -1133,7 +1133,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) void sbus_fill_device_irq(struct sbus_dev *sdev) { struct device_node *dp = of_find_node_by_phandle(sdev->prom_node); - struct linux_prom_irqs *irqs; + const struct linux_prom_irqs *irqs; irqs = of_get_property(dp, "interrupts", NULL); if (!irqs) { diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 3cb761ec895..259063f41f9 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -704,7 +704,7 @@ retry: return -EOPNOTSUPP; } -static int __init clock_model_matches(char *model) +static int __init clock_model_matches(const char *model) { if (strcmp(model, "mk48t02") && strcmp(model, "mk48t08") && @@ -721,7 +721,7 @@ static int __init clock_model_matches(char *model) static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; - char *model = of_get_property(dp, "model", NULL); + const char *model = of_get_property(dp, "model", NULL); unsigned long size, flags; void __iomem *regs; diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 9fcaad6dd11..542c808ec2c 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -224,7 +224,8 @@ static char *serial(char *buffer, int sz) *buffer = 0; if (dp) { - char *val = of_get_property(dp, "system-board-serial#", &len); + const char *val = + of_get_property(dp, "system-board-serial#", &len); if (val && len > 0) { if (len > sz) -- cgit v1.2.3 From ccf0dec6fcadb4e1c877b9bafb031a6bdb7112b9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Mar 2007 00:49:54 -0700 Subject: [SPARC/64] constify of_get_property return: drivers The only unfortunate bit here is that the name field of struct map_info is not const, so for now we put a cast on the assignment of it. Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- drivers/mtd/maps/sun_uflash.c | 4 ++-- drivers/net/sungem.c | 2 +- drivers/net/sunhme.c | 6 +++--- drivers/net/tg3.c | 2 +- drivers/net/tulip/tulip_core.c | 2 +- drivers/sbus/char/envctrl.c | 8 ++++---- drivers/sbus/char/flash.c | 2 +- drivers/sbus/char/openprom.c | 4 ++-- drivers/sbus/sbus.c | 4 ++-- drivers/scsi/qlogicpti.c | 2 +- drivers/serial/sunsu.c | 4 ++-- drivers/video/cg3.c | 2 +- 12 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 4db2055cee3..001af7f7ddd 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -39,7 +39,7 @@ MODULE_VERSION("2.0"); static LIST_HEAD(device_list); struct uflash_dev { - char *name; /* device name */ + const char *name; /* device name */ struct map_info map; /* mtd map info */ struct mtd_info *mtd; /* mtd info */ }; @@ -80,7 +80,7 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) up->name = of_get_property(dp, "model", NULL); if (up->name && 0 < strlen(up->name)) - up->map.name = up->name; + up->map.name = (char *)up->name; up->map.phys = res->start; diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 08ea61db46f..bb07b79817f 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2914,7 +2914,7 @@ static int __devinit gem_get_device_address(struct gem *gp) int use_idprom = 1; if (pcp != NULL) { - unsigned char *addr; + const unsigned char *addr; int len; addr = of_get_property(pcp->prom_node, "local-mac-address", diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 192bbc91c73..bee5e5b309b 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2704,7 +2704,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe dev->dev_addr[i] = macaddr[i]; macaddr[5]++; } else { - unsigned char *addr; + const unsigned char *addr; int len; addr = of_get_property(dp, "local-mac-address", &len); @@ -3081,7 +3081,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, macaddr[5]++; } else { #ifdef CONFIG_SPARC - unsigned char *addr; + const unsigned char *addr; int len; if (qfe_slot != -1 && @@ -3300,7 +3300,7 @@ static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_devic { struct sbus_dev *sdev = to_sbus_device(&dev->dev); struct device_node *dp = dev->node; - char *model = of_get_property(dp, "model", NULL); + const char *model = of_get_property(dp, "model", NULL); int is_qfe = (match->data != NULL); if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 256969e1300..45b4e018b5e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10996,7 +10996,7 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp) struct pcidev_cookie *pcp = pdev->sysdata; if (pcp != NULL) { - unsigned char *addr; + const unsigned char *addr; int len; addr = of_get_property(pcp->prom_node, "local-mac-address", diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index e3774a52237..03c14181b6b 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1544,7 +1544,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, dev->dev_addr[i] = last_phys_addr[i] + 1; #if defined(__sparc__) if (pcp) { - unsigned char *addr; + const unsigned char *addr; int len; addr = of_get_property(pcp->prom_node, diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 2cea4f5d208..f2be2ead874 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -726,7 +726,7 @@ static struct miscdevice envctrl_dev = { * Return: None. */ static void envctrl_set_mon(struct i2c_child_t *pchild, - char *chnl_desc, + const char *chnl_desc, int chnl_no) { /* Firmware only has temperature type. It does not distinguish @@ -763,8 +763,8 @@ static void envctrl_set_mon(struct i2c_child_t *pchild, static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp) { int i = 0, len; - char *pos; - unsigned int *pval; + const char *pos; + const unsigned int *pval; /* Firmware describe channels into a stream separated by a '\0'. */ pos = of_get_property(dp, "channels-description", &len); @@ -859,7 +859,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, { int len, i, tbls_size = 0; struct device_node *dp = edev_child->prom_node; - void *pval; + const void *pval; /* Get device address. */ pval = of_get_property(dp, "reg", &len); diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 6e99507aeb1..262f01e6859 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -190,7 +190,7 @@ static int __init flash_init(void) } if (!sdev) { #ifdef CONFIG_PCI - struct linux_prom_registers *ebus_regs; + const struct linux_prom_registers *ebus_regs; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 5041c9dfbe3..aec3b9f991f 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -141,7 +141,7 @@ static int copyout(void __user *info, struct openpromio *opp, int len) static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize) { - void *pval; + const void *pval; int len; if (!dp || @@ -410,7 +410,7 @@ static int opiocget(void __user *argp, DATA *data) struct opiocdesc op; struct device_node *dp; char *str; - void *pval; + const void *pval; int err, len; if (copy_from_user(&op, argp, sizeof(op))) diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 6349dd617f8..eee590a51d8 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -35,7 +35,7 @@ struct sbus_bus *sbus_root; static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) { unsigned long base; - void *pval; + const void *pval; int len, err; sdev->prom_node = dp->node; @@ -86,7 +86,7 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) { - void *pval; + const void *pval; int len; pval = of_get_property(dp, "ranges", &len); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 9f10689905a..c4195ea869e 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1403,7 +1403,7 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi struct scsi_host_template *tpnt = match->data; struct Scsi_Host *host; struct qlogicpti *qpti; - char *fcode; + const char *fcode; /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 96a852aa190..bfd44177a21 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1387,8 +1387,8 @@ static enum su_type __devinit su_get_type(struct device_node *dp) struct device_node *ap = of_find_node_by_path("/aliases"); if (ap) { - char *keyb = of_get_property(ap, "keyboard", NULL); - char *ms = of_get_property(ap, "mouse", NULL); + const char *keyb = of_get_property(ap, "keyboard", NULL); + const char *ms = of_get_property(ap, "mouse", NULL); if (keyb) { if (dp == of_find_node_by_path(keyb)) diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 767c850f8eb..f042428a84f 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -266,7 +266,7 @@ static void __devinit cg3_init_fix(struct fb_info *info, int linebytes, static void __devinit cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var, struct device_node *dp) { - char *params; + const char *params; char *p; int ww, hh; -- cgit v1.2.3 From 66f3cb7ccfe6d735bd1fa435aebc9b985ac74e07 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Mar 2007 00:50:29 -0700 Subject: [SPARC64] constify of_get_property return: include Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- include/asm-sparc64/floppy.h | 4 ++-- include/asm-sparc64/parport.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index 331013a0053..4aa0925e1b1 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -549,7 +549,7 @@ static int __init ebus_fdthree_p(struct linux_ebus_device *edev) if (!strcmp(edev->prom_node->name, "fdthree")) return 1; if (!strcmp(edev->prom_node->name, "floppy")) { - char *compat; + const char *compat; compat = of_get_property(edev->prom_node, "compatible", NULL); @@ -661,7 +661,7 @@ static unsigned long __init sun_floppy_init(void) struct linux_ebus_device *edev = NULL; unsigned long config = 0; void __iomem *auxio_reg; - char *state_prop; + const char *state_prop; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h index 284dfd01a33..6340a5253a3 100644 --- a/include/asm-sparc64/parport.h +++ b/include/asm-sparc64/parport.h @@ -103,7 +103,7 @@ static int ebus_ecpp_p(struct linux_ebus_device *edev) if (!strcmp(edev->prom_node->name, "ecpp")) return 1; if (!strcmp(edev->prom_node->name, "parallel")) { - char *compat; + const char *compat; compat = of_get_property(edev->prom_node, "compatible", NULL); -- cgit v1.2.3 From 3198514d2d10fb3ce5e49ba0c611764ad8a214d0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Mar 2007 00:50:57 -0700 Subject: [SPARC/64] constify of_get_property return: sound Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- sound/sparc/amd7930.c | 4 ++-- sound/sparc/cs4231.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index c899786f30f..07962a35f24 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -1067,8 +1067,8 @@ out_err: static int __devinit amd7930_obio_attach(struct device_node *dp) { - struct linux_prom_registers *regs; - struct linux_prom_irqs *irqp; + const struct linux_prom_registers *regs; + const struct linux_prom_irqs *irqp; struct resource res, *rp; int len; diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index f5956d557f7..900a00de35f 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -2284,7 +2284,7 @@ static int __init cs4231_init(void) if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) { match = 1; } else if (!strcmp(edev->prom_node->name, "audio")) { - char *compat; + const char *compat; compat = of_get_property(edev->prom_node, "compatible", NULL); -- cgit v1.2.3 From 64b94701c0714f814e640ff351d5f784fdc0381e Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Mar 2007 00:53:28 -0700 Subject: [SPARC/64]: constify of_get_property return Finally, we actually change the functions themselves. Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- arch/sparc/kernel/prom.c | 2 +- arch/sparc64/kernel/prom.c | 2 +- include/asm-sparc/prom.h | 2 +- include/asm-sparc64/prom.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 8359d00a248..d2a8297d56f 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -170,7 +170,7 @@ EXPORT_SYMBOL(of_find_property); * Find a property with a given name for a given node * and return the value. */ -void *of_get_property(struct device_node *np, const char *name, int *lenp) +const void *of_get_property(struct device_node *np, const char *name, int *lenp) { struct property *pp = of_find_property(np,name,lenp); return pp ? pp->value : NULL; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 25b70368973..493db961a1f 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -174,7 +174,7 @@ EXPORT_SYMBOL(of_find_property); * Find a property with a given name for a given node * and return the value. */ -void *of_get_property(struct device_node *np, const char *name, int *lenp) +const void *of_get_property(struct device_node *np, const char *name, int *lenp) { struct property *pp = of_find_property(np,name,lenp); return pp ? pp->value : NULL; diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index 274868d8598..30d53ed4f5c 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -89,7 +89,7 @@ extern struct property *of_find_property(struct device_node *np, const char *name, int *lenp); extern int of_device_is_compatible(struct device_node *device, const char *); -extern void *of_get_property(struct device_node *node, const char *name, +extern const void *of_get_property(struct device_node *node, const char *name, int *lenp); #define get_property(node,name,lenp) of_get_property(node,name,lenp) extern int of_set_property(struct device_node *node, const char *name, void *val, int len); diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 0eca2d98627..50b03387c97 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -97,8 +97,8 @@ extern struct property *of_find_property(struct device_node *np, const char *name, int *lenp); extern int of_device_is_compatible(struct device_node *device, const char *); -extern void *of_get_property(struct device_node *node, const char *name, - int *lenp); +extern const void *of_get_property(struct device_node *node, const char *name, + int *lenp); #define get_property(node,name,lenp) of_get_property(node,name,lenp) extern int of_set_property(struct device_node *node, const char *name, void *val, int len); extern int of_getintprop_default(struct device_node *np, -- cgit v1.2.3 From 357418e7cac16fed4ca558c6037d189d2109c9c2 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Mar 2007 00:54:04 -0700 Subject: [SPARC]: constify some paramaters of OF routines This starts bringing the PowerPC and Sparc implemetations back closer together. Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- arch/sparc/kernel/prom.c | 9 ++++++--- include/asm-sparc/prom.h | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index d2a8297d56f..9ddf6035915 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -32,7 +32,8 @@ static struct device_node *allnodes; */ static DEFINE_RWLOCK(devtree_lock); -int of_device_is_compatible(struct device_node *device, const char *compat) +int of_device_is_compatible(const struct device_node *device, + const char *compat) { const char* cp; int cplen, l; @@ -150,7 +151,8 @@ struct device_node *of_find_compatible_node(struct device_node *from, } EXPORT_SYMBOL(of_find_compatible_node); -struct property *of_find_property(struct device_node *np, const char *name, +struct property *of_find_property(const struct device_node *np, + const char *name, int *lenp) { struct property *pp; @@ -170,7 +172,8 @@ EXPORT_SYMBOL(of_find_property); * Find a property with a given name for a given node * and return the value. */ -const void *of_get_property(struct device_node *np, const char *name, int *lenp) +const void *of_get_property(const struct device_node *np, const char *name, + int *lenp) { struct property *pp = of_find_property(np,name,lenp); return pp ? pp->value : NULL; diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index 30d53ed4f5c..39ad2224a11 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -85,12 +85,14 @@ extern struct device_node *of_find_node_by_phandle(phandle handle); extern struct device_node *of_get_parent(const struct device_node *node); extern struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev); -extern struct property *of_find_property(struct device_node *np, +extern struct property *of_find_property(const struct device_node *np, const char *name, int *lenp); -extern int of_device_is_compatible(struct device_node *device, const char *); -extern const void *of_get_property(struct device_node *node, const char *name, - int *lenp); +extern int of_device_is_compatible(const struct device_node *device, + const char *); +extern const void *of_get_property(const struct device_node *node, + const char *name, + int *lenp); #define get_property(node,name,lenp) of_get_property(node,name,lenp) extern int of_set_property(struct device_node *node, const char *name, void *val, int len); extern int of_getintprop_default(struct device_node *np, -- cgit v1.2.3 From ded220bd8f0823771fc0a9bdf7f5bcbe543197b6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Mar 2007 01:18:42 -0700 Subject: [STRING]: Move strcasecmp/strncasecmp to lib/string.c We have several platforms using local copies of identical code. Signed-off-by: David S. Miller --- arch/alpha/lib/Makefile | 1 - arch/alpha/lib/strcasecmp.c | 26 -------------------------- arch/powerpc/kernel/ppc_ksyms.c | 2 -- arch/powerpc/lib/Makefile | 5 ++--- arch/powerpc/lib/strcase.c | 25 ------------------------- arch/ppc/kernel/ppc_ksyms.c | 2 -- arch/ppc/lib/Makefile | 2 +- arch/ppc/lib/strcase.c | 24 ------------------------ arch/sh/lib/Makefile | 2 +- arch/sh/lib/strcasecmp.c | 26 -------------------------- arch/xtensa/lib/Makefile | 2 +- arch/xtensa/lib/strcasecmp.c | 32 -------------------------------- include/asm-alpha/string.h | 2 -- include/asm-powerpc/string.h | 2 -- include/asm-sh/string.h | 3 --- include/linux/string.h | 6 ++++++ lib/string.c | 28 ++++++++++++++++++++++++++++ 17 files changed, 39 insertions(+), 151 deletions(-) delete mode 100644 arch/alpha/lib/strcasecmp.c delete mode 100644 arch/powerpc/lib/strcase.c delete mode 100644 arch/ppc/lib/strcase.c delete mode 100644 arch/sh/lib/strcasecmp.c delete mode 100644 arch/xtensa/lib/strcasecmp.c diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 21cf624d732..ea098f3b629 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -36,7 +36,6 @@ lib-y = __divqu.o __remqu.o __divlu.o __remlu.o \ $(ev6-y)csum_ipv6_magic.o \ $(ev6-y)clear_page.o \ $(ev6-y)copy_page.o \ - strcasecmp.o \ fpreg.o \ callback_srm.o srm_puts.o srm_printk.o diff --git a/arch/alpha/lib/strcasecmp.c b/arch/alpha/lib/strcasecmp.c deleted file mode 100644 index 4e57a216fea..00000000000 --- a/arch/alpha/lib/strcasecmp.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * linux/arch/alpha/lib/strcasecmp.c - */ - -#include - - -/* We handle nothing here except the C locale. Since this is used in - only one place, on strings known to contain only 7 bit ASCII, this - is ok. */ - -int strcasecmp(const char *a, const char *b) -{ - int ca, cb; - - do { - ca = *a++ & 0xff; - cb = *b++ & 0xff; - if (ca >= 'A' && ca <= 'Z') - ca += 'a' - 'A'; - if (cb >= 'A' && cb <= 'Z') - cb += 'a' - 'A'; - } while (ca == cb && ca != '\0'); - - return ca - cb; -} diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index ecee596d28f..2f8e9c02c92 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -84,8 +84,6 @@ EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strcasecmp); -EXPORT_SYMBOL(strncasecmp); EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial_copy_generic); diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 4b1ba49fbd9..450258de7ca 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -7,13 +7,12 @@ EXTRA_CFLAGS += -mno-minimal-toc endif ifeq ($(CONFIG_PPC_MERGE),y) -obj-y := string.o strcase.o +obj-y := string.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o endif obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ - memcpy_64.o usercopy_64.o mem_64.o string.o \ - strcase.o + memcpy_64.o usercopy_64.o mem_64.o string.o obj-$(CONFIG_QUICC_ENGINE) += rheap.o obj-$(CONFIG_XMON) += sstep.o obj-$(CONFIG_KPROBES) += sstep.o diff --git a/arch/powerpc/lib/strcase.c b/arch/powerpc/lib/strcase.c deleted file mode 100644 index f8ec1eba3fd..00000000000 --- a/arch/powerpc/lib/strcase.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include - -int strcasecmp(const char *s1, const char *s2) -{ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while (c1 == c2 && c1 != 0); - return c1 - c2; -} - -int strncasecmp(const char *s1, const char *s2, size_t n) -{ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while ((--n > 0) && c1 == c2 && c1 != 0); - return c1 - c2; -} diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 1318b6f4c3d..4ad499605d0 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -93,8 +93,6 @@ EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strcasecmp); -EXPORT_SYMBOL(strncasecmp); EXPORT_SYMBOL(__div64_32); EXPORT_SYMBOL(csum_partial); diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile index 50358e4ea15..422bef9bae7 100644 --- a/arch/ppc/lib/Makefile +++ b/arch/ppc/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for ppc-specific library files.. # -obj-y := checksum.o string.o strcase.o div64.o +obj-y := checksum.o string.o div64.o obj-$(CONFIG_8xx) += rheap.o obj-$(CONFIG_CPM2) += rheap.o diff --git a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c deleted file mode 100644 index 3b0094cc2b5..00000000000 --- a/arch/ppc/lib/strcase.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -int strcasecmp(const char *s1, const char *s2) -{ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while (c1 == c2 && c1 != 0); - return c1 - c2; -} - -int strncasecmp(const char *s1, const char *s2, size_t n) -{ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while ((--n > 0) && c1 == c2 && c1 != 0); - return c1 - c2; -} diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile index b5681e3f968..0b9cca5c7cb 100644 --- a/arch/sh/lib/Makefile +++ b/arch/sh/lib/Makefile @@ -3,7 +3,7 @@ # lib-y = delay.o memset.o memmove.o memchr.o \ - checksum.o strcasecmp.o strlen.o div64.o udivdi3.o \ + checksum.o strlen.o div64.o udivdi3.o \ div64-generic.o memcpy-y := memcpy.o diff --git a/arch/sh/lib/strcasecmp.c b/arch/sh/lib/strcasecmp.c deleted file mode 100644 index 4e57a216fea..00000000000 --- a/arch/sh/lib/strcasecmp.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * linux/arch/alpha/lib/strcasecmp.c - */ - -#include - - -/* We handle nothing here except the C locale. Since this is used in - only one place, on strings known to contain only 7 bit ASCII, this - is ok. */ - -int strcasecmp(const char *a, const char *b) -{ - int ca, cb; - - do { - ca = *a++ & 0xff; - cb = *b++ & 0xff; - if (ca >= 'A' && ca <= 'Z') - ca += 'a' - 'A'; - if (cb >= 'A' && cb <= 'Z') - cb += 'a' - 'A'; - } while (ca == cb && ca != '\0'); - - return ca - cb; -} diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile index ed935b58e8a..6c4fdd86acd 100644 --- a/arch/xtensa/lib/Makefile +++ b/arch/xtensa/lib/Makefile @@ -2,6 +2,6 @@ # Makefile for Xtensa-specific library files. # -lib-y += memcopy.o memset.o checksum.o strcasecmp.o \ +lib-y += memcopy.o memset.o checksum.o \ usercopy.o strncpy_user.o strnlen_user.o lib-$(CONFIG_PCI) += pci-auto.o diff --git a/arch/xtensa/lib/strcasecmp.c b/arch/xtensa/lib/strcasecmp.c deleted file mode 100644 index 165b2d6effa..00000000000 --- a/arch/xtensa/lib/strcasecmp.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * linux/arch/xtensa/lib/strcasecmp.c - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file "COPYING" in the main directory of - * this archive for more details. - * - * Copyright (C) 2002 Tensilica Inc. - */ - -#include - - -/* We handle nothing here except the C locale. Since this is used in - only one place, on strings known to contain only 7 bit ASCII, this - is ok. */ - -int strcasecmp(const char *a, const char *b) -{ - int ca, cb; - - do { - ca = *a++ & 0xff; - cb = *b++ & 0xff; - if (ca >= 'A' && ca <= 'Z') - ca += 'a' - 'A'; - if (cb >= 'A' && cb <= 'Z') - cb += 'a' - 'A'; - } while (ca == cb && ca != '\0'); - - return ca - cb; -} diff --git a/include/asm-alpha/string.h b/include/asm-alpha/string.h index 9e44fea669b..b02b8a28294 100644 --- a/include/asm-alpha/string.h +++ b/include/asm-alpha/string.h @@ -61,8 +61,6 @@ extern void * __memsetw(void *dest, unsigned short, size_t count); ? __constant_c_memset((s),0x0001000100010001UL*(unsigned short)(c),(n)) \ : __memsetw((s),(c),(n))) -extern int strcasecmp(const char *, const char *); - #endif /* __KERNEL__ */ #endif /* __ALPHA_STRING_H__ */ diff --git a/include/asm-powerpc/string.h b/include/asm-powerpc/string.h index faa407f33c6..aa40f92c298 100644 --- a/include/asm-powerpc/string.h +++ b/include/asm-powerpc/string.h @@ -14,8 +14,6 @@ #define __HAVE_ARCH_MEMCMP #define __HAVE_ARCH_MEMCHR -extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, __kernel_size_t); extern char * strcpy(char *,const char *); extern char * strncpy(char *,const char *, __kernel_size_t); extern __kernel_size_t strlen(const char *); diff --git a/include/asm-sh/string.h b/include/asm-sh/string.h index 95bc7db006b..55f8db6bc1d 100644 --- a/include/asm-sh/string.h +++ b/include/asm-sh/string.h @@ -126,9 +126,6 @@ extern void *memchr(const void *__s, int __c, size_t __n); #define __HAVE_ARCH_STRLEN extern size_t strlen(const char *); -/* arch/sh/lib/strcasecmp.c */ -extern int strcasecmp(const char *, const char *); - #endif /* __KERNEL__ */ #endif /* __ASM_SH_STRING_H */ diff --git a/include/linux/string.h b/include/linux/string.h index 4f69ef9e6eb..7f2eb6a477f 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -47,6 +47,12 @@ extern int strncmp(const char *,const char *,__kernel_size_t); #ifndef __HAVE_ARCH_STRNICMP extern int strnicmp(const char *, const char *, __kernel_size_t); #endif +#ifndef __HAVE_ARCH_STRCASECMP +extern int strcasecmp(const char *s1, const char *s2); +#endif +#ifndef __HAVE_ARCH_STRNCASECMP +extern int strncasecmp(const char *s1, const char *s2, size_t n); +#endif #ifndef __HAVE_ARCH_STRCHR extern char * strchr(const char *,int); #endif diff --git a/lib/string.c b/lib/string.c index bab440fb0df..5efafed3d6b 100644 --- a/lib/string.c +++ b/lib/string.c @@ -60,6 +60,34 @@ int strnicmp(const char *s1, const char *s2, size_t len) EXPORT_SYMBOL(strnicmp); #endif +#ifndef __HAVE_ARCH_STRCASECMP +int strcasecmp(const char *s1, const char *s2) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while (c1 == c2 && c1 != 0); + return c1 - c2; +} +EXPORT_SYMBOL(strcasecmp); +#endif + +#ifndef __HAVE_ARCH_STRNCASECMP +int strncasecmp(const char *s1, const char *s2, size_t n) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while ((--n > 0) && c1 == c2 && c1 != 0); + return c1 - c2; +} +EXPORT_SYMBOL(strncasecmp); +#endif + #ifndef __HAVE_ARCH_STRCPY /** * strcpy - Copy a %NUL terminated string -- cgit v1.2.3 From a8b8814bdfe3bb2bdfa23722de947bad8283037c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Mar 2007 01:28:51 -0700 Subject: [SPARC]: Use strcasecmp for OFW property name comparisons. This allows us to simplify sharing code with powerpc which has properties that have various forms of capitalization when on the sparc64 side the property is all lower-case. Signed-off-by: David S. Miller --- arch/sparc/kernel/prom.c | 4 ++-- arch/sparc64/kernel/prom.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 9ddf6035915..eed140b3c73 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -158,7 +158,7 @@ struct property *of_find_property(const struct device_node *np, struct property *pp; for (pp = np->properties; pp != 0; pp = pp->next) { - if (strcmp(pp->name, name) == 0) { + if (strcasecmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; break; @@ -242,7 +242,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len while (*prevp) { struct property *prop = *prevp; - if (!strcmp(prop->name, name)) { + if (!strcasecmp(prop->name, name)) { void *old_val = prop->value; int ret; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 493db961a1f..13734b50a6e 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -160,7 +160,7 @@ struct property *of_find_property(struct device_node *np, const char *name, struct property *pp; for (pp = np->properties; pp != 0; pp = pp->next) { - if (strcmp(pp->name, name) == 0) { + if (strcasecmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; break; @@ -243,7 +243,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len while (*prevp) { struct property *prop = *prevp; - if (!strcmp(prop->name, name)) { + if (!strcasecmp(prop->name, name)) { void *old_val = prop->value; int ret; -- cgit v1.2.3 From 9f47df264fa53e562cafa0de4a405d0846a81fbd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Mar 2007 01:33:46 -0700 Subject: [RADEON]: Probe clocks and monitor using OF properties on sparc. Just like powerpc does. Signed-off-by: David S. Miller --- drivers/video/aty/radeon_base.c | 12 +++++++----- drivers/video/aty/radeon_monitor.c | 16 ++++++++-------- drivers/video/aty/radeonfb.h | 4 ++-- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 1bf6f42eb40..a4b3fd185de 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -410,7 +410,7 @@ static int __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo) } #endif -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) /* * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device * tree. Hopefully, ATI OF driver is kind enough to fill these @@ -440,7 +440,7 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo) return 0; } -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ /* * Read PLL infos from chip registers @@ -645,7 +645,7 @@ static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo) rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) /* * Retrieve PLL infos from Open Firmware first */ @@ -653,7 +653,7 @@ static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo) printk(KERN_INFO "radeonfb: Retrieved PLL infos from Open Firmware\n"); goto found; } -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ /* * Check out if we have an X86 which gave us some PLL informations @@ -2231,7 +2231,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, rinfo->family == CHIP_FAMILY_RS200) rinfo->errata |= CHIP_ERRATA_PLL_DELAY; -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) /* On PPC, we obtain the OF device-node pointer to the firmware * data for this chip */ @@ -2240,6 +2240,8 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n", pci_name(rinfo->pdev)); +#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ +#ifdef CONFIG_PPC_OF /* On PPC, the firmware sets up a memory mapping that tends * to cause lockups when enabling the engine. We reconfigure * the card internal memory mappings properly diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c index 38c7dbf8c15..737b5c09dbd 100644 --- a/drivers/video/aty/radeon_monitor.c +++ b/drivers/video/aty/radeon_monitor.c @@ -52,7 +52,7 @@ static char *radeon_get_mon_name(int type) } -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) /* * Try to find monitor informations & EDID data out of the Open Firmware * device-tree. This also contains some "hacks" to work around a few machine @@ -156,7 +156,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ } return MT_NONE; } -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) @@ -495,11 +495,11 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, * Old single head cards */ if (!rinfo->has_CRTC2) { -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) if (rinfo->mon1_type == MT_NONE) rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, &rinfo->mon1_EDID); -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ #ifdef CONFIG_FB_RADEON_I2C if (rinfo->mon1_type == MT_NONE) rinfo->mon1_type = @@ -544,11 +544,11 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, /* * Probe primary head (DVI or laptop internal panel) */ -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) if (rinfo->mon1_type == MT_NONE) rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, &rinfo->mon1_EDID); -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ #ifdef CONFIG_FB_RADEON_I2C if (rinfo->mon1_type == MT_NONE) rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi, @@ -572,11 +572,11 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, /* * Probe secondary head (mostly VGA, can be DVI) */ -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) if (rinfo->mon2_type == MT_NONE) rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1, &rinfo->mon2_EDID); -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC_OF || defined(CONFIG_SPARC) */ #ifdef CONFIG_FB_RADEON_I2C if (rinfo->mon2_type == MT_NONE) rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga, diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index d5ff224a625..31900036028 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -16,7 +16,7 @@ #include -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) #include #endif @@ -292,7 +292,7 @@ struct radeonfb_info { unsigned long fb_local_base; struct pci_dev *pdev; -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) struct device_node *of_node; #endif -- cgit v1.2.3 From dadb830dac401c4b1420ee2fd6c7559871b43319 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 15:42:50 -0800 Subject: [SUNGEM]: __sparc__ --> CONFIG_SPARC Signed-off-by: David S. Miller --- drivers/net/sungem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index bb07b79817f..4fa3e49f935 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -64,7 +64,7 @@ #include #include -#ifdef __sparc__ +#ifdef CONFIG_SPARC #include #include #include @@ -2849,7 +2849,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return rc; } -#if (!defined(__sparc__) && !defined(CONFIG_PPC_PMAC)) +#if (!defined(CONFIG_SPARC) && !defined(CONFIG_PPC_PMAC)) /* Fetch MAC address from vital product data of PCI ROM. */ static int find_eth_addr_in_vpd(void __iomem *rom_base, int len, unsigned char *dev_addr) { @@ -2904,11 +2904,11 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr) static int __devinit gem_get_device_address(struct gem *gp) { -#if defined(__sparc__) || defined(CONFIG_PPC_PMAC) +#if defined(CONFIG_SPARC) || defined(CONFIG_PPC_PMAC) struct net_device *dev = gp->dev; #endif -#if defined(__sparc__) +#if defined(CONFIG_SPARC) struct pci_dev *pdev = gp->pdev; struct pcidev_cookie *pcp = pdev->sysdata; int use_idprom = 1; -- cgit v1.2.3 From 457e1a8afbcf5deffa501f2e9829526c18ed55b5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Mar 2007 01:36:44 -0700 Subject: [SUNGEM]: Consolidate powerpc and sparc MAC probing code. Signed-off-by: David S. Miller --- drivers/net/sungem.c | 31 ++++++------------------------- drivers/net/sungem.h | 2 +- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 4fa3e49f935..07f38907884 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -66,9 +66,7 @@ #ifdef CONFIG_SPARC #include -#include -#include -#include +#include #endif #ifdef CONFIG_PPC_PMAC @@ -2906,34 +2904,17 @@ static int __devinit gem_get_device_address(struct gem *gp) { #if defined(CONFIG_SPARC) || defined(CONFIG_PPC_PMAC) struct net_device *dev = gp->dev; -#endif - -#if defined(CONFIG_SPARC) - struct pci_dev *pdev = gp->pdev; - struct pcidev_cookie *pcp = pdev->sysdata; - int use_idprom = 1; - - if (pcp != NULL) { - const unsigned char *addr; - int len; - - addr = of_get_property(pcp->prom_node, "local-mac-address", - &len); - if (addr && len == 6) { - use_idprom = 0; - memcpy(dev->dev_addr, addr, 6); - } - } - if (use_idprom) - memcpy(dev->dev_addr, idprom->id_ethaddr, 6); -#elif defined(CONFIG_PPC_PMAC) const unsigned char *addr; addr = get_property(gp->of_node, "local-mac-address", NULL); if (addr == NULL) { +#ifdef CONFIG_SPARC + addr = idprom->id_ethaddr; +#else printk("\n"); printk(KERN_ERR "%s: can't get mac-address\n", dev->name); return -1; +#endif } memcpy(dev->dev_addr, addr, 6); #else @@ -3091,7 +3072,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, /* On Apple, we want a reference to the Open Firmware device-tree * node. We use it for clock control. */ -#ifdef CONFIG_PPC_PMAC +#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC) gp->of_node = pci_device_to_OF_node(pdev); #endif diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index a70067c85cc..58cf87c5751 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -1025,7 +1025,7 @@ struct gem { struct pci_dev *pdev; struct net_device *dev; -#ifdef CONFIG_PPC_PMAC +#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC) struct device_node *of_node; #endif }; -- cgit v1.2.3 From 6f85a8597d1d0d8ceeec5a82881c6ddf5cfb45e5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 16:40:57 -0800 Subject: [SUNHME]: Use pci_device_to_OF_node(). Signed-off-by: David S. Miller --- drivers/net/sunhme.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index bee5e5b309b..bf0d4844f9f 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -55,9 +55,6 @@ #ifdef CONFIG_PCI #include -#ifdef CONFIG_SPARC -#include -#endif #endif #include "sunhme.h" @@ -2986,7 +2983,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, { struct quattro *qp = NULL; #ifdef CONFIG_SPARC - struct pcidev_cookie *pcp; + struct device_node *dp; #endif struct happy_meal *hp; struct net_device *dev; @@ -2998,13 +2995,8 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, /* Now make sure pci_dev cookie is there. */ #ifdef CONFIG_SPARC - pcp = pdev->sysdata; - if (pcp == NULL) { - printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n"); - return -ENODEV; - } - - strcpy(prom_name, pcp->prom_node->name); + dp = pci_device_to_OF_node(pdev); + strcpy(prom_name, dp->name); #else if (is_quattro_p(pdev)) strcpy(prom_name, "SUNW,qfe"); @@ -3085,7 +3077,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, int len; if (qfe_slot != -1 && - (addr = of_get_property(pcp->prom_node, + (addr = of_get_property(dp, "local-mac-address", &len)) != NULL && len == 6) { memcpy(dev->dev_addr, addr, 6); @@ -3105,7 +3097,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, hp->tcvregs = (hpreg_base + 0x7000UL); #ifdef CONFIG_SPARC - hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff); + hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff); if (hp->hm_revision == 0xff) { unsigned char prev; -- cgit v1.2.3 From 49b6e95ff6d05722bcf7a52b00454566ce0c44eb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Mar 2007 01:38:42 -0700 Subject: [TG3]: Use pci_device_to_OF_node() on sparc. And use CONFIG_SPARC instead of CONFIG_SPARC64 as the test. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 45b4e018b5e..6aef1e95d39 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -46,10 +46,9 @@ #include #include -#ifdef CONFIG_SPARC64 +#ifdef CONFIG_SPARC #include -#include -#include +#include #endif #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) @@ -10988,24 +10987,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) return err; } -#ifdef CONFIG_SPARC64 +#ifdef CONFIG_SPARC static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp) { struct net_device *dev = tp->dev; struct pci_dev *pdev = tp->pdev; - struct pcidev_cookie *pcp = pdev->sysdata; - - if (pcp != NULL) { - const unsigned char *addr; - int len; - - addr = of_get_property(pcp->prom_node, "local-mac-address", - &len); - if (addr && len == 6) { - memcpy(dev->dev_addr, addr, 6); - memcpy(dev->perm_addr, dev->dev_addr, 6); - return 0; - } + struct device_node *dp = pci_device_to_OF_node(pdev); + unsigned char *addr; + int len; + + addr = of_get_property(dp, "local-mac-address", &len); + if (addr && len == 6) { + memcpy(dev->dev_addr, addr, 6); + memcpy(dev->perm_addr, dev->dev_addr, 6); + return 0; } return -ENODEV; } @@ -11026,7 +11021,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) u32 hi, lo, mac_offset; int addr_ok = 0; -#ifdef CONFIG_SPARC64 +#ifdef CONFIG_SPARC if (!tg3_get_macaddr_sparc(tp)) return 0; #endif -- cgit v1.2.3 From 49345103fef36617abc9a649dfc34f7e921c6878 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Mar 2007 01:39:44 -0700 Subject: [TULIP]: Use CONFIG_SPARC consistently in ifdef tests. Signed-off-by: David S. Miller --- drivers/net/tulip/de2104x.c | 2 +- drivers/net/tulip/de4x5.c | 10 +++------- drivers/net/tulip/tulip_core.c | 12 ++++++------ drivers/net/tulip/winbond-840.c | 2 +- drivers/net/tulip/xircom_tulip_cb.c | 2 +- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index c82befa209a..a0eda563559 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -63,7 +63,7 @@ MODULE_PARM_DESC (debug, "de2104x bitmapped message enable number"); /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(__sparc__) || defined(__ia64__) \ + || defined(CONFIG_SPARC) || defined(__ia64__) \ || defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 4b3cd3d8b62..e4af94e2282 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1160,7 +1160,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) sprintf(lp->adapter_name,"%s (%s)", name, gendev->bus_id); lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc); -#if defined(__alpha__) || defined(__powerpc__) || defined(__sparc_v9__) || defined(DE4X5_DO_MEMCPY) +#if defined(__alpha__) || defined(__powerpc__) || defined(CONFIG_SPARC) || defined(DE4X5_DO_MEMCPY) lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + DE4X5_ALIGN; #endif lp->rx_ring = dma_alloc_coherent(gendev, lp->dma_size, @@ -1175,7 +1175,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) ** Set up the RX descriptor ring (Intels) ** Allocate contiguous receive buffers, long word aligned (Alphas) */ -#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY) +#if !defined(__alpha__) && !defined(__powerpc__) && !defined(CONFIG_SPARC) && !defined(DE4X5_DO_MEMCPY) for (i=0; irx_ring[i].status = 0; lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); @@ -1252,11 +1252,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) mii_get_phy(dev); } -#ifndef __sparc_v9__ printk(" and requires IRQ%d (provided by %s).\n", dev->irq, -#else - printk(" and requires IRQ%x (provided by %s).\n", dev->irq, -#endif ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG")); } @@ -3627,7 +3623,7 @@ de4x5_alloc_rx_buff(struct net_device *dev, int index, int len) struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p; -#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY) +#if !defined(__alpha__) && !defined(__powerpc__) && !defined(CONFIG_SPARC) && !defined(DE4X5_DO_MEMCPY) struct sk_buff *ret; u_long i=0, tmp; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 03c14181b6b..81bcc564e15 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -36,7 +36,7 @@ #include #include -#ifdef __sparc__ +#ifdef CONFIG_SPARC #include #endif @@ -67,7 +67,7 @@ const char * const medianame[32] = { /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(__sparc__) || defined(__ia64__) \ + || defined(CONFIG_SPARC) || defined(__ia64__) \ || defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else @@ -91,7 +91,7 @@ static int rx_copybreak = 100; static int csr0 = 0x01A00000 | 0xE000; #elif defined(__i386__) || defined(__powerpc__) || defined(__x86_64__) static int csr0 = 0x01A00000 | 0x8000; -#elif defined(__sparc__) || defined(__hppa__) +#elif defined(CONFIG_SPARC) || defined(__hppa__) /* The UltraSparc PCI controllers will disconnect at every 64-byte * crossing anyways so it makes no sense to tell Tulip to burst * any more than that. @@ -1315,7 +1315,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, /* DM9102A has troubles with MRM & clear reserved bits 24:22, 20, 16, 7:1 */ if (tulip_uli_dm_quirk(pdev)) { csr0 &= ~0x01f100ff; -#if defined(__sparc__) +#if defined(CONFIG_SPARC) csr0 = (csr0 & ~0xff00) | 0xe000; #endif } @@ -1535,14 +1535,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, Many PCI BIOSes also incorrectly report the IRQ line, so we correct that here as well. */ if (sum == 0 || sum == 6*0xff) { -#if defined(__sparc__) +#if defined(CONFIG_SPARC) struct pcidev_cookie *pcp = pdev->sysdata; #endif eeprom_missing = 1; for (i = 0; i < 5; i++) dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; -#if defined(__sparc__) +#if defined(CONFIG_SPARC) if (pcp) { const unsigned char *addr; int len; diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 002a05e0722..e164a0d83fe 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -903,7 +903,7 @@ static void init_registers(struct net_device *dev) } #elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__) i |= 0xE000; -#elif defined(__sparc__) || defined (CONFIG_PARISC) +#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) i |= 0x4800; #else #warning Processor architecture undefined diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c index a998c5d0ae9..15a1be6a2fa 100644 --- a/drivers/net/tulip/xircom_tulip_cb.c +++ b/drivers/net/tulip/xircom_tulip_cb.c @@ -65,7 +65,7 @@ static int rx_copybreak = 100; static int csr0 = 0x01A00000 | 0xE000; #elif defined(__powerpc__) static int csr0 = 0x01B00000 | 0x8000; -#elif defined(__sparc__) +#elif defined(CONFIG_SPARC) static int csr0 = 0x01B00080 | 0x8000; #elif defined(__i386__) static int csr0 = 0x01A00000 | 0x8000; -- cgit v1.2.3 From d297c31fd101473983c17734a7e8a3752da1880f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Mar 2007 01:41:28 -0700 Subject: [TULIP]: Use pci_device_to_OF_node() on sparc. Signed-off-by: David S. Miller --- drivers/net/tulip/tulip_core.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 81bcc564e15..e9bf526ec53 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -37,7 +37,7 @@ #include #ifdef CONFIG_SPARC -#include +#include #endif static char version[] __devinitdata = @@ -1536,22 +1536,18 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, that here as well. */ if (sum == 0 || sum == 6*0xff) { #if defined(CONFIG_SPARC) - struct pcidev_cookie *pcp = pdev->sysdata; + struct device_node *dp = pci_device_to_OF_node(pdev); + const unsigned char *addr; + int len; #endif eeprom_missing = 1; for (i = 0; i < 5; i++) dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; #if defined(CONFIG_SPARC) - if (pcp) { - const unsigned char *addr; - int len; - - addr = of_get_property(pcp->prom_node, - "local-mac-address", &len); - if (addr && len == 6) - memcpy(dev->dev_addr, addr, 6); - } + addr = of_get_property(dp, "local-mac-address", &len); + if (addr && len == 6) + memcpy(dev->dev_addr, addr, 6); #endif #if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */ if (last_irq) -- cgit v1.2.3 From fa449bd602c8871da48e6dbadfa0faaf4d33d32e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 25 Apr 2007 16:01:51 -0700 Subject: [OPENPROM]: Use pci_device_to_OF_node(). Signed-off-by: David S. Miller --- drivers/sbus/char/openprom.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index aec3b9f991f..fbfeb89a6f3 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -44,7 +44,6 @@ #include #ifdef CONFIG_PCI #include -#include #endif MODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost (ecd@skynet.be)"); @@ -248,18 +247,17 @@ static int oprompci2node(void __user *argp, struct device_node *dp, struct openp if (bufsize >= 2*sizeof(int)) { #ifdef CONFIG_PCI struct pci_dev *pdev; - struct pcidev_cookie *pcp; + struct device_node *dp; + pdev = pci_get_bus_and_slot (((int *) op->oprom_array)[0], ((int *) op->oprom_array)[1]); - pcp = pdev->sysdata; - if (pcp != NULL) { - dp = pcp->prom_node; - data->current_node = dp; - *((int *)op->oprom_array) = dp->node; - op->oprom_size = sizeof(int); - err = copyout(argp, op, bufsize + sizeof(int)); - } + dp = pci_device_to_OF_node(pdev); + data->current_node = dp; + *((int *)op->oprom_array) = dp->node; + op->oprom_size = sizeof(int); + err = copyout(argp, op, bufsize + sizeof(int)); + pci_dev_put(pdev); #endif } -- cgit v1.2.3 From a02079cdb74dde27391d019abca4a37988504b4e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 17:02:45 -0800 Subject: [ATYFB]: Use pci_device_to_OF_node() in sparc. Signed-off-by: David S. Miller --- drivers/video/aty/atyfb_base.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index d7627fc4f11..8514f2a6f06 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2899,7 +2899,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, struct fb_info *info, unsigned long addr) { struct atyfb_par *par = info->par; - struct pcidev_cookie *pcp; + struct device_node *dp; char prop[128]; int node, len, i, j, ret; u32 mem, chip_id; @@ -3037,8 +3037,8 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, node = 0; } - pcp = pdev->sysdata; - if (node == pcp->prom_node->node) { + dp = pci_device_to_OF_node(pdev); + if (node == dp->node) { struct fb_var_screeninfo *var = &default_var; unsigned int N, P, Q, M, T, R; u32 v_total, h_total; -- cgit v1.2.3 From 9b1caafe09ccec8e0103e9375b711e3a0c838260 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 17:05:06 -0800 Subject: [IGAFB]: Use pci_device_to_OF_node() on sparc. Also __sparc__ --> CONFIG_SPARC Signed-off-by: David S. Miller --- drivers/video/igafb.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index 90592fb5915..eb1a4812ad1 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -44,8 +44,8 @@ #include -#ifdef __sparc__ -#include +#ifdef CONFIG_SPARC +#include #include #endif @@ -96,7 +96,7 @@ struct fb_var_screeninfo default_var = { .vmode = FB_VMODE_NONINTERLACED }; -#ifdef __sparc__ +#ifdef CONFIG_SPARC struct fb_var_screeninfo default_var_1024x768 __initdata = { /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ .xres = 1024, @@ -188,7 +188,7 @@ static inline void iga_outb(struct iga_par *par, unsigned char val, pci_outb(par, val, reg+1); } -#endif /* __sparc__ */ +#endif /* CONFIG_SPARC */ /* * Very important functionality for the JavaEngine1 computer: @@ -217,7 +217,7 @@ static void iga_blank_border(struct iga_par *par) iga_outb(par, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i); } -#ifdef __sparc__ +#ifdef CONFIG_SPARC static int igafb_mmap(struct fb_info *info, struct vm_area_struct *vma) { @@ -271,7 +271,7 @@ static int igafb_mmap(struct fb_info *info, vma->vm_flags |= VM_IO; return 0; } -#endif /* __sparc__ */ +#endif /* CONFIG_SPARC */ static int igafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, @@ -323,7 +323,7 @@ static struct fb_ops igafb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, -#ifdef __sparc__ +#ifdef CONFIG_SPARC .fb_mmap = igafb_mmap, #endif }; @@ -424,7 +424,7 @@ int __init igafb_init(void) par->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK; -#ifdef __sparc__ +#ifdef CONFIG_SPARC /* * The following is sparc specific and this is why: * @@ -477,8 +477,8 @@ int __init igafb_init(void) * Set default vmode and cmode from PROM properties. */ { - struct pcidev_cookie *cookie = pdev->sysdata; - int node = cookie->prom_node; + struct device_node *dp = pci_device_to_OF_node(pdev); + int node = dp->node; int width = prom_getintdefault(node, "width", 1024); int height = prom_getintdefault(node, "height", 768); int depth = prom_getintdefault(node, "depth", 8); @@ -534,7 +534,7 @@ int __init igafb_init(void) kfree(info); } -#ifdef __sparc__ +#ifdef CONFIG_SPARC /* * Add /dev/fb mmap values. */ @@ -552,7 +552,7 @@ int __init igafb_init(void) par->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */ par->mmap_map[1].prot_mask = SRMMU_CACHE; par->mmap_map[1].prot_flag = SRMMU_WRITE; -#endif /* __sparc__ */ +#endif /* CONFIG_SPARC */ return 0; } -- cgit v1.2.3 From 1327e9b62fc88e64ffbbd42d61fccd34e521bb86 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 17:55:46 -0800 Subject: [SPARC64] ebus: Convert to use pci_device_to_OF_node(). Also, we don't need to store or use the PBM so kill that from the linux_ebus. Signed-off-by: David S. Miller --- arch/sparc64/kernel/ebus.c | 12 +++--------- include/asm-sparc64/ebus.h | 2 -- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 1962bfa4ef3..0ace17bafba 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -438,11 +438,9 @@ static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p) void __init ebus_init(void) { - struct pci_pbm_info *pbm; struct linux_ebus_device *dev; struct linux_ebus *ebus; struct pci_dev *pdev; - struct pcidev_cookie *cookie; struct device_node *dp; int is_rio; int num_ebus = 0; @@ -453,8 +451,7 @@ void __init ebus_init(void) return; } - cookie = pdev->sysdata; - dp = cookie->prom_node; + dp = pci_device_to_OF_node(pdev); ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); ebus->next = NULL; @@ -480,8 +477,7 @@ void __init ebus_init(void) break; } ebus->is_rio = is_rio; - cookie = pdev->sysdata; - dp = cookie->prom_node; + dp = pci_device_to_OF_node(pdev); continue; } printk("ebus%d:", num_ebus); @@ -489,7 +485,6 @@ void __init ebus_init(void) ebus->index = num_ebus; ebus->prom_node = dp; ebus->self = pdev; - ebus->parent = pbm = cookie->pbm; ebus->ofdev.node = dp; ebus->ofdev.dev.parent = &pdev->dev; @@ -531,8 +526,7 @@ void __init ebus_init(void) if (!pdev) break; - cookie = pdev->sysdata; - dp = cookie->prom_node; + dp = pci_device_to_OF_node(pdev); ebus->next = ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h index a4afe9d5703..9c1c6db2a79 100644 --- a/include/asm-sparc64/ebus.h +++ b/include/asm-sparc64/ebus.h @@ -8,7 +8,6 @@ #ifndef __SPARC64_EBUS_H #define __SPARC64_EBUS_H -#include #include #include #include @@ -41,7 +40,6 @@ struct linux_ebus { struct of_device ofdev; struct linux_ebus *next; struct linux_ebus_device *devices; - struct pci_pbm_info *parent; struct pci_dev *self; int index; int is_rio; -- cgit v1.2.3 From deb66c4521e119442aa266553e8cbfc86eb71232 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 18:01:38 -0800 Subject: [SPARC64] isa: Convert to use pci_device_to_OF_node(). Also, do not try to compute resources by hand, instead use the pre-computed ones in the of_device. Signed-off-by: David S. Miller --- arch/sparc64/kernel/isa.c | 36 ++++-------------------------------- include/asm-sparc64/isa.h | 2 -- 2 files changed, 4 insertions(+), 34 deletions(-) diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index 791eeb7e387..6a6882e57ff 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -24,27 +24,9 @@ static void __init report_dev(struct sparc_isa_device *isa_dev, int child) static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev) { - const struct linux_prom_registers *pregs; - unsigned long base, len; - int prop_len; - - pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len); - if (!pregs) - return; - - /* Only the first one is interesting. */ - len = pregs[0].reg_size; - base = (((unsigned long)pregs[0].which_io << 32) | - (unsigned long)pregs[0].phys_addr); - base += isa_dev->bus->parent->io_space.start; - - isa_dev->resource.start = base; - isa_dev->resource.end = (base + len - 1UL); - isa_dev->resource.flags = IORESOURCE_IO; - isa_dev->resource.name = isa_dev->prom_node->name; + struct of_device *op = of_find_device_by_node(isa_dev->prom_node); - request_resource(&isa_dev->bus->parent->io_space, - &isa_dev->resource); + memcpy(&isa_dev->resource, &op->resource[0], sizeof(struct resource)); } static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev) @@ -158,19 +140,10 @@ void __init isa_init(void) pdev = NULL; while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) { - struct pcidev_cookie *pdev_cookie; - struct pci_pbm_info *pbm; struct sparc_isa_bridge *isa_br; struct device_node *dp; - pdev_cookie = pdev->sysdata; - if (!pdev_cookie) { - printk("ISA: Warning, ISA bridge ignored due to " - "lack of OBP data.\n"); - continue; - } - pbm = pdev_cookie->pbm; - dp = pdev_cookie->prom_node; + dp = pci_device_to_OF_node(pdev); isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL); if (!isa_br) { @@ -195,10 +168,9 @@ void __init isa_init(void) isa_br->next = isa_chain; isa_chain = isa_br; - isa_br->parent = pbm; isa_br->self = pdev; isa_br->index = index++; - isa_br->prom_node = pdev_cookie->prom_node; + isa_br->prom_node = dp; printk("isa%d:", isa_br->index); diff --git a/include/asm-sparc64/isa.h b/include/asm-sparc64/isa.h index d9728b9031f..ecd9290f78d 100644 --- a/include/asm-sparc64/isa.h +++ b/include/asm-sparc64/isa.h @@ -7,7 +7,6 @@ #ifndef __SPARC64_ISA_H #define __SPARC64_ISA_H -#include #include #include #include @@ -29,7 +28,6 @@ struct sparc_isa_bridge { struct of_device ofdev; struct sparc_isa_bridge *next; struct sparc_isa_device *devices; - struct pci_pbm_info *parent; struct pci_dev *self; int index; struct device_node *prom_node; -- cgit v1.2.3 From a2fb23af1c31ad6e0c281e56d385f803229d57fa Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 23:35:04 -0800 Subject: [SPARC64]: Probe PCI bus using OF device tree. Almost entirely taken from the 64-bit PowerPC PCI code. This allowed to eliminate a ton of cruft from the sparc64 PCI layer. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 375 ++++++++++++++++++++- arch/sparc64/kernel/pci_common.c | 707 --------------------------------------- arch/sparc64/kernel/pci_impl.h | 15 +- arch/sparc64/kernel/pci_iommu.c | 47 +-- arch/sparc64/kernel/pci_psycho.c | 26 +- arch/sparc64/kernel/pci_sabre.c | 53 +-- arch/sparc64/kernel/pci_schizo.c | 26 +- arch/sparc64/kernel/pci_sun4v.c | 199 ++--------- include/asm-sparc64/device.h | 18 +- include/asm-sparc64/pbm.h | 23 -- 10 files changed, 426 insertions(+), 1063 deletions(-) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 12109886bb1..246b8009a2b 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -1,9 +1,11 @@ -/* $Id: pci.c,v 1.39 2002/01/05 01:13:43 davem Exp $ - * pci.c: UltraSparc PCI controller support. +/* pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + * + * OF tree based PCI bus probing taken from the PowerPC port + * with minor modifications, see there for credits. */ #include @@ -300,6 +302,329 @@ static void __init pci_controller_probe(void) pci_controller_scan(pci_controller_init); } +static unsigned long pci_parse_of_flags(u32 addr0) +{ + unsigned long flags = 0; + + if (addr0 & 0x02000000) { + flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY; + flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64; + flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M; + if (addr0 & 0x40000000) + flags |= IORESOURCE_PREFETCH + | PCI_BASE_ADDRESS_MEM_PREFETCH; + } else if (addr0 & 0x01000000) + flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO; + return flags; +} + +/* The of_device layer has translated all of the assigned-address properties + * into physical address resources, we only have to figure out the register + * mapping. + */ +static void pci_parse_of_addrs(struct of_device *op, + struct device_node *node, + struct pci_dev *dev) +{ + struct resource *op_res; + const u32 *addrs; + int proplen; + + addrs = of_get_property(node, "assigned-addresses", &proplen); + if (!addrs) + return; + printk(" parse addresses (%d bytes) @ %p\n", proplen, addrs); + op_res = &op->resource[0]; + for (; proplen >= 20; proplen -= 20, addrs += 5, op_res++) { + struct resource *res; + unsigned long flags; + int i; + + flags = pci_parse_of_flags(addrs[0]); + if (!flags) + continue; + i = addrs[0] & 0xff; + printk(" start: %lx, end: %lx, i: %x\n", + op_res->start, op_res->end, i); + + if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { + res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; + } else if (i == dev->rom_base_reg) { + res = &dev->resource[PCI_ROM_RESOURCE]; + flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE; + } else { + printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i); + continue; + } + res->start = op_res->start; + res->end = op_res->end; + res->flags = flags; + res->name = pci_name(dev); + } +} + +struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, + struct device_node *node, + struct pci_bus *bus, int devfn) +{ + struct dev_archdata *sd; + struct pci_dev *dev; + const char *type; + + dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); + if (!dev) + return NULL; + + sd = &dev->dev.archdata; + sd->iommu = pbm->iommu; + sd->stc = &pbm->stc; + sd->host_controller = pbm; + sd->prom_node = node; + sd->op = of_find_device_by_node(node); + sd->msi_num = 0xffffffff; + + type = of_get_property(node, "device_type", NULL); + if (type == NULL) + type = ""; + + printk(" create device, devfn: %x, type: %s\n", devfn, type); + + dev->bus = bus; + dev->sysdata = node; + dev->dev.parent = bus->bridge; + dev->dev.bus = &pci_bus_type; + dev->devfn = devfn; + dev->multifunction = 0; /* maybe a lie? */ + + dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); + dev->device = of_getintprop_default(node, "device-id", 0xffff); + dev->subsystem_vendor = + of_getintprop_default(node, "subsystem-vendor-id", 0); + dev->subsystem_device = + of_getintprop_default(node, "subsystem-id", 0); + + dev->cfg_size = pci_cfg_space_size(dev); + + sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), + dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); + dev->class = of_getintprop_default(node, "class-code", 0); + + printk(" class: 0x%x\n", dev->class); + + dev->current_state = 4; /* unknown power state */ + dev->error_state = pci_channel_io_normal; + + if (!strcmp(type, "pci") || !strcmp(type, "pciex")) { + /* a PCI-PCI bridge */ + dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; + dev->rom_base_reg = PCI_ROM_ADDRESS1; + } else if (!strcmp(type, "cardbus")) { + dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; + } else { + dev->hdr_type = PCI_HEADER_TYPE_NORMAL; + dev->rom_base_reg = PCI_ROM_ADDRESS; + + dev->irq = sd->op->irqs[0]; + if (dev->irq == 0xffffffff) + dev->irq = PCI_IRQ_NONE; + } + + pci_parse_of_addrs(sd->op, node, dev); + + printk(" adding to system ...\n"); + + pci_device_add(dev, bus); + + return dev; +} + +static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, + struct device_node *node, + struct pci_bus *bus); + +#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) + +void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, + struct device_node *node, + struct pci_dev *dev) +{ + struct pci_bus *bus; + const u32 *busrange, *ranges; + int len, i; + struct resource *res; + unsigned int flags; + u64 size; + + printk("of_scan_pci_bridge(%s)\n", node->full_name); + + /* parse bus-range property */ + busrange = of_get_property(node, "bus-range", &len); + if (busrange == NULL || len != 8) { + printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n", + node->full_name); + return; + } + ranges = of_get_property(node, "ranges", &len); + if (ranges == NULL) { + printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", + node->full_name); + return; + } + + bus = pci_add_new_bus(dev->bus, dev, busrange[0]); + if (!bus) { + printk(KERN_ERR "Failed to create pci bus for %s\n", + node->full_name); + return; + } + + bus->primary = dev->bus->number; + bus->subordinate = busrange[1]; + bus->bridge_ctl = 0; + + /* parse ranges property */ + /* PCI #address-cells == 3 and #size-cells == 2 always */ + res = &dev->resource[PCI_BRIDGE_RESOURCES]; + for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) { + res->flags = 0; + bus->resource[i] = res; + ++res; + } + i = 1; + for (; len >= 32; len -= 32, ranges += 8) { + struct resource *root; + + flags = pci_parse_of_flags(ranges[0]); + size = GET_64BIT(ranges, 6); + if (flags == 0 || size == 0) + continue; + if (flags & IORESOURCE_IO) { + res = bus->resource[0]; + if (res->flags) { + printk(KERN_ERR "PCI: ignoring extra I/O range" + " for bridge %s\n", node->full_name); + continue; + } + root = &pbm->io_space; + } else { + if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) { + printk(KERN_ERR "PCI: too many memory ranges" + " for bridge %s\n", node->full_name); + continue; + } + res = bus->resource[i]; + ++i; + root = &pbm->mem_space; + } + + res->start = GET_64BIT(ranges, 1); + res->end = res->start + size - 1; + res->flags = flags; + + /* Another way to implement this would be to add an of_device + * layer routine that can calculate a resource for a given + * range property value in a PCI device. + */ + pbm->parent->resource_adjust(dev, res, root); + } + sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), + bus->number); + printk(" bus name: %s\n", bus->name); + + pci_of_scan_bus(pbm, node, bus); +} + +static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, + struct device_node *node, + struct pci_bus *bus) +{ + struct device_node *child; + const u32 *reg; + int reglen, devfn; + struct pci_dev *dev; + + printk("PCI: scan_bus[%s] bus no %d\n", + node->full_name, bus->number); + + child = NULL; + while ((child = of_get_next_child(node, child)) != NULL) { + printk(" * %s\n", child->full_name); + reg = of_get_property(child, "reg", ®len); + if (reg == NULL || reglen < 20) + continue; + devfn = (reg[0] >> 8) & 0xff; + + /* create a new pci_dev for this device */ + dev = of_create_pci_dev(pbm, child, bus, devfn); + if (!dev) + continue; + printk("PCI: dev header type: %x\n", dev->hdr_type); + + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + of_scan_pci_bridge(pbm, child, dev); + } +} + +static ssize_t +show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) +{ + struct pci_dev *pdev; + struct device_node *dp; + + pdev = to_pci_dev(dev); + dp = pdev->dev.archdata.prom_node; + + return snprintf (buf, PAGE_SIZE, "%s\n", dp->full_name); +} + +static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL); + +static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) +{ + struct pci_dev *dev; + int err; + + list_for_each_entry(dev, &bus->devices, bus_list) { + /* we don't really care if we can create this file or + * not, but we need to assign the result of the call + * or the world will fall under alien invasion and + * everybody will be frozen on a spaceship ready to be + * eaten on alpha centauri by some green and jelly + * humanoid. + */ + err = sysfs_create_file(&dev->dev.kobj, &dev_attr_obppath.attr); + } +} + +struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm) +{ + struct pci_controller_info *p = pbm->parent; + struct device_node *node = pbm->prom_node; + struct pci_bus *bus; + + printk("PCI: Scanning PBM %s\n", node->full_name); + + /* XXX parent device? XXX */ + bus = pci_create_bus(NULL, pbm->pci_first_busno, p->pci_ops, pbm); + if (!bus) { + printk(KERN_ERR "Failed to create bus for %s\n", + node->full_name); + return NULL; + } + bus->secondary = pbm->pci_first_busno; + bus->subordinate = pbm->pci_last_busno; + + bus->resource[0] = &pbm->io_space; + bus->resource[1] = &pbm->mem_space; + + pci_of_scan_bus(pbm, node, bus); + pci_bus_add_devices(bus); + pci_bus_register_of_sysfs(bus); + + return bus; +} + static void __init pci_scan_each_controller_bus(void) { struct pci_controller_info *p; @@ -360,8 +685,33 @@ void pcibios_align_resource(void *data, struct resource *res, { } -int pcibios_enable_device(struct pci_dev *pdev, int mask) +int pcibios_enable_device(struct pci_dev *dev, int mask) { + u16 cmd, oldcmd; + int i; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + oldcmd = cmd; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *res = &dev->resource[i]; + + /* Only set up the requested stuff */ + if (!(mask & (1<flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (res->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + + if (cmd != oldcmd) { + printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n", + pci_name(dev), cmd); + /* Enable the appropriate bits in the PCI command register. */ + pci_write_config_word(dev, PCI_COMMAND, cmd); + } return 0; } @@ -422,17 +772,10 @@ char * __devinit pcibios_setup(char *str) static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm; + struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; struct pci_controller_info *p; unsigned long space_size, user_offset, user_size; - if (!pcp) - return -ENXIO; - pbm = pcp->pbm; - if (!pbm) - return -ENXIO; - p = pbm->parent; if (p->pbms_same_domain) { unsigned long lowest, highest; @@ -651,8 +994,7 @@ EXPORT_SYMBOL(pci_domain_nr); #ifdef CONFIG_PCI_MSI int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; + struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; struct pci_controller_info *p = pbm->parent; int virt_irq, err; @@ -670,8 +1012,7 @@ void arch_teardown_msi_irq(unsigned int virt_irq) { struct msi_desc *entry = get_irq_msi(virt_irq); struct pci_dev *pdev = entry->dev; - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; + struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; struct pci_controller_info *p = pbm->parent; if (!pbm->msi_num || !p->setup_msi_irq) @@ -683,9 +1024,7 @@ void arch_teardown_msi_irq(unsigned int virt_irq) struct device_node *pci_device_to_OF_node(struct pci_dev *pdev) { - struct pcidev_cookie *pc = pdev->sysdata; - - return pc->op->node; + return pdev->dev.archdata.prom_node; } EXPORT_SYMBOL(pci_device_to_OF_node); diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 5a92cb90ebe..0d3c95df0d9 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -16,713 +16,6 @@ #include "pci_impl.h" -/* Fix self device of BUS and hook it into BUS->self. - * The pci_scan_bus does not do this for the host bridge. - */ -void __init pci_fixup_host_bridge_self(struct pci_bus *pbus) -{ - struct pci_dev *pdev; - - list_for_each_entry(pdev, &pbus->devices, bus_list) { - if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) { - pbus->self = pdev; - return; - } - } - - prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n"); - prom_halt(); -} - -/* Find the OBP PROM device tree node for a PCI device. */ -static struct device_node * __init -find_device_prom_node(struct pci_pbm_info *pbm, struct pci_dev *pdev, - struct device_node *bus_node, - struct linux_prom_pci_registers **pregs, - int *nregs) -{ - struct device_node *dp; - - *nregs = 0; - - /* - * Return the PBM's PROM node in case we are it's PCI device, - * as the PBM's reg property is different to standard PCI reg - * properties. We would delete this device entry otherwise, - * which confuses XFree86's device probing... - */ - if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) && - (pdev->vendor == PCI_VENDOR_ID_SUN) && - (pdev->device == PCI_DEVICE_ID_SUN_PBM || - pdev->device == PCI_DEVICE_ID_SUN_SCHIZO || - pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO || - pdev->device == PCI_DEVICE_ID_SUN_SABRE || - pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) - return bus_node; - - dp = bus_node->child; - while (dp) { - struct linux_prom_pci_registers *regs; - struct property *prop; - int len; - - prop = of_find_property(dp, "reg", &len); - if (!prop) - goto do_next_sibling; - - regs = prop->value; - if (((regs[0].phys_hi >> 8) & 0xff) == pdev->devfn) { - *pregs = regs; - *nregs = len / sizeof(struct linux_prom_pci_registers); - return dp; - } - - do_next_sibling: - dp = dp->sibling; - } - - return NULL; -} - -/* Older versions of OBP on PCI systems encode 64-bit MEM - * space assignments incorrectly, this fixes them up. We also - * take the opportunity here to hide other kinds of bogus - * assignments. - */ -static void __init fixup_obp_assignments(struct pci_dev *pdev, - struct pcidev_cookie *pcp) -{ - int i; - - if (pdev->vendor == PCI_VENDOR_ID_AL && - (pdev->device == PCI_DEVICE_ID_AL_M7101 || - pdev->device == PCI_DEVICE_ID_AL_M1533)) { - int i; - - /* Zap all of the normal resources, they are - * meaningless and generate bogus resource collision - * messages. This is OpenBoot's ill-fated attempt to - * represent the implicit resources that these devices - * have. - */ - pcp->num_prom_assignments = 0; - for (i = 0; i < 6; i++) { - pdev->resource[i].start = - pdev->resource[i].end = - pdev->resource[i].flags = 0; - } - pdev->resource[PCI_ROM_RESOURCE].start = - pdev->resource[PCI_ROM_RESOURCE].end = - pdev->resource[PCI_ROM_RESOURCE].flags = 0; - return; - } - - for (i = 0; i < pcp->num_prom_assignments; i++) { - struct linux_prom_pci_registers *ap; - int space; - - ap = &pcp->prom_assignments[i]; - space = ap->phys_hi >> 24; - if ((space & 0x3) == 2 && - (space & 0x4) != 0) { - ap->phys_hi &= ~(0x7 << 24); - ap->phys_hi |= 0x3 << 24; - } - } -} - -static ssize_t -show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) -{ - struct pci_dev *pdev; - struct pcidev_cookie *sysdata; - - pdev = to_pci_dev(dev); - sysdata = pdev->sysdata; - - return snprintf (buf, PAGE_SIZE, "%s\n", sysdata->prom_node->full_name); -} - -static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL); - -/* Fill in the PCI device cookie sysdata for the given - * PCI device. This cookie is the means by which one - * can get to OBP and PCI controller specific information - * for a PCI device. - */ -static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - struct device_node *bus_node) -{ - struct linux_prom_pci_registers *pregs = NULL; - struct pcidev_cookie *pcp; - struct device_node *dp; - struct property *prop; - int nregs, len, err; - - dp = find_device_prom_node(pbm, pdev, bus_node, - &pregs, &nregs); - if (!dp) { - /* If it is not in the OBP device tree then - * there must be a damn good reason for it. - * - * So what we do is delete the device from the - * PCI device tree completely. This scenario - * is seen, for example, on CP1500 for the - * second EBUS/HappyMeal pair if the external - * connector for it is not present. - */ - pci_remove_bus_device(pdev); - return; - } - - pcp = kzalloc(sizeof(*pcp), GFP_ATOMIC); - if (pcp == NULL) { - prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n"); - prom_halt(); - } - pcp->pbm = pbm; - pcp->prom_node = dp; - pcp->op = of_find_device_by_node(dp); - memcpy(pcp->prom_regs, pregs, - nregs * sizeof(struct linux_prom_pci_registers)); - pcp->num_prom_regs = nregs; - - /* We can't have the pcidev_cookie assignments be just - * direct pointers into the property value, since they - * are potentially modified by the probing process. - */ - prop = of_find_property(dp, "assigned-addresses", &len); - if (!prop) { - pcp->num_prom_assignments = 0; - } else { - memcpy(pcp->prom_assignments, prop->value, len); - pcp->num_prom_assignments = - (len / sizeof(pcp->prom_assignments[0])); - } - - if (strcmp(dp->name, "ebus") == 0) { - struct linux_prom_ebus_ranges *erng; - int iter; - - /* EBUS is special... */ - prop = of_find_property(dp, "ranges", &len); - if (!prop) { - prom_printf("EBUS: Fatal error, no range property\n"); - prom_halt(); - } - erng = prop->value; - len = (len / sizeof(erng[0])); - for (iter = 0; iter < len; iter++) { - struct linux_prom_ebus_ranges *ep = &erng[iter]; - struct linux_prom_pci_registers *ap; - - ap = &pcp->prom_assignments[iter]; - - ap->phys_hi = ep->parent_phys_hi; - ap->phys_mid = ep->parent_phys_mid; - ap->phys_lo = ep->parent_phys_lo; - ap->size_hi = 0; - ap->size_lo = ep->size; - } - pcp->num_prom_assignments = len; - } - - fixup_obp_assignments(pdev, pcp); - - pdev->sysdata = pcp; - - /* we don't really care if we can create this file or not, - * but we need to assign the result of the call or the world will fall - * under alien invasion and everybody will be frozen on a spaceship - * ready to be eaten on alpha centauri by some green and jelly humanoid. - */ - err = sysfs_create_file(&pdev->dev.kobj, &dev_attr_obppath.attr); -} - -void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus, - struct pci_pbm_info *pbm, - struct device_node *dp) -{ - struct pci_dev *pdev, *pdev_next; - struct pci_bus *this_pbus, *pbus_next; - - /* This must be _safe because the cookie fillin - routine can delete devices from the tree. */ - list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list) - pdev_cookie_fillin(pbm, pdev, dp); - - list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) { - struct pcidev_cookie *pcp = this_pbus->self->sysdata; - - pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node); - } -} - -static void __init bad_assignment(struct pci_dev *pdev, - struct linux_prom_pci_registers *ap, - struct resource *res, - int do_prom_halt) -{ - prom_printf("PCI: Bogus PROM assignment. BUS[%02x] DEVFN[%x]\n", - pdev->bus->number, pdev->devfn); - if (ap) - prom_printf("PCI: phys[%08x:%08x:%08x] size[%08x:%08x]\n", - ap->phys_hi, ap->phys_mid, ap->phys_lo, - ap->size_hi, ap->size_lo); - if (res) - prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n", - res->start, res->end, res->flags); - if (do_prom_halt) - prom_halt(); -} - -static struct resource * -__init get_root_resource(struct linux_prom_pci_registers *ap, - struct pci_pbm_info *pbm) -{ - int space = (ap->phys_hi >> 24) & 3; - - switch (space) { - case 0: - /* Configuration space, silently ignore it. */ - return NULL; - - case 1: - /* 16-bit IO space */ - return &pbm->io_space; - - case 2: - /* 32-bit MEM space */ - return &pbm->mem_space; - - case 3: - /* 64-bit MEM space, these are allocated out of - * the 32-bit mem_space range for the PBM, ie. - * we just zero out the upper 32-bits. - */ - return &pbm->mem_space; - - default: - printk("PCI: What is resource space %x?\n", space); - return NULL; - }; -} - -static struct resource * -__init get_device_resource(struct linux_prom_pci_registers *ap, - struct pci_dev *pdev) -{ - struct resource *res; - int breg = (ap->phys_hi & 0xff); - - switch (breg) { - case PCI_ROM_ADDRESS: - /* Unfortunately I have seen several cases where - * buggy FCODE uses a space value of '1' (I/O space) - * in the register property for the ROM address - * so disable this sanity check for now. - */ -#if 0 - { - int space = (ap->phys_hi >> 24) & 3; - - /* It had better be MEM space. */ - if (space != 2) - bad_assignment(pdev, ap, NULL, 0); - } -#endif - res = &pdev->resource[PCI_ROM_RESOURCE]; - break; - - case PCI_BASE_ADDRESS_0: - case PCI_BASE_ADDRESS_1: - case PCI_BASE_ADDRESS_2: - case PCI_BASE_ADDRESS_3: - case PCI_BASE_ADDRESS_4: - case PCI_BASE_ADDRESS_5: - res = &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4]; - break; - - default: - bad_assignment(pdev, ap, NULL, 0); - res = NULL; - break; - }; - - return res; -} - -static void __init pdev_record_assignments(struct pci_pbm_info *pbm, - struct pci_dev *pdev) -{ - struct pcidev_cookie *pcp = pdev->sysdata; - int i; - - for (i = 0; i < pcp->num_prom_assignments; i++) { - struct linux_prom_pci_registers *ap; - struct resource *root, *res; - - /* The format of this property is specified in - * the PCI Bus Binding to IEEE1275-1994. - */ - ap = &pcp->prom_assignments[i]; - root = get_root_resource(ap, pbm); - res = get_device_resource(ap, pdev); - if (root == NULL || res == NULL || - res->flags == 0) - continue; - - /* Ok we know which resource this PROM assignment is - * for, sanity check it. - */ - if ((res->start & 0xffffffffUL) != ap->phys_lo) - bad_assignment(pdev, ap, res, 1); - - /* If it is a 64-bit MEM space assignment, verify that - * the resource is too and that the upper 32-bits match. - */ - if (((ap->phys_hi >> 24) & 3) == 3) { - if (((res->flags & IORESOURCE_MEM) == 0) || - ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) - != PCI_BASE_ADDRESS_MEM_TYPE_64)) - bad_assignment(pdev, ap, res, 1); - if ((res->start >> 32) != ap->phys_mid) - bad_assignment(pdev, ap, res, 1); - - /* PBM cannot generate cpu initiated PIOs - * to the full 64-bit space. Therefore the - * upper 32-bits better be zero. If it is - * not, just skip it and we will assign it - * properly ourselves. - */ - if ((res->start >> 32) != 0UL) { - printk(KERN_ERR "PCI: OBP assigns out of range MEM address " - "%016lx for region %ld on device %s\n", - res->start, (res - &pdev->resource[0]), pci_name(pdev)); - continue; - } - } - - /* Adjust the resource into the physical address space - * of this PBM. - */ - pbm->parent->resource_adjust(pdev, res, root); - - if (request_resource(root, res) < 0) { - int rnum; - - /* OK, there is some conflict. But this is fine - * since we'll reassign it in the fixup pass. - * - * Do not print the warning for ROM resources - * as such a conflict is quite common and - * harmless as the ROM bar is disabled. - */ - rnum = (res - &pdev->resource[0]); - if (rnum != PCI_ROM_RESOURCE) - printk(KERN_ERR "PCI: Resource collision, " - "region %d " - "[%016lx:%016lx] of device %s\n", - rnum, - res->start, res->end, - pci_name(pdev)); - } - } -} - -void __init pci_record_assignments(struct pci_pbm_info *pbm, - struct pci_bus *pbus) -{ - struct pci_dev *dev; - struct pci_bus *bus; - - list_for_each_entry(dev, &pbus->devices, bus_list) - pdev_record_assignments(pbm, dev); - - list_for_each_entry(bus, &pbus->children, node) - pci_record_assignments(pbm, bus); -} - -/* Return non-zero if PDEV has implicit I/O resources even - * though it may not have an I/O base address register - * active. - */ -static int __init has_implicit_io(struct pci_dev *pdev) -{ - int class = pdev->class >> 8; - - if (class == PCI_CLASS_NOT_DEFINED || - class == PCI_CLASS_NOT_DEFINED_VGA || - class == PCI_CLASS_STORAGE_IDE || - (pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) - return 1; - - return 0; -} - -static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm, - struct pci_dev *pdev) -{ - u32 reg; - u16 cmd; - int i, io_seen, mem_seen; - - io_seen = mem_seen = 0; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *root, *res; - unsigned long size, min, max, align; - - res = &pdev->resource[i]; - - if (res->flags & IORESOURCE_IO) - io_seen++; - else if (res->flags & IORESOURCE_MEM) - mem_seen++; - - /* If it is already assigned or the resource does - * not exist, there is nothing to do. - */ - if (res->parent != NULL || res->flags == 0UL) - continue; - - /* Determine the root we allocate from. */ - if (res->flags & IORESOURCE_IO) { - root = &pbm->io_space; - min = root->start + 0x400UL; - max = root->end; - } else { - root = &pbm->mem_space; - min = root->start; - max = min + 0x80000000UL; - } - - size = res->end - res->start; - align = size + 1; - if (allocate_resource(root, res, size + 1, min, max, align, NULL, NULL) < 0) { - /* uh oh */ - prom_printf("PCI: Failed to allocate resource %d for %s\n", - i, pci_name(pdev)); - prom_halt(); - } - - /* Update PCI config space. */ - pbm->parent->base_address_update(pdev, i); - } - - /* Special case, disable the ROM. Several devices - * act funny (ie. do not respond to memory space writes) - * when it is left enabled. A good example are Qlogic,ISP - * adapters. - */ - pci_read_config_dword(pdev, PCI_ROM_ADDRESS, ®); - reg &= ~PCI_ROM_ADDRESS_ENABLE; - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, reg); - - /* If we saw I/O or MEM resources, enable appropriate - * bits in PCI command register. - */ - if (io_seen || mem_seen) { - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - if (io_seen || has_implicit_io(pdev)) - cmd |= PCI_COMMAND_IO; - if (mem_seen) - cmd |= PCI_COMMAND_MEMORY; - pci_write_config_word(pdev, PCI_COMMAND, cmd); - } - - /* If this is a PCI bridge or an IDE controller, - * enable bus mastering. In the former case also - * set the cache line size correctly. - */ - if (((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) || - (((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) && - ((pdev->class & 0x80) != 0))) { - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, cmd); - - if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) - pci_write_config_byte(pdev, - PCI_CACHE_LINE_SIZE, - (64 / sizeof(u32))); - } -} - -void __init pci_assign_unassigned(struct pci_pbm_info *pbm, - struct pci_bus *pbus) -{ - struct pci_dev *dev; - struct pci_bus *bus; - - list_for_each_entry(dev, &pbus->devices, bus_list) - pdev_assign_unassigned(pbm, dev); - - list_for_each_entry(bus, &pbus->children, node) - pci_assign_unassigned(pbm, bus); -} - -static void __init pdev_fixup_irq(struct pci_dev *pdev) -{ - struct pcidev_cookie *pcp = pdev->sysdata; - struct of_device *op = pcp->op; - - if (op->irqs[0] == 0xffffffff) { - pdev->irq = PCI_IRQ_NONE; - return; - } - - pdev->irq = op->irqs[0]; - - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, - pdev->irq & PCI_IRQ_INO); -} - -void __init pci_fixup_irq(struct pci_pbm_info *pbm, - struct pci_bus *pbus) -{ - struct pci_dev *dev; - struct pci_bus *bus; - - list_for_each_entry(dev, &pbus->devices, bus_list) - pdev_fixup_irq(dev); - - list_for_each_entry(bus, &pbus->children, node) - pci_fixup_irq(pbm, bus); -} - -static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz) -{ - u16 cmd; - u8 hdr_type, min_gnt, ltimer; - - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, cmd); - - /* Read it back, if the mastering bit did not - * get set, the device does not support bus - * mastering so we have nothing to do here. - */ - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - if ((cmd & PCI_COMMAND_MASTER) == 0) - return; - - /* Set correct cache line size, 64-byte on all - * Sparc64 PCI systems. Note that the value is - * measured in 32-bit words. - */ - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, - 64 / sizeof(u32)); - - pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr_type); - hdr_type &= ~0x80; - if (hdr_type != PCI_HEADER_TYPE_NORMAL) - return; - - /* If the latency timer is already programmed with a non-zero - * value, assume whoever set it (OBP or whoever) knows what - * they are doing. - */ - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, <imer); - if (ltimer != 0) - return; - - /* XXX Since I'm tipping off the min grant value to - * XXX choose a suitable latency timer value, I also - * XXX considered making use of the max latency value - * XXX as well. Unfortunately I've seen too many bogusly - * XXX low settings for it to the point where it lacks - * XXX any usefulness. In one case, an ethernet card - * XXX claimed a min grant of 10 and a max latency of 5. - * XXX Now, if I had two such cards on the same bus I - * XXX could not set the desired burst period (calculated - * XXX from min grant) without violating the max latency - * XXX bound. Duh... - * XXX - * XXX I blame dumb PC bios implementors for stuff like - * XXX this, most of them don't even try to do something - * XXX sensible with latency timer values and just set some - * XXX default value (usually 32) into every device. - */ - - pci_read_config_byte(pdev, PCI_MIN_GNT, &min_gnt); - - if (min_gnt == 0) { - /* If no min_gnt setting then use a default - * value. - */ - if (is_66mhz) - ltimer = 16; - else - ltimer = 32; - } else { - int shift_factor; - - if (is_66mhz) - shift_factor = 2; - else - shift_factor = 3; - - /* Use a default value when the min_gnt value - * is erroneously high. - */ - if (((unsigned int) min_gnt << shift_factor) > 512 || - ((min_gnt << shift_factor) & 0xff) == 0) { - ltimer = 8 << shift_factor; - } else { - ltimer = min_gnt << shift_factor; - } - } - - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer); -} - -void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, - struct pci_bus *pbus) -{ - struct pci_dev *pdev; - int all_are_66mhz; - u16 status; - - if (pbm->is_66mhz_capable == 0) { - all_are_66mhz = 0; - goto out; - } - - all_are_66mhz = 1; - list_for_each_entry(pdev, &pbus->devices, bus_list) { - pci_read_config_word(pdev, PCI_STATUS, &status); - if (!(status & PCI_STATUS_66MHZ)) { - all_are_66mhz = 0; - break; - } - } -out: - pbm->all_devs_66mhz = all_are_66mhz; - - printk("PCI%d(PBM%c): Bus running at %dMHz\n", - pbm->parent->index, - (pbm == &pbm->parent->pbm_A) ? 'A' : 'B', - (all_are_66mhz ? 66 : 33)); -} - -void pci_setup_busmastering(struct pci_pbm_info *pbm, - struct pci_bus *pbus) -{ - struct pci_dev *dev; - struct pci_bus *bus; - int is_66mhz; - - is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz; - - list_for_each_entry(dev, &pbus->devices, bus_list) - pdev_setup_busmastering(dev, is_66mhz); - - list_for_each_entry(bus, &pbus->children, node) - pci_setup_busmastering(pbm, bus); -} - void pci_register_legacy_regions(struct resource *io_res, struct resource *mem_res) { diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index 971e2bea30b..ea8a6bd146a 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -17,20 +17,7 @@ extern struct pci_controller_info *pci_controller_root; extern int pci_num_controllers; /* PCI bus scanning and fixup support. */ -extern void pci_fixup_host_bridge_self(struct pci_bus *pbus); -extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus, - struct pci_pbm_info *pbm, - struct device_node *prom_node); -extern void pci_record_assignments(struct pci_pbm_info *pbm, - struct pci_bus *pbus); -extern void pci_assign_unassigned(struct pci_pbm_info *pbm, - struct pci_bus *pbus); -extern void pci_fixup_irq(struct pci_pbm_info *pbm, - struct pci_bus *pbus); -extern void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, - struct pci_bus *pbus); -extern void pci_setup_busmastering(struct pci_pbm_info *pbm, - struct pci_bus *pbus); +extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); extern void pci_register_legacy_regions(struct resource *io_res, struct resource *mem_res); diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 7aca0f33f88..554daabb381 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -220,7 +220,6 @@ static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx) */ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; iopte_t *iopte; unsigned long flags, order, first_page; @@ -237,8 +236,7 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr return NULL; memset((char *)first_page, 0, PAGE_SIZE << order); - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; + iommu = pdev->dev.archdata.iommu; spin_lock_irqsave(&iommu->lock, flags); iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); @@ -268,14 +266,12 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr /* Free and unmap a consistent DMA translation. */ static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; iopte_t *iopte; unsigned long flags, order, npages; npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; + iommu = pdev->dev.archdata.iommu; iopte = iommu->page_table + ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); @@ -295,7 +291,6 @@ static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, */ static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; iopte_t *base; @@ -304,9 +299,8 @@ static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, u32 bus_addr, ret; unsigned long iopte_protection; - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; - strbuf = &pcp->pbm->stc; + iommu = pdev->dev.archdata.iommu; + strbuf = pdev->dev.archdata.stc; if (unlikely(direction == PCI_DMA_NONE)) goto bad_no_ctx; @@ -416,7 +410,6 @@ do_flush_sync: /* Unmap a single streaming mode DMA translation. */ static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; iopte_t *base; @@ -428,9 +421,8 @@ static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_ return; } - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; - strbuf = &pcp->pbm->stc; + iommu = pdev->dev.archdata.iommu; + strbuf = pdev->dev.archdata.stc; npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; @@ -549,7 +541,6 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, */ static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; unsigned long flags, ctx, npages, iopte_protection; @@ -570,9 +561,8 @@ static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n return 1; } - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; - strbuf = &pcp->pbm->stc; + iommu = pdev->dev.archdata.iommu; + strbuf = pdev->dev.archdata.stc; if (unlikely(direction == PCI_DMA_NONE)) goto bad_no_ctx; @@ -636,7 +626,6 @@ bad_no_ctx: /* Unmap a set of streaming mode DMA translations. */ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; iopte_t *base; @@ -648,9 +637,8 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in WARN_ON(1); } - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; - strbuf = &pcp->pbm->stc; + iommu = pdev->dev.archdata.iommu; + strbuf = pdev->dev.archdata.stc; bus_addr = sglist->dma_address & IO_PAGE_MASK; @@ -696,14 +684,12 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in */ static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; unsigned long flags, ctx, npages; - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; - strbuf = &pcp->pbm->stc; + iommu = pdev->dev.archdata.iommu; + strbuf = pdev->dev.archdata.stc; if (!strbuf->strbuf_enabled) return; @@ -736,15 +722,13 @@ static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_ */ static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; unsigned long flags, ctx, npages, i; u32 bus_addr; - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; - strbuf = &pcp->pbm->stc; + iommu = pdev->dev.archdata.iommu; + strbuf = pdev->dev.archdata.stc; if (!strbuf->strbuf_enabled) return; @@ -809,13 +793,12 @@ static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) int pci_dma_supported(struct pci_dev *pdev, u64 device_mask) { - struct pcidev_cookie *pcp = pdev->sysdata; u64 dma_addr_mask; if (pdev == NULL) { dma_addr_mask = 0xffffffff; } else { - struct pci_iommu *iommu = pcp->pbm->iommu; + struct pci_iommu *iommu = pdev->dev.archdata.iommu; dma_addr_mask = iommu->dma_addr_mask; diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index fda5db223d9..12ea30d30b2 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -905,8 +905,7 @@ static void psycho_resource_adjust(struct pci_dev *pdev, static void psycho_base_address_update(struct pci_dev *pdev, int resource) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; + struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; struct resource *res, *root; u32 reg; int where, size, is_64bit; @@ -968,28 +967,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) static void pbm_scan_bus(struct pci_controller_info *p, struct pci_pbm_info *pbm) { - struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); - - if (!cookie) { - prom_printf("PSYCHO: Critical allocation failure.\n"); - prom_halt(); - } - - /* All we care about is the PBM. */ - cookie->pbm = pbm; - - pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, - p->pci_ops, - pbm); - pci_fixup_host_bridge_self(pbm->pci_bus); - pbm->pci_bus->self->sysdata = cookie; - - pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); - pci_record_assignments(pbm, pbm->pci_bus); - pci_assign_unassigned(pbm, pbm->pci_bus); - pci_fixup_irq(pbm, pbm->pci_bus); - pci_determine_66mhz_disposition(pbm, pbm->pci_bus); - pci_setup_busmastering(pbm, pbm->pci_bus); + pbm->pci_bus = pci_scan_one_pbm(pbm); } static void psycho_scan_bus(struct pci_controller_info *p) diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 94bb681f232..bbf62451750 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -710,8 +710,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p) p->index); ret = IRQ_HANDLED; } - pci_read_config_word(sabre_root_bus->self, - PCI_STATUS, &stat); + pci_bus_read_config_word(sabre_root_bus, 0, + PCI_STATUS, &stat); if (stat & (PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_REC_TARGET_ABORT | @@ -719,8 +719,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p) PCI_STATUS_SIG_SYSTEM_ERROR)) { printk("SABRE%d: PCI bus error, PCI_STATUS[%04x]\n", p->index, stat); - pci_write_config_word(sabre_root_bus->self, - PCI_STATUS, 0xffff); + pci_bus_write_config_word(sabre_root_bus, 0, + PCI_STATUS, 0xffff); ret = IRQ_HANDLED; } return ret; @@ -887,8 +887,7 @@ static void sabre_resource_adjust(struct pci_dev *pdev, static void sabre_base_address_update(struct pci_dev *pdev, int resource) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; + struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; struct resource *res; unsigned long base; u32 reg; @@ -978,27 +977,11 @@ static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) } } -static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) -{ - struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); - - if (!cookie) { - prom_printf("SABRE: Critical allocation failure.\n"); - prom_halt(); - } - - /* All we care about is the PBM. */ - cookie->pbm = pbm; - - return cookie; -} - static void sabre_scan_bus(struct pci_controller_info *p) { static int once; struct pci_bus *sabre_bus, *pbus; struct pci_pbm_info *pbm; - struct pcidev_cookie *cookie; int sabres_scanned; /* The APB bridge speaks to the Sabre host PCI bridge @@ -1020,13 +1003,9 @@ static void sabre_scan_bus(struct pci_controller_info *p) } once++; - cookie = alloc_bridge_cookie(&p->pbm_A); - - sabre_bus = pci_scan_bus(p->pci_first_busno, - p->pci_ops, - &p->pbm_A); - pci_fixup_host_bridge_self(sabre_bus); - sabre_bus->self->sysdata = cookie; + sabre_bus = pci_scan_one_pbm(&p->pbm_A); + if (!sabre_bus) + return; sabre_root_bus = sabre_bus; @@ -1043,19 +1022,9 @@ static void sabre_scan_bus(struct pci_controller_info *p) } else continue; - cookie = alloc_bridge_cookie(pbm); - pbus->self->sysdata = cookie; - sabres_scanned++; - pbus->sysdata = pbm; pbm->pci_bus = pbus; - pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node); - pci_record_assignments(pbm, pbus); - pci_assign_unassigned(pbm, pbus); - pci_fixup_irq(pbm, pbus); - pci_determine_66mhz_disposition(pbm, pbus); - pci_setup_busmastering(pbm, pbus); } if (!sabres_scanned) { @@ -1063,12 +1032,6 @@ static void sabre_scan_bus(struct pci_controller_info *p) pbm = &p->pbm_A; sabre_bus->sysdata = pbm; pbm->pci_bus = sabre_bus; - pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node); - pci_record_assignments(pbm, sabre_bus); - pci_assign_unassigned(pbm, sabre_bus); - pci_fixup_irq(pbm, sabre_bus); - pci_determine_66mhz_disposition(pbm, sabre_bus); - pci_setup_busmastering(pbm, sabre_bus); } sabre_register_error_handlers(p); diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 66911b126ae..48dea52ac52 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1232,28 +1232,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) static void pbm_scan_bus(struct pci_controller_info *p, struct pci_pbm_info *pbm) { - struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); - - if (!cookie) { - prom_printf("%s: Critical allocation failure.\n", pbm->name); - prom_halt(); - } - - /* All we care about is the PBM. */ - cookie->pbm = pbm; - - pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, - p->pci_ops, - pbm); - pci_fixup_host_bridge_self(pbm->pci_bus); - pbm->pci_bus->self->sysdata = cookie; - - pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); - pci_record_assignments(pbm, pbm->pci_bus); - pci_assign_unassigned(pbm, pbm->pci_bus); - pci_fixup_irq(pbm, pbm->pci_bus); - pci_determine_66mhz_disposition(pbm, pbm->pci_bus); - pci_setup_busmastering(pbm, pbm->pci_bus); + pbm->pci_bus = pci_scan_one_pbm(pbm); } static void __schizo_scan_bus(struct pci_controller_info *p, @@ -1297,8 +1276,7 @@ static void tomatillo_scan_bus(struct pci_controller_info *p) static void schizo_base_address_update(struct pci_dev *pdev, int resource) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; + struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; struct resource *res, *root; u32 reg; int where, size, is_64bit; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index bd74c155519..eec7def379d 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -53,8 +53,8 @@ static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long pro /* Interrupts must be disabled. */ static long pci_iommu_batch_flush(struct pci_iommu_batch *p) { - struct pcidev_cookie *pcp = p->pdev->sysdata; - unsigned long devhandle = pcp->pbm->devhandle; + struct pci_pbm_info *pbm = p->pdev->dev.archdata.host_controller; + unsigned long devhandle = pbm->devhandle; unsigned long prot = p->prot; unsigned long entry = p->entry; u64 *pglist = p->pglist; @@ -159,7 +159,6 @@ static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, un static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; unsigned long flags, order, first_page, npages, n; void *ret; @@ -178,8 +177,7 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr memset((char *)first_page, 0, PAGE_SIZE << order); - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; + iommu = pdev->dev.archdata.iommu; spin_lock_irqsave(&iommu->lock, flags); entry = pci_arena_alloc(&iommu->arena, npages); @@ -226,15 +224,15 @@ arena_alloc_fail: static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) { - struct pcidev_cookie *pcp; + struct pci_pbm_info *pbm; struct pci_iommu *iommu; unsigned long flags, order, npages, entry; u32 devhandle; npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; - devhandle = pcp->pbm->devhandle; + iommu = pdev->dev.archdata.iommu; + pbm = pdev->dev.archdata.host_controller; + devhandle = pbm->devhandle; entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); spin_lock_irqsave(&iommu->lock, flags); @@ -259,7 +257,6 @@ static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; unsigned long flags, npages, oaddr; unsigned long i, base_paddr; @@ -267,8 +264,7 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, unsigned long prot; long entry; - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; + iommu = pdev->dev.archdata.iommu; if (unlikely(direction == PCI_DMA_NONE)) goto bad; @@ -324,7 +320,7 @@ iommu_map_fail: static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct pcidev_cookie *pcp; + struct pci_pbm_info *pbm; struct pci_iommu *iommu; unsigned long flags, npages; long entry; @@ -336,9 +332,9 @@ static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_ return; } - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; - devhandle = pcp->pbm->devhandle; + iommu = pdev->dev.archdata.iommu; + pbm = pdev->dev.archdata.host_controller; + devhandle = pbm->devhandle; npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; @@ -460,7 +456,6 @@ iommu_map_failed: static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pcidev_cookie *pcp; struct pci_iommu *iommu; unsigned long flags, npages, prot; u32 dma_base; @@ -480,8 +475,7 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n return 1; } - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; + iommu = pdev->dev.archdata.iommu; if (unlikely(direction == PCI_DMA_NONE)) goto bad; @@ -537,7 +531,7 @@ iommu_map_failed: static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pcidev_cookie *pcp; + struct pci_pbm_info *pbm; struct pci_iommu *iommu; unsigned long flags, i, npages; long entry; @@ -548,9 +542,9 @@ static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in WARN_ON(1); } - pcp = pdev->sysdata; - iommu = pcp->pbm->iommu; - devhandle = pcp->pbm->devhandle; + iommu = pdev->dev.archdata.iommu; + pbm = pdev->dev.archdata.host_controller; + devhandle = pbm->devhandle; bus_addr = sglist->dma_address & IO_PAGE_MASK; @@ -600,132 +594,12 @@ struct pci_iommu_ops pci_sun4v_iommu_ops = { .dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu, }; -/* SUN4V PCI configuration space accessors. */ - -struct pdev_entry { - struct pdev_entry *next; - u32 devhandle; - unsigned int bus; - unsigned int device; - unsigned int func; -}; - -#define PDEV_HTAB_SIZE 16 -#define PDEV_HTAB_MASK (PDEV_HTAB_SIZE - 1) -static struct pdev_entry *pdev_htab[PDEV_HTAB_SIZE]; - -static inline unsigned int pdev_hashfn(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) -{ - unsigned int val; - - val = (devhandle ^ (devhandle >> 4)); - val ^= bus; - val ^= device; - val ^= func; - - return val & PDEV_HTAB_MASK; -} - -static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) -{ - struct pdev_entry *p = kmalloc(sizeof(*p), GFP_KERNEL); - struct pdev_entry **slot; - - if (!p) - return -ENOMEM; - - slot = &pdev_htab[pdev_hashfn(devhandle, bus, device, func)]; - p->next = *slot; - *slot = p; - - p->devhandle = devhandle; - p->bus = bus; - p->device = device; - p->func = func; - - return 0; -} - -/* Recursively descend into the OBP device tree, rooted at toplevel_node, - * looking for a PCI device matching bus and devfn. - */ -static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn) -{ - toplevel_node = toplevel_node->child; - - while (toplevel_node != NULL) { - struct linux_prom_pci_registers *regs; - struct property *prop; - int ret; - - ret = obp_find(toplevel_node, bus, devfn); - if (ret != 0) - return ret; - - prop = of_find_property(toplevel_node, "reg", NULL); - if (!prop) - goto next_sibling; - - regs = prop->value; - if (((regs->phys_hi >> 16) & 0xff) == bus && - ((regs->phys_hi >> 8) & 0xff) == devfn) - break; - - next_sibling: - toplevel_node = toplevel_node->sibling; - } - - return toplevel_node != NULL; -} - -static int pdev_htab_populate(struct pci_pbm_info *pbm) -{ - u32 devhandle = pbm->devhandle; - unsigned int bus; - - for (bus = pbm->pci_first_busno; bus <= pbm->pci_last_busno; bus++) { - unsigned int devfn; - - for (devfn = 0; devfn < 256; devfn++) { - unsigned int device = PCI_SLOT(devfn); - unsigned int func = PCI_FUNC(devfn); - - if (obp_find(pbm->prom_node, bus, devfn)) { - int err = pdev_htab_add(devhandle, bus, - device, func); - if (err) - return err; - } - } - } - - return 0; -} - -static struct pdev_entry *pdev_find(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) -{ - struct pdev_entry *p; - - p = pdev_htab[pdev_hashfn(devhandle, bus, device, func)]; - while (p) { - if (p->devhandle == devhandle && - p->bus == bus && - p->device == device && - p->func == func) - break; - - p = p->next; - } - - return p; -} - static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func) { if (bus < pbm->pci_first_busno || bus > pbm->pci_last_busno) return 1; - return pdev_find(pbm->devhandle, bus, device, func) == NULL; + return 0; } static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, @@ -800,27 +674,7 @@ static struct pci_ops pci_sun4v_ops = { static void pbm_scan_bus(struct pci_controller_info *p, struct pci_pbm_info *pbm) { - struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); - - if (!cookie) { - prom_printf("%s: Critical allocation failure.\n", pbm->name); - prom_halt(); - } - - /* All we care about is the PBM. */ - cookie->pbm = pbm; - - pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm); -#if 0 - pci_fixup_host_bridge_self(pbm->pci_bus); - pbm->pci_bus->self->sysdata = cookie; -#endif - pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); - pci_record_assignments(pbm, pbm->pci_bus); - pci_assign_unassigned(pbm, pbm->pci_bus); - pci_fixup_irq(pbm, pbm->pci_bus); - pci_determine_66mhz_disposition(pbm, pbm->pci_bus); - pci_setup_busmastering(pbm, pbm->pci_bus); + pbm->pci_bus = pci_scan_one_pbm(pbm); } static void pci_sun4v_scan_bus(struct pci_controller_info *p) @@ -846,8 +700,7 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p) static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; + struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; struct resource *res, *root; u32 reg; int where, size, is_64bit; @@ -1410,8 +1263,7 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p, struct pci_dev *pdev, struct msi_desc *entry) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; + struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; unsigned long devino, msiqid; struct msi_msg msg; int msi_num, err; @@ -1455,7 +1307,7 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p, if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID)) goto out_err; - pcp->msi_num = msi_num; + pdev->dev.archdata.msi_num = msi_num; if (entry->msi_attrib.is_64) { msg.address_hi = pbm->msi64_start >> 32; @@ -1484,12 +1336,11 @@ out_err: static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq, struct pci_dev *pdev) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; + struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; unsigned long msiqid, err; unsigned int msi_num; - msi_num = pcp->msi_num; + msi_num = pdev->dev.archdata.msi_num; err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid); if (err) { printk(KERN_ERR "%s: getmsiq gives error %lu\n", @@ -1559,8 +1410,6 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pci_sun4v_get_bus_range(pbm); pci_sun4v_iommu_init(pbm); pci_sun4v_msi_init(pbm); - - pdev_htab_populate(pbm); } void sun4v_pci_init(struct device_node *dp, char *model_name) diff --git a/include/asm-sparc64/device.h b/include/asm-sparc64/device.h index d8f9872b0e2..d5a4559b955 100644 --- a/include/asm-sparc64/device.h +++ b/include/asm-sparc64/device.h @@ -3,5 +3,21 @@ * * This file is released under the GPLv2 */ -#include +#ifndef _ASM_SPARC64_DEVICE_H +#define _ASM_SPARC64_DEVICE_H +struct device_node; +struct of_device; + +struct dev_archdata { + void *iommu; + void *stc; + void *host_controller; + + struct device_node *prom_node; + struct of_device *op; + + unsigned int msi_num; +}; + +#endif /* _ASM_SPARC64_DEVICE_H */ diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 7a246d8a182..88974d685a3 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -244,27 +244,4 @@ struct pci_controller_info { unsigned int pci_last_busno; }; -/* PCI devices which are not bridges have this placed in their pci_dev - * sysdata member. This makes OBP aware PCI device drivers easier to - * code. - */ -struct pcidev_cookie { - struct pci_pbm_info *pbm; - struct device_node *prom_node; - struct of_device *op; - struct linux_prom_pci_registers prom_regs[PROMREG_MAX]; - int num_prom_regs; - struct linux_prom_pci_registers prom_assignments[PROMREG_MAX]; - int num_prom_assignments; -#ifdef CONFIG_PCI_MSI - unsigned int msi_num; -#endif -}; - -/* Currently these are the same across all PCI controllers - * we support. Someday they may not be... - */ -#define PCI_IRQ_IGN 0x000007c0 /* Interrupt Group Number */ -#define PCI_IRQ_INO 0x0000003f /* Interrupt Number */ - #endif /* !(__SPARC64_PBM_H) */ -- cgit v1.2.3 From 1e8a8cc52daa95e702303ca3ce67955a4c051d7d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 23:38:38 -0800 Subject: [SPARC64]: Internalize pci_memspace_mask. The only user was bus_dvma_to_mem() which is no longer used by any driver, so kill that, and the export of pci_memspace_mask. The only user now is the PCI mmap support code. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 2 ++ arch/sparc64/kernel/pci_impl.h | 1 + arch/sparc64/kernel/sparc64_ksyms.c | 1 - include/asm-sparc64/io.h | 8 -------- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 246b8009a2b..ec0d12a48c2 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -27,6 +27,8 @@ #include #include +#include "pci_impl.h" + unsigned long pci_memspace_mask = 0xffffffffUL; #ifndef CONFIG_PCI diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index ea8a6bd146a..c4ba702e1fd 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -13,6 +13,7 @@ #include extern struct pci_controller_info *pci_controller_root; +extern unsigned long pci_memspace_mask; extern int pci_num_controllers; diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index beffc82a1e8..d00f51a5683 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -212,7 +212,6 @@ EXPORT_SYMBOL(insl); #ifdef CONFIG_PCI EXPORT_SYMBOL(ebus_chain); EXPORT_SYMBOL(isa_chain); -EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h index 30b912d8e8b..ad595b67984 100644 --- a/include/asm-sparc64/io.h +++ b/include/asm-sparc64/io.h @@ -24,14 +24,6 @@ extern unsigned long kern_base, kern_size; #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define BIO_VMERGE_BOUNDARY 8192 -/* Different PCI controllers we support have their PCI MEM space - * mapped to an either 2GB (Psycho) or 4GB (Sabre) aligned area, - * so need to chop off the top 33 or 32 bits. - */ -extern unsigned long pci_memspace_mask; - -#define bus_dvma_to_mem(__vaddr) ((__vaddr) & pci_memspace_mask) - static __inline__ u8 _inb(unsigned long addr) { u8 ret; -- cgit v1.2.3 From bc606f3c917aa453fca62b76c8e9998b4171f4fa Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 Mar 2007 11:20:37 -0800 Subject: [SPARC64]: Minor cleanups to schizo pci controller driver. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_schizo.c | 110 +++++++++++---------------------------- 1 file changed, 31 insertions(+), 79 deletions(-) diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 48dea52ac52..332cfd9736b 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1229,21 +1229,8 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) pci_config_write8(addr, 64); } -static void pbm_scan_bus(struct pci_controller_info *p, - struct pci_pbm_info *pbm) -{ - pbm->pci_bus = pci_scan_one_pbm(pbm); -} - -static void __schizo_scan_bus(struct pci_controller_info *p, - int chip_type) +static void schizo_scan_bus(struct pci_controller_info *p) { - if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) { - printk("PCI: Only one PCI bus module of controller found.\n"); - printk("PCI: Ignoring entire controller.\n"); - return; - } - pbm_config_busmastering(&p->pbm_B); p->pbm_B.is_66mhz_capable = (of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL) @@ -1252,28 +1239,19 @@ static void __schizo_scan_bus(struct pci_controller_info *p, p->pbm_A.is_66mhz_capable = (of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL) != NULL); - pbm_scan_bus(p, &p->pbm_B); - pbm_scan_bus(p, &p->pbm_A); + + p->pbm_B.pci_bus = pci_scan_one_pbm(&p->pbm_B); + p->pbm_A.pci_bus = pci_scan_one_pbm(&p->pbm_A); /* After the PCI bus scan is complete, we can register * the error interrupt handlers. */ - if (chip_type == PBM_CHIP_TYPE_TOMATILLO) + if (p->pbm_B.chip_type == PBM_CHIP_TYPE_TOMATILLO) tomatillo_register_error_handlers(p); else schizo_register_error_handlers(p); } -static void schizo_scan_bus(struct pci_controller_info *p) -{ - __schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO); -} - -static void tomatillo_scan_bus(struct pci_controller_info *p) -{ - __schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO); -} - static void schizo_base_address_update(struct pci_dev *pdev, int resource) { struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; @@ -1633,7 +1611,6 @@ static void schizo_pbm_init(struct pci_controller_info *p, int chip_type) { struct linux_prom64_registers *regs; - struct property *prop; unsigned int *busrange; struct pci_pbm_info *pbm; const char *chipset_name; @@ -1667,11 +1644,9 @@ static void schizo_pbm_init(struct pci_controller_info *p, * 3) PBM PCI config space * 4) Ichip regs */ - prop = of_find_property(dp, "reg", NULL); - regs = prop->value; + regs = of_get_property(dp, "reg", NULL); is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000); - if (is_pbm_a) pbm = &p->pbm_A; else @@ -1683,14 +1658,8 @@ static void schizo_pbm_init(struct pci_controller_info *p, pbm->pci_first_slot = 1; pbm->chip_type = chip_type; - pbm->chip_version = 0; - prop = of_find_property(dp, "version#", NULL); - if (prop) - pbm->chip_version = *(int *) prop->value; - pbm->chip_revision = 0; - prop = of_find_property(dp, "module-revision#", NULL); - if (prop) - pbm->chip_revision = *(int *) prop->value; + pbm->chip_version = of_getintprop_default(dp, "version#", 0); + pbm->chip_revision = of_getintprop_default(dp, "module-version#", 0); pbm->pbm_regs = regs[0].phys_addr; pbm->controller_regs = regs[1].phys_addr - 0x10000UL; @@ -1701,40 +1670,31 @@ static void schizo_pbm_init(struct pci_controller_info *p, pbm->name = dp->full_name; printk("%s: %s PCI Bus Module ver[%x:%x]\n", - pbm->name, - (chip_type == PBM_CHIP_TYPE_TOMATILLO ? - "TOMATILLO" : "SCHIZO"), + pbm->name, chipset_name, pbm->chip_version, pbm->chip_revision); schizo_pbm_hw_init(pbm); - prop = of_find_property(dp, "ranges", &len); - pbm->pbm_ranges = prop->value; + pbm->pbm_ranges = of_get_property(dp, "ranges", &len); pbm->num_pbm_ranges = (len / sizeof(struct linux_prom_pci_ranges)); schizo_determine_mem_io_space(pbm); pbm_register_toplevel_resources(p, pbm); - prop = of_find_property(dp, "interrupt-map", &len); - if (prop) { - pbm->pbm_intmap = prop->value; + pbm->pbm_intmap = of_get_property(dp, "interrupt-map", &len); + if (pbm->pbm_intmap) { pbm->num_pbm_intmap = (len / sizeof(struct linux_prom_pci_intmap)); - - prop = of_find_property(dp, "interrupt-map-mask", NULL); - pbm->pbm_intmask = prop->value; - } else { - pbm->num_pbm_intmap = 0; + pbm->pbm_intmask = + of_get_property(dp, "interrupt-map-mask", NULL); } - prop = of_find_property(dp, "ino-bitmap", NULL); - ino_bitmap = prop->value; + ino_bitmap = of_get_property(dp, "ino-bitmap", NULL); pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) | ((u64)ino_bitmap[0] << 0UL)); - prop = of_find_property(dp, "bus-range", NULL); - busrange = prop->value; + busrange = of_get_property(dp, "bus-range", NULL); pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; @@ -1756,14 +1716,9 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ { struct pci_controller_info *p; struct pci_iommu *iommu; - struct property *prop; - int is_pbm_a; u32 portid; - portid = 0xff; - prop = of_find_property(dp, "portid", NULL); - if (prop) - portid = *(u32 *) prop->value; + portid = of_getintprop_default(dp, "portid", 0xff); for (p = pci_controller_root; p; p = p->next) { struct pci_pbm_info *pbm; @@ -1776,40 +1731,32 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ &p->pbm_B); if (portid_compare(pbm->portid, portid, chip_type)) { - is_pbm_a = (p->pbm_A.prom_node == NULL); schizo_pbm_init(p, dp, portid, chip_type); return; } } p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); - if (!p) { - prom_printf("SCHIZO: Fatal memory allocation error.\n"); - prom_halt(); - } + if (!p) + goto memfail; iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); - if (!iommu) { - prom_printf("SCHIZO: Fatal memory allocation error.\n"); - prom_halt(); - } + if (!iommu) + goto memfail; + p->pbm_A.iommu = iommu; iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); - if (!iommu) { - prom_printf("SCHIZO: Fatal memory allocation error.\n"); - prom_halt(); - } + if (!iommu) + goto memfail; + p->pbm_B.iommu = iommu; p->next = pci_controller_root; pci_controller_root = p; p->index = pci_num_controllers++; - p->pbms_same_domain = 0; - p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ? - tomatillo_scan_bus : - schizo_scan_bus); + p->scan_bus = schizo_scan_bus; p->base_address_update = schizo_base_address_update; p->resource_adjust = schizo_resource_adjust; p->pci_ops = &schizo_ops; @@ -1818,6 +1765,11 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ pci_memspace_mask = 0x7fffffffUL; schizo_pbm_init(p, dp, portid, chip_type); + return; + +memfail: + prom_printf("SCHIZO: Fatal memory allocation error.\n"); + prom_halt(); } void schizo_init(struct device_node *dp, char *model_name) -- cgit v1.2.3 From a378fd0ee8ea6af5dafd0ab3d634f22b926b5ac4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 Mar 2007 11:46:13 -0800 Subject: [SPARC64]: Fix obppath pci device sysfs creation. Need to traverse recursively down child busses else we only get the file created under devices at the top-level. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index ec0d12a48c2..425e883e7e3 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -585,6 +585,7 @@ static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, N static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) { struct pci_dev *dev; + struct pci_bus *child_bus; int err; list_for_each_entry(dev, &bus->devices, bus_list) { @@ -597,6 +598,8 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) */ err = sysfs_create_file(&dev->dev.kobj, &dev_attr_obppath.attr); } + list_for_each_entry(child_bus, &bus->children, node) + pci_bus_register_of_sysfs(child_bus); } struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm) -- cgit v1.2.3 From 01f94c4a6ced476ce69b895426fc29bfc48c69bd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 4 Mar 2007 12:53:19 -0800 Subject: [SPARC64]: Fix sabre pci controllers with new probing scheme. The SIMBA APB bridge is strange, it is a PCI bridge but it lacks some standard OF properties, in particular it lacks a 'ranges' property. What you have to do is read the IO and MEM range registers in the APB bridge to determine the ranges handled by each bridge. So fill in the bus resources by doing that. Since we now handle this quirk in the generic PCI and OF device probing layers, we can flat out eliminate all of that code from the sabre pci controller driver. In fact we can thus eliminate completely another quirk of the sabre driver. It tried to make the two APB bridges look like PBMs but that makes zero sense now (and it's questionable whether it ever made sense). So now just use pbm_A and probe the whole PCI hierarchy using that as the root. This simplification allows many future cleanups to occur. Also, I've found yet another quirk that needs to be worked around while testing this. You can't use the 'class-code' OF firmware property, especially for IDE controllers. We have to read the value out of PCI config space or else we'll see the value the device was showing before it was programmed into native mode. I'm starting to think it might be wise to just read all of the values out of PCI config space instead of using the OF properties. :-/ Signed-off-by: David S. Miller --- arch/sparc64/kernel/of_device.c | 29 ++++ arch/sparc64/kernel/pci.c | 80 +++++++++- arch/sparc64/kernel/pci_sabre.c | 340 ++++++++-------------------------------- 3 files changed, 165 insertions(+), 284 deletions(-) diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 6b8798141f2..8964eacb004 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -317,6 +317,11 @@ static unsigned int of_bus_default_get_flags(const u32 *addr) static int of_bus_pci_match(struct device_node *np) { if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { + char *model = of_get_property(np, "model", NULL); + + if (model && !strcmp(model, "SUNW,simba")) + return 0; + /* Do not do PCI specific frobbing if the * PCI bridge lacks a ranges property. We * want to pass it through up to the next @@ -332,6 +337,21 @@ static int of_bus_pci_match(struct device_node *np) return 0; } +static int of_bus_simba_match(struct device_node *np) +{ + char *model = of_get_property(np, "model", NULL); + + if (model && !strcmp(model, "SUNW,simba")) + return 1; + return 0; +} + +static int of_bus_simba_map(u32 *addr, const u32 *range, + int na, int ns, int pna) +{ + return 0; +} + static void of_bus_pci_count_cells(struct device_node *np, int *addrc, int *sizec) { @@ -436,6 +456,15 @@ static struct of_bus of_busses[] = { .map = of_bus_pci_map, .get_flags = of_bus_pci_get_flags, }, + /* SIMBA */ + { + .name = "simba", + .addr_prop_name = "assigned-addresses", + .match = of_bus_simba_match, + .count_cells = of_bus_pci_count_cells, + .map = of_bus_simba_map, + .get_flags = of_bus_pci_get_flags, + }, /* SBUS */ { .name = "sbus", diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 425e883e7e3..b63341c2a33 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "pci_impl.h" @@ -372,6 +373,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, struct dev_archdata *sd; struct pci_dev *dev; const char *type; + u32 class; dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); if (!dev) @@ -409,7 +411,15 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); - dev->class = of_getintprop_default(node, "class-code", 0); + + /* dev->class = of_getintprop_default(node, "class-code", 0); */ + /* We can't actually use the firmware value, we have to read what + * is in the register right now. One reason is that in the case + * of IDE interfaces the firmware can sample the value before the + * the IDE interface is programmed into native mode. + */ + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); + dev->class = class >> 8; printk(" class: 0x%x\n", dev->class); @@ -440,6 +450,53 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, return dev; } +static void __init apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p) +{ + u32 idx, first, last; + + first = 8; + last = 0; + for (idx = 0; idx < 8; idx++) { + if ((map & (1 << idx)) != 0) { + if (first > idx) + first = idx; + if (last < idx) + last = idx; + } + } + + *first_p = first; + *last_p = last; +} + +/* Cook up fake bus resources for SUNW,simba PCI bridges which lack + * a proper 'ranges' property. + */ +static void __init apb_fake_ranges(struct pci_dev *dev, + struct pci_bus *bus, + struct pci_pbm_info *pbm) +{ + struct resource *res; + u32 first, last; + u8 map; + + pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map); + apb_calc_first_last(map, &first, &last); + res = bus->resource[0]; + res->start = (first << 21); + res->end = (last << 21) + ((1 << 21) - 1); + res->flags = IORESOURCE_IO; + pbm->parent->resource_adjust(dev, res, &pbm->io_space); + + pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map); + apb_calc_first_last(map, &first, &last); + res = bus->resource[1]; + res->start = (first << 21); + res->end = (last << 21) + ((1 << 21) - 1); + res->flags = IORESOURCE_MEM; + pbm->parent->resource_adjust(dev, res, &pbm->mem_space); +} + static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, struct device_node *node, struct pci_bus *bus); @@ -452,7 +509,7 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, { struct pci_bus *bus; const u32 *busrange, *ranges; - int len, i; + int len, i, simba; struct resource *res; unsigned int flags; u64 size; @@ -467,10 +524,16 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, return; } ranges = of_get_property(node, "ranges", &len); + simba = 0; if (ranges == NULL) { - printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", - node->full_name); - return; + char *model = of_get_property(node, "model", NULL); + if (model && !strcmp(model, "SUNW,simba")) { + simba = 1; + } else { + printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", + node->full_name); + return; + } } bus = pci_add_new_bus(dev->bus, dev, busrange[0]); @@ -484,7 +547,7 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, bus->subordinate = busrange[1]; bus->bridge_ctl = 0; - /* parse ranges property */ + /* parse ranges property, or cook one up by hand for Simba */ /* PCI #address-cells == 3 and #size-cells == 2 always */ res = &dev->resource[PCI_BRIDGE_RESOURCES]; for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) { @@ -492,6 +555,10 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, bus->resource[i] = res; ++res; } + if (simba) { + apb_fake_ranges(dev, bus, pbm); + goto simba_cont; + } i = 1; for (; len >= 32; len -= 32, ranges += 8) { struct resource *root; @@ -529,6 +596,7 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, */ pbm->parent->resource_adjust(dev, res, root); } +simba_cont: sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), bus->number); printk(" bus name: %s\n", bus->name); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index bbf62451750..f4e346092a5 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -254,9 +254,6 @@ static int __sabre_out_of_range(struct pci_pbm_info *pbm, return 0; return ((pbm->parent == 0) || - ((pbm == &pbm->parent->pbm_B) && - (bus == pbm->pci_first_busno) && - PCI_SLOT(devfn) > 8) || ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8)); @@ -800,12 +797,10 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id) if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) { sabre_check_iommu_error(p, afsr, afar); pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus); - pci_scan_for_target_abort(p, &p->pbm_B, p->pbm_B.pci_bus); } - if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) { + if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus); - pci_scan_for_master_abort(p, &p->pbm_B, p->pbm_B.pci_bus); - } + /* For excessive retries, SABRE/PBM will abort the device * and there is no way to specifically check for excessive * retries in the config space status registers. So what @@ -813,10 +808,8 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id) * abort events. */ - if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) { + if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus); - pci_scan_for_parity_error(p, &p->pbm_B, p->pbm_B.pci_bus); - } return IRQ_HANDLED; } @@ -935,44 +928,33 @@ static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) struct pci_dev *pdev; list_for_each_entry(pdev, &sabre_bus->devices, bus_list) { - if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { - u32 word32; u16 word16; - sabre_read_pci_cfg(pdev->bus, pdev->devfn, - PCI_COMMAND, 2, &word32); - word16 = (u16) word32; + pci_read_config_word(pdev, PCI_COMMAND, &word16); word16 |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; - word32 = (u32) word16; - sabre_write_pci_cfg(pdev->bus, pdev->devfn, - PCI_COMMAND, 2, word32); + pci_write_config_word(pdev, PCI_COMMAND, word16); /* Status register bits are "write 1 to clear". */ - sabre_write_pci_cfg(pdev->bus, pdev->devfn, - PCI_STATUS, 2, 0xffff); - sabre_write_pci_cfg(pdev->bus, pdev->devfn, - PCI_SEC_STATUS, 2, 0xffff); + pci_write_config_word(pdev, PCI_STATUS, 0xffff); + pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff); /* Use a primary/seconday latency timer value * of 64. */ - sabre_write_pci_cfg(pdev->bus, pdev->devfn, - PCI_LATENCY_TIMER, 1, 64); - sabre_write_pci_cfg(pdev->bus, pdev->devfn, - PCI_SEC_LATENCY_TIMER, 1, 64); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); + pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); /* Enable reporting/forwarding of master aborts, * parity, and SERR. */ - sabre_write_pci_cfg(pdev->bus, pdev->devfn, - PCI_BRIDGE_CONTROL, 1, - (PCI_BRIDGE_CTL_PARITY | - PCI_BRIDGE_CTL_SERR | - PCI_BRIDGE_CTL_MASTER_ABORT)); + pci_write_config_byte(pdev, PCI_BRIDGE_CONTROL, + (PCI_BRIDGE_CTL_PARITY | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_MASTER_ABORT)); } } } @@ -980,16 +962,13 @@ static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) static void sabre_scan_bus(struct pci_controller_info *p) { static int once; - struct pci_bus *sabre_bus, *pbus; - struct pci_pbm_info *pbm; - int sabres_scanned; + struct pci_bus *pbus; /* The APB bridge speaks to the Sabre host PCI bridge * at 66Mhz, but the front side of APB runs at 33Mhz * for both segments. */ p->pbm_A.is_66mhz_capable = 0; - p->pbm_B.is_66mhz_capable = 0; /* This driver has not been verified to handle * multiple SABREs yet, so trap this. @@ -1003,36 +982,13 @@ static void sabre_scan_bus(struct pci_controller_info *p) } once++; - sabre_bus = pci_scan_one_pbm(&p->pbm_A); - if (!sabre_bus) + pbus = pci_scan_one_pbm(&p->pbm_A); + if (!pbus) return; - sabre_root_bus = sabre_bus; - - apb_init(p, sabre_bus); - - sabres_scanned = 0; + sabre_root_bus = pbus; - list_for_each_entry(pbus, &sabre_bus->children, node) { - - if (pbus->number == p->pbm_A.pci_first_busno) { - pbm = &p->pbm_A; - } else if (pbus->number == p->pbm_B.pci_first_busno) { - pbm = &p->pbm_B; - } else - continue; - - sabres_scanned++; - pbus->sysdata = pbm; - pbm->pci_bus = pbus; - } - - if (!sabres_scanned) { - /* Hummingbird, no APBs. */ - pbm = &p->pbm_A; - sabre_bus->sysdata = pbm; - pbm->pci_bus = sabre_bus; - } + apb_init(p, pbus); sabre_register_error_handlers(p); } @@ -1089,213 +1045,54 @@ static void sabre_iommu_init(struct pci_controller_info *p, sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control); } -static void pbm_register_toplevel_resources(struct pci_controller_info *p, - struct pci_pbm_info *pbm) +static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end) { - char *name = pbm->name; - unsigned long ibase = p->pbm_A.controller_regs + SABRE_IOSPACE; - unsigned long mbase = p->pbm_A.controller_regs + SABRE_MEMSPACE; - unsigned int devfn; - unsigned long first, last, i; - u8 *addr, map; - - sprintf(name, "SABRE%d PBM%c", - p->index, - (pbm == &p->pbm_A ? 'A' : 'B')); - pbm->io_space.name = pbm->mem_space.name = name; - - devfn = PCI_DEVFN(1, (pbm == &p->pbm_A) ? 0 : 1); - addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_IO_ADDRESS_MAP); - map = 0; - pci_config_read8(addr, &map); - - first = 8; - last = 0; - for (i = 0; i < 8; i++) { - if ((map & (1 << i)) != 0) { - if (first > i) - first = i; - if (last < i) - last = i; - } - } - pbm->io_space.start = ibase + (first << 21UL); - pbm->io_space.end = ibase + (last << 21UL) + ((1 << 21UL) - 1); + struct pci_pbm_info *pbm; + struct resource *rp; + + pbm = &p->pbm_A; + pbm->name = dp->full_name; + printk("%s: SABRE PCI Bus Module\n", pbm->name); + + pbm->chip_type = PBM_CHIP_TYPE_SABRE; + pbm->parent = p; + pbm->prom_node = dp; + pbm->pci_first_slot = 1; + pbm->pci_first_busno = p->pci_first_busno; + pbm->pci_last_busno = p->pci_last_busno; + + pbm->io_space.name = pbm->mem_space.name = pbm->name; + + pbm->io_space.start = p->pbm_A.controller_regs + SABRE_IOSPACE; + pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL; pbm->io_space.flags = IORESOURCE_IO; - addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_MEM_ADDRESS_MAP); - map = 0; - pci_config_read8(addr, &map); - - first = 8; - last = 0; - for (i = 0; i < 8; i++) { - if ((map & (1 << i)) != 0) { - if (first > i) - first = i; - if (last < i) - last = i; - } - } - pbm->mem_space.start = mbase + (first << 29UL); - pbm->mem_space.end = mbase + (last << 29UL) + ((1 << 29UL) - 1); + pbm->mem_space.start = (p->pbm_A.controller_regs + SABRE_MEMSPACE); + pbm->mem_space.end = (pbm->mem_space.start + ((1UL << 32UL) - 1UL)); pbm->mem_space.flags = IORESOURCE_MEM; if (request_resource(&ioport_resource, &pbm->io_space) < 0) { - prom_printf("Cannot register PBM-%c's IO space.\n", - (pbm == &p->pbm_A ? 'A' : 'B')); + prom_printf("Cannot register Sabre's IO space.\n"); prom_halt(); } if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { - prom_printf("Cannot register PBM-%c's MEM space.\n", - (pbm == &p->pbm_A ? 'A' : 'B')); + prom_printf("Cannot register Sabre's MEM space.\n"); prom_halt(); } - /* Register legacy regions if this PBM covers that area. */ - if (pbm->io_space.start == ibase && - pbm->mem_space.start == mbase) - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); -} - -static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end) -{ - struct pci_pbm_info *pbm; - struct device_node *node; - struct property *prop; - u32 *busrange; - int len, simbas_found; - - simbas_found = 0; - node = dp->child; - while (node != NULL) { - if (strcmp(node->name, "pci")) - goto next_pci; - - prop = of_find_property(node, "model", NULL); - if (!prop || strncmp(prop->value, "SUNW,simba", prop->length)) - goto next_pci; - - simbas_found++; - - prop = of_find_property(node, "bus-range", NULL); - busrange = prop->value; - if (busrange[0] == 1) - pbm = &p->pbm_B; - else - pbm = &p->pbm_A; - - pbm->name = node->full_name; - printk("%s: SABRE PCI Bus Module\n", pbm->name); - - pbm->chip_type = PBM_CHIP_TYPE_SABRE; - pbm->parent = p; - pbm->prom_node = node; - pbm->pci_first_slot = 1; - pbm->pci_first_busno = busrange[0]; - pbm->pci_last_busno = busrange[1]; - - prop = of_find_property(node, "ranges", &len); - if (prop) { - pbm->pbm_ranges = prop->value; - pbm->num_pbm_ranges = - (len / sizeof(struct linux_prom_pci_ranges)); - } else { - pbm->num_pbm_ranges = 0; - } - - prop = of_find_property(node, "interrupt-map", &len); - if (prop) { - pbm->pbm_intmap = prop->value; - pbm->num_pbm_intmap = - (len / sizeof(struct linux_prom_pci_intmap)); - - prop = of_find_property(node, "interrupt-map-mask", - NULL); - pbm->pbm_intmask = prop->value; - } else { - pbm->num_pbm_intmap = 0; - } - - pbm_register_toplevel_resources(p, pbm); - - next_pci: - node = node->sibling; - } - if (simbas_found == 0) { - struct resource *rp; - - /* No APBs underneath, probably this is a hummingbird - * system. - */ - pbm = &p->pbm_A; - pbm->parent = p; - pbm->prom_node = dp; - pbm->pci_first_busno = p->pci_first_busno; - pbm->pci_last_busno = p->pci_last_busno; - - prop = of_find_property(dp, "ranges", &len); - if (prop) { - pbm->pbm_ranges = prop->value; - pbm->num_pbm_ranges = - (len / sizeof(struct linux_prom_pci_ranges)); - } else { - pbm->num_pbm_ranges = 0; - } - - prop = of_find_property(dp, "interrupt-map", &len); - if (prop) { - pbm->pbm_intmap = prop->value; - pbm->num_pbm_intmap = - (len / sizeof(struct linux_prom_pci_intmap)); - - prop = of_find_property(dp, "interrupt-map-mask", - NULL); - pbm->pbm_intmask = prop->value; - } else { - pbm->num_pbm_intmap = 0; - } - - pbm->name = dp->full_name; - printk("%s: SABRE PCI Bus Module\n", pbm->name); - - pbm->io_space.name = pbm->mem_space.name = pbm->name; - - /* Hack up top-level resources. */ - pbm->io_space.start = p->pbm_A.controller_regs + SABRE_IOSPACE; - pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL; - pbm->io_space.flags = IORESOURCE_IO; - - pbm->mem_space.start = - (p->pbm_A.controller_regs + SABRE_MEMSPACE); - pbm->mem_space.end = - (pbm->mem_space.start + ((1UL << 32UL) - 1UL)); - pbm->mem_space.flags = IORESOURCE_MEM; - - if (request_resource(&ioport_resource, &pbm->io_space) < 0) { - prom_printf("Cannot register Hummingbird's IO space.\n"); - prom_halt(); - } - if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { - prom_printf("Cannot register Hummingbird's MEM space.\n"); - prom_halt(); - } - - rp = kmalloc(sizeof(*rp), GFP_KERNEL); - if (!rp) { - prom_printf("Cannot allocate IOMMU resource.\n"); - prom_halt(); - } - rp->name = "IOMMU"; - rp->start = pbm->mem_space.start + (unsigned long) dma_start; - rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL; - rp->flags = IORESOURCE_BUSY; - request_resource(&pbm->mem_space, rp); - - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); + rp = kmalloc(sizeof(*rp), GFP_KERNEL); + if (!rp) { + prom_printf("Cannot allocate IOMMU resource.\n"); + prom_halt(); } + rp->name = "IOMMU"; + rp->start = pbm->mem_space.start + (unsigned long) dma_start; + rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL; + rp->flags = IORESOURCE_BUSY; + request_resource(&pbm->mem_space, rp); + + pci_register_legacy_regions(&pbm->io_space, + &pbm->mem_space); } void sabre_init(struct device_node *dp, char *model_name) @@ -1303,7 +1100,6 @@ void sabre_init(struct device_node *dp, char *model_name) struct linux_prom64_registers *pr_regs; struct pci_controller_info *p; struct pci_iommu *iommu; - struct property *prop; int tsbsize; u32 *busrange; u32 *vdma; @@ -1314,13 +1110,9 @@ void sabre_init(struct device_node *dp, char *model_name) if (!strcmp(model_name, "pci108e,a001")) hummingbird_p = 1; else if (!strcmp(model_name, "SUNW,sabre")) { - prop = of_find_property(dp, "compatible", NULL); - if (prop) { - const char *compat = prop->value; - - if (!strcmp(compat, "pci108e,a001")) - hummingbird_p = 1; - } + const char *compat = of_get_property(dp, "compatible", NULL); + if (compat && !strcmp(compat, "pci108e,a001")) + hummingbird_p = 1; if (!hummingbird_p) { struct device_node *dp; @@ -1344,18 +1136,14 @@ void sabre_init(struct device_node *dp, char *model_name) prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n"); prom_halt(); } - p->pbm_A.iommu = p->pbm_B.iommu = iommu; + p->pbm_A.iommu = iommu; - upa_portid = 0xff; - prop = of_find_property(dp, "upa-portid", NULL); - if (prop) - upa_portid = *(u32 *) prop->value; + upa_portid = of_getintprop_default(dp, "upa-portid", 0xff); p->next = pci_controller_root; pci_controller_root = p; p->pbm_A.portid = upa_portid; - p->pbm_B.portid = upa_portid; p->index = pci_num_controllers++; p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; @@ -1367,14 +1155,12 @@ void sabre_init(struct device_node *dp, char *model_name) * Map in SABRE register set and report the presence of this SABRE. */ - prop = of_find_property(dp, "reg", NULL); - pr_regs = prop->value; + pr_regs = of_get_property(dp, "reg", NULL); /* * First REG in property is base of entire SABRE register space. */ p->pbm_A.controller_regs = pr_regs[0].phys_addr; - p->pbm_B.controller_regs = pr_regs[0].phys_addr; /* Clear interrupts */ @@ -1392,11 +1178,10 @@ void sabre_init(struct device_node *dp, char *model_name) SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN)); /* Now map in PCI config space for entire SABRE. */ - p->pbm_A.config_space = p->pbm_B.config_space = + p->pbm_A.config_space = (p->pbm_A.controller_regs + SABRE_CONFIGSPACE); - prop = of_find_property(dp, "virtual-dma", NULL); - vdma = prop->value; + vdma = of_get_property(dp, "virtual-dma", NULL); dma_mask = vdma[0]; switch(vdma[1]) { @@ -1420,8 +1205,7 @@ void sabre_init(struct device_node *dp, char *model_name) sabre_iommu_init(p, tsbsize, vdma[0], dma_mask); - prop = of_find_property(dp, "bus-range", NULL); - busrange = prop->value; + busrange = of_get_property(dp, "bus-range", NULL); p->pci_first_busno = busrange[0]; p->pci_last_busno = busrange[1]; -- cgit v1.2.3 From 9fd8b64761d3fe7e4ef567161be57e4234af5c1c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Mar 2007 21:55:49 -0800 Subject: [SPARC64]: Consolidate PCI mem/io resource determination. It can be done for every PCI configuration using OF properties. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_common.c | 94 +++++++++++++++++++++++++++++++++++++--- arch/sparc64/kernel/pci_impl.h | 8 ++-- arch/sparc64/kernel/pci_psycho.c | 29 ++----------- arch/sparc64/kernel/pci_sabre.c | 38 ++-------------- arch/sparc64/kernel/pci_schizo.c | 81 ++-------------------------------- arch/sparc64/kernel/pci_sun4v.c | 71 +----------------------------- 6 files changed, 103 insertions(+), 218 deletions(-) diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 0d3c95df0d9..4945d700a76 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -1,7 +1,6 @@ -/* $Id: pci_common.c,v 1.29 2002/02/01 00:56:03 davem Exp $ - * pci_common.c: PCI controller common support. +/* pci_common.c: PCI controller common support. * - * Copyright (C) 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -16,8 +15,8 @@ #include "pci_impl.h" -void pci_register_legacy_regions(struct resource *io_res, - struct resource *mem_res) +static void pci_register_legacy_regions(struct resource *io_res, + struct resource *mem_res) { struct resource *p; @@ -53,6 +52,91 @@ void pci_register_legacy_regions(struct resource *io_res, request_resource(mem_res, p); } +static void pci_register_iommu_region(struct pci_pbm_info *pbm) +{ + u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL); + + if (vdma) { + struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL); + + if (!rp) { + prom_printf("Cannot allocate IOMMU resource.\n"); + prom_halt(); + } + rp->name = "IOMMU"; + rp->start = pbm->mem_space.start + (unsigned long) vdma[0]; + rp->end = rp->start + (unsigned long) vdma[1] - 1UL; + rp->flags = IORESOURCE_BUSY; + request_resource(&pbm->mem_space, rp); + } +} + +void pci_determine_mem_io_space(struct pci_pbm_info *pbm) +{ + int i, saw_mem, saw_io; + + saw_mem = saw_io = 0; + for (i = 0; i < pbm->num_pbm_ranges; i++) { + struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; + unsigned long a; + int type; + + type = (pr->child_phys_hi >> 24) & 0x3; + a = (((unsigned long)pr->parent_phys_hi << 32UL) | + ((unsigned long)pr->parent_phys_lo << 0UL)); + + switch (type) { + case 0: + /* PCI config space, 16MB */ + pbm->config_space = a; + break; + + case 1: + /* 16-bit IO space, 16MB */ + pbm->io_space.start = a; + pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); + pbm->io_space.flags = IORESOURCE_IO; + saw_io = 1; + break; + + case 2: + /* 32-bit MEM space, 2GB */ + pbm->mem_space.start = a; + pbm->mem_space.end = a + (0x80000000UL - 1UL); + pbm->mem_space.flags = IORESOURCE_MEM; + saw_mem = 1; + break; + + case 3: + /* XXX 64-bit MEM handling XXX */ + + default: + break; + }; + } + + if (!saw_io || !saw_mem) { + prom_printf("%s: Fatal error, missing %s PBM range.\n", + pbm->name, + (!saw_io ? "IO" : "MEM")); + prom_halt(); + } + + printk("%s: PCI IO[%lx] MEM[%lx]\n", + pbm->name, + pbm->io_space.start, + pbm->mem_space.start); + + pbm->io_space.name = pbm->mem_space.name = pbm->name; + + request_resource(&ioport_resource, &pbm->io_space); + request_resource(&iomem_resource, &pbm->mem_space); + + pci_register_legacy_regions(&pbm->io_space, + &pbm->mem_space); + pci_register_iommu_region(pbm); +} + /* Generic helper routines for PCI error reporting. */ void pci_scan_for_target_abort(struct pci_controller_info *p, struct pci_pbm_info *pbm, diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index c4ba702e1fd..c6714548d82 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -1,7 +1,6 @@ -/* $Id: pci_impl.h,v 1.9 2001/06/13 06:34:30 davem Exp $ - * pci_impl.h: Helper definitions for PCI controller support. +/* pci_impl.h: Helper definitions for PCI controller support. * - * Copyright (C) 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) */ #ifndef PCI_IMPL_H @@ -19,8 +18,7 @@ extern int pci_num_controllers; /* PCI bus scanning and fixup support. */ extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); -extern void pci_register_legacy_regions(struct resource *io_res, - struct resource *mem_res); +extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm); /* Error reporting support. */ extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 12ea30d30b2..c08681b7a44 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1,7 +1,6 @@ -/* $Id: pci_psycho.c,v 1.33 2002/02/01 00:58:33 davem Exp $ - * pci_psycho.c: PSYCHO/U2P specific PCI controller support. +/* pci_psycho.c: PSYCHO/U2P specific PCI controller support. * - * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ @@ -1072,19 +1071,6 @@ static void psycho_controller_hwinit(struct pci_controller_info *p) psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp); } -static void pbm_register_toplevel_resources(struct pci_controller_info *p, - struct pci_pbm_info *pbm) -{ - char *name = pbm->name; - - pbm->io_space.name = pbm->mem_space.name = name; - - request_resource(&ioport_resource, &pbm->io_space); - request_resource(&iomem_resource, &pbm->mem_space); - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); -} - static void psycho_pbm_strbuf_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, int is_pbm_a) @@ -1155,13 +1141,9 @@ static void psycho_pbm_init(struct pci_controller_info *p, if (is_pbm_a) { pbm = &p->pbm_A; pbm->pci_first_slot = 1; - pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_A; - pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_A; } else { pbm = &p->pbm_B; pbm->pci_first_slot = 2; - pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_B; - pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_B; } pbm->chip_type = PBM_CHIP_TYPE_PSYCHO; @@ -1174,17 +1156,12 @@ static void psycho_pbm_init(struct pci_controller_info *p, if (prop) pbm->chip_revision = *(int *) prop->value; - pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE; - pbm->io_space.flags = IORESOURCE_IO; - pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE; - pbm->mem_space.flags = IORESOURCE_MEM; + pci_determine_mem_io_space(pbm); pbm->parent = p; pbm->prom_node = dp; pbm->name = dp->full_name; - pbm_register_toplevel_resources(p, pbm); - printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n", pbm->name, pbm->chip_version, pbm->chip_revision); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index f4e346092a5..2dad171b54e 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1045,10 +1045,9 @@ static void sabre_iommu_init(struct pci_controller_info *p, sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control); } -static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end) +static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp) { struct pci_pbm_info *pbm; - struct resource *rp; pbm = &p->pbm_A; pbm->name = dp->full_name; @@ -1061,38 +1060,7 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp pbm->pci_first_busno = p->pci_first_busno; pbm->pci_last_busno = p->pci_last_busno; - pbm->io_space.name = pbm->mem_space.name = pbm->name; - - pbm->io_space.start = p->pbm_A.controller_regs + SABRE_IOSPACE; - pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL; - pbm->io_space.flags = IORESOURCE_IO; - - pbm->mem_space.start = (p->pbm_A.controller_regs + SABRE_MEMSPACE); - pbm->mem_space.end = (pbm->mem_space.start + ((1UL << 32UL) - 1UL)); - pbm->mem_space.flags = IORESOURCE_MEM; - - if (request_resource(&ioport_resource, &pbm->io_space) < 0) { - prom_printf("Cannot register Sabre's IO space.\n"); - prom_halt(); - } - if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { - prom_printf("Cannot register Sabre's MEM space.\n"); - prom_halt(); - } - - rp = kmalloc(sizeof(*rp), GFP_KERNEL); - if (!rp) { - prom_printf("Cannot allocate IOMMU resource.\n"); - prom_halt(); - } - rp->name = "IOMMU"; - rp->start = pbm->mem_space.start + (unsigned long) dma_start; - rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL; - rp->flags = IORESOURCE_BUSY; - request_resource(&pbm->mem_space, rp); - - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); + pci_determine_mem_io_space(pbm); } void sabre_init(struct device_node *dp, char *model_name) @@ -1212,5 +1180,5 @@ void sabre_init(struct device_node *dp, char *model_name) /* * Look for APB underneath. */ - sabre_pbm_init(p, dp, vdma[0], vdma[0] + vdma[1]); + sabre_pbm_init(p, dp); } diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 332cfd9736b..79ad2688317 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1,7 +1,6 @@ -/* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $ - * pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. +/* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. * - * Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -1304,79 +1303,6 @@ static void schizo_resource_adjust(struct pci_dev *pdev, res->end += root->start; } -/* Use ranges property to determine where PCI MEM, I/O, and Config - * space are for this PCI bus module. - */ -static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm) -{ - int i, saw_cfg, saw_mem, saw_io; - - saw_cfg = saw_mem = saw_io = 0; - for (i = 0; i < pbm->num_pbm_ranges; i++) { - struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; - unsigned long a; - int type; - - type = (pr->child_phys_hi >> 24) & 0x3; - a = (((unsigned long)pr->parent_phys_hi << 32UL) | - ((unsigned long)pr->parent_phys_lo << 0UL)); - - switch (type) { - case 0: - /* PCI config space, 16MB */ - pbm->config_space = a; - saw_cfg = 1; - break; - - case 1: - /* 16-bit IO space, 16MB */ - pbm->io_space.start = a; - pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); - pbm->io_space.flags = IORESOURCE_IO; - saw_io = 1; - break; - - case 2: - /* 32-bit MEM space, 2GB */ - pbm->mem_space.start = a; - pbm->mem_space.end = a + (0x80000000UL - 1UL); - pbm->mem_space.flags = IORESOURCE_MEM; - saw_mem = 1; - break; - - default: - break; - }; - } - - if (!saw_cfg || !saw_io || !saw_mem) { - prom_printf("%s: Fatal error, missing %s PBM range.\n", - pbm->name, - ((!saw_cfg ? - "CFG" : - (!saw_io ? - "IO" : "MEM")))); - prom_halt(); - } - - printk("%s: PCI CFG[%lx] IO[%lx] MEM[%lx]\n", - pbm->name, - pbm->config_space, - pbm->io_space.start, - pbm->mem_space.start); -} - -static void pbm_register_toplevel_resources(struct pci_controller_info *p, - struct pci_pbm_info *pbm) -{ - pbm->io_space.name = pbm->mem_space.name = pbm->name; - - request_resource(&ioport_resource, &pbm->io_space); - request_resource(&iomem_resource, &pbm->mem_space); - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); -} - #define SCHIZO_STRBUF_CONTROL (0x02800UL) #define SCHIZO_STRBUF_FLUSH (0x02808UL) #define SCHIZO_STRBUF_FSYNC (0x02810UL) @@ -1679,8 +1605,7 @@ static void schizo_pbm_init(struct pci_controller_info *p, pbm->num_pbm_ranges = (len / sizeof(struct linux_prom_pci_ranges)); - schizo_determine_mem_io_space(pbm); - pbm_register_toplevel_resources(p, pbm); + pci_determine_mem_io_space(pbm); pbm->pbm_intmap = of_get_property(dp, "interrupt-map", &len); if (pbm->pbm_intmap) { diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index eec7def379d..e1af009617c 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1,6 +1,6 @@ /* pci_sun4v.c: SUN4V specific PCI controller support. * - * Copyright (C) 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -751,72 +751,6 @@ static void pci_sun4v_resource_adjust(struct pci_dev *pdev, res->end += root->start; } -/* Use ranges property to determine where PCI MEM, I/O, and Config - * space are for this PCI bus module. - */ -static void pci_sun4v_determine_mem_io_space(struct pci_pbm_info *pbm) -{ - int i, saw_mem, saw_io; - - saw_mem = saw_io = 0; - for (i = 0; i < pbm->num_pbm_ranges; i++) { - struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; - unsigned long a; - int type; - - type = (pr->child_phys_hi >> 24) & 0x3; - a = (((unsigned long)pr->parent_phys_hi << 32UL) | - ((unsigned long)pr->parent_phys_lo << 0UL)); - - switch (type) { - case 1: - /* 16-bit IO space, 16MB */ - pbm->io_space.start = a; - pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); - pbm->io_space.flags = IORESOURCE_IO; - saw_io = 1; - break; - - case 2: - /* 32-bit MEM space, 2GB */ - pbm->mem_space.start = a; - pbm->mem_space.end = a + (0x80000000UL - 1UL); - pbm->mem_space.flags = IORESOURCE_MEM; - saw_mem = 1; - break; - - case 3: - /* XXX 64-bit MEM handling XXX */ - - default: - break; - }; - } - - if (!saw_io || !saw_mem) { - prom_printf("%s: Fatal error, missing %s PBM range.\n", - pbm->name, - (!saw_io ? "IO" : "MEM")); - prom_halt(); - } - - printk("%s: PCI IO[%lx] MEM[%lx]\n", - pbm->name, - pbm->io_space.start, - pbm->mem_space.start); -} - -static void pbm_register_toplevel_resources(struct pci_controller_info *p, - struct pci_pbm_info *pbm) -{ - pbm->io_space.name = pbm->mem_space.name = pbm->name; - - request_resource(&ioport_resource, &pbm->io_space); - request_resource(&iomem_resource, &pbm->mem_space); - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); -} - static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, struct pci_iommu *iommu) { @@ -1396,8 +1330,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node for (i = 0; i < pbm->num_pbm_ranges; i++) pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff; - pci_sun4v_determine_mem_io_space(pbm); - pbm_register_toplevel_resources(p, pbm); + pci_determine_mem_io_space(pbm); prop = of_find_property(dp, "interrupt-map", &len); pbm->pbm_intmap = prop->value; -- cgit v1.2.3 From 229177c7f38d6a2b1285b42da4b19d76346b4bac Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Mar 2007 22:11:00 -0800 Subject: [SPARC64]: Kill PBM intmap software state. Set but never used. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_psycho.c | 12 ------------ arch/sparc64/kernel/pci_schizo.c | 8 -------- arch/sparc64/kernel/pci_sun4v.c | 8 -------- include/asm-sparc64/pbm.h | 3 --- 4 files changed, 31 deletions(-) diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index c08681b7a44..7b7010a1eb2 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1175,18 +1175,6 @@ static void psycho_pbm_init(struct pci_controller_info *p, pbm->num_pbm_ranges = 0; } - prop = of_find_property(dp, "interrupt-map", &len); - if (prop) { - pbm->pbm_intmap = prop->value; - pbm->num_pbm_intmap = - (len / sizeof(struct linux_prom_pci_intmap)); - - prop = of_find_property(dp, "interrupt-map-mask", NULL); - pbm->pbm_intmask = prop->value; - } else { - pbm->num_pbm_intmap = 0; - } - prop = of_find_property(dp, "bus-range", NULL); busrange = prop->value; pbm->pci_first_busno = busrange[0]; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 79ad2688317..81daf903bdf 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1607,14 +1607,6 @@ static void schizo_pbm_init(struct pci_controller_info *p, pci_determine_mem_io_space(pbm); - pbm->pbm_intmap = of_get_property(dp, "interrupt-map", &len); - if (pbm->pbm_intmap) { - pbm->num_pbm_intmap = - (len / sizeof(struct linux_prom_pci_intmap)); - pbm->pbm_intmask = - of_get_property(dp, "interrupt-map-mask", NULL); - } - ino_bitmap = of_get_property(dp, "ino-bitmap", NULL); pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) | ((u64)ino_bitmap[0] << 0UL)); diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index e1af009617c..7bee6b19272 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1332,14 +1332,6 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pci_determine_mem_io_space(pbm); - prop = of_find_property(dp, "interrupt-map", &len); - pbm->pbm_intmap = prop->value; - pbm->num_pbm_intmap = - (len / sizeof(struct linux_prom_pci_intmap)); - - prop = of_find_property(dp, "interrupt-map-mask", NULL); - pbm->pbm_intmask = prop->value; - pci_sun4v_get_bus_range(pbm); pci_sun4v_iommu_init(pbm); pci_sun4v_msi_init(pbm); diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 88974d685a3..f31de45f487 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -162,9 +162,6 @@ struct pci_pbm_info { struct device_node *prom_node; struct linux_prom_pci_ranges *pbm_ranges; int num_pbm_ranges; - struct linux_prom_pci_intmap *pbm_intmap; - int num_pbm_intmap; - struct linux_prom_pci_intmask *pbm_intmask; u64 ino_bitmap; /* PBM I/O and Memory space resources. */ -- cgit v1.2.3 From 3487a1f9e719d36c9b2d4d492994b2dd815a58b7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Mar 2007 22:28:17 -0800 Subject: [SPARC64]: Kill PBM ranges software state. It is only used in one spot and we can just fetch the OF property right there. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_common.c | 19 +++++++++++++++---- arch/sparc64/kernel/pci_psycho.c | 10 ---------- arch/sparc64/kernel/pci_schizo.c | 5 ----- arch/sparc64/kernel/pci_sun4v.c | 13 ------------- include/asm-sparc64/pbm.h | 2 -- 5 files changed, 15 insertions(+), 34 deletions(-) diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 4945d700a76..6b5c8e7a3eb 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -73,17 +73,28 @@ static void pci_register_iommu_region(struct pci_pbm_info *pbm) void pci_determine_mem_io_space(struct pci_pbm_info *pbm) { + struct linux_prom_pci_ranges *pbm_ranges; int i, saw_mem, saw_io; + int num_pbm_ranges; saw_mem = saw_io = 0; - for (i = 0; i < pbm->num_pbm_ranges; i++) { - struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; + pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i); + num_pbm_ranges = i / sizeof(*pbm_ranges); + + for (i = 0; i < num_pbm_ranges; i++) { + struct linux_prom_pci_ranges *pr = &pbm_ranges[i]; unsigned long a; + u32 parent_phys_hi, parent_phys_lo; int type; + parent_phys_hi = pr->parent_phys_hi; + parent_phys_lo = pr->parent_phys_lo; + if (tlb_type == hypervisor) + parent_phys_hi &= 0x0fffffff; + type = (pr->child_phys_hi >> 24) & 0x3; - a = (((unsigned long)pr->parent_phys_hi << 32UL) | - ((unsigned long)pr->parent_phys_lo << 0UL)); + a = (((unsigned long)parent_phys_hi << 32UL) | + ((unsigned long)parent_phys_lo << 0UL)); switch (type) { case 0: diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 7b7010a1eb2..1717df54948 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1136,7 +1136,6 @@ static void psycho_pbm_init(struct pci_controller_info *p, unsigned int *busrange; struct property *prop; struct pci_pbm_info *pbm; - int len; if (is_pbm_a) { pbm = &p->pbm_A; @@ -1166,15 +1165,6 @@ static void psycho_pbm_init(struct pci_controller_info *p, pbm->name, pbm->chip_version, pbm->chip_revision); - prop = of_find_property(dp, "ranges", &len); - if (prop) { - pbm->pbm_ranges = prop->value; - pbm->num_pbm_ranges = - (len / sizeof(struct linux_prom_pci_ranges)); - } else { - pbm->num_pbm_ranges = 0; - } - prop = of_find_property(dp, "bus-range", NULL); busrange = prop->value; pbm->pci_first_busno = busrange[0]; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 81daf903bdf..dec8dc9499e 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1542,7 +1542,6 @@ static void schizo_pbm_init(struct pci_controller_info *p, const char *chipset_name; u32 *ino_bitmap; int is_pbm_a; - int len; switch (chip_type) { case PBM_CHIP_TYPE_TOMATILLO: @@ -1601,10 +1600,6 @@ static void schizo_pbm_init(struct pci_controller_info *p, schizo_pbm_hw_init(pbm); - pbm->pbm_ranges = of_get_property(dp, "ranges", &len); - pbm->num_pbm_ranges = - (len / sizeof(struct linux_prom_pci_ranges)); - pci_determine_mem_io_space(pbm); ino_bitmap = of_get_property(dp, "ino-bitmap", NULL); diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 7bee6b19272..9b57ba1cb94 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1301,8 +1301,6 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle) { struct pci_pbm_info *pbm; - struct property *prop; - int len, i; if (devhandle & 0x40) pbm = &p->pbm_B; @@ -1319,17 +1317,6 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node printk("%s: SUN4V PCI Bus Module\n", pbm->name); - prop = of_find_property(dp, "ranges", &len); - pbm->pbm_ranges = prop->value; - pbm->num_pbm_ranges = - (len / sizeof(struct linux_prom_pci_ranges)); - - /* Mask out the top 8 bits of the ranges, leaving the real - * physical address. - */ - for (i = 0; i < pbm->num_pbm_ranges; i++) - pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff; - pci_determine_mem_io_space(pbm); pci_sun4v_get_bus_range(pbm); diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index f31de45f487..62929098742 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -160,8 +160,6 @@ struct pci_pbm_info { /* OBP specific information. */ struct device_node *prom_node; - struct linux_prom_pci_ranges *pbm_ranges; - int num_pbm_ranges; u64 ino_bitmap; /* PBM I/O and Memory space resources. */ -- cgit v1.2.3 From 0bae5f81b6f8130f5197e59b0e2ad6820c766b2b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Mar 2007 22:42:19 -0800 Subject: [SPARC64]: Kill pci_controller->resource_adjust() All the implementations can be identical and generic, so no need for controller specific methods. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 17 ++++++++++++----- arch/sparc64/kernel/pci_psycho.c | 9 --------- arch/sparc64/kernel/pci_sabre.c | 17 ----------------- arch/sparc64/kernel/pci_schizo.c | 9 --------- arch/sparc64/kernel/pci_sun4v.c | 9 --------- include/asm-sparc64/pbm.h | 1 - 6 files changed, 12 insertions(+), 50 deletions(-) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index b63341c2a33..6b94d97e56a 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -469,6 +469,13 @@ static void __init apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p) *last_p = last; } +static void __init pci_resource_adjust(struct resource *res, + struct resource *root) +{ + res->start += root->start; + res->end += root->start; +} + /* Cook up fake bus resources for SUNW,simba PCI bridges which lack * a proper 'ranges' property. */ @@ -486,7 +493,7 @@ static void __init apb_fake_ranges(struct pci_dev *dev, res->start = (first << 21); res->end = (last << 21) + ((1 << 21) - 1); res->flags = IORESOURCE_IO; - pbm->parent->resource_adjust(dev, res, &pbm->io_space); + pci_resource_adjust(res, &pbm->io_space); pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map); apb_calc_first_last(map, &first, &last); @@ -494,7 +501,7 @@ static void __init apb_fake_ranges(struct pci_dev *dev, res->start = (first << 21); res->end = (last << 21) + ((1 << 21) - 1); res->flags = IORESOURCE_MEM; - pbm->parent->resource_adjust(dev, res, &pbm->mem_space); + pci_resource_adjust(res, &pbm->mem_space); } static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, @@ -594,7 +601,7 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, * layer routine that can calculate a resource for a given * range property value in a PCI device. */ - pbm->parent->resource_adjust(dev, res, root); + pci_resource_adjust(res, root); } simba_cont: sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), @@ -803,7 +810,7 @@ void pcibios_resource_to_bus(struct pci_dev *pdev, struct pci_bus_region *region else root = &pbm->mem_space; - pbm->parent->resource_adjust(pdev, &zero_res, root); + pci_resource_adjust(&zero_res, root); region->start = res->start - zero_res.start; region->end = res->end - zero_res.start; @@ -824,7 +831,7 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res, else root = &pbm->mem_space; - pbm->parent->resource_adjust(pdev, res, root); + pci_resource_adjust(res, root); } EXPORT_SYMBOL(pcibios_bus_to_resource); diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 1717df54948..c3f212725b0 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -894,14 +894,6 @@ static void psycho_register_error_handlers(struct pci_controller_info *p) } /* PSYCHO boot time probing and initialization. */ -static void psycho_resource_adjust(struct pci_dev *pdev, - struct resource *res, - struct resource *root) -{ - res->start += root->start; - res->end += root->start; -} - static void psycho_base_address_update(struct pci_dev *pdev, int resource) { struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; @@ -1218,7 +1210,6 @@ void psycho_init(struct device_node *dp, char *model_name) p->pbms_same_domain = 0; p->scan_bus = psycho_scan_bus; p->base_address_update = psycho_base_address_update; - p->resource_adjust = psycho_resource_adjust; p->pci_ops = &psycho_ops; prop = of_find_property(dp, "reg", NULL); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 2dad171b54e..64cdce81d86 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -862,22 +862,6 @@ static void sabre_register_error_handlers(struct pci_controller_info *p) sabre_write(base + SABRE_PCICTRL, tmp); } -static void sabre_resource_adjust(struct pci_dev *pdev, - struct resource *res, - struct resource *root) -{ - struct pci_pbm_info *pbm = pdev->bus->sysdata; - unsigned long base; - - if (res->flags & IORESOURCE_IO) - base = pbm->controller_regs + SABRE_IOSPACE; - else - base = pbm->controller_regs + SABRE_MEMSPACE; - - res->start += base; - res->end += base; -} - static void sabre_base_address_update(struct pci_dev *pdev, int resource) { struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; @@ -1116,7 +1100,6 @@ void sabre_init(struct device_node *dp, char *model_name) p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; p->base_address_update = sabre_base_address_update; - p->resource_adjust = sabre_resource_adjust; p->pci_ops = &sabre_ops; /* diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index dec8dc9499e..ba9206eb951 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1295,14 +1295,6 @@ static void schizo_base_address_update(struct pci_dev *pdev, int resource) pci_write_config_dword(pdev, where + 4, 0); } -static void schizo_resource_adjust(struct pci_dev *pdev, - struct resource *res, - struct resource *root) -{ - res->start += root->start; - res->end += root->start; -} - #define SCHIZO_STRBUF_CONTROL (0x02800UL) #define SCHIZO_STRBUF_FLUSH (0x02808UL) #define SCHIZO_STRBUF_FSYNC (0x02810UL) @@ -1670,7 +1662,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ p->index = pci_num_controllers++; p->scan_bus = schizo_scan_bus; p->base_address_update = schizo_base_address_update; - p->resource_adjust = schizo_resource_adjust; p->pci_ops = &schizo_ops; /* Like PSYCHO we have a 2GB aligned area for memory space. */ diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 9b57ba1cb94..ce0417e776a 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -743,14 +743,6 @@ static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) pci_write_config_dword(pdev, where + 4, 0); } -static void pci_sun4v_resource_adjust(struct pci_dev *pdev, - struct resource *res, - struct resource *root) -{ - res->start += root->start; - res->end += root->start; -} - static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, struct pci_iommu *iommu) { @@ -1387,7 +1379,6 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) p->scan_bus = pci_sun4v_scan_bus; p->base_address_update = pci_sun4v_base_address_update; - p->resource_adjust = pci_sun4v_resource_adjust; #ifdef CONFIG_PCI_MSI p->setup_msi_irq = pci_sun4v_setup_msi_irq; p->teardown_msi_irq = pci_sun4v_teardown_msi_irq; diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 62929098742..1bd5b37c6d4 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -225,7 +225,6 @@ struct pci_controller_info { /* Operations which are controller specific. */ void (*scan_bus)(struct pci_controller_info *); void (*base_address_update)(struct pci_dev *, int); - void (*resource_adjust)(struct pci_dev *, struct resource *, struct resource *); #ifdef CONFIG_PCI_MSI int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev, -- cgit v1.2.3 From 8d3aee937596d2ca6676c2c27789751445bf0bc9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Mar 2007 22:46:02 -0800 Subject: [SPARC64]: Kill pci_controller->base_address_update(). Implemented but never actually used. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_psycho.c | 45 --------------------------------------- arch/sparc64/kernel/pci_sabre.c | 46 ---------------------------------------- arch/sparc64/kernel/pci_schizo.c | 45 --------------------------------------- arch/sparc64/kernel/pci_sun4v.c | 46 ---------------------------------------- include/asm-sparc64/pbm.h | 1 - 5 files changed, 183 deletions(-) diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index c3f212725b0..64bd3579f1c 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -894,50 +894,6 @@ static void psycho_register_error_handlers(struct pci_controller_info *p) } /* PSYCHO boot time probing and initialization. */ -static void psycho_base_address_update(struct pci_dev *pdev, int resource) -{ - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; - struct resource *res, *root; - u32 reg; - int where, size, is_64bit; - - res = &pdev->resource[resource]; - if (resource < 6) { - where = PCI_BASE_ADDRESS_0 + (resource * 4); - } else if (resource == PCI_ROM_RESOURCE) { - where = pdev->rom_base_reg; - } else { - /* Somebody might have asked allocation of a non-standard resource */ - return; - } - - is_64bit = 0; - if (res->flags & IORESOURCE_IO) - root = &pbm->io_space; - else { - root = &pbm->mem_space; - if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) - == PCI_BASE_ADDRESS_MEM_TYPE_64) - is_64bit = 1; - } - - size = res->end - res->start; - pci_read_config_dword(pdev, where, ®); - reg = ((reg & size) | - (((u32)(res->start - root->start)) & ~size)); - if (resource == PCI_ROM_RESOURCE) { - reg |= PCI_ROM_ADDRESS_ENABLE; - res->flags |= IORESOURCE_ROM_ENABLE; - } - pci_write_config_dword(pdev, where, reg); - - /* This knows that the upper 32-bits of the address - * must be zero. Our PCI common layer enforces this. - */ - if (is_64bit) - pci_write_config_dword(pdev, where + 4, 0); -} - static void pbm_config_busmastering(struct pci_pbm_info *pbm) { u8 *addr; @@ -1209,7 +1165,6 @@ void psycho_init(struct device_node *dp, char *model_name) p->index = pci_num_controllers++; p->pbms_same_domain = 0; p->scan_bus = psycho_scan_bus; - p->base_address_update = psycho_base_address_update; p->pci_ops = &psycho_ops; prop = of_find_property(dp, "reg", NULL); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 64cdce81d86..f3ec7bdacdc 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -862,51 +862,6 @@ static void sabre_register_error_handlers(struct pci_controller_info *p) sabre_write(base + SABRE_PCICTRL, tmp); } -static void sabre_base_address_update(struct pci_dev *pdev, int resource) -{ - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; - struct resource *res; - unsigned long base; - u32 reg; - int where, size, is_64bit; - - res = &pdev->resource[resource]; - if (resource < 6) { - where = PCI_BASE_ADDRESS_0 + (resource * 4); - } else if (resource == PCI_ROM_RESOURCE) { - where = pdev->rom_base_reg; - } else { - /* Somebody might have asked allocation of a non-standard resource */ - return; - } - - is_64bit = 0; - if (res->flags & IORESOURCE_IO) - base = pbm->controller_regs + SABRE_IOSPACE; - else { - base = pbm->controller_regs + SABRE_MEMSPACE; - if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) - == PCI_BASE_ADDRESS_MEM_TYPE_64) - is_64bit = 1; - } - - size = res->end - res->start; - pci_read_config_dword(pdev, where, ®); - reg = ((reg & size) | - (((u32)(res->start - base)) & ~size)); - if (resource == PCI_ROM_RESOURCE) { - reg |= PCI_ROM_ADDRESS_ENABLE; - res->flags |= IORESOURCE_ROM_ENABLE; - } - pci_write_config_dword(pdev, where, reg); - - /* This knows that the upper 32-bits of the address - * must be zero. Our PCI common layer enforces this. - */ - if (is_64bit) - pci_write_config_dword(pdev, where + 4, 0); -} - static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) { struct pci_dev *pdev; @@ -1099,7 +1054,6 @@ void sabre_init(struct device_node *dp, char *model_name) p->index = pci_num_controllers++; p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; - p->base_address_update = sabre_base_address_update; p->pci_ops = &sabre_ops; /* diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index ba9206eb951..99912db4e7e 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1251,50 +1251,6 @@ static void schizo_scan_bus(struct pci_controller_info *p) schizo_register_error_handlers(p); } -static void schizo_base_address_update(struct pci_dev *pdev, int resource) -{ - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; - struct resource *res, *root; - u32 reg; - int where, size, is_64bit; - - res = &pdev->resource[resource]; - if (resource < 6) { - where = PCI_BASE_ADDRESS_0 + (resource * 4); - } else if (resource == PCI_ROM_RESOURCE) { - where = pdev->rom_base_reg; - } else { - /* Somebody might have asked allocation of a non-standard resource */ - return; - } - - is_64bit = 0; - if (res->flags & IORESOURCE_IO) - root = &pbm->io_space; - else { - root = &pbm->mem_space; - if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) - == PCI_BASE_ADDRESS_MEM_TYPE_64) - is_64bit = 1; - } - - size = res->end - res->start; - pci_read_config_dword(pdev, where, ®); - reg = ((reg & size) | - (((u32)(res->start - root->start)) & ~size)); - if (resource == PCI_ROM_RESOURCE) { - reg |= PCI_ROM_ADDRESS_ENABLE; - res->flags |= IORESOURCE_ROM_ENABLE; - } - pci_write_config_dword(pdev, where, reg); - - /* This knows that the upper 32-bits of the address - * must be zero. Our PCI common layer enforces this. - */ - if (is_64bit) - pci_write_config_dword(pdev, where + 4, 0); -} - #define SCHIZO_STRBUF_CONTROL (0x02800UL) #define SCHIZO_STRBUF_FLUSH (0x02808UL) #define SCHIZO_STRBUF_FSYNC (0x02810UL) @@ -1661,7 +1617,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ p->index = pci_num_controllers++; p->scan_bus = schizo_scan_bus; - p->base_address_update = schizo_base_address_update; p->pci_ops = &schizo_ops; /* Like PSYCHO we have a 2GB aligned area for memory space. */ diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index ce0417e776a..f9cd9f620d4 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -698,51 +698,6 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p) /* XXX register error interrupt handlers XXX */ } -static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) -{ - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; - struct resource *res, *root; - u32 reg; - int where, size, is_64bit; - - res = &pdev->resource[resource]; - if (resource < 6) { - where = PCI_BASE_ADDRESS_0 + (resource * 4); - } else if (resource == PCI_ROM_RESOURCE) { - where = pdev->rom_base_reg; - } else { - /* Somebody might have asked allocation of a non-standard resource */ - return; - } - - /* XXX 64-bit MEM handling is not %100 correct... XXX */ - is_64bit = 0; - if (res->flags & IORESOURCE_IO) - root = &pbm->io_space; - else { - root = &pbm->mem_space; - if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) - == PCI_BASE_ADDRESS_MEM_TYPE_64) - is_64bit = 1; - } - - size = res->end - res->start; - pci_read_config_dword(pdev, where, ®); - reg = ((reg & size) | - (((u32)(res->start - root->start)) & ~size)); - if (resource == PCI_ROM_RESOURCE) { - reg |= PCI_ROM_ADDRESS_ENABLE; - res->flags |= IORESOURCE_ROM_ENABLE; - } - pci_write_config_dword(pdev, where, reg); - - /* This knows that the upper 32-bits of the address - * must be zero. Our PCI common layer enforces this. - */ - if (is_64bit) - pci_write_config_dword(pdev, where + 4, 0); -} - static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, struct pci_iommu *iommu) { @@ -1378,7 +1333,6 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) p->pbms_same_domain = 0; p->scan_bus = pci_sun4v_scan_bus; - p->base_address_update = pci_sun4v_base_address_update; #ifdef CONFIG_PCI_MSI p->setup_msi_irq = pci_sun4v_setup_msi_irq; p->teardown_msi_irq = pci_sun4v_teardown_msi_irq; diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 1bd5b37c6d4..07f58adb591 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -224,7 +224,6 @@ struct pci_controller_info { /* Operations which are controller specific. */ void (*scan_bus)(struct pci_controller_info *); - void (*base_address_update)(struct pci_dev *, int); #ifdef CONFIG_PCI_MSI int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev, -- cgit v1.2.3 From 3875c5c02d7112aa85f815d65d8add2e39ae9e34 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Mar 2007 22:52:11 -0800 Subject: [SPARC64]: Kill pci_controller->pbms_same_domain We don't do the "Simba APB is a PBM" bogosity for Sabre controllers any longer, so this pbms_same_domain thing is no longer necessary. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 75 +++++++--------------------------------- arch/sparc64/kernel/pci_psycho.c | 1 - arch/sparc64/kernel/pci_sabre.c | 1 - arch/sparc64/kernel/pci_sun4v.c | 1 - include/asm-sparc64/pbm.h | 3 -- 5 files changed, 12 insertions(+), 69 deletions(-) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 6b94d97e56a..a7809a00324 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -857,43 +857,12 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc unsigned long space_size, user_offset, user_size; p = pbm->parent; - if (p->pbms_same_domain) { - unsigned long lowest, highest; - - lowest = ~0UL; highest = 0UL; - if (mmap_state == pci_mmap_io) { - if (p->pbm_A.io_space.flags) { - lowest = p->pbm_A.io_space.start; - highest = p->pbm_A.io_space.end + 1; - } - if (p->pbm_B.io_space.flags) { - if (lowest > p->pbm_B.io_space.start) - lowest = p->pbm_B.io_space.start; - if (highest < p->pbm_B.io_space.end + 1) - highest = p->pbm_B.io_space.end + 1; - } - space_size = highest - lowest; - } else { - if (p->pbm_A.mem_space.flags) { - lowest = p->pbm_A.mem_space.start; - highest = p->pbm_A.mem_space.end + 1; - } - if (p->pbm_B.mem_space.flags) { - if (lowest > p->pbm_B.mem_space.start) - lowest = p->pbm_B.mem_space.start; - if (highest < p->pbm_B.mem_space.end + 1) - highest = p->pbm_B.mem_space.end + 1; - } - space_size = highest - lowest; - } + if (mmap_state == pci_mmap_io) { + space_size = (pbm->io_space.end - + pbm->io_space.start) + 1; } else { - if (mmap_state == pci_mmap_io) { - space_size = (pbm->io_space.end - - pbm->io_space.start) + 1; - } else { - space_size = (pbm->mem_space.end - - pbm->mem_space.start) + 1; - } + space_size = (pbm->mem_space.end - + pbm->mem_space.start) + 1; } /* Make sure the request is in range. */ @@ -904,31 +873,12 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc (user_offset + user_size) > space_size) return -EINVAL; - if (p->pbms_same_domain) { - unsigned long lowest = ~0UL; - - if (mmap_state == pci_mmap_io) { - if (p->pbm_A.io_space.flags) - lowest = p->pbm_A.io_space.start; - if (p->pbm_B.io_space.flags && - lowest > p->pbm_B.io_space.start) - lowest = p->pbm_B.io_space.start; - } else { - if (p->pbm_A.mem_space.flags) - lowest = p->pbm_A.mem_space.start; - if (p->pbm_B.mem_space.flags && - lowest > p->pbm_B.mem_space.start) - lowest = p->pbm_B.mem_space.start; - } - vma->vm_pgoff = (lowest + user_offset) >> PAGE_SHIFT; + if (mmap_state == pci_mmap_io) { + vma->vm_pgoff = (pbm->io_space.start + + user_offset) >> PAGE_SHIFT; } else { - if (mmap_state == pci_mmap_io) { - vma->vm_pgoff = (pbm->io_space.start + - user_offset) >> PAGE_SHIFT; - } else { - vma->vm_pgoff = (pbm->mem_space.start + - user_offset) >> PAGE_SHIFT; - } + vma->vm_pgoff = (pbm->mem_space.start + + user_offset) >> PAGE_SHIFT; } return 0; @@ -1062,9 +1012,8 @@ int pci_domain_nr(struct pci_bus *pbus) struct pci_controller_info *p = pbm->parent; ret = p->index; - if (p->pbms_same_domain == 0) - ret = ((ret << 1) + - ((pbm == &pbm->parent->pbm_B) ? 1 : 0)); + ret = ((ret << 1) + + ((pbm == &pbm->parent->pbm_B) ? 1 : 0)); } return ret; diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 64bd3579f1c..0ab2aa0261c 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1163,7 +1163,6 @@ void psycho_init(struct device_node *dp, char *model_name) p->pbm_A.portid = upa_portid; p->pbm_B.portid = upa_portid; p->index = pci_num_controllers++; - p->pbms_same_domain = 0; p->scan_bus = psycho_scan_bus; p->pci_ops = &psycho_ops; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index f3ec7bdacdc..cef81c88548 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1052,7 +1052,6 @@ void sabre_init(struct device_node *dp, char *model_name) p->pbm_A.portid = upa_portid; p->index = pci_num_controllers++; - p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; p->pci_ops = &sabre_ops; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index f9cd9f620d4..b63ef26abf0 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1330,7 +1330,6 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) pci_controller_root = p; p->index = pci_num_controllers++; - p->pbms_same_domain = 0; p->scan_bus = pci_sun4v_scan_bus; #ifdef CONFIG_PCI_MSI diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 07f58adb591..43b07b9b42c 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -215,9 +215,6 @@ struct pci_controller_info { */ int index; - /* Do the PBMs both exist in the same PCI domain? */ - int pbms_same_domain; - /* The PCI bus modules controlled by us. */ struct pci_pbm_info pbm_A; struct pci_pbm_info pbm_B; -- cgit v1.2.3 From 0bba2dd823fd995ed805ae5cbd5a1c1381257a12 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Mar 2007 23:06:39 -0800 Subject: [SPARC64]: Kill pbm->pci_first_slot. Set but never used. Signed-off-by: David S. Miller --- arch/sparc64/kernel/of_device.c | 6 ------ arch/sparc64/kernel/pci_psycho.c | 7 ++----- arch/sparc64/kernel/pci_sabre.c | 1 - arch/sparc64/kernel/pci_schizo.c | 1 - arch/sparc64/kernel/pci_sun4v.c | 1 - include/asm-sparc64/pbm.h | 3 --- 6 files changed, 2 insertions(+), 17 deletions(-) diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 8964eacb004..f18eec6ad69 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -759,12 +759,6 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp, * D: 2-bit slot number, derived from PCI device number as * (dev - 1) for bus A, or (dev - 2) for bus B * L: 2-bit line number - * - * Actually, more "portable" way to calculate the funky - * slot number is to subtract pbm->pci_first_slot from the - * device number, and that's exactly what the pre-OF - * sparc64 code did, but we're building this stuff generically - * using the OBP tree, not in the PCI controller layer. */ if (bus & 0x80) { /* PBM-A */ diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 0ab2aa0261c..2e5d40a26db 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1085,13 +1085,10 @@ static void psycho_pbm_init(struct pci_controller_info *p, struct property *prop; struct pci_pbm_info *pbm; - if (is_pbm_a) { + if (is_pbm_a) pbm = &p->pbm_A; - pbm->pci_first_slot = 1; - } else { + else pbm = &p->pbm_B; - pbm->pci_first_slot = 2; - } pbm->chip_type = PBM_CHIP_TYPE_PSYCHO; pbm->chip_version = 0; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index cef81c88548..1bd7fc7c05e 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -995,7 +995,6 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp pbm->chip_type = PBM_CHIP_TYPE_SABRE; pbm->parent = p; pbm->prom_node = dp; - pbm->pci_first_slot = 1; pbm->pci_first_busno = p->pci_first_busno; pbm->pci_last_busno = p->pci_last_busno; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 99912db4e7e..f1f105af8d3 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1528,7 +1528,6 @@ static void schizo_pbm_init(struct pci_controller_info *p, pbm->portid = portid; pbm->parent = p; pbm->prom_node = dp; - pbm->pci_first_slot = 1; pbm->chip_type = chip_type; pbm->chip_version = of_getintprop_default(dp, "version#", 0); diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index b63ef26abf0..c6feae6e969 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1256,7 +1256,6 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pbm->parent = p; pbm->prom_node = dp; - pbm->pci_first_slot = 1; pbm->devhandle = devhandle; diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 43b07b9b42c..3a811c2cd3c 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -197,9 +197,6 @@ struct pci_pbm_info { /* IOMMU state, potentially shared by both PBM segments. */ struct pci_iommu *iommu; - /* PCI slot mapping. */ - unsigned int pci_first_slot; - /* Now things for the actual PCI bus probes. */ unsigned int pci_first_busno; unsigned int pci_last_busno; -- cgit v1.2.3 From c6e87566ea080bbbe926c0e429fed48e6f680d93 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 9 Mar 2007 16:58:43 -0800 Subject: [SPARC64]: Const'ify pci_iommu_ops. Based upon a similar patch for x86_64 written by Stephen Hemminger. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 4 ++-- arch/sparc64/kernel/pci_iommu.c | 2 +- arch/sparc64/kernel/pci_sun4v.c | 2 +- include/asm-sparc64/pci.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index a7809a00324..914a216da33 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -282,10 +282,10 @@ int __init pcic_present(void) return pci_controller_scan(pci_is_controller); } -struct pci_iommu_ops *pci_iommu_ops; +const struct pci_iommu_ops *pci_iommu_ops; EXPORT_SYMBOL(pci_iommu_ops); -extern struct pci_iommu_ops pci_sun4u_iommu_ops, +extern const struct pci_iommu_ops pci_sun4u_iommu_ops, pci_sun4v_iommu_ops; /* Find each controller in the system, attach and initialize diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 554daabb381..aefdcc51045 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -759,7 +759,7 @@ static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist spin_unlock_irqrestore(&iommu->lock, flags); } -struct pci_iommu_ops pci_sun4u_iommu_ops = { +const struct pci_iommu_ops pci_sun4u_iommu_ops = { .alloc_consistent = pci_4u_alloc_consistent, .free_consistent = pci_4u_free_consistent, .map_single = pci_4u_map_single, diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index c6feae6e969..a8c12c1e803 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -583,7 +583,7 @@ static void pci_4v_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist /* Nothing to do... */ } -struct pci_iommu_ops pci_sun4v_iommu_ops = { +const struct pci_iommu_ops pci_sun4v_iommu_ops = { .alloc_consistent = pci_4v_alloc_consistent, .free_consistent = pci_4v_free_consistent, .map_single = pci_4v_map_single, diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index b14a725b430..47cea16e1ba 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h @@ -54,7 +54,7 @@ struct pci_iommu_ops { void (*dma_sync_sg_for_cpu)(struct pci_dev *, struct scatterlist *, int, int); }; -extern struct pci_iommu_ops *pci_iommu_ops; +extern const struct pci_iommu_ops *pci_iommu_ops; /* Allocate and map kernel buffer using consistent mode DMA for a device. * hwdev should be valid struct pci_dev pointer for PCI devices. -- cgit v1.2.3 From 97b3cf050b467dda571943ceadff5452bed04549 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 11 Mar 2007 16:42:53 -0700 Subject: [SPARC64]: Add dummy host controller to root of all PCI domains. We fake up a dummy one in all cases because that is the simplest thing to do and it happens to be necessary for hypervisor systems. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 119 +++++++++++++++++++++++++++++---------- arch/sparc64/kernel/pci_impl.h | 9 +++ arch/sparc64/kernel/pci_psycho.c | 7 +++ arch/sparc64/kernel/pci_sabre.c | 12 ++++ arch/sparc64/kernel/pci_schizo.c | 6 ++ arch/sparc64/kernel/pci_sun4v.c | 6 ++ 6 files changed, 129 insertions(+), 30 deletions(-) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 914a216da33..ec5f85b030e 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -368,7 +368,8 @@ static void pci_parse_of_addrs(struct of_device *op, struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, struct device_node *node, - struct pci_bus *bus, int devfn) + struct pci_bus *bus, int devfn, + int host_controller) { struct dev_archdata *sd; struct pci_dev *dev; @@ -400,47 +401,62 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, dev->devfn = devfn; dev->multifunction = 0; /* maybe a lie? */ - dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); - dev->device = of_getintprop_default(node, "device-id", 0xffff); - dev->subsystem_vendor = - of_getintprop_default(node, "subsystem-vendor-id", 0); - dev->subsystem_device = - of_getintprop_default(node, "subsystem-id", 0); - - dev->cfg_size = pci_cfg_space_size(dev); - + if (host_controller) { + dev->vendor = 0x108e; + dev->device = 0x8000; + dev->subsystem_vendor = 0x0000; + dev->subsystem_device = 0x0000; + dev->cfg_size = 256; + } else { + dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); + dev->device = of_getintprop_default(node, "device-id", 0xffff); + dev->subsystem_vendor = + of_getintprop_default(node, "subsystem-vendor-id", 0); + dev->subsystem_device = + of_getintprop_default(node, "subsystem-id", 0); + + dev->cfg_size = pci_cfg_space_size(dev); + } sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); - /* dev->class = of_getintprop_default(node, "class-code", 0); */ - /* We can't actually use the firmware value, we have to read what - * is in the register right now. One reason is that in the case - * of IDE interfaces the firmware can sample the value before the - * the IDE interface is programmed into native mode. - */ - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); - dev->class = class >> 8; - + if (host_controller) { + dev->class = PCI_CLASS_BRIDGE_HOST << 8; + } else { + /* We can't actually use the firmware value, we have + * to read what is in the register right now. One + * reason is that in the case of IDE interfaces the + * firmware can sample the value before the the IDE + * interface is programmed into native mode. + */ + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); + dev->class = class >> 8; + } printk(" class: 0x%x\n", dev->class); dev->current_state = 4; /* unknown power state */ dev->error_state = pci_channel_io_normal; - if (!strcmp(type, "pci") || !strcmp(type, "pciex")) { - /* a PCI-PCI bridge */ + if (host_controller) { dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; dev->rom_base_reg = PCI_ROM_ADDRESS1; - } else if (!strcmp(type, "cardbus")) { - dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; + dev->irq = PCI_IRQ_NONE; } else { - dev->hdr_type = PCI_HEADER_TYPE_NORMAL; - dev->rom_base_reg = PCI_ROM_ADDRESS; + if (!strcmp(type, "pci") || !strcmp(type, "pciex")) { + /* a PCI-PCI bridge */ + dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; + dev->rom_base_reg = PCI_ROM_ADDRESS1; + } else if (!strcmp(type, "cardbus")) { + dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; + } else { + dev->hdr_type = PCI_HEADER_TYPE_NORMAL; + dev->rom_base_reg = PCI_ROM_ADDRESS; - dev->irq = sd->op->irqs[0]; - if (dev->irq == 0xffffffff) - dev->irq = PCI_IRQ_NONE; + dev->irq = sd->op->irqs[0]; + if (dev->irq == 0xffffffff) + dev->irq = PCI_IRQ_NONE; + } } - pci_parse_of_addrs(sd->op, node, dev); printk(" adding to system ...\n"); @@ -632,7 +648,7 @@ static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, devfn = (reg[0] >> 8) & 0xff; /* create a new pci_dev for this device */ - dev = of_create_pci_dev(pbm, child, bus, devfn); + dev = of_create_pci_dev(pbm, child, bus, devfn, 0); if (!dev) continue; printk("PCI: dev header type: %x\n", dev->hdr_type); @@ -677,10 +693,49 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) pci_bus_register_of_sysfs(child_bus); } +int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev, + unsigned int devfn, + int where, int size, + u32 *value) +{ + static u8 fake_pci_config[] = { + 0x8e, 0x10, /* Vendor: 0x108e (Sun) */ + 0x00, 0x80, /* Device: 0x8000 (PBM) */ + 0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */ + 0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */ + 0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */ + 0x00, /* Cacheline: 0x00 */ + 0x40, /* Latency: 0x40 */ + 0x00, /* Header-Type: 0x00 normal */ + }; + + *value = 0; + if (where >= 0 && where < sizeof(fake_pci_config) && + (where + size) >= 0 && + (where + size) < sizeof(fake_pci_config) && + size <= sizeof(u32)) { + while (size--) { + *value <<= 8; + *value |= fake_pci_config[where + size]; + } + } + + return PCIBIOS_SUCCESSFUL; +} + +int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev, + unsigned int devfn, + int where, int size, + u32 value) +{ + return PCIBIOS_SUCCESSFUL; +} + struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm) { struct pci_controller_info *p = pbm->parent; struct device_node *node = pbm->prom_node; + struct pci_dev *host_pdev; struct pci_bus *bus; printk("PCI: Scanning PBM %s\n", node->full_name); @@ -698,6 +753,10 @@ struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm) bus->resource[0] = &pbm->io_space; bus->resource[1] = &pbm->mem_space; + /* Create the dummy host bridge and link it in. */ + host_pdev = of_create_pci_dev(pbm, node, bus, 0x00, 1); + bus->self = host_pdev; + pci_of_scan_bus(pbm, node, bus); pci_bus_add_devices(bus); pci_bus_register_of_sysfs(bus); diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index c6714548d82..1208583fcb8 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -20,6 +20,15 @@ extern int pci_num_controllers; extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm); +extern int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev, + unsigned int devfn, + int where, int size, + u32 *value); +extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev, + unsigned int devfn, + int where, int size, + u32 value); + /* Error reporting support. */ extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 2e5d40a26db..154c03290d5 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -118,6 +118,10 @@ static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, u16 tmp16; u8 tmp8; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, + size, value); + switch (size) { case 1: *value = 0xff; @@ -171,6 +175,9 @@ static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned char bus = bus_dev->number; u32 *addr; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, + size, value); addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 1bd7fc7c05e..a2f129d29c2 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -319,6 +319,12 @@ static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { + struct pci_pbm_info *pbm = bus->sysdata; + + if (bus == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus, devfn, where, + size, value); + if (!bus->number && sabre_out_of_range(devfn)) { switch (size) { case 1: @@ -435,6 +441,12 @@ static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { + struct pci_pbm_info *pbm = bus->sysdata; + + if (bus == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus, devfn, where, + size, value); + if (bus->number) return __sabre_write_pci_cfg(bus, devfn, where, size, value); diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index f1f105af8d3..322cdbf50ef 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -125,6 +125,9 @@ static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, u16 tmp16; u8 tmp8; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, + size, value); switch (size) { case 1: *value = 0xff; @@ -178,6 +181,9 @@ static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned char bus = bus_dev->number; u32 *addr; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, + size, value); addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index a8c12c1e803..52bd4563492 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -612,6 +612,9 @@ static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned int func = PCI_FUNC(devfn); unsigned long ret; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, + size, value); if (pci_sun4v_out_of_range(pbm, bus, device, func)) { ret = ~0UL; } else { @@ -650,6 +653,9 @@ static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned int func = PCI_FUNC(devfn); unsigned long ret; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, + size, value); if (pci_sun4v_out_of_range(pbm, bus, device, func)) { /* Do nothing. */ } else { -- cgit v1.2.3 From 28f57e774d91ce01e03ff65caa2313bc8786b66f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 12 Mar 2007 19:40:26 -0700 Subject: [SPARC64]: Force dummy host controller onto bus zero. This helps deal with the invisible bridge that sits between the host controller and the top-most visisble PCI devices on hypervisor systems. For example, on T1000 the bus-range property says 2 --> 4 and so there is a PCI express bridge at bus 2, devfn 0, etc. So if we don't force the dummy host controller to bus zero, we'll try to create two devices with the same domain/bus/devfn triplet. Also, add some more log diagnostics to make debugging stuff like this easyer. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index ec5f85b030e..8a7c699bb10 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -392,7 +392,8 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, if (type == NULL) type = ""; - printk(" create device, devfn: %x, type: %s\n", devfn, type); + printk(" create device, devfn: %x, type: %s hostcontroller(%d)\n", + devfn, type, host_controller); dev->bus = bus; dev->sysdata = node; @@ -407,6 +408,9 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, dev->subsystem_vendor = 0x0000; dev->subsystem_device = 0x0000; dev->cfg_size = 256; + dev->class = PCI_CLASS_BRIDGE_HOST << 8; + sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), + 0x00, PCI_SLOT(devfn), PCI_FUNC(devfn)); } else { dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); dev->device = of_getintprop_default(node, "device-id", 0xffff); @@ -416,13 +420,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, of_getintprop_default(node, "subsystem-id", 0); dev->cfg_size = pci_cfg_space_size(dev); - } - sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), - dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); - if (host_controller) { - dev->class = PCI_CLASS_BRIDGE_HOST << 8; - } else { /* We can't actually use the firmware value, we have * to read what is in the register right now. One * reason is that in the case of IDE interfaces the @@ -431,8 +429,12 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, */ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); dev->class = class >> 8; + + sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), + dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); } - printk(" class: 0x%x\n", dev->class); + printk(" class: 0x%x device name: %s\n", + dev->class, pci_name(dev)); dev->current_state = 4; /* unknown power state */ dev->error_state = pci_channel_io_normal; -- cgit v1.2.3 From 43bed127376ff2ef9c268cf6688a43d0fbed2ff4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 14 Mar 2007 18:33:49 -0700 Subject: [SPARC64]: Use DECLARE_BITMAP in struct pci_iommu. Signed-off-by: David S. Miller --- include/asm-sparc64/pbm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 3a811c2cd3c..9afcc06a575 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -78,7 +78,7 @@ struct pci_iommu { /* CTX allocation. */ unsigned long ctx_lowest_free; - unsigned long ctx_bitmap[IOMMU_NUM_CTXS / (sizeof(unsigned long) * 8)]; + DECLARE_BITMAP(ctx_bitmap, IOMMU_NUM_CTXS); /* Here a PCI controller driver describes the areas of * PCI memory space where DMA to/from physical memory -- cgit v1.2.3 From d78d0891d3dd976a2fb707c6c691d9cd5ed60727 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 14 Mar 2007 22:47:01 -0700 Subject: [SPARC64]: Use SPARSEMEM_STATIC Decrease the SECTION_SIZE_BITS --> MAX_PHYSADDR_BITS range a little bit. The cost of going to SPARSEMEM_STATIC becomes 8K of BSS space, and in return we save a pointer dereferences on every page struct lookup. Even better we hit the main kernel image for the base address which is in a hugepage locked TLB entry. Signed-off-by: David S. Miller --- arch/sparc64/Kconfig | 1 + include/asm-sparc64/sparsemem.h | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 51c87fdd998..590a41b864b 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -220,6 +220,7 @@ config ARCH_SPARSEMEM_ENABLE config ARCH_SPARSEMEM_DEFAULT def_bool y + select SPARSEMEM_STATIC config LARGE_ALLOCS def_bool y diff --git a/include/asm-sparc64/sparsemem.h b/include/asm-sparc64/sparsemem.h index ed5c9d8541e..411e0e255cf 100644 --- a/include/asm-sparc64/sparsemem.h +++ b/include/asm-sparc64/sparsemem.h @@ -3,9 +3,9 @@ #ifdef __KERNEL__ -#define SECTION_SIZE_BITS 26 -#define MAX_PHYSADDR_BITS 42 -#define MAX_PHYSMEM_BITS 42 +#define SECTION_SIZE_BITS 31 +#define MAX_PHYSADDR_BITS 41 +#define MAX_PHYSMEM_BITS 41 #endif /* !(__KERNEL__) */ -- cgit v1.2.3 From 0015d3d68c84eb33e6b380802ad61b23f7eb6523 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 00:06:34 -0700 Subject: [SPARC64]: Simplify read_obp_memory(). Kick out empty entries as soon as we spot them, and use memmove() instead of a silly loop to make the operation more clear. Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index f146071a4b2..973c4e122f2 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -122,24 +122,19 @@ static void __init read_obp_memory(const char *property, size = 0UL; base = new_base; } - regs[i].phys_addr = base; - regs[i].reg_size = size; - } - - for (i = 0; i < ents; i++) { - if (regs[i].reg_size == 0UL) { - int j; - - for (j = i; j < ents - 1; j++) { - regs[j].phys_addr = - regs[j+1].phys_addr; - regs[j].reg_size = - regs[j+1].reg_size; - } - - ents--; + if (size == 0UL) { + /* If it is empty, simply get rid of it. + * This simplifies the logic of the other + * functions that process these arrays. + */ + memmove(®s[i], ®s[i + 1], + (ents - i - 1) * sizeof(regs[0])); i--; + ents--; + continue; } + regs[i].phys_addr = base; + regs[i].reg_size = size; } *num_ents = ents; -- cgit v1.2.3 From 4e286d5be63c93b17f8a82d6f3618faa9c1b025c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 00:21:45 -0700 Subject: [SPARC64]: MAX_PHYSADDR_BITS et al. really need to be 42 bits not 41. Signed-off-by: David S. Miller --- include/asm-sparc64/sparsemem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-sparc64/sparsemem.h b/include/asm-sparc64/sparsemem.h index 411e0e255cf..77bcd2bfa53 100644 --- a/include/asm-sparc64/sparsemem.h +++ b/include/asm-sparc64/sparsemem.h @@ -4,8 +4,8 @@ #ifdef __KERNEL__ #define SECTION_SIZE_BITS 31 -#define MAX_PHYSADDR_BITS 41 -#define MAX_PHYSMEM_BITS 41 +#define MAX_PHYSADDR_BITS 42 +#define MAX_PHYSMEM_BITS 42 #endif /* !(__KERNEL__) */ -- cgit v1.2.3 From a0963bdfb91ca97c2b0b6d4ca81ff557fac66901 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 15:09:06 -0700 Subject: [SPARC64]: Kill _start[]/_end[] declarations in mm/init.c We already get those from asm/sections.h Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 973c4e122f2..56be943a6f0 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -155,9 +155,6 @@ unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; #define CTX_BMAP_SLOTS (1UL << (CTX_NR_BITS - 6)) unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; -/* References to special section boundaries */ -extern char _start[], _end[]; - /* Initial ramdisk setup */ extern unsigned long sparc_ramdisk_image64; extern unsigned int sparc_ramdisk_image; -- cgit v1.2.3 From 4be5c34dc47b5a9e6f91c8f5937a93c464870b8e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 15:44:05 -0700 Subject: [SPARC64]: Privatize sun4u_get_pte() and fix name. __get_phys is only called from init.c as is prom_virt_to_phys(), __get_iospace() is not called at all, and sun4u_get_pte() is largely misnamed. Privatize the implementation and helper functions of sun4u_get_phys() to mm/init.c, and rename to kvaddr_to_paddr(). The only used of this thing is flush_icache_range(), and thus things can be considerably further simplified. For example, we should only see module or PAGE_OFFSET kernel addresses here, so we don't need the OBP firmware range handling at all. Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 129 ++++++++++++++++++++---------------------- include/asm-sparc64/pgtable.h | 14 ----- 2 files changed, 62 insertions(+), 81 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 56be943a6f0..3cacea5da6c 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -392,6 +392,67 @@ out: put_cpu(); } +struct linux_prom_translation { + unsigned long virt; + unsigned long size; + unsigned long data; +}; + +/* Exported for kernel TLB miss handling in ktlb.S */ +struct linux_prom_translation prom_trans[512] __read_mostly; +unsigned int prom_trans_ents __read_mostly; + +/* + * Translate PROM's mapping we capture at boot time into physical address. + * The second parameter is only set from prom_callback() invocations. + */ +static unsigned long prom_virt_to_phys(unsigned long promva) +{ + unsigned long mask; + int i; + + mask = _PAGE_PADDR_4U; + if (tlb_type == hypervisor) + mask = _PAGE_PADDR_4V; + + for (i = 0; i < prom_trans_ents; i++) { + struct linux_prom_translation *p = &prom_trans[i]; + + if (promva >= p->virt && + promva < (p->virt + p->size)) { + unsigned long base = p->data & mask; + + return base + (promva & (8192 - 1)); + } + } + return 0UL; +} + +static unsigned long kvaddr_to_phys(unsigned long addr) +{ + pgd_t *pgdp; + pud_t *pudp; + pmd_t *pmdp; + pte_t *ptep; + unsigned long mask = _PAGE_PADDR_4U; + + if (tlb_type == hypervisor) + mask = _PAGE_PADDR_4V; + + if (addr >= PAGE_OFFSET) + return addr & mask; + + if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS)) + return prom_virt_to_phys(addr); + + pgdp = pgd_offset_k(addr); + pudp = pud_offset(pgdp, addr); + pmdp = pmd_offset(pudp, addr); + ptep = pte_offset_kernel(pmdp, addr); + + return pte_val(*ptep) & mask; +} + void __kprobes flush_icache_range(unsigned long start, unsigned long end) { /* Cheetah and Hypervisor platform cpus have coherent I-cache. */ @@ -399,7 +460,7 @@ void __kprobes flush_icache_range(unsigned long start, unsigned long end) unsigned long kaddr; for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) - __flush_icache_page(__get_phys(kaddr)); + __flush_icache_page(kvaddr_to_phys(kaddr)); } } @@ -436,16 +497,6 @@ void mmu_info(struct seq_file *m) #endif /* CONFIG_DEBUG_DCFLUSH */ } -struct linux_prom_translation { - unsigned long virt; - unsigned long size; - unsigned long data; -}; - -/* Exported for kernel TLB miss handling in ktlb.S */ -struct linux_prom_translation prom_trans[512] __read_mostly; -unsigned int prom_trans_ents __read_mostly; - /* Exported for SMP bootup purposes. */ unsigned long kern_locked_tte_data; @@ -1875,62 +1926,6 @@ static unsigned long kern_large_tte(unsigned long paddr) return val | paddr; } -/* - * Translate PROM's mapping we capture at boot time into physical address. - * The second parameter is only set from prom_callback() invocations. - */ -unsigned long prom_virt_to_phys(unsigned long promva, int *error) -{ - unsigned long mask; - int i; - - mask = _PAGE_PADDR_4U; - if (tlb_type == hypervisor) - mask = _PAGE_PADDR_4V; - - for (i = 0; i < prom_trans_ents; i++) { - struct linux_prom_translation *p = &prom_trans[i]; - - if (promva >= p->virt && - promva < (p->virt + p->size)) { - unsigned long base = p->data & mask; - - if (error) - *error = 0; - return base + (promva & (8192 - 1)); - } - } - if (error) - *error = 1; - return 0UL; -} - -/* XXX We should kill off this ugly thing at so me point. XXX */ -unsigned long sun4u_get_pte(unsigned long addr) -{ - pgd_t *pgdp; - pud_t *pudp; - pmd_t *pmdp; - pte_t *ptep; - unsigned long mask = _PAGE_PADDR_4U; - - if (tlb_type == hypervisor) - mask = _PAGE_PADDR_4V; - - if (addr >= PAGE_OFFSET) - return addr & mask; - - if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS)) - return prom_virt_to_phys(addr, NULL); - - pgdp = pgd_offset_k(addr); - pudp = pud_offset(pgdp, addr); - pmdp = pmd_offset(pudp, addr); - ptep = pte_offset_kernel(pmdp, addr); - - return pte_val(*ptep) & mask; -} - /* If not locked, zap it. */ void __flush_tlb_all(void) { diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index b12be7a869f..fd46dd615b6 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -737,20 +737,6 @@ extern unsigned long pte_file(pte_t); extern pte_t pgoff_to_pte(unsigned long); #define PTE_FILE_MAX_BITS (64UL - PAGE_SHIFT - 1UL) -extern unsigned long prom_virt_to_phys(unsigned long, int *); - -extern unsigned long sun4u_get_pte(unsigned long); - -static inline unsigned long __get_phys(unsigned long addr) -{ - return sun4u_get_pte(addr); -} - -static inline int __get_iospace(unsigned long addr) -{ - return ((sun4u_get_pte(addr) & 0xf0000000) >> 28); -} - extern unsigned long *sparc64_valid_addr_bitmap; /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ -- cgit v1.2.3 From a94aa2530643f02a4b243f81b5f6354b9b958d7e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 15:50:11 -0700 Subject: [SPARC64]: Kill kvaddr_to_phys() and friends. Just inline it into flush_icache_range() which is the only user. Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 91 ++++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 63 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 3cacea5da6c..fca253989e5 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -392,75 +392,30 @@ out: put_cpu(); } -struct linux_prom_translation { - unsigned long virt; - unsigned long size; - unsigned long data; -}; - -/* Exported for kernel TLB miss handling in ktlb.S */ -struct linux_prom_translation prom_trans[512] __read_mostly; -unsigned int prom_trans_ents __read_mostly; - -/* - * Translate PROM's mapping we capture at boot time into physical address. - * The second parameter is only set from prom_callback() invocations. - */ -static unsigned long prom_virt_to_phys(unsigned long promva) -{ - unsigned long mask; - int i; - - mask = _PAGE_PADDR_4U; - if (tlb_type == hypervisor) - mask = _PAGE_PADDR_4V; - - for (i = 0; i < prom_trans_ents; i++) { - struct linux_prom_translation *p = &prom_trans[i]; - - if (promva >= p->virt && - promva < (p->virt + p->size)) { - unsigned long base = p->data & mask; - - return base + (promva & (8192 - 1)); - } - } - return 0UL; -} - -static unsigned long kvaddr_to_phys(unsigned long addr) -{ - pgd_t *pgdp; - pud_t *pudp; - pmd_t *pmdp; - pte_t *ptep; - unsigned long mask = _PAGE_PADDR_4U; - - if (tlb_type == hypervisor) - mask = _PAGE_PADDR_4V; - - if (addr >= PAGE_OFFSET) - return addr & mask; - - if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS)) - return prom_virt_to_phys(addr); - - pgdp = pgd_offset_k(addr); - pudp = pud_offset(pgdp, addr); - pmdp = pmd_offset(pudp, addr); - ptep = pte_offset_kernel(pmdp, addr); - - return pte_val(*ptep) & mask; -} - void __kprobes flush_icache_range(unsigned long start, unsigned long end) { /* Cheetah and Hypervisor platform cpus have coherent I-cache. */ if (tlb_type == spitfire) { unsigned long kaddr; - for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) - __flush_icache_page(kvaddr_to_phys(kaddr)); + /* This code only runs on Spitfire cpus so this is + * why we can assume _PAGE_PADDR_4U. + */ + for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) { + unsigned long paddr, mask = _PAGE_PADDR_4U; + + if (kaddr >= PAGE_OFFSET) + paddr = kaddr & mask; + else { + pgd_t *pgdp = pgd_offset_k(kaddr); + pud_t *pudp = pud_offset(pgdp, kaddr); + pmd_t *pmdp = pmd_offset(pudp, kaddr); + pte_t *ptep = pte_offset_kernel(pmdp, kaddr); + + paddr = pte_val(*ptep) & mask; + } + __flush_icache_page(paddr); + } } } @@ -497,6 +452,16 @@ void mmu_info(struct seq_file *m) #endif /* CONFIG_DEBUG_DCFLUSH */ } +struct linux_prom_translation { + unsigned long virt; + unsigned long size; + unsigned long data; +}; + +/* Exported for kernel TLB miss handling in ktlb.S */ +struct linux_prom_translation prom_trans[512] __read_mostly; +unsigned int prom_trans_ents __read_mostly; + /* Exported for SMP bootup purposes. */ unsigned long kern_locked_tte_data; -- cgit v1.2.3 From 28256ca2e04c72eee1e83524d7f78ce5646030e2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 15:56:07 -0700 Subject: [SPARC64]: Mark show_mem() printk's with KERN_INFO. Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index fca253989e5..6fa78c5a30c 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -421,12 +421,12 @@ void __kprobes flush_icache_range(unsigned long start, unsigned long end) void show_mem(void) { - printk("Mem-info:\n"); + printk(KERN_INFO "Mem-info:\n"); show_free_areas(); - printk("Free swap: %6ldkB\n", + printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages << (PAGE_SHIFT-10)); - printk("%ld pages of RAM\n", num_physpages); - printk("%lu free pages\n", nr_free_pages()); + printk(KERN_INFO "%ld pages of RAM\n", num_physpages); + printk(KERN_INFO "%lu free pages\n", nr_free_pages()); } void mmu_info(struct seq_file *m) -- cgit v1.2.3 From 5be4a963675d3270fab7f55e8c4a2e56afd408f6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 16:00:29 -0700 Subject: [SPARC64]: Give move verbose show_mem() output just like i386. We now report everything i386 does except for highmem which doesn't apply. Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 6fa78c5a30c..97b5ebc9116 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -421,12 +421,47 @@ void __kprobes flush_icache_range(unsigned long start, unsigned long end) void show_mem(void) { + unsigned long total = 0, reserved = 0; + unsigned long shared = 0, cached = 0; + pg_data_t *pgdat; + printk(KERN_INFO "Mem-info:\n"); show_free_areas(); printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages << (PAGE_SHIFT-10)); - printk(KERN_INFO "%ld pages of RAM\n", num_physpages); - printk(KERN_INFO "%lu free pages\n", nr_free_pages()); + for_each_online_pgdat(pgdat) { + unsigned long i, flags; + + pgdat_resize_lock(pgdat, &flags); + for (i = 0; i < pgdat->node_spanned_pages; i++) { + struct page *page = pgdat_page_nr(pgdat, i); + total++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page) - 1; + } + pgdat_resize_unlock(pgdat, &flags); + } + + printk(KERN_INFO "%lu pages of RAM\n", total); + printk(KERN_INFO "%lu reserved pages\n", reserved); + printk(KERN_INFO "%lu pages shared\n", shared); + printk(KERN_INFO "%lu pages swap cached\n", cached); + + printk(KERN_INFO "%lu pages dirty\n", + global_page_state(NR_FILE_DIRTY)); + printk(KERN_INFO "%lu pages writeback\n", + global_page_state(NR_WRITEBACK)); + printk(KERN_INFO "%lu pages mapped\n", + global_page_state(NR_FILE_MAPPED)); + printk(KERN_INFO "%lu pages slab\n", + global_page_state(NR_SLAB_RECLAIMABLE) + + global_page_state(NR_SLAB_UNRECLAIMABLE)); + printk(KERN_INFO "%lu pages pagetables\n", + global_page_state(NR_PAGETABLE)); } void mmu_info(struct seq_file *m) -- cgit v1.2.3 From 85f1e1f66011e67e68065f2db4cde499decb9c84 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 17:51:26 -0700 Subject: [SPARC64]: Use DECLARE_BITMAP and BITS_TO_LONGS in mm/init.c Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 97b5ebc9116..83a76a2eb71 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -149,12 +149,6 @@ unsigned long *sparc64_valid_addr_bitmap __read_mostly; unsigned long kern_base __read_mostly; unsigned long kern_size __read_mostly; -/* get_new_mmu_context() uses "cache + 1". */ -DEFINE_SPINLOCK(ctx_alloc_lock); -unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; -#define CTX_BMAP_SLOTS (1UL << (CTX_NR_BITS - 6)) -unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; - /* Initial ramdisk setup */ extern unsigned long sparc_ramdisk_image64; extern unsigned int sparc_ramdisk_image; @@ -701,6 +695,13 @@ void __flush_dcache_range(unsigned long start, unsigned long end) } #endif /* DCACHE_ALIASING_POSSIBLE */ +/* get_new_mmu_context() uses "cache + 1". */ +DEFINE_SPINLOCK(ctx_alloc_lock); +unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; +#define MAX_CTX_NR (1UL << CTX_NR_BITS) +#define CTX_BMAP_SLOTS BITS_TO_LONGS(MAX_CTX_NR) +DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR); + /* Caller does TLB context flushing on local CPU if necessary. * The caller also ensures that CTX_VALID(mm->context) is false. * -- cgit v1.2.3 From 9753f0d6502acd65761ff15244d26d0e88f0820a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 18:26:00 -0700 Subject: [SPARC64]: Kill sparc_ultra_dump_{i,d}tlb() While useful in odd circumstances to debug something, they are normally totally unused and anyone can fetch this code out of the history if they really need it. And in any event, the person who needs this kind of code is usually me :-) Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 87 -------------------------------------------------- 1 file changed, 87 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 83a76a2eb71..668b7bba90e 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -761,93 +761,6 @@ out: smp_new_mmu_context_version(); } -void sparc_ultra_dump_itlb(void) -{ - int slot; - - if (tlb_type == spitfire) { - printk ("Contents of itlb: "); - for (slot = 0; slot < 14; slot++) printk (" "); - printk ("%2x:%016lx,%016lx\n", - 0, - spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0)); - for (slot = 1; slot < 64; slot+=3) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", - slot, - spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot), - slot+1, - spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1), - slot+2, - spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2)); - } - } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { - printk ("Contents of itlb0:\n"); - for (slot = 0; slot < 16; slot+=2) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", - slot, - cheetah_get_litlb_tag(slot), cheetah_get_litlb_data(slot), - slot+1, - cheetah_get_litlb_tag(slot+1), cheetah_get_litlb_data(slot+1)); - } - printk ("Contents of itlb2:\n"); - for (slot = 0; slot < 128; slot+=2) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", - slot, - cheetah_get_itlb_tag(slot), cheetah_get_itlb_data(slot), - slot+1, - cheetah_get_itlb_tag(slot+1), cheetah_get_itlb_data(slot+1)); - } - } -} - -void sparc_ultra_dump_dtlb(void) -{ - int slot; - - if (tlb_type == spitfire) { - printk ("Contents of dtlb: "); - for (slot = 0; slot < 14; slot++) printk (" "); - printk ("%2x:%016lx,%016lx\n", 0, - spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0)); - for (slot = 1; slot < 64; slot+=3) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", - slot, - spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot), - slot+1, - spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1), - slot+2, - spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2)); - } - } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { - printk ("Contents of dtlb0:\n"); - for (slot = 0; slot < 16; slot+=2) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", - slot, - cheetah_get_ldtlb_tag(slot), cheetah_get_ldtlb_data(slot), - slot+1, - cheetah_get_ldtlb_tag(slot+1), cheetah_get_ldtlb_data(slot+1)); - } - printk ("Contents of dtlb2:\n"); - for (slot = 0; slot < 512; slot+=2) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", - slot, - cheetah_get_dtlb_tag(slot, 2), cheetah_get_dtlb_data(slot, 2), - slot+1, - cheetah_get_dtlb_tag(slot+1, 2), cheetah_get_dtlb_data(slot+1, 2)); - } - if (tlb_type == cheetah_plus) { - printk ("Contents of dtlb3:\n"); - for (slot = 0; slot < 512; slot+=2) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", - slot, - cheetah_get_dtlb_tag(slot, 3), cheetah_get_dtlb_data(slot, 3), - slot+1, - cheetah_get_dtlb_tag(slot+1, 3), cheetah_get_dtlb_data(slot+1, 3)); - } - } - } -} - extern unsigned long cmdline_memory_size; /* Find a free area for the bootmem map, avoiding the kernel image -- cgit v1.2.3 From b93f2620231d4641bdbaaa952d3e8890687124bb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 18:29:13 -0700 Subject: [SPARC64]: Add proper header file extern for cmdline_memory_size. Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 2 -- include/asm-sparc64/pgtable.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 668b7bba90e..df4e37e0b0f 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -761,8 +761,6 @@ out: smp_new_mmu_context_version(); } -extern unsigned long cmdline_memory_size; - /* Find a free area for the bootmem map, avoiding the kernel image * and the initial ramdisk. */ diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index fd46dd615b6..46705ef47d2 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -777,6 +777,8 @@ extern void pgtable_cache_init(void); extern void sun4v_register_fault_status(void); extern void sun4v_ktsb_register(void); +extern unsigned long cmdline_memory_size; + #endif /* !(__ASSEMBLY__) */ #endif /* !(_SPARC64_PGTABLE_H) */ -- cgit v1.2.3 From 3996465392fd1632b671707d16bbc96a9481cfe2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 19:36:53 -0700 Subject: [SPARC64]: Use bootmem_bootmap_pages() in choose_bootmap_pfn(). Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index df4e37e0b0f..40276189c10 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -770,8 +770,8 @@ static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn, unsigned long avoid_start, avoid_end, bootmap_size; int i; - bootmap_size = ((end_pfn - start_pfn) + 7) / 8; - bootmap_size = ALIGN(bootmap_size, sizeof(long)); + bootmap_size = bootmem_bootmap_pages(end_pfn - start_pfn); + bootmap_size <<= PAGE_SHIFT; avoid_start = avoid_end = 0; #ifdef CONFIG_BLK_DEV_INITRD -- cgit v1.2.3 From 0f3e25049e0a54916d0991c1eaa5f8df926c7f92 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 21:44:03 -0700 Subject: [SPARC64]: Make sure pbm->prom_node is setup easly enough in psycho.c It needs to be ready before we invoke pci_determine_mem_io_space(). Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_psycho.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 154c03290d5..3725910c8b2 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1107,8 +1107,6 @@ static void psycho_pbm_init(struct pci_controller_info *p, if (prop) pbm->chip_revision = *(int *) prop->value; - pci_determine_mem_io_space(pbm); - pbm->parent = p; pbm->prom_node = dp; pbm->name = dp->full_name; @@ -1117,6 +1115,8 @@ static void psycho_pbm_init(struct pci_controller_info *p, pbm->name, pbm->chip_version, pbm->chip_revision); + pci_determine_mem_io_space(pbm); + prop = of_find_property(dp, "bus-range", NULL); busrange = prop->value; pbm->pci_first_busno = busrange[0]; -- cgit v1.2.3 From f1cfdb55f16596752e8a61a8570a90ee26af183a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 15 Mar 2007 22:52:18 -0700 Subject: [SPARC64]: Document and fix calculation of pages_avail. It should be set to the total number of pages that the system will really have available after things like initmem, the bootmem map, and initrd are freed up. Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 40276189c10..cafadcbcdf3 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -938,6 +938,20 @@ static void __init trim_pavail(unsigned long *cur_size_p, } } +/* About pages_avail, this is the value we will use to calculate + * the zholes_size[] argument given to free_area_init_node(). The + * page allocator uses this to calculate nr_kernel_pages, + * nr_all_pages and zone->present_pages. On NUMA it is used + * to calculate zone->min_unmapped_pages and zone->min_slab_pages. + * + * So this number should really be set to what the page allocator + * actually ends up with. This means: + * 1) It should include bootmem map pages, we'll release those. + * 2) It should not include the kernel image, except for the + * __init sections which we will also release. + * 3) It should include the initrd image, since we'll release + * that too. + */ static unsigned long __init bootmem_init(unsigned long *pages_avail, unsigned long phys_base) { @@ -1024,7 +1038,6 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, initrd_start, initrd_end); #endif reserve_bootmem(initrd_start, size); - *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; initrd_start += PAGE_OFFSET; initrd_end += PAGE_OFFSET; @@ -1037,6 +1050,11 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, reserve_bootmem(kern_base, kern_size); *pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT; + /* Add back in the initmem pages. */ + size = ((unsigned long)(__init_end) & PAGE_MASK) - + PAGE_ALIGN((unsigned long)__init_begin); + *pages_avail += size >> PAGE_SHIFT; + /* Reserve the bootmem map. We do not account for it * in pages_avail because we will release that memory * in free_all_bootmem. @@ -1047,7 +1065,6 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, (bootmap_pfn << PAGE_SHIFT), size); #endif reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size); - *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; for (i = 0; i < pavail_ents; i++) { unsigned long start_pfn, end_pfn; @@ -1539,6 +1556,10 @@ void __init mem_init(void) #ifdef CONFIG_DEBUG_BOOTMEM prom_printf("mem_init: Calling free_all_bootmem().\n"); #endif + + /* We subtract one to account for the mem_map_zero page + * allocated below. + */ totalram_pages = num_physpages = free_all_bootmem() - 1; /* -- cgit v1.2.3 From a165b4205e0097c7544ec3c59522a3b20ec14eb1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Mar 2007 01:50:16 -0700 Subject: [SPARC64]: Fix PCI rework to adhere to of_get_property() const return. Signed-off-by: David S. Miller --- arch/sparc64/kernel/of_device.c | 4 ++-- arch/sparc64/kernel/pci.c | 2 +- arch/sparc64/kernel/pci_common.c | 6 +++--- arch/sparc64/kernel/pci_sabre.c | 6 +++--- arch/sparc64/kernel/pci_schizo.c | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index f18eec6ad69..9ac9a307999 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -317,7 +317,7 @@ static unsigned int of_bus_default_get_flags(const u32 *addr) static int of_bus_pci_match(struct device_node *np) { if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { - char *model = of_get_property(np, "model", NULL); + const char *model = of_get_property(np, "model", NULL); if (model && !strcmp(model, "SUNW,simba")) return 0; @@ -339,7 +339,7 @@ static int of_bus_pci_match(struct device_node *np) static int of_bus_simba_match(struct device_node *np) { - char *model = of_get_property(np, "model", NULL); + const char *model = of_get_property(np, "model", NULL); if (model && !strcmp(model, "SUNW,simba")) return 1; diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 8a7c699bb10..023af41ad68 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -551,7 +551,7 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, ranges = of_get_property(node, "ranges", &len); simba = 0; if (ranges == NULL) { - char *model = of_get_property(node, "model", NULL); + const char *model = of_get_property(node, "model", NULL); if (model && !strcmp(model, "SUNW,simba")) { simba = 1; } else { diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 6b5c8e7a3eb..1e6aeedf43c 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -54,7 +54,7 @@ static void pci_register_legacy_regions(struct resource *io_res, static void pci_register_iommu_region(struct pci_pbm_info *pbm) { - u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL); + const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL); if (vdma) { struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL); @@ -73,7 +73,7 @@ static void pci_register_iommu_region(struct pci_pbm_info *pbm) void pci_determine_mem_io_space(struct pci_pbm_info *pbm) { - struct linux_prom_pci_ranges *pbm_ranges; + const struct linux_prom_pci_ranges *pbm_ranges; int i, saw_mem, saw_io; int num_pbm_ranges; @@ -82,7 +82,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) num_pbm_ranges = i / sizeof(*pbm_ranges); for (i = 0; i < num_pbm_ranges; i++) { - struct linux_prom_pci_ranges *pr = &pbm_ranges[i]; + const struct linux_prom_pci_ranges *pr = &pbm_ranges[i]; unsigned long a; u32 parent_phys_hi, parent_phys_lo; int type; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index a2f129d29c2..9a2ce0637c8 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1015,12 +1015,12 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp void sabre_init(struct device_node *dp, char *model_name) { - struct linux_prom64_registers *pr_regs; + const struct linux_prom64_registers *pr_regs; struct pci_controller_info *p; struct pci_iommu *iommu; int tsbsize; - u32 *busrange; - u32 *vdma; + const u32 *busrange; + const u32 *vdma; u32 upa_portid, dma_mask; u64 clear_irq; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 322cdbf50ef..47a5aa94dca 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1490,11 +1490,11 @@ static void schizo_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 portid, int chip_type) { - struct linux_prom64_registers *regs; - unsigned int *busrange; + const struct linux_prom64_registers *regs; + const unsigned int *busrange; struct pci_pbm_info *pbm; const char *chipset_name; - u32 *ino_bitmap; + const u32 *ino_bitmap; int is_pbm_a; switch (chip_type) { -- cgit v1.2.3 From 374d4cac6283469f101282ca83ee008368bd8350 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Mar 2007 01:57:57 -0700 Subject: [TIGON3]: of_get_property() returns const. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6aef1e95d39..9d07d2d5dfa 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10993,7 +10993,7 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp) struct net_device *dev = tp->dev; struct pci_dev *pdev = tp->pdev; struct device_node *dp = pci_device_to_OF_node(pdev); - unsigned char *addr; + const unsigned char *addr; int len; addr = of_get_property(dp, "local-mac-address", &len); -- cgit v1.2.3 From 3dfe10ee7caae9802d84a06fe7724274dea24020 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Mar 2007 11:22:57 -0700 Subject: [SPARC64]: constify some paramaters of OF routines This starts bringing the PowerPC and Sparc64 implemetations back closer together. Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- arch/sparc64/kernel/prom.c | 11 +++++++---- include/asm-sparc64/prom.h | 10 ++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 13734b50a6e..5e1fcd05160 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -36,12 +36,13 @@ static struct device_node *allnodes; */ static DEFINE_RWLOCK(devtree_lock); -int of_device_is_compatible(struct device_node *device, const char *compat) +int of_device_is_compatible(const struct device_node *device, + const char *compat) { const char* cp; int cplen, l; - cp = (char *) of_get_property(device, "compatible", &cplen); + cp = of_get_property(device, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { @@ -154,7 +155,8 @@ struct device_node *of_find_compatible_node(struct device_node *from, } EXPORT_SYMBOL(of_find_compatible_node); -struct property *of_find_property(struct device_node *np, const char *name, +struct property *of_find_property(const struct device_node *np, + const char *name, int *lenp) { struct property *pp; @@ -174,7 +176,8 @@ EXPORT_SYMBOL(of_find_property); * Find a property with a given name for a given node * and return the value. */ -const void *of_get_property(struct device_node *np, const char *name, int *lenp) +const void *of_get_property(const struct device_node *np, const char *name, + int *lenp) { struct property *pp = of_find_property(np,name,lenp); return pp ? pp->value : NULL; diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 50b03387c97..6394bd1cdcd 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -93,12 +93,14 @@ extern struct device_node *of_find_node_by_phandle(phandle handle); extern struct device_node *of_get_parent(const struct device_node *node); extern struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev); -extern struct property *of_find_property(struct device_node *np, +extern struct property *of_find_property(const struct device_node *np, const char *name, int *lenp); -extern int of_device_is_compatible(struct device_node *device, const char *); -extern const void *of_get_property(struct device_node *node, const char *name, - int *lenp); +extern int of_device_is_compatible(const struct device_node *device, + const char *); +extern const void *of_get_property(const struct device_node *node, + const char *name, + int *lenp); #define get_property(node,name,lenp) of_get_property(node,name,lenp) extern int of_set_property(struct device_node *node, const char *name, void *val, int len); extern int of_getintprop_default(struct device_node *np, -- cgit v1.2.3 From 711b360d64418e88ed45f812e0ebd202073d888d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 12 Apr 2007 14:38:34 -0700 Subject: [SPARC]: Make device_node name and type const Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- include/asm-sparc/prom.h | 4 ++-- include/asm-sparc64/prom.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index 39ad2224a11..9ea105ebe2f 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -35,8 +35,8 @@ struct property { }; struct device_node { - char *name; - char *type; + const char *name; + const char *type; phandle node; char *path_component_name; char *full_name; diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 6394bd1cdcd..ddad5f99ac7 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -36,8 +36,8 @@ struct property { struct of_irq_controller; struct device_node { - char *name; - char *type; + const char *name; + const char *type; phandle node; char *path_component_name; char *full_name; -- cgit v1.2.3 From 9b3627f389c07c5be9c86ac4d472a0d4fd47feac Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 24 Apr 2007 23:51:18 -0700 Subject: [SPARC64]: Consolidate {sbus,pci}_iommu_arena. Move to asm-sparc64/iommu.h and rename to plain "iommu_arena". Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_iommu.c | 4 ++-- arch/sparc64/kernel/pci_sun4v.c | 6 +++--- arch/sparc64/kernel/sbus.c | 12 +++--------- include/asm-sparc64/iommu.h | 22 ++++++++++++++-------- include/asm-sparc64/pbm.h | 8 +------- 5 files changed, 23 insertions(+), 29 deletions(-) diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index aefdcc51045..355ed0ba937 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -77,7 +77,7 @@ static inline void iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte) /* Based largely upon the ppc64 iommu allocator. */ static long pci_arena_alloc(struct pci_iommu *iommu, unsigned long npages) { - struct pci_iommu_arena *arena = &iommu->arena; + struct iommu_arena *arena = &iommu->arena; unsigned long n, i, start, end, limit; int pass; @@ -116,7 +116,7 @@ again: return n; } -static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages) +static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) { unsigned long i; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 52bd4563492..0e99808f212 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -110,7 +110,7 @@ static inline long pci_iommu_batch_end(void) return pci_iommu_batch_flush(p); } -static long pci_arena_alloc(struct pci_iommu_arena *arena, unsigned long npages) +static long pci_arena_alloc(struct iommu_arena *arena, unsigned long npages) { unsigned long n, i, start, end, limit; int pass; @@ -149,7 +149,7 @@ again: return n; } -static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages) +static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) { unsigned long i; @@ -707,7 +707,7 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p) static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, struct pci_iommu *iommu) { - struct pci_iommu_arena *arena = &iommu->arena; + struct iommu_arena *arena = &iommu->arena; unsigned long i, cnt = 0; u32 devhandle; diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index d403f3df2dc..279758d56b2 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -26,16 +26,10 @@ #define MAP_BASE ((u32)0xc0000000) -struct sbus_iommu_arena { - unsigned long *map; - unsigned int hint; - unsigned int limit; -}; - struct sbus_iommu { spinlock_t lock; - struct sbus_iommu_arena arena; + struct iommu_arena arena; iopte_t *page_table; unsigned long strbuf_regs; @@ -123,7 +117,7 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long /* Based largely upon the ppc64 iommu allocator. */ static long sbus_arena_alloc(struct sbus_iommu *iommu, unsigned long npages) { - struct sbus_iommu_arena *arena = &iommu->arena; + struct iommu_arena *arena = &iommu->arena; unsigned long n, i, start, end, limit; int pass; @@ -162,7 +156,7 @@ again: return n; } -static void sbus_arena_free(struct sbus_iommu_arena *arena, unsigned long base, unsigned long npages) +static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) { unsigned long i; diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h index 0de7a3da79c..d8d98f8f747 100644 --- a/include/asm-sparc64/iommu.h +++ b/include/asm-sparc64/iommu.h @@ -7,15 +7,21 @@ #define _SPARC64_IOMMU_H /* The format of an iopte in the page tables. */ -#define IOPTE_VALID 0x8000000000000000UL /* IOPTE is valid */ -#define IOPTE_64K 0x2000000000000000UL /* IOPTE is for 64k page */ -#define IOPTE_STBUF 0x1000000000000000UL /* DVMA can use streaming buffer */ -#define IOPTE_INTRA 0x0800000000000000UL /* SBUS slot-->slot direct transfer*/ -#define IOPTE_CONTEXT 0x07ff800000000000UL /* Context number */ -#define IOPTE_PAGE 0x00007fffffffe000UL /* Physical page number (PA[42:13])*/ -#define IOPTE_CACHE 0x0000000000000010UL /* Cached (in UPA E-cache) */ -#define IOPTE_WRITE 0x0000000000000002UL /* Writeable */ +#define IOPTE_VALID 0x8000000000000000UL +#define IOPTE_64K 0x2000000000000000UL +#define IOPTE_STBUF 0x1000000000000000UL +#define IOPTE_INTRA 0x0800000000000000UL +#define IOPTE_CONTEXT 0x07ff800000000000UL +#define IOPTE_PAGE 0x00007fffffffe000UL +#define IOPTE_CACHE 0x0000000000000010UL +#define IOPTE_WRITE 0x0000000000000002UL #define IOMMU_NUM_CTXS 4096 +struct iommu_arena { + unsigned long *map; + unsigned int hint; + unsigned int limit; +}; + #endif /* !(_SPARC_IOMMU_H) */ diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 9afcc06a575..4a0ed2ea950 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -35,19 +35,13 @@ struct pci_controller_info; /* This contains the software state necessary to drive a PCI * controller's IOMMU. */ -struct pci_iommu_arena { - unsigned long *map; - unsigned int hint; - unsigned int limit; -}; - struct pci_iommu { /* This protects the controller's IOMMU and all * streaming buffers underneath. */ spinlock_t lock; - struct pci_iommu_arena arena; + struct iommu_arena arena; /* IOMMU page table, a linear array of ioptes. */ iopte_t *page_table; /* The page table itself. */ -- cgit v1.2.3 From 66875088098f314af1a4d9e0cc47e617d643bffd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 25 Apr 2007 00:12:09 -0700 Subject: [SPARC64]: Add generic iommu and strbuf structs to iommu.h Signed-off-by: David S. Miller --- include/asm-sparc64/iommu.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h index d8d98f8f747..e199594a1e9 100644 --- a/include/asm-sparc64/iommu.h +++ b/include/asm-sparc64/iommu.h @@ -24,4 +24,33 @@ struct iommu_arena { unsigned int limit; }; +struct iommu { + spinlock_t lock; + struct iommu_arena arena; + iopte_t *page_table; + u32 page_table_map_base; + unsigned long iommu_control; + unsigned long iommu_tsbbase; + unsigned long iommu_flush; + unsigned long iommu_ctxflush; + unsigned long write_complete_reg; + unsigned long dummy_page; + unsigned long dummy_page_pa; + unsigned long ctx_lowest_free; + DECLARE_BITMAP(ctx_bitmap, IOMMU_NUM_CTXS); + u32 dma_addr_mask; +}; + +struct strbuf { + int strbuf_enabled; + unsigned long strbuf_control; + unsigned long strbuf_pflush; + unsigned long strbuf_fsync; + unsigned long strbuf_ctxflush; + unsigned long strbuf_ctxmatch_base; + unsigned long strbuf_flushflag_pa; + volatile unsigned long *strbuf_flushflag; + volatile unsigned long __flushflag_buf[(64+(64-1)) / sizeof(long)]; +}; + #endif /* !(_SPARC_IOMMU_H) */ -- cgit v1.2.3 From 3e4d26508af6d03034a97583c895f33bef671d06 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 25 Apr 2007 15:58:22 -0700 Subject: [SPARC64]: Convert SBUS over to generic iommu/strbuf structs. Signed-off-by: David S. Miller --- arch/sparc64/kernel/sbus.c | 229 ++++++++++++++++++++++++++------------------- 1 file changed, 132 insertions(+), 97 deletions(-) diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 279758d56b2..3b05428cc90 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -26,17 +26,9 @@ #define MAP_BASE ((u32)0xc0000000) -struct sbus_iommu { - spinlock_t lock; - - struct iommu_arena arena; - - iopte_t *page_table; - unsigned long strbuf_regs; - unsigned long iommu_regs; - unsigned long sbus_control_reg; - - volatile unsigned long strbuf_flushflag; +struct sbus_info { + struct iommu iommu; + struct strbuf strbuf; }; /* Offsets from iommu_regs */ @@ -52,16 +44,17 @@ struct sbus_iommu { #define IOMMU_DRAM_VALID (1UL << 30UL) -static void __iommu_flushall(struct sbus_iommu *iommu) +static void __iommu_flushall(struct iommu *iommu) { - unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG; + unsigned long tag; int entry; + tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL); for (entry = 0; entry < 16; entry++) { upa_writeq(0, tag); tag += 8UL; } - upa_readq(iommu->sbus_control_reg); + upa_readq(iommu->write_complete_reg); } /* Offsets from strbuf_regs */ @@ -76,15 +69,14 @@ static void __iommu_flushall(struct sbus_iommu *iommu) #define STRBUF_TAG_VALID 0x02UL -static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages, int direction) +static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 base, unsigned long npages, int direction) { unsigned long n; int limit; n = npages; while (n--) - upa_writeq(base + (n << IO_PAGE_SHIFT), - iommu->strbuf_regs + STRBUF_PFLUSH); + upa_writeq(base + (n << IO_PAGE_SHIFT), strbuf->strbuf_pflush); /* If the device could not have possibly put dirty data into * the streaming cache, no flush-flag synchronization needs @@ -93,15 +85,14 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long if (direction == SBUS_DMA_TODEVICE) return; - iommu->strbuf_flushflag = 0UL; + *(strbuf->strbuf_flushflag) = 0UL; /* Whoopee cushion! */ - upa_writeq(__pa(&iommu->strbuf_flushflag), - iommu->strbuf_regs + STRBUF_FSYNC); - upa_readq(iommu->sbus_control_reg); + upa_writeq(strbuf->strbuf_flushflag_pa, strbuf->strbuf_fsync); + upa_readq(iommu->write_complete_reg); limit = 100000; - while (iommu->strbuf_flushflag == 0UL) { + while (*(strbuf->strbuf_flushflag) == 0UL) { limit--; if (!limit) break; @@ -115,7 +106,7 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long } /* Based largely upon the ppc64 iommu allocator. */ -static long sbus_arena_alloc(struct sbus_iommu *iommu, unsigned long npages) +static long sbus_arena_alloc(struct iommu *iommu, unsigned long npages) { struct iommu_arena *arena = &iommu->arena; unsigned long n, i, start, end, limit; @@ -164,7 +155,7 @@ static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsig __clear_bit(i, arena->map); } -static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize) +static void sbus_iommu_table_init(struct iommu *iommu, unsigned int tsbsize) { unsigned long tsbbase, order, sz, num_tsb_entries; @@ -172,13 +163,14 @@ static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize /* Setup initial software IOMMU state. */ spin_lock_init(&iommu->lock); + iommu->page_table_map_base = MAP_BASE; /* Allocate and initialize the free area map. */ sz = num_tsb_entries / 8; sz = (sz + 7UL) & ~7UL; iommu->arena.map = kzalloc(sz, GFP_KERNEL); if (!iommu->arena.map) { - prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); + prom_printf("SBUS_IOMMU: Error, kmalloc(arena.map) failed.\n"); prom_halt(); } iommu->arena.limit = num_tsb_entries; @@ -194,7 +186,7 @@ static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize memset(iommu->page_table, 0, tsbsize); } -static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npages) +static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) { long entry; @@ -205,14 +197,15 @@ static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npag return iommu->page_table + entry; } -static inline void free_npages(struct sbus_iommu *iommu, dma_addr_t base, unsigned long npages) +static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages) { sbus_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); } void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma_addr) { - struct sbus_iommu *iommu; + struct sbus_info *info; + struct iommu *iommu; iopte_t *iopte; unsigned long flags, order, first_page; void *ret; @@ -228,7 +221,8 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma return NULL; memset((char *)first_page, 0, PAGE_SIZE << order); - iommu = sdev->bus->iommu; + info = sdev->bus->iommu; + iommu = &info->iommu; spin_lock_irqsave(&iommu->lock, flags); iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); @@ -239,7 +233,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma return NULL; } - *dvma_addr = (MAP_BASE + + *dvma_addr = (iommu->page_table_map_base + ((iopte - iommu->page_table) << IO_PAGE_SHIFT)); ret = (void *) first_page; npages = size >> IO_PAGE_SHIFT; @@ -257,18 +251,20 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_addr_t dvma) { - struct sbus_iommu *iommu; + struct sbus_info *info; + struct iommu *iommu; iopte_t *iopte; unsigned long flags, order, npages; npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - iommu = sdev->bus->iommu; + info = sdev->bus->iommu; + iommu = &info->iommu; iopte = iommu->page_table + - ((dvma - MAP_BASE) >> IO_PAGE_SHIFT); + ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); spin_lock_irqsave(&iommu->lock, flags); - free_npages(iommu, dvma - MAP_BASE, npages); + free_npages(iommu, dvma - iommu->page_table_map_base, npages); spin_unlock_irqrestore(&iommu->lock, flags); @@ -279,14 +275,16 @@ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_add dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int direction) { - struct sbus_iommu *iommu; + struct sbus_info *info; + struct iommu *iommu; iopte_t *base; unsigned long flags, npages, oaddr; unsigned long i, base_paddr; u32 bus_addr, ret; unsigned long iopte_protection; - iommu = sdev->bus->iommu; + info = sdev->bus->iommu; + iommu = &info->iommu; if (unlikely(direction == SBUS_DMA_NONE)) BUG(); @@ -302,7 +300,7 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire if (unlikely(!base)) BUG(); - bus_addr = (MAP_BASE + + bus_addr = (iommu->page_table_map_base + ((base - iommu->page_table) << IO_PAGE_SHIFT)); ret = bus_addr | (oaddr & ~IO_PAGE_MASK); base_paddr = __pa(oaddr & IO_PAGE_MASK); @@ -319,7 +317,9 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct sbus_iommu *iommu = sdev->bus->iommu; + struct sbus_info *info = sdev->bus->iommu; + struct iommu *iommu = &info->iommu; + struct strbuf *strbuf = &info->strbuf; iopte_t *base; unsigned long flags, npages, i; @@ -329,15 +329,15 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, in npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; base = iommu->page_table + - ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT); + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); bus_addr &= IO_PAGE_MASK; spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, bus_addr, npages, direction); + sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); for (i = 0; i < npages; i++) iopte_val(base[i]) = 0UL; - free_npages(iommu, bus_addr - MAP_BASE, npages); + free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -419,7 +419,8 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction) { - struct sbus_iommu *iommu; + struct sbus_info *info; + struct iommu *iommu; unsigned long flags, npages, iopte_protection; iopte_t *base; u32 dma_base; @@ -436,7 +437,8 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i return 1; } - iommu = sdev->bus->iommu; + info = sdev->bus->iommu; + iommu = &info->iommu; if (unlikely(direction == SBUS_DMA_NONE)) BUG(); @@ -450,7 +452,7 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i if (unlikely(base == NULL)) BUG(); - dma_base = MAP_BASE + + dma_base = iommu->page_table_map_base + ((base - iommu->page_table) << IO_PAGE_SHIFT); /* Normalize DVMA addresses. */ @@ -479,7 +481,9 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction) { - struct sbus_iommu *iommu; + struct sbus_info *info; + struct iommu *iommu; + struct strbuf *strbuf; iopte_t *base; unsigned long flags, i, npages; u32 bus_addr; @@ -487,7 +491,9 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems if (unlikely(direction == SBUS_DMA_NONE)) BUG(); - iommu = sdev->bus->iommu; + info = sdev->bus->iommu; + iommu = &info->iommu; + strbuf = &info->strbuf; bus_addr = sglist->dma_address & IO_PAGE_MASK; @@ -499,29 +505,33 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems bus_addr) >> IO_PAGE_SHIFT; base = iommu->page_table + - ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT); + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, bus_addr, npages, direction); + sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); for (i = 0; i < npages; i++) iopte_val(base[i]) = 0UL; - free_npages(iommu, bus_addr - MAP_BASE, npages); + free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); spin_unlock_irqrestore(&iommu->lock, flags); } void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct sbus_iommu *iommu; + struct sbus_info *info; + struct iommu *iommu; + struct strbuf *strbuf; unsigned long flags, npages; - iommu = sdev->bus->iommu; + info = sdev->bus->iommu; + iommu = &info->iommu; + strbuf = &info->strbuf; npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; bus_addr &= IO_PAGE_MASK; spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, bus_addr, npages, direction); + sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -531,11 +541,15 @@ void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, siz void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction) { - struct sbus_iommu *iommu; + struct sbus_info *info; + struct iommu *iommu; + struct strbuf *strbuf; unsigned long flags, npages, i; u32 bus_addr; - iommu = sdev->bus->iommu; + info = sdev->bus->iommu; + iommu = &info->iommu; + strbuf = &info->strbuf; bus_addr = sglist[0].dma_address & IO_PAGE_MASK; for (i = 0; i < nelems; i++) { @@ -547,7 +561,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, - bus_addr) >> IO_PAGE_SHIFT; spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, bus_addr, npages, direction); + sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -558,12 +572,13 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, /* Enable 64-bit DVMA mode for the given device. */ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) { - struct sbus_iommu *iommu = sdev->bus->iommu; + struct sbus_info *info = sdev->bus->iommu; + struct iommu *iommu = &info->iommu; int slot = sdev->slot; unsigned long cfg_reg; u64 val; - cfg_reg = iommu->sbus_control_reg; + cfg_reg = iommu->write_complete_reg; switch (slot) { case 0: cfg_reg += 0x20UL; @@ -698,8 +713,9 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap) unsigned int sbus_build_irq(void *buscookie, unsigned int ino) { struct sbus_bus *sbus = (struct sbus_bus *)buscookie; - struct sbus_iommu *iommu = sbus->iommu; - unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; + struct sbus_info *info = sbus->iommu; + struct iommu *iommu = &info->iommu; + unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned long imap, iclr; int sbus_level = 0; @@ -760,8 +776,9 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) static irqreturn_t sysio_ue_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; - struct sbus_iommu *iommu = sbus->iommu; - unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; + struct sbus_info *info = sbus->iommu; + struct iommu *iommu = &info->iommu; + unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; int reported; @@ -832,8 +849,9 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id) static irqreturn_t sysio_ce_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; - struct sbus_iommu *iommu = sbus->iommu; - unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; + struct sbus_info *info = sbus->iommu; + struct iommu *iommu = &info->iommu; + unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; int reported; @@ -909,12 +927,13 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id) static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; - struct sbus_iommu *iommu = sbus->iommu; + struct sbus_info *info = sbus->iommu; + struct iommu *iommu = &info->iommu; unsigned long afsr_reg, afar_reg, reg_base; unsigned long afsr, afar, error_bits; int reported; - reg_base = iommu->sbus_control_reg - 0x2000UL; + reg_base = iommu->write_complete_reg - 0x2000UL; afsr_reg = reg_base + SYSIO_SBUS_AFSR; afar_reg = reg_base + SYSIO_SBUS_AFAR; @@ -976,8 +995,9 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) static void __init sysio_register_error_handlers(struct sbus_bus *sbus) { - struct sbus_iommu *iommu = sbus->iommu; - unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; + struct sbus_info *info = sbus->iommu; + struct iommu *iommu = &info->iommu; + unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned int irq; u64 control; @@ -1011,9 +1031,9 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus) SYSIO_ECNTRL_CEEN), reg_base + ECC_CONTROL); - control = upa_readq(iommu->sbus_control_reg); + control = upa_readq(iommu->write_complete_reg); control |= 0x100UL; /* SBUS Error Interrupt Enable */ - upa_writeq(control, iommu->sbus_control_reg); + upa_writeq(control, iommu->write_complete_reg); } /* Boot time initialization. */ @@ -1021,8 +1041,10 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) { const struct linux_prom64_registers *pr; struct device_node *dp; - struct sbus_iommu *iommu; - unsigned long regs; + struct sbus_info *info; + struct iommu *iommu; + struct strbuf *strbuf; + unsigned long regs, reg_base; u64 control; int i; @@ -1037,33 +1059,42 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) } regs = pr->phys_addr; - iommu = kmalloc(sizeof(*iommu) + SMP_CACHE_BYTES, GFP_ATOMIC); - if (iommu == NULL) { - prom_printf("sbus_iommu_init: Fatal error, kmalloc(iommu) failed\n"); + info = kzalloc(sizeof(*info), GFP_ATOMIC); + if (info == NULL) { + prom_printf("sbus_iommu_init: Fatal error, " + "kmalloc(info) failed\n"); prom_halt(); } - /* Align on E$ line boundary. */ - iommu = (struct sbus_iommu *) - (((unsigned long)iommu + (SMP_CACHE_BYTES - 1UL)) & - ~(SMP_CACHE_BYTES - 1UL)); + iommu = &info->iommu; + strbuf = &info->strbuf; - memset(iommu, 0, sizeof(*iommu)); + reg_base = regs + SYSIO_IOMMUREG_BASE; + iommu->iommu_control = reg_base + IOMMU_CONTROL; + iommu->iommu_tsbbase = reg_base + IOMMU_TSBBASE; + iommu->iommu_flush = reg_base + IOMMU_FLUSH; - /* Setup spinlock. */ - spin_lock_init(&iommu->lock); + reg_base = regs + SYSIO_STRBUFREG_BASE; + strbuf->strbuf_control = reg_base + STRBUF_CONTROL; + strbuf->strbuf_pflush = reg_base + STRBUF_PFLUSH; + strbuf->strbuf_fsync = reg_base + STRBUF_FSYNC; + + strbuf->strbuf_enabled = 1; - /* Init register offsets. */ - iommu->iommu_regs = regs + SYSIO_IOMMUREG_BASE; - iommu->strbuf_regs = regs + SYSIO_STRBUFREG_BASE; + strbuf->strbuf_flushflag = (volatile unsigned long *) + ((((unsigned long)&strbuf->__flushflag_buf[0]) + + 63UL) + & ~63UL); + strbuf->strbuf_flushflag_pa = (unsigned long) + __pa(strbuf->strbuf_flushflag); /* The SYSIO SBUS control register is used for dummy reads * in order to ensure write completion. */ - iommu->sbus_control_reg = regs + 0x2000UL; + iommu->write_complete_reg = regs + 0x2000UL; /* Link into SYSIO software state. */ - sbus->iommu = iommu; + sbus->iommu = info; printk("SYSIO: UPA portID %x, at %016lx\n", sbus->portid, regs); @@ -1071,40 +1102,44 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */ sbus_iommu_table_init(iommu, IO_TSB_SIZE); - control = upa_readq(iommu->iommu_regs + IOMMU_CONTROL); + control = upa_readq(iommu->iommu_control); control = ((7UL << 16UL) | (0UL << 2UL) | (1UL << 1UL) | (1UL << 0UL)); - upa_writeq(control, iommu->iommu_regs + IOMMU_CONTROL); + upa_writeq(control, iommu->iommu_control); /* Clean out any cruft in the IOMMU using * diagnostic accesses. */ for (i = 0; i < 16; i++) { - unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG; - unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG; + unsigned long dram, tag; + + dram = iommu->iommu_control + (IOMMU_DRAMDIAG - IOMMU_CONTROL); + tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL); dram += (unsigned long)i * 8UL; tag += (unsigned long)i * 8UL; upa_writeq(0, dram); upa_writeq(0, tag); } - upa_readq(iommu->sbus_control_reg); + upa_readq(iommu->write_complete_reg); /* Give the TSB to SYSIO. */ - upa_writeq(__pa(iommu->page_table), iommu->iommu_regs + IOMMU_TSBBASE); + upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase); /* Setup streaming buffer, DE=1 SB_EN=1 */ control = (1UL << 1UL) | (1UL << 0UL); - upa_writeq(control, iommu->strbuf_regs + STRBUF_CONTROL); + upa_writeq(control, strbuf->strbuf_control); /* Clear out the tags using diagnostics. */ for (i = 0; i < 16; i++) { unsigned long ptag, ltag; - ptag = iommu->strbuf_regs + STRBUF_PTAGDIAG; - ltag = iommu->strbuf_regs + STRBUF_LTAGDIAG; + ptag = strbuf->strbuf_control + + (STRBUF_PTAGDIAG - STRBUF_CONTROL); + ltag = strbuf->strbuf_control + + (STRBUF_LTAGDIAG - STRBUF_CONTROL); ptag += (unsigned long)i * 8UL; ltag += (unsigned long)i * 8UL; @@ -1113,9 +1148,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) } /* Enable DVMA arbitration for all devices/slots. */ - control = upa_readq(iommu->sbus_control_reg); + control = upa_readq(iommu->write_complete_reg); control |= 0x3fUL; - upa_writeq(control, iommu->sbus_control_reg); + upa_writeq(control, iommu->write_complete_reg); /* Now some Xfire specific grot... */ if (this_is_starfire) -- cgit v1.2.3 From ee5ac9ddf2ea13be2418ac7d0ce5a930e78af013 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 26 Apr 2007 00:03:53 -0700 Subject: [SPARC]: device_node name constification fallout A couple of routines need their arguments to be const. Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- arch/sparc/kernel/ebus.c | 4 ++-- arch/sparc/kernel/pcic.c | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c index 7724e206715..7bb86b9cdaa 100644 --- a/arch/sparc/kernel/ebus.c +++ b/arch/sparc/kernel/ebus.c @@ -25,7 +25,7 @@ struct linux_ebus *ebus_chain = NULL; /* We are together with pcic.c under CONFIG_PCI. */ -extern unsigned int pcic_pin_to_irq(unsigned int, char *name); +extern unsigned int pcic_pin_to_irq(unsigned int, const char *name); /* * IRQ Blacklist @@ -69,7 +69,7 @@ static inline unsigned long ebus_alloc(size_t size) /* */ -int __init ebus_blacklist_irq(char *name) +int __init ebus_blacklist_irq(const char *name) { struct ebus_device_irq *dp; diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 1c927c538b8..5ca7e8f42bd 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -37,8 +37,6 @@ #include -unsigned int pcic_pin_to_irq(unsigned int pin, char *name); - /* * I studied different documents and many live PROMs both from 2.30 * family and 3.xx versions. I came to the amazing conclusion: there is @@ -681,7 +679,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) * pcic_pin_to_irq() is exported to ebus.c. */ unsigned int -pcic_pin_to_irq(unsigned int pin, char *name) +pcic_pin_to_irq(unsigned int pin, const char *name) { struct linux_pcic *pcic = &pcic0; unsigned int irq; -- cgit v1.2.3 From 16ce82d846f2e6b652a064f91c5019cfe8682be4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 26 Apr 2007 21:08:21 -0700 Subject: [SPARC64]: Convert PCI over to generic struct iommu/strbuf. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_iommu.c | 53 ++++++++++++----------- arch/sparc64/kernel/pci_psycho.c | 10 ++--- arch/sparc64/kernel/pci_sabre.c | 11 +++-- arch/sparc64/kernel/pci_schizo.c | 12 +++--- arch/sparc64/kernel/pci_sun4v.c | 34 +++++++-------- include/asm-sparc64/pbm.h | 90 ++++------------------------------------ 6 files changed, 66 insertions(+), 144 deletions(-) diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 355ed0ba937..66712772f49 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -1,7 +1,6 @@ -/* $Id: pci_iommu.c,v 1.17 2001/12/17 07:05:09 davem Exp $ - * pci_iommu.c: UltraSparc PCI controller IOM/STC support. +/* pci_iommu.c: UltraSparc PCI controller IOM/STC support. * - * Copyright (C) 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) * Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com) */ @@ -36,7 +35,7 @@ "i" (ASI_PHYS_BYPASS_EC_E)) /* Must be invoked under the IOMMU lock. */ -static void __iommu_flushall(struct pci_iommu *iommu) +static void __iommu_flushall(struct iommu *iommu) { unsigned long tag; int entry; @@ -64,7 +63,7 @@ static void __iommu_flushall(struct pci_iommu *iommu) #define IOPTE_IS_DUMMY(iommu, iopte) \ ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa) -static inline void iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte) +static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte) { unsigned long val = iopte_val(*iopte); @@ -75,7 +74,7 @@ static inline void iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte) } /* Based largely upon the ppc64 iommu allocator. */ -static long pci_arena_alloc(struct pci_iommu *iommu, unsigned long npages) +static long pci_arena_alloc(struct iommu *iommu, unsigned long npages) { struct iommu_arena *arena = &iommu->arena; unsigned long n, i, start, end, limit; @@ -124,7 +123,7 @@ static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsign __clear_bit(i, arena->map); } -void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask) +void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask) { unsigned long i, tsbbase, order, sz, num_tsb_entries; @@ -170,7 +169,7 @@ void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, iopte_make_dummy(iommu, &iommu->page_table[i]); } -static inline iopte_t *alloc_npages(struct pci_iommu *iommu, unsigned long npages) +static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) { long entry; @@ -181,12 +180,12 @@ static inline iopte_t *alloc_npages(struct pci_iommu *iommu, unsigned long npage return iommu->page_table + entry; } -static inline void free_npages(struct pci_iommu *iommu, dma_addr_t base, unsigned long npages) +static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages) { pci_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); } -static int iommu_alloc_ctx(struct pci_iommu *iommu) +static int iommu_alloc_ctx(struct iommu *iommu) { int lowest = iommu->ctx_lowest_free; int sz = IOMMU_NUM_CTXS - lowest; @@ -205,7 +204,7 @@ static int iommu_alloc_ctx(struct pci_iommu *iommu) return n; } -static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx) +static inline void iommu_free_ctx(struct iommu *iommu, int ctx) { if (likely(ctx)) { __clear_bit(ctx, iommu->ctx_bitmap); @@ -220,7 +219,7 @@ static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx) */ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { - struct pci_iommu *iommu; + struct iommu *iommu; iopte_t *iopte; unsigned long flags, order, first_page; void *ret; @@ -266,7 +265,7 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr /* Free and unmap a consistent DMA translation. */ static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) { - struct pci_iommu *iommu; + struct iommu *iommu; iopte_t *iopte; unsigned long flags, order, npages; @@ -291,8 +290,8 @@ static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, */ static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) { - struct pci_iommu *iommu; - struct pci_strbuf *strbuf; + struct iommu *iommu; + struct strbuf *strbuf; iopte_t *base; unsigned long flags, npages, oaddr; unsigned long i, base_paddr, ctx; @@ -343,7 +342,7 @@ bad_no_ctx: return PCI_DMA_ERROR_CODE; } -static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction) +static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction) { int limit; @@ -410,8 +409,8 @@ do_flush_sync: /* Unmap a single streaming mode DMA translation. */ static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct pci_iommu *iommu; - struct pci_strbuf *strbuf; + struct iommu *iommu; + struct strbuf *strbuf; iopte_t *base; unsigned long flags, npages, ctx, i; @@ -541,8 +540,8 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, */ static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pci_iommu *iommu; - struct pci_strbuf *strbuf; + struct iommu *iommu; + struct strbuf *strbuf; unsigned long flags, ctx, npages, iopte_protection; iopte_t *base; u32 dma_base; @@ -626,8 +625,8 @@ bad_no_ctx: /* Unmap a set of streaming mode DMA translations. */ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pci_iommu *iommu; - struct pci_strbuf *strbuf; + struct iommu *iommu; + struct strbuf *strbuf; iopte_t *base; unsigned long flags, ctx, i, npages; u32 bus_addr; @@ -684,8 +683,8 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in */ static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct pci_iommu *iommu; - struct pci_strbuf *strbuf; + struct iommu *iommu; + struct strbuf *strbuf; unsigned long flags, ctx, npages; iommu = pdev->dev.archdata.iommu; @@ -722,8 +721,8 @@ static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_ */ static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pci_iommu *iommu; - struct pci_strbuf *strbuf; + struct iommu *iommu; + struct strbuf *strbuf; unsigned long flags, ctx, npages, i; u32 bus_addr; @@ -798,7 +797,7 @@ int pci_dma_supported(struct pci_dev *pdev, u64 device_mask) if (pdev == NULL) { dma_addr_mask = 0xffffffff; } else { - struct pci_iommu *iommu = pdev->dev.archdata.iommu; + struct iommu *iommu = pdev->dev.archdata.iommu; dma_addr_mask = iommu->dma_addr_mask; diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 3725910c8b2..253d40ec224 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -269,7 +269,7 @@ static void __psycho_check_one_stc(struct pci_controller_info *p, struct pci_pbm_info *pbm, int is_pbm_a) { - struct pci_strbuf *strbuf = &pbm->stc; + struct strbuf *strbuf = &pbm->stc; unsigned long regbase = p->pbm_A.controller_regs; unsigned long err_base, tag_base, line_base; u64 control; @@ -418,7 +418,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p, unsigned long afar, enum psycho_error_type type) { - struct pci_iommu *iommu = p->pbm_A.iommu; + struct iommu *iommu = p->pbm_A.iommu; unsigned long iommu_tag[16]; unsigned long iommu_data[16]; unsigned long flags; @@ -941,7 +941,7 @@ static void psycho_scan_bus(struct pci_controller_info *p) static void psycho_iommu_init(struct pci_controller_info *p) { - struct pci_iommu *iommu = p->pbm_A.iommu; + struct iommu *iommu = p->pbm_A.iommu; unsigned long i; u64 control; @@ -1131,7 +1131,7 @@ void psycho_init(struct device_node *dp, char *model_name) { struct linux_prom64_registers *pr_regs; struct pci_controller_info *p; - struct pci_iommu *iommu; + struct iommu *iommu; struct property *prop; u32 upa_portid; int is_pbm_a; @@ -1154,7 +1154,7 @@ void psycho_init(struct device_node *dp, char *model_name) prom_printf("PSYCHO: Fatal memory allocation error.\n"); prom_halt(); } - iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); if (!iommu) { prom_printf("PSYCHO: Fatal memory allocation error.\n"); prom_halt(); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 9a2ce0637c8..397862fbd9e 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1,7 +1,6 @@ -/* $Id: pci_sabre.c,v 1.42 2002/01/23 11:27:32 davem Exp $ - * pci_sabre.c: Sabre specific PCI controller support. +/* pci_sabre.c: Sabre specific PCI controller support. * - * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ @@ -499,7 +498,7 @@ static void sabre_check_iommu_error(struct pci_controller_info *p, unsigned long afsr, unsigned long afar) { - struct pci_iommu *iommu = p->pbm_A.iommu; + struct iommu *iommu = p->pbm_A.iommu; unsigned long iommu_tag[16]; unsigned long iommu_data[16]; unsigned long flags; @@ -948,7 +947,7 @@ static void sabre_iommu_init(struct pci_controller_info *p, int tsbsize, unsigned long dvma_offset, u32 dma_mask) { - struct pci_iommu *iommu = p->pbm_A.iommu; + struct iommu *iommu = p->pbm_A.iommu; unsigned long i; u64 control; @@ -1017,7 +1016,7 @@ void sabre_init(struct device_node *dp, char *model_name) { const struct linux_prom64_registers *pr_regs; struct pci_controller_info *p; - struct pci_iommu *iommu; + struct iommu *iommu; int tsbsize; const u32 *busrange; const u32 *vdma; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 47a5aa94dca..91a7385e5d3 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -279,7 +279,7 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino) static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, enum schizo_error_type type) { - struct pci_strbuf *strbuf = &pbm->stc; + struct strbuf *strbuf = &pbm->stc; unsigned long regbase = pbm->pbm_regs; unsigned long err_base, tag_base, line_base; u64 control; @@ -387,7 +387,7 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, enum schizo_error_type type) { - struct pci_iommu *iommu = pbm->iommu; + struct iommu *iommu = pbm->iommu; unsigned long iommu_tag[16]; unsigned long iommu_data[16]; unsigned long flags; @@ -1308,7 +1308,7 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm) static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) { - struct pci_iommu *iommu = pbm->iommu; + struct iommu *iommu = pbm->iommu; unsigned long i, tagbase, database; struct property *prop; u32 vdma[2], dma_mask; @@ -1580,7 +1580,7 @@ static inline int portid_compare(u32 x, u32 y, int chip_type) static void __schizo_init(struct device_node *dp, char *model_name, int chip_type) { struct pci_controller_info *p; - struct pci_iommu *iommu; + struct iommu *iommu; u32 portid; portid = of_getintprop_default(dp, "portid", 0xff); @@ -1605,13 +1605,13 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ if (!p) goto memfail; - iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); if (!iommu) goto memfail; p->pbm_A.iommu = iommu; - iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); if (!iommu) goto memfail; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 0e99808f212..94295c21932 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -29,7 +29,7 @@ #define PGLIST_NENTS (PAGE_SIZE / sizeof(u64)) -struct pci_iommu_batch { +struct iommu_batch { struct pci_dev *pdev; /* Device mapping is for. */ unsigned long prot; /* IOMMU page protections */ unsigned long entry; /* Index into IOTSB. */ @@ -37,12 +37,12 @@ struct pci_iommu_batch { unsigned long npages; /* Number of pages in list. */ }; -static DEFINE_PER_CPU(struct pci_iommu_batch, pci_iommu_batch); +static DEFINE_PER_CPU(struct iommu_batch, pci_iommu_batch); /* Interrupts must be disabled. */ static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long prot, unsigned long entry) { - struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); + struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch); p->pdev = pdev; p->prot = prot; @@ -51,7 +51,7 @@ static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long pro } /* Interrupts must be disabled. */ -static long pci_iommu_batch_flush(struct pci_iommu_batch *p) +static long pci_iommu_batch_flush(struct iommu_batch *p) { struct pci_pbm_info *pbm = p->pdev->dev.archdata.host_controller; unsigned long devhandle = pbm->devhandle; @@ -89,7 +89,7 @@ static long pci_iommu_batch_flush(struct pci_iommu_batch *p) /* Interrupts must be disabled. */ static inline long pci_iommu_batch_add(u64 phys_page) { - struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); + struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch); BUG_ON(p->npages >= PGLIST_NENTS); @@ -103,7 +103,7 @@ static inline long pci_iommu_batch_add(u64 phys_page) /* Interrupts must be disabled. */ static inline long pci_iommu_batch_end(void) { - struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); + struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch); BUG_ON(p->npages >= PGLIST_NENTS); @@ -159,7 +159,7 @@ static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsign static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { - struct pci_iommu *iommu; + struct iommu *iommu; unsigned long flags, order, first_page, npages, n; void *ret; long entry; @@ -225,7 +225,7 @@ arena_alloc_fail: static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) { struct pci_pbm_info *pbm; - struct pci_iommu *iommu; + struct iommu *iommu; unsigned long flags, order, npages, entry; u32 devhandle; @@ -257,7 +257,7 @@ static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) { - struct pci_iommu *iommu; + struct iommu *iommu; unsigned long flags, npages, oaddr; unsigned long i, base_paddr; u32 bus_addr, ret; @@ -321,7 +321,7 @@ iommu_map_fail: static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { struct pci_pbm_info *pbm; - struct pci_iommu *iommu; + struct iommu *iommu; unsigned long flags, npages; long entry; u32 devhandle; @@ -456,7 +456,7 @@ iommu_map_failed: static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pci_iommu *iommu; + struct iommu *iommu; unsigned long flags, npages, prot; u32 dma_base; struct scatterlist *sgtmp; @@ -532,7 +532,7 @@ iommu_map_failed: static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { struct pci_pbm_info *pbm; - struct pci_iommu *iommu; + struct iommu *iommu; unsigned long flags, i, npages; long entry; u32 devhandle, bus_addr; @@ -705,7 +705,7 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p) } static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, - struct pci_iommu *iommu) + struct iommu *iommu) { struct iommu_arena *arena = &iommu->arena; unsigned long i, cnt = 0; @@ -734,7 +734,7 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) { - struct pci_iommu *iommu = pbm->iommu; + struct iommu *iommu = pbm->iommu; struct property *prop; unsigned long num_tsb_entries, sz; u32 vdma[2], dma_mask, dma_offset; @@ -1279,7 +1279,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node void sun4v_pci_init(struct device_node *dp, char *model_name) { struct pci_controller_info *p; - struct pci_iommu *iommu; + struct iommu *iommu; struct property *prop; struct linux_prom64_registers *regs; u32 devhandle; @@ -1319,13 +1319,13 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) if (!p) goto fatal_memory_error; - iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); if (!iommu) goto fatal_memory_error; p->pbm_A.iommu = iommu; - iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); if (!iommu) goto fatal_memory_error; diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 4a0ed2ea950..c008cecca14 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -1,7 +1,6 @@ -/* $Id: pbm.h,v 1.27 2001/08/12 13:18:23 davem Exp $ - * pbm.h: UltraSparc PCI controller software state. +/* pbm.h: UltraSparc PCI controller software state. * - * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net) */ #ifndef __SPARC64_PBM_H @@ -30,84 +29,7 @@ * PCI bus. */ -struct pci_controller_info; - -/* This contains the software state necessary to drive a PCI - * controller's IOMMU. - */ -struct pci_iommu { - /* This protects the controller's IOMMU and all - * streaming buffers underneath. - */ - spinlock_t lock; - - struct iommu_arena arena; - - /* IOMMU page table, a linear array of ioptes. */ - iopte_t *page_table; /* The page table itself. */ - - /* Base PCI memory space address where IOMMU mappings - * begin. - */ - u32 page_table_map_base; - - /* IOMMU Controller Registers */ - unsigned long iommu_control; /* IOMMU control register */ - unsigned long iommu_tsbbase; /* IOMMU page table base register */ - unsigned long iommu_flush; /* IOMMU page flush register */ - unsigned long iommu_ctxflush; /* IOMMU context flush register */ - - /* This is a register in the PCI controller, which if - * read will have no side-effects but will guarantee - * completion of all previous writes into IOMMU/STC. - */ - unsigned long write_complete_reg; - - /* In order to deal with some buggy third-party PCI bridges that - * do wrong prefetching, we never mark valid mappings as invalid. - * Instead we point them at this dummy page. - */ - unsigned long dummy_page; - unsigned long dummy_page_pa; - - /* CTX allocation. */ - unsigned long ctx_lowest_free; - DECLARE_BITMAP(ctx_bitmap, IOMMU_NUM_CTXS); - - /* Here a PCI controller driver describes the areas of - * PCI memory space where DMA to/from physical memory - * are addressed. Drivers interrogate the PCI layer - * if their device has addressing limitations. They - * do so via pci_dma_supported, and pass in a mask of - * DMA address bits their device can actually drive. - * - * The test for being usable is: - * (device_mask & dma_addr_mask) == dma_addr_mask - */ - u32 dma_addr_mask; -}; - -extern void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask); - -/* This describes a PCI bus module's streaming buffer. */ -struct pci_strbuf { - int strbuf_enabled; /* Present and using it? */ - - /* Streaming Buffer Control Registers */ - unsigned long strbuf_control; /* STC control register */ - unsigned long strbuf_pflush; /* STC page flush register */ - unsigned long strbuf_fsync; /* STC flush synchronization reg */ - unsigned long strbuf_ctxflush; /* STC context flush register */ - unsigned long strbuf_ctxmatch_base; /* STC context flush match reg */ - unsigned long strbuf_flushflag_pa; /* Physical address of flush flag */ - volatile unsigned long *strbuf_flushflag; /* The flush flag itself */ - - /* And this is the actual flush flag area. - * We allocate extra because the chips require - * a 64-byte aligned area. - */ - volatile unsigned long __flushflag_buf[(64 + (64 - 1)) / sizeof(long)]; -}; +extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask); #define PCI_STC_FLUSHFLAG_INIT(STC) \ (*((STC)->strbuf_flushflag) = 0UL) @@ -120,6 +42,8 @@ struct pci_strbuf { #define PROM_PCIRNG_MAX 64 #define PROM_PCIIMAP_MAX 64 +struct pci_controller_info; + struct pci_pbm_info { /* PCI controller we sit under. */ struct pci_controller_info *parent; @@ -186,10 +110,10 @@ struct pci_pbm_info { #endif /* !(CONFIG_PCI_MSI) */ /* This PBM's streaming buffer. */ - struct pci_strbuf stc; + struct strbuf stc; /* IOMMU state, potentially shared by both PBM segments. */ - struct pci_iommu *iommu; + struct iommu *iommu; /* Now things for the actual PCI bus probes. */ unsigned int pci_first_busno; -- cgit v1.2.3 From cd9ad58d4061494e7fdd70ded7bcf2418daf356a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 26 Apr 2007 21:19:23 -0700 Subject: [SCSI] SUNESP: Complete driver rewrite to version 2.0 Major features: 1) Tagged queuing support. 2) Will properly negotiate for synchronous transfers even on devices that reject the wide negotiation message, such as CDROMs 3) Significantly lower kernel stack usage in interrupt handler path by elimination of function vector arrays, replaced by a top-level switch statement state machine. 4) Uses generic scsi infrastructure as much as possible to avoid code duplication. 5) Automatic request of sense data in response to CHECK_CONDITION 6) Portable to other platforms using ESP such as DEC and Sun3 systems. Signed-off-by: David S. Miller --- drivers/scsi/Kconfig | 6 + drivers/scsi/Makefile | 3 +- drivers/scsi/esp.c | 4394 ----------------------------------------------- drivers/scsi/esp.h | 406 ----- drivers/scsi/esp_scsi.c | 2710 +++++++++++++++++++++++++++++ drivers/scsi/esp_scsi.h | 560 ++++++ drivers/scsi/sun_esp.c | 634 +++++++ 7 files changed, 3912 insertions(+), 4801 deletions(-) delete mode 100644 drivers/scsi/esp.c delete mode 100644 drivers/scsi/esp.h create mode 100644 drivers/scsi/esp_scsi.c create mode 100644 drivers/scsi/esp_scsi.h create mode 100644 drivers/scsi/sun_esp.c diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 4cd280e8696..fcc4cb6c7f4 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1763,9 +1763,15 @@ config SUN3X_ESP The ESP was an on-board SCSI controller used on Sun 3/80 machines. Say Y here to compile in support for it. +config SCSI_ESP_CORE + tristate "ESP Scsi Driver Core" + depends on SCSI + select SCSI_SPI_ATTRS + config SCSI_SUNESP tristate "Sparc ESP Scsi Driver" depends on SBUS && SCSI + select SCSI_ESP_CORE help This is the driver for the Sun ESP SCSI host adapter. The ESP chipset is present in most SPARC SBUS-based computers. diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 79ecf4ebe6e..70cff4c599d 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -106,7 +106,8 @@ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_MEGARAID_SAS) += megaraid/ obj-$(CONFIG_SCSI_ACARD) += atp870u.o -obj-$(CONFIG_SCSI_SUNESP) += esp.o +obj-$(CONFIG_SCSI_ESP_CORE) += esp_scsi.o +obj-$(CONFIG_SCSI_SUNESP) += sun_esp.o obj-$(CONFIG_SCSI_GDTH) += gdth.o obj-$(CONFIG_SCSI_INITIO) += initio.o obj-$(CONFIG_SCSI_INIA100) += a100u2w.o diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c deleted file mode 100644 index 2c2fe80bc42..00000000000 --- a/drivers/scsi/esp.c +++ /dev/null @@ -1,4394 +0,0 @@ -/* esp.c: ESP Sun SCSI driver. - * - * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net) - */ - -/* TODO: - * - * 1) Maybe disable parity checking in config register one for SCSI1 - * targets. (Gilmore says parity error on the SBus can lock up - * old sun4c's) - * 2) Add support for DMA2 pipelining. - * 3) Add tagged queueing. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "esp.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef __sparc_v9__ -#include -#include -#endif - -#include -#include -#include -#include -#include -#include - -#define DRV_VERSION "1.101" - -#define DEBUG_ESP -/* #define DEBUG_ESP_HME */ -/* #define DEBUG_ESP_DATA */ -/* #define DEBUG_ESP_QUEUE */ -/* #define DEBUG_ESP_DISCONNECT */ -/* #define DEBUG_ESP_STATUS */ -/* #define DEBUG_ESP_PHASES */ -/* #define DEBUG_ESP_WORKBUS */ -/* #define DEBUG_STATE_MACHINE */ -/* #define DEBUG_ESP_CMDS */ -/* #define DEBUG_ESP_IRQS */ -/* #define DEBUG_SDTR */ -/* #define DEBUG_ESP_SG */ - -/* Use the following to sprinkle debugging messages in a way which - * suits you if combinations of the above become too verbose when - * trying to track down a specific problem. - */ -/* #define DEBUG_ESP_MISC */ - -#if defined(DEBUG_ESP) -#define ESPLOG(foo) printk foo -#else -#define ESPLOG(foo) -#endif /* (DEBUG_ESP) */ - -#if defined(DEBUG_ESP_HME) -#define ESPHME(foo) printk foo -#else -#define ESPHME(foo) -#endif - -#if defined(DEBUG_ESP_DATA) -#define ESPDATA(foo) printk foo -#else -#define ESPDATA(foo) -#endif - -#if defined(DEBUG_ESP_QUEUE) -#define ESPQUEUE(foo) printk foo -#else -#define ESPQUEUE(foo) -#endif - -#if defined(DEBUG_ESP_DISCONNECT) -#define ESPDISC(foo) printk foo -#else -#define ESPDISC(foo) -#endif - -#if defined(DEBUG_ESP_STATUS) -#define ESPSTAT(foo) printk foo -#else -#define ESPSTAT(foo) -#endif - -#if defined(DEBUG_ESP_PHASES) -#define ESPPHASE(foo) printk foo -#else -#define ESPPHASE(foo) -#endif - -#if defined(DEBUG_ESP_WORKBUS) -#define ESPBUS(foo) printk foo -#else -#define ESPBUS(foo) -#endif - -#if defined(DEBUG_ESP_IRQS) -#define ESPIRQ(foo) printk foo -#else -#define ESPIRQ(foo) -#endif - -#if defined(DEBUG_SDTR) -#define ESPSDTR(foo) printk foo -#else -#define ESPSDTR(foo) -#endif - -#if defined(DEBUG_ESP_MISC) -#define ESPMISC(foo) printk foo -#else -#define ESPMISC(foo) -#endif - -/* Command phase enumeration. */ -enum { - not_issued = 0x00, /* Still in the issue_SC queue. */ - - /* Various forms of selecting a target. */ -#define in_slct_mask 0x10 - in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */ - in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */ - in_slct_msg = 0x12, /* select, then send a message */ - in_slct_tag = 0x13, /* select and send tagged queue msg */ - in_slct_sneg = 0x14, /* select and acquire sync capabilities */ - - /* Any post selection activity. */ -#define in_phases_mask 0x20 - in_datain = 0x20, /* Data is transferring from the bus */ - in_dataout = 0x21, /* Data is transferring to the bus */ - in_data_done = 0x22, /* Last DMA data operation done (maybe) */ - in_msgin = 0x23, /* Eating message from target */ - in_msgincont = 0x24, /* Eating more msg bytes from target */ - in_msgindone = 0x25, /* Decide what to do with what we got */ - in_msgout = 0x26, /* Sending message to target */ - in_msgoutdone = 0x27, /* Done sending msg out */ - in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */ - in_cmdend = 0x29, /* Done sending slow cmd */ - in_status = 0x2a, /* Was in status phase, finishing cmd */ - in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */ - in_the_dark = 0x2c, /* Don't know what bus phase we are in */ - - /* Special states, ie. not normal bus transitions... */ -#define in_spec_mask 0x80 - in_abortone = 0x80, /* Aborting one command currently */ - in_abortall = 0x81, /* Blowing away all commands we have */ - in_resetdev = 0x82, /* SCSI target reset in progress */ - in_resetbus = 0x83, /* SCSI bus reset in progress */ - in_tgterror = 0x84, /* Target did something stupid */ -}; - -enum { - /* Zero has special meaning, see skipahead[12]. */ -/*0*/ do_never, - -/*1*/ do_phase_determine, -/*2*/ do_reset_bus, -/*3*/ do_reset_complete, -/*4*/ do_work_bus, -/*5*/ do_intr_end -}; - -/* Forward declarations. */ -static irqreturn_t esp_intr(int irq, void *dev_id); - -/* Debugging routines */ -struct esp_cmdstrings { - u8 cmdchar; - char *text; -} esp_cmd_strings[] = { - /* Miscellaneous */ - { ESP_CMD_NULL, "ESP_NOP", }, - { ESP_CMD_FLUSH, "FIFO_FLUSH", }, - { ESP_CMD_RC, "RSTESP", }, - { ESP_CMD_RS, "RSTSCSI", }, - /* Disconnected State Group */ - { ESP_CMD_RSEL, "RESLCTSEQ", }, - { ESP_CMD_SEL, "SLCTNATN", }, - { ESP_CMD_SELA, "SLCTATN", }, - { ESP_CMD_SELAS, "SLCTATNSTOP", }, - { ESP_CMD_ESEL, "ENSLCTRESEL", }, - { ESP_CMD_DSEL, "DISSELRESEL", }, - { ESP_CMD_SA3, "SLCTATN3", }, - { ESP_CMD_RSEL3, "RESLCTSEQ", }, - /* Target State Group */ - { ESP_CMD_SMSG, "SNDMSG", }, - { ESP_CMD_SSTAT, "SNDSTATUS", }, - { ESP_CMD_SDATA, "SNDDATA", }, - { ESP_CMD_DSEQ, "DISCSEQ", }, - { ESP_CMD_TSEQ, "TERMSEQ", }, - { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", }, - { ESP_CMD_DCNCT, "DISC", }, - { ESP_CMD_RMSG, "RCVMSG", }, - { ESP_CMD_RCMD, "RCVCMD", }, - { ESP_CMD_RDATA, "RCVDATA", }, - { ESP_CMD_RCSEQ, "RCVCMDSEQ", }, - /* Initiator State Group */ - { ESP_CMD_TI, "TRANSINFO", }, - { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", }, - { ESP_CMD_MOK, "MSGACCEPTED", }, - { ESP_CMD_TPAD, "TPAD", }, - { ESP_CMD_SATN, "SATN", }, - { ESP_CMD_RATN, "RATN", }, -}; -#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings))) - -/* Print textual representation of an ESP command */ -static inline void esp_print_cmd(u8 espcmd) -{ - u8 dma_bit = espcmd & ESP_CMD_DMA; - int i; - - espcmd &= ~dma_bit; - for (i = 0; i < NUM_ESP_COMMANDS; i++) - if (esp_cmd_strings[i].cmdchar == espcmd) - break; - if (i == NUM_ESP_COMMANDS) - printk("ESP_Unknown"); - else - printk("%s%s", esp_cmd_strings[i].text, - ((dma_bit) ? "+DMA" : "")); -} - -/* Print the status register's value */ -static inline void esp_print_statreg(u8 statreg) -{ - u8 phase; - - printk("STATUS<"); - phase = statreg & ESP_STAT_PMASK; - printk("%s,", (phase == ESP_DOP ? "DATA-OUT" : - (phase == ESP_DIP ? "DATA-IN" : - (phase == ESP_CMDP ? "COMMAND" : - (phase == ESP_STATP ? "STATUS" : - (phase == ESP_MOP ? "MSG-OUT" : - (phase == ESP_MIP ? "MSG_IN" : - "unknown"))))))); - if (statreg & ESP_STAT_TDONE) - printk("TRANS_DONE,"); - if (statreg & ESP_STAT_TCNT) - printk("TCOUNT_ZERO,"); - if (statreg & ESP_STAT_PERR) - printk("P_ERROR,"); - if (statreg & ESP_STAT_SPAM) - printk("SPAM,"); - if (statreg & ESP_STAT_INTR) - printk("IRQ,"); - printk(">"); -} - -/* Print the interrupt register's value */ -static inline void esp_print_ireg(u8 intreg) -{ - printk("INTREG< "); - if (intreg & ESP_INTR_S) - printk("SLCT_NATN "); - if (intreg & ESP_INTR_SATN) - printk("SLCT_ATN "); - if (intreg & ESP_INTR_RSEL) - printk("RSLCT "); - if (intreg & ESP_INTR_FDONE) - printk("FDONE "); - if (intreg & ESP_INTR_BSERV) - printk("BSERV "); - if (intreg & ESP_INTR_DC) - printk("DISCNCT "); - if (intreg & ESP_INTR_IC) - printk("ILL_CMD "); - if (intreg & ESP_INTR_SR) - printk("SCSI_BUS_RESET "); - printk(">"); -} - -/* Print the sequence step registers contents */ -static inline void esp_print_seqreg(u8 stepreg) -{ - stepreg &= ESP_STEP_VBITS; - printk("STEP<%s>", - (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" : - (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" : - (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" : - (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" : - (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" : - "UNKNOWN")))))); -} - -static char *phase_string(int phase) -{ - switch (phase) { - case not_issued: - return "UNISSUED"; - case in_slct_norm: - return "SLCTNORM"; - case in_slct_stop: - return "SLCTSTOP"; - case in_slct_msg: - return "SLCTMSG"; - case in_slct_tag: - return "SLCTTAG"; - case in_slct_sneg: - return "SLCTSNEG"; - case in_datain: - return "DATAIN"; - case in_dataout: - return "DATAOUT"; - case in_data_done: - return "DATADONE"; - case in_msgin: - return "MSGIN"; - case in_msgincont: - return "MSGINCONT"; - case in_msgindone: - return "MSGINDONE"; - case in_msgout: - return "MSGOUT"; - case in_msgoutdone: - return "MSGOUTDONE"; - case in_cmdbegin: - return "CMDBEGIN"; - case in_cmdend: - return "CMDEND"; - case in_status: - return "STATUS"; - case in_freeing: - return "FREEING"; - case in_the_dark: - return "CLUELESS"; - case in_abortone: - return "ABORTONE"; - case in_abortall: - return "ABORTALL"; - case in_resetdev: - return "RESETDEV"; - case in_resetbus: - return "RESETBUS"; - case in_tgterror: - return "TGTERROR"; - default: - return "UNKNOWN"; - }; -} - -#ifdef DEBUG_STATE_MACHINE -static inline void esp_advance_phase(struct scsi_cmnd *s, int newphase) -{ - ESPLOG(("<%s>", phase_string(newphase))); - s->SCp.sent_command = s->SCp.phase; - s->SCp.phase = newphase; -} -#else -#define esp_advance_phase(__s, __newphase) \ - (__s)->SCp.sent_command = (__s)->SCp.phase; \ - (__s)->SCp.phase = (__newphase); -#endif - -#ifdef DEBUG_ESP_CMDS -static inline void esp_cmd(struct esp *esp, u8 cmd) -{ - esp->espcmdlog[esp->espcmdent] = cmd; - esp->espcmdent = (esp->espcmdent + 1) & 31; - sbus_writeb(cmd, esp->eregs + ESP_CMD); -} -#else -#define esp_cmd(__esp, __cmd) \ - sbus_writeb((__cmd), ((__esp)->eregs) + ESP_CMD) -#endif - -#define ESP_INTSOFF(__dregs) \ - sbus_writel(sbus_readl((__dregs)+DMA_CSR)&~(DMA_INT_ENAB), (__dregs)+DMA_CSR) -#define ESP_INTSON(__dregs) \ - sbus_writel(sbus_readl((__dregs)+DMA_CSR)|DMA_INT_ENAB, (__dregs)+DMA_CSR) -#define ESP_IRQ_P(__dregs) \ - (sbus_readl((__dregs)+DMA_CSR) & (DMA_HNDL_INTR|DMA_HNDL_ERROR)) - -/* How we use the various Linux SCSI data structures for operation. - * - * struct scsi_cmnd: - * - * We keep track of the synchronous capabilities of a target - * in the device member, using sync_min_period and - * sync_max_offset. These are the values we directly write - * into the ESP registers while running a command. If offset - * is zero the ESP will use asynchronous transfers. - * If the borken flag is set we assume we shouldn't even bother - * trying to negotiate for synchronous transfer as this target - * is really stupid. If we notice the target is dropping the - * bus, and we have been allowing it to disconnect, we clear - * the disconnect flag. - */ - - -/* Manipulation of the ESP command queues. Thanks to the aha152x driver - * and its author, Juergen E. Fischer, for the methods used here. - * Note that these are per-ESP queues, not global queues like - * the aha152x driver uses. - */ -static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC) -{ - struct scsi_cmnd *end; - - new_SC->host_scribble = (unsigned char *) NULL; - if (!*SC) - *SC = new_SC; - else { - for (end=*SC;end->host_scribble;end=(struct scsi_cmnd *)end->host_scribble) - ; - end->host_scribble = (unsigned char *) new_SC; - } -} - -static inline void prepend_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC) -{ - new_SC->host_scribble = (unsigned char *) *SC; - *SC = new_SC; -} - -static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd **SC) -{ - struct scsi_cmnd *ptr; - ptr = *SC; - if (ptr) - *SC = (struct scsi_cmnd *) (*SC)->host_scribble; - return ptr; -} - -static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, int target, int lun) -{ - struct scsi_cmnd *ptr, *prev; - - for (ptr = *SC, prev = NULL; - ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); - prev = ptr, ptr = (struct scsi_cmnd *) ptr->host_scribble) - ; - if (ptr) { - if (prev) - prev->host_scribble=ptr->host_scribble; - else - *SC=(struct scsi_cmnd *)ptr->host_scribble; - } - return ptr; -} - -/* Resetting various pieces of the ESP scsi driver chipset/buses. */ -static void esp_reset_dma(struct esp *esp) -{ - int can_do_burst16, can_do_burst32, can_do_burst64; - int can_do_sbus64; - u32 tmp; - - can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; - can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; - can_do_burst64 = 0; - can_do_sbus64 = 0; - if (sbus_can_dma_64bit(esp->sdev)) - can_do_sbus64 = 1; - if (sbus_can_burst64(esp->sdev)) - can_do_burst64 = (esp->bursts & DMA_BURST64) != 0; - - /* Punt the DVMA into a known state. */ - if (esp->dma->revision != dvmahme) { - tmp = sbus_readl(esp->dregs + DMA_CSR); - sbus_writel(tmp | DMA_RST_SCSI, esp->dregs + DMA_CSR); - sbus_writel(tmp & ~DMA_RST_SCSI, esp->dregs + DMA_CSR); - } - switch (esp->dma->revision) { - case dvmahme: - /* This is the HME DVMA gate array. */ - - sbus_writel(DMA_RESET_FAS366, esp->dregs + DMA_CSR); - sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR); - - esp->prev_hme_dmacsr = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB); - esp->prev_hme_dmacsr &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ); - - if (can_do_burst64) - esp->prev_hme_dmacsr |= DMA_BRST64; - else if (can_do_burst32) - esp->prev_hme_dmacsr |= DMA_BRST32; - - if (can_do_sbus64) { - esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; - sbus_set_sbus64(esp->sdev, esp->bursts); - } - - /* This chip is horrible. */ - while (sbus_readl(esp->dregs + DMA_CSR) & DMA_PEND_READ) - udelay(1); - - sbus_writel(0, esp->dregs + DMA_CSR); - sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); - - /* This is necessary to avoid having the SCSI channel - * engine lock up on us. - */ - sbus_writel(0, esp->dregs + DMA_ADDR); - - break; - case dvmarev2: - /* This is the gate array found in the sun4m - * NCR SBUS I/O subsystem. - */ - if (esp->erev != esp100) { - tmp = sbus_readl(esp->dregs + DMA_CSR); - sbus_writel(tmp | DMA_3CLKS, esp->dregs + DMA_CSR); - } - break; - case dvmarev3: - tmp = sbus_readl(esp->dregs + DMA_CSR); - tmp &= ~DMA_3CLKS; - tmp |= DMA_2CLKS; - if (can_do_burst32) { - tmp &= ~DMA_BRST_SZ; - tmp |= DMA_BRST32; - } - sbus_writel(tmp, esp->dregs + DMA_CSR); - break; - case dvmaesc1: - /* This is the DMA unit found on SCSI/Ether cards. */ - tmp = sbus_readl(esp->dregs + DMA_CSR); - tmp |= DMA_ADD_ENABLE; - tmp &= ~DMA_BCNT_ENAB; - if (!can_do_burst32 && can_do_burst16) { - tmp |= DMA_ESC_BURST; - } else { - tmp &= ~(DMA_ESC_BURST); - } - sbus_writel(tmp, esp->dregs + DMA_CSR); - break; - default: - break; - }; - ESP_INTSON(esp->dregs); -} - -/* Reset the ESP chip, _not_ the SCSI bus. */ -static void __init esp_reset_esp(struct esp *esp) -{ - u8 family_code, version; - int i; - - /* Now reset the ESP chip */ - esp_cmd(esp, ESP_CMD_RC); - esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); - esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); - - /* Reload the configuration registers */ - sbus_writeb(esp->cfact, esp->eregs + ESP_CFACT); - esp->prev_stp = 0; - sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); - esp->prev_soff = 0; - sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); - sbus_writeb(esp->neg_defp, esp->eregs + ESP_TIMEO); - - /* This is the only point at which it is reliable to read - * the ID-code for a fast ESP chip variants. - */ - esp->max_period = ((35 * esp->ccycle) / 1000); - if (esp->erev == fast) { - version = sbus_readb(esp->eregs + ESP_UID); - family_code = (version & 0xf8) >> 3; - if (family_code == 0x02) - esp->erev = fas236; - else if (family_code == 0x0a) - esp->erev = fashme; /* Version is usually '5'. */ - else - esp->erev = fas100a; - ESPMISC(("esp%d: FAST chip is %s (family=%d, version=%d)\n", - esp->esp_id, - (esp->erev == fas236) ? "fas236" : - ((esp->erev == fas100a) ? "fas100a" : - "fasHME"), family_code, (version & 7))); - - esp->min_period = ((4 * esp->ccycle) / 1000); - } else { - esp->min_period = ((5 * esp->ccycle) / 1000); - } - esp->max_period = (esp->max_period + 3)>>2; - esp->min_period = (esp->min_period + 3)>>2; - - sbus_writeb(esp->config1, esp->eregs + ESP_CFG1); - switch (esp->erev) { - case esp100: - /* nothing to do */ - break; - case esp100a: - sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); - break; - case esp236: - /* Slow 236 */ - sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); - esp->prev_cfg3 = esp->config3[0]; - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - break; - case fashme: - esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB); - /* fallthrough... */ - case fas236: - /* Fast 236 or HME */ - sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); - for (i = 0; i < 16; i++) { - if (esp->erev == fashme) { - u8 cfg3; - - cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH; - if (esp->scsi_id >= 8) - cfg3 |= ESP_CONFIG3_IDBIT3; - esp->config3[i] |= cfg3; - } else { - esp->config3[i] |= ESP_CONFIG3_FCLK; - } - } - esp->prev_cfg3 = esp->config3[0]; - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - if (esp->erev == fashme) { - esp->radelay = 80; - } else { - if (esp->diff) - esp->radelay = 0; - else - esp->radelay = 96; - } - break; - case fas100a: - /* Fast 100a */ - sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); - for (i = 0; i < 16; i++) - esp->config3[i] |= ESP_CONFIG3_FCLOCK; - esp->prev_cfg3 = esp->config3[0]; - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - esp->radelay = 32; - break; - default: - panic("esp: what could it be... I wonder..."); - break; - }; - - /* Eat any bitrot in the chip */ - sbus_readb(esp->eregs + ESP_INTRPT); - udelay(100); -} - -/* This places the ESP into a known state at boot time. */ -static void __init esp_bootup_reset(struct esp *esp) -{ - u8 tmp; - - /* Reset the DMA */ - esp_reset_dma(esp); - - /* Reset the ESP */ - esp_reset_esp(esp); - - /* Reset the SCSI bus, but tell ESP not to generate an irq */ - tmp = sbus_readb(esp->eregs + ESP_CFG1); - tmp |= ESP_CONFIG1_SRRDISAB; - sbus_writeb(tmp, esp->eregs + ESP_CFG1); - - esp_cmd(esp, ESP_CMD_RS); - udelay(400); - - sbus_writeb(esp->config1, esp->eregs + ESP_CFG1); - - /* Eat any bitrot in the chip and we are done... */ - sbus_readb(esp->eregs + ESP_INTRPT); -} - -static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev) -{ - struct sbus_dev *sdev = esp->sdev; - struct sbus_dma *dma; - - if (dma_sdev != NULL) { - for_each_dvma(dma) { - if (dma->sdev == dma_sdev) - break; - } - } else { - for_each_dvma(dma) { - /* If allocated already, can't use it. */ - if (dma->allocated) - continue; - - if (dma->sdev == NULL) - break; - - /* If bus + slot are the same and it has the - * correct OBP name, it's ours. - */ - if (sdev->bus == dma->sdev->bus && - sdev->slot == dma->sdev->slot && - (!strcmp(dma->sdev->prom_name, "dma") || - !strcmp(dma->sdev->prom_name, "espdma"))) - break; - } - } - - /* If we don't know how to handle the dvma, - * do not use this device. - */ - if (dma == NULL) { - printk("Cannot find dvma for ESP%d's SCSI\n", esp->esp_id); - return -1; - } - if (dma->allocated) { - printk("esp%d: can't use my espdma\n", esp->esp_id); - return -1; - } - dma->allocated = 1; - esp->dma = dma; - esp->dregs = dma->regs; - - return 0; -} - -static int __init esp_map_regs(struct esp *esp, int hme) -{ - struct sbus_dev *sdev = esp->sdev; - struct resource *res; - - /* On HME, two reg sets exist, first is DVMA, - * second is ESP registers. - */ - if (hme) - res = &sdev->resource[1]; - else - res = &sdev->resource[0]; - - esp->eregs = sbus_ioremap(res, 0, ESP_REG_SIZE, "ESP Registers"); - - if (esp->eregs == 0) - return -1; - return 0; -} - -static int __init esp_map_cmdarea(struct esp *esp) -{ - struct sbus_dev *sdev = esp->sdev; - - esp->esp_command = sbus_alloc_consistent(sdev, 16, - &esp->esp_command_dvma); - if (esp->esp_command == NULL || - esp->esp_command_dvma == 0) - return -1; - return 0; -} - -static int __init esp_register_irq(struct esp *esp) -{ - esp->ehost->irq = esp->irq = esp->sdev->irqs[0]; - - /* We used to try various overly-clever things to - * reduce the interrupt processing overhead on - * sun4c/sun4m when multiple ESP's shared the - * same IRQ. It was too complex and messy to - * sanely maintain. - */ - if (request_irq(esp->ehost->irq, esp_intr, - IRQF_SHARED, "ESP SCSI", esp)) { - printk("esp%d: Cannot acquire irq line\n", - esp->esp_id); - return -1; - } - - printk("esp%d: IRQ %d ", esp->esp_id, - esp->ehost->irq); - - return 0; -} - -static void __init esp_get_scsi_id(struct esp *esp) -{ - struct sbus_dev *sdev = esp->sdev; - struct device_node *dp = sdev->ofdev.node; - - esp->scsi_id = of_getintprop_default(dp, - "initiator-id", - -1); - if (esp->scsi_id == -1) - esp->scsi_id = of_getintprop_default(dp, - "scsi-initiator-id", - -1); - if (esp->scsi_id == -1) - esp->scsi_id = (sdev->bus == NULL) ? 7 : - of_getintprop_default(sdev->bus->ofdev.node, - "scsi-initiator-id", - 7); - esp->ehost->this_id = esp->scsi_id; - esp->scsi_id_mask = (1 << esp->scsi_id); - -} - -static void __init esp_get_clock_params(struct esp *esp) -{ - struct sbus_dev *sdev = esp->sdev; - int prom_node = esp->prom_node; - int sbus_prom_node; - unsigned int fmhz; - u8 ccf; - - if (sdev != NULL && sdev->bus != NULL) - sbus_prom_node = sdev->bus->prom_node; - else - sbus_prom_node = 0; - - /* This is getting messy but it has to be done - * correctly or else you get weird behavior all - * over the place. We are trying to basically - * figure out three pieces of information. - * - * a) Clock Conversion Factor - * - * This is a representation of the input - * crystal clock frequency going into the - * ESP on this machine. Any operation whose - * timing is longer than 400ns depends on this - * value being correct. For example, you'll - * get blips for arbitration/selection during - * high load or with multiple targets if this - * is not set correctly. - * - * b) Selection Time-Out - * - * The ESP isn't very bright and will arbitrate - * for the bus and try to select a target - * forever if you let it. This value tells - * the ESP when it has taken too long to - * negotiate and that it should interrupt - * the CPU so we can see what happened. - * The value is computed as follows (from - * NCR/Symbios chip docs). - * - * (Time Out Period) * (Input Clock) - * STO = ---------------------------------- - * (8192) * (Clock Conversion Factor) - * - * You usually want the time out period to be - * around 250ms, I think we'll set it a little - * bit higher to account for fully loaded SCSI - * bus's and slow devices that don't respond so - * quickly to selection attempts. (yeah, I know - * this is out of spec. but there is a lot of - * buggy pieces of firmware out there so bite me) - * - * c) Imperical constants for synchronous offset - * and transfer period register values - * - * This entails the smallest and largest sync - * period we could ever handle on this ESP. - */ - - fmhz = prom_getintdefault(prom_node, "clock-frequency", -1); - if (fmhz == -1) - fmhz = (!sbus_prom_node) ? 0 : - prom_getintdefault(sbus_prom_node, "clock-frequency", -1); - - if (fmhz <= (5000000)) - ccf = 0; - else - ccf = (((5000000 - 1) + (fmhz))/(5000000)); - - if (!ccf || ccf > 8) { - /* If we can't find anything reasonable, - * just assume 20MHZ. This is the clock - * frequency of the older sun4c's where I've - * been unable to find the clock-frequency - * PROM property. All other machines provide - * useful values it seems. - */ - ccf = ESP_CCF_F4; - fmhz = (20000000); - } - - if (ccf == (ESP_CCF_F7 + 1)) - esp->cfact = ESP_CCF_F0; - else if (ccf == ESP_CCF_NEVER) - esp->cfact = ESP_CCF_F2; - else - esp->cfact = ccf; - esp->raw_cfact = ccf; - - esp->cfreq = fmhz; - esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz); - esp->ctick = ESP_TICK(ccf, esp->ccycle); - esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); - esp->sync_defp = SYNC_DEFP_SLOW; - - printk("SCSI ID %d Clk %dMHz CCYC=%d CCF=%d TOut %d ", - esp->scsi_id, (fmhz / 1000000), - (int)esp->ccycle, (int)ccf, (int) esp->neg_defp); -} - -static void __init esp_get_bursts(struct esp *esp, struct sbus_dev *dma) -{ - struct sbus_dev *sdev = esp->sdev; - u8 bursts; - - bursts = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff); - - if (dma) { - u8 tmp = prom_getintdefault(dma->prom_node, - "burst-sizes", 0xff); - if (tmp != 0xff) - bursts &= tmp; - } - - if (sdev->bus) { - u8 tmp = prom_getintdefault(sdev->bus->prom_node, - "burst-sizes", 0xff); - if (tmp != 0xff) - bursts &= tmp; - } - - if (bursts == 0xff || - (bursts & DMA_BURST16) == 0 || - (bursts & DMA_BURST32) == 0) - bursts = (DMA_BURST32 - 1); - - esp->bursts = bursts; -} - -static void __init esp_get_revision(struct esp *esp) -{ - u8 tmp; - - esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); - esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); - sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); - - tmp = sbus_readb(esp->eregs + ESP_CFG2); - tmp &= ~ESP_CONFIG2_MAGIC; - if (tmp != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { - /* If what we write to cfg2 does not come back, cfg2 - * is not implemented, therefore this must be a plain - * esp100. - */ - esp->erev = esp100; - printk("NCR53C90(esp100)\n"); - } else { - esp->config2 = 0; - esp->prev_cfg3 = esp->config3[0] = 5; - sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); - sbus_writeb(0, esp->eregs + ESP_CFG3); - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - - tmp = sbus_readb(esp->eregs + ESP_CFG3); - if (tmp != 5) { - /* The cfg2 register is implemented, however - * cfg3 is not, must be esp100a. - */ - esp->erev = esp100a; - printk("NCR53C90A(esp100a)\n"); - } else { - int target; - - for (target = 0; target < 16; target++) - esp->config3[target] = 0; - esp->prev_cfg3 = 0; - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - - /* All of cfg{1,2,3} implemented, must be one of - * the fas variants, figure out which one. - */ - if (esp->raw_cfact > ESP_CCF_F5) { - esp->erev = fast; - esp->sync_defp = SYNC_DEFP_FAST; - printk("NCR53C9XF(espfast)\n"); - } else { - esp->erev = esp236; - printk("NCR53C9x(esp236)\n"); - } - esp->config2 = 0; - sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); - } - } -} - -static void __init esp_init_swstate(struct esp *esp) -{ - int i; - - /* Command queues... */ - esp->current_SC = NULL; - esp->disconnected_SC = NULL; - esp->issue_SC = NULL; - - /* Target and current command state... */ - esp->targets_present = 0; - esp->resetting_bus = 0; - esp->snip = 0; - - init_waitqueue_head(&esp->reset_queue); - - /* Debugging... */ - for(i = 0; i < 32; i++) - esp->espcmdlog[i] = 0; - esp->espcmdent = 0; - - /* MSG phase state... */ - for(i = 0; i < 16; i++) { - esp->cur_msgout[i] = 0; - esp->cur_msgin[i] = 0; - } - esp->prevmsgout = esp->prevmsgin = 0; - esp->msgout_len = esp->msgin_len = 0; - - /* Clear the one behind caches to hold unmatchable values. */ - esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff; - esp->prev_hme_dmacsr = 0xffffffff; -} - -static int __init detect_one_esp(struct scsi_host_template *tpnt, - struct device *dev, - struct sbus_dev *esp_dev, - struct sbus_dev *espdma, - struct sbus_bus *sbus, - int hme) -{ - static int instance; - struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp)); - struct esp *esp; - - if (!esp_host) - return -ENOMEM; - - if (hme) - esp_host->max_id = 16; - esp = (struct esp *) esp_host->hostdata; - esp->ehost = esp_host; - esp->sdev = esp_dev; - esp->esp_id = instance; - esp->prom_node = esp_dev->prom_node; - prom_getstring(esp->prom_node, "name", esp->prom_name, - sizeof(esp->prom_name)); - - if (esp_find_dvma(esp, espdma) < 0) - goto fail_unlink; - if (esp_map_regs(esp, hme) < 0) { - printk("ESP registers unmappable"); - goto fail_dvma_release; - } - if (esp_map_cmdarea(esp) < 0) { - printk("ESP DVMA transport area unmappable"); - goto fail_unmap_regs; - } - if (esp_register_irq(esp) < 0) - goto fail_unmap_cmdarea; - - esp_get_scsi_id(esp); - - esp->diff = prom_getbool(esp->prom_node, "differential"); - if (esp->diff) - printk("Differential "); - - esp_get_clock_params(esp); - esp_get_bursts(esp, espdma); - esp_get_revision(esp); - esp_init_swstate(esp); - - esp_bootup_reset(esp); - - if (scsi_add_host(esp_host, dev)) - goto fail_free_irq; - - dev_set_drvdata(&esp_dev->ofdev.dev, esp); - - scsi_scan_host(esp_host); - instance++; - - return 0; - -fail_free_irq: - free_irq(esp->ehost->irq, esp); - -fail_unmap_cmdarea: - sbus_free_consistent(esp->sdev, 16, - (void *) esp->esp_command, - esp->esp_command_dvma); - -fail_unmap_regs: - sbus_iounmap(esp->eregs, ESP_REG_SIZE); - -fail_dvma_release: - esp->dma->allocated = 0; - -fail_unlink: - scsi_host_put(esp_host); - return -1; -} - -/* Detecting ESP chips on the machine. This is the simple and easy - * version. - */ -static int __devexit esp_remove_common(struct esp *esp) -{ - unsigned int irq = esp->ehost->irq; - - scsi_remove_host(esp->ehost); - - ESP_INTSOFF(esp->dregs); -#if 0 - esp_reset_dma(esp); - esp_reset_esp(esp); -#endif - - free_irq(irq, esp); - sbus_free_consistent(esp->sdev, 16, - (void *) esp->esp_command, esp->esp_command_dvma); - sbus_iounmap(esp->eregs, ESP_REG_SIZE); - esp->dma->allocated = 0; - - scsi_host_put(esp->ehost); - - return 0; -} - - -#ifdef CONFIG_SUN4 - -#include - -static struct sbus_dev sun4_esp_dev; - -static int __init esp_sun4_probe(struct scsi_host_template *tpnt) -{ - if (sun4_esp_physaddr) { - memset(&sun4_esp_dev, 0, sizeof(sun4_esp_dev)); - sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr; - sun4_esp_dev.irqs[0] = 4; - sun4_esp_dev.resource[0].start = sun4_esp_physaddr; - sun4_esp_dev.resource[0].end = - sun4_esp_physaddr + ESP_REG_SIZE - 1; - sun4_esp_dev.resource[0].flags = IORESOURCE_IO; - - return detect_one_esp(tpnt, NULL, - &sun4_esp_dev, NULL, NULL, 0); - } - return 0; -} - -static int __devexit esp_sun4_remove(void) -{ - struct of_device *dev = &sun4_esp_dev.ofdev; - struct esp *esp = dev_get_drvdata(&dev->dev); - - return esp_remove_common(esp); -} - -#else /* !CONFIG_SUN4 */ - -static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - struct device_node *dp = dev->node; - struct sbus_dev *dma_sdev = NULL; - int hme = 0; - - if (dp->parent && - (!strcmp(dp->parent->name, "espdma") || - !strcmp(dp->parent->name, "dma"))) - dma_sdev = sdev->parent; - else if (!strcmp(dp->name, "SUNW,fas")) { - dma_sdev = sdev; - hme = 1; - } - - return detect_one_esp(match->data, &dev->dev, - sdev, dma_sdev, sdev->bus, hme); -} - -static int __devexit esp_sbus_remove(struct of_device *dev) -{ - struct esp *esp = dev_get_drvdata(&dev->dev); - - return esp_remove_common(esp); -} - -#endif /* !CONFIG_SUN4 */ - -/* The info function will return whatever useful - * information the developer sees fit. If not provided, then - * the name field will be used instead. - */ -static const char *esp_info(struct Scsi_Host *host) -{ - struct esp *esp; - - esp = (struct esp *) host->hostdata; - switch (esp->erev) { - case esp100: - return "Sparc ESP100 (NCR53C90)"; - case esp100a: - return "Sparc ESP100A (NCR53C90A)"; - case esp236: - return "Sparc ESP236"; - case fas236: - return "Sparc ESP236-FAST"; - case fashme: - return "Sparc ESP366-HME"; - case fas100a: - return "Sparc ESP100A-FAST"; - default: - return "Bogon ESP revision"; - }; -} - -/* From Wolfgang Stanglmeier's NCR scsi driver. */ -struct info_str -{ - char *buffer; - int length; - int offset; - int pos; -}; - -static void copy_mem_info(struct info_str *info, char *data, int len) -{ - if (info->pos + len > info->length) - len = info->length - info->pos; - - if (info->pos + len < info->offset) { - info->pos += len; - return; - } - if (info->pos < info->offset) { - data += (info->offset - info->pos); - len -= (info->offset - info->pos); - } - - if (len > 0) { - memcpy(info->buffer + info->pos, data, len); - info->pos += len; - } -} - -static int copy_info(struct info_str *info, char *fmt, ...) -{ - va_list args; - char buf[81]; - int len; - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - copy_mem_info(info, buf, len); - return len; -} - -static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len) -{ - struct scsi_device *sdev; - struct info_str info; - int i; - - info.buffer = ptr; - info.length = len; - info.offset = offset; - info.pos = 0; - - copy_info(&info, "Sparc ESP Host Adapter:\n"); - copy_info(&info, "\tPROM node\t\t%08x\n", (unsigned int) esp->prom_node); - copy_info(&info, "\tPROM name\t\t%s\n", esp->prom_name); - copy_info(&info, "\tESP Model\t\t"); - switch (esp->erev) { - case esp100: - copy_info(&info, "ESP100\n"); - break; - case esp100a: - copy_info(&info, "ESP100A\n"); - break; - case esp236: - copy_info(&info, "ESP236\n"); - break; - case fas236: - copy_info(&info, "FAS236\n"); - break; - case fas100a: - copy_info(&info, "FAS100A\n"); - break; - case fast: - copy_info(&info, "FAST\n"); - break; - case fashme: - copy_info(&info, "Happy Meal FAS\n"); - break; - case espunknown: - default: - copy_info(&info, "Unknown!\n"); - break; - }; - copy_info(&info, "\tDMA Revision\t\t"); - switch (esp->dma->revision) { - case dvmarev0: - copy_info(&info, "Rev 0\n"); - break; - case dvmaesc1: - copy_info(&info, "ESC Rev 1\n"); - break; - case dvmarev1: - copy_info(&info, "Rev 1\n"); - break; - case dvmarev2: - copy_info(&info, "Rev 2\n"); - break; - case dvmarev3: - copy_info(&info, "Rev 3\n"); - break; - case dvmarevplus: - copy_info(&info, "Rev 1+\n"); - break; - case dvmahme: - copy_info(&info, "Rev HME/FAS\n"); - break; - default: - copy_info(&info, "Unknown!\n"); - break; - }; - copy_info(&info, "\tLive Targets\t\t[ "); - for (i = 0; i < 15; i++) { - if (esp->targets_present & (1 << i)) - copy_info(&info, "%d ", i); - } - copy_info(&info, "]\n\n"); - - /* Now describe the state of each existing target. */ - copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n"); - - shost_for_each_device(sdev, esp->ehost) { - struct esp_device *esp_dev = sdev->hostdata; - uint id = sdev->id; - - if (!(esp->targets_present & (1 << id))) - continue; - - copy_info(&info, "%d\t\t", id); - copy_info(&info, "%08lx\t", esp->config3[id]); - copy_info(&info, "[%02lx,%02lx]\t\t\t", - esp_dev->sync_max_offset, - esp_dev->sync_min_period); - copy_info(&info, "%s\t\t", - esp_dev->disconnect ? "yes" : "no"); - copy_info(&info, "%s\n", - (esp->config3[id] & ESP_CONFIG3_EWIDE) ? "yes" : "no"); - } - return info.pos > info.offset? info.pos - info.offset : 0; -} - -/* ESP proc filesystem code. */ -static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int inout) -{ - struct esp *esp = (struct esp *) host->hostdata; - - if (inout) - return -EINVAL; /* not yet */ - - if (start) - *start = buffer; - - return esp_host_info(esp, buffer, offset, length); -} - -static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp) -{ - if (sp->use_sg == 0) { - sp->SCp.this_residual = sp->request_bufflen; - sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; - sp->SCp.buffers_residual = 0; - if (sp->request_bufflen) { - sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer, - sp->SCp.this_residual, - sp->sc_data_direction); - sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in); - } else { - sp->SCp.ptr = NULL; - } - } else { - sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; - sp->SCp.buffers_residual = sbus_map_sg(esp->sdev, - sp->SCp.buffer, - sp->use_sg, - sp->sc_data_direction); - sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer); - sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer)); - } -} - -static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp) -{ - if (sp->use_sg) { - sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg, - sp->sc_data_direction); - } else if (sp->request_bufflen) { - sbus_unmap_single(esp->sdev, - sp->SCp.have_data_in, - sp->request_bufflen, - sp->sc_data_direction); - } -} - -static void esp_restore_pointers(struct esp *esp, struct scsi_cmnd *sp) -{ - struct esp_pointers *ep = &esp->data_pointers[sp->device->id]; - - sp->SCp.ptr = ep->saved_ptr; - sp->SCp.buffer = ep->saved_buffer; - sp->SCp.this_residual = ep->saved_this_residual; - sp->SCp.buffers_residual = ep->saved_buffers_residual; -} - -static void esp_save_pointers(struct esp *esp, struct scsi_cmnd *sp) -{ - struct esp_pointers *ep = &esp->data_pointers[sp->device->id]; - - ep->saved_ptr = sp->SCp.ptr; - ep->saved_buffer = sp->SCp.buffer; - ep->saved_this_residual = sp->SCp.this_residual; - ep->saved_buffers_residual = sp->SCp.buffers_residual; -} - -/* Some rules: - * - * 1) Never ever panic while something is live on the bus. - * If there is to be any chance of syncing the disks this - * rule is to be obeyed. - * - * 2) Any target that causes a foul condition will no longer - * have synchronous transfers done to it, no questions - * asked. - * - * 3) Keep register accesses to a minimum. Think about some - * day when we have Xbus machines this is running on and - * the ESP chip is on the other end of the machine on a - * different board from the cpu where this is running. - */ - -/* Fire off a command. We assume the bus is free and that the only - * case where we could see an interrupt is where we have disconnected - * commands active and they are trying to reselect us. - */ -static inline void esp_check_cmd(struct esp *esp, struct scsi_cmnd *sp) -{ - switch (sp->cmd_len) { - case 6: - case 10: - case 12: - esp->esp_slowcmd = 0; - break; - - default: - esp->esp_slowcmd = 1; - esp->esp_scmdleft = sp->cmd_len; - esp->esp_scmdp = &sp->cmnd[0]; - break; - }; -} - -static inline void build_sync_nego_msg(struct esp *esp, int period, int offset) -{ - esp->cur_msgout[0] = EXTENDED_MESSAGE; - esp->cur_msgout[1] = 3; - esp->cur_msgout[2] = EXTENDED_SDTR; - esp->cur_msgout[3] = period; - esp->cur_msgout[4] = offset; - esp->msgout_len = 5; -} - -/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */ -static inline void build_wide_nego_msg(struct esp *esp, int size) -{ - esp->cur_msgout[0] = EXTENDED_MESSAGE; - esp->cur_msgout[1] = 2; - esp->cur_msgout[2] = EXTENDED_WDTR; - switch (size) { - case 32: - esp->cur_msgout[3] = 2; - break; - case 16: - esp->cur_msgout[3] = 1; - break; - case 8: - default: - esp->cur_msgout[3] = 0; - break; - }; - - esp->msgout_len = 4; -} - -static void esp_exec_cmd(struct esp *esp) -{ - struct scsi_cmnd *SCptr; - struct scsi_device *SDptr; - struct esp_device *esp_dev; - volatile u8 *cmdp = esp->esp_command; - u8 the_esp_command; - int lun, target; - int i; - - /* Hold off if we have disconnected commands and - * an IRQ is showing... - */ - if (esp->disconnected_SC && ESP_IRQ_P(esp->dregs)) - return; - - /* Grab first member of the issue queue. */ - SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC); - - /* Safe to panic here because current_SC is null. */ - if (!SCptr) - panic("esp: esp_exec_cmd and issue queue is NULL"); - - SDptr = SCptr->device; - esp_dev = SDptr->hostdata; - lun = SCptr->device->lun; - target = SCptr->device->id; - - esp->snip = 0; - esp->msgout_len = 0; - - /* Send it out whole, or piece by piece? The ESP - * only knows how to automatically send out 6, 10, - * and 12 byte commands. I used to think that the - * Linux SCSI code would never throw anything other - * than that to us, but then again there is the - * SCSI generic driver which can send us anything. - */ - esp_check_cmd(esp, SCptr); - - /* If arbitration/selection is successful, the ESP will leave - * ATN asserted, causing the target to go into message out - * phase. The ESP will feed the target the identify and then - * the target can only legally go to one of command, - * datain/out, status, or message in phase, or stay in message - * out phase (should we be trying to send a sync negotiation - * message after the identify). It is not allowed to drop - * BSY, but some buggy targets do and we check for this - * condition in the selection complete code. Most of the time - * we'll make the command bytes available to the ESP and it - * will not interrupt us until it finishes command phase, we - * cannot do this for command sizes the ESP does not - * understand and in this case we'll get interrupted right - * when the target goes into command phase. - * - * It is absolutely _illegal_ in the presence of SCSI-2 devices - * to use the ESP select w/o ATN command. When SCSI-2 devices are - * present on the bus we _must_ always go straight to message out - * phase with an identify message for the target. Being that - * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2 - * selections should not confuse SCSI-1 we hope. - */ - - if (esp_dev->sync) { - /* this targets sync is known */ -#ifndef __sparc_v9__ -do_sync_known: -#endif - if (esp_dev->disconnect) - *cmdp++ = IDENTIFY(1, lun); - else - *cmdp++ = IDENTIFY(0, lun); - - if (esp->esp_slowcmd) { - the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); - esp_advance_phase(SCptr, in_slct_stop); - } else { - the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); - esp_advance_phase(SCptr, in_slct_norm); - } - } else if (!(esp->targets_present & (1<disconnect)) { - /* After the bootup SCSI code sends both the - * TEST_UNIT_READY and INQUIRY commands we want - * to at least attempt allowing the device to - * disconnect. - */ - ESPMISC(("esp: Selecting device for first time. target=%d " - "lun=%d\n", target, SCptr->device->lun)); - if (!SDptr->borken && !esp_dev->disconnect) - esp_dev->disconnect = 1; - - *cmdp++ = IDENTIFY(0, lun); - esp->prevmsgout = NOP; - esp_advance_phase(SCptr, in_slct_norm); - the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); - - /* Take no chances... */ - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - } else { - /* Sorry, I have had way too many problems with - * various CDROM devices on ESP. -DaveM - */ - int cdrom_hwbug_wkaround = 0; - -#ifndef __sparc_v9__ - /* Never allow disconnects or synchronous transfers on - * SparcStation1 and SparcStation1+. Allowing those - * to be enabled seems to lockup the machine completely. - */ - if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || - (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { - /* But we are nice and allow tapes and removable - * disks (but not CDROMs) to disconnect. - */ - if(SDptr->type == TYPE_TAPE || - (SDptr->type != TYPE_ROM && SDptr->removable)) - esp_dev->disconnect = 1; - else - esp_dev->disconnect = 0; - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - esp_dev->sync = 1; - esp->snip = 0; - goto do_sync_known; - } -#endif /* !(__sparc_v9__) */ - - /* We've talked to this guy before, - * but never negotiated. Let's try, - * need to attempt WIDE first, before - * sync nego, as per SCSI 2 standard. - */ - if (esp->erev == fashme && !esp_dev->wide) { - if (!SDptr->borken && - SDptr->type != TYPE_ROM && - SDptr->removable == 0) { - build_wide_nego_msg(esp, 16); - esp_dev->wide = 1; - esp->wnip = 1; - goto after_nego_msg_built; - } else { - esp_dev->wide = 1; - /* Fall through and try sync. */ - } - } - - if (!SDptr->borken) { - if ((SDptr->type == TYPE_ROM)) { - /* Nice try sucker... */ - ESPMISC(("esp%d: Disabling sync for buggy " - "CDROM.\n", esp->esp_id)); - cdrom_hwbug_wkaround = 1; - build_sync_nego_msg(esp, 0, 0); - } else if (SDptr->removable != 0) { - ESPMISC(("esp%d: Not negotiating sync/wide but " - "allowing disconnect for removable media.\n", - esp->esp_id)); - build_sync_nego_msg(esp, 0, 0); - } else { - build_sync_nego_msg(esp, esp->sync_defp, 15); - } - } else { - build_sync_nego_msg(esp, 0, 0); - } - esp_dev->sync = 1; - esp->snip = 1; - -after_nego_msg_built: - /* A fix for broken SCSI1 targets, when they disconnect - * they lock up the bus and confuse ESP. So disallow - * disconnects for SCSI1 targets for now until we - * find a better fix. - * - * Addendum: This is funny, I figured out what was going - * on. The blotzed SCSI1 target would disconnect, - * one of the other SCSI2 targets or both would be - * disconnected as well. The SCSI1 target would - * stay disconnected long enough that we start - * up a command on one of the SCSI2 targets. As - * the ESP is arbitrating for the bus the SCSI1 - * target begins to arbitrate as well to reselect - * the ESP. The SCSI1 target refuses to drop it's - * ID bit on the data bus even though the ESP is - * at ID 7 and is the obvious winner for any - * arbitration. The ESP is a poor sport and refuses - * to lose arbitration, it will continue indefinitely - * trying to arbitrate for the bus and can only be - * stopped via a chip reset or SCSI bus reset. - * Therefore _no_ disconnects for SCSI1 targets - * thank you very much. ;-) - */ - if(((SDptr->scsi_level < 3) && - (SDptr->type != TYPE_TAPE) && - SDptr->removable == 0) || - cdrom_hwbug_wkaround || SDptr->borken) { - ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d " - "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); - esp_dev->disconnect = 0; - *cmdp++ = IDENTIFY(0, lun); - } else { - *cmdp++ = IDENTIFY(1, lun); - } - - /* ESP fifo is only so big... - * Make this look like a slow command. - */ - esp->esp_slowcmd = 1; - esp->esp_scmdleft = SCptr->cmd_len; - esp->esp_scmdp = &SCptr->cmnd[0]; - - the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); - esp_advance_phase(SCptr, in_slct_msg); - } - - if (!esp->esp_slowcmd) - for (i = 0; i < SCptr->cmd_len; i++) - *cmdp++ = SCptr->cmnd[i]; - - /* HME sucks... */ - if (esp->erev == fashme) - sbus_writeb((target & 0xf) | (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT), - esp->eregs + ESP_BUSID); - else - sbus_writeb(target & 7, esp->eregs + ESP_BUSID); - if (esp->prev_soff != esp_dev->sync_max_offset || - esp->prev_stp != esp_dev->sync_min_period || - (esp->erev > esp100a && - esp->prev_cfg3 != esp->config3[target])) { - esp->prev_soff = esp_dev->sync_max_offset; - esp->prev_stp = esp_dev->sync_min_period; - sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); - sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); - if (esp->erev > esp100a) { - esp->prev_cfg3 = esp->config3[target]; - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - } - } - i = (cmdp - esp->esp_command); - - if (esp->erev == fashme) { - esp_cmd(esp, ESP_CMD_FLUSH); /* Grrr! */ - - /* Set up the DMA and HME counters */ - sbus_writeb(i, esp->eregs + ESP_TCLOW); - sbus_writeb(0, esp->eregs + ESP_TCMED); - sbus_writeb(0, esp->eregs + FAS_RLO); - sbus_writeb(0, esp->eregs + FAS_RHI); - esp_cmd(esp, the_esp_command); - - /* Talk about touchy hardware... */ - esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | - (DMA_SCSI_DISAB | DMA_ENABLE)) & - ~(DMA_ST_WRITE)); - sbus_writel(16, esp->dregs + DMA_COUNT); - sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR); - sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); - } else { - u32 tmp; - - /* Set up the DMA and ESP counters */ - sbus_writeb(i, esp->eregs + ESP_TCLOW); - sbus_writeb(0, esp->eregs + ESP_TCMED); - tmp = sbus_readl(esp->dregs + DMA_CSR); - tmp &= ~DMA_ST_WRITE; - tmp |= DMA_ENABLE; - sbus_writel(tmp, esp->dregs + DMA_CSR); - if (esp->dma->revision == dvmaesc1) { - if (i) /* Workaround ESC gate array SBUS rerun bug. */ - sbus_writel(PAGE_SIZE, esp->dregs + DMA_COUNT); - } - sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR); - - /* Tell ESP to "go". */ - esp_cmd(esp, the_esp_command); - } -} - -/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */ -static int esp_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) -{ - struct esp *esp; - - /* Set up func ptr and initial driver cmd-phase. */ - SCpnt->scsi_done = done; - SCpnt->SCp.phase = not_issued; - - /* We use the scratch area. */ - ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->device->lun)); - ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->device->lun)); - - esp = (struct esp *) SCpnt->device->host->hostdata; - esp_get_dmabufs(esp, SCpnt); - esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */ - - SCpnt->SCp.Status = CHECK_CONDITION; - SCpnt->SCp.Message = 0xff; - SCpnt->SCp.sent_command = 0; - - /* Place into our queue. */ - if (SCpnt->cmnd[0] == REQUEST_SENSE) { - ESPQUEUE(("RQSENSE\n")); - prepend_SC(&esp->issue_SC, SCpnt); - } else { - ESPQUEUE(("\n")); - append_SC(&esp->issue_SC, SCpnt); - } - - /* Run it now if we can. */ - if (!esp->current_SC && !esp->resetting_bus) - esp_exec_cmd(esp); - - return 0; -} - -/* Dump driver state. */ -static void esp_dump_cmd(struct scsi_cmnd *SCptr) -{ - ESPLOG(("[tgt<%02x> lun<%02x> " - "pphase<%s> cphase<%s>]", - SCptr->device->id, SCptr->device->lun, - phase_string(SCptr->SCp.sent_command), - phase_string(SCptr->SCp.phase))); -} - -static void esp_dump_state(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; -#ifdef DEBUG_ESP_CMDS - int i; -#endif - - ESPLOG(("esp%d: dumping state\n", esp->esp_id)); - ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n", - esp->esp_id, - sbus_readl(esp->dregs + DMA_CSR), - sbus_readl(esp->dregs + DMA_ADDR))); - ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n", - esp->esp_id, esp->sreg, esp->seqreg, esp->ireg)); - ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n", - esp->esp_id, - sbus_readb(esp->eregs + ESP_STATUS), - sbus_readb(esp->eregs + ESP_SSTEP), - sbus_readb(esp->eregs + ESP_INTRPT))); -#ifdef DEBUG_ESP_CMDS - printk("esp%d: last ESP cmds [", esp->esp_id); - i = (esp->espcmdent - 1) & 31; - printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); - i = (i - 1) & 31; - printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); - i = (i - 1) & 31; - printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); - i = (i - 1) & 31; - printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); - printk("]\n"); -#endif /* (DEBUG_ESP_CMDS) */ - - if (SCptr) { - ESPLOG(("esp%d: current command ", esp->esp_id)); - esp_dump_cmd(SCptr); - } - ESPLOG(("\n")); - SCptr = esp->disconnected_SC; - ESPLOG(("esp%d: disconnected ", esp->esp_id)); - while (SCptr) { - esp_dump_cmd(SCptr); - SCptr = (struct scsi_cmnd *) SCptr->host_scribble; - } - ESPLOG(("\n")); -} - -/* Abort a command. The host_lock is acquired by caller. */ -static int esp_abort(struct scsi_cmnd *SCptr) -{ - struct esp *esp = (struct esp *) SCptr->device->host->hostdata; - int don; - - ESPLOG(("esp%d: Aborting command\n", esp->esp_id)); - esp_dump_state(esp); - - /* Wheee, if this is the current command on the bus, the - * best we can do is assert ATN and wait for msgout phase. - * This should even fix a hung SCSI bus when we lose state - * in the driver and timeout because the eventual phase change - * will cause the ESP to (eventually) give an interrupt. - */ - if (esp->current_SC == SCptr) { - esp->cur_msgout[0] = ABORT; - esp->msgout_len = 1; - esp->msgout_ctr = 0; - esp_cmd(esp, ESP_CMD_SATN); - return SUCCESS; - } - - /* If it is still in the issue queue then we can safely - * call the completion routine and report abort success. - */ - don = (sbus_readl(esp->dregs + DMA_CSR) & DMA_INT_ENAB); - if (don) { - ESP_INTSOFF(esp->dregs); - } - if (esp->issue_SC) { - struct scsi_cmnd **prev, *this; - for (prev = (&esp->issue_SC), this = esp->issue_SC; - this != NULL; - prev = (struct scsi_cmnd **) &(this->host_scribble), - this = (struct scsi_cmnd *) this->host_scribble) { - - if (this == SCptr) { - *prev = (struct scsi_cmnd *) this->host_scribble; - this->host_scribble = NULL; - - esp_release_dmabufs(esp, this); - this->result = DID_ABORT << 16; - this->scsi_done(this); - - if (don) - ESP_INTSON(esp->dregs); - - return SUCCESS; - } - } - } - - /* Yuck, the command to abort is disconnected, it is not - * worth trying to abort it now if something else is live - * on the bus at this time. So, we let the SCSI code wait - * a little bit and try again later. - */ - if (esp->current_SC) { - if (don) - ESP_INTSON(esp->dregs); - return FAILED; - } - - /* It's disconnected, we have to reconnect to re-establish - * the nexus and tell the device to abort. However, we really - * cannot 'reconnect' per se. Don't try to be fancy, just - * indicate failure, which causes our caller to reset the whole - * bus. - */ - - if (don) - ESP_INTSON(esp->dregs); - - return FAILED; -} - -/* We've sent ESP_CMD_RS to the ESP, the interrupt had just - * arrived indicating the end of the SCSI bus reset. Our job - * is to clean out the command queues and begin re-execution - * of SCSI commands once more. - */ -static int esp_finish_reset(struct esp *esp) -{ - struct scsi_cmnd *sp = esp->current_SC; - - /* Clean up currently executing command, if any. */ - if (sp != NULL) { - esp->current_SC = NULL; - - esp_release_dmabufs(esp, sp); - sp->result = (DID_RESET << 16); - - sp->scsi_done(sp); - } - - /* Clean up disconnected queue, they have been invalidated - * by the bus reset. - */ - if (esp->disconnected_SC) { - while ((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) { - esp_release_dmabufs(esp, sp); - sp->result = (DID_RESET << 16); - - sp->scsi_done(sp); - } - } - - /* SCSI bus reset is complete. */ - esp->resetting_bus = 0; - wake_up(&esp->reset_queue); - - /* Ok, now it is safe to get commands going once more. */ - if (esp->issue_SC) - esp_exec_cmd(esp); - - return do_intr_end; -} - -static int esp_do_resetbus(struct esp *esp) -{ - ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id)); - esp->resetting_bus = 1; - esp_cmd(esp, ESP_CMD_RS); - - return do_intr_end; -} - -/* Reset ESP chip, reset hanging bus, then kill active and - * disconnected commands for targets without soft reset. - * - * The host_lock is acquired by caller. - */ -static int esp_reset(struct scsi_cmnd *SCptr) -{ - struct esp *esp = (struct esp *) SCptr->device->host->hostdata; - - spin_lock_irq(esp->ehost->host_lock); - (void) esp_do_resetbus(esp); - spin_unlock_irq(esp->ehost->host_lock); - - wait_event(esp->reset_queue, (esp->resetting_bus == 0)); - - return SUCCESS; -} - -/* Internal ESP done function. */ -static void esp_done(struct esp *esp, int error) -{ - struct scsi_cmnd *done_SC = esp->current_SC; - - esp->current_SC = NULL; - - esp_release_dmabufs(esp, done_SC); - done_SC->result = error; - - done_SC->scsi_done(done_SC); - - /* Bus is free, issue any commands in the queue. */ - if (esp->issue_SC && !esp->current_SC) - esp_exec_cmd(esp); - -} - -/* Wheee, ESP interrupt engine. */ - -/* Forward declarations. */ -static int esp_do_phase_determine(struct esp *esp); -static int esp_do_data_finale(struct esp *esp); -static int esp_select_complete(struct esp *esp); -static int esp_do_status(struct esp *esp); -static int esp_do_msgin(struct esp *esp); -static int esp_do_msgindone(struct esp *esp); -static int esp_do_msgout(struct esp *esp); -static int esp_do_cmdbegin(struct esp *esp); - -#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP) -#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP) - -/* Read any bytes found in the FAS366 fifo, storing them into - * the ESP driver software state structure. - */ -static void hme_fifo_read(struct esp *esp) -{ - u8 count = 0; - u8 status = esp->sreg; - - /* Cannot safely frob the fifo for these following cases, but - * we must always read the fifo when the reselect interrupt - * is pending. - */ - if (((esp->ireg & ESP_INTR_RSEL) == 0) && - (sreg_datainp(status) || - sreg_dataoutp(status) || - (esp->current_SC && - esp->current_SC->SCp.phase == in_data_done))) { - ESPHME(("")); - } else { - unsigned long fcnt = sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES; - - /* The HME stores bytes in multiples of 2 in the fifo. */ - ESPHME(("hme_fifo[fcnt=%d", (int)fcnt)); - while (fcnt) { - esp->hme_fifo_workaround_buffer[count++] = - sbus_readb(esp->eregs + ESP_FDATA); - esp->hme_fifo_workaround_buffer[count++] = - sbus_readb(esp->eregs + ESP_FDATA); - ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1])); - fcnt--; - } - if (sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_F1BYTE) { - ESPHME(("")); - sbus_writeb(0, esp->eregs + ESP_FDATA); - esp->hme_fifo_workaround_buffer[count++] = - sbus_readb(esp->eregs + ESP_FDATA); - ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1])); - ESPHME(("CMD_FLUSH")); - esp_cmd(esp, ESP_CMD_FLUSH); - } else { - ESPHME(("no_xtra_byte")); - } - } - ESPHME(("wkarnd_cnt=%d]", (int)count)); - esp->hme_fifo_workaround_count = count; -} - -static inline void hme_fifo_push(struct esp *esp, u8 *bytes, u8 count) -{ - esp_cmd(esp, ESP_CMD_FLUSH); - while (count) { - u8 tmp = *bytes++; - sbus_writeb(tmp, esp->eregs + ESP_FDATA); - sbus_writeb(0, esp->eregs + ESP_FDATA); - count--; - } -} - -/* We try to avoid some interrupts by jumping ahead and see if the ESP - * has gotten far enough yet. Hence the following. - */ -static inline int skipahead1(struct esp *esp, struct scsi_cmnd *scp, - int prev_phase, int new_phase) -{ - if (scp->SCp.sent_command != prev_phase) - return 0; - if (ESP_IRQ_P(esp->dregs)) { - /* Yes, we are able to save an interrupt. */ - if (esp->erev == fashme) - esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2); - esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR)); - esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); - if (esp->erev == fashme) { - /* This chip is really losing. */ - ESPHME(("HME[")); - /* Must latch fifo before reading the interrupt - * register else garbage ends up in the FIFO - * which confuses the driver utterly. - * Happy Meal indeed.... - */ - ESPHME(("fifo_workaround]")); - if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || - (esp->sreg2 & ESP_STAT2_F1BYTE)) - hme_fifo_read(esp); - } - if (!(esp->ireg & ESP_INTR_SR)) - return 0; - else - return do_reset_complete; - } - /* Ho hum, target is taking forever... */ - scp->SCp.sent_command = new_phase; /* so we don't recurse... */ - return do_intr_end; -} - -static inline int skipahead2(struct esp *esp, struct scsi_cmnd *scp, - int prev_phase1, int prev_phase2, int new_phase) -{ - if (scp->SCp.sent_command != prev_phase1 && - scp->SCp.sent_command != prev_phase2) - return 0; - if (ESP_IRQ_P(esp->dregs)) { - /* Yes, we are able to save an interrupt. */ - if (esp->erev == fashme) - esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2); - esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR)); - esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); - if (esp->erev == fashme) { - /* This chip is really losing. */ - ESPHME(("HME[")); - - /* Must latch fifo before reading the interrupt - * register else garbage ends up in the FIFO - * which confuses the driver utterly. - * Happy Meal indeed.... - */ - ESPHME(("fifo_workaround]")); - if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || - (esp->sreg2 & ESP_STAT2_F1BYTE)) - hme_fifo_read(esp); - } - if (!(esp->ireg & ESP_INTR_SR)) - return 0; - else - return do_reset_complete; - } - /* Ho hum, target is taking forever... */ - scp->SCp.sent_command = new_phase; /* so we don't recurse... */ - return do_intr_end; -} - -/* Now some dma helpers. */ -static void dma_setup(struct esp *esp, __u32 addr, int count, int write) -{ - u32 nreg = sbus_readl(esp->dregs + DMA_CSR); - - if (write) - nreg |= DMA_ST_WRITE; - else - nreg &= ~(DMA_ST_WRITE); - nreg |= DMA_ENABLE; - sbus_writel(nreg, esp->dregs + DMA_CSR); - if (esp->dma->revision == dvmaesc1) { - /* This ESC gate array sucks! */ - __u32 src = addr; - __u32 dest = src + count; - - if (dest & (PAGE_SIZE - 1)) - count = PAGE_ALIGN(count); - sbus_writel(count, esp->dregs + DMA_COUNT); - } - sbus_writel(addr, esp->dregs + DMA_ADDR); -} - -static void dma_drain(struct esp *esp) -{ - u32 tmp; - - if (esp->dma->revision == dvmahme) - return; - if ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_FIFO_ISDRAIN) { - switch (esp->dma->revision) { - default: - tmp |= DMA_FIFO_STDRAIN; - sbus_writel(tmp, esp->dregs + DMA_CSR); - - case dvmarev3: - case dvmaesc1: - while (sbus_readl(esp->dregs + DMA_CSR) & DMA_FIFO_ISDRAIN) - udelay(1); - }; - } -} - -static void dma_invalidate(struct esp *esp) -{ - u32 tmp; - - if (esp->dma->revision == dvmahme) { - sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR); - - esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | - (DMA_PARITY_OFF | DMA_2CLKS | - DMA_SCSI_DISAB | DMA_INT_ENAB)) & - ~(DMA_ST_WRITE | DMA_ENABLE)); - - sbus_writel(0, esp->dregs + DMA_CSR); - sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); - - /* This is necessary to avoid having the SCSI channel - * engine lock up on us. - */ - sbus_writel(0, esp->dregs + DMA_ADDR); - } else { - while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ) - udelay(1); - - tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); - tmp |= DMA_FIFO_INV; - sbus_writel(tmp, esp->dregs + DMA_CSR); - tmp &= ~DMA_FIFO_INV; - sbus_writel(tmp, esp->dregs + DMA_CSR); - } -} - -static inline void dma_flashclear(struct esp *esp) -{ - dma_drain(esp); - dma_invalidate(esp); -} - -static int dma_can_transfer(struct esp *esp, struct scsi_cmnd *sp) -{ - __u32 base, end, sz; - - if (esp->dma->revision == dvmarev3) { - sz = sp->SCp.this_residual; - if (sz > 0x1000000) - sz = 0x1000000; - } else { - base = ((__u32)((unsigned long)sp->SCp.ptr)); - base &= (0x1000000 - 1); - end = (base + sp->SCp.this_residual); - if (end > 0x1000000) - end = 0x1000000; - sz = (end - base); - } - return sz; -} - -/* Misc. esp helper macros. */ -#define esp_setcount(__eregs, __cnt, __hme) \ - sbus_writeb(((__cnt)&0xff), (__eregs) + ESP_TCLOW); \ - sbus_writeb((((__cnt)>>8)&0xff), (__eregs) + ESP_TCMED); \ - if (__hme) { \ - sbus_writeb((((__cnt)>>16)&0xff), (__eregs) + FAS_RLO); \ - sbus_writeb(0, (__eregs) + FAS_RHI); \ - } - -#define esp_getcount(__eregs, __hme) \ - ((sbus_readb((__eregs) + ESP_TCLOW)&0xff) | \ - ((sbus_readb((__eregs) + ESP_TCMED)&0xff) << 8) | \ - ((__hme) ? sbus_readb((__eregs) + FAS_RLO) << 16 : 0)) - -#define fcount(__esp) \ - (((__esp)->erev == fashme) ? \ - (__esp)->hme_fifo_workaround_count : \ - sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_FBYTES) - -#define fnzero(__esp) \ - (((__esp)->erev == fashme) ? 0 : \ - sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_ONOTZERO) - -/* XXX speculative nops unnecessary when continuing amidst a data phase - * XXX even on esp100!!! another case of flooding the bus with I/O reg - * XXX writes... - */ -#define esp_maybe_nop(__esp) \ - if ((__esp)->erev == esp100) \ - esp_cmd((__esp), ESP_CMD_NULL) - -#define sreg_to_dataphase(__sreg) \ - ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain) - -/* The ESP100 when in synchronous data phase, can mistake a long final - * REQ pulse from the target as an extra byte, it places whatever is on - * the data lines into the fifo. For now, we will assume when this - * happens that the target is a bit quirky and we don't want to - * be talking synchronously to it anyways. Regardless, we need to - * tell the ESP to eat the extraneous byte so that we can proceed - * to the next phase. - */ -static int esp100_sync_hwbug(struct esp *esp, struct scsi_cmnd *sp, int fifocnt) -{ - /* Do not touch this piece of code. */ - if ((!(esp->erev == esp100)) || - (!(sreg_datainp((esp->sreg = sbus_readb(esp->eregs + ESP_STATUS))) && - !fifocnt) && - !(sreg_dataoutp(esp->sreg) && !fnzero(esp)))) { - if (sp->SCp.phase == in_dataout) - esp_cmd(esp, ESP_CMD_FLUSH); - return 0; - } else { - /* Async mode for this guy. */ - build_sync_nego_msg(esp, 0, 0); - - /* Ack the bogus byte, but set ATN first. */ - esp_cmd(esp, ESP_CMD_SATN); - esp_cmd(esp, ESP_CMD_MOK); - return 1; - } -} - -/* This closes the window during a selection with a reselect pending, because - * we use DMA for the selection process the FIFO should hold the correct - * contents if we get reselected during this process. So we just need to - * ack the possible illegal cmd interrupt pending on the esp100. - */ -static inline int esp100_reconnect_hwbug(struct esp *esp) -{ - u8 tmp; - - if (esp->erev != esp100) - return 0; - tmp = sbus_readb(esp->eregs + ESP_INTRPT); - if (tmp & ESP_INTR_SR) - return 1; - return 0; -} - -/* This verifies the BUSID bits during a reselection so that we know which - * target is talking to us. - */ -static inline int reconnect_target(struct esp *esp) -{ - int it, me = esp->scsi_id_mask, targ = 0; - - if (2 != fcount(esp)) - return -1; - if (esp->erev == fashme) { - /* HME does not latch it's own BUS ID bits during - * a reselection. Also the target number is given - * as an unsigned char, not as a sole bit number - * like the other ESP's do. - * Happy Meal indeed.... - */ - targ = esp->hme_fifo_workaround_buffer[0]; - } else { - it = sbus_readb(esp->eregs + ESP_FDATA); - if (!(it & me)) - return -1; - it &= ~me; - if (it & (it - 1)) - return -1; - while (!(it & 1)) - targ++, it >>= 1; - } - return targ; -} - -/* This verifies the identify from the target so that we know which lun is - * being reconnected. - */ -static inline int reconnect_lun(struct esp *esp) -{ - int lun; - - if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) - return -1; - if (esp->erev == fashme) - lun = esp->hme_fifo_workaround_buffer[1]; - else - lun = sbus_readb(esp->eregs + ESP_FDATA); - - /* Yes, you read this correctly. We report lun of zero - * if we see parity error. ESP reports parity error for - * the lun byte, and this is the only way to hope to recover - * because the target is connected. - */ - if (esp->sreg & ESP_STAT_PERR) - return 0; - - /* Check for illegal bits being set in the lun. */ - if ((lun & 0x40) || !(lun & 0x80)) - return -1; - - return lun & 7; -} - -/* This puts the driver in a state where it can revitalize a command that - * is being continued due to reselection. - */ -static inline void esp_connect(struct esp *esp, struct scsi_cmnd *sp) -{ - struct esp_device *esp_dev = sp->device->hostdata; - - if (esp->prev_soff != esp_dev->sync_max_offset || - esp->prev_stp != esp_dev->sync_min_period || - (esp->erev > esp100a && - esp->prev_cfg3 != esp->config3[sp->device->id])) { - esp->prev_soff = esp_dev->sync_max_offset; - esp->prev_stp = esp_dev->sync_min_period; - sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); - sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); - if (esp->erev > esp100a) { - esp->prev_cfg3 = esp->config3[sp->device->id]; - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - } - } - esp->current_SC = sp; -} - -/* This will place the current working command back into the issue queue - * if we are to receive a reselection amidst a selection attempt. - */ -static inline void esp_reconnect(struct esp *esp, struct scsi_cmnd *sp) -{ - if (!esp->disconnected_SC) - ESPLOG(("esp%d: Weird, being reselected but disconnected " - "command queue is empty.\n", esp->esp_id)); - esp->snip = 0; - esp->current_SC = NULL; - sp->SCp.phase = not_issued; - append_SC(&esp->issue_SC, sp); -} - -/* Begin message in phase. */ -static int esp_do_msgin(struct esp *esp) -{ - /* Must be very careful with the fifo on the HME */ - if ((esp->erev != fashme) || - !(sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_FEMPTY)) - esp_cmd(esp, ESP_CMD_FLUSH); - esp_maybe_nop(esp); - esp_cmd(esp, ESP_CMD_TI); - esp->msgin_len = 1; - esp->msgin_ctr = 0; - esp_advance_phase(esp->current_SC, in_msgindone); - return do_work_bus; -} - -/* This uses various DMA csr fields and the fifo flags count value to - * determine how many bytes were successfully sent/received by the ESP. - */ -static inline int esp_bytes_sent(struct esp *esp, int fifo_count) -{ - int rval = sbus_readl(esp->dregs + DMA_ADDR) - esp->esp_command_dvma; - - if (esp->dma->revision == dvmarev1) - rval -= (4 - ((sbus_readl(esp->dregs + DMA_CSR) & DMA_READ_AHEAD)>>11)); - return rval - fifo_count; -} - -static inline void advance_sg(struct scsi_cmnd *sp) -{ - ++sp->SCp.buffer; - --sp->SCp.buffers_residual; - sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer); - sp->SCp.ptr = (char *)((unsigned long)sg_dma_address(sp->SCp.buffer)); -} - -/* Please note that the way I've coded these routines is that I _always_ - * check for a disconnect during any and all information transfer - * phases. The SCSI standard states that the target _can_ cause a BUS - * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note - * that during information transfer phases the target controls every - * change in phase, the only thing the initiator can do is "ask" for - * a message out phase by driving ATN true. The target can, and sometimes - * will, completely ignore this request so we cannot assume anything when - * we try to force a message out phase to abort/reset a target. Most of - * the time the target will eventually be nice and go to message out, so - * we may have to hold on to our state about what we want to tell the target - * for some period of time. - */ - -/* I think I have things working here correctly. Even partial transfers - * within a buffer or sub-buffer should not upset us at all no matter - * how bad the target and/or ESP fucks things up. - */ -static int esp_do_data(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; - int thisphase, hmuch; - - ESPDATA(("esp_do_data: ")); - esp_maybe_nop(esp); - thisphase = sreg_to_dataphase(esp->sreg); - esp_advance_phase(SCptr, thisphase); - ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT")); - hmuch = dma_can_transfer(esp, SCptr); - if (hmuch > (64 * 1024) && (esp->erev != fashme)) - hmuch = (64 * 1024); - ESPDATA(("hmuch<%d> ", hmuch)); - esp->current_transfer_size = hmuch; - - if (esp->erev == fashme) { - u32 tmp = esp->prev_hme_dmacsr; - - /* Always set the ESP count registers first. */ - esp_setcount(esp->eregs, hmuch, 1); - - /* Get the DMA csr computed. */ - tmp |= (DMA_SCSI_DISAB | DMA_ENABLE); - if (thisphase == in_datain) - tmp |= DMA_ST_WRITE; - else - tmp &= ~(DMA_ST_WRITE); - esp->prev_hme_dmacsr = tmp; - - ESPDATA(("DMA|TI --> do_intr_end\n")); - if (thisphase == in_datain) { - sbus_writel(hmuch, esp->dregs + DMA_COUNT); - esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); - } else { - esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); - sbus_writel(hmuch, esp->dregs + DMA_COUNT); - } - sbus_writel((__u32)((unsigned long)SCptr->SCp.ptr), esp->dregs+DMA_ADDR); - sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); - } else { - esp_setcount(esp->eregs, hmuch, 0); - dma_setup(esp, ((__u32)((unsigned long)SCptr->SCp.ptr)), - hmuch, (thisphase == in_datain)); - ESPDATA(("DMA|TI --> do_intr_end\n")); - esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); - } - return do_intr_end; -} - -/* See how successful the data transfer was. */ -static int esp_do_data_finale(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; - struct esp_device *esp_dev = SCptr->device->hostdata; - int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0; - - ESPDATA(("esp_do_data_finale: ")); - - if (SCptr->SCp.phase == in_datain) { - if (esp->sreg & ESP_STAT_PERR) { - /* Yuck, parity error. The ESP asserts ATN - * so that we can go to message out phase - * immediately and inform the target that - * something bad happened. - */ - ESPLOG(("esp%d: data bad parity detected.\n", - esp->esp_id)); - esp->cur_msgout[0] = INITIATOR_ERROR; - esp->msgout_len = 1; - } - dma_drain(esp); - } - dma_invalidate(esp); - - /* This could happen for the above parity error case. */ - if (esp->ireg != ESP_INTR_BSERV) { - /* Please go to msgout phase, please please please... */ - ESPLOG(("esp%d: !BSERV after data, probably to msgout\n", - esp->esp_id)); - return esp_do_phase_determine(esp); - } - - /* Check for partial transfers and other horrible events. - * Note, here we read the real fifo flags register even - * on HME broken adapters because we skip the HME fifo - * workaround code in esp_handle() if we are doing data - * phase things. We don't want to fuck directly with - * the fifo like that, especially if doing synchronous - * transfers! Also, will need to double the count on - * HME if we are doing wide transfers, as the HME fifo - * will move and count 16-bit quantities during wide data. - * SMCC _and_ Qlogic can both bite me. - */ - fifocnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES); - if (esp->erev != fashme) - ecount = esp_getcount(esp->eregs, 0); - bytes_sent = esp->current_transfer_size; - - ESPDATA(("trans_sz(%d), ", bytes_sent)); - if (esp->erev == fashme) { - if (!(esp->sreg & ESP_STAT_TCNT)) { - ecount = esp_getcount(esp->eregs, 1); - bytes_sent -= ecount; - } - - /* Always subtract any cruft remaining in the FIFO. */ - if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE) - fifocnt <<= 1; - if (SCptr->SCp.phase == in_dataout) - bytes_sent -= fifocnt; - - /* I have an IBM disk which exhibits the following - * behavior during writes to it. It disconnects in - * the middle of a partial transfer, the current sglist - * buffer is 1024 bytes, the disk stops data transfer - * at 512 bytes. - * - * However the FAS366 reports that 32 more bytes were - * transferred than really were. This is precisely - * the size of a fully loaded FIFO in wide scsi mode. - * The FIFO state recorded indicates that it is empty. - * - * I have no idea if this is a bug in the FAS366 chip - * or a bug in the firmware on this IBM disk. In any - * event the following seems to be a good workaround. -DaveM - */ - if (bytes_sent != esp->current_transfer_size && - SCptr->SCp.phase == in_dataout) { - int mask = (64 - 1); - - if ((esp->prev_cfg3 & ESP_CONFIG3_EWIDE) == 0) - mask >>= 1; - - if (bytes_sent & mask) - bytes_sent -= (bytes_sent & mask); - } - } else { - if (!(esp->sreg & ESP_STAT_TCNT)) - bytes_sent -= ecount; - if (SCptr->SCp.phase == in_dataout) - bytes_sent -= fifocnt; - } - - ESPDATA(("bytes_sent(%d), ", bytes_sent)); - - /* If we were in synchronous mode, check for peculiarities. */ - if (esp->erev == fashme) { - if (esp_dev->sync_max_offset) { - if (SCptr->SCp.phase == in_dataout) - esp_cmd(esp, ESP_CMD_FLUSH); - } else { - esp_cmd(esp, ESP_CMD_FLUSH); - } - } else { - if (esp_dev->sync_max_offset) - bogus_data = esp100_sync_hwbug(esp, SCptr, fifocnt); - else - esp_cmd(esp, ESP_CMD_FLUSH); - } - - /* Until we are sure of what has happened, we are certainly - * in the dark. - */ - esp_advance_phase(SCptr, in_the_dark); - - if (bytes_sent < 0) { - /* I've seen this happen due to lost state in this - * driver. No idea why it happened, but allowing - * this value to be negative caused things to - * lock up. This allows greater chance of recovery. - * In fact every time I've seen this, it has been - * a driver bug without question. - */ - ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id)); - ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n", - esp->esp_id, - esp->current_transfer_size, fifocnt, ecount)); - ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n", - esp->esp_id, - SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual)); - ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, - SCptr->device->id)); - SCptr->device->borken = 1; - esp_dev->sync = 0; - bytes_sent = 0; - } - - /* Update the state of our transfer. */ - SCptr->SCp.ptr += bytes_sent; - SCptr->SCp.this_residual -= bytes_sent; - if (SCptr->SCp.this_residual < 0) { - /* shit */ - ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id)); - SCptr->SCp.this_residual = 0; - } - - /* Maybe continue. */ - if (!bogus_data) { - ESPDATA(("!bogus_data, ")); - - /* NO MATTER WHAT, we advance the scatterlist, - * if the target should decide to disconnect - * in between scatter chunks (which is common) - * we could die horribly! I used to have the sg - * advance occur only if we are going back into - * (or are staying in) a data phase, you can - * imagine the hell I went through trying to - * figure this out. - */ - if (SCptr->use_sg && !SCptr->SCp.this_residual) - advance_sg(SCptr); - if (sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) { - ESPDATA(("to more data\n")); - return esp_do_data(esp); - } - ESPDATA(("to new phase\n")); - return esp_do_phase_determine(esp); - } - /* Bogus data, just wait for next interrupt. */ - ESPLOG(("esp%d: bogus_data during end of data phase\n", - esp->esp_id)); - return do_intr_end; -} - -/* We received a non-good status return at the end of - * running a SCSI command. This is used to decide if - * we should clear our synchronous transfer state for - * such a device when that happens. - * - * The idea is that when spinning up a disk or rewinding - * a tape, we don't want to go into a loop re-negotiating - * synchronous capabilities over and over. - */ -static int esp_should_clear_sync(struct scsi_cmnd *sp) -{ - u8 cmd = sp->cmnd[0]; - - /* These cases are for spinning up a disk and - * waiting for that spinup to complete. - */ - if (cmd == START_STOP) - return 0; - - if (cmd == TEST_UNIT_READY) - return 0; - - /* One more special case for SCSI tape drives, - * this is what is used to probe the device for - * completion of a rewind or tape load operation. - */ - if (sp->device->type == TYPE_TAPE) { - if (cmd == MODE_SENSE) - return 0; - } - - return 1; -} - -/* Either a command is completing or a target is dropping off the bus - * to continue the command in the background so we can do other work. - */ -static int esp_do_freebus(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; - struct esp_device *esp_dev = SCptr->device->hostdata; - int rval; - - rval = skipahead2(esp, SCptr, in_status, in_msgindone, in_freeing); - if (rval) - return rval; - if (esp->ireg != ESP_INTR_DC) { - ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id)); - return do_reset_bus; /* target will not drop BSY... */ - } - esp->msgout_len = 0; - esp->prevmsgout = NOP; - if (esp->prevmsgin == COMMAND_COMPLETE) { - /* Normal end of nexus. */ - if (esp->disconnected_SC || (esp->erev == fashme)) - esp_cmd(esp, ESP_CMD_ESEL); - - if (SCptr->SCp.Status != GOOD && - SCptr->SCp.Status != CONDITION_GOOD && - ((1<device->id) & esp->targets_present) && - esp_dev->sync && - esp_dev->sync_max_offset) { - /* SCSI standard says that the synchronous capabilities - * should be renegotiated at this point. Most likely - * we are about to request sense from this target - * in which case we want to avoid using sync - * transfers until we are sure of the current target - * state. - */ - ESPMISC(("esp: Status <%d> for target %d lun %d\n", - SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun)); - - /* But don't do this when spinning up a disk at - * boot time while we poll for completion as it - * fills up the console with messages. Also, tapes - * can report not ready many times right after - * loading up a tape. - */ - if (esp_should_clear_sync(SCptr) != 0) - esp_dev->sync = 0; - } - ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); - esp_done(esp, ((SCptr->SCp.Status & 0xff) | - ((SCptr->SCp.Message & 0xff)<<8) | - (DID_OK << 16))); - } else if (esp->prevmsgin == DISCONNECT) { - /* Normal disconnect. */ - esp_cmd(esp, ESP_CMD_ESEL); - ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); - append_SC(&esp->disconnected_SC, SCptr); - esp->current_SC = NULL; - if (esp->issue_SC) - esp_exec_cmd(esp); - } else { - /* Driver bug, we do not expect a disconnect here - * and should not have advanced the state engine - * to in_freeing. - */ - ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n", - esp->esp_id)); - return do_reset_bus; - } - return do_intr_end; -} - -/* When a reselect occurs, and we cannot find the command to - * reconnect to in our queues, we do this. - */ -static int esp_bad_reconnect(struct esp *esp) -{ - struct scsi_cmnd *sp; - - ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n", - esp->esp_id)); - ESPLOG(("QUEUE DUMP\n")); - sp = esp->issue_SC; - ESPLOG(("esp%d: issue_SC[", esp->esp_id)); - while (sp) { - ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); - sp = (struct scsi_cmnd *) sp->host_scribble; - } - ESPLOG(("]\n")); - sp = esp->current_SC; - ESPLOG(("esp%d: current_SC[", esp->esp_id)); - if (sp) - ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); - else - ESPLOG(("")); - ESPLOG(("]\n")); - sp = esp->disconnected_SC; - ESPLOG(("esp%d: disconnected_SC[", esp->esp_id)); - while (sp) { - ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); - sp = (struct scsi_cmnd *) sp->host_scribble; - } - ESPLOG(("]\n")); - return do_reset_bus; -} - -/* Do the needy when a target tries to reconnect to us. */ -static int esp_do_reconnect(struct esp *esp) -{ - int lun, target; - struct scsi_cmnd *SCptr; - - /* Check for all bogus conditions first. */ - target = reconnect_target(esp); - if (target < 0) { - ESPDISC(("bad bus bits\n")); - return do_reset_bus; - } - lun = reconnect_lun(esp); - if (lun < 0) { - ESPDISC(("target=%2x, bad identify msg\n", target)); - return do_reset_bus; - } - - /* Things look ok... */ - ESPDISC(("R<%02x,%02x>", target, lun)); - - /* Must not flush FIFO or DVMA on HME. */ - if (esp->erev != fashme) { - esp_cmd(esp, ESP_CMD_FLUSH); - if (esp100_reconnect_hwbug(esp)) - return do_reset_bus; - esp_cmd(esp, ESP_CMD_NULL); - } - - SCptr = remove_SC(&esp->disconnected_SC, (u8) target, (u8) lun); - if (!SCptr) - return esp_bad_reconnect(esp); - - esp_connect(esp, SCptr); - esp_cmd(esp, ESP_CMD_MOK); - - if (esp->erev == fashme) - sbus_writeb(((SCptr->device->id & 0xf) | - (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT)), - esp->eregs + ESP_BUSID); - - /* Reconnect implies a restore pointers operation. */ - esp_restore_pointers(esp, SCptr); - - esp->snip = 0; - esp_advance_phase(SCptr, in_the_dark); - return do_intr_end; -} - -/* End of NEXUS (hopefully), pick up status + message byte then leave if - * all goes well. - */ -static int esp_do_status(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; - int intr, rval; - - rval = skipahead1(esp, SCptr, in_the_dark, in_status); - if (rval) - return rval; - intr = esp->ireg; - ESPSTAT(("esp_do_status: ")); - if (intr != ESP_INTR_DC) { - int message_out = 0; /* for parity problems */ - - /* Ack the message. */ - ESPSTAT(("ack msg, ")); - esp_cmd(esp, ESP_CMD_MOK); - - if (esp->erev != fashme) { - dma_flashclear(esp); - - /* Wait till the first bits settle. */ - while (esp->esp_command[0] == 0xff) - udelay(1); - } else { - esp->esp_command[0] = esp->hme_fifo_workaround_buffer[0]; - esp->esp_command[1] = esp->hme_fifo_workaround_buffer[1]; - } - - ESPSTAT(("got something, ")); - /* ESP chimes in with one of - * - * 1) function done interrupt: - * both status and message in bytes - * are available - * - * 2) bus service interrupt: - * only status byte was acquired - * - * 3) Anything else: - * can't happen, but we test for it - * anyways - * - * ALSO: If bad parity was detected on either - * the status _or_ the message byte then - * the ESP has asserted ATN on the bus - * and we must therefore wait for the - * next phase change. - */ - if (intr & ESP_INTR_FDONE) { - /* We got it all, hallejulia. */ - ESPSTAT(("got both, ")); - SCptr->SCp.Status = esp->esp_command[0]; - SCptr->SCp.Message = esp->esp_command[1]; - esp->prevmsgin = SCptr->SCp.Message; - esp->cur_msgin[0] = SCptr->SCp.Message; - if (esp->sreg & ESP_STAT_PERR) { - /* There was bad parity for the - * message byte, the status byte - * was ok. - */ - message_out = MSG_PARITY_ERROR; - } - } else if (intr == ESP_INTR_BSERV) { - /* Only got status byte. */ - ESPLOG(("esp%d: got status only, ", esp->esp_id)); - if (!(esp->sreg & ESP_STAT_PERR)) { - SCptr->SCp.Status = esp->esp_command[0]; - SCptr->SCp.Message = 0xff; - } else { - /* The status byte had bad parity. - * we leave the scsi_pointer Status - * field alone as we set it to a default - * of CHECK_CONDITION in esp_queue. - */ - message_out = INITIATOR_ERROR; - } - } else { - /* This shouldn't happen ever. */ - ESPSTAT(("got bolixed\n")); - esp_advance_phase(SCptr, in_the_dark); - return esp_do_phase_determine(esp); - } - - if (!message_out) { - ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status, - SCptr->SCp.Message)); - if (SCptr->SCp.Message == COMMAND_COMPLETE) { - ESPSTAT(("and was COMMAND_COMPLETE\n")); - esp_advance_phase(SCptr, in_freeing); - return esp_do_freebus(esp); - } else { - ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n", - esp->esp_id)); - esp->msgin_len = esp->msgin_ctr = 1; - esp_advance_phase(SCptr, in_msgindone); - return esp_do_msgindone(esp); - } - } else { - /* With luck we'll be able to let the target - * know that bad parity happened, it will know - * which byte caused the problems and send it - * again. For the case where the status byte - * receives bad parity, I do not believe most - * targets recover very well. We'll see. - */ - ESPLOG(("esp%d: bad parity somewhere mout=%2x\n", - esp->esp_id, message_out)); - esp->cur_msgout[0] = message_out; - esp->msgout_len = esp->msgout_ctr = 1; - esp_advance_phase(SCptr, in_the_dark); - return esp_do_phase_determine(esp); - } - } else { - /* If we disconnect now, all hell breaks loose. */ - ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id)); - esp_advance_phase(SCptr, in_the_dark); - return esp_do_phase_determine(esp); - } -} - -static int esp_enter_status(struct esp *esp) -{ - u8 thecmd = ESP_CMD_ICCSEQ; - - esp_cmd(esp, ESP_CMD_FLUSH); - if (esp->erev != fashme) { - u32 tmp; - - esp->esp_command[0] = esp->esp_command[1] = 0xff; - sbus_writeb(2, esp->eregs + ESP_TCLOW); - sbus_writeb(0, esp->eregs + ESP_TCMED); - tmp = sbus_readl(esp->dregs + DMA_CSR); - tmp |= (DMA_ST_WRITE | DMA_ENABLE); - sbus_writel(tmp, esp->dregs + DMA_CSR); - if (esp->dma->revision == dvmaesc1) - sbus_writel(0x100, esp->dregs + DMA_COUNT); - sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR); - thecmd |= ESP_CMD_DMA; - } - esp_cmd(esp, thecmd); - esp_advance_phase(esp->current_SC, in_status); - - return esp_do_status(esp); -} - -static int esp_disconnect_amidst_phases(struct esp *esp) -{ - struct scsi_cmnd *sp = esp->current_SC; - struct esp_device *esp_dev = sp->device->hostdata; - - /* This means real problems if we see this - * here. Unless we were actually trying - * to force the device to abort/reset. - */ - ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id)); - ESPLOG(("pphase<%s> cphase<%s>, ", - phase_string(sp->SCp.phase), - phase_string(sp->SCp.sent_command))); - - if (esp->disconnected_SC != NULL || (esp->erev == fashme)) - esp_cmd(esp, ESP_CMD_ESEL); - - switch (esp->cur_msgout[0]) { - default: - /* We didn't expect this to happen at all. */ - ESPLOG(("device is bolixed\n")); - esp_advance_phase(sp, in_tgterror); - esp_done(esp, (DID_ERROR << 16)); - break; - - case BUS_DEVICE_RESET: - ESPLOG(("device reset successful\n")); - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - esp_dev->sync = 0; - esp_advance_phase(sp, in_resetdev); - esp_done(esp, (DID_RESET << 16)); - break; - - case ABORT: - ESPLOG(("device abort successful\n")); - esp_advance_phase(sp, in_abortone); - esp_done(esp, (DID_ABORT << 16)); - break; - - }; - return do_intr_end; -} - -static int esp_enter_msgout(struct esp *esp) -{ - esp_advance_phase(esp->current_SC, in_msgout); - return esp_do_msgout(esp); -} - -static int esp_enter_msgin(struct esp *esp) -{ - esp_advance_phase(esp->current_SC, in_msgin); - return esp_do_msgin(esp); -} - -static int esp_enter_cmd(struct esp *esp) -{ - esp_advance_phase(esp->current_SC, in_cmdbegin); - return esp_do_cmdbegin(esp); -} - -static int esp_enter_badphase(struct esp *esp) -{ - ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id, - esp->sreg & ESP_STAT_PMASK)); - return do_reset_bus; -} - -typedef int (*espfunc_t)(struct esp *); - -static espfunc_t phase_vector[] = { - esp_do_data, /* ESP_DOP */ - esp_do_data, /* ESP_DIP */ - esp_enter_cmd, /* ESP_CMDP */ - esp_enter_status, /* ESP_STATP */ - esp_enter_badphase, /* ESP_STAT_PMSG */ - esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */ - esp_enter_msgout, /* ESP_MOP */ - esp_enter_msgin, /* ESP_MIP */ -}; - -/* The target has control of the bus and we have to see where it has - * taken us. - */ -static int esp_do_phase_determine(struct esp *esp) -{ - if ((esp->ireg & ESP_INTR_DC) != 0) - return esp_disconnect_amidst_phases(esp); - return phase_vector[esp->sreg & ESP_STAT_PMASK](esp); -} - -/* First interrupt after exec'ing a cmd comes here. */ -static int esp_select_complete(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; - struct esp_device *esp_dev = SCptr->device->hostdata; - int cmd_bytes_sent, fcnt; - - if (esp->erev != fashme) - esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS); - - if (esp->erev == fashme) - fcnt = esp->hme_fifo_workaround_count; - else - fcnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES); - - cmd_bytes_sent = esp_bytes_sent(esp, fcnt); - dma_invalidate(esp); - - /* Let's check to see if a reselect happened - * while we we're trying to select. This must - * be checked first. - */ - if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) { - esp_reconnect(esp, SCptr); - return esp_do_reconnect(esp); - } - - /* Looks like things worked, we should see a bus service & - * a function complete interrupt at this point. Note we - * are doing a direct comparison because we don't want to - * be fooled into thinking selection was successful if - * ESP_INTR_DC is set, see below. - */ - if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) { - /* target speaks... */ - esp->targets_present |= (1<device->id); - - /* What if the target ignores the sdtr? */ - if (esp->snip) - esp_dev->sync = 1; - - /* See how far, if at all, we got in getting - * the information out to the target. - */ - switch (esp->seqreg) { - default: - - case ESP_STEP_ASEL: - /* Arbitration won, target selected, but - * we are in some phase which is not command - * phase nor is it message out phase. - * - * XXX We've confused the target, obviously. - * XXX So clear it's state, but we also end - * XXX up clearing everyone elses. That isn't - * XXX so nice. I'd like to just reset this - * XXX target, but if I cannot even get it's - * XXX attention and finish selection to talk - * XXX to it, there is not much more I can do. - * XXX If we have a loaded bus we're going to - * XXX spend the next second or so renegotiating - * XXX for synchronous transfers. - */ - ESPLOG(("esp%d: STEP_ASEL for tgt %d\n", - esp->esp_id, SCptr->device->id)); - - case ESP_STEP_SID: - /* Arbitration won, target selected, went - * to message out phase, sent one message - * byte, then we stopped. ATN is asserted - * on the SCSI bus and the target is still - * there hanging on. This is a legal - * sequence step if we gave the ESP a select - * and stop command. - * - * XXX See above, I could set the borken flag - * XXX in the device struct and retry the - * XXX command. But would that help for - * XXX tagged capable targets? - */ - - case ESP_STEP_NCMD: - /* Arbitration won, target selected, maybe - * sent the one message byte in message out - * phase, but we did not go to command phase - * in the end. Actually, we could have sent - * only some of the message bytes if we tried - * to send out the entire identify and tag - * message using ESP_CMD_SA3. - */ - cmd_bytes_sent = 0; - break; - - case ESP_STEP_PPC: - /* No, not the powerPC pinhead. Arbitration - * won, all message bytes sent if we went to - * message out phase, went to command phase - * but only part of the command was sent. - * - * XXX I've seen this, but usually in conjunction - * XXX with a gross error which appears to have - * XXX occurred between the time I told the - * XXX ESP to arbitrate and when I got the - * XXX interrupt. Could I have misloaded the - * XXX command bytes into the fifo? Actually, - * XXX I most likely missed a phase, and therefore - * XXX went into never never land and didn't even - * XXX know it. That was the old driver though. - * XXX What is even more peculiar is that the ESP - * XXX showed the proper function complete and - * XXX bus service bits in the interrupt register. - */ - - case ESP_STEP_FINI4: - case ESP_STEP_FINI5: - case ESP_STEP_FINI6: - case ESP_STEP_FINI7: - /* Account for the identify message */ - if (SCptr->SCp.phase == in_slct_norm) - cmd_bytes_sent -= 1; - }; - - if (esp->erev != fashme) - esp_cmd(esp, ESP_CMD_NULL); - - /* Be careful, we could really get fucked during synchronous - * data transfers if we try to flush the fifo now. - */ - if ((esp->erev != fashme) && /* not a Happy Meal and... */ - !fcnt && /* Fifo is empty and... */ - /* either we are not doing synchronous transfers or... */ - (!esp_dev->sync_max_offset || - /* We are not going into data in phase. */ - ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP))) - esp_cmd(esp, ESP_CMD_FLUSH); /* flush is safe */ - - /* See how far we got if this is not a slow command. */ - if (!esp->esp_slowcmd) { - if (cmd_bytes_sent < 0) - cmd_bytes_sent = 0; - if (cmd_bytes_sent != SCptr->cmd_len) { - /* Crapola, mark it as a slowcmd - * so that we have some chance of - * keeping the command alive with - * good luck. - * - * XXX Actually, if we didn't send it all - * XXX this means either we didn't set things - * XXX up properly (driver bug) or the target - * XXX or the ESP detected parity on one of - * XXX the command bytes. This makes much - * XXX more sense, and therefore this code - * XXX should be changed to send out a - * XXX parity error message or if the status - * XXX register shows no parity error then - * XXX just expect the target to bring the - * XXX bus into message in phase so that it - * XXX can send us the parity error message. - * XXX SCSI sucks... - */ - esp->esp_slowcmd = 1; - esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]); - esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent); - } - } - - /* Now figure out where we went. */ - esp_advance_phase(SCptr, in_the_dark); - return esp_do_phase_determine(esp); - } - - /* Did the target even make it? */ - if (esp->ireg == ESP_INTR_DC) { - /* wheee... nobody there or they didn't like - * what we told it to do, clean up. - */ - - /* If anyone is off the bus, but working on - * a command in the background for us, tell - * the ESP to listen for them. - */ - if (esp->disconnected_SC) - esp_cmd(esp, ESP_CMD_ESEL); - - if (((1<device->id) & esp->targets_present) && - esp->seqreg != 0 && - (esp->cur_msgout[0] == EXTENDED_MESSAGE) && - (SCptr->SCp.phase == in_slct_msg || - SCptr->SCp.phase == in_slct_stop)) { - /* shit */ - esp->snip = 0; - ESPLOG(("esp%d: Failed synchronous negotiation for target %d " - "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - esp_dev->sync = 1; /* so we don't negotiate again */ - - /* Run the command again, this time though we - * won't try to negotiate for synchronous transfers. - * - * XXX I'd like to do something like send an - * XXX INITIATOR_ERROR or ABORT message to the - * XXX target to tell it, "Sorry I confused you, - * XXX please come back and I will be nicer next - * XXX time". But that requires having the target - * XXX on the bus, and it has dropped BSY on us. - */ - esp->current_SC = NULL; - esp_advance_phase(SCptr, not_issued); - prepend_SC(&esp->issue_SC, SCptr); - esp_exec_cmd(esp); - return do_intr_end; - } - - /* Ok, this is normal, this is what we see during boot - * or whenever when we are scanning the bus for targets. - * But first make sure that is really what is happening. - */ - if (((1<device->id) & esp->targets_present)) { - ESPLOG(("esp%d: Warning, live target %d not responding to " - "selection.\n", esp->esp_id, SCptr->device->id)); - - /* This _CAN_ happen. The SCSI standard states that - * the target is to _not_ respond to selection if - * _it_ detects bad parity on the bus for any reason. - * Therefore, we assume that if we've talked successfully - * to this target before, bad parity is the problem. - */ - esp_done(esp, (DID_PARITY << 16)); - } else { - /* Else, there really isn't anyone there. */ - ESPMISC(("esp: selection failure, maybe nobody there?\n")); - ESPMISC(("esp: target %d lun %d\n", - SCptr->device->id, SCptr->device->lun)); - esp_done(esp, (DID_BAD_TARGET << 16)); - } - return do_intr_end; - } - - ESPLOG(("esp%d: Selection failure.\n", esp->esp_id)); - printk("esp%d: Currently -- ", esp->esp_id); - esp_print_ireg(esp->ireg); printk(" "); - esp_print_statreg(esp->sreg); printk(" "); - esp_print_seqreg(esp->seqreg); printk("\n"); - printk("esp%d: New -- ", esp->esp_id); - esp->sreg = sbus_readb(esp->eregs + ESP_STATUS); - esp->seqreg = sbus_readb(esp->eregs + ESP_SSTEP); - esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); - esp_print_ireg(esp->ireg); printk(" "); - esp_print_statreg(esp->sreg); printk(" "); - esp_print_seqreg(esp->seqreg); printk("\n"); - ESPLOG(("esp%d: resetting bus\n", esp->esp_id)); - return do_reset_bus; /* ugh... */ -} - -/* Continue reading bytes for msgin phase. */ -static int esp_do_msgincont(struct esp *esp) -{ - if (esp->ireg & ESP_INTR_BSERV) { - /* in the right phase too? */ - if ((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) { - /* phew... */ - esp_cmd(esp, ESP_CMD_TI); - esp_advance_phase(esp->current_SC, in_msgindone); - return do_intr_end; - } - - /* We changed phase but ESP shows bus service, - * in this case it is most likely that we, the - * hacker who has been up for 20hrs straight - * staring at the screen, drowned in coffee - * smelling like retched cigarette ashes - * have miscoded something..... so, try to - * recover as best we can. - */ - ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id)); - } - esp_advance_phase(esp->current_SC, in_the_dark); - return do_phase_determine; -} - -static int check_singlebyte_msg(struct esp *esp) -{ - esp->prevmsgin = esp->cur_msgin[0]; - if (esp->cur_msgin[0] & 0x80) { - /* wheee... */ - ESPLOG(("esp%d: target sends identify amidst phases\n", - esp->esp_id)); - esp_advance_phase(esp->current_SC, in_the_dark); - return 0; - } else if (((esp->cur_msgin[0] & 0xf0) == 0x20) || - (esp->cur_msgin[0] == EXTENDED_MESSAGE)) { - esp->msgin_len = 2; - esp_advance_phase(esp->current_SC, in_msgincont); - return 0; - } - esp_advance_phase(esp->current_SC, in_the_dark); - switch (esp->cur_msgin[0]) { - default: - /* We don't want to hear about it. */ - ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id, - esp->cur_msgin[0])); - return MESSAGE_REJECT; - - case NOP: - ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id, - esp->current_SC->device->id)); - return 0; - - case RESTORE_POINTERS: - /* In this case we might also have to backup the - * "slow command" pointer. It is rare to get such - * a save/restore pointer sequence so early in the - * bus transition sequences, but cover it. - */ - if (esp->esp_slowcmd) { - esp->esp_scmdleft = esp->current_SC->cmd_len; - esp->esp_scmdp = &esp->current_SC->cmnd[0]; - } - esp_restore_pointers(esp, esp->current_SC); - return 0; - - case SAVE_POINTERS: - esp_save_pointers(esp, esp->current_SC); - return 0; - - case COMMAND_COMPLETE: - case DISCONNECT: - /* Freeing the bus, let it go. */ - esp->current_SC->SCp.phase = in_freeing; - return 0; - - case MESSAGE_REJECT: - ESPMISC(("msg reject, ")); - if (esp->prevmsgout == EXTENDED_MESSAGE) { - struct esp_device *esp_dev = esp->current_SC->device->hostdata; - - /* Doesn't look like this target can - * do synchronous or WIDE transfers. - */ - ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n")); - esp_dev->sync = 1; - esp_dev->wide = 1; - esp_dev->sync_min_period = 0; - esp_dev->sync_max_offset = 0; - return 0; - } else { - ESPMISC(("not sync nego, sending ABORT\n")); - return ABORT; - } - }; -} - -/* Target negotiates for synchronous transfers before we do, this - * is legal although very strange. What is even funnier is that - * the SCSI2 standard specifically recommends against targets doing - * this because so many initiators cannot cope with this occurring. - */ -static int target_with_ants_in_pants(struct esp *esp, - struct scsi_cmnd *SCptr, - struct esp_device *esp_dev) -{ - if (esp_dev->sync || SCptr->device->borken) { - /* sorry, no can do */ - ESPSDTR(("forcing to async, ")); - build_sync_nego_msg(esp, 0, 0); - esp_dev->sync = 1; - esp->snip = 1; - ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id)); - esp_advance_phase(SCptr, in_the_dark); - return EXTENDED_MESSAGE; - } - - /* Ok, we'll check them out... */ - return 0; -} - -static void sync_report(struct esp *esp) -{ - int msg3, msg4; - char *type; - - msg3 = esp->cur_msgin[3]; - msg4 = esp->cur_msgin[4]; - if (msg4) { - int hz = 1000000000 / (msg3 * 4); - int integer = hz / 1000000; - int fraction = (hz - (integer * 1000000)) / 10000; - if ((esp->erev == fashme) && - (esp->config3[esp->current_SC->device->id] & ESP_CONFIG3_EWIDE)) { - type = "FAST-WIDE"; - integer <<= 1; - fraction <<= 1; - } else if ((msg3 * 4) < 200) { - type = "FAST"; - } else { - type = "synchronous"; - } - - /* Do not transform this back into one big printk - * again, it triggers a bug in our sparc64-gcc272 - * sibling call optimization. -DaveM - */ - ESPLOG((KERN_INFO "esp%d: target %d ", - esp->esp_id, esp->current_SC->device->id)); - ESPLOG(("[period %dns offset %d %d.%02dMHz ", - (int) msg3 * 4, (int) msg4, - integer, fraction)); - ESPLOG(("%s SCSI%s]\n", type, - (((msg3 * 4) < 200) ? "-II" : ""))); - } else { - ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n", - esp->esp_id, esp->current_SC->device->id)); - } -} - -static int check_multibyte_msg(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; - struct esp_device *esp_dev = SCptr->device->hostdata; - u8 regval = 0; - int message_out = 0; - - ESPSDTR(("chk multibyte msg: ")); - if (esp->cur_msgin[2] == EXTENDED_SDTR) { - int period = esp->cur_msgin[3]; - int offset = esp->cur_msgin[4]; - - ESPSDTR(("is sync nego response, ")); - if (!esp->snip) { - int rval; - - /* Target negotiates first! */ - ESPSDTR(("target jumps the gun, ")); - message_out = EXTENDED_MESSAGE; /* we must respond */ - rval = target_with_ants_in_pants(esp, SCptr, esp_dev); - if (rval) - return rval; - } - - ESPSDTR(("examining sdtr, ")); - - /* Offset cannot be larger than ESP fifo size. */ - if (offset > 15) { - ESPSDTR(("offset too big %2x, ", offset)); - offset = 15; - ESPSDTR(("sending back new offset\n")); - build_sync_nego_msg(esp, period, offset); - return EXTENDED_MESSAGE; - } - - if (offset && period > esp->max_period) { - /* Yeee, async for this slow device. */ - ESPSDTR(("period too long %2x, ", period)); - build_sync_nego_msg(esp, 0, 0); - ESPSDTR(("hoping for msgout\n")); - esp_advance_phase(esp->current_SC, in_the_dark); - return EXTENDED_MESSAGE; - } else if (offset && period < esp->min_period) { - ESPSDTR(("period too short %2x, ", period)); - period = esp->min_period; - if (esp->erev > esp236) - regval = 4; - else - regval = 5; - } else if (offset) { - int tmp; - - ESPSDTR(("period is ok, ")); - tmp = esp->ccycle / 1000; - regval = (((period << 2) + tmp - 1) / tmp); - if (regval && ((esp->erev == fas100a || - esp->erev == fas236 || - esp->erev == fashme))) { - if (period >= 50) - regval--; - } - } - - if (offset) { - u8 bit; - - esp_dev->sync_min_period = (regval & 0x1f); - esp_dev->sync_max_offset = (offset | esp->radelay); - if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) { - if ((esp->erev == fas100a) || (esp->erev == fashme)) - bit = ESP_CONFIG3_FAST; - else - bit = ESP_CONFIG3_FSCSI; - if (period < 50) { - /* On FAS366, if using fast-20 synchronous transfers - * we need to make sure the REQ/ACK assert/deassert - * control bits are clear. - */ - if (esp->erev == fashme) - esp_dev->sync_max_offset &= ~esp->radelay; - esp->config3[SCptr->device->id] |= bit; - } else { - esp->config3[SCptr->device->id] &= ~bit; - } - esp->prev_cfg3 = esp->config3[SCptr->device->id]; - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - } - esp->prev_soff = esp_dev->sync_max_offset; - esp->prev_stp = esp_dev->sync_min_period; - sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); - sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); - ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n", - esp_dev->sync_max_offset, - esp_dev->sync_min_period, - esp->config3[SCptr->device->id])); - - esp->snip = 0; - } else if (esp_dev->sync_max_offset) { - u8 bit; - - /* back to async mode */ - ESPSDTR(("unaccaptable sync nego, forcing async\n")); - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - esp->prev_soff = 0; - esp->prev_stp = 0; - sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); - sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); - if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) { - if ((esp->erev == fas100a) || (esp->erev == fashme)) - bit = ESP_CONFIG3_FAST; - else - bit = ESP_CONFIG3_FSCSI; - esp->config3[SCptr->device->id] &= ~bit; - esp->prev_cfg3 = esp->config3[SCptr->device->id]; - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - } - } - - sync_report(esp); - - ESPSDTR(("chk multibyte msg: sync is known, ")); - esp_dev->sync = 1; - - if (message_out) { - ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n", - esp->esp_id)); - build_sync_nego_msg(esp, period, offset); - esp_advance_phase(SCptr, in_the_dark); - return EXTENDED_MESSAGE; - } - - ESPSDTR(("returning zero\n")); - esp_advance_phase(SCptr, in_the_dark); /* ...or else! */ - return 0; - } else if (esp->cur_msgin[2] == EXTENDED_WDTR) { - int size = 8 << esp->cur_msgin[3]; - - esp->wnip = 0; - if (esp->erev != fashme) { - ESPLOG(("esp%d: AIEEE wide msg received and not HME.\n", - esp->esp_id)); - message_out = MESSAGE_REJECT; - } else if (size > 16) { - ESPLOG(("esp%d: AIEEE wide transfer for %d size " - "not supported.\n", esp->esp_id, size)); - message_out = MESSAGE_REJECT; - } else { - /* Things look good; let's see what we got. */ - if (size == 16) { - /* Set config 3 register for this target. */ - esp->config3[SCptr->device->id] |= ESP_CONFIG3_EWIDE; - } else { - /* Just make sure it was one byte sized. */ - if (size != 8) { - ESPLOG(("esp%d: Aieee, wide nego of %d size.\n", - esp->esp_id, size)); - message_out = MESSAGE_REJECT; - goto finish; - } - /* Pure paranoia. */ - esp->config3[SCptr->device->id] &= ~(ESP_CONFIG3_EWIDE); - } - esp->prev_cfg3 = esp->config3[SCptr->device->id]; - sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); - - /* Regardless, next try for sync transfers. */ - build_sync_nego_msg(esp, esp->sync_defp, 15); - esp_dev->sync = 1; - esp->snip = 1; - message_out = EXTENDED_MESSAGE; - } - } else if (esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) { - ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id)); - message_out = MESSAGE_REJECT; - } -finish: - esp_advance_phase(SCptr, in_the_dark); - return message_out; -} - -static int esp_do_msgindone(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; - int message_out = 0, it = 0, rval; - - rval = skipahead1(esp, SCptr, in_msgin, in_msgindone); - if (rval) - return rval; - if (SCptr->SCp.sent_command != in_status) { - if (!(esp->ireg & ESP_INTR_DC)) { - if (esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) { - message_out = MSG_PARITY_ERROR; - esp_cmd(esp, ESP_CMD_FLUSH); - } else if (esp->erev != fashme && - (it = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES)) != 1) { - /* We certainly dropped the ball somewhere. */ - message_out = INITIATOR_ERROR; - esp_cmd(esp, ESP_CMD_FLUSH); - } else if (!esp->msgin_len) { - if (esp->erev == fashme) - it = esp->hme_fifo_workaround_buffer[0]; - else - it = sbus_readb(esp->eregs + ESP_FDATA); - esp_advance_phase(SCptr, in_msgincont); - } else { - /* it is ok and we want it */ - if (esp->erev == fashme) - it = esp->cur_msgin[esp->msgin_ctr] = - esp->hme_fifo_workaround_buffer[0]; - else - it = esp->cur_msgin[esp->msgin_ctr] = - sbus_readb(esp->eregs + ESP_FDATA); - esp->msgin_ctr++; - } - } else { - esp_advance_phase(SCptr, in_the_dark); - return do_work_bus; - } - } else { - it = esp->cur_msgin[0]; - } - if (!message_out && esp->msgin_len) { - if (esp->msgin_ctr < esp->msgin_len) { - esp_advance_phase(SCptr, in_msgincont); - } else if (esp->msgin_len == 1) { - message_out = check_singlebyte_msg(esp); - } else if (esp->msgin_len == 2) { - if (esp->cur_msgin[0] == EXTENDED_MESSAGE) { - if ((it + 2) >= 15) { - message_out = MESSAGE_REJECT; - } else { - esp->msgin_len = (it + 2); - esp_advance_phase(SCptr, in_msgincont); - } - } else { - message_out = MESSAGE_REJECT; /* foo on you */ - } - } else { - message_out = check_multibyte_msg(esp); - } - } - if (message_out < 0) { - return -message_out; - } else if (message_out) { - if (((message_out != 1) && - ((message_out < 0x20) || (message_out & 0x80)))) - esp->msgout_len = 1; - esp->cur_msgout[0] = message_out; - esp_cmd(esp, ESP_CMD_SATN); - esp_advance_phase(SCptr, in_the_dark); - esp->msgin_len = 0; - } - esp->sreg = sbus_readb(esp->eregs + ESP_STATUS); - esp->sreg &= ~(ESP_STAT_INTR); - if ((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD)) - esp_cmd(esp, ESP_CMD_MOK); - if ((SCptr->SCp.sent_command == in_msgindone) && - (SCptr->SCp.phase == in_freeing)) - return esp_do_freebus(esp); - return do_intr_end; -} - -static int esp_do_cmdbegin(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; - - esp_advance_phase(SCptr, in_cmdend); - if (esp->erev == fashme) { - u32 tmp = sbus_readl(esp->dregs + DMA_CSR); - int i; - - for (i = 0; i < esp->esp_scmdleft; i++) - esp->esp_command[i] = *esp->esp_scmdp++; - esp->esp_scmdleft = 0; - esp_cmd(esp, ESP_CMD_FLUSH); - esp_setcount(esp->eregs, i, 1); - esp_cmd(esp, (ESP_CMD_DMA | ESP_CMD_TI)); - tmp |= (DMA_SCSI_DISAB | DMA_ENABLE); - tmp &= ~(DMA_ST_WRITE); - sbus_writel(i, esp->dregs + DMA_COUNT); - sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR); - sbus_writel(tmp, esp->dregs + DMA_CSR); - } else { - u8 tmp; - - esp_cmd(esp, ESP_CMD_FLUSH); - tmp = *esp->esp_scmdp++; - esp->esp_scmdleft--; - sbus_writeb(tmp, esp->eregs + ESP_FDATA); - esp_cmd(esp, ESP_CMD_TI); - } - return do_intr_end; -} - -static int esp_do_cmddone(struct esp *esp) -{ - if (esp->erev == fashme) - dma_invalidate(esp); - else - esp_cmd(esp, ESP_CMD_NULL); - - if (esp->ireg & ESP_INTR_BSERV) { - esp_advance_phase(esp->current_SC, in_the_dark); - return esp_do_phase_determine(esp); - } - - ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n", - esp->esp_id)); - return do_reset_bus; -} - -static int esp_do_msgout(struct esp *esp) -{ - esp_cmd(esp, ESP_CMD_FLUSH); - switch (esp->msgout_len) { - case 1: - if (esp->erev == fashme) - hme_fifo_push(esp, &esp->cur_msgout[0], 1); - else - sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA); - - esp_cmd(esp, ESP_CMD_TI); - break; - - case 2: - esp->esp_command[0] = esp->cur_msgout[0]; - esp->esp_command[1] = esp->cur_msgout[1]; - - if (esp->erev == fashme) { - hme_fifo_push(esp, &esp->cur_msgout[0], 2); - esp_cmd(esp, ESP_CMD_TI); - } else { - dma_setup(esp, esp->esp_command_dvma, 2, 0); - esp_setcount(esp->eregs, 2, 0); - esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); - } - break; - - case 4: - esp->esp_command[0] = esp->cur_msgout[0]; - esp->esp_command[1] = esp->cur_msgout[1]; - esp->esp_command[2] = esp->cur_msgout[2]; - esp->esp_command[3] = esp->cur_msgout[3]; - esp->snip = 1; - - if (esp->erev == fashme) { - hme_fifo_push(esp, &esp->cur_msgout[0], 4); - esp_cmd(esp, ESP_CMD_TI); - } else { - dma_setup(esp, esp->esp_command_dvma, 4, 0); - esp_setcount(esp->eregs, 4, 0); - esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); - } - break; - - case 5: - esp->esp_command[0] = esp->cur_msgout[0]; - esp->esp_command[1] = esp->cur_msgout[1]; - esp->esp_command[2] = esp->cur_msgout[2]; - esp->esp_command[3] = esp->cur_msgout[3]; - esp->esp_command[4] = esp->cur_msgout[4]; - esp->snip = 1; - - if (esp->erev == fashme) { - hme_fifo_push(esp, &esp->cur_msgout[0], 5); - esp_cmd(esp, ESP_CMD_TI); - } else { - dma_setup(esp, esp->esp_command_dvma, 5, 0); - esp_setcount(esp->eregs, 5, 0); - esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); - } - break; - - default: - /* whoops */ - ESPMISC(("bogus msgout sending NOP\n")); - esp->cur_msgout[0] = NOP; - - if (esp->erev == fashme) { - hme_fifo_push(esp, &esp->cur_msgout[0], 1); - } else { - sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA); - } - - esp->msgout_len = 1; - esp_cmd(esp, ESP_CMD_TI); - break; - }; - - esp_advance_phase(esp->current_SC, in_msgoutdone); - return do_intr_end; -} - -static int esp_do_msgoutdone(struct esp *esp) -{ - if (esp->msgout_len > 1) { - /* XXX HME/FAS ATN deassert workaround required, - * XXX no DMA flushing, only possible ESP_CMD_FLUSH - * XXX to kill the fifo. - */ - if (esp->erev != fashme) { - u32 tmp; - - while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ) - udelay(1); - tmp &= ~DMA_ENABLE; - sbus_writel(tmp, esp->dregs + DMA_CSR); - dma_invalidate(esp); - } else { - esp_cmd(esp, ESP_CMD_FLUSH); - } - } - if (!(esp->ireg & ESP_INTR_DC)) { - if (esp->erev != fashme) - esp_cmd(esp, ESP_CMD_NULL); - switch (esp->sreg & ESP_STAT_PMASK) { - case ESP_MOP: - /* whoops, parity error */ - ESPLOG(("esp%d: still in msgout, parity error assumed\n", - esp->esp_id)); - if (esp->msgout_len > 1) - esp_cmd(esp, ESP_CMD_SATN); - esp_advance_phase(esp->current_SC, in_msgout); - return do_work_bus; - - case ESP_DIP: - break; - - default: - /* Happy Meal fifo is touchy... */ - if ((esp->erev != fashme) && - !fcount(esp) && - !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset)) - esp_cmd(esp, ESP_CMD_FLUSH); - break; - - }; - } else { - ESPLOG(("esp%d: disconnect, resetting bus\n", esp->esp_id)); - return do_reset_bus; - } - - /* If we sent out a synchronous negotiation message, update - * our state. - */ - if (esp->cur_msgout[2] == EXTENDED_MESSAGE && - esp->cur_msgout[4] == EXTENDED_SDTR) { - esp->snip = 1; /* anal retentiveness... */ - } - - esp->prevmsgout = esp->cur_msgout[0]; - esp->msgout_len = 0; - esp_advance_phase(esp->current_SC, in_the_dark); - return esp_do_phase_determine(esp); -} - -static int esp_bus_unexpected(struct esp *esp) -{ - ESPLOG(("esp%d: command in weird state %2x\n", - esp->esp_id, esp->current_SC->SCp.phase)); - return do_reset_bus; -} - -static espfunc_t bus_vector[] = { - esp_do_data_finale, - esp_do_data_finale, - esp_bus_unexpected, - esp_do_msgin, - esp_do_msgincont, - esp_do_msgindone, - esp_do_msgout, - esp_do_msgoutdone, - esp_do_cmdbegin, - esp_do_cmddone, - esp_do_status, - esp_do_freebus, - esp_do_phase_determine, - esp_bus_unexpected, - esp_bus_unexpected, - esp_bus_unexpected, -}; - -/* This is the second tier in our dual-level SCSI state machine. */ -static int esp_work_bus(struct esp *esp) -{ - struct scsi_cmnd *SCptr = esp->current_SC; - unsigned int phase; - - ESPBUS(("esp_work_bus: ")); - if (!SCptr) { - ESPBUS(("reconnect\n")); - return esp_do_reconnect(esp); - } - phase = SCptr->SCp.phase; - if ((phase & 0xf0) == in_phases_mask) - return bus_vector[(phase & 0x0f)](esp); - else if ((phase & 0xf0) == in_slct_mask) - return esp_select_complete(esp); - else - return esp_bus_unexpected(esp); -} - -static espfunc_t isvc_vector[] = { - NULL, - esp_do_phase_determine, - esp_do_resetbus, - esp_finish_reset, - esp_work_bus -}; - -/* Main interrupt handler for an esp adapter. */ -static void esp_handle(struct esp *esp) -{ - struct scsi_cmnd *SCptr; - int what_next = do_intr_end; - - SCptr = esp->current_SC; - - /* Check for errors. */ - esp->sreg = sbus_readb(esp->eregs + ESP_STATUS); - esp->sreg &= (~ESP_STAT_INTR); - if (esp->erev == fashme) { - esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2); - esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS); - } - - if (esp->sreg & (ESP_STAT_SPAM)) { - /* Gross error, could be due to one of: - * - * - top of fifo overwritten, could be because - * we tried to do a synchronous transfer with - * an offset greater than ESP fifo size - * - * - top of command register overwritten - * - * - DMA setup to go in one direction, SCSI - * bus points in the other, whoops - * - * - weird phase change during asynchronous - * data phase while we are initiator - */ - ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg)); - - /* If a command is live on the bus we cannot safely - * reset the bus, so we'll just let the pieces fall - * where they may. Here we are hoping that the - * target will be able to cleanly go away soon - * so we can safely reset things. - */ - if (!SCptr) { - ESPLOG(("esp%d: No current cmd during gross error, " - "resetting bus\n", esp->esp_id)); - what_next = do_reset_bus; - goto state_machine; - } - } - - if (sbus_readl(esp->dregs + DMA_CSR) & DMA_HNDL_ERROR) { - /* A DMA gate array error. Here we must - * be seeing one of two things. Either the - * virtual to physical address translation - * on the SBUS could not occur, else the - * translation it did get pointed to a bogus - * page. Ho hum... - */ - ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id, - sbus_readl(esp->dregs + DMA_CSR))); - - /* DMA gate array itself must be reset to clear the - * error condition. - */ - esp_reset_dma(esp); - - what_next = do_reset_bus; - goto state_machine; - } - - esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); /* Unlatch intr reg */ - - if (esp->erev == fashme) { - /* This chip is really losing. */ - ESPHME(("HME[")); - - ESPHME(("sreg2=%02x,", esp->sreg2)); - /* Must latch fifo before reading the interrupt - * register else garbage ends up in the FIFO - * which confuses the driver utterly. - */ - if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || - (esp->sreg2 & ESP_STAT2_F1BYTE)) { - ESPHME(("fifo_workaround]")); - hme_fifo_read(esp); - } else { - ESPHME(("no_fifo_workaround]")); - } - } - - /* No current cmd is only valid at this point when there are - * commands off the bus or we are trying a reset. - */ - if (!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) { - /* Panic is safe, since current_SC is null. */ - ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id)); - panic("esp_handle: current_SC == penguin within interrupt!"); - } - - if (esp->ireg & (ESP_INTR_IC)) { - /* Illegal command fed to ESP. Outside of obvious - * software bugs that could cause this, there is - * a condition with esp100 where we can confuse the - * ESP into an erroneous illegal command interrupt - * because it does not scrape the FIFO properly - * for reselection. See esp100_reconnect_hwbug() - * to see how we try very hard to avoid this. - */ - ESPLOG(("esp%d: invalid command\n", esp->esp_id)); - - esp_dump_state(esp); - - if (SCptr != NULL) { - /* Devices with very buggy firmware can drop BSY - * during a scatter list interrupt when using sync - * mode transfers. We continue the transfer as - * expected, the target drops the bus, the ESP - * gets confused, and we get a illegal command - * interrupt because the bus is in the disconnected - * state now and ESP_CMD_TI is only allowed when - * a nexus is alive on the bus. - */ - ESPLOG(("esp%d: Forcing async and disabling disconnect for " - "target %d\n", esp->esp_id, SCptr->device->id)); - SCptr->device->borken = 1; /* foo on you */ - } - - what_next = do_reset_bus; - } else if (!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) { - if (SCptr) { - unsigned int phase = SCptr->SCp.phase; - - if (phase & in_phases_mask) { - what_next = esp_work_bus(esp); - } else if (phase & in_slct_mask) { - what_next = esp_select_complete(esp); - } else { - ESPLOG(("esp%d: interrupt for no good reason...\n", - esp->esp_id)); - what_next = do_intr_end; - } - } else { - ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n", - esp->esp_id)); - what_next = do_reset_bus; - } - } else if (esp->ireg & ESP_INTR_SR) { - ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id)); - what_next = do_reset_complete; - } else if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) { - ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n", - esp->esp_id)); - what_next = do_reset_bus; - } else if (esp->ireg & ESP_INTR_RSEL) { - if (SCptr == NULL) { - /* This is ok. */ - what_next = esp_do_reconnect(esp); - } else if (SCptr->SCp.phase & in_slct_mask) { - /* Only selection code knows how to clean - * up properly. - */ - ESPDISC(("Reselected during selection attempt\n")); - what_next = esp_select_complete(esp); - } else { - ESPLOG(("esp%d: Reselected while bus is busy\n", - esp->esp_id)); - what_next = do_reset_bus; - } - } - - /* This is tier-one in our dual level SCSI state machine. */ -state_machine: - while (what_next != do_intr_end) { - if (what_next >= do_phase_determine && - what_next < do_intr_end) { - what_next = isvc_vector[what_next](esp); - } else { - /* state is completely lost ;-( */ - ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n", - esp->esp_id)); - what_next = do_reset_bus; - } - } -} - -/* Service only the ESP described by dev_id. */ -static irqreturn_t esp_intr(int irq, void *dev_id) -{ - struct esp *esp = dev_id; - unsigned long flags; - - spin_lock_irqsave(esp->ehost->host_lock, flags); - if (ESP_IRQ_P(esp->dregs)) { - ESP_INTSOFF(esp->dregs); - - ESPIRQ(("I[%d:%d](", smp_processor_id(), esp->esp_id)); - esp_handle(esp); - ESPIRQ((")")); - - ESP_INTSON(esp->dregs); - } - spin_unlock_irqrestore(esp->ehost->host_lock, flags); - - return IRQ_HANDLED; -} - -static int esp_slave_alloc(struct scsi_device *SDptr) -{ - struct esp_device *esp_dev = - kmalloc(sizeof(struct esp_device), GFP_ATOMIC); - - if (!esp_dev) - return -ENOMEM; - memset(esp_dev, 0, sizeof(struct esp_device)); - SDptr->hostdata = esp_dev; - return 0; -} - -static void esp_slave_destroy(struct scsi_device *SDptr) -{ - struct esp *esp = (struct esp *) SDptr->host->hostdata; - - esp->targets_present &= ~(1 << SDptr->id); - kfree(SDptr->hostdata); - SDptr->hostdata = NULL; -} - -static struct scsi_host_template esp_template = { - .module = THIS_MODULE, - .name = "esp", - .info = esp_info, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, - .proc_name = "esp", - .proc_info = esp_proc_info, -}; - -#ifndef CONFIG_SUN4 -static struct of_device_id esp_match[] = { - { - .name = "SUNW,esp", - .data = &esp_template, - }, - { - .name = "SUNW,fas", - .data = &esp_template, - }, - { - .name = "esp", - .data = &esp_template, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, esp_match); - -static struct of_platform_driver esp_sbus_driver = { - .name = "esp", - .match_table = esp_match, - .probe = esp_sbus_probe, - .remove = __devexit_p(esp_sbus_remove), -}; -#endif - -static int __init esp_init(void) -{ -#ifdef CONFIG_SUN4 - return esp_sun4_probe(&esp_template); -#else - return of_register_driver(&esp_sbus_driver, &sbus_bus_type); -#endif -} - -static void __exit esp_exit(void) -{ -#ifdef CONFIG_SUN4 - esp_sun4_remove(); -#else - of_unregister_driver(&esp_sbus_driver); -#endif -} - -MODULE_DESCRIPTION("ESP Sun SCSI driver"); -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -module_init(esp_init); -module_exit(esp_exit); diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h deleted file mode 100644 index a98cda9121f..00000000000 --- a/drivers/scsi/esp.h +++ /dev/null @@ -1,406 +0,0 @@ -/* $Id: esp.h,v 1.29 2001/12/11 04:55:47 davem Exp $ - * esp.h: Defines and structures for the Sparc ESP (Enhanced SCSI - * Processor) driver under Linux. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ - -#ifndef _SPARC_ESP_H -#define _SPARC_ESP_H - -/* For dvma controller register definitions. */ -#include - -/* The ESP SCSI controllers have their register sets in three - * "classes": - * - * 1) Registers which are both read and write. - * 2) Registers which are read only. - * 3) Registers which are write only. - * - * Yet, they all live within the same IO space. - */ - -/* All the ESP registers are one byte each and are accessed longwords - * apart with a big-endian ordering to the bytes. - */ - /* Access Description Offset */ -#define ESP_TCLOW 0x00UL /* rw Low bits of the transfer count 0x00 */ -#define ESP_TCMED 0x04UL /* rw Mid bits of the transfer count 0x04 */ -#define ESP_FDATA 0x08UL /* rw FIFO data bits 0x08 */ -#define ESP_CMD 0x0cUL /* rw SCSI command bits 0x0c */ -#define ESP_STATUS 0x10UL /* ro ESP status register 0x10 */ -#define ESP_BUSID ESP_STATUS /* wo Bus ID for select/reselect 0x10 */ -#define ESP_INTRPT 0x14UL /* ro Kind of interrupt 0x14 */ -#define ESP_TIMEO ESP_INTRPT /* wo Timeout value for select/resel 0x14 */ -#define ESP_SSTEP 0x18UL /* ro Sequence step register 0x18 */ -#define ESP_STP ESP_SSTEP /* wo Transfer period per sync 0x18 */ -#define ESP_FFLAGS 0x1cUL /* ro Bits of current FIFO info 0x1c */ -#define ESP_SOFF ESP_FFLAGS /* wo Sync offset 0x1c */ -#define ESP_CFG1 0x20UL /* rw First configuration register 0x20 */ -#define ESP_CFACT 0x24UL /* wo Clock conversion factor 0x24 */ -#define ESP_STATUS2 ESP_CFACT /* ro HME status2 register 0x24 */ -#define ESP_CTEST 0x28UL /* wo Chip test register 0x28 */ -#define ESP_CFG2 0x2cUL /* rw Second configuration register 0x2c */ -#define ESP_CFG3 0x30UL /* rw Third configuration register 0x30 */ -#define ESP_TCHI 0x38UL /* rw High bits of transfer count 0x38 */ -#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */ -#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */ -#define ESP_FGRND 0x3cUL /* rw Data base for fifo 0x3c */ -#define FAS_RHI ESP_FGRND /* rw HME extended counter 0x3c */ -#define ESP_REG_SIZE 0x40UL - -/* Various revisions of the ESP board. */ -enum esp_rev { - esp100 = 0x00, /* NCR53C90 - very broken */ - esp100a = 0x01, /* NCR53C90A */ - esp236 = 0x02, - fas236 = 0x03, - fas100a = 0x04, - fast = 0x05, - fashme = 0x06, - espunknown = 0x07 -}; - -/* We allocate one of these for each scsi device and attach it to - * SDptr->hostdata for use in the driver - */ -struct esp_device { - unsigned char sync_min_period; - unsigned char sync_max_offset; - unsigned sync:1; - unsigned wide:1; - unsigned disconnect:1; -}; - -struct scsi_cmnd; - -/* We get one of these for each ESP probed. */ -struct esp { - void __iomem *eregs; /* ESP controller registers */ - void __iomem *dregs; /* DMA controller registers */ - struct sbus_dma *dma; /* DMA controller sw state */ - struct Scsi_Host *ehost; /* Backpointer to SCSI Host */ - struct sbus_dev *sdev; /* Pointer to SBus entry */ - - /* ESP Configuration Registers */ - u8 config1; /* Copy of the 1st config register */ - u8 config2; /* Copy of the 2nd config register */ - u8 config3[16]; /* Copy of the 3rd config register */ - - /* The current command we are sending to the ESP chip. This esp_command - * ptr needs to be mapped in DVMA area so we can send commands and read - * from the ESP fifo without burning precious CPU cycles. Programmed I/O - * sucks when we have the DVMA to do it for us. The ESP is stupid and will - * only send out 6, 10, and 12 byte SCSI commands, others we need to send - * one byte at a time. esp_slowcmd being set says that we are doing one - * of the command types ESP doesn't understand, esp_scmdp keeps track of - * which byte we are sending, esp_scmdleft says how many bytes to go. - */ - volatile u8 *esp_command; /* Location of command (CPU view) */ - __u32 esp_command_dvma;/* Location of command (DVMA view) */ - unsigned char esp_clen; /* Length of this command */ - unsigned char esp_slowcmd; - unsigned char *esp_scmdp; - unsigned char esp_scmdleft; - - /* The following are used to determine the cause of an IRQ. Upon every - * IRQ entry we synchronize these with the hardware registers. - */ - u8 ireg; /* Copy of ESP interrupt register */ - u8 sreg; /* Copy of ESP status register */ - u8 seqreg; /* Copy of ESP sequence step register */ - u8 sreg2; /* Copy of HME status2 register */ - - /* To save register writes to the ESP, which can be expensive, we - * keep track of the previous value that various registers had for - * the last target we connected to. If they are the same for the - * current target, we skip the register writes as they are not needed. - */ - u8 prev_soff, prev_stp; - u8 prev_cfg3, __cache_pad; - - /* We also keep a cache of the previous FAS/HME DMA CSR register value. */ - u32 prev_hme_dmacsr; - - /* The HME is the biggest piece of shit I have ever seen. */ - u8 hme_fifo_workaround_buffer[16 * 2]; - u8 hme_fifo_workaround_count; - - /* For each target we keep track of save/restore data - * pointer information. This needs to be updated majorly - * when we add support for tagged queueing. -DaveM - */ - struct esp_pointers { - char *saved_ptr; - struct scatterlist *saved_buffer; - int saved_this_residual; - int saved_buffers_residual; - } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/; - - /* Clock periods, frequencies, synchronization, etc. */ - unsigned int cfreq; /* Clock frequency in HZ */ - unsigned int cfact; /* Clock conversion factor */ - unsigned int raw_cfact; /* Raw copy from probing */ - unsigned int ccycle; /* One ESP clock cycle */ - unsigned int ctick; /* One ESP clock time */ - unsigned int radelay; /* FAST chip req/ack delay */ - unsigned int neg_defp; /* Default negotiation period */ - unsigned int sync_defp; /* Default sync transfer period */ - unsigned int max_period; /* longest our period can be */ - unsigned int min_period; /* shortest period we can withstand */ - - struct esp *next; /* Next ESP we probed or NULL */ - char prom_name[64]; /* Name of ESP device from prom */ - int prom_node; /* Prom node where ESP found */ - int esp_id; /* Unique per-ESP ID number */ - - /* For slow to medium speed input clock rates we shoot for 5mb/s, - * but for high input clock rates we try to do 10mb/s although I - * don't think a transfer can even run that fast with an ESP even - * with DMA2 scatter gather pipelining. - */ -#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */ -#define SYNC_DEFP_FAST 0x19 /* 10mb/s */ - - unsigned int snip; /* Sync. negotiation in progress */ - unsigned int wnip; /* WIDE negotiation in progress */ - unsigned int targets_present;/* targets spoken to before */ - - int current_transfer_size; /* Set at beginning of data dma */ - - u8 espcmdlog[32]; /* Log of current esp cmds sent. */ - u8 espcmdent; /* Current entry in esp cmd log. */ - - /* Misc. info about this ESP */ - enum esp_rev erev; /* ESP revision */ - int irq; /* SBus IRQ for this ESP */ - int scsi_id; /* Who am I as initiator? */ - int scsi_id_mask; /* Bitmask of 'me'. */ - int diff; /* Differential SCSI bus? */ - int bursts; /* Burst sizes our DVMA supports */ - - /* Our command queues, only one cmd lives in the current_SC queue. */ - struct scsi_cmnd *issue_SC; /* Commands to be issued */ - struct scsi_cmnd *current_SC; /* Who is currently working the bus */ - struct scsi_cmnd *disconnected_SC;/* Commands disconnected from the bus */ - - /* Message goo */ - u8 cur_msgout[16]; - u8 cur_msgin[16]; - u8 prevmsgout, prevmsgin; - u8 msgout_len, msgin_len; - u8 msgout_ctr, msgin_ctr; - - /* States that we cannot keep in the per cmd structure because they - * cannot be assosciated with any specific command. - */ - u8 resetting_bus; - wait_queue_head_t reset_queue; -}; - -/* Bitfield meanings for the above registers. */ - -/* ESP config reg 1, read-write, found on all ESP chips */ -#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */ -#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */ -#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */ -#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */ -#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */ -#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */ - -/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */ -#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */ -#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */ -#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */ -#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tmode only) */ -#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */ -#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */ -#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */ -#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */ -#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216) */ -#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */ -#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */ -#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */ -#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */ - -/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */ -#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */ -#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */ -#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */ -#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */ -#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */ -#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */ -#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */ -#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */ -#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */ -#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */ -#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */ -#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */ -#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */ -#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */ -#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */ -#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */ - -/* ESP command register read-write */ -/* Group 1 commands: These may be sent at any point in time to the ESP - * chip. None of them can generate interrupts 'cept - * the "SCSI bus reset" command if you have not disabled - * SCSI reset interrupts in the config1 ESP register. - */ -#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */ -#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */ -#define ESP_CMD_RC 0x02 /* Chip reset */ -#define ESP_CMD_RS 0x03 /* SCSI bus reset */ - -/* Group 2 commands: ESP must be an initiator and connected to a target - * for these commands to work. - */ -#define ESP_CMD_TI 0x10 /* Transfer Information */ -#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */ -#define ESP_CMD_MOK 0x12 /* Message okie-dokie */ -#define ESP_CMD_TPAD 0x18 /* Transfer Pad */ -#define ESP_CMD_SATN 0x1a /* Set ATN */ -#define ESP_CMD_RATN 0x1b /* De-assert ATN */ - -/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected - * to a target as the initiator for these commands to work. - */ -#define ESP_CMD_SMSG 0x20 /* Send message */ -#define ESP_CMD_SSTAT 0x21 /* Send status */ -#define ESP_CMD_SDATA 0x22 /* Send data */ -#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */ -#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */ -#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */ -#define ESP_CMD_DCNCT 0x27 /* Disconnect */ -#define ESP_CMD_RMSG 0x28 /* Receive Message */ -#define ESP_CMD_RCMD 0x29 /* Receive Command */ -#define ESP_CMD_RDATA 0x2a /* Receive Data */ -#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */ - -/* Group 4 commands: The ESP must be in the disconnected state and must - * not be connected to any targets as initiator for - * these commands to work. - */ -#define ESP_CMD_RSEL 0x40 /* Reselect */ -#define ESP_CMD_SEL 0x41 /* Select w/o ATN */ -#define ESP_CMD_SELA 0x42 /* Select w/ATN */ -#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */ -#define ESP_CMD_ESEL 0x44 /* Enable selection */ -#define ESP_CMD_DSEL 0x45 /* Disable selections */ -#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */ -#define ESP_CMD_RSEL3 0x47 /* Reselect3 */ - -/* This bit enables the ESP's DMA on the SBus */ -#define ESP_CMD_DMA 0x80 /* Do DMA? */ - - -/* ESP status register read-only */ -#define ESP_STAT_PIO 0x01 /* IO phase bit */ -#define ESP_STAT_PCD 0x02 /* CD phase bit */ -#define ESP_STAT_PMSG 0x04 /* MSG phase bit */ -#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */ -#define ESP_STAT_TDONE 0x08 /* Transfer Completed */ -#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */ -#define ESP_STAT_PERR 0x20 /* Parity error */ -#define ESP_STAT_SPAM 0x40 /* Real bad error */ -/* This indicates the 'interrupt pending' condition on esp236, it is a reserved - * bit on other revs of the ESP. - */ -#define ESP_STAT_INTR 0x80 /* Interrupt */ - -/* HME only: status 2 register */ -#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */ -#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */ -#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */ -#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */ -#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */ -#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */ -#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */ -#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */ - -/* The status register can be masked with ESP_STAT_PMASK and compared - * with the following values to determine the current phase the ESP - * (at least thinks it) is in. For our purposes we also add our own - * software 'done' bit for our phase management engine. - */ -#define ESP_DOP (0) /* Data Out */ -#define ESP_DIP (ESP_STAT_PIO) /* Data In */ -#define ESP_CMDP (ESP_STAT_PCD) /* Command */ -#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */ -#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */ -#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */ - -/* ESP interrupt register read-only */ -#define ESP_INTR_S 0x01 /* Select w/o ATN */ -#define ESP_INTR_SATN 0x02 /* Select w/ATN */ -#define ESP_INTR_RSEL 0x04 /* Reselected */ -#define ESP_INTR_FDONE 0x08 /* Function done */ -#define ESP_INTR_BSERV 0x10 /* Bus service */ -#define ESP_INTR_DC 0x20 /* Disconnect */ -#define ESP_INTR_IC 0x40 /* Illegal command given */ -#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */ - -/* Interrupt status macros */ -#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR)) -#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC)) -#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN)) -#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S)) -#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \ - (ESP_SELECT_WITHOUT_ATN_IRQ(esp))) -#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL)) - -/* ESP sequence step register read-only */ -#define ESP_STEP_VBITS 0x07 /* Valid bits */ -#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */ -#define ESP_STEP_SID 0x01 /* One msg byte sent */ -#define ESP_STEP_NCMD 0x02 /* Was not in command phase */ -#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd - * bytes to be lost - */ -#define ESP_STEP_FINI4 0x04 /* Command was sent ok */ - -/* Ho hum, some ESP's set the step register to this as well... */ -#define ESP_STEP_FINI5 0x05 -#define ESP_STEP_FINI6 0x06 -#define ESP_STEP_FINI7 0x07 - -/* ESP chip-test register read-write */ -#define ESP_TEST_TARG 0x01 /* Target test mode */ -#define ESP_TEST_INI 0x02 /* Initiator test mode */ -#define ESP_TEST_TS 0x04 /* Tristate test mode */ - -/* ESP unique ID register read-only, found on fas236+fas100a only */ -#define ESP_UID_F100A 0x00 /* ESP FAS100A */ -#define ESP_UID_F236 0x02 /* ESP FAS236 */ -#define ESP_UID_REV 0x07 /* ESP revision */ -#define ESP_UID_FAM 0xf8 /* ESP family */ - -/* ESP fifo flags register read-only */ -/* Note that the following implies a 16 byte FIFO on the ESP. */ -#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */ -#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */ -#define ESP_FF_SSTEP 0xe0 /* Sequence step */ - -/* ESP clock conversion factor register write-only */ -#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */ -#define ESP_CCF_NEVER 0x01 /* Set it to this and die */ -#define ESP_CCF_F2 0x02 /* 10MHz */ -#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */ -#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */ -#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */ -#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */ -#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */ - -/* HME only... */ -#define ESP_BUSID_RESELID 0x10 -#define ESP_BUSID_CTR32BIT 0x40 - -#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */ -#define ESP_TIMEO_CONST 8192 -#define ESP_NEG_DEFP(mhz, cfact) \ - ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact))) -#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000)) -#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000)) - -#endif /* !(_SPARC_ESP_H) */ diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c new file mode 100644 index 00000000000..3cd5bf723da --- /dev/null +++ b/drivers/scsi/esp_scsi.c @@ -0,0 +1,2710 @@ +/* esp_scsi.c: ESP SCSI driver. + * + * Copyright (C) 2007 David S. Miller (davem@davemloft.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "esp_scsi.h" + +#define DRV_MODULE_NAME "esp" +#define PFX DRV_MODULE_NAME ": " +#define DRV_VERSION "2.000" +#define DRV_MODULE_RELDATE "April 19, 2007" + +/* SCSI bus reset settle time in seconds. */ +static int esp_bus_reset_settle = 3; + +static u32 esp_debug; +#define ESP_DEBUG_INTR 0x00000001 +#define ESP_DEBUG_SCSICMD 0x00000002 +#define ESP_DEBUG_RESET 0x00000004 +#define ESP_DEBUG_MSGIN 0x00000008 +#define ESP_DEBUG_MSGOUT 0x00000010 +#define ESP_DEBUG_CMDDONE 0x00000020 +#define ESP_DEBUG_DISCONNECT 0x00000040 +#define ESP_DEBUG_DATASTART 0x00000080 +#define ESP_DEBUG_DATADONE 0x00000100 +#define ESP_DEBUG_RECONNECT 0x00000200 +#define ESP_DEBUG_AUTOSENSE 0x00000400 + +#define esp_log_intr(f, a...) \ +do { if (esp_debug & ESP_DEBUG_INTR) \ + printk(f, ## a); \ +} while (0) + +#define esp_log_reset(f, a...) \ +do { if (esp_debug & ESP_DEBUG_RESET) \ + printk(f, ## a); \ +} while (0) + +#define esp_log_msgin(f, a...) \ +do { if (esp_debug & ESP_DEBUG_MSGIN) \ + printk(f, ## a); \ +} while (0) + +#define esp_log_msgout(f, a...) \ +do { if (esp_debug & ESP_DEBUG_MSGOUT) \ + printk(f, ## a); \ +} while (0) + +#define esp_log_cmddone(f, a...) \ +do { if (esp_debug & ESP_DEBUG_CMDDONE) \ + printk(f, ## a); \ +} while (0) + +#define esp_log_disconnect(f, a...) \ +do { if (esp_debug & ESP_DEBUG_DISCONNECT) \ + printk(f, ## a); \ +} while (0) + +#define esp_log_datastart(f, a...) \ +do { if (esp_debug & ESP_DEBUG_DATASTART) \ + printk(f, ## a); \ +} while (0) + +#define esp_log_datadone(f, a...) \ +do { if (esp_debug & ESP_DEBUG_DATADONE) \ + printk(f, ## a); \ +} while (0) + +#define esp_log_reconnect(f, a...) \ +do { if (esp_debug & ESP_DEBUG_RECONNECT) \ + printk(f, ## a); \ +} while (0) + +#define esp_log_autosense(f, a...) \ +do { if (esp_debug & ESP_DEBUG_AUTOSENSE) \ + printk(f, ## a); \ +} while (0) + +#define esp_read8(REG) esp->ops->esp_read8(esp, REG) +#define esp_write8(VAL,REG) esp->ops->esp_write8(esp, VAL, REG) + +static void esp_log_fill_regs(struct esp *esp, + struct esp_event_ent *p) +{ + p->sreg = esp->sreg; + p->seqreg = esp->seqreg; + p->sreg2 = esp->sreg2; + p->ireg = esp->ireg; + p->select_state = esp->select_state; + p->event = esp->event; +} + +void scsi_esp_cmd(struct esp *esp, u8 val) +{ + struct esp_event_ent *p; + int idx = esp->esp_event_cur; + + p = &esp->esp_event_log[idx]; + p->type = ESP_EVENT_TYPE_CMD; + p->val = val; + esp_log_fill_regs(esp, p); + + esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1); + + esp_write8(val, ESP_CMD); +} +EXPORT_SYMBOL(scsi_esp_cmd); + +static void esp_event(struct esp *esp, u8 val) +{ + struct esp_event_ent *p; + int idx = esp->esp_event_cur; + + p = &esp->esp_event_log[idx]; + p->type = ESP_EVENT_TYPE_EVENT; + p->val = val; + esp_log_fill_regs(esp, p); + + esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1); + + esp->event = val; +} + +static void esp_dump_cmd_log(struct esp *esp) +{ + int idx = esp->esp_event_cur; + int stop = idx; + + printk(KERN_INFO PFX "esp%d: Dumping command log\n", + esp->host->unique_id); + do { + struct esp_event_ent *p = &esp->esp_event_log[idx]; + + printk(KERN_INFO PFX "esp%d: ent[%d] %s ", + esp->host->unique_id, idx, + p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT"); + + printk("val[%02x] sreg[%02x] seqreg[%02x] " + "sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n", + p->val, p->sreg, p->seqreg, + p->sreg2, p->ireg, p->select_state, p->event); + + idx = (idx + 1) & (ESP_EVENT_LOG_SZ - 1); + } while (idx != stop); +} + +static void esp_flush_fifo(struct esp *esp) +{ + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + if (esp->rev == ESP236) { + int lim = 1000; + + while (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) { + if (--lim == 0) { + printk(KERN_ALERT PFX "esp%d: ESP_FF_BYTES " + "will not clear!\n", + esp->host->unique_id); + break; + } + udelay(1); + } + } +} + +static void hme_read_fifo(struct esp *esp) +{ + int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; + int idx = 0; + + while (fcnt--) { + esp->fifo[idx++] = esp_read8(ESP_FDATA); + esp->fifo[idx++] = esp_read8(ESP_FDATA); + } + if (esp->sreg2 & ESP_STAT2_F1BYTE) { + esp_write8(0, ESP_FDATA); + esp->fifo[idx++] = esp_read8(ESP_FDATA); + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + } + esp->fifo_cnt = idx; +} + +static void esp_set_all_config3(struct esp *esp, u8 val) +{ + int i; + + for (i = 0; i < ESP_MAX_TARGET; i++) + esp->target[i].esp_config3 = val; +} + +/* Reset the ESP chip, _not_ the SCSI bus. */ +static void esp_reset_esp(struct esp *esp) +{ + u8 family_code, version; + + /* Now reset the ESP chip */ + scsi_esp_cmd(esp, ESP_CMD_RC); + scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); + scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); + + /* Reload the configuration registers */ + esp_write8(esp->cfact, ESP_CFACT); + + esp->prev_stp = 0; + esp_write8(esp->prev_stp, ESP_STP); + + esp->prev_soff = 0; + esp_write8(esp->prev_soff, ESP_SOFF); + + esp_write8(esp->neg_defp, ESP_TIMEO); + + /* This is the only point at which it is reliable to read + * the ID-code for a fast ESP chip variants. + */ + esp->max_period = ((35 * esp->ccycle) / 1000); + if (esp->rev == FAST) { + version = esp_read8(ESP_UID); + family_code = (version & 0xf8) >> 3; + if (family_code == 0x02) + esp->rev = FAS236; + else if (family_code == 0x0a) + esp->rev = FASHME; /* Version is usually '5'. */ + else + esp->rev = FAS100A; + esp->min_period = ((4 * esp->ccycle) / 1000); + } else { + esp->min_period = ((5 * esp->ccycle) / 1000); + } + esp->max_period = (esp->max_period + 3)>>2; + esp->min_period = (esp->min_period + 3)>>2; + + esp_write8(esp->config1, ESP_CFG1); + switch (esp->rev) { + case ESP100: + /* nothing to do */ + break; + + case ESP100A: + esp_write8(esp->config2, ESP_CFG2); + break; + + case ESP236: + /* Slow 236 */ + esp_write8(esp->config2, ESP_CFG2); + esp->prev_cfg3 = esp->target[0].esp_config3; + esp_write8(esp->prev_cfg3, ESP_CFG3); + break; + + case FASHME: + esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB); + /* fallthrough... */ + + case FAS236: + /* Fast 236 or HME */ + esp_write8(esp->config2, ESP_CFG2); + if (esp->rev == FASHME) { + u8 cfg3 = esp->target[0].esp_config3; + + cfg3 |= ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH; + if (esp->scsi_id >= 8) + cfg3 |= ESP_CONFIG3_IDBIT3; + esp_set_all_config3(esp, cfg3); + } else { + u32 cfg3 = esp->target[0].esp_config3; + + cfg3 |= ESP_CONFIG3_FCLK; + esp_set_all_config3(esp, cfg3); + } + esp->prev_cfg3 = esp->target[0].esp_config3; + esp_write8(esp->prev_cfg3, ESP_CFG3); + if (esp->rev == FASHME) { + esp->radelay = 80; + } else { + if (esp->flags & ESP_FLAG_DIFFERENTIAL) + esp->radelay = 0; + else + esp->radelay = 96; + } + break; + + case FAS100A: + /* Fast 100a */ + esp_write8(esp->config2, ESP_CFG2); + esp_set_all_config3(esp, + (esp->target[0].esp_config3 | + ESP_CONFIG3_FCLOCK)); + esp->prev_cfg3 = esp->target[0].esp_config3; + esp_write8(esp->prev_cfg3, ESP_CFG3); + esp->radelay = 32; + break; + + default: + break; + } + + /* Eat any bitrot in the chip */ + esp_read8(ESP_INTRPT); + udelay(100); +} + +static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) +{ + struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); + struct scatterlist *sg = cmd->request_buffer; + int dir = cmd->sc_data_direction; + int total, i; + + if (dir == DMA_NONE) + return; + + BUG_ON(cmd->use_sg == 0); + + spriv->u.num_sg = esp->ops->map_sg(esp, sg, + cmd->use_sg, dir); + spriv->cur_residue = sg_dma_len(sg); + spriv->cur_sg = sg; + + total = 0; + for (i = 0; i < spriv->u.num_sg; i++) + total += sg_dma_len(&sg[i]); + spriv->tot_residue = total; +} + +static dma_addr_t esp_cur_dma_addr(struct esp_cmd_entry *ent, + struct scsi_cmnd *cmd) +{ + struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); + + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { + return ent->sense_dma + + (ent->sense_ptr - cmd->sense_buffer); + } + + return sg_dma_address(p->cur_sg) + + (sg_dma_len(p->cur_sg) - + p->cur_residue); +} + +static unsigned int esp_cur_dma_len(struct esp_cmd_entry *ent, + struct scsi_cmnd *cmd) +{ + struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); + + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { + return SCSI_SENSE_BUFFERSIZE - + (ent->sense_ptr - cmd->sense_buffer); + } + return p->cur_residue; +} + +static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent, + struct scsi_cmnd *cmd, unsigned int len) +{ + struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); + + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { + ent->sense_ptr += len; + return; + } + + p->cur_residue -= len; + p->tot_residue -= len; + if (p->cur_residue < 0 || p->tot_residue < 0) { + printk(KERN_ERR PFX "esp%d: Data transfer overflow.\n", + esp->host->unique_id); + printk(KERN_ERR PFX "esp%d: cur_residue[%d] tot_residue[%d] " + "len[%u]\n", + esp->host->unique_id, + p->cur_residue, p->tot_residue, len); + p->cur_residue = 0; + p->tot_residue = 0; + } + if (!p->cur_residue && p->tot_residue) { + p->cur_sg++; + p->cur_residue = sg_dma_len(p->cur_sg); + } +} + +static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd) +{ + struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); + int dir = cmd->sc_data_direction; + + if (dir == DMA_NONE) + return; + + esp->ops->unmap_sg(esp, cmd->request_buffer, + spriv->u.num_sg, dir); +} + +static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent) +{ + struct scsi_cmnd *cmd = ent->cmd; + struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); + + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { + ent->saved_sense_ptr = ent->sense_ptr; + return; + } + ent->saved_cur_residue = spriv->cur_residue; + ent->saved_cur_sg = spriv->cur_sg; + ent->saved_tot_residue = spriv->tot_residue; +} + +static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent) +{ + struct scsi_cmnd *cmd = ent->cmd; + struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); + + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { + ent->sense_ptr = ent->saved_sense_ptr; + return; + } + spriv->cur_residue = ent->saved_cur_residue; + spriv->cur_sg = ent->saved_cur_sg; + spriv->tot_residue = ent->saved_tot_residue; +} + +static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd) +{ + if (cmd->cmd_len == 6 || + cmd->cmd_len == 10 || + cmd->cmd_len == 12) { + esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; + } else { + esp->flags |= ESP_FLAG_DOING_SLOWCMD; + } +} + +static void esp_write_tgt_config3(struct esp *esp, int tgt) +{ + if (esp->rev > ESP100A) { + u8 val = esp->target[tgt].esp_config3; + + if (val != esp->prev_cfg3) { + esp->prev_cfg3 = val; + esp_write8(val, ESP_CFG3); + } + } +} + +static void esp_write_tgt_sync(struct esp *esp, int tgt) +{ + u8 off = esp->target[tgt].esp_offset; + u8 per = esp->target[tgt].esp_period; + + if (off != esp->prev_soff) { + esp->prev_soff = off; + esp_write8(off, ESP_SOFF); + } + if (per != esp->prev_stp) { + esp->prev_stp = per; + esp_write8(per, ESP_STP); + } +} + +static u32 esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) +{ + if (esp->rev == FASHME) { + /* Arbitrary segment boundaries, 24-bit counts. */ + if (dma_len > (1U << 24)) + dma_len = (1U << 24); + } else { + u32 base, end; + + /* ESP chip limits other variants by 16-bits of transfer + * count. Actually on FAS100A and FAS236 we could get + * 24-bits of transfer count by enabling ESP_CONFIG2_FENAB + * in the ESP_CFG2 register but that causes other unwanted + * changes so we don't use it currently. + */ + if (dma_len > (1U << 16)) + dma_len = (1U << 16); + + /* All of the DMA variants hooked up to these chips + * cannot handle crossing a 24-bit address boundary. + */ + base = dma_addr & ((1U << 24) - 1U); + end = base + dma_len; + if (end > (1U << 24)) + end = (1U <<24); + dma_len = end - base; + } + return dma_len; +} + +static int esp_need_to_nego_wide(struct esp_target_data *tp) +{ + struct scsi_target *target = tp->starget; + + return spi_width(target) != tp->nego_goal_width; +} + +static int esp_need_to_nego_sync(struct esp_target_data *tp) +{ + struct scsi_target *target = tp->starget; + + /* When offset is zero, period is "don't care". */ + if (!spi_offset(target) && !tp->nego_goal_offset) + return 0; + + if (spi_offset(target) == tp->nego_goal_offset && + spi_period(target) == tp->nego_goal_period) + return 0; + + return 1; +} + +static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, + struct esp_lun_data *lp) +{ + if (!ent->tag[0]) { + /* Non-tagged, slot already taken? */ + if (lp->non_tagged_cmd) + return -EBUSY; + + if (lp->hold) { + /* We are being held by active tagged + * commands. + */ + if (lp->num_tagged) + return -EBUSY; + + /* Tagged commands completed, we can unplug + * the queue and run this untagged command. + */ + lp->hold = 0; + } else if (lp->num_tagged) { + /* Plug the queue until num_tagged decreases + * to zero in esp_free_lun_tag. + */ + lp->hold = 1; + return -EBUSY; + } + + lp->non_tagged_cmd = ent; + return 0; + } else { + /* Tagged command, see if blocked by a + * non-tagged one. + */ + if (lp->non_tagged_cmd || lp->hold) + return -EBUSY; + } + + BUG_ON(lp->tagged_cmds[ent->tag[1]]); + + lp->tagged_cmds[ent->tag[1]] = ent; + lp->num_tagged++; + + return 0; +} + +static void esp_free_lun_tag(struct esp_cmd_entry *ent, + struct esp_lun_data *lp) +{ + if (ent->tag[0]) { + BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent); + lp->tagged_cmds[ent->tag[1]] = NULL; + lp->num_tagged--; + } else { + BUG_ON(lp->non_tagged_cmd != ent); + lp->non_tagged_cmd = NULL; + } +} + +/* When a contingent allegiance conditon is created, we force feed a + * REQUEST_SENSE command to the device to fetch the sense data. I + * tried many other schemes, relying on the scsi error handling layer + * to send out the REQUEST_SENSE automatically, but this was difficult + * to get right especially in the presence of applications like smartd + * which use SG_IO to send out their own REQUEST_SENSE commands. + */ +static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent) +{ + struct scsi_cmnd *cmd = ent->cmd; + struct scsi_device *dev = cmd->device; + int tgt, lun; + u8 *p, val; + + tgt = dev->id; + lun = dev->lun; + + + if (!ent->sense_ptr) { + esp_log_autosense("esp%d: Doing auto-sense for " + "tgt[%d] lun[%d]\n", + esp->host->unique_id, tgt, lun); + + ent->sense_ptr = cmd->sense_buffer; + ent->sense_dma = esp->ops->map_single(esp, + ent->sense_ptr, + SCSI_SENSE_BUFFERSIZE, + DMA_FROM_DEVICE); + } + ent->saved_sense_ptr = ent->sense_ptr; + + esp->active_cmd = ent; + + p = esp->command_block; + esp->msg_out_len = 0; + + *p++ = IDENTIFY(0, lun); + *p++ = REQUEST_SENSE; + *p++ = ((dev->scsi_level <= SCSI_2) ? + (lun << 5) : 0); + *p++ = 0; + *p++ = 0; + *p++ = SCSI_SENSE_BUFFERSIZE; + *p++ = 0; + + esp->select_state = ESP_SELECT_BASIC; + + val = tgt; + if (esp->rev == FASHME) + val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT; + esp_write8(val, ESP_BUSID); + + esp_write_tgt_sync(esp, tgt); + esp_write_tgt_config3(esp, tgt); + + val = (p - esp->command_block); + + if (esp->rev == FASHME) + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + esp->ops->send_dma_cmd(esp, esp->command_block_dma, + val, 16, 0, ESP_CMD_DMA | ESP_CMD_SELA); +} + +static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp) +{ + struct esp_cmd_entry *ent; + + list_for_each_entry(ent, &esp->queued_cmds, list) { + struct scsi_cmnd *cmd = ent->cmd; + struct scsi_device *dev = cmd->device; + struct esp_lun_data *lp = dev->hostdata; + + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { + ent->tag[0] = 0; + ent->tag[1] = 0; + return ent; + } + + if (!scsi_populate_tag_msg(cmd, &ent->tag[0])) { + ent->tag[0] = 0; + ent->tag[1] = 0; + } + + if (esp_alloc_lun_tag(ent, lp) < 0) + continue; + + return ent; + } + + return NULL; +} + +static void esp_maybe_execute_command(struct esp *esp) +{ + struct esp_target_data *tp; + struct esp_lun_data *lp; + struct scsi_device *dev; + struct scsi_cmnd *cmd; + struct esp_cmd_entry *ent; + int tgt, lun, i; + u32 val, start_cmd; + u8 *p; + + if (esp->active_cmd || + (esp->flags & ESP_FLAG_RESETTING)) + return; + + ent = find_and_prep_issuable_command(esp); + if (!ent) + return; + + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { + esp_autosense(esp, ent); + return; + } + + cmd = ent->cmd; + dev = cmd->device; + tgt = dev->id; + lun = dev->lun; + tp = &esp->target[tgt]; + lp = dev->hostdata; + + list_del(&ent->list); + list_add(&ent->list, &esp->active_cmds); + + esp->active_cmd = ent; + + esp_map_dma(esp, cmd); + esp_save_pointers(esp, ent); + + esp_check_command_len(esp, cmd); + + p = esp->command_block; + + esp->msg_out_len = 0; + if (tp->flags & ESP_TGT_CHECK_NEGO) { + /* Need to negotiate. If the target is broken + * go for synchronous transfers and non-wide. + */ + if (tp->flags & ESP_TGT_BROKEN) { + tp->flags &= ~ESP_TGT_DISCONNECT; + tp->nego_goal_period = 0; + tp->nego_goal_offset = 0; + tp->nego_goal_width = 0; + tp->nego_goal_tags = 0; + } + + /* If the settings are not changing, skip this. */ + if (spi_width(tp->starget) == tp->nego_goal_width && + spi_period(tp->starget) == tp->nego_goal_period && + spi_offset(tp->starget) == tp->nego_goal_offset) { + tp->flags &= ~ESP_TGT_CHECK_NEGO; + goto build_identify; + } + + if (esp->rev == FASHME && esp_need_to_nego_wide(tp)) { + esp->msg_out_len = + spi_populate_width_msg(&esp->msg_out[0], + (tp->nego_goal_width ? + 1 : 0)); + tp->flags |= ESP_TGT_NEGO_WIDE; + } else if (esp_need_to_nego_sync(tp)) { + esp->msg_out_len = + spi_populate_sync_msg(&esp->msg_out[0], + tp->nego_goal_period, + tp->nego_goal_offset); + tp->flags |= ESP_TGT_NEGO_SYNC; + } else { + tp->flags &= ~ESP_TGT_CHECK_NEGO; + } + + /* Process it like a slow command. */ + if (tp->flags & (ESP_TGT_NEGO_WIDE | ESP_TGT_NEGO_SYNC)) + esp->flags |= ESP_FLAG_DOING_SLOWCMD; + } + +build_identify: + /* If we don't have a lun-data struct yet, we're probing + * so do not disconnect. Also, do not disconnect unless + * we have a tag on this command. + */ + if (lp && (tp->flags & ESP_TGT_DISCONNECT) && ent->tag[0]) + *p++ = IDENTIFY(1, lun); + else + *p++ = IDENTIFY(0, lun); + + if (ent->tag[0] && esp->rev == ESP100) { + /* ESP100 lacks select w/atn3 command, use select + * and stop instead. + */ + esp->flags |= ESP_FLAG_DOING_SLOWCMD; + } + + if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) { + start_cmd = ESP_CMD_DMA | ESP_CMD_SELA; + if (ent->tag[0]) { + *p++ = ent->tag[0]; + *p++ = ent->tag[1]; + + start_cmd = ESP_CMD_DMA | ESP_CMD_SA3; + } + + for (i = 0; i < cmd->cmd_len; i++) + *p++ = cmd->cmnd[i]; + + esp->select_state = ESP_SELECT_BASIC; + } else { + esp->cmd_bytes_left = cmd->cmd_len; + esp->cmd_bytes_ptr = &cmd->cmnd[0]; + + if (ent->tag[0]) { + for (i = esp->msg_out_len - 1; + i >= 0; i--) + esp->msg_out[i + 2] = esp->msg_out[i]; + esp->msg_out[0] = ent->tag[0]; + esp->msg_out[1] = ent->tag[1]; + esp->msg_out_len += 2; + } + + start_cmd = ESP_CMD_DMA | ESP_CMD_SELAS; + esp->select_state = ESP_SELECT_MSGOUT; + } + val = tgt; + if (esp->rev == FASHME) + val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT; + esp_write8(val, ESP_BUSID); + + esp_write_tgt_sync(esp, tgt); + esp_write_tgt_config3(esp, tgt); + + val = (p - esp->command_block); + + if (esp_debug & ESP_DEBUG_SCSICMD) { + printk("ESP: tgt[%d] lun[%d] scsi_cmd [ ", tgt, lun); + for (i = 0; i < cmd->cmd_len; i++) + printk("%02x ", cmd->cmnd[i]); + printk("]\n"); + } + + if (esp->rev == FASHME) + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + esp->ops->send_dma_cmd(esp, esp->command_block_dma, + val, 16, 0, start_cmd); +} + +static struct esp_cmd_entry *esp_get_ent(struct esp *esp) +{ + struct list_head *head = &esp->esp_cmd_pool; + struct esp_cmd_entry *ret; + + if (list_empty(head)) { + ret = kzalloc(sizeof(struct esp_cmd_entry), GFP_ATOMIC); + } else { + ret = list_entry(head->next, struct esp_cmd_entry, list); + list_del(&ret->list); + memset(ret, 0, sizeof(*ret)); + } + return ret; +} + +static void esp_put_ent(struct esp *esp, struct esp_cmd_entry *ent) +{ + list_add(&ent->list, &esp->esp_cmd_pool); +} + +static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent, + struct scsi_cmnd *cmd, unsigned int result) +{ + struct scsi_device *dev = cmd->device; + int tgt = dev->id; + int lun = dev->lun; + + esp->active_cmd = NULL; + esp_unmap_dma(esp, cmd); + esp_free_lun_tag(ent, dev->hostdata); + cmd->result = result; + + if (ent->eh_done) { + complete(ent->eh_done); + ent->eh_done = NULL; + } + + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { + esp->ops->unmap_single(esp, ent->sense_dma, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); + ent->sense_ptr = NULL; + + /* Restore the message/status bytes to what we actually + * saw originally. Also, report that we are providing + * the sense data. + */ + cmd->result = ((DRIVER_SENSE << 24) | + (DID_OK << 16) | + (COMMAND_COMPLETE << 8) | + (SAM_STAT_CHECK_CONDITION << 0)); + + ent->flags &= ~ESP_CMD_FLAG_AUTOSENSE; + if (esp_debug & ESP_DEBUG_AUTOSENSE) { + int i; + + printk("esp%d: tgt[%d] lun[%d] AUTO SENSE[ ", + esp->host->unique_id, tgt, lun); + for (i = 0; i < 18; i++) + printk("%02x ", cmd->sense_buffer[i]); + printk("]\n"); + } + } + + cmd->scsi_done(cmd); + + list_del(&ent->list); + esp_put_ent(esp, ent); + + esp_maybe_execute_command(esp); +} + +static unsigned int compose_result(unsigned int status, unsigned int message, + unsigned int driver_code) +{ + return (status | (message << 8) | (driver_code << 16)); +} + +static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent) +{ + struct scsi_device *dev = ent->cmd->device; + struct esp_lun_data *lp = dev->hostdata; + + scsi_track_queue_full(dev, lp->num_tagged - 1); +} + +static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) +{ + struct scsi_device *dev = cmd->device; + struct esp *esp = host_to_esp(dev->host); + struct esp_cmd_priv *spriv; + struct esp_cmd_entry *ent; + + ent = esp_get_ent(esp); + if (!ent) + return SCSI_MLQUEUE_HOST_BUSY; + + ent->cmd = cmd; + + cmd->scsi_done = done; + + spriv = ESP_CMD_PRIV(cmd); + spriv->u.dma_addr = ~(dma_addr_t)0x0; + + list_add_tail(&ent->list, &esp->queued_cmds); + + esp_maybe_execute_command(esp); + + return 0; +} + +static int esp_check_gross_error(struct esp *esp) +{ + if (esp->sreg & ESP_STAT_SPAM) { + /* Gross Error, could be one of: + * - top of fifo overwritten + * - top of command register overwritten + * - DMA programmed with wrong direction + * - improper phase change + */ + printk(KERN_ERR PFX "esp%d: Gross error sreg[%02x]\n", + esp->host->unique_id, esp->sreg); + /* XXX Reset the chip. XXX */ + return 1; + } + return 0; +} + +static int esp_check_spur_intr(struct esp *esp) +{ + switch (esp->rev) { + case ESP100: + case ESP100A: + /* The interrupt pending bit of the status register cannot + * be trusted on these revisions. + */ + esp->sreg &= ~ESP_STAT_INTR; + break; + + default: + if (!(esp->sreg & ESP_STAT_INTR)) { + esp->ireg = esp_read8(ESP_INTRPT); + if (esp->ireg & ESP_INTR_SR) + return 1; + + /* If the DMA is indicating interrupt pending and the + * ESP is not, the only possibility is a DMA error. + */ + if (!esp->ops->dma_error(esp)) { + printk(KERN_ERR PFX "esp%d: Spurious irq, " + "sreg=%x.\n", + esp->host->unique_id, esp->sreg); + return -1; + } + + printk(KERN_ERR PFX "esp%d: DMA error\n", + esp->host->unique_id); + + /* XXX Reset the chip. XXX */ + return -1; + } + break; + } + + return 0; +} + +static void esp_schedule_reset(struct esp *esp) +{ + esp_log_reset("ESP: esp_schedule_reset() from %p\n", + __builtin_return_address(0)); + esp->flags |= ESP_FLAG_RESETTING; + esp_event(esp, ESP_EVENT_RESET); +} + +/* In order to avoid having to add a special half-reconnected state + * into the driver we just sit here and poll through the rest of + * the reselection process to get the tag message bytes. + */ +static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp, + struct esp_lun_data *lp) +{ + struct esp_cmd_entry *ent; + int i; + + if (!lp->num_tagged) { + printk(KERN_ERR PFX "esp%d: Reconnect w/num_tagged==0\n", + esp->host->unique_id); + return NULL; + } + + esp_log_reconnect("ESP: reconnect tag, "); + + for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) { + if (esp->ops->irq_pending(esp)) + break; + } + if (i == ESP_QUICKIRQ_LIMIT) { + printk(KERN_ERR PFX "esp%d: Reconnect IRQ1 timeout\n", + esp->host->unique_id); + return NULL; + } + + esp->sreg = esp_read8(ESP_STATUS); + esp->ireg = esp_read8(ESP_INTRPT); + + esp_log_reconnect("IRQ(%d:%x:%x), ", + i, esp->ireg, esp->sreg); + + if (esp->ireg & ESP_INTR_DC) { + printk(KERN_ERR PFX "esp%d: Reconnect, got disconnect.\n", + esp->host->unique_id); + return NULL; + } + + if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) { + printk(KERN_ERR PFX "esp%d: Reconnect, not MIP sreg[%02x].\n", + esp->host->unique_id, esp->sreg); + return NULL; + } + + /* DMA in the tag bytes... */ + esp->command_block[0] = 0xff; + esp->command_block[1] = 0xff; + esp->ops->send_dma_cmd(esp, esp->command_block_dma, + 2, 2, 1, ESP_CMD_DMA | ESP_CMD_TI); + + /* ACK the msssage. */ + scsi_esp_cmd(esp, ESP_CMD_MOK); + + for (i = 0; i < ESP_RESELECT_TAG_LIMIT; i++) { + if (esp->ops->irq_pending(esp)) { + esp->sreg = esp_read8(ESP_STATUS); + esp->ireg = esp_read8(ESP_INTRPT); + if (esp->ireg & ESP_INTR_FDONE) + break; + } + udelay(1); + } + if (i == ESP_RESELECT_TAG_LIMIT) { + printk(KERN_ERR PFX "esp%d: Reconnect IRQ2 timeout\n", + esp->host->unique_id); + return NULL; + } + esp->ops->dma_drain(esp); + esp->ops->dma_invalidate(esp); + + esp_log_reconnect("IRQ2(%d:%x:%x) tag[%x:%x]\n", + i, esp->ireg, esp->sreg, + esp->command_block[0], + esp->command_block[1]); + + if (esp->command_block[0] < SIMPLE_QUEUE_TAG || + esp->command_block[0] > ORDERED_QUEUE_TAG) { + printk(KERN_ERR PFX "esp%d: Reconnect, bad tag " + "type %02x.\n", + esp->host->unique_id, esp->command_block[0]); + return NULL; + } + + ent = lp->tagged_cmds[esp->command_block[1]]; + if (!ent) { + printk(KERN_ERR PFX "esp%d: Reconnect, no entry for " + "tag %02x.\n", + esp->host->unique_id, esp->command_block[1]); + return NULL; + } + + return ent; +} + +static int esp_reconnect(struct esp *esp) +{ + struct esp_cmd_entry *ent; + struct esp_target_data *tp; + struct esp_lun_data *lp; + struct scsi_device *dev; + int target, lun; + + BUG_ON(esp->active_cmd); + if (esp->rev == FASHME) { + /* FASHME puts the target and lun numbers directly + * into the fifo. + */ + target = esp->fifo[0]; + lun = esp->fifo[1] & 0x7; + } else { + u8 bits = esp_read8(ESP_FDATA); + + /* Older chips put the lun directly into the fifo, but + * the target is given as a sample of the arbitration + * lines on the bus at reselection time. So we should + * see the ID of the ESP and the one reconnecting target + * set in the bitmap. + */ + if (!(bits & esp->scsi_id_mask)) + goto do_reset; + bits &= ~esp->scsi_id_mask; + if (!bits || (bits & (bits - 1))) + goto do_reset; + + target = ffs(bits) - 1; + lun = (esp_read8(ESP_FDATA) & 0x7); + + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + if (esp->rev == ESP100) { + u8 ireg = esp_read8(ESP_INTRPT); + /* This chip has a bug during reselection that can + * cause a spurious illegal-command interrupt, which + * we simply ACK here. Another possibility is a bus + * reset so we must check for that. + */ + if (ireg & ESP_INTR_SR) + goto do_reset; + } + scsi_esp_cmd(esp, ESP_CMD_NULL); + } + + esp_write_tgt_sync(esp, target); + esp_write_tgt_config3(esp, target); + + scsi_esp_cmd(esp, ESP_CMD_MOK); + + if (esp->rev == FASHME) + esp_write8(target | ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT, + ESP_BUSID); + + tp = &esp->target[target]; + dev = __scsi_device_lookup_by_target(tp->starget, lun); + if (!dev) { + printk(KERN_ERR PFX "esp%d: Reconnect, no lp " + "tgt[%u] lun[%u]\n", + esp->host->unique_id, target, lun); + goto do_reset; + } + lp = dev->hostdata; + + ent = lp->non_tagged_cmd; + if (!ent) { + ent = esp_reconnect_with_tag(esp, lp); + if (!ent) + goto do_reset; + } + + esp->active_cmd = ent; + + if (ent->flags & ESP_CMD_FLAG_ABORT) { + esp->msg_out[0] = ABORT_TASK_SET; + esp->msg_out_len = 1; + scsi_esp_cmd(esp, ESP_CMD_SATN); + } + + esp_event(esp, ESP_EVENT_CHECK_PHASE); + esp_restore_pointers(esp, ent); + esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; + return 1; + +do_reset: + esp_schedule_reset(esp); + return 0; +} + +static int esp_finish_select(struct esp *esp) +{ + struct esp_cmd_entry *ent; + struct scsi_cmnd *cmd; + u8 orig_select_state; + + orig_select_state = esp->select_state; + + /* No longer selecting. */ + esp->select_state = ESP_SELECT_NONE; + + esp->seqreg = esp_read8(ESP_SSTEP) & ESP_STEP_VBITS; + ent = esp->active_cmd; + cmd = ent->cmd; + + if (esp->ops->dma_error(esp)) { + /* If we see a DMA error during or as a result of selection, + * all bets are off. + */ + esp_schedule_reset(esp); + esp_cmd_is_done(esp, ent, cmd, (DID_ERROR << 16)); + return 0; + } + + esp->ops->dma_invalidate(esp); + + if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) { + struct esp_target_data *tp = &esp->target[cmd->device->id]; + + /* Carefully back out of the selection attempt. Release + * resources (such as DMA mapping & TAG) and reset state (such + * as message out and command delivery variables). + */ + if (!(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) { + esp_unmap_dma(esp, cmd); + esp_free_lun_tag(ent, cmd->device->hostdata); + tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE); + esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; + esp->cmd_bytes_ptr = NULL; + esp->cmd_bytes_left = 0; + } else { + esp->ops->unmap_single(esp, ent->sense_dma, + SCSI_SENSE_BUFFERSIZE, + DMA_FROM_DEVICE); + ent->sense_ptr = NULL; + } + + /* Now that the state is unwound properly, put back onto + * the issue queue. This command is no longer active. + */ + list_del(&ent->list); + list_add(&ent->list, &esp->queued_cmds); + esp->active_cmd = NULL; + + /* Return value ignored by caller, it directly invokes + * esp_reconnect(). + */ + return 0; + } + + if (esp->ireg == ESP_INTR_DC) { + struct scsi_device *dev = cmd->device; + + /* Disconnect. Make sure we re-negotiate sync and + * wide parameters if this target starts responding + * again in the future. + */ + esp->target[dev->id].flags |= ESP_TGT_CHECK_NEGO; + + scsi_esp_cmd(esp, ESP_CMD_ESEL); + esp_cmd_is_done(esp, ent, cmd, (DID_BAD_TARGET << 16)); + return 1; + } + + if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) { + /* Selection successful. On pre-FAST chips we have + * to do a NOP and possibly clean out the FIFO. + */ + if (esp->rev <= ESP236) { + int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; + + scsi_esp_cmd(esp, ESP_CMD_NULL); + + if (!fcnt && + (!esp->prev_soff || + ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP))) + esp_flush_fifo(esp); + } + + /* If we are doing a slow command, negotiation, etc. + * we'll do the right thing as we transition to the + * next phase. + */ + esp_event(esp, ESP_EVENT_CHECK_PHASE); + return 0; + } + + printk("ESP: Unexpected selection completion ireg[%x].\n", + esp->ireg); + esp_schedule_reset(esp); + return 0; +} + +static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent, + struct scsi_cmnd *cmd) +{ + int fifo_cnt, ecount, bytes_sent, flush_fifo; + + fifo_cnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; + if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE) + fifo_cnt <<= 1; + + ecount = 0; + if (!(esp->sreg & ESP_STAT_TCNT)) { + ecount = ((unsigned int)esp_read8(ESP_TCLOW) | + (((unsigned int)esp_read8(ESP_TCMED)) << 8)); + if (esp->rev == FASHME) + ecount |= ((unsigned int)esp_read8(FAS_RLO)) << 16; + } + + bytes_sent = esp->data_dma_len; + bytes_sent -= ecount; + + if (!(ent->flags & ESP_CMD_FLAG_WRITE)) + bytes_sent -= fifo_cnt; + + flush_fifo = 0; + if (!esp->prev_soff) { + /* Synchronous data transfer, always flush fifo. */ + flush_fifo = 1; + } else { + if (esp->rev == ESP100) { + u32 fflags, phase; + + /* ESP100 has a chip bug where in the synchronous data + * phase it can mistake a final long REQ pulse from the + * target as an extra data byte. Fun. + * + * To detect this case we resample the status register + * and fifo flags. If we're still in a data phase and + * we see spurious chunks in the fifo, we return error + * to the caller which should reset and set things up + * such that we only try future transfers to this + * target in synchronous mode. + */ + esp->sreg = esp_read8(ESP_STATUS); + phase = esp->sreg & ESP_STAT_PMASK; + fflags = esp_read8(ESP_FFLAGS); + + if ((phase == ESP_DOP && + (fflags & ESP_FF_ONOTZERO)) || + (phase == ESP_DIP && + (fflags & ESP_FF_FBYTES))) + return -1; + } + if (!(ent->flags & ESP_CMD_FLAG_WRITE)) + flush_fifo = 1; + } + + if (flush_fifo) + esp_flush_fifo(esp); + + return bytes_sent; +} + +static void esp_setsync(struct esp *esp, struct esp_target_data *tp, + u8 scsi_period, u8 scsi_offset, + u8 esp_stp, u8 esp_soff) +{ + spi_period(tp->starget) = scsi_period; + spi_offset(tp->starget) = scsi_offset; + spi_width(tp->starget) = (tp->flags & ESP_TGT_WIDE) ? 1 : 0; + + if (esp_soff) { + esp_stp &= 0x1f; + esp_soff |= esp->radelay; + if (esp->rev >= FAS236) { + u8 bit = ESP_CONFIG3_FSCSI; + if (esp->rev >= FAS100A) + bit = ESP_CONFIG3_FAST; + + if (scsi_period < 50) { + if (esp->rev == FASHME) + esp_soff &= ~esp->radelay; + tp->esp_config3 |= bit; + } else { + tp->esp_config3 &= ~bit; + } + esp->prev_cfg3 = tp->esp_config3; + esp_write8(esp->prev_cfg3, ESP_CFG3); + } + } + + tp->esp_period = esp->prev_stp = esp_stp; + tp->esp_offset = esp->prev_soff = esp_soff; + + esp_write8(esp_soff, ESP_SOFF); + esp_write8(esp_stp, ESP_STP); + + tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO); + + spi_display_xfer_agreement(tp->starget); +} + +static void esp_msgin_reject(struct esp *esp) +{ + struct esp_cmd_entry *ent = esp->active_cmd; + struct scsi_cmnd *cmd = ent->cmd; + struct esp_target_data *tp; + int tgt; + + tgt = cmd->device->id; + tp = &esp->target[tgt]; + + if (tp->flags & ESP_TGT_NEGO_WIDE) { + tp->flags &= ~(ESP_TGT_NEGO_WIDE | ESP_TGT_WIDE); + + if (!esp_need_to_nego_sync(tp)) { + tp->flags &= ~ESP_TGT_CHECK_NEGO; + scsi_esp_cmd(esp, ESP_CMD_RATN); + } else { + esp->msg_out_len = + spi_populate_sync_msg(&esp->msg_out[0], + tp->nego_goal_period, + tp->nego_goal_offset); + tp->flags |= ESP_TGT_NEGO_SYNC; + scsi_esp_cmd(esp, ESP_CMD_SATN); + } + return; + } + + if (tp->flags & ESP_TGT_NEGO_SYNC) { + tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO); + tp->esp_period = 0; + tp->esp_offset = 0; + esp_setsync(esp, tp, 0, 0, 0, 0); + scsi_esp_cmd(esp, ESP_CMD_RATN); + return; + } + + esp->msg_out[0] = ABORT_TASK_SET; + esp->msg_out_len = 1; + scsi_esp_cmd(esp, ESP_CMD_SATN); +} + +static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp) +{ + u8 period = esp->msg_in[3]; + u8 offset = esp->msg_in[4]; + u8 stp; + + if (!(tp->flags & ESP_TGT_NEGO_SYNC)) + goto do_reject; + + if (offset > 15) + goto do_reject; + + if (offset) { + int rounded_up, one_clock; + + if (period > esp->max_period) { + period = offset = 0; + goto do_sdtr; + } + if (period < esp->min_period) + goto do_reject; + + one_clock = esp->ccycle / 1000; + rounded_up = (period << 2); + rounded_up = (rounded_up + one_clock - 1) / one_clock; + stp = rounded_up; + if (stp && esp->rev >= FAS236) { + if (stp >= 50) + stp--; + } + } else { + stp = 0; + } + + esp_setsync(esp, tp, period, offset, stp, offset); + return; + +do_reject: + esp->msg_out[0] = MESSAGE_REJECT; + esp->msg_out_len = 1; + scsi_esp_cmd(esp, ESP_CMD_SATN); + return; + +do_sdtr: + tp->nego_goal_period = period; + tp->nego_goal_offset = offset; + esp->msg_out_len = + spi_populate_sync_msg(&esp->msg_out[0], + tp->nego_goal_period, + tp->nego_goal_offset); + scsi_esp_cmd(esp, ESP_CMD_SATN); +} + +static void esp_msgin_wdtr(struct esp *esp, struct esp_target_data *tp) +{ + int size = 8 << esp->msg_in[3]; + u8 cfg3; + + if (esp->rev != FASHME) + goto do_reject; + + if (size != 8 && size != 16) + goto do_reject; + + if (!(tp->flags & ESP_TGT_NEGO_WIDE)) + goto do_reject; + + cfg3 = tp->esp_config3; + if (size == 16) { + tp->flags |= ESP_TGT_WIDE; + cfg3 |= ESP_CONFIG3_EWIDE; + } else { + tp->flags &= ~ESP_TGT_WIDE; + cfg3 &= ~ESP_CONFIG3_EWIDE; + } + tp->esp_config3 = cfg3; + esp->prev_cfg3 = cfg3; + esp_write8(cfg3, ESP_CFG3); + + tp->flags &= ~ESP_TGT_NEGO_WIDE; + + spi_period(tp->starget) = 0; + spi_offset(tp->starget) = 0; + if (!esp_need_to_nego_sync(tp)) { + tp->flags &= ~ESP_TGT_CHECK_NEGO; + scsi_esp_cmd(esp, ESP_CMD_RATN); + } else { + esp->msg_out_len = + spi_populate_sync_msg(&esp->msg_out[0], + tp->nego_goal_period, + tp->nego_goal_offset); + tp->flags |= ESP_TGT_NEGO_SYNC; + scsi_esp_cmd(esp, ESP_CMD_SATN); + } + return; + +do_reject: + esp->msg_out[0] = MESSAGE_REJECT; + esp->msg_out_len = 1; + scsi_esp_cmd(esp, ESP_CMD_SATN); +} + +static void esp_msgin_extended(struct esp *esp) +{ + struct esp_cmd_entry *ent = esp->active_cmd; + struct scsi_cmnd *cmd = ent->cmd; + struct esp_target_data *tp; + int tgt = cmd->device->id; + + tp = &esp->target[tgt]; + if (esp->msg_in[2] == EXTENDED_SDTR) { + esp_msgin_sdtr(esp, tp); + return; + } + if (esp->msg_in[2] == EXTENDED_WDTR) { + esp_msgin_wdtr(esp, tp); + return; + } + + printk("ESP: Unexpected extended msg type %x\n", + esp->msg_in[2]); + + esp->msg_out[0] = ABORT_TASK_SET; + esp->msg_out_len = 1; + scsi_esp_cmd(esp, ESP_CMD_SATN); +} + +/* Analyze msgin bytes received from target so far. Return non-zero + * if there are more bytes needed to complete the message. + */ +static int esp_msgin_process(struct esp *esp) +{ + u8 msg0 = esp->msg_in[0]; + int len = esp->msg_in_len; + + if (msg0 & 0x80) { + /* Identify */ + printk("ESP: Unexpected msgin identify\n"); + return 0; + } + + switch (msg0) { + case EXTENDED_MESSAGE: + if (len == 1) + return 1; + if (len < esp->msg_in[1] + 2) + return 1; + esp_msgin_extended(esp); + return 0; + + case IGNORE_WIDE_RESIDUE: { + struct esp_cmd_entry *ent; + struct esp_cmd_priv *spriv; + if (len == 1) + return 1; + + if (esp->msg_in[1] != 1) + goto do_reject; + + ent = esp->active_cmd; + spriv = ESP_CMD_PRIV(ent->cmd); + + if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) { + spriv->cur_sg--; + spriv->cur_residue = 1; + } else + spriv->cur_residue++; + spriv->tot_residue++; + return 0; + } + case NOP: + return 0; + case RESTORE_POINTERS: + esp_restore_pointers(esp, esp->active_cmd); + return 0; + case SAVE_POINTERS: + esp_save_pointers(esp, esp->active_cmd); + return 0; + + case COMMAND_COMPLETE: + case DISCONNECT: { + struct esp_cmd_entry *ent = esp->active_cmd; + + ent->message = msg0; + esp_event(esp, ESP_EVENT_FREE_BUS); + esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; + return 0; + } + case MESSAGE_REJECT: + esp_msgin_reject(esp); + return 0; + + default: + do_reject: + esp->msg_out[0] = MESSAGE_REJECT; + esp->msg_out_len = 1; + scsi_esp_cmd(esp, ESP_CMD_SATN); + return 0; + } +} + +static int esp_process_event(struct esp *esp) +{ + int write; + +again: + write = 0; + switch (esp->event) { + case ESP_EVENT_CHECK_PHASE: + switch (esp->sreg & ESP_STAT_PMASK) { + case ESP_DOP: + esp_event(esp, ESP_EVENT_DATA_OUT); + break; + case ESP_DIP: + esp_event(esp, ESP_EVENT_DATA_IN); + break; + case ESP_STATP: + esp_flush_fifo(esp); + scsi_esp_cmd(esp, ESP_CMD_ICCSEQ); + esp_event(esp, ESP_EVENT_STATUS); + esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; + return 1; + + case ESP_MOP: + esp_event(esp, ESP_EVENT_MSGOUT); + break; + + case ESP_MIP: + esp_event(esp, ESP_EVENT_MSGIN); + break; + + case ESP_CMDP: + esp_event(esp, ESP_EVENT_CMD_START); + break; + + default: + printk("ESP: Unexpected phase, sreg=%02x\n", + esp->sreg); + esp_schedule_reset(esp); + return 0; + } + goto again; + break; + + case ESP_EVENT_DATA_IN: + write = 1; + /* fallthru */ + + case ESP_EVENT_DATA_OUT: { + struct esp_cmd_entry *ent = esp->active_cmd; + struct scsi_cmnd *cmd = ent->cmd; + dma_addr_t dma_addr = esp_cur_dma_addr(ent, cmd); + unsigned int dma_len = esp_cur_dma_len(ent, cmd); + + if (esp->rev == ESP100) + scsi_esp_cmd(esp, ESP_CMD_NULL); + + if (write) + ent->flags |= ESP_CMD_FLAG_WRITE; + else + ent->flags &= ~ESP_CMD_FLAG_WRITE; + + dma_len = esp_dma_length_limit(esp, dma_addr, dma_len); + esp->data_dma_len = dma_len; + + if (!dma_len) { + printk(KERN_ERR PFX "esp%d: DMA length is zero!\n", + esp->host->unique_id); + printk(KERN_ERR PFX "esp%d: cur adr[%08x] len[%08x]\n", + esp->host->unique_id, + esp_cur_dma_addr(ent, cmd), + esp_cur_dma_len(ent, cmd)); + esp_schedule_reset(esp); + return 0; + } + + esp_log_datastart("ESP: start data addr[%08x] len[%u] " + "write(%d)\n", + dma_addr, dma_len, write); + + esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len, + write, ESP_CMD_DMA | ESP_CMD_TI); + esp_event(esp, ESP_EVENT_DATA_DONE); + break; + } + case ESP_EVENT_DATA_DONE: { + struct esp_cmd_entry *ent = esp->active_cmd; + struct scsi_cmnd *cmd = ent->cmd; + int bytes_sent; + + if (esp->ops->dma_error(esp)) { + printk("ESP: data done, DMA error, resetting\n"); + esp_schedule_reset(esp); + return 0; + } + + if (ent->flags & ESP_CMD_FLAG_WRITE) { + /* XXX parity errors, etc. XXX */ + + esp->ops->dma_drain(esp); + } + esp->ops->dma_invalidate(esp); + + if (esp->ireg != ESP_INTR_BSERV) { + /* We should always see exactly a bus-service + * interrupt at the end of a successful transfer. + */ + printk("ESP: data done, not BSERV, resetting\n"); + esp_schedule_reset(esp); + return 0; + } + + bytes_sent = esp_data_bytes_sent(esp, ent, cmd); + + esp_log_datadone("ESP: data done flgs[%x] sent[%d]\n", + ent->flags, bytes_sent); + + if (bytes_sent < 0) { + /* XXX force sync mode for this target XXX */ + esp_schedule_reset(esp); + return 0; + } + + esp_advance_dma(esp, ent, cmd, bytes_sent); + esp_event(esp, ESP_EVENT_CHECK_PHASE); + goto again; + break; + } + + case ESP_EVENT_STATUS: { + struct esp_cmd_entry *ent = esp->active_cmd; + + if (esp->ireg & ESP_INTR_FDONE) { + ent->status = esp_read8(ESP_FDATA); + ent->message = esp_read8(ESP_FDATA); + scsi_esp_cmd(esp, ESP_CMD_MOK); + } else if (esp->ireg == ESP_INTR_BSERV) { + ent->status = esp_read8(ESP_FDATA); + ent->message = 0xff; + esp_event(esp, ESP_EVENT_MSGIN); + return 0; + } + + if (ent->message != COMMAND_COMPLETE) { + printk("ESP: Unexpected message %x in status\n", + ent->message); + esp_schedule_reset(esp); + return 0; + } + + esp_event(esp, ESP_EVENT_FREE_BUS); + esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; + break; + } + case ESP_EVENT_FREE_BUS: { + struct esp_cmd_entry *ent = esp->active_cmd; + struct scsi_cmnd *cmd = ent->cmd; + + if (ent->message == COMMAND_COMPLETE || + ent->message == DISCONNECT) + scsi_esp_cmd(esp, ESP_CMD_ESEL); + + if (ent->message == COMMAND_COMPLETE) { + esp_log_cmddone("ESP: Command done status[%x] " + "message[%x]\n", + ent->status, ent->message); + if (ent->status == SAM_STAT_TASK_SET_FULL) + esp_event_queue_full(esp, ent); + + if (ent->status == SAM_STAT_CHECK_CONDITION && + !(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) { + ent->flags |= ESP_CMD_FLAG_AUTOSENSE; + esp_autosense(esp, ent); + } else { + esp_cmd_is_done(esp, ent, cmd, + compose_result(ent->status, + ent->message, + DID_OK)); + } + } else if (ent->message == DISCONNECT) { + esp_log_disconnect("ESP: Disconnecting tgt[%d] " + "tag[%x:%x]\n", + cmd->device->id, + ent->tag[0], ent->tag[1]); + + esp->active_cmd = NULL; + esp_maybe_execute_command(esp); + } else { + printk("ESP: Unexpected message %x in freebus\n", + ent->message); + esp_schedule_reset(esp); + return 0; + } + if (esp->active_cmd) + esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; + break; + } + case ESP_EVENT_MSGOUT: { + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + + if (esp_debug & ESP_DEBUG_MSGOUT) { + int i; + printk("ESP: Sending message [ "); + for (i = 0; i < esp->msg_out_len; i++) + printk("%02x ", esp->msg_out[i]); + printk("]\n"); + } + + if (esp->rev == FASHME) { + int i; + + /* Always use the fifo. */ + for (i = 0; i < esp->msg_out_len; i++) { + esp_write8(esp->msg_out[i], ESP_FDATA); + esp_write8(0, ESP_FDATA); + } + scsi_esp_cmd(esp, ESP_CMD_TI); + } else { + if (esp->msg_out_len == 1) { + esp_write8(esp->msg_out[0], ESP_FDATA); + scsi_esp_cmd(esp, ESP_CMD_TI); + } else { + /* Use DMA. */ + memcpy(esp->command_block, + esp->msg_out, + esp->msg_out_len); + + esp->ops->send_dma_cmd(esp, + esp->command_block_dma, + esp->msg_out_len, + esp->msg_out_len, + 0, + ESP_CMD_DMA|ESP_CMD_TI); + } + } + esp_event(esp, ESP_EVENT_MSGOUT_DONE); + break; + } + case ESP_EVENT_MSGOUT_DONE: + if (esp->rev == FASHME) { + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + } else { + if (esp->msg_out_len > 1) + esp->ops->dma_invalidate(esp); + } + + if (!(esp->ireg & ESP_INTR_DC)) { + if (esp->rev != FASHME) + scsi_esp_cmd(esp, ESP_CMD_NULL); + } + esp_event(esp, ESP_EVENT_CHECK_PHASE); + goto again; + case ESP_EVENT_MSGIN: + if (esp->ireg & ESP_INTR_BSERV) { + if (esp->rev == FASHME) { + if (!(esp_read8(ESP_STATUS2) & + ESP_STAT2_FEMPTY)) + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + } else { + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + if (esp->rev == ESP100) + scsi_esp_cmd(esp, ESP_CMD_NULL); + } + scsi_esp_cmd(esp, ESP_CMD_TI); + esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; + return 1; + } + if (esp->ireg & ESP_INTR_FDONE) { + u8 val; + + if (esp->rev == FASHME) + val = esp->fifo[0]; + else + val = esp_read8(ESP_FDATA); + esp->msg_in[esp->msg_in_len++] = val; + + esp_log_msgin("ESP: Got msgin byte %x\n", val); + + if (!esp_msgin_process(esp)) + esp->msg_in_len = 0; + + if (esp->rev == FASHME) + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + + scsi_esp_cmd(esp, ESP_CMD_MOK); + + if (esp->event != ESP_EVENT_FREE_BUS) + esp_event(esp, ESP_EVENT_CHECK_PHASE); + } else { + printk("ESP: MSGIN neither BSERV not FDON, resetting"); + esp_schedule_reset(esp); + return 0; + } + break; + case ESP_EVENT_CMD_START: + memcpy(esp->command_block, esp->cmd_bytes_ptr, + esp->cmd_bytes_left); + if (esp->rev == FASHME) + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + esp->ops->send_dma_cmd(esp, esp->command_block_dma, + esp->cmd_bytes_left, 16, 0, + ESP_CMD_DMA | ESP_CMD_TI); + esp_event(esp, ESP_EVENT_CMD_DONE); + esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; + break; + case ESP_EVENT_CMD_DONE: + esp->ops->dma_invalidate(esp); + if (esp->ireg & ESP_INTR_BSERV) { + esp_event(esp, ESP_EVENT_CHECK_PHASE); + goto again; + } + esp_schedule_reset(esp); + return 0; + break; + + case ESP_EVENT_RESET: + scsi_esp_cmd(esp, ESP_CMD_RS); + break; + + default: + printk("ESP: Unexpected event %x, resetting\n", + esp->event); + esp_schedule_reset(esp); + return 0; + break; + } + return 1; +} + +static void esp_reset_cleanup_one(struct esp *esp, struct esp_cmd_entry *ent) +{ + struct scsi_cmnd *cmd = ent->cmd; + + esp_unmap_dma(esp, cmd); + esp_free_lun_tag(ent, cmd->device->hostdata); + cmd->result = DID_RESET << 16; + + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { + esp->ops->unmap_single(esp, ent->sense_dma, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); + ent->sense_ptr = NULL; + } + + cmd->scsi_done(cmd); + list_del(&ent->list); + esp_put_ent(esp, ent); +} + +static void esp_clear_hold(struct scsi_device *dev, void *data) +{ + struct esp_lun_data *lp = dev->hostdata; + + BUG_ON(lp->num_tagged); + lp->hold = 0; +} + +static void esp_reset_cleanup(struct esp *esp) +{ + struct esp_cmd_entry *ent, *tmp; + int i; + + list_for_each_entry_safe(ent, tmp, &esp->queued_cmds, list) { + struct scsi_cmnd *cmd = ent->cmd; + + list_del(&ent->list); + cmd->result = DID_RESET << 16; + cmd->scsi_done(cmd); + esp_put_ent(esp, ent); + } + + list_for_each_entry_safe(ent, tmp, &esp->active_cmds, list) { + if (ent == esp->active_cmd) + esp->active_cmd = NULL; + esp_reset_cleanup_one(esp, ent); + } + + BUG_ON(esp->active_cmd != NULL); + + /* Force renegotiation of sync/wide transfers. */ + for (i = 0; i < ESP_MAX_TARGET; i++) { + struct esp_target_data *tp = &esp->target[i]; + + tp->esp_period = 0; + tp->esp_offset = 0; + tp->esp_config3 &= ~(ESP_CONFIG3_EWIDE | + ESP_CONFIG3_FSCSI | + ESP_CONFIG3_FAST); + tp->flags &= ~ESP_TGT_WIDE; + tp->flags |= ESP_TGT_CHECK_NEGO; + + if (tp->starget) + starget_for_each_device(tp->starget, NULL, + esp_clear_hold); + } +} + +/* Runs under host->lock */ +static void __esp_interrupt(struct esp *esp) +{ + int finish_reset, intr_done; + u8 phase; + + esp->sreg = esp_read8(ESP_STATUS); + + if (esp->flags & ESP_FLAG_RESETTING) { + finish_reset = 1; + } else { + if (esp_check_gross_error(esp)) + return; + + finish_reset = esp_check_spur_intr(esp); + if (finish_reset < 0) + return; + } + + esp->ireg = esp_read8(ESP_INTRPT); + + if (esp->ireg & ESP_INTR_SR) + finish_reset = 1; + + if (finish_reset) { + esp_reset_cleanup(esp); + if (esp->eh_reset) { + complete(esp->eh_reset); + esp->eh_reset = NULL; + } + return; + } + + phase = (esp->sreg & ESP_STAT_PMASK); + if (esp->rev == FASHME) { + if (((phase != ESP_DIP && phase != ESP_DOP) && + esp->select_state == ESP_SELECT_NONE && + esp->event != ESP_EVENT_STATUS && + esp->event != ESP_EVENT_DATA_DONE) || + (esp->ireg & ESP_INTR_RSEL)) { + esp->sreg2 = esp_read8(ESP_STATUS2); + if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || + (esp->sreg2 & ESP_STAT2_F1BYTE)) + hme_read_fifo(esp); + } + } + + esp_log_intr("ESP: intr sreg[%02x] seqreg[%02x] " + "sreg2[%02x] ireg[%02x]\n", + esp->sreg, esp->seqreg, esp->sreg2, esp->ireg); + + intr_done = 0; + + if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN | ESP_INTR_IC)) { + printk("ESP: unexpected IREG %02x\n", esp->ireg); + if (esp->ireg & ESP_INTR_IC) + esp_dump_cmd_log(esp); + + esp_schedule_reset(esp); + } else { + if (!(esp->ireg & ESP_INTR_RSEL)) { + /* Some combination of FDONE, BSERV, DC. */ + if (esp->select_state != ESP_SELECT_NONE) + intr_done = esp_finish_select(esp); + } else if (esp->ireg & ESP_INTR_RSEL) { + if (esp->active_cmd) + (void) esp_finish_select(esp); + intr_done = esp_reconnect(esp); + } + } + while (!intr_done) + intr_done = esp_process_event(esp); +} + +irqreturn_t scsi_esp_intr(int irq, void *dev_id) +{ + struct esp *esp = dev_id; + unsigned long flags; + irqreturn_t ret; + + spin_lock_irqsave(esp->host->host_lock, flags); + ret = IRQ_NONE; + if (esp->ops->irq_pending(esp)) { + ret = IRQ_HANDLED; + for (;;) { + int i; + + __esp_interrupt(esp); + if (!(esp->flags & ESP_FLAG_QUICKIRQ_CHECK)) + break; + esp->flags &= ~ESP_FLAG_QUICKIRQ_CHECK; + + for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) { + if (esp->ops->irq_pending(esp)) + break; + } + if (i == ESP_QUICKIRQ_LIMIT) + break; + } + } + spin_unlock_irqrestore(esp->host->host_lock, flags); + + return ret; +} +EXPORT_SYMBOL(scsi_esp_intr); + +static void __devinit esp_get_revision(struct esp *esp) +{ + u8 val; + + esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); + esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); + esp_write8(esp->config2, ESP_CFG2); + + val = esp_read8(ESP_CFG2); + val &= ~ESP_CONFIG2_MAGIC; + if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { + /* If what we write to cfg2 does not come back, cfg2 is not + * implemented, therefore this must be a plain esp100. + */ + esp->rev = ESP100; + } else { + esp->config2 = 0; + esp_set_all_config3(esp, 5); + esp->prev_cfg3 = 5; + esp_write8(esp->config2, ESP_CFG2); + esp_write8(0, ESP_CFG3); + esp_write8(esp->prev_cfg3, ESP_CFG3); + + val = esp_read8(ESP_CFG3); + if (val != 5) { + /* The cfg2 register is implemented, however + * cfg3 is not, must be esp100a. + */ + esp->rev = ESP100A; + } else { + esp_set_all_config3(esp, 0); + esp->prev_cfg3 = 0; + esp_write8(esp->prev_cfg3, ESP_CFG3); + + /* All of cfg{1,2,3} implemented, must be one of + * the fas variants, figure out which one. + */ + if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) { + esp->rev = FAST; + esp->sync_defp = SYNC_DEFP_FAST; + } else { + esp->rev = ESP236; + } + esp->config2 = 0; + esp_write8(esp->config2, ESP_CFG2); + } + } +} + +static void __devinit esp_init_swstate(struct esp *esp) +{ + int i; + + INIT_LIST_HEAD(&esp->queued_cmds); + INIT_LIST_HEAD(&esp->active_cmds); + INIT_LIST_HEAD(&esp->esp_cmd_pool); + + /* Start with a clear state, domain validation (via ->slave_configure, + * spi_dv_device()) will attempt to enable SYNC, WIDE, and tagged + * commands. + */ + for (i = 0 ; i < ESP_MAX_TARGET; i++) { + esp->target[i].flags = 0; + esp->target[i].nego_goal_period = 0; + esp->target[i].nego_goal_offset = 0; + esp->target[i].nego_goal_width = 0; + esp->target[i].nego_goal_tags = 0; + } +} + +/* This places the ESP into a known state at boot time. */ +static void __devinit esp_bootup_reset(struct esp *esp) +{ + u8 val; + + /* Reset the DMA */ + esp->ops->reset_dma(esp); + + /* Reset the ESP */ + esp_reset_esp(esp); + + /* Reset the SCSI bus, but tell ESP not to generate an irq */ + val = esp_read8(ESP_CFG1); + val |= ESP_CONFIG1_SRRDISAB; + esp_write8(val, ESP_CFG1); + + scsi_esp_cmd(esp, ESP_CMD_RS); + udelay(400); + + esp_write8(esp->config1, ESP_CFG1); + + /* Eat any bitrot in the chip and we are done... */ + esp_read8(ESP_INTRPT); +} + +static void __devinit esp_set_clock_params(struct esp *esp) +{ + int fmhz; + u8 ccf; + + /* This is getting messy but it has to be done correctly or else + * you get weird behavior all over the place. We are trying to + * basically figure out three pieces of information. + * + * a) Clock Conversion Factor + * + * This is a representation of the input crystal clock frequency + * going into the ESP on this machine. Any operation whose timing + * is longer than 400ns depends on this value being correct. For + * example, you'll get blips for arbitration/selection during high + * load or with multiple targets if this is not set correctly. + * + * b) Selection Time-Out + * + * The ESP isn't very bright and will arbitrate for the bus and try + * to select a target forever if you let it. This value tells the + * ESP when it has taken too long to negotiate and that it should + * interrupt the CPU so we can see what happened. The value is + * computed as follows (from NCR/Symbios chip docs). + * + * (Time Out Period) * (Input Clock) + * STO = ---------------------------------- + * (8192) * (Clock Conversion Factor) + * + * We use a time out period of 250ms (ESP_BUS_TIMEOUT). + * + * c) Imperical constants for synchronous offset and transfer period + * register values + * + * This entails the smallest and largest sync period we could ever + * handle on this ESP. + */ + fmhz = esp->cfreq; + + ccf = ((fmhz / 1000000) + 4) / 5; + if (ccf == 1) + ccf = 2; + + /* If we can't find anything reasonable, just assume 20MHZ. + * This is the clock frequency of the older sun4c's where I've + * been unable to find the clock-frequency PROM property. All + * other machines provide useful values it seems. + */ + if (fmhz <= 5000000 || ccf < 1 || ccf > 8) { + fmhz = 20000000; + ccf = 4; + } + + esp->cfact = (ccf == 8 ? 0 : ccf); + esp->cfreq = fmhz; + esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz); + esp->ctick = ESP_TICK(ccf, esp->ccycle); + esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); + esp->sync_defp = SYNC_DEFP_SLOW; +} + +static const char *esp_chip_names[] = { + "ESP100", + "ESP100A", + "ESP236", + "FAS236", + "FAS100A", + "FAST", + "FASHME", +}; + +static struct scsi_transport_template *esp_transport_template; + +int __devinit scsi_esp_register(struct esp *esp, struct device *dev) +{ + static int instance; + int err; + + esp->host->transportt = esp_transport_template; + esp->host->max_lun = ESP_MAX_LUN; + esp->host->cmd_per_lun = 2; + + esp_set_clock_params(esp); + + esp_get_revision(esp); + + esp_init_swstate(esp); + + esp_bootup_reset(esp); + + printk(KERN_INFO PFX "esp%u, regs[%1p:%1p] irq[%u]\n", + esp->host->unique_id, esp->regs, esp->dma_regs, + esp->host->irq); + printk(KERN_INFO PFX "esp%u is a %s, %u MHz (ccf=%u), SCSI ID %u\n", + esp->host->unique_id, esp_chip_names[esp->rev], + esp->cfreq / 1000000, esp->cfact, esp->scsi_id); + + /* Let the SCSI bus reset settle. */ + ssleep(esp_bus_reset_settle); + + err = scsi_add_host(esp->host, dev); + if (err) + return err; + + esp->host->unique_id = instance++; + + scsi_scan_host(esp->host); + + return 0; +} +EXPORT_SYMBOL(scsi_esp_register); + +void __devexit scsi_esp_unregister(struct esp *esp) +{ + scsi_remove_host(esp->host); +} +EXPORT_SYMBOL(scsi_esp_unregister); + +static int esp_slave_alloc(struct scsi_device *dev) +{ + struct esp *esp = host_to_esp(dev->host); + struct esp_target_data *tp = &esp->target[dev->id]; + struct esp_lun_data *lp; + + lp = kzalloc(sizeof(*lp), GFP_KERNEL); + if (!lp) + return -ENOMEM; + dev->hostdata = lp; + + tp->starget = dev->sdev_target; + + spi_min_period(tp->starget) = esp->min_period; + spi_max_offset(tp->starget) = 15; + + if (esp->flags & ESP_FLAG_WIDE_CAPABLE) + spi_max_width(tp->starget) = 1; + else + spi_max_width(tp->starget) = 0; + + return 0; +} + +static int esp_slave_configure(struct scsi_device *dev) +{ + struct esp *esp = host_to_esp(dev->host); + struct esp_target_data *tp = &esp->target[dev->id]; + int goal_tags, queue_depth; + + goal_tags = 0; + + if (dev->tagged_supported) { + /* XXX make this configurable somehow XXX */ + goal_tags = ESP_DEFAULT_TAGS; + + if (goal_tags > ESP_MAX_TAG) + goal_tags = ESP_MAX_TAG; + } + + queue_depth = goal_tags; + if (queue_depth < dev->host->cmd_per_lun) + queue_depth = dev->host->cmd_per_lun; + + if (goal_tags) { + scsi_set_tag_type(dev, MSG_ORDERED_TAG); + scsi_activate_tcq(dev, queue_depth); + } else { + scsi_deactivate_tcq(dev, queue_depth); + } + tp->flags |= ESP_TGT_DISCONNECT; + + if (!spi_initial_dv(dev->sdev_target)) + spi_dv_device(dev); + + return 0; +} + +static void esp_slave_destroy(struct scsi_device *dev) +{ + struct esp_lun_data *lp = dev->hostdata; + + kfree(lp); + dev->hostdata = NULL; +} + +static int esp_eh_abort_handler(struct scsi_cmnd *cmd) +{ + struct esp *esp = host_to_esp(cmd->device->host); + struct esp_cmd_entry *ent, *tmp; + struct completion eh_done; + unsigned long flags; + + /* XXX This helps a lot with debugging but might be a bit + * XXX much for the final driver. + */ + spin_lock_irqsave(esp->host->host_lock, flags); + printk(KERN_ERR PFX "esp%d: Aborting command [%p:%02x]\n", + esp->host->unique_id, cmd, cmd->cmnd[0]); + ent = esp->active_cmd; + if (ent) + printk(KERN_ERR PFX "esp%d: Current command [%p:%02x]\n", + esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]); + list_for_each_entry(ent, &esp->queued_cmds, list) { + printk(KERN_ERR PFX "esp%d: Queued command [%p:%02x]\n", + esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]); + } + list_for_each_entry(ent, &esp->active_cmds, list) { + printk(KERN_ERR PFX "esp%d: Active command [%p:%02x]\n", + esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]); + } + esp_dump_cmd_log(esp); + spin_unlock_irqrestore(esp->host->host_lock, flags); + + spin_lock_irqsave(esp->host->host_lock, flags); + + ent = NULL; + list_for_each_entry(tmp, &esp->queued_cmds, list) { + if (tmp->cmd == cmd) { + ent = tmp; + break; + } + } + + if (ent) { + /* Easiest case, we didn't even issue the command + * yet so it is trivial to abort. + */ + list_del(&ent->list); + + cmd->result = DID_ABORT << 16; + cmd->scsi_done(cmd); + + esp_put_ent(esp, ent); + + goto out_success; + } + + init_completion(&eh_done); + + ent = esp->active_cmd; + if (ent && ent->cmd == cmd) { + /* Command is the currently active command on + * the bus. If we already have an output message + * pending, no dice. + */ + if (esp->msg_out_len) + goto out_failure; + + /* Send out an abort, encouraging the target to + * go to MSGOUT phase by asserting ATN. + */ + esp->msg_out[0] = ABORT_TASK_SET; + esp->msg_out_len = 1; + ent->eh_done = &eh_done; + + scsi_esp_cmd(esp, ESP_CMD_SATN); + } else { + /* The command is disconnected. This is not easy to + * abort. For now we fail and let the scsi error + * handling layer go try a scsi bus reset or host + * reset. + * + * What we could do is put together a scsi command + * solely for the purpose of sending an abort message + * to the target. Coming up with all the code to + * cook up scsi commands, special case them everywhere, + * etc. is for questionable gain and it would be better + * if the generic scsi error handling layer could do at + * least some of that for us. + * + * Anyways this is an area for potential future improvement + * in this driver. + */ + goto out_failure; + } + + spin_unlock_irqrestore(esp->host->host_lock, flags); + + if (!wait_for_completion_timeout(&eh_done, 5 * HZ)) { + spin_lock_irqsave(esp->host->host_lock, flags); + ent->eh_done = NULL; + spin_unlock_irqrestore(esp->host->host_lock, flags); + + return FAILED; + } + + return SUCCESS; + +out_success: + spin_unlock_irqrestore(esp->host->host_lock, flags); + return SUCCESS; + +out_failure: + /* XXX This might be a good location to set ESP_TGT_BROKEN + * XXX since we know which target/lun in particular is + * XXX causing trouble. + */ + spin_unlock_irqrestore(esp->host->host_lock, flags); + return FAILED; +} + +static int esp_eh_bus_reset_handler(struct scsi_cmnd *cmd) +{ + struct esp *esp = host_to_esp(cmd->device->host); + struct completion eh_reset; + unsigned long flags; + + init_completion(&eh_reset); + + spin_lock_irqsave(esp->host->host_lock, flags); + + esp->eh_reset = &eh_reset; + + /* XXX This is too simple... We should add lots of + * XXX checks here so that if we find that the chip is + * XXX very wedged we return failure immediately so + * XXX that we can perform a full chip reset. + */ + esp->flags |= ESP_FLAG_RESETTING; + scsi_esp_cmd(esp, ESP_CMD_RS); + + spin_unlock_irqrestore(esp->host->host_lock, flags); + + ssleep(esp_bus_reset_settle); + + if (!wait_for_completion_timeout(&eh_reset, 5 * HZ)) { + spin_lock_irqsave(esp->host->host_lock, flags); + esp->eh_reset = NULL; + spin_unlock_irqrestore(esp->host->host_lock, flags); + + return FAILED; + } + + return SUCCESS; +} + +/* All bets are off, reset the entire device. */ +static int esp_eh_host_reset_handler(struct scsi_cmnd *cmd) +{ + struct esp *esp = host_to_esp(cmd->device->host); + unsigned long flags; + + spin_lock_irqsave(esp->host->host_lock, flags); + esp_bootup_reset(esp); + esp_reset_cleanup(esp); + spin_unlock_irqrestore(esp->host->host_lock, flags); + + ssleep(esp_bus_reset_settle); + + return SUCCESS; +} + +static const char *esp_info(struct Scsi_Host *host) +{ + return "esp"; +} + +struct scsi_host_template scsi_esp_template = { + .module = THIS_MODULE, + .name = "esp", + .info = esp_info, + .queuecommand = esp_queuecommand, + .slave_alloc = esp_slave_alloc, + .slave_configure = esp_slave_configure, + .slave_destroy = esp_slave_destroy, + .eh_abort_handler = esp_eh_abort_handler, + .eh_bus_reset_handler = esp_eh_bus_reset_handler, + .eh_host_reset_handler = esp_eh_host_reset_handler, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .use_clustering = ENABLE_CLUSTERING, + .max_sectors = 0xffff, + .skip_settle_delay = 1, +}; +EXPORT_SYMBOL(scsi_esp_template); + +static void esp_get_signalling(struct Scsi_Host *host) +{ + struct esp *esp = host_to_esp(host); + enum spi_signal_type type; + + if (esp->flags & ESP_FLAG_DIFFERENTIAL) + type = SPI_SIGNAL_HVD; + else + type = SPI_SIGNAL_SE; + + spi_signalling(host) = type; +} + +static void esp_set_offset(struct scsi_target *target, int offset) +{ + struct Scsi_Host *host = dev_to_shost(target->dev.parent); + struct esp *esp = host_to_esp(host); + struct esp_target_data *tp = &esp->target[target->id]; + + tp->nego_goal_offset = offset; + tp->flags |= ESP_TGT_CHECK_NEGO; +} + +static void esp_set_period(struct scsi_target *target, int period) +{ + struct Scsi_Host *host = dev_to_shost(target->dev.parent); + struct esp *esp = host_to_esp(host); + struct esp_target_data *tp = &esp->target[target->id]; + + tp->nego_goal_period = period; + tp->flags |= ESP_TGT_CHECK_NEGO; +} + +static void esp_set_width(struct scsi_target *target, int width) +{ + struct Scsi_Host *host = dev_to_shost(target->dev.parent); + struct esp *esp = host_to_esp(host); + struct esp_target_data *tp = &esp->target[target->id]; + + tp->nego_goal_width = (width ? 1 : 0); + tp->flags |= ESP_TGT_CHECK_NEGO; +} + +static struct spi_function_template esp_transport_ops = { + .set_offset = esp_set_offset, + .show_offset = 1, + .set_period = esp_set_period, + .show_period = 1, + .set_width = esp_set_width, + .show_width = 1, + .get_signalling = esp_get_signalling, +}; + +static int __init esp_init(void) +{ + BUILD_BUG_ON(sizeof(struct scsi_pointer) < + sizeof(struct esp_cmd_priv)); + + esp_transport_template = spi_attach_transport(&esp_transport_ops); + if (!esp_transport_template) + return -ENODEV; + + return 0; +} + +static void __exit esp_exit(void) +{ + spi_release_transport(esp_transport_template); +} + +MODULE_DESCRIPTION("ESP SCSI driver core"); +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_param(esp_bus_reset_settle, int, 0); +MODULE_PARM_DESC(esp_bus_reset_settle, + "ESP scsi bus reset delay in seconds"); + +module_param(esp_debug, int, 0); +MODULE_PARM_DESC(esp_debug, +"ESP bitmapped debugging message enable value:\n" +" 0x00000001 Log interrupt events\n" +" 0x00000002 Log scsi commands\n" +" 0x00000004 Log resets\n" +" 0x00000008 Log message in events\n" +" 0x00000010 Log message out events\n" +" 0x00000020 Log command completion\n" +" 0x00000040 Log disconnects\n" +" 0x00000080 Log data start\n" +" 0x00000100 Log data done\n" +" 0x00000200 Log reconnects\n" +" 0x00000400 Log auto-sense data\n" +); + +module_init(esp_init); +module_exit(esp_exit); diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h new file mode 100644 index 00000000000..8d4a6690401 --- /dev/null +++ b/drivers/scsi/esp_scsi.h @@ -0,0 +1,560 @@ +/* esp_scsi.h: Defines and structures for the ESP drier. + * + * Copyright (C) 2007 David S. Miller (davem@davemloft.net) + */ + +#ifndef _ESP_SCSI_H +#define _ESP_SCSI_H + + /* Access Description Offset */ +#define ESP_TCLOW 0x00UL /* rw Low bits transfer count 0x00 */ +#define ESP_TCMED 0x01UL /* rw Mid bits transfer count 0x04 */ +#define ESP_FDATA 0x02UL /* rw FIFO data bits 0x08 */ +#define ESP_CMD 0x03UL /* rw SCSI command bits 0x0c */ +#define ESP_STATUS 0x04UL /* ro ESP status register 0x10 */ +#define ESP_BUSID ESP_STATUS /* wo BusID for sel/resel 0x10 */ +#define ESP_INTRPT 0x05UL /* ro Kind of interrupt 0x14 */ +#define ESP_TIMEO ESP_INTRPT /* wo Timeout for sel/resel 0x14 */ +#define ESP_SSTEP 0x06UL /* ro Sequence step register 0x18 */ +#define ESP_STP ESP_SSTEP /* wo Transfer period/sync 0x18 */ +#define ESP_FFLAGS 0x07UL /* ro Bits current FIFO info 0x1c */ +#define ESP_SOFF ESP_FFLAGS /* wo Sync offset 0x1c */ +#define ESP_CFG1 0x08UL /* rw First cfg register 0x20 */ +#define ESP_CFACT 0x09UL /* wo Clock conv factor 0x24 */ +#define ESP_STATUS2 ESP_CFACT /* ro HME status2 register 0x24 */ +#define ESP_CTEST 0x0aUL /* wo Chip test register 0x28 */ +#define ESP_CFG2 0x0bUL /* rw Second cfg register 0x2c */ +#define ESP_CFG3 0x0cUL /* rw Third cfg register 0x30 */ +#define ESP_TCHI 0x0eUL /* rw High bits transf count 0x38 */ +#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */ +#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */ +#define ESP_FGRND 0x0fUL /* rw Data base for fifo 0x3c */ +#define FAS_RHI ESP_FGRND /* rw HME extended counter 0x3c */ + +#define SBUS_ESP_REG_SIZE 0x40UL + +/* Bitfield meanings for the above registers. */ + +/* ESP config reg 1, read-write, found on all ESP chips */ +#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */ +#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */ +#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */ +#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */ +#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */ +#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */ + +/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */ +#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */ +#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */ +#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */ +#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tgtmode) */ +#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */ +#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */ +#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */ +#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */ +#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,216) */ +#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (236) */ +#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */ +#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */ +#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */ + +/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */ +#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */ +#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */ +#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */ +#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */ +#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */ +#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */ +#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */ +#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */ +#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */ +#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */ +#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */ +#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */ +#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */ +#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */ +#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */ +#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */ + +/* ESP command register read-write */ +/* Group 1 commands: These may be sent at any point in time to the ESP + * chip. None of them can generate interrupts 'cept + * the "SCSI bus reset" command if you have not disabled + * SCSI reset interrupts in the config1 ESP register. + */ +#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */ +#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */ +#define ESP_CMD_RC 0x02 /* Chip reset */ +#define ESP_CMD_RS 0x03 /* SCSI bus reset */ + +/* Group 2 commands: ESP must be an initiator and connected to a target + * for these commands to work. + */ +#define ESP_CMD_TI 0x10 /* Transfer Information */ +#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */ +#define ESP_CMD_MOK 0x12 /* Message okie-dokie */ +#define ESP_CMD_TPAD 0x18 /* Transfer Pad */ +#define ESP_CMD_SATN 0x1a /* Set ATN */ +#define ESP_CMD_RATN 0x1b /* De-assert ATN */ + +/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected + * to a target as the initiator for these commands to work. + */ +#define ESP_CMD_SMSG 0x20 /* Send message */ +#define ESP_CMD_SSTAT 0x21 /* Send status */ +#define ESP_CMD_SDATA 0x22 /* Send data */ +#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */ +#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */ +#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */ +#define ESP_CMD_DCNCT 0x27 /* Disconnect */ +#define ESP_CMD_RMSG 0x28 /* Receive Message */ +#define ESP_CMD_RCMD 0x29 /* Receive Command */ +#define ESP_CMD_RDATA 0x2a /* Receive Data */ +#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */ + +/* Group 4 commands: The ESP must be in the disconnected state and must + * not be connected to any targets as initiator for + * these commands to work. + */ +#define ESP_CMD_RSEL 0x40 /* Reselect */ +#define ESP_CMD_SEL 0x41 /* Select w/o ATN */ +#define ESP_CMD_SELA 0x42 /* Select w/ATN */ +#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */ +#define ESP_CMD_ESEL 0x44 /* Enable selection */ +#define ESP_CMD_DSEL 0x45 /* Disable selections */ +#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */ +#define ESP_CMD_RSEL3 0x47 /* Reselect3 */ + +/* This bit enables the ESP's DMA on the SBus */ +#define ESP_CMD_DMA 0x80 /* Do DMA? */ + +/* ESP status register read-only */ +#define ESP_STAT_PIO 0x01 /* IO phase bit */ +#define ESP_STAT_PCD 0x02 /* CD phase bit */ +#define ESP_STAT_PMSG 0x04 /* MSG phase bit */ +#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */ +#define ESP_STAT_TDONE 0x08 /* Transfer Completed */ +#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */ +#define ESP_STAT_PERR 0x20 /* Parity error */ +#define ESP_STAT_SPAM 0x40 /* Real bad error */ +/* This indicates the 'interrupt pending' condition on esp236, it is a reserved + * bit on other revs of the ESP. + */ +#define ESP_STAT_INTR 0x80 /* Interrupt */ + +/* The status register can be masked with ESP_STAT_PMASK and compared + * with the following values to determine the current phase the ESP + * (at least thinks it) is in. For our purposes we also add our own + * software 'done' bit for our phase management engine. + */ +#define ESP_DOP (0) /* Data Out */ +#define ESP_DIP (ESP_STAT_PIO) /* Data In */ +#define ESP_CMDP (ESP_STAT_PCD) /* Command */ +#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */ +#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */ +#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */ + +/* HME only: status 2 register */ +#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */ +#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */ +#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */ +#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */ +#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */ +#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */ +#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */ +#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */ + +/* ESP interrupt register read-only */ +#define ESP_INTR_S 0x01 /* Select w/o ATN */ +#define ESP_INTR_SATN 0x02 /* Select w/ATN */ +#define ESP_INTR_RSEL 0x04 /* Reselected */ +#define ESP_INTR_FDONE 0x08 /* Function done */ +#define ESP_INTR_BSERV 0x10 /* Bus service */ +#define ESP_INTR_DC 0x20 /* Disconnect */ +#define ESP_INTR_IC 0x40 /* Illegal command given */ +#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */ + +/* ESP sequence step register read-only */ +#define ESP_STEP_VBITS 0x07 /* Valid bits */ +#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */ +#define ESP_STEP_SID 0x01 /* One msg byte sent */ +#define ESP_STEP_NCMD 0x02 /* Was not in command phase */ +#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd + * bytes to be lost + */ +#define ESP_STEP_FINI4 0x04 /* Command was sent ok */ + +/* Ho hum, some ESP's set the step register to this as well... */ +#define ESP_STEP_FINI5 0x05 +#define ESP_STEP_FINI6 0x06 +#define ESP_STEP_FINI7 0x07 + +/* ESP chip-test register read-write */ +#define ESP_TEST_TARG 0x01 /* Target test mode */ +#define ESP_TEST_INI 0x02 /* Initiator test mode */ +#define ESP_TEST_TS 0x04 /* Tristate test mode */ + +/* ESP unique ID register read-only, found on fas236+fas100a only */ +#define ESP_UID_F100A 0x00 /* ESP FAS100A */ +#define ESP_UID_F236 0x02 /* ESP FAS236 */ +#define ESP_UID_REV 0x07 /* ESP revision */ +#define ESP_UID_FAM 0xf8 /* ESP family */ + +/* ESP fifo flags register read-only */ +/* Note that the following implies a 16 byte FIFO on the ESP. */ +#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */ +#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */ +#define ESP_FF_SSTEP 0xe0 /* Sequence step */ + +/* ESP clock conversion factor register write-only */ +#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */ +#define ESP_CCF_NEVER 0x01 /* Set it to this and die */ +#define ESP_CCF_F2 0x02 /* 10MHz */ +#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */ +#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */ +#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */ +#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */ +#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */ + +/* HME only... */ +#define ESP_BUSID_RESELID 0x10 +#define ESP_BUSID_CTR32BIT 0x40 + +#define ESP_BUS_TIMEOUT 250 /* In milli-seconds */ +#define ESP_TIMEO_CONST 8192 +#define ESP_NEG_DEFP(mhz, cfact) \ + ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact))) +#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000)) +#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000)) + +/* For slow to medium speed input clock rates we shoot for 5mb/s, but for high + * input clock rates we try to do 10mb/s although I don't think a transfer can + * even run that fast with an ESP even with DMA2 scatter gather pipelining. + */ +#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */ +#define SYNC_DEFP_FAST 0x19 /* 10mb/s */ + +struct esp_cmd_priv { + union { + dma_addr_t dma_addr; + int num_sg; + } u; + + unsigned int cur_residue; + struct scatterlist *cur_sg; + unsigned int tot_residue; +}; +#define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp)) + +enum esp_rev { + ESP100 = 0x00, /* NCR53C90 - very broken */ + ESP100A = 0x01, /* NCR53C90A */ + ESP236 = 0x02, + FAS236 = 0x03, + FAS100A = 0x04, + FAST = 0x05, + FASHME = 0x06, +}; + +struct esp_cmd_entry { + struct list_head list; + + struct scsi_cmnd *cmd; + + unsigned int saved_cur_residue; + struct scatterlist *saved_cur_sg; + unsigned int saved_tot_residue; + + u8 flags; +#define ESP_CMD_FLAG_WRITE 0x01 /* DMA is a write */ +#define ESP_CMD_FLAG_ABORT 0x02 /* being aborted */ +#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */ + + u8 tag[2]; + + u8 status; + u8 message; + + unsigned char *sense_ptr; + unsigned char *saved_sense_ptr; + dma_addr_t sense_dma; + + struct completion *eh_done; +}; + +/* XXX make this configurable somehow XXX */ +#define ESP_DEFAULT_TAGS 16 + +#define ESP_MAX_TARGET 16 +#define ESP_MAX_LUN 8 +#define ESP_MAX_TAG 256 + +struct esp_lun_data { + struct esp_cmd_entry *non_tagged_cmd; + int num_tagged; + int hold; + struct esp_cmd_entry *tagged_cmds[ESP_MAX_TAG]; +}; + +struct esp_target_data { + /* These are the ESP_STP, ESP_SOFF, and ESP_CFG3 register values which + * match the currently negotiated settings for this target. The SCSI + * protocol values are maintained in spi_{offset,period,wide}(starget). + */ + u8 esp_period; + u8 esp_offset; + u8 esp_config3; + + u8 flags; +#define ESP_TGT_WIDE 0x01 +#define ESP_TGT_DISCONNECT 0x02 +#define ESP_TGT_NEGO_WIDE 0x04 +#define ESP_TGT_NEGO_SYNC 0x08 +#define ESP_TGT_CHECK_NEGO 0x40 +#define ESP_TGT_BROKEN 0x80 + + /* When ESP_TGT_CHECK_NEGO is set, on the next scsi command to this + * device we will try to negotiate the following parameters. + */ + u8 nego_goal_period; + u8 nego_goal_offset; + u8 nego_goal_width; + u8 nego_goal_tags; + + struct scsi_target *starget; +}; + +struct esp_event_ent { + u8 type; +#define ESP_EVENT_TYPE_EVENT 0x01 +#define ESP_EVENT_TYPE_CMD 0x02 + u8 val; + + u8 sreg; + u8 seqreg; + u8 sreg2; + u8 ireg; + u8 select_state; + u8 event; + u8 __pad; +}; + +struct esp; +struct esp_driver_ops { + /* Read and write the ESP 8-bit registers. On some + * applications of the ESP chip the registers are at 4-byte + * instead of 1-byte intervals. + */ + void (*esp_write8)(struct esp *esp, u8 val, unsigned long reg); + u8 (*esp_read8)(struct esp *esp, unsigned long reg); + + /* Map and unmap DMA memory. Eventually the driver will be + * converted to the generic DMA API as soon as SBUS is able to + * cope with that. At such time we can remove this. + */ + dma_addr_t (*map_single)(struct esp *esp, void *buf, + size_t sz, int dir); + int (*map_sg)(struct esp *esp, struct scatterlist *sg, + int num_sg, int dir); + void (*unmap_single)(struct esp *esp, dma_addr_t addr, + size_t sz, int dir); + void (*unmap_sg)(struct esp *esp, struct scatterlist *sg, + int num_sg, int dir); + + /* Return non-zero if there is an IRQ pending. Usually this + * status bit lives in the DMA controller sitting in front of + * the ESP. This has to be accurate or else the ESP interrupt + * handler will not run. + */ + int (*irq_pending)(struct esp *esp); + + /* Reset the DMA engine entirely. On return, ESP interrupts + * should be enabled. Often the interrupt enabling is + * controlled in the DMA engine. + */ + void (*reset_dma)(struct esp *esp); + + /* Drain any pending DMA in the DMA engine after a transfer. + * This is for writes to memory. + */ + void (*dma_drain)(struct esp *esp); + + /* Invalidate the DMA engine after a DMA transfer. */ + void (*dma_invalidate)(struct esp *esp); + + /* Setup an ESP command that will use a DMA transfer. + * The 'esp_count' specifies what transfer length should be + * programmed into the ESP transfer counter registers, whereas + * the 'dma_count' is the length that should be programmed into + * the DMA controller. Usually they are the same. If 'write' + * is non-zero, this transfer is a write into memory. 'cmd' + * holds the ESP command that should be issued by calling + * scsi_esp_cmd() at the appropriate time while programming + * the DMA hardware. + */ + void (*send_dma_cmd)(struct esp *esp, u32 dma_addr, u32 esp_count, + u32 dma_count, int write, u8 cmd); + + /* Return non-zero if the DMA engine is reporting an error + * currently. + */ + int (*dma_error)(struct esp *esp); +}; + +#define ESP_MAX_MSG_SZ 8 +#define ESP_EVENT_LOG_SZ 32 + +#define ESP_QUICKIRQ_LIMIT 100 +#define ESP_RESELECT_TAG_LIMIT 2500 + +struct esp { + void __iomem *regs; + void __iomem *dma_regs; + + const struct esp_driver_ops *ops; + + struct Scsi_Host *host; + void *dev; + + struct esp_cmd_entry *active_cmd; + + struct list_head queued_cmds; + struct list_head active_cmds; + + u8 *command_block; + dma_addr_t command_block_dma; + + unsigned int data_dma_len; + + /* The following are used to determine the cause of an IRQ. Upon every + * IRQ entry we synchronize these with the hardware registers. + */ + u8 sreg; + u8 seqreg; + u8 sreg2; + u8 ireg; + + u32 prev_hme_dmacsr; + u8 prev_soff; + u8 prev_stp; + u8 prev_cfg3; + u8 __pad; + + struct list_head esp_cmd_pool; + + struct esp_target_data target[ESP_MAX_TARGET]; + + int fifo_cnt; + u8 fifo[16]; + + struct esp_event_ent esp_event_log[ESP_EVENT_LOG_SZ]; + int esp_event_cur; + + u8 msg_out[ESP_MAX_MSG_SZ]; + int msg_out_len; + + u8 msg_in[ESP_MAX_MSG_SZ]; + int msg_in_len; + + u8 bursts; + u8 config1; + u8 config2; + + u8 scsi_id; + u32 scsi_id_mask; + + enum esp_rev rev; + + u32 flags; +#define ESP_FLAG_DIFFERENTIAL 0x00000001 +#define ESP_FLAG_RESETTING 0x00000002 +#define ESP_FLAG_DOING_SLOWCMD 0x00000004 +#define ESP_FLAG_WIDE_CAPABLE 0x00000008 +#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010 + + u8 select_state; +#define ESP_SELECT_NONE 0x00 /* Not selecting */ +#define ESP_SELECT_BASIC 0x01 /* Select w/o MSGOUT phase */ +#define ESP_SELECT_MSGOUT 0x02 /* Select with MSGOUT */ + + /* When we are not selecting, we are expecting an event. */ + u8 event; +#define ESP_EVENT_NONE 0x00 +#define ESP_EVENT_CMD_START 0x01 +#define ESP_EVENT_CMD_DONE 0x02 +#define ESP_EVENT_DATA_IN 0x03 +#define ESP_EVENT_DATA_OUT 0x04 +#define ESP_EVENT_DATA_DONE 0x05 +#define ESP_EVENT_MSGIN 0x06 +#define ESP_EVENT_MSGIN_MORE 0x07 +#define ESP_EVENT_MSGIN_DONE 0x08 +#define ESP_EVENT_MSGOUT 0x09 +#define ESP_EVENT_MSGOUT_DONE 0x0a +#define ESP_EVENT_STATUS 0x0b +#define ESP_EVENT_FREE_BUS 0x0c +#define ESP_EVENT_CHECK_PHASE 0x0d +#define ESP_EVENT_RESET 0x10 + + /* Probed in esp_get_clock_params() */ + u32 cfact; + u32 cfreq; + u32 ccycle; + u32 ctick; + u32 neg_defp; + u32 sync_defp; + + /* Computed in esp_reset_esp() */ + u32 max_period; + u32 min_period; + u32 radelay; + + /* Slow command state. */ + u8 *cmd_bytes_ptr; + int cmd_bytes_left; + + struct completion *eh_reset; + + struct sbus_dma *dma; +}; + +#define host_to_esp(host) ((struct esp *)(host)->hostdata) + +/* A front-end driver for the ESP chip should do the following in + * it's device probe routine: + * 1) Allocate the host and private area using scsi_host_alloc() + * with size 'sizeof(struct esp)'. The first argument to + * scsi_host_alloc() should be &scsi_esp_template. + * 2) Set host->max_id as appropriate. + * 3) Set esp->host to the scsi_host itself, and esp->dev + * to the device object pointer. + * 4) Hook up esp->ops to the front-end implementation. + * 5) If the ESP chip supports wide transfers, set ESP_FLAG_WIDE_CAPABLE + * in esp->flags. + * 6) Map the DMA and ESP chip registers. + * 7) DMA map the ESP command block, store the DMA address + * in esp->command_block_dma. + * 8) Register the scsi_esp_intr() interrupt handler. + * 9) Probe for and provide the following chip properties: + * esp->scsi_id (assign to esp->host->this_id too) + * esp->scsi_id_mask + * If ESP bus is differential, set ESP_FLAG_DIFFERENTIAL + * esp->cfreq + * DMA burst bit mask in esp->bursts, if necessary + * 10) Perform any actions necessary before the ESP device can + * be programmed for the first time. On some configs, for + * example, the DMA engine has to be reset before ESP can + * be programmed. + * 11) If necessary, call dev_set_drvdata() as needed. + * 12) Call scsi_esp_register() with prepared 'esp' structure + * and a device pointer if possible. + * 13) Check scsi_esp_register() return value, release all resources + * if an error was returned. + */ +extern struct scsi_host_template scsi_esp_template; +extern int scsi_esp_register(struct esp *, struct device *); + +extern void scsi_esp_unregister(struct esp *); +extern irqreturn_t scsi_esp_intr(int, void *); +extern void scsi_esp_cmd(struct esp *, u8); + +#endif /* !(_ESP_SCSI_H) */ diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c new file mode 100644 index 00000000000..8c766bcd109 --- /dev/null +++ b/drivers/scsi/sun_esp.c @@ -0,0 +1,634 @@ +/* sun_esp.c: ESP front-end for Sparc SBUS systems. + * + * Copyright (C) 2007 David S. Miller (davem@davemloft.net) + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include "esp_scsi.h" + +#define DRV_MODULE_NAME "sun_esp" +#define PFX DRV_MODULE_NAME ": " +#define DRV_VERSION "1.000" +#define DRV_MODULE_RELDATE "April 19, 2007" + +#define dma_read32(REG) \ + sbus_readl(esp->dma_regs + (REG)) +#define dma_write32(VAL, REG) \ + sbus_writel((VAL), esp->dma_regs + (REG)) + +static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev) +{ + struct sbus_dev *sdev = esp->dev; + struct sbus_dma *dma; + + if (dma_sdev != NULL) { + for_each_dvma(dma) { + if (dma->sdev == dma_sdev) + break; + } + } else { + for_each_dvma(dma) { + if (dma->sdev == NULL) + break; + + /* If bus + slot are the same and it has the + * correct OBP name, it's ours. + */ + if (sdev->bus == dma->sdev->bus && + sdev->slot == dma->sdev->slot && + (!strcmp(dma->sdev->prom_name, "dma") || + !strcmp(dma->sdev->prom_name, "espdma"))) + break; + } + } + + if (dma == NULL) { + printk(KERN_ERR PFX "[%s] Cannot find dma.\n", + sdev->ofdev.node->full_name); + return -ENODEV; + } + esp->dma = dma; + esp->dma_regs = dma->regs; + + return 0; + +} + +static int __devinit esp_sbus_map_regs(struct esp *esp, int hme) +{ + struct sbus_dev *sdev = esp->dev; + struct resource *res; + + /* On HME, two reg sets exist, first is DVMA, + * second is ESP registers. + */ + if (hme) + res = &sdev->resource[1]; + else + res = &sdev->resource[0]; + + esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP"); + if (!esp->regs) + return -ENOMEM; + + return 0; +} + +static int __devinit esp_sbus_map_command_block(struct esp *esp) +{ + struct sbus_dev *sdev = esp->dev; + + esp->command_block = sbus_alloc_consistent(sdev, 16, + &esp->command_block_dma); + if (!esp->command_block) + return -ENOMEM; + return 0; +} + +static int __devinit esp_sbus_register_irq(struct esp *esp) +{ + struct Scsi_Host *host = esp->host; + struct sbus_dev *sdev = esp->dev; + + host->irq = sdev->irqs[0]; + return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); +} + +static void __devinit esp_get_scsi_id(struct esp *esp) +{ + struct sbus_dev *sdev = esp->dev; + struct device_node *dp = sdev->ofdev.node; + + esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff); + if (esp->scsi_id != 0xff) + goto done; + + esp->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", 0xff); + if (esp->scsi_id != 0xff) + goto done; + + if (!sdev->bus) { + /* SUN4 */ + esp->scsi_id = 7; + goto done; + } + + esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node, + "scsi-initiator-id", 7); + +done: + esp->host->this_id = esp->scsi_id; + esp->scsi_id_mask = (1 << esp->scsi_id); +} + +static void __devinit esp_get_differential(struct esp *esp) +{ + struct sbus_dev *sdev = esp->dev; + struct device_node *dp = sdev->ofdev.node; + + if (of_find_property(dp, "differential", NULL)) + esp->flags |= ESP_FLAG_DIFFERENTIAL; + else + esp->flags &= ~ESP_FLAG_DIFFERENTIAL; +} + +static void __devinit esp_get_clock_params(struct esp *esp) +{ + struct sbus_dev *sdev = esp->dev; + struct device_node *dp = sdev->ofdev.node; + struct device_node *bus_dp; + int fmhz; + + bus_dp = NULL; + if (sdev != NULL && sdev->bus != NULL) + bus_dp = sdev->bus->ofdev.node; + + fmhz = of_getintprop_default(dp, "clock-frequency", 0); + if (fmhz == 0) + fmhz = (!bus_dp) ? 0 : + of_getintprop_default(bus_dp, "clock-frequency", 0); + + esp->cfreq = fmhz; +} + +static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma) +{ + struct sbus_dev *sdev = esp->dev; + struct device_node *dp = sdev->ofdev.node; + u8 bursts; + + bursts = of_getintprop_default(dp, "burst-sizes", 0xff); + if (dma) { + struct device_node *dma_dp = dma->ofdev.node; + u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff); + if (val != 0xff) + bursts &= val; + } + + if (sdev->bus) { + u8 val = of_getintprop_default(sdev->bus->ofdev.node, + "burst-sizes", 0xff); + if (val != 0xff) + bursts &= val; + } + + if (bursts == 0xff || + (bursts & DMA_BURST16) == 0 || + (bursts & DMA_BURST32) == 0) + bursts = (DMA_BURST32 - 1); + + esp->bursts = bursts; +} + +static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma) +{ + esp_get_scsi_id(esp); + esp_get_differential(esp); + esp_get_clock_params(esp); + esp_get_bursts(esp, espdma); +} + +static void sbus_esp_write8(struct esp *esp, u8 val, unsigned long reg) +{ + sbus_writeb(val, esp->regs + (reg * 4UL)); +} + +static u8 sbus_esp_read8(struct esp *esp, unsigned long reg) +{ + return sbus_readb(esp->regs + (reg * 4UL)); +} + +static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf, + size_t sz, int dir) +{ + return sbus_map_single(esp->dev, buf, sz, dir); +} + +static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg, + int num_sg, int dir) +{ + return sbus_map_sg(esp->dev, sg, num_sg, dir); +} + +static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr, + size_t sz, int dir) +{ + sbus_unmap_single(esp->dev, addr, sz, dir); +} + +static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, + int num_sg, int dir) +{ + sbus_unmap_sg(esp->dev, sg, num_sg, dir); +} + +static int sbus_esp_irq_pending(struct esp *esp) +{ + if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) + return 1; + return 0; +} + +static void sbus_esp_reset_dma(struct esp *esp) +{ + int can_do_burst16, can_do_burst32, can_do_burst64; + int can_do_sbus64, lim; + u32 val; + + can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; + can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; + can_do_burst64 = 0; + can_do_sbus64 = 0; + if (sbus_can_dma_64bit(esp->dev)) + can_do_sbus64 = 1; + if (sbus_can_burst64(esp->sdev)) + can_do_burst64 = (esp->bursts & DMA_BURST64) != 0; + + /* Put the DVMA into a known state. */ + if (esp->dma->revision != dvmahme) { + val = dma_read32(DMA_CSR); + dma_write32(val | DMA_RST_SCSI, DMA_CSR); + dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); + } + switch (esp->dma->revision) { + case dvmahme: + dma_write32(DMA_RESET_FAS366, DMA_CSR); + dma_write32(DMA_RST_SCSI, DMA_CSR); + + esp->prev_hme_dmacsr = (DMA_PARITY_OFF | DMA_2CLKS | + DMA_SCSI_DISAB | DMA_INT_ENAB); + + esp->prev_hme_dmacsr &= ~(DMA_ENABLE | DMA_ST_WRITE | + DMA_BRST_SZ); + + if (can_do_burst64) + esp->prev_hme_dmacsr |= DMA_BRST64; + else if (can_do_burst32) + esp->prev_hme_dmacsr |= DMA_BRST32; + + if (can_do_sbus64) { + esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; + sbus_set_sbus64(esp->dev, esp->bursts); + } + + lim = 1000; + while (dma_read32(DMA_CSR) & DMA_PEND_READ) { + if (--lim == 0) { + printk(KERN_ALERT PFX "esp%d: DMA_PEND_READ " + "will not clear!\n", + esp->host->unique_id); + break; + } + udelay(1); + } + + dma_write32(0, DMA_CSR); + dma_write32(esp->prev_hme_dmacsr, DMA_CSR); + + dma_write32(0, DMA_ADDR); + break; + + case dvmarev2: + if (esp->rev != ESP100) { + val = dma_read32(DMA_CSR); + dma_write32(val | DMA_3CLKS, DMA_CSR); + } + break; + + case dvmarev3: + val = dma_read32(DMA_CSR); + val &= ~DMA_3CLKS; + val |= DMA_2CLKS; + if (can_do_burst32) { + val &= ~DMA_BRST_SZ; + val |= DMA_BRST32; + } + dma_write32(val, DMA_CSR); + break; + + case dvmaesc1: + val = dma_read32(DMA_CSR); + val |= DMA_ADD_ENABLE; + val &= ~DMA_BCNT_ENAB; + if (!can_do_burst32 && can_do_burst16) { + val |= DMA_ESC_BURST; + } else { + val &= ~(DMA_ESC_BURST); + } + dma_write32(val, DMA_CSR); + break; + + default: + break; + } + + /* Enable interrupts. */ + val = dma_read32(DMA_CSR); + dma_write32(val | DMA_INT_ENAB, DMA_CSR); +} + +static void sbus_esp_dma_drain(struct esp *esp) +{ + u32 csr; + int lim; + + if (esp->dma->revision == dvmahme) + return; + + csr = dma_read32(DMA_CSR); + if (!(csr & DMA_FIFO_ISDRAIN)) + return; + + if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1) + dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); + + lim = 1000; + while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { + if (--lim == 0) { + printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", + esp->host->unique_id); + break; + } + udelay(1); + } +} + +static void sbus_esp_dma_invalidate(struct esp *esp) +{ + if (esp->dma->revision == dvmahme) { + dma_write32(DMA_RST_SCSI, DMA_CSR); + + esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | + (DMA_PARITY_OFF | DMA_2CLKS | + DMA_SCSI_DISAB | DMA_INT_ENAB)) & + ~(DMA_ST_WRITE | DMA_ENABLE)); + + dma_write32(0, DMA_CSR); + dma_write32(esp->prev_hme_dmacsr, DMA_CSR); + + /* This is necessary to avoid having the SCSI channel + * engine lock up on us. + */ + dma_write32(0, DMA_ADDR); + } else { + u32 val; + int lim; + + lim = 1000; + while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { + if (--lim == 0) { + printk(KERN_ALERT PFX "esp%d: DMA will not " + "invalidate!\n", esp->host->unique_id); + break; + } + udelay(1); + } + + val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); + val |= DMA_FIFO_INV; + dma_write32(val, DMA_CSR); + val &= ~DMA_FIFO_INV; + dma_write32(val, DMA_CSR); + } +} + +static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, + u32 dma_count, int write, u8 cmd) +{ + u32 csr; + + BUG_ON(!(cmd & ESP_CMD_DMA)); + + sbus_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); + sbus_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); + if (esp->rev == FASHME) { + sbus_esp_write8(esp, (esp_count >> 16) & 0xff, FAS_RLO); + sbus_esp_write8(esp, 0, FAS_RHI); + + scsi_esp_cmd(esp, cmd); + + csr = esp->prev_hme_dmacsr; + csr |= DMA_SCSI_DISAB | DMA_ENABLE; + if (write) + csr |= DMA_ST_WRITE; + else + csr &= ~DMA_ST_WRITE; + esp->prev_hme_dmacsr = csr; + + dma_write32(dma_count, DMA_COUNT); + dma_write32(addr, DMA_ADDR); + dma_write32(csr, DMA_CSR); + } else { + csr = dma_read32(DMA_CSR); + csr |= DMA_ENABLE; + if (write) + csr |= DMA_ST_WRITE; + else + csr &= ~DMA_ST_WRITE; + dma_write32(csr, DMA_CSR); + if (esp->dma->revision == dvmaesc1) { + u32 end = PAGE_ALIGN(addr + dma_count + 16U); + dma_write32(end - addr, DMA_COUNT); + } + dma_write32(addr, DMA_ADDR); + + scsi_esp_cmd(esp, cmd); + } + +} + +static int sbus_esp_dma_error(struct esp *esp) +{ + u32 csr = dma_read32(DMA_CSR); + + if (csr & DMA_HNDL_ERROR) + return 1; + + return 0; +} + +static const struct esp_driver_ops sbus_esp_ops = { + .esp_write8 = sbus_esp_write8, + .esp_read8 = sbus_esp_read8, + .map_single = sbus_esp_map_single, + .map_sg = sbus_esp_map_sg, + .unmap_single = sbus_esp_unmap_single, + .unmap_sg = sbus_esp_unmap_sg, + .irq_pending = sbus_esp_irq_pending, + .reset_dma = sbus_esp_reset_dma, + .dma_drain = sbus_esp_dma_drain, + .dma_invalidate = sbus_esp_dma_invalidate, + .send_dma_cmd = sbus_esp_send_dma_cmd, + .dma_error = sbus_esp_dma_error, +}; + +static int __devinit esp_sbus_probe_one(struct device *dev, + struct sbus_dev *esp_dev, + struct sbus_dev *espdma, + struct sbus_bus *sbus, + int hme) +{ + struct scsi_host_template *tpnt = &scsi_esp_template; + struct Scsi_Host *host; + struct esp *esp; + int err; + + host = scsi_host_alloc(tpnt, sizeof(struct esp)); + + err = -ENOMEM; + if (!host) + goto fail; + + host->max_id = (hme ? 16 : 8); + esp = host_to_esp(host); + + esp->host = host; + esp->dev = esp_dev; + esp->ops = &sbus_esp_ops; + + if (hme) + esp->flags |= ESP_FLAG_WIDE_CAPABLE; + + err = esp_sbus_find_dma(esp, espdma); + if (err < 0) + goto fail_unlink; + + err = esp_sbus_map_regs(esp, hme); + if (err < 0) + goto fail_unlink; + + err = esp_sbus_map_command_block(esp); + if (err < 0) + goto fail_unmap_regs; + + err = esp_sbus_register_irq(esp); + if (err < 0) + goto fail_unmap_command_block; + + esp_sbus_get_props(esp, espdma); + + /* Before we try to touch the ESP chip, ESC1 dma can + * come up with the reset bit set, so make sure that + * is clear first. + */ + if (esp->dma->revision == dvmaesc1) { + u32 val = dma_read32(DMA_CSR); + + dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); + } + + dev_set_drvdata(&esp_dev->ofdev.dev, esp); + + err = scsi_esp_register(esp, dev); + if (err) + goto fail_free_irq; + + return 0; + +fail_free_irq: + free_irq(host->irq, esp); +fail_unmap_command_block: + sbus_free_consistent(esp->dev, 16, + esp->command_block, + esp->command_block_dma); +fail_unmap_regs: + sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE); +fail_unlink: + scsi_host_put(host); +fail: + return err; +} + +static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; + struct sbus_dev *dma_sdev = NULL; + int hme = 0; + + if (dp->parent && + (!strcmp(dp->parent->name, "espdma") || + !strcmp(dp->parent->name, "dma"))) + dma_sdev = sdev->parent; + else if (!strcmp(dp->name, "SUNW,fas")) { + dma_sdev = sdev; + hme = 1; + } + + return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev, + sdev->bus, hme); +} + +static int __devexit esp_sbus_remove(struct of_device *dev) +{ + struct esp *esp = dev_get_drvdata(&dev->dev); + unsigned int irq = esp->host->irq; + u32 val; + + scsi_esp_unregister(esp); + + /* Disable interrupts. */ + val = dma_read32(DMA_CSR); + dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); + + free_irq(irq, esp); + sbus_free_consistent(esp->dev, 16, + esp->command_block, + esp->command_block_dma); + sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE); + + scsi_host_put(esp->host); + + return 0; +} + +static struct of_device_id esp_match[] = { + { + .name = "SUNW,esp", + }, + { + .name = "SUNW,fas", + }, + { + .name = "esp", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, esp_match); + +static struct of_platform_driver esp_sbus_driver = { + .name = "esp", + .match_table = esp_match, + .probe = esp_sbus_probe, + .remove = __devexit_p(esp_sbus_remove), +}; + +static int __init sunesp_init(void) +{ + return of_register_driver(&esp_sbus_driver, &sbus_bus_type); +} + +static void __exit sunesp_exit(void) +{ + of_unregister_driver(&esp_sbus_driver); +} + +MODULE_DESCRIPTION("Sun ESP SCSI driver"); +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(sunesp_init); +module_exit(sunesp_exit); -- cgit v1.2.3