diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-29 17:07:03 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-29 17:07:03 -0700 |
commit | e0a515bc6a2188f02916e976f419a8640312e32a (patch) | |
tree | dd8f4f64cffe37725000c7a80d4b2b973c69f65a /arch | |
parent | 991cef7be26ce78fe2bac72bedaf89e002cc2712 (diff) | |
parent | 6fb8f3acbe833586eb32598d1f844eb9f77c4fba (diff) |
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc:
[PATCH] powerpc: update cell_defconfig
[PATCH] spufs: Disable local interrupts for SPE hash_page calls.
[PATCH] powerpc: Add cputable entry for POWER6
[PATCH] ppc32 CPM_UART: Fixed odd address translations
[PATCH] ppc32: Update board-specific code of the CPM UART users
[PATCH] ppc32 CPM_UART: Convert to use platform devices
[PATCH] ppc32: odd fixes and improvements in ppc_sys
[PATCH] powerpc: Wire up *at syscalls
[PATCH] ppc32: add 440GX erratum 440_43 workaround
[PATCH] powerpc: Use check_legacy_ioport() on ppc32 too.
[PATCH] powerpc64: Fix loading of modules without a .toc section
[PATCH] sound/ppc: snd_pmac_toonie_init should be __init
powerpc/pseries: Tell firmware our capabilities on new machines
[PATCH] powerpc: Fix pagetable bloat for hugepages
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/configs/cell_defconfig | 40 | ||||
-rw-r--r-- | arch/powerpc/kernel/cputable.c | 16 | ||||
-rw-r--r-- | arch/powerpc/kernel/module_64.c | 16 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 112 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup-common.c | 8 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 8 | ||||
-rw-r--r-- | arch/powerpc/kernel/systbl.S | 13 | ||||
-rw-r--r-- | arch/powerpc/mm/hugetlbpage.c | 295 | ||||
-rw-r--r-- | arch/powerpc/mm/init_64.c | 7 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 10 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spu_callbacks.c | 13 | ||||
-rw-r--r-- | arch/ppc/platforms/4xx/ocotea.c | 2 | ||||
-rw-r--r-- | arch/ppc/platforms/mpc8272ads_setup.c | 114 | ||||
-rw-r--r-- | arch/ppc/platforms/mpc866ads_setup.c | 140 | ||||
-rw-r--r-- | arch/ppc/platforms/mpc885ads_setup.c | 131 | ||||
-rw-r--r-- | arch/ppc/platforms/pq2ads.c | 31 | ||||
-rw-r--r-- | arch/ppc/syslib/ibm440gx_common.c | 13 | ||||
-rw-r--r-- | arch/ppc/syslib/ibm440gx_common.h | 4 | ||||
-rw-r--r-- | arch/ppc/syslib/mpc8xx_devices.c | 25 | ||||
-rw-r--r-- | arch/ppc/syslib/ppc_sys.c | 4 | ||||
-rw-r--r-- | arch/ppc/syslib/pq2_sys.c | 8 |
21 files changed, 926 insertions, 84 deletions
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig index fe22e54ab2b..dbe421dc3c1 100644 --- a/arch/powerpc/configs/cell_defconfig +++ b/arch/powerpc/configs/cell_defconfig @@ -9,6 +9,7 @@ CONFIG_PPC_MERGE=y CONFIG_MMU=y CONFIG_GENERIC_HARDIRQS=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PPC=y CONFIG_EARLY_PRINTK=y @@ -55,6 +56,7 @@ CONFIG_SYSCTL=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +# CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y # CONFIG_EMBEDDED is not set @@ -69,10 +71,6 @@ CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 CONFIG_SLAB=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -84,7 +82,6 @@ CONFIG_BASE_SMALL=0 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y @@ -93,6 +90,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # +# CONFIG_BLK_DEV_IO_TRACE is not set # # IO Schedulers @@ -126,6 +124,7 @@ CONFIG_RTAS_FLASH=y CONFIG_MMIO_NVRAM=y CONFIG_CELL_IIC=y # CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set # CONFIG_CPU_FREQ is not set # CONFIG_WANT_EARLY_SERIAL is not set @@ -167,7 +166,6 @@ CONFIG_HAVE_MEMORY_PRESENT=y CONFIG_SPARSEMEM_EXTREME=y # CONFIG_MEMORY_HOTPLUG is not set CONFIG_SPLIT_PTLOCK_CPUS=4 -CONFIG_MIGRATION=y # CONFIG_PPC_64K_PAGES is not set CONFIG_SCHED_SMT=y CONFIG_PROC_DEVICETREE=y @@ -184,7 +182,6 @@ CONFIG_GENERIC_ISA_DMA=y # CONFIG_PPC_INDIRECT_PCI is not set CONFIG_PCI=y CONFIG_PCI_DOMAINS=y -CONFIG_PCI_LEGACY_PROC=y # CONFIG_PCI_DEBUG is not set # @@ -226,6 +223,7 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set CONFIG_INET_TUNNEL=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y @@ -242,6 +240,7 @@ CONFIG_IPV6=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m +CONFIG_INET6_XFRM_TUNNEL=m CONFIG_INET6_TUNNEL=m CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y @@ -632,6 +631,7 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_8250_RUNTIME_UARTS=4 # CONFIG_SERIAL_8250_EXTENDED is not set @@ -717,7 +717,6 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set -# CONFIG_SCx200_ACB is not set # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set # CONFIG_I2C_SIS96X is not set @@ -736,9 +735,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 is not set # CONFIG_SENSORS_MAX6875 is not set -# CONFIG_RTC_X1205_I2C is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -766,10 +763,6 @@ CONFIG_I2C_ALGOBIT=y # # -# Multimedia Capabilities Port drivers -# - -# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -818,6 +811,19 @@ CONFIG_USB_ARCH_HAS_EHCI=y # CONFIG_MMC is not set # +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# # InfiniBand support # CONFIG_INFINIBAND=y @@ -834,6 +840,11 @@ CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y # # +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# # File systems # CONFIG_EXT2_FS=y @@ -889,7 +900,6 @@ CONFIG_TMPFS=y CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y -# CONFIG_RELAYFS_FS is not set # CONFIG_CONFIGFS_FS is not set # diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 39e348a3ade..3f7182db9ed 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -57,6 +57,8 @@ extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP) #define COMMON_USER_POWER5_PLUS (COMMON_USER_PPC64 | PPC_FEATURE_POWER5_PLUS|\ PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP) +#define COMMON_USER_POWER6 (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_05 |\ + PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP) #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ PPC_FEATURE_BOOKE) @@ -263,6 +265,20 @@ struct cpu_spec cpu_specs[] = { .oprofile_type = PPC_OPROFILE_POWER4, .platform = "power5+", }, + { /* Power6 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x003e0000, + .cpu_name = "POWER6", + .cpu_features = CPU_FTRS_POWER6, + .cpu_user_features = COMMON_USER_POWER6, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 6, + .cpu_setup = __setup_cpu_power4, + .oprofile_cpu_type = "ppc64/power6", + .oprofile_type = PPC_OPROFILE_POWER4, + .platform = "power6", + }, { /* Cell Broadband Engine */ .pvr_mask = 0xffff0000, .pvr_value = 0x00700000, diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 928b8581fcb..ba34001fca8 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -191,11 +191,19 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr, (void *)hdr + sechdrs[sechdrs[i].sh_link].sh_offset); } - if (!me->arch.stubs_section || !me->arch.toc_section) { - printk("%s: doesn't contain .toc or .stubs.\n", me->name); + + if (!me->arch.stubs_section) { + printk("%s: doesn't contain .stubs.\n", me->name); return -ENOEXEC; } + /* If we don't have a .toc, just use .stubs. We need to set r2 + to some reasonable value in case the module calls out to + other functions via a stub, or if a function pointer escapes + the module by some means. */ + if (!me->arch.toc_section) + me->arch.toc_section = me->arch.stubs_section; + /* Override the stubs size */ sechdrs[me->arch.stubs_section].sh_size = get_stubs_size(hdr, sechdrs); return 0; @@ -342,7 +350,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, break; case R_PPC64_TOC16: - /* Subtact TOC pointer */ + /* Subtract TOC pointer */ value -= my_r2(sechdrs, me); if (value + 0x8000 > 0xffff) { printk("%s: bad TOC16 relocation (%lu)\n", @@ -355,7 +363,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, break; case R_PPC64_TOC16_DS: - /* Subtact TOC pointer */ + /* Subtract TOC pointer */ value -= my_r2(sechdrs, me); if ((value & 3) != 0 || value + 0x8000 > 0xffff) { printk("%s: bad TOC16_DS relocation (%lu)\n", diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 7e4d54821a0..078fb553354 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -636,10 +636,96 @@ static void __init early_cmdline_parse(void) #ifdef CONFIG_PPC_PSERIES /* - * To tell the firmware what our capabilities are, we have to pass - * it a fake 32-bit ELF header containing a couple of PT_NOTE sections - * that contain structures that contain the actual values. + * There are two methods for telling firmware what our capabilities are. + * Newer machines have an "ibm,client-architecture-support" method on the + * root node. For older machines, we have to call the "process-elf-header" + * method in the /packages/elf-loader node, passing it a fake 32-bit + * ELF header containing a couple of PT_NOTE sections that contain + * structures that contain various information. */ + +/* + * New method - extensible architecture description vector. + * + * Because the description vector contains a mix of byte and word + * values, we declare it as an unsigned char array, and use this + * macro to put word values in. + */ +#define W(x) ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \ + ((x) >> 8) & 0xff, (x) & 0xff + +/* Option vector bits - generic bits in byte 1 */ +#define OV_IGNORE 0x80 /* ignore this vector */ +#define OV_CESSATION_POLICY 0x40 /* halt if unsupported option present*/ + +/* Option vector 1: processor architectures supported */ +#define OV1_PPC_2_00 0x80 /* set if we support PowerPC 2.00 */ +#define OV1_PPC_2_01 0x40 /* set if we support PowerPC 2.01 */ +#define OV1_PPC_2_02 0x20 /* set if we support PowerPC 2.02 */ +#define OV1_PPC_2_03 0x10 /* set if we support PowerPC 2.03 */ +#define OV1_PPC_2_04 0x08 /* set if we support PowerPC 2.04 */ +#define OV1_PPC_2_05 0x04 /* set if we support PowerPC 2.05 */ + +/* Option vector 2: Open Firmware options supported */ +#define OV2_REAL_MODE 0x20 /* set if we want OF in real mode */ + +/* Option vector 3: processor options supported */ +#define OV3_FP 0x80 /* floating point */ +#define OV3_VMX 0x40 /* VMX/Altivec */ + +/* Option vector 5: PAPR/OF options supported */ +#define OV5_LPAR 0x80 /* logical partitioning supported */ +#define OV5_SPLPAR 0x40 /* shared-processor LPAR supported */ +/* ibm,dynamic-reconfiguration-memory property supported */ +#define OV5_DRCONF_MEMORY 0x20 +#define OV5_LARGE_PAGES 0x10 /* large pages supported */ + +/* + * The architecture vector has an array of PVR mask/value pairs, + * followed by # option vectors - 1, followed by the option vectors. + */ +static unsigned char ibm_architecture_vec[] = { + W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ + W(0xffff0000), W(0x003e0000), /* POWER6 */ + W(0xfffffffe), W(0x0f000001), /* all 2.04-compliant and earlier */ + 5 - 1, /* 5 option vectors */ + + /* option vector 1: processor architectures supported */ + 3 - 1, /* length */ + 0, /* don't ignore, don't halt */ + OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 | + OV1_PPC_2_04 | OV1_PPC_2_05, + + /* option vector 2: Open Firmware options supported */ + 34 - 1, /* length */ + OV2_REAL_MODE, + 0, 0, + W(0xffffffff), /* real_base */ + W(0xffffffff), /* real_size */ + W(0xffffffff), /* virt_base */ + W(0xffffffff), /* virt_size */ + W(0xffffffff), /* load_base */ + W(64), /* 128MB min RMA */ + W(0xffffffff), /* full client load */ + 0, /* min RMA percentage of total RAM */ + 48, /* max log_2(hash table size) */ + + /* option vector 3: processor options supported */ + 3 - 1, /* length */ + 0, /* don't ignore, don't halt */ + OV3_FP | OV3_VMX, + + /* option vector 4: IBM PAPR implementation */ + 2 - 1, /* length */ + 0, /* don't halt */ + + /* option vector 5: PAPR/OF options */ + 3 - 1, /* length */ + 0, /* don't ignore, don't halt */ + OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES, +}; + +/* Old method - ELF header with PT_NOTE sections */ static struct fake_elf { Elf32_Ehdr elfhdr; Elf32_Phdr phdr[2]; @@ -728,8 +814,26 @@ static struct fake_elf { static void __init prom_send_capabilities(void) { - ihandle elfloader; + ihandle elfloader, root; + prom_arg_t ret; + + root = call_prom("open", 1, 1, ADDR("/")); + if (root != 0) { + /* try calling the ibm,client-architecture-support method */ + if (call_prom_ret("call-method", 3, 2, &ret, + ADDR("ibm,client-architecture-support"), + ADDR(ibm_architecture_vec)) == 0) { + /* the call exists... */ + if (ret) + prom_printf("WARNING: ibm,client-architecture" + "-support call FAILED!\n"); + call_prom("close", 1, 0, root); + return; + } + call_prom("close", 1, 0, root); + } + /* no ibm,client-architecture-support call, try the old way */ elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); if (elfloader == 0) { prom_printf("couldn't open /packages/elf-loader\n"); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 1d93e73a700..684ab1d49c6 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -516,3 +516,11 @@ void probe_machine(void) printk(KERN_INFO "Using %s machine description\n", ppc_md.name); } + +int check_legacy_ioport(unsigned long base_port) +{ + if (ppc_md.check_legacy_ioport == NULL) + return 0; + return ppc_md.check_legacy_ioport(base_port); +} +EXPORT_SYMBOL(check_legacy_ioport); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 13e91c4d70a..4467c49903b 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -594,14 +594,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) printk("[terminate]%04x %s\n", src, msg); } -int check_legacy_ioport(unsigned long base_port) -{ - if (ppc_md.check_legacy_ioport == NULL) - return 0; - return ppc_md.check_legacy_ioport(base_port); -} -EXPORT_SYMBOL(check_legacy_ioport); - void cpu_die(void) { if (ppc_md.cpu_die) diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 0b98eea73c5..cf56a1d499f 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -325,6 +325,19 @@ SYSCALL(unshare) SYSCALL(splice) SYSCALL(tee) SYSCALL(vmsplice) +COMPAT_SYS(openat) +SYSCALL(mkdirat) +SYSCALL(mknodat) +SYSCALL(fchownat) +COMPAT_SYS(futimesat) +SYSX(sys_newfstatat, sys_fstatat64, sys_fstatat64) +SYSCALL(unlinkat) +SYSCALL(renameat) +SYSCALL(linkat) +SYSCALL(symlinkat) +SYSCALL(readlinkat) +SYSCALL(fchmodat) +SYSCALL(faccessat) /* * please add new calls to arch/powerpc/platforms/cell/spu_callbacks.c diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 7370f9f33e2..266b8b2ceac 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -30,13 +30,66 @@ #define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT) #define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT) +#ifdef CONFIG_PPC_64K_PAGES +#define HUGEPTE_INDEX_SIZE (PMD_SHIFT-HPAGE_SHIFT) +#else +#define HUGEPTE_INDEX_SIZE (PUD_SHIFT-HPAGE_SHIFT) +#endif +#define PTRS_PER_HUGEPTE (1 << HUGEPTE_INDEX_SIZE) +#define HUGEPTE_TABLE_SIZE (sizeof(pte_t) << HUGEPTE_INDEX_SIZE) + +#define HUGEPD_SHIFT (HPAGE_SHIFT + HUGEPTE_INDEX_SIZE) +#define HUGEPD_SIZE (1UL << HUGEPD_SHIFT) +#define HUGEPD_MASK (~(HUGEPD_SIZE-1)) + +#define huge_pgtable_cache (pgtable_cache[HUGEPTE_CACHE_NUM]) + +/* Flag to mark huge PD pointers. This means pmd_bad() and pud_bad() + * will choke on pointers to hugepte tables, which is handy for + * catching screwups early. */ +#define HUGEPD_OK 0x1 + +typedef struct { unsigned long pd; } hugepd_t; + +#define hugepd_none(hpd) ((hpd).pd == 0) + +static inline pte_t *hugepd_page(hugepd_t hpd) +{ + BUG_ON(!(hpd.pd & HUGEPD_OK)); + return (pte_t *)(hpd.pd & ~HUGEPD_OK); +} + +static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr) +{ + unsigned long idx = ((addr >> HPAGE_SHIFT) & (PTRS_PER_HUGEPTE-1)); + pte_t *dir = hugepd_page(*hpdp); + + return dir + idx; +} + +static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, + unsigned long address) +{ + pte_t *new = kmem_cache_alloc(huge_pgtable_cache, + GFP_KERNEL|__GFP_REPEAT); + + if (! new) + return -ENOMEM; + + spin_lock(&mm->page_table_lock); + if (!hugepd_none(*hpdp)) + kmem_cache_free(huge_pgtable_cache, new); + else + hpdp->pd = (unsigned long)new | HUGEPD_OK; + spin_unlock(&mm->page_table_lock); + return 0; +} + /* Modelled after find_linux_pte() */ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) { pgd_t *pg; pud_t *pu; - pmd_t *pm; - pte_t *pt; BUG_ON(! in_hugepage_area(mm->context, addr)); @@ -46,26 +99,14 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) if (!pgd_none(*pg)) { pu = pud_offset(pg, addr); if (!pud_none(*pu)) { - pm = pmd_offset(pu, addr); #ifdef CONFIG_PPC_64K_PAGES - /* Currently, we use the normal PTE offset within full - * size PTE pages, thus our huge PTEs are scattered in - * the PTE page and we do waste some. We may change - * that in the future, but the current mecanism keeps - * things much simpler - */ - if (!pmd_none(*pm)) { - /* Note: pte_offset_* are all equivalent on - * ppc64 as we don't have HIGHMEM - */ - pt = pte_offset_kernel(pm, addr); - return pt; - } -#else /* CONFIG_PPC_64K_PAGES */ - /* On 4k pages, we put huge PTEs in the PMD page */ - pt = (pte_t *)pm; - return pt; -#endif /* CONFIG_PPC_64K_PAGES */ + pmd_t *pm; + pm = pmd_offset(pu, addr); + if (!pmd_none(*pm)) + return hugepte_offset((hugepd_t *)pm, addr); +#else + return hugepte_offset((hugepd_t *)pu, addr); +#endif } } @@ -76,8 +117,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) { pgd_t *pg; pud_t *pu; - pmd_t *pm; - pte_t *pt; + hugepd_t *hpdp = NULL; BUG_ON(! in_hugepage_area(mm->context, addr)); @@ -87,23 +127,182 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) pu = pud_alloc(mm, pg, addr); if (pu) { +#ifdef CONFIG_PPC_64K_PAGES + pmd_t *pm; pm = pmd_alloc(mm, pu, addr); - if (pm) { + if (pm) + hpdp = (hugepd_t *)pm; +#else + hpdp = (hugepd_t *)pu; +#endif + } + + if (! hpdp) + return NULL; + + if (hugepd_none(*hpdp) && __hugepte_alloc(mm, hpdp, addr)) + return NULL; + + return hugepte_offset(hpdp, addr); +} + +static void free_hugepte_range(struct mmu_gather *tlb, hugepd_t *hpdp) +{ + pte_t *hugepte = hugepd_page(*hpdp); + + hpdp->pd = 0; + tlb->need_flush = 1; + pgtable_free_tlb(tlb, pgtable_free_cache(hugepte, HUGEPTE_CACHE_NUM, + HUGEPTE_TABLE_SIZE-1)); +} + #ifdef CONFIG_PPC_64K_PAGES - /* See comment in huge_pte_offset. Note that if we ever - * want to put the page size in the PMD, we would have - * to open code our own pte_alloc* function in order - * to populate and set the size atomically - */ - pt = pte_alloc_map(mm, pm, addr); -#else /* CONFIG_PPC_64K_PAGES */ - pt = (pte_t *)pm; -#endif /* CONFIG_PPC_64K_PAGES */ - return pt; - } +static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud, + unsigned long addr, unsigned long end, + unsigned long floor, unsigned long ceiling) +{ + pmd_t *pmd; + unsigned long next; + unsigned long start; + + start = addr; + pmd = pmd_offset(pud, addr); + do { + next = pmd_addr_end(addr, end); + if (pmd_none(*pmd)) + continue; + free_hugepte_range(tlb, (hugepd_t *)pmd); + } while (pmd++, addr = next, addr != end); + + start &= PUD_MASK; + if (start < floor) + return; + if (ceiling) { + ceiling &= PUD_MASK; + if (!ceiling) + return; } + if (end - 1 > ceiling - 1) + return; - return NULL; + pmd = pmd_offset(pud, start); + pud_clear(pud); + pmd_free_tlb(tlb, pmd); +} +#endif + +static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd, + unsigned long addr, unsigned long end, + unsigned long floor, unsigned long ceiling) +{ + pud_t *pud; + unsigned long next; + unsigned long start; + + start = addr; + pud = pud_offset(pgd, addr); + do { + next = pud_addr_end(addr, end); +#ifdef CONFIG_PPC_64K_PAGES + if (pud_none_or_clear_bad(pud)) + continue; + hugetlb_free_pmd_range(tlb, pud, addr, next, floor, ceiling); +#else + if (pud_none(*pud)) + continue; + free_hugepte_range(tlb, (hugepd_t *)pud); +#endif + } while (pud++, addr = next, addr != end); + + start &= PGDIR_MASK; + if (start < floor) + return; + if (ceiling) { + ceiling &= PGDIR_MASK; + if (!ceiling) + return; + } + if (end - 1 > ceiling - 1) + return; + + pud = pud_offset(pgd, start); + pgd_clear(pgd); + pud_free_tlb(tlb, pud); +} + +/* + * This function frees user-level page tables of a process. + * + * Must be called with pagetable lock held. + */ +void hugetlb_free_pgd_range(struct mmu_gather **tlb, + unsigned long addr, unsigned long end, + unsigned long floor, unsigned long ceiling) +{ + pgd_t *pgd; + unsigned long next; + unsigned long start; + + /* + * Comments below take from the normal free_pgd_range(). They + * apply here too. The tests against HUGEPD_MASK below are + * essential, because we *don't* test for this at the bottom + * level. Without them we'll attempt to free a hugepte table + * when we unmap just part of it, even if there are other + * active mappings using it. + * + * The next few lines have given us lots of grief... + * + * Why are we testing HUGEPD* at this top level? Because + * often there will be no work to do at all, and we'd prefer + * not to go all the way down to the bottom just to discover + * that. + * + * Why all these "- 1"s? Because 0 represents both the bottom + * of the address space and the top of it (using -1 for the + * top wouldn't help much: the masks would do the wrong thing). + * The rule is that addr 0 and floor 0 refer to the bottom of + * the address space, but end 0 and ceiling 0 refer to the top + * Comparisons need to use "end - 1" and "ceiling - 1" (though + * that end 0 case should be mythical). + * + * Wherever addr is brought up or ceiling brought down, we + * must be careful to reject "the opposite 0" before it + * confuses the subsequent tests. But what about where end is + * brought down by HUGEPD_SIZE below? no, end can't go down to + * 0 there. + * + * Whereas we round start (addr) and ceiling down, by different + * masks at different levels, in order to test whether a table + * now has no other vmas using it, so can be freed, we don't + * bother to round floor or end up - the tests don't need that. + */ + + addr &= HUGEPD_MASK; + if (addr < floor) { + addr += HUGEPD_SIZE; + if (!addr) + return; + } + if (ceiling) { + ceiling &= HUGEPD_MASK; + if (!ceiling) + return; + } + if (end - 1 > ceiling - 1) + end -= HUGEPD_SIZE; + if (addr > end - 1) + return; + + start = addr; + pgd = pgd_offset((*tlb)->mm, addr); + do { + BUG_ON(! in_hugepage_area((*tlb)->mm->context, addr)); + next = pgd_addr_end(addr, end); + if (pgd_none_or_clear_bad(pgd)) + continue; + hugetlb_free_pud_range(*tlb, pgd, addr, next, floor, ceiling); + } while (pgd++, addr = next, addr != end); } void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, @@ -841,3 +1040,27 @@ repeat: out: return err; } + +static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) +{ + memset(addr, 0, kmem_cache_size(cache)); +} + +static int __init hugetlbpage_init(void) +{ + if (!cpu_has_feature(CPU_FTR_16M_PAGE)) + return -ENODEV; + + huge_pgtable_cache = kmem_cache_create("hugepte_cache", + HUGEPTE_TABLE_SIZE, + HUGEPTE_TABLE_SIZE, + SLAB_HWCACHE_ALIGN | + SLAB_MUST_HWCACHE_ALIGN, + zero_ctor, NULL); + if (! huge_pgtable_cache) + panic("hugetlbpage_init(): could not create hugepte cache\n"); + + return 0; +} + +module_init(hugetlbpage_init); diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index babebd15bdc..9e30f968c18 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -162,7 +162,14 @@ static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { }; #endif /* CONFIG_PPC_64K_PAGES */ +#ifdef CONFIG_HUGETLB_PAGE +/* Hugepages need one extra cache, initialized in hugetlbpage.c. We + * can't put into the tables above, because HPAGE_SHIFT is not compile + * time constant. */ +kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)+1]; +#else kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)]; +#endif void pgtable_cache_init(void) { diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 269dda4fd0b..ef47a6239d4 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -306,19 +306,19 @@ spu_request_irqs(struct spu *spu) snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number); ret = request_irq(irq_base + spu->isrc, - spu_irq_class_0, 0, spu->irq_c0, spu); + spu_irq_class_0, SA_INTERRUPT, spu->irq_c0, spu); if (ret) goto out; snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number); ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, - spu_irq_class_1, 0, spu->irq_c1, spu); + spu_irq_class_1, SA_INTERRUPT, spu->irq_c1, spu); if (ret) goto out1; snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number); ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, - spu_irq_class_2, 0, spu->irq_c2, spu); + spu_irq_class_2, SA_INTERRUPT, spu->irq_c2, spu); if (ret) goto out2; goto out; @@ -487,10 +487,14 @@ int spu_irq_class_1_bottom(struct spu *spu) ea = spu->dar; dsisr = spu->dsisr; if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) { + u64 flags; + access = (_PAGE_PRESENT | _PAGE_USER); access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; + local_irq_save(flags); if (hash_page(ea, access, 0x300) != 0) error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; + local_irq_restore(flags); } if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) { if ((ret = spu_handle_mm_fault(spu)) != 0) diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c index b283380a2a1..95b36430aa0 100644 --- a/arch/powerpc/platforms/cell/spu_callbacks.c +++ b/arch/powerpc/platforms/cell/spu_callbacks.c @@ -319,6 +319,19 @@ void *spu_syscall_table[] = { [__NR_splice] sys_splice, [__NR_tee] sys_tee, [__NR_vmsplice] sys_vmsplice, + [__NR_openat] sys_openat, + [__NR_mkdirat] sys_mkdirat, + [__NR_mknodat] sys_mknodat, + [__NR_fchownat] sys_fchownat, + [__NR_futimesat] sys_futimesat, + [__NR_newfstatat] sys_newfstatat, + [__NR_unlinkat] sys_unlinkat, + [__NR_renameat] sys_renameat, + [__NR_linkat] sys_linkat, + [__NR_symlinkat] sys_symlinkat, + [__NR_readlinkat] sys_readlinkat, + [__NR_fchmodat] sys_fchmodat, + [__NR_faccessat] sys_faccessat, }; long spu_sys_callback(struct spu_syscall_block *s) diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c index f841972f1fa..554776d4b8a 100644 --- a/arch/ppc/platforms/4xx/ocotea.c +++ b/arch/ppc/platforms/4xx/ocotea.c @@ -331,7 +331,7 @@ static void __init ocotea_init(void) void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - ibm44x_platform_init(r3, r4, r5, r6, r7); + ibm440gx_platform_init(r3, r4, r5, r6, r7); ppc_md.setup_arch = ocotea_setup_arch; ppc_md.show_cpuinfo = ocotea_show_cpuinfo; diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c index bc9b94f77e3..e62b75707f7 100644 --- a/arch/ppc/platforms/mpc8272ads_setup.c +++ b/arch/ppc/platforms/mpc8272ads_setup.c @@ -26,11 +26,35 @@ #include <asm/irq.h> #include <asm/ppc_sys.h> #include <asm/ppcboot.h> +#include <linux/fs_uart_pd.h> #include "pq2ads_pd.h" static void init_fcc1_ioports(void); static void init_fcc2_ioports(void); +static void init_scc1_uart_ioports(void); +static void init_scc4_uart_ioports(void); + +static struct fs_uart_platform_info mpc8272_uart_pdata[] = { + [fsid_scc1_uart] = { + .init_ioports = init_scc1_uart_ioports, + .fs_no = fsid_scc1_uart, + .brg = 1, + .tx_num_fifo = 4, + .tx_buf_size = 32, + .rx_num_fifo = 4, + .rx_buf_size = 32, + }, + [fsid_scc4_uart] = { + .init_ioports = init_scc4_uart_ioports, + .fs_no = fsid_scc4_uart, + .brg = 4, + .tx_num_fifo = 4, + .tx_buf_size = 32, + .rx_num_fifo = 4, + .rx_buf_size = 32, + }, +}; static struct fs_mii_bus_info mii_bus_info = { .method = fsmii_bitbang, @@ -201,6 +225,55 @@ static void __init mpc8272ads_fixup_enet_pdata(struct platform_device *pdev, } } +static void mpc8272ads_fixup_uart_pdata(struct platform_device *pdev, + int idx) +{ + bd_t *bd = (bd_t *) __res; + struct fs_uart_platform_info *pinfo; + int num = ARRAY_SIZE(mpc8272_uart_pdata); + int id = fs_uart_id_scc2fsid(idx); + + /* no need to alter anything if console */ + if ((id <= num) && (!pdev->dev.platform_data)) { + pinfo = &mpc8272_uart_pdata[id]; + pinfo->uart_clk = bd->bi_intfreq; + pdev->dev.platform_data = pinfo; + } +} + +static void init_scc1_uart_ioports(void) +{ + cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t)); + + /* SCC1 is only on port D */ + setbits32(&immap->im_ioport.iop_ppard,0x00000003); + clrbits32(&immap->im_ioport.iop_psord,0x00000001); + setbits32(&immap->im_ioport.iop_psord,0x00000002); + clrbits32(&immap->im_ioport.iop_pdird,0x00000001); + setbits32(&immap->im_ioport.iop_pdird,0x00000002); + + /* Wire BRG1 to SCC1 */ + clrbits32(&immap->im_cpmux.cmx_scr,0x00ffffff); + + iounmap(immap); +} + +static void init_scc4_uart_ioports(void) +{ + cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t)); + + setbits32(&immap->im_ioport.iop_ppard,0x00000600); + clrbits32(&immap->im_ioport.iop_psord,0x00000600); + clrbits32(&immap->im_ioport.iop_pdird,0x00000200); + setbits32(&immap->im_ioport.iop_pdird,0x00000400); + + /* Wire BRG4 to SCC4 */ + clrbits32(&immap->im_cpmux.cmx_scr,0x000000ff); + setbits32(&immap->im_cpmux.cmx_scr,0x0000001b); + + iounmap(immap); +} + static int mpc8272ads_platform_notify(struct device *dev) { static const struct platform_notify_dev_map dev_map[] = { @@ -209,6 +282,10 @@ static int mpc8272ads_platform_notify(struct device *dev) .rtn = mpc8272ads_fixup_enet_pdata }, { + .bus_id = "fsl-cpm-scc:uart", + .rtn = mpc + }, + { .bus_id = NULL } }; @@ -230,7 +307,44 @@ int __init mpc8272ads_init(void) ppc_sys_device_enable(MPC82xx_CPM_FCC1); ppc_sys_device_enable(MPC82xx_CPM_FCC2); + /* to be ready for console, let's attach pdata here */ +#ifdef CONFIG_SERIAL_CPM_SCC1 + ppc_sys_device_setfunc(MPC82xx_CPM_SCC1, PPC_SYS_FUNC_UART); + ppc_sys_device_enable(MPC82xx_CPM_SCC1); + +#endif + +#ifdef CONFIG_SERIAL_CPM_SCC4 + ppc_sys_device_setfunc(MPC82xx_CPM_SCC4, PPC_SYS_FUNC_UART); + ppc_sys_device_enable(MPC82xx_CPM_SCC4); +#endif + + return 0; } +/* + To prevent confusion, console selection is gross: + by 0 assumed SCC1 and by 1 assumed SCC4 + */ +struct platform_device* early_uart_get_pdev(int index) +{ + bd_t *bd = (bd_t *) __res; + struct fs_uart_platform_info *pinfo; + + struct platform_device* pdev = NULL; + if(index) { /*assume SCC4 here*/ + pdev = &ppc_sys_platform_devices[MPC82xx_CPM_SCC4]; + pinfo = &mpc8272<F12>_uart_pdata[1]; + } else { /*over SCC1*/ + pdev = &ppc_sys_platform_devices[MPC82xx_CPM_SCC1]; + pinfo = &mpc8272_uart_pdata[0]; + } + + pinfo->uart_clk = bd->bi_intfreq; + pdev->dev.platform_data = pinfo; + ppc_sys_fixup_mem_resource(pdev, IMAP_ADDR); + return NULL; +} + arch_initcall(mpc8272ads_init); diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c index ac8fcc68afe..6ce3b842def 100644 --- a/arch/ppc/platforms/mpc866ads_setup.c +++ b/arch/ppc/platforms/mpc866ads_setup.c @@ -20,6 +20,7 @@ #include <linux/device.h> #include <linux/fs_enet_pd.h> +#include <linux/fs_uart_pd.h> #include <linux/mii.h> #include <asm/delay.h> @@ -37,6 +38,11 @@ extern unsigned char __res[]; +static void setup_fec1_ioports(void); +static void setup_scc1_ioports(void); +static void setup_smc1_ioports(void); +static void setup_smc2_ioports(void); + static struct fs_mii_bus_info fec_mii_bus_info = { .method = fsmii_fec, .id = 0, @@ -79,6 +85,28 @@ static struct fs_platform_info mpc8xx_scc_pdata = { .phy_irq = -1, .bus_info = &scc_mii_bus_info, + +}; + +static struct fs_uart_platform_info mpc866_uart_pdata[] = { + [fsid_smc1_uart] = { + .brg = 1, + .fs_no = fsid_smc1_uart, + .init_ioports = setup_smc1_ioports, + .tx_num_fifo = 4, + .tx_buf_size = 32, + .rx_num_fifo = 4, + .rx_buf_size = 32, + }, + [fsid_smc2_uart] = { + .brg = 2, + .fs_no = fsid_smc2_uart, + .init_ioports = setup_smc2_ioports, + .tx_num_fifo = 4, + .tx_buf_size = 32, + .rx_num_fifo = 4, + .rx_buf_size = 32, + }, }; void __init board_init(void) @@ -92,9 +120,12 @@ void __init board_init(void) printk(KERN_CRIT "Could not remap BCSR1\n"); return; } + #ifdef CONFIG_SERIAL_CPM_SMC1 cp->cp_simode &= ~(0xe0000000 >> 17); /* brg1 */ clrbits32(bcsr_io,(0x80000000 >> 7)); + cp->cp_smc[0].smc_smcm |= (SMCM_RX | SMCM_TX); + cp->cp_smc[0].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); #else setbits32(bcsr_io,(0x80000000 >> 7)); @@ -108,6 +139,8 @@ void __init board_init(void) cp->cp_simode &= ~(0xe0000000 >> 1); cp->cp_simode |= (0x20000000 >> 1); /* brg2 */ clrbits32(bcsr_io,(0x80000000 >> 13)); + cp->cp_smc[1].smc_smcm |= (SMCM_RX | SMCM_TX); + cp->cp_smc[1].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); #else clrbits32(bcsr_io,(0x80000000 >> 13)); cp->cp_pbpar &= ~(0x00000c00); @@ -232,6 +265,74 @@ static void mpc866ads_fixup_scc_enet_pdata(struct platform_device *pdev, mpc866ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1); } +static void setup_smc1_ioports(void) +{ + immap_t *immap = (immap_t *) IMAP_ADDR; + unsigned *bcsr_io; + unsigned int iobits = 0x000000c0; + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR1\n"); + return; + } + + clrbits32(bcsr_io,BCSR1_RS232EN_1); + iounmap(bcsr_io); + + setbits32(&immap->im_cpm.cp_pbpar, iobits); + clrbits32(&immap->im_cpm.cp_pbdir, iobits); + clrbits16(&immap->im_cpm.cp_pbodr, iobits); + +} + +static void setup_smc2_ioports(void) +{ + immap_t *immap = (immap_t *) IMAP_ADDR; + unsigned *bcsr_io; + unsigned int iobits = 0x00000c00; + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR1\n"); + return; + } + + clrbits32(bcsr_io,BCSR1_RS232EN_2); + + iounmap(bcsr_io); + +#ifndef CONFIG_SERIAL_CPM_ALT_SMC2 + setbits32(&immap->im_cpm.cp_pbpar, iobits); + clrbits32(&immap->im_cpm.cp_pbdir, iobits); + clrbits16(&immap->im_cpm.cp_pbodr, iobits); +#else + setbits16(&immap->im_ioport.iop_papar, iobits); + clrbits16(&immap->im_ioport.iop_padir, iobits); + clrbits16(&immap->im_ioport.iop_paodr, iobits); +#endif + +} + +static void __init mpc866ads_fixup_uart_pdata(struct platform_device *pdev, + int idx) +{ + bd_t *bd = (bd_t *) __res; + struct fs_uart_platform_info *pinfo; + int num = ARRAY_SIZE(mpc866_uart_pdata); + + int id = fs_uart_id_smc2fsid(idx); + + /* no need to alter anything if console */ + if ((id <= num) && (!pdev->dev.platform_data)) { + pinfo = &mpc866_uart_pdata[id]; + pinfo->uart_clk = bd->bi_intfreq; + pdev->dev.platform_data = pinfo; + } +} + static int mpc866ads_platform_notify(struct device *dev) { static const struct platform_notify_dev_map dev_map[] = { @@ -244,6 +345,10 @@ static int mpc866ads_platform_notify(struct device *dev) .rtn = mpc866ads_fixup_scc_enet_pdata, }, { + .bus_id = "fsl-cpm-smc:uart", + .rtn = mpc866ads_fixup_uart_pdata + }, + { .bus_id = NULL } }; @@ -267,7 +372,42 @@ int __init mpc866ads_init(void) #endif ppc_sys_device_enable(MPC8xx_CPM_FEC1); +/* Since either of the uarts could be used as console, they need to ready */ +#ifdef CONFIG_SERIAL_CPM_SMC1 + ppc_sys_device_enable(MPC8xx_CPM_SMC1); + ppc_sys_device_setfunc(MPC8xx_CPM_SMC1, PPC_SYS_FUNC_UART); +#endif + +#ifdef CONFIG_SERIAL_CPM_SMCer + ppc_sys_device_enable(MPC8xx_CPM_SMC2); + ppc_sys_device_setfunc(MPC8xx_CPM_SMC2, PPC_SYS_FUNC_UART); +#endif + return 0; } +/* + To prevent confusion, console selection is gross: + by 0 assumed SMC1 and by 1 assumed SMC2 + */ +struct platform_device* early_uart_get_pdev(int index) +{ + bd_t *bd = (bd_t *) __res; + struct fs_uart_platform_info *pinfo; + + struct platform_device* pdev = NULL; + if(index) { /*assume SMC2 here*/ + pdev = &ppc_sys_platform_devices[MPC8xx_CPM_SMC2]; + pinfo = &mpc866_uart_pdata[1]; + } else { /*over SMC1*/ + pdev = &ppc_sys_platform_devices[MPC8xx_CPM_SMC1]; + pinfo = &mpc866_uart_pdata[0]; + } + + pinfo->uart_clk = bd->bi_intfreq; + pdev->dev.platform_data = pinfo; + ppc_sys_fixup_mem_resource(pdev, IMAP_ADDR); + return NULL; +} + arch_initcall(mpc866ads_init); diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c index 50a99e5f7c6..4b88679cd31 100644 --- a/arch/ppc/platforms/mpc885ads_setup.c +++ b/arch/ppc/platforms/mpc885ads_setup.c @@ -20,6 +20,7 @@ #include <linux/device.h> #include <linux/fs_enet_pd.h> +#include <linux/fs_uart_pd.h> #include <linux/mii.h> #include <asm/delay.h> @@ -35,9 +36,32 @@ #include <asm/ppc_sys.h> extern unsigned char __res[]; +static void setup_smc1_ioports(void); +static void setup_smc2_ioports(void); static void __init mpc885ads_scc_phy_init(char); +static struct fs_uart_platform_info mpc885_uart_pdata[] = { + [fsid_smc1_uart] = { + .brg = 1, + .fs_no = fsid_smc1_uart, + .init_ioports = setup_smc1_ioports, + .tx_num_fifo = 4, + .tx_buf_size = 32, + .rx_num_fifo = 4, + .rx_buf_size = 32, + }, + [fsid_smc2_uart] = { + .brg = 2, + .fs_no = fsid_smc2_uart, + .init_ioports = setup_smc2_ioports, + .tx_num_fifo = 4, + .tx_buf_size = 32, + .rx_num_fifo = 4, + .rx_buf_size = 32, + }, +}; + static struct fs_mii_bus_info fec_mii_bus_info = { .method = fsmii_fec, .id = 0, @@ -116,6 +140,8 @@ void __init board_init(void) #ifdef CONFIG_SERIAL_CPM_SMC1 cp->cp_simode &= ~(0xe0000000 >> 17); /* brg1 */ clrbits32(bcsr_io, BCSR1_RS232EN_1); + cp->cp_smc[0].smc_smcm |= (SMCM_RX | SMCM_TX); + cp->cp_smc[0].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); #else setbits32(bcsr_io,BCSR1_RS232EN_1); cp->cp_smc[0].smc_smcmr = 0; @@ -126,6 +152,8 @@ void __init board_init(void) cp->cp_simode &= ~(0xe0000000 >> 1); cp->cp_simode |= (0x20000000 >> 1); /* brg2 */ clrbits32(bcsr_io,BCSR1_RS232EN_2); + cp->cp_smc[1].smc_smcm |= (SMCM_RX | SMCM_TX); + cp->cp_smc[1].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); #else setbits32(bcsr_io,BCSR1_RS232EN_2); cp->cp_smc[1].smc_smcmr = 0; @@ -343,6 +371,70 @@ static void mpc885ads_scc_phy_init(char phy_addr) out_be32(&fecp->fec_mii_speed, 0); } +static void setup_smc1_ioports(void) +{ + immap_t *immap = (immap_t *) IMAP_ADDR; + unsigned *bcsr_io; + unsigned int iobits = 0x000000c0; + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR1\n"); + return; + } + clrbits32(bcsr_io,BCSR1_RS232EN_1); + iounmap(bcsr_io); + + setbits32(&immap->im_cpm.cp_pbpar, iobits); + clrbits32(&immap->im_cpm.cp_pbdir, iobits); + clrbits16(&immap->im_cpm.cp_pbodr, iobits); +} + +static void setup_smc2_ioports(void) +{ + immap_t *immap = (immap_t *) IMAP_ADDR; + unsigned *bcsr_io; + unsigned int iobits = 0x00000c00; + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR1\n"); + return; + } + clrbits32(bcsr_io,BCSR1_RS232EN_2); + iounmap(bcsr_io); + +#ifndef CONFIG_SERIAL_CPM_ALT_SMC2 + setbits32(&immap->im_cpm.cp_pbpar, iobits); + clrbits32(&immap->im_cpm.cp_pbdir, iobits); + clrbits16(&immap->im_cpm.cp_pbodr, iobits); +#else + setbits16(&immap->im_ioport.iop_papar, iobits); + clrbits16(&immap->im_ioport.iop_padir, iobits); + clrbits16(&immap->im_ioport.iop_paodr, iobits); +#endif +} + +static void __init mpc885ads_fixup_uart_pdata(struct platform_device *pdev, + int idx) +{ + bd_t *bd = (bd_t *) __res; + struct fs_uart_platform_info *pinfo; + int num = ARRAY_SIZE(mpc885_uart_pdata); + + int id = fs_uart_id_smc2fsid(idx); + + /* no need to alter anything if console */ + if ((id <= num) && (!pdev->dev.platform_data)) { + pinfo = &mpc885_uart_pdata[id]; + pinfo->uart_clk = bd->bi_intfreq; + pdev->dev.platform_data = pinfo; + } +} + + static int mpc885ads_platform_notify(struct device *dev) { @@ -356,12 +448,17 @@ static int mpc885ads_platform_notify(struct device *dev) .rtn = mpc885ads_fixup_scc_enet_pdata, }, { + .bus_id = "fsl-cpm-smc:uart", + .rtn = mpc885ads_fixup_uart_pdata + }, + { .bus_id = NULL } }; platform_notify_map(dev_map,dev); + return 0; } int __init mpc885ads_init(void) @@ -383,7 +480,41 @@ int __init mpc885ads_init(void) ppc_sys_device_enable(MPC8xx_CPM_FEC2); #endif +#ifdef CONFIG_SERIAL_CPM_SMC1 + ppc_sys_device_enable(MPC8xx_CPM_SMC1); + ppc_sys_device_setfunc(MPC8xx_CPM_SMC1, PPC_SYS_FUNC_UART); +#endif + +#ifdef CONFIG_SERIAL_CPM_SMC2 + ppc_sys_device_enable(MPC8xx_CPM_SMC2); + ppc_sys_device_setfunc(MPC8xx_CPM_SMC2, PPC_SYS_FUNC_UART); +#endif return 0; } arch_initcall(mpc885ads_init); + +/* + To prevent confusion, console selection is gross: + by 0 assumed SMC1 and by 1 assumed SMC2 + */ +struct platform_device* early_uart_get_pdev(int index) +{ + bd_t *bd = (bd_t *) __res; + struct fs_uart_platform_info *pinfo; + + struct platform_device* pdev = NULL; + if(index) { /*assume SMC2 here*/ + pdev = &ppc_sys_platform_devices[MPC8xx_CPM_SMC2]; + pinfo = &mpc885_uart_pdata[1]; + } else { /*over SMC1*/ + pdev = &ppc_sys_platform_devices[MPC8xx_CPM_SMC1]; + pinfo = &mpc885_uart_pdata[0]; + } + + pinfo->uart_clk = bd->bi_intfreq; + pdev->dev.platform_data = pinfo; + ppc_sys_fixup_mem_resource(pdev, IMAP_ADDR); + return NULL; +} + diff --git a/arch/ppc/platforms/pq2ads.c b/arch/ppc/platforms/pq2ads.c index 3365fd788a7..7fc2e02f524 100644 --- a/arch/ppc/platforms/pq2ads.c +++ b/arch/ppc/platforms/pq2ads.c @@ -14,11 +14,40 @@ #include <linux/init.h> +#include <asm/io.h> #include <asm/mpc8260.h> +#include <asm/cpm2.h> +#include <asm/immap_cpm2.h> void __init m82xx_board_setup(void) { + cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t)); + u32 *bcsr = ioremap(BCSR_ADDR+4, sizeof(u32)); + /* Enable the 2nd UART port */ - *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_RS232_EN2; + clrbits32(bcsr, BCSR1_RS232_EN2); + +#ifdef CONFIG_SERIAL_CPM_SCC1 + clrbits32((u32*)&immap->im_scc[0].scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32((u32*)&immap->im_scc[0].scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + +#ifdef CONFIG_SERIAL_CPM_SCC2 + clrbits32((u32*)&immap->im_scc[1].scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32((u32*)&immap->im_scc[1].scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + +#ifdef CONFIG_SERIAL_CPM_SCC3 + clrbits32((u32*)&immap->im_scc[2].scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32((u32*)&immap->im_scc[2].scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + +#ifdef CONFIG_SERIAL_CPM_SCC4 + clrbits32((u32*)&immap->im_scc[3].scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32((u32*)&immap->im_scc[3].scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + + iounmap(bcsr); + iounmap(immap); } diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c index a7dd55f1c63..f6cc1688852 100644 --- a/arch/ppc/syslib/ibm440gx_common.c +++ b/arch/ppc/syslib/ibm440gx_common.c @@ -2,7 +2,7 @@ * PPC440GX system library * * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * Copyright (c) 2003, 2004 Zultys Technologies + * Copyright (c) 2003 - 2006 Zultys Technologies * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -282,3 +282,14 @@ int ibm440gx_show_cpuinfo(struct seq_file *m){ return 0; } +void __init ibm440gx_platform_init(unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, + unsigned long r7) +{ + /* Erratum 440_43 workaround, disable L1 cache parity checking */ + if (!strcmp(cur_cpu_spec->cpu_name, "440GX Rev. C") || + !strcmp(cur_cpu_spec->cpu_name, "440GX Rev. F")) + mtspr(SPRN_CCR1, mfspr(SPRN_CCR1) | CCR1_DPC); + + ibm44x_platform_init(r3, r4, r5, r6, r7); +} diff --git a/arch/ppc/syslib/ibm440gx_common.h b/arch/ppc/syslib/ibm440gx_common.h index a2ab9fab8e3..a03ec6022e8 100644 --- a/arch/ppc/syslib/ibm440gx_common.h +++ b/arch/ppc/syslib/ibm440gx_common.h @@ -29,6 +29,10 @@ void ibm440gx_get_clocks(struct ibm44x_clocks*, unsigned int sys_clk, unsigned int ser_clk) __init; +/* common 440GX platform init */ +void ibm440gx_platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) __init; + /* Enable L2 cache */ void ibm440gx_l2c_enable(void) __init; diff --git a/arch/ppc/syslib/mpc8xx_devices.c b/arch/ppc/syslib/mpc8xx_devices.c index bd41ed83beb..6f536383866 100644 --- a/arch/ppc/syslib/mpc8xx_devices.c +++ b/arch/ppc/syslib/mpc8xx_devices.c @@ -170,12 +170,18 @@ struct platform_device ppc_sys_platform_devices[] = { [MPC8xx_CPM_SMC1] = { .name = "fsl-cpm-smc", .id = 1, - .num_resources = 2, + .num_resources = 3, .resource = (struct resource[]) { { .name = "regs", - .start = 0xa82, - .end = 0xa91, + .start = 0xa80, + .end = 0xa8f, + .flags = IORESOURCE_MEM, + }, + { + .name = "pram", + .start = 0x3e80, + .end = 0x3ebf, .flags = IORESOURCE_MEM, }, { @@ -189,15 +195,22 @@ struct platform_device ppc_sys_platform_devices[] = { [MPC8xx_CPM_SMC2] = { .name = "fsl-cpm-smc", .id = 2, - .num_resources = 2, + .num_resources = 3, .resource = (struct resource[]) { { .name = "regs", - .start = 0xa92, - .end = 0xaa1, + .start = 0xa90, + .end = 0xa9f, .flags = IORESOURCE_MEM, }, { + .name = "pram", + .start = 0x3f80, + .end = 0x3fbf, + .flags = IORESOURCE_MEM, + + }, + { .name = "interrupt", .start = MPC8xx_INT_SMC2, .end = MPC8xx_INT_SMC2, diff --git a/arch/ppc/syslib/ppc_sys.c b/arch/ppc/syslib/ppc_sys.c index 7662c4e6e7d..2d48018b71d 100644 --- a/arch/ppc/syslib/ppc_sys.c +++ b/arch/ppc/syslib/ppc_sys.c @@ -109,9 +109,11 @@ ppc_sys_fixup_mem_resource(struct platform_device *pdev, phys_addr_t paddr) int i; for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; - if ((r->flags & IORESOURCE_MEM) == IORESOURCE_MEM) { + if (((r->flags & IORESOURCE_MEM) == IORESOURCE_MEM) && + ((r->flags & PPC_SYS_IORESOURCE_FIXUPPED) != PPC_SYS_IORESOURCE_FIXUPPED)) { r->start += paddr; r->end += paddr; + r->flags |= PPC_SYS_IORESOURCE_FIXUPPED; } } } diff --git a/arch/ppc/syslib/pq2_sys.c b/arch/ppc/syslib/pq2_sys.c index 75e64f1c144..433b0fa203e 100644 --- a/arch/ppc/syslib/pq2_sys.c +++ b/arch/ppc/syslib/pq2_sys.c @@ -113,13 +113,13 @@ struct ppc_sys_spec ppc_sys_specs[] = { .ppc_sys_name = "8248", .mask = 0x0000ff00, .value = 0x00000c00, - .num_devices = 11, + .num_devices = 12, .device_list = (enum ppc_sys_devices[]) { MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1, - MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SMC1, - MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C, - MPC82xx_CPM_USB, MPC82xx_SEC1, + MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SCC4, + MPC82xx_CPM_SMC1, MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, + MPC82xx_CPM_I2C, MPC82xx_CPM_USB, MPC82xx_SEC1, }, }, { |