From c6423658c9c50f9dda5f42f33735b458fafbfc62 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 6 Feb 2005 22:37:01 -0800 Subject: [PATCH] Remove pci_dev->slot_name This is a pointer to dev.bus_id, which is properly accessed through the pci_name() function. Signed-off-by: Dave Jones Signed-off-by: Greg Kroah-Hartman --- include/linux/pci.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/linux/pci.h b/include/linux/pci.h index d0844ceb2810..930a8dfd997d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -549,8 +549,6 @@ struct pci_dev { unsigned int irq; struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ - char * slot_name; /* pointer to dev.bus_id */ - /* These fields are used by common fixups */ unsigned int transparent:1; /* Transparent PCI bridge */ unsigned int multifunction:1;/* Part of multi-function device */ -- cgit v1.2.3 From 223c286758da50d1e1b237b9078e785bb3be92b0 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Sun, 6 Feb 2005 22:38:06 -0800 Subject: [PATCH] PCI: pci_proc_domain There's no need for the architectures to know how to name busses, so replace pci_name_bus with pci_proc_domain -- a predicate to allow architectures to choose whether domains are included in /proc/bus/pci or not. I've converted all architectures but only tested ia64 and a CONFIG_PCI_DOMAINS=n build. Signed-off-by: Matthew Wilcox Signed-off-by: Greg Kroah-Hartman --- arch/ppc64/kernel/pci.c | 16 ++++++---------- arch/sparc64/kernel/pci.c | 6 ------ drivers/pci/proc.c | 20 +++++++++++++------- include/asm-alpha/pci.h | 11 ++--------- include/asm-ia64/pci.h | 9 ++------- include/asm-mips/pci.h | 11 ++--------- include/asm-ppc/pci.h | 3 +-- include/asm-ppc64/pci.h | 4 ++-- include/asm-sparc64/pci.h | 5 ++++- include/linux/pci.h | 3 +-- 10 files changed, 33 insertions(+), 55 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index f7486bee078f..c67b5c7b8456 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -300,19 +300,15 @@ int pci_domain_nr(struct pci_bus *bus) EXPORT_SYMBOL(pci_domain_nr); -/* Set the name of the bus as it appears in /proc/bus/pci */ -int pci_name_bus(char *name, struct pci_bus *bus) +/* Decide whether to display the domain number in /proc */ +int pci_proc_domain(struct pci_bus *bus) { -#ifndef CONFIG_PPC_ISERIES +#ifdef CONFIG_PPC_ISERIES + return 0; +#else struct pci_controller *hose = pci_bus_to_host(bus); - - if (hose->buid) - sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number); - else + return hose->buid; #endif - sprintf(name, "%02x", bus->number); - - return 0; } /* diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 2ffd1efefcc0..3f524d52d531 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -794,12 +794,6 @@ int pci_domain_nr(struct pci_bus *pbus) } EXPORT_SYMBOL(pci_domain_nr); -int pci_name_bus(char *name, struct pci_bus *bus) -{ - sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number); - return 0; -} - int pcibios_prep_mwi(struct pci_dev *dev) { /* We set correct PCI_CACHE_LINE_SIZE register values for every diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index da51bf96a15c..b53bb859ce91 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -384,26 +384,32 @@ static struct proc_dir_entry *proc_bus_pci_dir; int pci_proc_attach_device(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; - struct proc_dir_entry *de, *e; + struct proc_dir_entry *e; char name[16]; if (!proc_initialized) return -EACCES; - if (!(de = bus->procdir)) { - if (pci_name_bus(name, bus)) - return -EEXIST; - de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir); - if (!de) + if (!bus->procdir) { + if (pci_proc_domain(bus)) { + sprintf(name, "%04x:%02x", pci_domain_nr(bus), + bus->number); + } else { + sprintf(name, "%02x", bus->number); + } + bus->procdir = proc_mkdir(name, proc_bus_pci_dir); + if (!bus->procdir) return -ENOMEM; } + sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de); + e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir); if (!e) return -ENOMEM; e->proc_fops = &proc_bus_pci_operations; e->data = dev; e->size = dev->cfg_size; + dev->procent = e; return 0; } diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h index bbefe1238d63..88854a9dd150 100644 --- a/include/asm-alpha/pci.h +++ b/include/asm-alpha/pci.h @@ -228,17 +228,10 @@ extern void pcibios_resource_to_bus(struct pci_dev *, struct pci_bus_region *, #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index -static inline int -pci_name_bus(char *name, struct pci_bus *bus) +static inline int pci_proc_domain(struct pci_bus *bus) { struct pci_controller *hose = bus->sysdata; - - if (likely(hose->need_domain_info == 0)) { - sprintf(name, "%02x", bus->number); - } else { - sprintf(name, "%04x:%02x", hose->index, bus->number); - } - return 0; + return hose->need_domain_info; } static inline void diff --git a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h index 48e565fb5e0f..a8314ee4e7d2 100644 --- a/include/asm-ia64/pci.h +++ b/include/asm-ia64/pci.h @@ -121,14 +121,9 @@ struct pci_controller { extern struct pci_ops pci_root_ops; -static inline int pci_name_bus(char *name, struct pci_bus *bus) +static inline int pci_proc_domain(struct pci_bus *bus) { - if (pci_domain_nr(bus) == 0) { - sprintf(name, "%02x", bus->number); - } else { - sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number); - } - return 0; + return (pci_domain_nr(bus) != 0); } static inline void pcibios_add_platform_entries(struct pci_dev *dev) diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h index 987090e07a65..c9c576b48556 100644 --- a/include/asm-mips/pci.h +++ b/include/asm-mips/pci.h @@ -137,17 +137,10 @@ extern void pcibios_resource_to_bus(struct pci_dev *dev, #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index -static inline int -pci_name_bus(char *name, struct pci_bus *bus) +static inline int pci_proc_domain(struct pci_bus *bus) { struct pci_controller *hose = bus->sysdata; - - if (likely(hose->need_domain_info == 0)) { - sprintf(name, "%02x", bus->number); - } else { - sprintf(name, "%04x:%02x", hose->index, bus->number); - } - return 0; + return hose->need_domain_info; } #endif /* CONFIG_PCI_DOMAINS */ diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h index 5349f5ca4697..4312793a1d41 100644 --- a/include/asm-ppc/pci.h +++ b/include/asm-ppc/pci.h @@ -79,9 +79,8 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr); #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index /* Set the name of the bus as it appears in /proc/bus/pci */ -static inline int pci_name_bus(char *name, struct pci_bus *bus) +static inline int pci_proc_domain(struct pci_bus *bus) { - sprintf(name, "%02x", bus->number); return 0; } diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h index 144878b404aa..d87b70e088b2 100644 --- a/include/asm-ppc64/pci.h +++ b/include/asm-ppc64/pci.h @@ -190,8 +190,8 @@ static inline int pci_dma_mapping_error(dma_addr_t dma_addr) extern int pci_domain_nr(struct pci_bus *bus); -/* Set the name of the bus as it appears in /proc/bus/pci */ -extern int pci_name_bus(char *name, struct pci_bus *bus); +/* Decide whether to display the domain number in /proc */ +extern int pci_proc_domain(struct pci_bus *bus); struct vm_area_struct; /* Map a range of PCI memory or I/O space for a device into user space */ diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index 861f16533ba2..2a0c85cd1c11 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h @@ -223,7 +223,10 @@ static inline int pci_dma_mapping_error(dma_addr_t dma_addr) /* Return the index of the PCI controller for device PDEV. */ extern int pci_domain_nr(struct pci_bus *bus); -extern int pci_name_bus(char *name, struct pci_bus *bus); +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return 1; +} /* Platform support for /proc/bus/pci/X/Y mmap()s. */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 930a8dfd997d..5a4aa98e538f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -964,9 +964,8 @@ static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int en */ #ifndef CONFIG_PCI_DOMAINS static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } -static inline int pci_name_bus(char *name, struct pci_bus *bus) +static inline int pci_proc_domain(struct pci_bus *bus) { - sprintf(name, "%02x", bus->number); return 0; } #endif -- cgit v1.2.3 From 8d79a5154ce614249c9a624138e2bd8b463c2c87 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 7 Feb 2005 00:21:16 -0800 Subject: [PATCH] PCI: pci_raw_ops should use unsigned args Convert pci_raw_ops to use unsigned segment (aka domain), bus, and devfn. With the previous code, various ia64 config accesses fail due to segment sign-extension problems. ia64: - With a signed seg >= 0x8, unwanted sign-extension occurs when "seg << 28" is cast to u64 in PCI_SAL_EXT_ADDRESS() - PCI_SAL_EXT_ADDRESS(): cast to u64 *before* shifting; otherwise "seg << 28" is evaluated as unsigned int (32 bits) and gets truncated when seg > 0xf - pci_sal_read(): validate "value" ptr as other arches do - pci_sal_{read,write}(): return -EINVAL rather than SAL error status arch/i386/pci/direct.c | 12 ++++++---- arch/i386/pci/mmconfig.c | 6 +++-- arch/i386/pci/numa.c | 6 +++-- arch/i386/pci/pcbios.c | 6 +++-- arch/ia64/pci/pci.c | 53 ++++++++++++++++++--------------------------- arch/x86_64/pci/mmconfig.c | 8 ++++-- include/linux/pci.h | 6 +++-- 7 files changed, 51 insertions(+), 46 deletions(-) Signed-off-by: Bjorn Helgaas Acked-by: Matthew Wilcox Signed-off-by: Greg Kroah-Hartman --- arch/i386/pci/direct.c | 12 +++++++---- arch/i386/pci/mmconfig.c | 6 ++++-- arch/i386/pci/numa.c | 6 ++++-- arch/i386/pci/pcbios.c | 6 ++++-- arch/ia64/pci/pci.c | 53 +++++++++++++++++++--------------------------- arch/x86_64/pci/mmconfig.c | 8 ++++--- include/linux/pci.h | 6 ++++-- 7 files changed, 51 insertions(+), 46 deletions(-) (limited to 'include') diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c index 3decbc498b0a..30b7e9b4f6a2 100644 --- a/arch/i386/pci/direct.c +++ b/arch/i386/pci/direct.c @@ -13,7 +13,8 @@ #define PCI_CONF1_ADDRESS(bus, devfn, reg) \ (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3)) -static int pci_conf1_read (int seg, int bus, int devfn, int reg, int len, u32 *value) +static int pci_conf1_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) { unsigned long flags; @@ -41,7 +42,8 @@ static int pci_conf1_read (int seg, int bus, int devfn, int reg, int len, u32 *v return 0; } -static int pci_conf1_write (int seg, int bus, int devfn, int reg, int len, u32 value) +static int pci_conf1_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) { unsigned long flags; @@ -83,7 +85,8 @@ struct pci_raw_ops pci_direct_conf1 = { #define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg) -static int pci_conf2_read(int seg, int bus, int devfn, int reg, int len, u32 *value) +static int pci_conf2_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) { unsigned long flags; int dev, fn; @@ -121,7 +124,8 @@ static int pci_conf2_read(int seg, int bus, int devfn, int reg, int len, u32 *va return 0; } -static int pci_conf2_write (int seg, int bus, int devfn, int reg, int len, u32 value) +static int pci_conf2_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) { unsigned long flags; int dev, fn; diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index 504fb18fe87d..021a50aa51f4 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -34,7 +34,8 @@ static inline void pci_exp_set_dev_base(int bus, int devfn) } } -static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value) +static int pci_mmcfg_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) { unsigned long flags; @@ -62,7 +63,8 @@ static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *va return 0; } -static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value) +static int pci_mmcfg_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) { unsigned long flags; diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c index 589512e57549..9e3695461899 100644 --- a/arch/i386/pci/numa.c +++ b/arch/i386/pci/numa.c @@ -14,7 +14,8 @@ #define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \ (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3)) -static int pci_conf1_mq_read (int seg, int bus, int devfn, int reg, int len, u32 *value) +static int pci_conf1_mq_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) { unsigned long flags; @@ -42,7 +43,8 @@ static int pci_conf1_mq_read (int seg, int bus, int devfn, int reg, int len, u32 return 0; } -static int pci_conf1_mq_write (int seg, int bus, int devfn, int reg, int len, u32 value) +static int pci_conf1_mq_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) { unsigned long flags; diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c index d0f3c2d0db89..141421b673b0 100644 --- a/arch/i386/pci/pcbios.c +++ b/arch/i386/pci/pcbios.c @@ -172,7 +172,8 @@ static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short return (int) (ret & 0xff00) >> 8; } -static int pci_bios_read (int seg, int bus, int devfn, int reg, int len, u32 *value) +static int pci_bios_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) { unsigned long result = 0; unsigned long flags; @@ -227,7 +228,8 @@ static int pci_bios_read (int seg, int bus, int devfn, int reg, int len, u32 *va return (int)((result & 0xff00) >> 8); } -static int pci_bios_write (int seg, int bus, int devfn, int reg, int len, u32 value) +static int pci_bios_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) { unsigned long result = 0; unsigned long flags; diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 2a0dcf6083d6..e710cd8acec8 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -3,9 +3,9 @@ * * Derived from bios32.c of i386 tree. * - * Copyright (C) 2002 Hewlett-Packard Co + * (c) Copyright 2002, 2005 Hewlett-Packard Development Company, L.P. * David Mosberger-Tang - * Bjorn Helgaas + * Bjorn Helgaas * Copyright (C) 2004 Silicon Graphics, Inc. * * Note: Above list of copyright holders is incomplete... @@ -27,26 +27,12 @@ #include #include #include - #include - - -#ifdef CONFIG_SMP -# include -#endif +#include #include #include -#undef DEBUG -#define DEBUG - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - static int pci_routeirq; /* @@ -55,23 +41,22 @@ static int pci_routeirq; * synchronization mechanism here. */ -#define PCI_SAL_ADDRESS(seg, bus, devfn, reg) \ - ((u64)(seg << 24) | (u64)(bus << 16) | \ - (u64)(devfn << 8) | (u64)(reg)) +#define PCI_SAL_ADDRESS(seg, bus, devfn, reg) \ + (((u64) seg << 24) | (bus << 16) | (devfn << 8) | (reg)) /* SAL 3.2 adds support for extended config space. */ #define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \ - ((u64)(seg << 28) | (u64)(bus << 20) | \ - (u64)(devfn << 12) | (u64)(reg)) + (((u64) seg << 28) | (bus << 20) | (devfn << 12) | (reg)) static int -pci_sal_read (int seg, int bus, int devfn, int reg, int len, u32 *value) +pci_sal_read (unsigned int seg, unsigned int bus, unsigned int devfn, + int reg, int len, u32 *value) { - u64 addr, mode, data = 0; - int result = 0; + u64 addr, data = 0; + int mode, result; - if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) + if (!value || (seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; if ((seg | reg) <= 255) { @@ -82,16 +67,19 @@ pci_sal_read (int seg, int bus, int devfn, int reg, int len, u32 *value) mode = 1; } result = ia64_sal_pci_config_read(addr, mode, len, &data); + if (result != 0) + return -EINVAL; *value = (u32) data; - - return result; + return 0; } static int -pci_sal_write (int seg, int bus, int devfn, int reg, int len, u32 value) +pci_sal_write (unsigned int seg, unsigned int bus, unsigned int devfn, + int reg, int len, u32 value) { - u64 addr, mode; + u64 addr; + int mode, result; if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; @@ -103,7 +91,10 @@ pci_sal_write (int seg, int bus, int devfn, int reg, int len, u32 value) addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg); mode = 1; } - return ia64_sal_pci_config_write(addr, mode, len, value); + result = ia64_sal_pci_config_write(addr, mode, len, value); + if (result != 0) + return -EINVAL; + return 0; } static struct pci_raw_ops pci_sal_ops = { diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index 142b9befee3f..b693c232fd07 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c @@ -17,12 +17,13 @@ u32 pci_mmcfg_base_addr; /* Static virtual mapping of the MMCONFIG aperture */ char *pci_mmcfg_virt; -static inline char *pci_dev_base(int bus, int devfn) +static inline char *pci_dev_base(unsigned int bus, unsigned int devfn) { return pci_mmcfg_virt + ((bus << 20) | (devfn << 12)); } -static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value) +static int pci_mmcfg_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) { char *addr = pci_dev_base(bus, devfn); @@ -44,7 +45,8 @@ static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *va return 0; } -static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value) +static int pci_mmcfg_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) { char *addr = pci_dev_base(bus,devfn); diff --git a/include/linux/pci.h b/include/linux/pci.h index 5a4aa98e538f..87da80182983 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -640,8 +640,10 @@ struct pci_ops { }; struct pci_raw_ops { - int (*read)(int dom, int bus, int devfn, int reg, int len, u32 *val); - int (*write)(int dom, int bus, int devfn, int reg, int len, u32 val); + int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn, + int reg, int len, u32 *val); + int (*write)(unsigned int domain, unsigned int bus, unsigned int devfn, + int reg, int len, u32 val); }; extern struct pci_raw_ops *raw_pci_ops; -- cgit v1.2.3 From 47b2eb2bc711921a677146822099b75aa9305fd9 Mon Sep 17 00:00:00 2001 From: Carl-Daniel Hailfinger Date: Wed, 16 Feb 2005 23:06:37 -0800 Subject: [PATCH] pci/quirks.c: unhide SMBus device on Samsung P35 laptop this patch is needed to make the SMBus device on my Samsung P35 laptop visible. By default, it doesn't appear as a pci device. Patch tested, works perfectly for me. Please apply. Signed-off-by: Carl-Daniel Hailfinger Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 6 ++++++ include/linux/pci_ids.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'include') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f573273088cc..a87524d3bad2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -807,6 +807,12 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x0001: /* Toshiba Satellite A40 */ asus_hides_smbus = 1; } + } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) { + if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) + switch(dev->subsystem_device) { + case 0xC00C: /* Samsung P35 notebook */ + asus_hides_smbus = 1; + } } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge ); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 919fa9768c19..c4d793c934a2 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1905,6 +1905,8 @@ #define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513 #define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521 +#define PCI_VENDOR_ID_SAMSUNG 0x144d + #define PCI_VENDOR_ID_AIRONET 0x14b9 #define PCI_DEVICE_ID_AIRONET_4800_1 0x0001 #define PCI_DEVICE_ID_AIRONET_4800 0x4500 // values switched? see -- cgit v1.2.3 From b2e3409a12673460e2dd5b6778ca0fcc152e6b82 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 24 Feb 2005 22:36:10 -0800 Subject: [PATCH] PCI: Apple PCI IDs update please sent that to Andrew/Linus in your next batch for after 2.6.11, those new IDs will be needed for support of the new iMac G5. The changes to pci.ids match the changes already submitted to the web database. From: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- include/linux/pci_ids.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c4d793c934a2..208c7e410d83 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -862,6 +862,9 @@ #define PCI_DEVICE_ID_APPLE_KEYLARGO_I 0x003e #define PCI_DEVICE_ID_APPLE_K2_ATA100 0x0043 #define PCI_DEVICE_ID_APPLE_K2_GMAC 0x004c +#define PCI_DEVICE_ID_APPLE_SH_ATA 0x0050 +#define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051 +#define PCI_DEVICE_ID_APPLE_SH_FW 0x0052 #define PCI_DEVICE_ID_APPLE_TIGON3 0x1645 #define PCI_VENDOR_ID_YAMAHA 0x1073 -- cgit v1.2.3 From 5e49e9e81c8eb46dc9f155815c2d6f865dc8cf6e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 Mar 2005 19:52:48 -0800 Subject: [PATCH] I2C: Kill i2c_client.id (4/5) > (4/5) Deprecate i2c_client.id. Now that i2c_client.id has no more users in the kernel (none that I could find at least) we could remove that struct member. I however think that it's better to only deprecate it at the moment, in case I missed users or any of the other patches are delayed for some reason. We could then delete the id member definitely in a month or so. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 3000c102171e..828c2a4a7719 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -144,7 +144,7 @@ extern struct bus_type i2c_bus_type; * function is mainly used for lookup & other admin. functions. */ struct i2c_client { - int id; + __attribute__ ((deprecated)) int id; unsigned int flags; /* div., see below */ unsigned int addr; /* chip address - NOTE: 7bit */ /* addresses are stored in the */ -- cgit v1.2.3 From 3732c94014b1838a116fafdb338550609e423427 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 1 Mar 2005 19:58:47 -0800 Subject: [PATCH] I2C: just delete the id field, let's not delay it any longer Becides, sparse keeps complaining when it sees this attribute within a structure... Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 828c2a4a7719..894e6be8fbb1 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -144,7 +144,6 @@ extern struct bus_type i2c_bus_type; * function is mainly used for lookup & other admin. functions. */ struct i2c_client { - __attribute__ ((deprecated)) int id; unsigned int flags; /* div., see below */ unsigned int addr; /* chip address - NOTE: 7bit */ /* addresses are stored in the */ -- cgit v1.2.3 From fc08381fb44ed8b67c8fbf5f7bdff33fd3b8c9d5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 1 Mar 2005 20:12:54 -0800 Subject: [PATCH] i2c-core.c: make some code static This patch makes some needlessly global code static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/i2c-core.c | 79 +++++++++++++++++++++++++------------------------- include/linux/i2c.h | 2 -- 2 files changed, 39 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 42776f1a82c8..387ccb02d983 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -38,12 +38,43 @@ static LIST_HEAD(drivers); static DECLARE_MUTEX(core_lists); static DEFINE_IDR(i2c_adapter_idr); -int i2c_device_probe(struct device *dev) +/* match always succeeds, as we want the probe() to tell if we really accept this match */ +static int i2c_device_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static int i2c_bus_suspend(struct device * dev, pm_message_t state) +{ + int rc = 0; + + if (dev->driver && dev->driver->suspend) + rc = dev->driver->suspend(dev,state,0); + return rc; +} + +static int i2c_bus_resume(struct device * dev) +{ + int rc = 0; + + if (dev->driver && dev->driver->resume) + rc = dev->driver->resume(dev,0); + return rc; +} + +static struct bus_type i2c_bus_type = { + .name = "i2c", + .match = i2c_device_match, + .suspend = i2c_bus_suspend, + .resume = i2c_bus_resume, +}; + +static int i2c_device_probe(struct device *dev) { return -ENODEV; } -int i2c_device_remove(struct device *dev) +static int i2c_device_remove(struct device *dev) { return 0; } @@ -523,38 +554,6 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) up(&adap->clist_lock); } - -/* match always succeeds, as we want the probe() to tell if we really accept this match */ -static int i2c_device_match(struct device *dev, struct device_driver *drv) -{ - return 1; -} - -static int i2c_bus_suspend(struct device * dev, u32 state) -{ - int rc = 0; - - if (dev->driver && dev->driver->suspend) - rc = dev->driver->suspend(dev,state,0); - return rc; -} - -static int i2c_bus_resume(struct device * dev) -{ - int rc = 0; - - if (dev->driver && dev->driver->resume) - rc = dev->driver->resume(dev,0); - return rc; -} - -struct bus_type i2c_bus_type = { - .name = "i2c", - .match = i2c_device_match, - .suspend = i2c_bus_suspend, - .resume = i2c_bus_resume, -}; - static int __init i2c_init(void) { int retval; @@ -860,7 +859,7 @@ crc8(u16 data) /* CRC over count bytes in the first array plus the bytes in the rest array if it is non-null. rest[0] is the (length of rest) - 1 and is included. */ -u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) +static u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) { int i; @@ -872,7 +871,7 @@ u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) return crc; } -u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) +static u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) { return i2c_smbus_partial_pec(0, count, first, rest); } @@ -880,8 +879,8 @@ u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) /* Returns new "size" (transaction type) Note that we convert byte to byte_data and byte_data to word_data rather than invent new xxx_PEC transactions. */ -int i2c_smbus_add_pec(u16 addr, u8 command, int size, - union i2c_smbus_data *data) +static int i2c_smbus_add_pec(u16 addr, u8 command, int size, + union i2c_smbus_data *data) { u8 buf[3]; @@ -910,8 +909,8 @@ int i2c_smbus_add_pec(u16 addr, u8 command, int size, return size; } -int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, - union i2c_smbus_data *data) +static int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, + union i2c_smbus_data *data) { u8 buf[3], rpec, cpec; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 894e6be8fbb1..101666b106cc 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -134,8 +134,6 @@ struct i2c_driver { }; #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) -extern struct bus_type i2c_bus_type; - #define I2C_NAME_SIZE 50 /* -- cgit v1.2.3 From 460698873c9556ce3d315f7c2a5ca2bd8dff8b90 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Tue, 1 Mar 2005 20:17:29 -0800 Subject: [PATCH] I2C: add Marvell mv64xxx i2c driver Marvell makes a line of host bridge for PPC and MIPS systems. On those bridges is an i2c controller. This patch adds the driver for that i2c controller. Please apply. Depends on patch submitted by Jean Delvare: http://archives.andrew.net.au/lm-sensors/msg29405.html Signed-off-by: Mark A. Greer Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-mv64xxx.c | 596 +++++++++++++++++++++++++++++++++++++++ include/linux/i2c-id.h | 3 + include/linux/mv643xx.h | 17 +- 5 files changed, 621 insertions(+), 6 deletions(-) create mode 100644 drivers/i2c/busses/i2c-mv64xxx.c (limited to 'include') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3d06bf980a3f..459fc5a02148 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -486,4 +486,14 @@ config I2C_PCA_ISA This driver can also be built as a module. If so, the module will be called i2c-pca-isa. +config I2C_MV64XXX + tristate "Marvell mv64xxx I2C Controller" + depends on I2C && MV64X60 && EXPERIMENTAL + help + If you say yes to this option, support will be included for the + built-in I2C interface on the Marvell 64xxx line of host bridges. + + This driver can also be built as a module. If so, the module + will be called i2c-mv64xxx. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index e5f4b1e507d4..42d6d814da72 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o +obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c new file mode 100644 index 000000000000..db88a1243956 --- /dev/null +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -0,0 +1,596 @@ +/* + * drivers/i2c/busses/i2c-mv64xxx.c + * + * Driver for the i2c controller on the Marvell line of host bridges for MIPS + * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0). + * + * Author: Mark A. Greer + * + * 2005 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include +#include +#include +#include +#include +#include +#include + +/* Register defines */ +#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 +#define MV64XXX_I2C_REG_DATA 0x04 +#define MV64XXX_I2C_REG_CONTROL 0x08 +#define MV64XXX_I2C_REG_STATUS 0x0c +#define MV64XXX_I2C_REG_BAUD 0x0c +#define MV64XXX_I2C_REG_EXT_SLAVE_ADDR 0x10 +#define MV64XXX_I2C_REG_SOFT_RESET 0x1c + +#define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004 +#define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008 +#define MV64XXX_I2C_REG_CONTROL_STOP 0x00000010 +#define MV64XXX_I2C_REG_CONTROL_START 0x00000020 +#define MV64XXX_I2C_REG_CONTROL_TWSIEN 0x00000040 +#define MV64XXX_I2C_REG_CONTROL_INTEN 0x00000080 + +/* Ctlr status values */ +#define MV64XXX_I2C_STATUS_BUS_ERR 0x00 +#define MV64XXX_I2C_STATUS_MAST_START 0x08 +#define MV64XXX_I2C_STATUS_MAST_REPEAT_START 0x10 +#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK 0x18 +#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20 +#define MV64XXX_I2C_STATUS_MAST_WR_ACK 0x28 +#define MV64XXX_I2C_STATUS_MAST_WR_NO_ACK 0x30 +#define MV64XXX_I2C_STATUS_MAST_LOST_ARB 0x38 +#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK 0x40 +#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48 +#define MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK 0x50 +#define MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58 +#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0 +#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8 +#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0 +#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8 +#define MV64XXX_I2C_STATUS_NO_STATUS 0xf8 + +/* Driver states */ +enum { + MV64XXX_I2C_STATE_INVALID, + MV64XXX_I2C_STATE_IDLE, + MV64XXX_I2C_STATE_WAITING_FOR_START_COND, + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA, + MV64XXX_I2C_STATE_ABORTING, +}; + +/* Driver actions */ +enum { + MV64XXX_I2C_ACTION_INVALID, + MV64XXX_I2C_ACTION_CONTINUE, + MV64XXX_I2C_ACTION_SEND_START, + MV64XXX_I2C_ACTION_SEND_ADDR_1, + MV64XXX_I2C_ACTION_SEND_ADDR_2, + MV64XXX_I2C_ACTION_SEND_DATA, + MV64XXX_I2C_ACTION_RCV_DATA, + MV64XXX_I2C_ACTION_RCV_DATA_STOP, + MV64XXX_I2C_ACTION_SEND_STOP, +}; + +struct mv64xxx_i2c_data { + int irq; + u32 state; + u32 action; + u32 cntl_bits; + void __iomem *reg_base; + u32 reg_base_p; + u32 addr1; + u32 addr2; + u32 bytes_left; + u32 byte_posn; + u32 block; + int rc; + u32 freq_m; + u32 freq_n; + wait_queue_head_t waitq; + spinlock_t lock; + struct i2c_msg *msg; + struct i2c_adapter adapter; +}; + +/* + ***************************************************************************** + * + * Finite State Machine & Interrupt Routines + * + ***************************************************************************** + */ +static void +mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) +{ + /* + * If state is idle, then this is likely the remnants of an old + * operation that driver has given up on or the user has killed. + * If so, issue the stop condition and go to idle. + */ + if (drv_data->state == MV64XXX_I2C_STATE_IDLE) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + return; + } + + if (drv_data->state == MV64XXX_I2C_STATE_ABORTING) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + return; + } + + /* The status from the ctlr [mostly] tells us what to do next */ + switch (status) { + /* Start condition interrupt */ + case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */ + case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */ + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; + break; + + /* Performing a write */ + case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */ + if (drv_data->msg->flags & I2C_M_TEN) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; + break; + } + /* FALLTHRU */ + case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */ + case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */ + if (drv_data->bytes_left > 0) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; + drv_data->bytes_left--; + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + } + break; + + /* Performing a read */ + case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */ + if (drv_data->msg->flags & I2C_M_TEN) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; + break; + } + /* FALLTHRU */ + case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */ + if (drv_data->bytes_left == 0) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + break; + } + /* FALLTHRU */ + case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */ + if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK) + drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; + else { + drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA; + drv_data->bytes_left--; + } + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; + + if (drv_data->bytes_left == 1) + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK; + break; + + case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */ + drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + break; + + case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */ + case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */ + case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */ + /* Doesn't seem to be a device at other end */ + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + drv_data->rc = -ENODEV; + break; + + default: + dev_err(&drv_data->adapter.dev, + "mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, " + "status: 0x%x, addr: 0x%x, flags: 0x%x\n", + drv_data->state, status, drv_data->msg->addr, + drv_data->msg->flags); + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + drv_data->rc = -EIO; + } +} + +static void +mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) +{ + switch(drv_data->action) { + case MV64XXX_I2C_ACTION_CONTINUE: + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_SEND_START: + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_SEND_ADDR_1: + writel(drv_data->addr1, + drv_data->reg_base + MV64XXX_I2C_REG_DATA); + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_SEND_ADDR_2: + writel(drv_data->addr2, + drv_data->reg_base + MV64XXX_I2C_REG_DATA); + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_SEND_DATA: + writel(drv_data->msg->buf[drv_data->byte_posn++], + drv_data->reg_base + MV64XXX_I2C_REG_DATA); + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_RCV_DATA: + drv_data->msg->buf[drv_data->byte_posn++] = + readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_RCV_DATA_STOP: + drv_data->msg->buf[drv_data->byte_posn++] = + readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->block = 0; + wake_up_interruptible(&drv_data->waitq); + break; + + case MV64XXX_I2C_ACTION_INVALID: + default: + dev_err(&drv_data->adapter.dev, + "mv64xxx_i2c_do_action: Invalid action: %d\n", + drv_data->action); + drv_data->rc = -EIO; + /* FALLTHRU */ + case MV64XXX_I2C_ACTION_SEND_STOP: + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->block = 0; + wake_up_interruptible(&drv_data->waitq); + break; + } +} + +static int +mv64xxx_i2c_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mv64xxx_i2c_data *drv_data = dev_id; + unsigned long flags; + u32 status; + int rc = IRQ_NONE; + + spin_lock_irqsave(&drv_data->lock, flags); + while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) & + MV64XXX_I2C_REG_CONTROL_IFLG) { + status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS); + mv64xxx_i2c_fsm(drv_data, status); + mv64xxx_i2c_do_action(drv_data); + rc = IRQ_HANDLED; + } + spin_unlock_irqrestore(&drv_data->lock, flags); + + return rc; +} + +/* + ***************************************************************************** + * + * I2C Msg Execution Routines + * + ***************************************************************************** + */ +static void +mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, + struct i2c_msg *msg) +{ + u32 dir = 0; + + drv_data->msg = msg; + drv_data->byte_posn = 0; + drv_data->bytes_left = msg->len; + drv_data->rc = 0; + drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | + MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; + + if (msg->flags & I2C_M_RD) + dir = 1; + + if (msg->flags & I2C_M_REV_DIR_ADDR) + dir ^= 1; + + if (msg->flags & I2C_M_TEN) { + drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir; + drv_data->addr2 = (u32)msg->addr & 0xff; + } else { + drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir; + drv_data->addr2 = 0; + } +} + +static void +mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) +{ + long time_left; + unsigned long flags; + char abort = 0; + + time_left = wait_event_interruptible_timeout(drv_data->waitq, + !drv_data->block, msecs_to_jiffies(drv_data->adapter.timeout)); + + spin_lock_irqsave(&drv_data->lock, flags); + if (!time_left) { /* Timed out */ + drv_data->rc = -ETIMEDOUT; + abort = 1; + } else if (time_left < 0) { /* Interrupted/Error */ + drv_data->rc = time_left; /* errno value */ + abort = 1; + } + + if (abort && drv_data->block) { + drv_data->state = MV64XXX_I2C_STATE_ABORTING; + spin_unlock_irqrestore(&drv_data->lock, flags); + + time_left = wait_event_timeout(drv_data->waitq, + !drv_data->block, + msecs_to_jiffies(drv_data->adapter.timeout)); + + if (time_left <= 0) { + drv_data->state = MV64XXX_I2C_STATE_IDLE; + dev_err(&drv_data->adapter.dev, + "mv64xxx: I2C bus locked\n"); + } + } else + spin_unlock_irqrestore(&drv_data->lock, flags); +} + +static int +mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) +{ + unsigned long flags; + + spin_lock_irqsave(&drv_data->lock, flags); + mv64xxx_i2c_prepare_for_io(drv_data, msg); + + if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */ + if (drv_data->msg->flags & I2C_M_RD) { + /* No action to do, wait for slave to send a byte */ + drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; + drv_data->bytes_left--; + } + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_START; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; + } + + drv_data->block = 1; + mv64xxx_i2c_do_action(drv_data); + spin_unlock_irqrestore(&drv_data->lock, flags); + + mv64xxx_i2c_wait_for_completion(drv_data); + return drv_data->rc; +} + +/* + ***************************************************************************** + * + * I2C Core Support Routines (Interface to higher level I2C code) + * + ***************************************************************************** + */ +static u32 +mv64xxx_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; +} + +static int +mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); + int i, rc = 0; + + for (i=0; ireg_base + MV64XXX_I2C_REG_SOFT_RESET); + writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)), + drv_data->reg_base + MV64XXX_I2C_REG_BAUD); + writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR); + writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR); + writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->state = MV64XXX_I2C_STATE_IDLE; +} + +static int __devinit +mv64xxx_i2c_map_regs(struct platform_device *pd, + struct mv64xxx_i2c_data *drv_data) +{ + struct resource *r; + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) && + request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE, + drv_data->adapter.name)) { + + drv_data->reg_base = ioremap(r->start, + MV64XXX_I2C_REG_BLOCK_SIZE); + drv_data->reg_base_p = r->start; + } else + return -ENOMEM; + + return 0; +} + +static void __devexit +mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) +{ + if (drv_data->reg_base) { + iounmap(drv_data->reg_base); + release_mem_region(drv_data->reg_base_p, + MV64XXX_I2C_REG_BLOCK_SIZE); + } + + drv_data->reg_base = NULL; + drv_data->reg_base_p = 0; +} + +static int __devinit +mv64xxx_i2c_probe(struct device *dev) +{ + struct platform_device *pd = to_platform_device(dev); + struct mv64xxx_i2c_data *drv_data; + struct mv64xxx_i2c_pdata *pdata = dev->platform_data; + int rc; + + if ((pd->id != 0) || !pdata) + return -ENODEV; + + drv_data = kmalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); + + if (!drv_data) + return -ENOMEM; + + memset(drv_data, 0, sizeof(struct mv64xxx_i2c_data)); + + if (mv64xxx_i2c_map_regs(pd, drv_data)) { + rc = -ENODEV; + goto exit_kfree; + } + + strncpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", + I2C_NAME_SIZE); + + init_waitqueue_head(&drv_data->waitq); + spin_lock_init(&drv_data->lock); + + drv_data->freq_m = pdata->freq_m; + drv_data->freq_n = pdata->freq_n; + drv_data->irq = platform_get_irq(pd, 0); + drv_data->adapter.id = I2C_ALGO_MV64XXX | I2C_HW_MV64XXX; + drv_data->adapter.algo = &mv64xxx_i2c_algo; + drv_data->adapter.timeout = pdata->timeout; + drv_data->adapter.retries = pdata->retries; + dev_set_drvdata(dev, drv_data); + i2c_set_adapdata(&drv_data->adapter, drv_data); + + if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, + MV64XXX_I2C_CTLR_NAME, drv_data)) { + + dev_err(dev, "mv64xxx: Can't register intr handler " + "irq: %d\n", drv_data->irq); + rc = -EINVAL; + goto exit_unmap_regs; + } else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) { + dev_err(dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); + goto exit_free_irq; + } + + mv64xxx_i2c_hw_init(drv_data); + + return 0; + + exit_free_irq: + free_irq(drv_data->irq, drv_data); + exit_unmap_regs: + mv64xxx_i2c_unmap_regs(drv_data); + exit_kfree: + kfree(drv_data); + return rc; +} + +static int __devexit +mv64xxx_i2c_remove(struct device *dev) +{ + struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev); + int rc; + + rc = i2c_del_adapter(&drv_data->adapter); + free_irq(drv_data->irq, drv_data); + mv64xxx_i2c_unmap_regs(drv_data); + kfree(drv_data); + + return rc; +} + +static struct device_driver mv64xxx_i2c_driver = { + .name = MV64XXX_I2C_CTLR_NAME, + .bus = &platform_bus_type, + .probe = mv64xxx_i2c_probe, + .remove = mv64xxx_i2c_remove, +}; + +static int __init +mv64xxx_i2c_init(void) +{ + return driver_register(&mv64xxx_i2c_driver); +} + +static void __exit +mv64xxx_i2c_exit(void) +{ + driver_unregister(&mv64xxx_i2c_driver); +} + +module_init(mv64xxx_i2c_init); +module_exit(mv64xxx_i2c_exit); + +MODULE_AUTHOR("Mark A. Greer "); +MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 8ac11f5c1b84..7cde0ef49481 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -310,4 +310,7 @@ /* --- MCP107 adapter */ #define I2C_HW_MPC107 0x00 +/* --- Marvell mv64xxx i2c adapter */ +#define I2C_HW_MV64XXX 0x00 + #endif /* LINUX_I2C_ID_H */ diff --git a/include/linux/mv643xx.h b/include/linux/mv643xx.h index ef7470732f14..88293844db7e 100644 --- a/include/linux/mv643xx.h +++ b/include/linux/mv643xx.h @@ -977,12 +977,9 @@ /* I2C Registers */ /****************************************/ -#define MV64340_I2C_SLAVE_ADDR 0xc000 -#define MV64340_I2C_EXTENDED_SLAVE_ADDR 0xc010 -#define MV64340_I2C_DATA 0xc004 -#define MV64340_I2C_CONTROL 0xc008 -#define MV64340_I2C_STATUS_BAUDE_RATE 0xc00C -#define MV64340_I2C_SOFT_RESET 0xc01c +#define MV64XXX_I2C_CTLR_NAME "mv64xxx i2c" +#define MV64XXX_I2C_OFFSET 0xc000 +#define MV64XXX_I2C_REG_BLOCK_SIZE 0x0020 /****************************************/ /* GPP Interface Registers */ @@ -1085,4 +1082,12 @@ struct mpsc_pdata { u32 brg_clk_freq; }; +/* i2c Platform Device, Driver Data */ +struct mv64xxx_i2c_pdata { + u32 freq_m; + u32 freq_n; + u32 timeout; /* In milliseconds */ + u32 retries; +}; + #endif /* __ASM_MV64340_H */ -- cgit v1.2.3 From 9962e88327fdb4ec6dc92efeb6d25019a15b350e Mon Sep 17 00:00:00 2001 From: "hfvogt@gmx.net" Date: Tue, 1 Mar 2005 20:18:53 -0800 Subject: [PATCH] I2C i2c-nforce2: add support for nForce4 (patch against 2.6.11-rc4) can you please apply the attached patch (against 2.6.11-rc4, but works as well for 2.6.11-rc3-mm2), that adds support for the two SMBusses of the nForce4 to the i2c-nforce2 i2c bus driver. The patch is reported to work on the standard nForce4 (i.e. non-Ultra, non-SLI), but I expect that it works as well for the other nForce4 chipsets, that seem to have the same PCI-id for the SMBus-device. This patch was proposed by Chuck , thanks to him for the information, testing and his patch. Signed-off-by: Hans-Frieder Vogt Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-nforce2.c | 6 ++++-- include/linux/pci_ids.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index b2b6081327d8..6d13127c8c4e 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -29,9 +29,10 @@ nForce2 Ultra 400 MCP 0084 nForce3 Pro150 MCP 00D4 nForce3 250Gb MCP 00E4 + nForce4 MCP 0052 - This driver supports the 2 SMBuses that are included in the MCP2 of the - nForce2 chipset. + This driver supports the 2 SMBuses that are included in the MCP of the + nForce2/3/4 chipsets. */ /* Note: we assume there can only be one nForce2, with two SMBus interfaces */ @@ -295,6 +296,7 @@ static struct pci_device_id nforce2_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) }, { 0 } }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3dca3b53f74b..099d7b439401 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1098,6 +1098,7 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037 #define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e +#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS 0x0052 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055 -- cgit v1.2.3 From 01389791cf97d952a1ec5ec329181b508956820b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 Mar 2005 23:02:10 -0800 Subject: [PATCH] I2C: Make i2c list terminators explicitely unsigned Shouldn't the i2c list terminators be explicitely declared as unsigned? I'd hope it to help code analysis tools and possibly avoid false positives. Coverity's SWAT pointed my attention to these constants. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 101666b106cc..3f6c820c78a2 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -299,8 +299,8 @@ struct i2c_client_address_data { }; /* Internal numbers to terminate lists */ -#define I2C_CLIENT_END 0xfffe -#define I2C_CLIENT_ISA_END 0xfffefffe +#define I2C_CLIENT_END 0xfffeU +#define I2C_CLIENT_ISA_END 0xfffefffeU /* The numbers to use to set I2C bus address */ #define ANY_I2C_BUS 0xffff -- cgit v1.2.3 From 96ad05d373635c55902f1e826c6d7258cc187c87 Mon Sep 17 00:00:00 2001 From: Mickey Stein Date: Tue, 1 Mar 2005 23:02:27 -0800 Subject: [PATCH] I2C: Fix some gcc 4.0 compile failures and warnings gcc 4.0.x cvs seems to dislike "include/linux/i2c.h file" and others due to a current gcc 4.0.x change having to do with array declarations. Example error msg: include/linux/i2c.h:{55,194} error: array type has incomplete element type A. Daplas has recently done a workaround for this on another header file. A thread discussing this can be found by following the link below: http://gcc.gnu.org/ml/gcc/2005-02/msg00053.html The patch changes the array(struct i2c_msg) declaration used by *i2c_transfer and *master_xfer from "struct i2c_msg msg[]" format to "struct i2c_msg *msg". After some grepping, I came up with about a dozen files that used the format disliked by gcc4 that're addressed by the attached patch. Tested on gcc 3.x & gcc 4.x by configuring kernel with all i2c switches enabled as module, and saw no errors or warnings in i2c. Signed-off-by: Mickey Stein Signed-off-by: Greg Kroah-Hartman --- Documentation/i2c/writing-clients | 2 +- drivers/i2c/algos/i2c-algo-ite.c | 4 ++-- drivers/i2c/algos/i2c-algo-pca.c | 2 +- drivers/i2c/algos/i2c-algo-pcf.c | 2 +- drivers/i2c/algos/i2c-algo-sgi.c | 2 +- drivers/i2c/busses/i2c-au1550.c | 2 +- drivers/i2c/busses/i2c-ibm_iic.c | 2 +- drivers/i2c/busses/i2c-iop3xx.c | 2 +- drivers/i2c/busses/i2c-keywest.c | 2 +- drivers/i2c/busses/i2c-mpc.c | 2 +- drivers/i2c/busses/i2c-s3c2410.c | 4 ++-- drivers/i2c/i2c-core.c | 2 +- drivers/media/common/saa7146_i2c.c | 8 ++++---- drivers/media/dvb/b2c2/skystar2.c | 2 +- drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c | 2 +- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 2 +- drivers/media/video/bttv-i2c.c | 2 +- drivers/media/video/saa7134/saa7134-i2c.c | 2 +- include/linux/i2c.h | 4 ++-- include/media/saa7146.h | 2 +- 20 files changed, 26 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 5c60ff21d38d..ad27511e3c7d 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -638,7 +638,7 @@ contains the i2c address, so you do not have to include it. The second parameter contains the bytes the read/write, the third the length of the buffer. Returned is the actual number of bytes read/written. - extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num); This sends a series of messages. Each message can be a read or write, diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c index 1b2c67c7fd1b..ffd87404b0a0 100644 --- a/drivers/i2c/algos/i2c-algo-ite.c +++ b/drivers/i2c/algos/i2c-algo-ite.c @@ -490,7 +490,7 @@ static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, * condition. */ #if 0 -static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { int i; struct i2c_msg *pmsg; @@ -600,7 +600,7 @@ static inline int iic_doAddress(struct i2c_algo_iic_data *adap, * verify that the bus is not busy or in some unknown state. */ static int iic_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], + struct i2c_msg *msgs, int num) { struct i2c_algo_iic_data *adap = i2c_adap->algo_data; diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index fa87bfccb730..c3d912cbbbc3 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -178,7 +178,7 @@ static void pca_reset(struct i2c_algo_pca_data *adap) } static int pca_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], + struct i2c_msg *msgs, int num) { struct i2c_algo_pca_data *adap = i2c_adap->algo_data; diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index fbbe1d2bdcc4..66e681cb33d1 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -332,7 +332,7 @@ static inline int pcf_doAddress(struct i2c_algo_pcf_data *adap, } static int pcf_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], + struct i2c_msg *msgs, int num) { struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c index b4e0a065b78b..422721b241e5 100644 --- a/drivers/i2c/algos/i2c-algo-sgi.c +++ b/drivers/i2c/algos/i2c-algo-sgi.c @@ -131,7 +131,7 @@ static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf, return 0; } -static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], +static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct i2c_algo_sgi_data *adap = i2c_adap->algo_data; diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index c43353aa3d20..75831a20b0bd 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -253,7 +253,7 @@ i2c_write(struct i2c_au1550_data *adap, unsigned char *buf, } static int -au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct i2c_au1550_data *adap = i2c_adap->algo_data; struct i2c_msg *p; diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 8168f2d3b922..17326cdd68d7 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -549,7 +549,7 @@ static inline int iic_address_neq(const struct i2c_msg* p1, * Generic master transfer entrypoint. * Returns the number of processed messages or error (<0) */ -static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap)); volatile struct iic_regs __iomem *iic = dev->vaddr; diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 961241b19f88..c961ba4cfb32 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -361,7 +361,7 @@ iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) * master_xfer() - main read/write entry */ static int -iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], +iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index bc94b8cd36a5..dd0d4c463146 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -399,7 +399,7 @@ keywest_smbus_xfer( struct i2c_adapter* adap, */ static int keywest_xfer( struct i2c_adapter *adap, - struct i2c_msg msgs[], + struct i2c_msg *msgs, int num) { struct keywest_chan* chan = i2c_get_adapdata(adap); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 67d6e7d299a2..75b8d867dae1 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -233,7 +233,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target, return length; } -static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct i2c_msg *pmsg; int i; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 9cb69744a71b..6b5c9aaeba08 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -483,7 +483,7 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) * this starts an i2c transfer */ -static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg msgs[], int num) +static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { unsigned long timeout; int ret; @@ -534,7 +534,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg msgs[], in */ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg msgs[], int num) + struct i2c_msg *msgs, int num) { struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data; int retry; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 387ccb02d983..56a67457341d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -582,7 +582,7 @@ module_exit(i2c_exit); * ---------------------------------------------------- */ -int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) +int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) { int ret; diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 875ebd46623c..c59cde0157bd 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -25,7 +25,7 @@ static inline u32 saa7146_i2c_status(struct saa7146_dev *dev) sent through the saa7146. have a look at the specifications p. 122 ff to understand this. it returns the number of u32s to send, or -1 in case of an error. */ -static int saa7146_i2c_msg_prepare(const struct i2c_msg m[], int num, u32 *op) +static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op) { int h1, h2; int i, j, addr; @@ -89,7 +89,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg m[], int num, u32 *op) which bytes were read through the adapter and write them back to the corresponding i2c-message. but instead, we simply write back all bytes. fixme: this could be improved. */ -static int saa7146_i2c_msg_cleanup(const struct i2c_msg m[], int num, u32 *op) +static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op) { int i, j; int op_count = 0; @@ -272,7 +272,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d return 0; } -int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg msgs[], int num, int retries) +int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) { int i = 0, count = 0; u32* buffer = dev->d_i2c.cpu_addr; @@ -372,7 +372,7 @@ out: } /* utility functions */ -static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg msg[], int num) +static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) { struct saa7146_dev* dev = i2c_get_adapdata(adapter); diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c index 9db469957419..fba10993d4e4 100644 --- a/drivers/media/dvb/b2c2/skystar2.c +++ b/drivers/media/dvb/b2c2/skystar2.c @@ -293,7 +293,7 @@ static u32 flex_i2c_write(struct adapter *adapter, u32 device, u32 bus, u32 addr return buf - start; } -static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msgs[], int num) +static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msgs, int num) { struct adapter *tmp = i2c_get_adapdata(adapter); int i, ret = 0; diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c index 925c8599faab..bddf3b39b87e 100644 --- a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c +++ b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c @@ -38,7 +38,7 @@ int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, /* * I2C master xfer function */ -static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num) { struct usb_dibusb *dib = i2c_get_adapdata(adap); int i; diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 0485faa51b4d..5ea692d464e0 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -252,7 +252,7 @@ static int ttusb_i2c_msg(struct ttusb *ttusb, return rcv_len; } -static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msg[], int num) +static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) { struct ttusb *ttusb = i2c_get_adapdata(adapter); int i = 0; diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index a35eedc6bb4a..1cae7a5f4f5a 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -245,7 +245,7 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) return retval; } -static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct bttv *btv = i2c_get_adapdata(i2c_adap); int retval = 0; diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 109c880b3450..e5944d0599a1 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -236,7 +236,7 @@ static inline int i2c_recv_byte(struct saa7134_dev *dev) } static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) + struct i2c_msg *msgs, int num) { struct saa7134_dev *dev = i2c_adap->algo_data; enum i2c_status status; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 3f6c820c78a2..9015e79c6748 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -55,7 +55,7 @@ extern int i2c_master_recv(struct i2c_client *,char* ,int); /* Transfer num messages. */ -extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num); +extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); /* * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor. @@ -191,7 +191,7 @@ struct i2c_algorithm { to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages */ - int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], + int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs, int num); int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 171dbb682a0e..d8ac909fb01d 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -157,7 +157,7 @@ struct saa7146_dev /* from saa7146_i2c.c */ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); -int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg msgs[], int num, int retries); +int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct *i2c_msg msgs, int num, int retries); /* from saa7146_core.c */ extern struct list_head saa7146_devices; -- cgit v1.2.3 From b8513f1c6ee58b8427111ca127d9836f92ae8f7f Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 1 Mar 2005 23:03:00 -0800 Subject: [PATCH] I2C: minor I2C cleanups This is one in a series of patches for adding a non-blocking interface to the I2C driver for supporting the IPMI SMBus driver. This patch is a simply some minor cleanups and is in addition to the patch by Mickey Stein (http://marc.theaimsgroup.com/?l=linux-kernel&m=110919738708916&w=2). Clean up some general I2C things. Fix some grammar and put () around all the #defines that are compound to avoid nasty side-effects. Signed-off-by: Corey Minyard Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c.h | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 9015e79c6748..da901fd6b590 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -187,7 +187,7 @@ struct i2c_algorithm { char name[32]; /* textual description */ unsigned int id; - /* If an adapter algorithm can't to I2C-level access, set master_xfer + /* If an adapter algorithm can't do I2C-level access, set master_xfer to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages */ @@ -420,22 +420,22 @@ struct i2c_msg { #define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */ -#define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \ - I2C_FUNC_SMBUS_WRITE_BYTE -#define I2C_FUNC_SMBUS_BYTE_DATA I2C_FUNC_SMBUS_READ_BYTE_DATA | \ - I2C_FUNC_SMBUS_WRITE_BYTE_DATA -#define I2C_FUNC_SMBUS_WORD_DATA I2C_FUNC_SMBUS_READ_WORD_DATA | \ - I2C_FUNC_SMBUS_WRITE_WORD_DATA -#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA -#define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK -#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 -#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC -#define I2C_FUNC_SMBUS_WORD_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ - I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC +#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ + I2C_FUNC_SMBUS_WRITE_BYTE) +#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ + I2C_FUNC_SMBUS_WRITE_BYTE_DATA) +#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ + I2C_FUNC_SMBUS_WRITE_WORD_DATA) +#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) +#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) +#define I2C_FUNC_SMBUS_I2C_BLOCK_2 (I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2) +#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC (I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC) +#define I2C_FUNC_SMBUS_WORD_DATA_PEC (I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ + I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC) #define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA #define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA @@ -444,14 +444,14 @@ struct i2c_msg { #define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA #define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA -#define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \ - I2C_FUNC_SMBUS_BYTE | \ - I2C_FUNC_SMBUS_BYTE_DATA | \ - I2C_FUNC_SMBUS_WORD_DATA | \ - I2C_FUNC_SMBUS_PROC_CALL | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ - I2C_FUNC_SMBUS_I2C_BLOCK +#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \ + I2C_FUNC_SMBUS_BYTE | \ + I2C_FUNC_SMBUS_BYTE_DATA | \ + I2C_FUNC_SMBUS_WORD_DATA | \ + I2C_FUNC_SMBUS_PROC_CALL | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ + I2C_FUNC_SMBUS_I2C_BLOCK) /* * Data for SMBus Messages -- cgit v1.2.3 From 8edbaf4d45403272b7dd42d349ce41814943a54d Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 1 Mar 2005 23:03:32 -0800 Subject: [PATCH] I2C: saa7146 build fix include/media/saa7146.h:160: parse error before `*' include/media/saa7146.h:160: warning: function declaration isn't a prototype Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/media/saa7146.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/media/saa7146.h b/include/media/saa7146.h index d8ac909fb01d..b9b19888aeb9 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -157,7 +157,7 @@ struct saa7146_dev /* from saa7146_i2c.c */ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); -int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct *i2c_msg msgs, int num, int retries); +int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg *msgs, int num, int retries); /* from saa7146_core.c */ extern struct list_head saa7146_devices; -- cgit v1.2.3 From 1491bba79c2c6afb91c9e589d6d1dad33462baa4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 1 Mar 2005 23:50:42 -0800 Subject: [PATCH] I2C: fixed up the i2c-id.h algo ids. Thanks to Jean Delvare for the help with this. Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c-id.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 7cde0ef49481..89270ce51470 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -20,8 +20,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ -/* $Id: i2c-id.h,v 1.68 2003/02/25 02:55:18 mds Exp $ */ - #ifndef LINUX_I2C_ID_H #define LINUX_I2C_ID_H @@ -196,11 +194,15 @@ #define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ #define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */ #define I2C_ALGO_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */ -#define I2C_ALGO_PCA 0x150000 /* PCA 9564 style adapters */ - #define I2C_ALGO_SIBYTE 0x150000 /* Broadcom SiByte SOCs */ -#define I2C_ALGO_SGI 0x160000 /* SGI algorithm */ -#define I2C_ALGO_AU1550 0x170000 /* Au1550 PSC algorithm */ +#define I2C_ALGO_SGI 0x160000 /* SGI algorithm */ + +#define I2C_ALGO_USB 0x170000 /* USB algorithm */ +#define I2C_ALGO_VIRT 0x180000 /* Virtual bus adapter */ + +#define I2C_ALGO_MV64XXX 0x190000 /* Marvell mv64xxx i2c ctlr */ +#define I2C_ALGO_PCA 0x1a0000 /* PCA 9564 style adapters */ +#define I2C_ALGO_AU1550 0x1b0000 /* Au1550 PSC algorithm */ #define I2C_ALGO_EXP 0x800000 /* experimental */ @@ -240,6 +242,7 @@ #define I2C_HW_B_IXP4XX 0x17 /* GPIO on IXP4XX systems */ #define I2C_HW_B_S3VIA 0x18 /* S3Via ProSavage adapter */ #define I2C_HW_B_ZR36067 0x19 /* Zoran-36057/36067 based boards */ +#define I2C_HW_B_PCILYNX 0x1a /* TI PCILynx I2C adapter */ #define I2C_HW_B_CX2388x 0x1b /* connexant 2388x based tv cards */ /* --- PCF 8584 based algorithms */ -- cgit v1.2.3 From a98faa0cfb14567db871088699adde16c81957eb Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 2 Mar 2005 15:09:38 +0000 Subject: [ARM] Update syscall table Add demultiplexed socket and ipc syscalls. Add key syscalls. Leave the new numbers for the demultiplexed socket and ipc syscalls commented out in asm-arm/unistd.h for the time being. Signed-off-by: Russell King --- arch/arm/kernel/calls.S | 35 +++++++++++++++++++++++++++++++++-- arch/arm/kernel/sys_arm.c | 12 ++++++++++++ include/asm-arm/unistd.h | 42 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 85 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index fbb9b81a9d30..fa2403c86348 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -1,7 +1,7 @@ /* * linux/arch/arm/kernel/calls.S * - * Copyright (C) 1995-2004 Russell King + * Copyright (C) 1995-2005 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -10,7 +10,7 @@ * This file is included twice in entry-common.S */ #ifndef NR_syscalls -#define NR_syscalls 288 +#define NR_syscalls 320 #else __syscall_start: @@ -295,6 +295,37 @@ __syscall_start: .long sys_mq_notify .long sys_mq_getsetattr /* 280 */ .long sys_waitid + .long sys_socket + .long sys_bind + .long sys_connect + .long sys_listen +/* 285 */ .long sys_accept + .long sys_getsockname + .long sys_getpeername + .long sys_socketpair + .long sys_send +/* 290 */ .long sys_sendto + .long sys_recv + .long sys_recvfrom + .long sys_shutdown + .long sys_setsockopt +/* 295 */ .long sys_getsockopt + .long sys_sendmsg + .long sys_recvmsg + .long sys_semop + .long sys_semget +/* 300 */ .long sys_semctl + .long sys_msgsnd + .long sys_msgrcv + .long sys_msgget + .long sys_msgctl +/* 305 */ .long sys_shmat + .long sys_shmdt + .long sys_shmget + .long sys_shmctl + .long sys_add_key +/* 310 */ .long sys_request_key + .long sys_keyctl __syscall_end: .rept NR_syscalls - (__syscall_end - __syscall_start) / 4 diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index c087e26021c0..7b041bfa48b7 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -230,6 +230,18 @@ asmlinkage int sys_ipc(uint call, int first, int second, int third, } } +asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg, + unsigned long __user *addr) +{ + unsigned long ret; + long err; + + err = do_shmat(shmid, shmaddr, shmflg, &ret); + if (err == 0) + err = put_user(ret, addr); + return err; +} + /* Fork a new task - this creates a new program thread. * This is called indirectly via a small wrapper */ diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index b3efbb2c3f9e..c4cc286f16e8 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/unistd.h * - * Copyright (C) 2001-2003 Russell King + * Copyright (C) 2001-2005 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -307,6 +307,44 @@ #define __NR_mq_getsetattr (__NR_SYSCALL_BASE+279) #define __NR_waitid (__NR_SYSCALL_BASE+280) +#if 0 /* reserve these for un-muxing socketcall */ +#define __NR_socket (__NR_SYSCALL_BASE+281) +#define __NR_bind (__NR_SYSCALL_BASE+282) +#define __NR_connect (__NR_SYSCALL_BASE+283) +#define __NR_listen (__NR_SYSCALL_BASE+284) +#define __NR_accept (__NR_SYSCALL_BASE+285) +#define __NR_getsockname (__NR_SYSCALL_BASE+286) +#define __NR_getpeername (__NR_SYSCALL_BASE+287) +#define __NR_socketpair (__NR_SYSCALL_BASE+288) +#define __NR_send (__NR_SYSCALL_BASE+289) +#define __NR_sendto (__NR_SYSCALL_BASE+290) +#define __NR_recv (__NR_SYSCALL_BASE+291) +#define __NR_recvfrom (__NR_SYSCALL_BASE+292) +#define __NR_shutdown (__NR_SYSCALL_BASE+293) +#define __NR_setsockopt (__NR_SYSCALL_BASE+294) +#define __NR_getsockopt (__NR_SYSCALL_BASE+295) +#define __NR_sendmsg (__NR_SYSCALL_BASE+296) +#define __NR_recvmsg (__NR_SYSCALL_BASE+297) +#endif + +#if 0 /* reserve these for un-muxing ipc */ +#define __NR_semop (__NR_SYSCALL_BASE+298) +#define __NR_semget (__NR_SYSCALL_BASE+299) +#define __NR_semctl (__NR_SYSCALL_BASE+300) +#define __NR_msgsnd (__NR_SYSCALL_BASE+301) +#define __NR_msgrcv (__NR_SYSCALL_BASE+302) +#define __NR_msgget (__NR_SYSCALL_BASE+303) +#define __NR_msgctl (__NR_SYSCALL_BASE+304) +#define __NR_shmat (__NR_SYSCALL_BASE+305) +#define __NR_shmdt (__NR_SYSCALL_BASE+306) +#define __NR_shmget (__NR_SYSCALL_BASE+307) +#define __NR_shmctl (__NR_SYSCALL_BASE+308) +#endif + +#define __NR_add_key (__NR_SYSCALL_BASE+309) +#define __NR_request_key (__NR_SYSCALL_BASE+310) +#define __NR_keyctl (__NR_SYSCALL_BASE+311) + /* * The following SWIs are ARM private. */ @@ -335,7 +373,7 @@ #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + if ((unsigned long)(res) >= (unsigned long)(-129)) { \ errno = -(res); \ res = -1; \ } \ -- cgit v1.2.3 From 32fc453e050822b013b6a1d92b60470999bd385c Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 2 Mar 2005 22:21:51 +0000 Subject: [ARM] Acorn expansion card core update. Add __iomem annotations and use iomem functions where appropriate. Separate out expansion card allocation/initialisation and freeing. Convert device attributes to be handled by driver core. Clean up deprecated function warnings for internal ecard_address usage. Signed-off-by: Russell King --- arch/arm/kernel/ecard.c | 216 +++++++++++++++++++++++++++--------------------- include/asm-arm/ecard.h | 15 +++- 2 files changed, 133 insertions(+), 98 deletions(-) (limited to 'include') diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 3f6b4b529aa9..a2e47627d76d 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -85,27 +85,21 @@ static struct expcard_blacklist __initdata blacklist[] = { }; asmlinkage extern int -ecard_loader_reset(volatile unsigned char *pa, loader_t loader); +ecard_loader_reset(unsigned long base, loader_t loader); asmlinkage extern int -ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader); +ecard_loader_read(int off, unsigned long base, loader_t loader); -static const struct ecard_id * -ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec); - -static inline unsigned short -ecard_getu16(unsigned char *v) +static inline unsigned short ecard_getu16(unsigned char *v) { return v[0] | v[1] << 8; } -static inline signed long -ecard_gets24(unsigned char *v) +static inline signed long ecard_gets24(unsigned char *v) { return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); } -static inline ecard_t * -slot_to_ecard(unsigned int slot) +static inline ecard_t *slot_to_ecard(unsigned int slot) { return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL; } @@ -122,26 +116,31 @@ slot_to_ecard(unsigned int slot) * From a security standpoint, we trust the card vendors. This * may be a misplaced trust. */ -#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) -#define POD_INT_ADDR(x) ((volatile unsigned char *)\ - ((BUS_ADDR((x)) - IO_BASE) + IO_START)) - static void ecard_task_reset(struct ecard_request *req) { struct expansion_card *ec = req->ec; - if (ec->loader) - ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader); + struct resource *res; + + res = ec->slot_no == 8 + ? &ec->resource[ECARD_RES_MEMC] + : ec->type == ECARD_EASI + ? &ec->resource[ECARD_RES_EASI] + : &ec->resource[ECARD_RES_IOCSYNC]; + + ecard_loader_reset(res->start, ec->loader); } static void ecard_task_readbytes(struct ecard_request *req) { - unsigned char *buf = (unsigned char *)req->buffer; - volatile unsigned char *base_addr = - (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr); + struct expansion_card *ec = req->ec; + unsigned char *buf = req->buffer; unsigned int len = req->length; unsigned int off = req->address; - if (req->ec->slot_no == 8) { + if (ec->slot_no == 8) { + void __iomem *base = (void __iomem *) + ec->resource[ECARD_RES_MEMC].start; + /* * The card maintains an index which increments the address * into a 4096-byte page on each access. We need to keep @@ -161,7 +160,7 @@ static void ecard_task_readbytes(struct ecard_request *req) * greater than the offset, reset the hardware index counter. */ if (off == 0 || index > off) { - *base_addr = 0; + writeb(0, base); index = 0; } @@ -170,21 +169,24 @@ static void ecard_task_readbytes(struct ecard_request *req) * required offset. The read bytes are discarded. */ while (index < off) { - unsigned char byte; - byte = base_addr[page]; + readb(base + page); index += 1; } while (len--) { - *buf++ = base_addr[page]; + *buf++ = readb(base + page); index += 1; } } else { + unsigned long base = (ec->type == ECARD_EASI + ? &ec->resource[ECARD_RES_EASI] + : &ec->resource[ECARD_RES_IOCSYNC])->start; + void __iomem *pbase = (void __iomem *)base; - if (!req->use_loader || !req->ec->loader) { + if (!req->use_loader || !ec->loader) { off *= 4; while (len--) { - *buf++ = base_addr[off]; + *buf++ = readb(pbase + off); off += 4; } } else { @@ -194,8 +196,8 @@ static void ecard_task_readbytes(struct ecard_request *req) * expansion card loader programs. */ *(unsigned long *)0x108 = 0; - *buf++ = ecard_loader_read(off++, base_addr, - req->ec->loader); + *buf++ = ecard_loader_read(off++, base, + ec->loader); } } } @@ -406,7 +408,7 @@ static void ecard_def_irq_disable(ecard_t *ec, int irqnr) static int ecard_def_irq_pending(ecard_t *ec) { - return !ec->irqmask || ec->irqaddr[0] & ec->irqmask; + return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask; } static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) @@ -421,7 +423,7 @@ static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr) static int ecard_def_fiq_pending(ecard_t *ec) { - return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask; + return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask; } static expansioncard_ops_t ecard_default_ops = { @@ -522,7 +524,7 @@ static void ecard_dump_irq_state(void) ec->ops->irqpending(ec) ? "" : "not "); else printk("irqaddr %p, mask = %02X, status = %02X\n", - ec->irqaddr, ec->irqmask, *ec->irqaddr); + ec->irqaddr, ec->irqmask, readb(ec->irqaddr)); } } @@ -675,7 +677,7 @@ static int __init ecard_probeirqhw(void) #define IO_EC_MEMC8_BASE 0 #endif -unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) +unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) { unsigned long address = 0; int slot = ec->slot_no; @@ -779,55 +781,89 @@ static void ecard_proc_init(void) get_ecard_dev_info); } -#define ec_set_resource(ec,nr,st,sz,flg) \ +#define ec_set_resource(ec,nr,st,sz) \ do { \ (ec)->resource[nr].name = ec->dev.bus_id; \ (ec)->resource[nr].start = st; \ (ec)->resource[nr].end = (st) + (sz) - 1; \ - (ec)->resource[nr].flags = flg; \ + (ec)->resource[nr].flags = IORESOURCE_MEM; \ } while (0) -static void __init ecard_init_resources(struct expansion_card *ec) +static void __init ecard_free_card(struct expansion_card *ec) +{ + int i; + + for (i = 0; i < ECARD_NUM_RESOURCES; i++) + if (ec->resource[i].flags) + release_resource(&ec->resource[i]); + + kfree(ec); +} + +static struct expansion_card *__init ecard_alloc_card(int type, int slot) { - unsigned long base = PODSLOT_IOC4_BASE; - unsigned int slot = ec->slot_no; + struct expansion_card *ec; + unsigned long base; int i; + ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); + if (!ec) { + ec = ERR_PTR(-ENOMEM); + goto nomem; + } + + memset(ec, 0, sizeof(ecard_t)); + + ec->slot_no = slot; + ec->type = type; + ec->irq = NO_IRQ; + ec->fiq = NO_IRQ; + ec->dma = NO_DMA; + ec->ops = &ecard_default_ops; + + snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); + ec->dev.parent = NULL; + ec->dev.bus = &ecard_bus_type; + ec->dev.dma_mask = &ec->dma_mask; + ec->dma_mask = (u64)0xffffffff; + if (slot < 4) { ec_set_resource(ec, ECARD_RES_MEMC, PODSLOT_MEMC_BASE + (slot << 14), - PODSLOT_MEMC_SIZE, IORESOURCE_MEM); - base = PODSLOT_IOC0_BASE; - } + PODSLOT_MEMC_SIZE); + base = PODSLOT_IOC0_BASE + (slot << 14); + } else + base = PODSLOT_IOC4_BASE + ((slot - 4) << 14); #ifdef CONFIG_ARCH_RPC if (slot < 8) { ec_set_resource(ec, ECARD_RES_EASI, PODSLOT_EASI_BASE + (slot << 24), - PODSLOT_EASI_SIZE, IORESOURCE_MEM); + PODSLOT_EASI_SIZE); } if (slot == 8) { - ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, - NETSLOT_SIZE, IORESOURCE_MEM); + ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE); } else #endif - for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) { + for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) ec_set_resource(ec, i + ECARD_RES_IOCSLOW, - base + (slot << 14) + (i << 19), - PODSLOT_IOC_SIZE, IORESOURCE_MEM); - } + base + (i << 19), PODSLOT_IOC_SIZE); for (i = 0; i < ECARD_NUM_RESOURCES; i++) { - if (ec->resource[i].start && + if (ec->resource[i].flags && request_resource(&iomem_resource, &ec->resource[i])) { printk(KERN_ERR "%s: resource(s) not available\n", ec->dev.bus_id); ec->resource[i].end -= ec->resource[i].start; ec->resource[i].start = 0; + ec->resource[i].flags = 0; } } + + nomem: + return ec; } static ssize_t ecard_show_irq(struct device *dev, char *buf) @@ -836,16 +872,12 @@ static ssize_t ecard_show_irq(struct device *dev, char *buf) return sprintf(buf, "%u\n", ec->irq); } -static DEVICE_ATTR(irq, S_IRUGO, ecard_show_irq, NULL); - static ssize_t ecard_show_dma(struct device *dev, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->dma); } -static DEVICE_ATTR(dma, S_IRUGO, ecard_show_dma, NULL); - static ssize_t ecard_show_resources(struct device *dev, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); @@ -861,23 +893,33 @@ static ssize_t ecard_show_resources(struct device *dev, char *buf) return str - buf; } -static DEVICE_ATTR(resource, S_IRUGO, ecard_show_resources, NULL); - static ssize_t ecard_show_vendor(struct device *dev, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->cid.manufacturer); } -static DEVICE_ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL); - static ssize_t ecard_show_device(struct device *dev, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->cid.product); } -static DEVICE_ATTR(device, S_IRUGO, ecard_show_device, NULL); +static ssize_t ecard_show_type(struct device *dev, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC"); +} + +static struct device_attribute ecard_dev_attrs[] = { + __ATTR(device, S_IRUGO, ecard_show_device, NULL), + __ATTR(dma, S_IRUGO, ecard_show_dma, NULL), + __ATTR(irq, S_IRUGO, ecard_show_irq, NULL), + __ATTR(resource, S_IRUGO, ecard_show_resources, NULL), + __ATTR(type, S_IRUGO, ecard_show_type, NULL), + __ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL), + __ATTR_NULL, +}; int ecard_request_resources(struct expansion_card *ec) @@ -927,21 +969,13 @@ ecard_probe(int slot, card_type_t type) ecard_t **ecp; ecard_t *ec; struct ex_ecid cid; - int i, rc = -ENOMEM; + int i, rc; - ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); - if (!ec) + ec = ecard_alloc_card(type, slot); + if (IS_ERR(ec)) { + rc = PTR_ERR(ec); goto nomem; - - memset(ec, 0, sizeof(ecard_t)); - - ec->slot_no = slot; - ec->type = type; - ec->irq = NO_IRQ; - ec->fiq = NO_IRQ; - ec->dma = NO_DMA; - ec->card_desc = NULL; - ec->ops = &ecard_default_ops; + } rc = -ENODEV; if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0) @@ -964,7 +998,7 @@ ecard_probe(int slot, card_type_t type) ec->cid.fiqmask = cid.r_fiqmask; ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); ec->fiqaddr = - ec->irqaddr = (unsigned char *)ioaddr(ec->podaddr); + ec->irqaddr = (void __iomem *)ioaddr(ec->podaddr); if (ec->cid.is) { ec->irqmask = ec->cid.irqmask; @@ -983,14 +1017,6 @@ ecard_probe(int slot, card_type_t type) break; } - snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); - ec->dev.parent = NULL; - ec->dev.bus = &ecard_bus_type; - ec->dev.dma_mask = &ec->dma_mask; - ec->dma_mask = (u64)0xffffffff; - - ecard_init_resources(ec); - /* * hook the interrupt handlers */ @@ -1017,17 +1043,12 @@ ecard_probe(int slot, card_type_t type) slot_to_expcard[slot] = ec; device_register(&ec->dev); - device_create_file(&ec->dev, &dev_attr_dma); - device_create_file(&ec->dev, &dev_attr_irq); - device_create_file(&ec->dev, &dev_attr_resource); - device_create_file(&ec->dev, &dev_attr_vendor); - device_create_file(&ec->dev, &dev_attr_device); return 0; -nodev: - kfree(ec); -nomem: + nodev: + ecard_free_card(ec); + nomem: return rc; } @@ -1128,9 +1149,15 @@ static void ecard_drv_shutdown(struct device *dev) if (drv->shutdown) drv->shutdown(ec); ecard_release(ec); - req.fn = ecard_task_reset; - req.ec = ec; - ecard_call(&req); + + /* + * If this card has a loader, call the reset handler. + */ + if (ec->loader) { + req.fn = ecard_task_reset; + req.ec = ec; + ecard_call(&req); + } } int ecard_register_driver(struct ecard_driver *drv) @@ -1164,8 +1191,9 @@ static int ecard_match(struct device *_dev, struct device_driver *_drv) } struct bus_type ecard_bus_type = { - .name = "ecard", - .match = ecard_match, + .name = "ecard", + .dev_attrs = ecard_dev_attrs, + .match = ecard_match, }; static int ecard_bus_init(void) @@ -1176,7 +1204,7 @@ static int ecard_bus_init(void) postcore_initcall(ecard_bus_init); EXPORT_SYMBOL(ecard_readchunk); -EXPORT_SYMBOL(ecard_address); +EXPORT_SYMBOL(__ecard_address); EXPORT_SYMBOL(ecard_register_driver); EXPORT_SYMBOL(ecard_remove_driver); EXPORT_SYMBOL(ecard_bus_type); diff --git a/include/asm-arm/ecard.h b/include/asm-arm/ecard.h index 358799f28df0..a0ae2b954d29 100644 --- a/include/asm-arm/ecard.h +++ b/include/asm-arm/ecard.h @@ -155,8 +155,8 @@ struct expansion_card { struct resource resource[ECARD_NUM_RESOURCES]; /* Public data */ - volatile unsigned char *irqaddr; /* address of IRQ register */ - volatile unsigned char *fiqaddr; /* address of FIQ register */ + void __iomem *irqaddr; /* address of IRQ register */ + void __iomem *fiqaddr; /* address of FIQ register */ unsigned char irqmask; /* IRQ mask */ unsigned char fiqmask; /* FIQ mask */ unsigned char claimed; /* Card claimed? */ @@ -207,9 +207,16 @@ struct in_chunk_dir { extern int ecard_readchunk (struct in_chunk_dir *cd, struct expansion_card *ec, int id, int num); /* - * Obtain the address of a card + * Obtain the address of a card. This returns the "old style" address + * and should no longer be used. */ -extern __deprecated unsigned int ecard_address (struct expansion_card *ec, card_type_t card_type, card_speed_t speed); +static inline unsigned int __deprecated +ecard_address(struct expansion_card *ec, card_type_t type, card_speed_t speed) +{ + extern unsigned int __ecard_address(struct expansion_card *, + card_type_t, card_speed_t); + return __ecard_address(ec, type, speed); +} /* * Request and release ecard resources -- cgit v1.2.3 From 4a5506940d40d563b503c4409e7b75eb1dc5997d Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Wed, 2 Mar 2005 23:20:52 +0000 Subject: [ARM PATCH] 2450/1: Add missing REG_OFFSET to ixp4xx platform.h header Patch from Deepak Saxena Patch 2449/1 depends on this since it removes REG_OFFSET from the individual board implementations. Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- include/asm-arm/arch-ixp4xx/platform.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include') diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h index d0e195b32953..3a626c03ea26 100644 --- a/include/asm-arm/arch-ixp4xx/platform.h +++ b/include/asm-arm/arch-ixp4xx/platform.h @@ -15,6 +15,12 @@ #include +#ifndef __ARMEB__ +#define REG_OFFSET 0 +#else +#define REG_OFFSET 3 +#endif + /* * Expansion bus memory regions */ -- cgit v1.2.3 From 592dd383dcdd82d6a971c5a5c4238dcedf0b2d8d Mon Sep 17 00:00:00 2001 From: John Lenz Date: Wed, 2 Mar 2005 23:39:59 +0000 Subject: [ARM PATCH] 2460/1: fix up resource usage on locomo Patch from John Lenz Add the list of devices on the locomo chip, and change around how resources and struct resource are used. There is only one struct resource for the entire locomo, but each driver will call request_mem_region on the pieces it is using. Secondly, add a few helper functions to locomo.c to control GPIOs and DAC. Signed-off-by: John Lenz Signed-off-by: Russell King --- arch/arm/common/locomo.c | 359 +++++++++++++++++++++++++++++++++++--- include/asm-arm/hardware/locomo.h | 224 ++++++++++++------------ 2 files changed, 443 insertions(+), 140 deletions(-) (limited to 'include') diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 34c8cf33ad9a..41f12658c8b4 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -34,11 +34,33 @@ #include +/* M62332 output channel selection */ +#define M62332_EVR_CH 1 /* M62332 volume channel number */ + /* 0 : CH.1 , 1 : CH. 2 */ +/* DAC send data */ +#define M62332_SLAVE_ADDR 0x4e /* Slave address */ +#define M62332_W_BIT 0x00 /* W bit (0 only) */ +#define M62332_SUB_ADDR 0x00 /* Sub address */ +#define M62332_A_BIT 0x00 /* A bit (0 only) */ + +/* DAC setup and hold times (expressed in us) */ +#define DAC_BUS_FREE_TIME 5 /* 4.7 us */ +#define DAC_START_SETUP_TIME 5 /* 4.7 us */ +#define DAC_STOP_SETUP_TIME 4 /* 4.0 us */ +#define DAC_START_HOLD_TIME 5 /* 4.7 us */ +#define DAC_SCL_LOW_HOLD_TIME 5 /* 4.7 us */ +#define DAC_SCL_HIGH_HOLD_TIME 4 /* 4.0 us */ +#define DAC_DATA_SETUP_TIME 1 /* 250 ns */ +#define DAC_DATA_HOLD_TIME 1 /* 300 ns */ +#define DAC_LOW_SETUP_TIME 1 /* 300 ns */ +#define DAC_HIGH_SETUP_TIME 1 /* 1000 ns */ + /* the following is the overall data for the locomo chip */ struct locomo { struct device *dev; unsigned long phys; unsigned int irq; + spinlock_t lock; void *base; }; @@ -50,7 +72,57 @@ struct locomo_dev_info { const char * name; }; +/* All the locomo devices. If offset is non-zero, the mapbase for the + * locomo_dev will be set to the chip base plus offset. If offset is + * zero, then the mapbase for the locomo_dev will be set to zero. An + * offset of zero means the device only uses GPIOs or other helper + * functions inside this file */ static struct locomo_dev_info locomo_devices[] = { + { + .devid = LOCOMO_DEVID_KEYBOARD, + .irq = { + IRQ_LOCOMO_KEY, + }, + .name = "locomo-keyboard", + .offset = LOCOMO_KEYBOARD, + .length = 16, + }, + { + .devid = LOCOMO_DEVID_FRONTLIGHT, + .irq = {}, + .name = "locomo-frontlight", + .offset = LOCOMO_FRONTLIGHT, + .length = 8, + + }, + { + .devid = LOCOMO_DEVID_BACKLIGHT, + .irq = {}, + .name = "locomo-backlight", + .offset = LOCOMO_BACKLIGHT, + .length = 8, + }, + { + .devid = LOCOMO_DEVID_AUDIO, + .irq = {}, + .name = "locomo-audio", + .offset = LOCOMO_AUDIO, + .length = 4, + }, + { + .devid = LOCOMO_DEVID_LED, + .irq = {}, + .name = "locomo-led", + .offset = LOCOMO_LED, + .length = 8, + }, + { + .devid = LOCOMO_DEVID_UART, + .irq = {}, + .name = "locomo-uart", + .offset = 0, + .length = 0, + }, }; @@ -146,7 +218,7 @@ static void locomo_key_handler(unsigned int irq, struct irqdesc *desc, struct irqdesc *d; void *mapbase = get_irq_chipdata(irq); - if (locomo_readl(mapbase + LOCOMO_KIC) & 0x0001) { + if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) { d = irq_desc + LOCOMO_IRQ_KEY_START; d->handle(LOCOMO_IRQ_KEY_START, d, regs); } @@ -156,27 +228,27 @@ static void locomo_key_ack_irq(unsigned int irq) { void *mapbase = get_irq_chipdata(irq); unsigned int r; - r = locomo_readl(mapbase + LOCOMO_KIC); + r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); r &= ~(0x0100 << (irq - LOCOMO_IRQ_KEY_START)); - locomo_writel(r, mapbase + LOCOMO_KIC); + locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); } static void locomo_key_mask_irq(unsigned int irq) { void *mapbase = get_irq_chipdata(irq); unsigned int r; - r = locomo_readl(mapbase + LOCOMO_KIC); + r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); r &= ~(0x0010 << (irq - LOCOMO_IRQ_KEY_START)); - locomo_writel(r, mapbase + LOCOMO_KIC); + locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); } static void locomo_key_unmask_irq(unsigned int irq) { void *mapbase = get_irq_chipdata(irq); unsigned int r; - r = locomo_readl(mapbase + LOCOMO_KIC); + r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); r |= (0x0010 << (irq - LOCOMO_IRQ_KEY_START)); - locomo_writel(r, mapbase + LOCOMO_KIC); + locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC); } static struct irqchip locomo_key_chip = { @@ -421,13 +493,11 @@ static void locomo_dev_release(struct device *_dev) { struct locomo_dev *dev = LOCOMO_DEV(_dev); - release_resource(&dev->res); kfree(dev); } static int -locomo_init_one_child(struct locomo *lchip, struct resource *parent, - struct locomo_dev_info *info) +locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info) { struct locomo_dev *dev; int ret; @@ -454,25 +524,17 @@ locomo_init_one_child(struct locomo *lchip, struct resource *parent, dev->dev.bus = &locomo_bus_type; dev->dev.release = locomo_dev_release; dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask; - dev->res.start = lchip->phys + info->offset; - dev->res.end = dev->res.start + info->length; - dev->res.name = dev->dev.bus_id; - dev->res.flags = IORESOURCE_MEM; - dev->mapbase = lchip->base + info->offset; - memmove(dev->irq, info->irq, sizeof(dev->irq)); - if (info->length) { - ret = request_resource(parent, &dev->res); - if (ret) { - printk("LoCoMo: failed to allocate resource for %s\n", - dev->res.name); - goto out; - } - } + if (info->offset) + dev->mapbase = lchip->base + info->offset; + else + dev->mapbase = 0; + dev->length = info->length; + + memmove(dev->irq, info->irq, sizeof(dev->irq)); ret = device_register(&dev->dev); if (ret) { - release_resource(&dev->res); out: kfree(dev); } @@ -504,6 +566,8 @@ __locomo_probe(struct device *me, struct resource *mem, int irq) memset(lchip, 0, sizeof(struct locomo)); + spin_lock_init(&lchip->lock); + lchip->dev = me; dev_set_drvdata(lchip->dev, lchip); @@ -523,7 +587,7 @@ __locomo_probe(struct device *me, struct resource *mem, int irq) /* locomo initialize */ locomo_writel(0, lchip->base + LOCOMO_ICR); /* KEYBOARD */ - locomo_writel(0, lchip->base + LOCOMO_KIC); + locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); /* GPIO */ locomo_writel(0, lchip->base + LOCOMO_GPO); @@ -534,8 +598,8 @@ __locomo_probe(struct device *me, struct resource *mem, int irq) locomo_writel(0, lchip->base + LOCOMO_GIE); /* FrontLight */ - locomo_writel(0, lchip->base + LOCOMO_ALS); - locomo_writel(0, lchip->base + LOCOMO_ALD); + locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); + locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD); /* Longtime timer */ locomo_writel(0, lchip->base + LOCOMO_LTINT); /* SPI */ @@ -578,7 +642,7 @@ __locomo_probe(struct device *me, struct resource *mem, int irq) locomo_setup_irq(lchip); for (i = 0; i < ARRAY_SIZE(locomo_devices); i++) - locomo_init_one_child(lchip, mem, &locomo_devices[i]); + locomo_init_one_child(lchip, &locomo_devices[i]); return 0; @@ -654,6 +718,238 @@ static inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev) return (struct locomo *)dev_get_drvdata(ldev->dev.parent); } +void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir) +{ + struct locomo *lchip = locomo_chip_driver(ldev); + unsigned long flags; + unsigned int r; + + spin_lock_irqsave(&lchip->lock, flags); + + r = locomo_readl(lchip->base + LOCOMO_GPD); + r &= ~bits; + locomo_writel(r, lchip->base + LOCOMO_GPD); + + r = locomo_readl(lchip->base + LOCOMO_GPE); + if (dir) + r |= bits; + else + r &= ~bits; + locomo_writel(r, lchip->base + LOCOMO_GPE); + + spin_unlock_irqrestore(&lchip->lock, flags); +} + +unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits) +{ + struct locomo *lchip = locomo_chip_driver(ldev); + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&lchip->lock, flags); + ret = locomo_readl(lchip->base + LOCOMO_GPL); + spin_unlock_irqrestore(&lchip->lock, flags); + + ret &= bits; + return ret; +} + +unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits) +{ + struct locomo *lchip = locomo_chip_driver(ldev); + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&lchip->lock, flags); + ret = locomo_readl(lchip->base + LOCOMO_GPO); + spin_unlock_irqrestore(&lchip->lock, flags); + + ret &= bits; + return ret; +} + +void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set) +{ + struct locomo *lchip = locomo_chip_driver(ldev); + unsigned long flags; + unsigned int r; + + spin_lock_irqsave(&lchip->lock, flags); + + r = locomo_readl(lchip->base + LOCOMO_GPO); + if (set) + r |= bits; + else + r &= ~bits; + locomo_writel(r, lchip->base + LOCOMO_GPO); + + spin_unlock_irqrestore(&lchip->lock, flags); +} + +static void locomo_m62332_sendbit(void *mapbase, int bit) +{ + unsigned int r; + + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SCLOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SCLOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ + + if (bit & 1) { + r = locomo_readl(mapbase + LOCOMO_DAC); + r |= LOCOMO_DAC_SDAOEB; + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ + } else { + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SDAOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + } + + udelay(DAC_DATA_SETUP_TIME); /* 250 nsec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r |= LOCOMO_DAC_SCLOEB; + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ + udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ +} + +void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel) +{ + struct locomo *lchip = locomo_chip_driver(ldev); + int i; + unsigned char data; + unsigned int r; + void *mapbase = lchip->base; + unsigned long flags; + + spin_lock_irqsave(&lchip->lock, flags); + + /* Start */ + udelay(DAC_BUS_FREE_TIME); /* 5.0 usec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ + udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SDAOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_START_HOLD_TIME); /* 5.0 usec */ + udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ + + /* Send slave address and W bit (LSB is W bit) */ + data = (M62332_SLAVE_ADDR << 1) | M62332_W_BIT; + for (i = 1; i <= 8; i++) { + locomo_m62332_sendbit(mapbase, data >> (8 - i)); + } + + /* Check A bit */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SCLOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SDAOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r |= LOCOMO_DAC_SCLOEB; + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ + udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ + if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ + printk(KERN_WARNING "locomo: m62332_senddata Error 1\n"); + return; + } + + /* Send Sub address (LSB is channel select) */ + /* channel = 0 : ch1 select */ + /* = 1 : ch2 select */ + data = M62332_SUB_ADDR + channel; + for (i = 1; i <= 8; i++) { + locomo_m62332_sendbit(mapbase, data >> (8 - i)); + } + + /* Check A bit */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SCLOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SDAOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r |= LOCOMO_DAC_SCLOEB; + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ + udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ + if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ + printk(KERN_WARNING "locomo: m62332_senddata Error 2\n"); + return; + } + + /* Send DAC data */ + for (i = 1; i <= 8; i++) { + locomo_m62332_sendbit(mapbase, dac_data >> (8 - i)); + } + + /* Check A bit */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SCLOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SDAOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r |= LOCOMO_DAC_SCLOEB; + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ + udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ + if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ + printk(KERN_WARNING "locomo: m62332_senddata Error 3\n"); + return; + } + + /* stop */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r &= ~(LOCOMO_DAC_SCLOEB); + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ + udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r |= LOCOMO_DAC_SCLOEB; + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ + udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ + r = locomo_readl(mapbase + LOCOMO_DAC); + r |= LOCOMO_DAC_SDAOEB; + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ + udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ + + r = locomo_readl(mapbase + LOCOMO_DAC); + r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; + locomo_writel(r, mapbase + LOCOMO_DAC); + udelay(DAC_LOW_SETUP_TIME); /* 1000 nsec */ + udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ + + spin_unlock_irqrestore(&lchip->lock, flags); +} + /* * LoCoMo "Register Access Bus." * @@ -755,3 +1051,8 @@ MODULE_AUTHOR("John Lenz "); EXPORT_SYMBOL(locomo_driver_register); EXPORT_SYMBOL(locomo_driver_unregister); +EXPORT_SYMBOL(locomo_gpio_set_dir); +EXPORT_SYMBOL(locomo_gpio_read_level); +EXPORT_SYMBOL(locomo_gpio_read_output); +EXPORT_SYMBOL(locomo_gpio_write); +EXPORT_SYMBOL(locomo_m62332_senddata); diff --git a/include/asm-arm/hardware/locomo.h b/include/asm-arm/hardware/locomo.h index 98d6da2dc424..5f9218c15142 100644 --- a/include/asm-arm/hardware/locomo.h +++ b/include/asm-arm/hardware/locomo.h @@ -35,146 +35,139 @@ #define LOCOMO_MCSX3 0x1c /* Touch panel controller */ -#define LOCOMO_ASD 0x20 /* AD start delay */ -#define LOCOMO_HSD 0x28 /* HSYS delay */ -#define LOCOMO_HSC 0x2c /* HSYS period */ -#define LOCOMO_TADC 0x30 /* tablet ADC clock */ +#define LOCOMO_ASD 0x20 /* AD start delay */ +#define LOCOMO_HSD 0x28 /* HSYS delay */ +#define LOCOMO_HSC 0x2c /* HSYS period */ +#define LOCOMO_TADC 0x30 /* tablet ADC clock */ -/* TFT signal */ -#define LOCOMO_TC 0x38 /* TFT control signal */ -#define LOCOMO_CPSD 0x3c /* CPS delay */ - -/* Key controller */ -#define LOCOMO_KIB 0x40 /* KIB level */ -#define LOCOMO_KSC 0x44 /* KSTRB control */ -#define LOCOMO_KCMD 0x48 /* KSTRB command */ -#define LOCOMO_KIC 0x4c /* Key interrupt */ - -/* Audio clock */ -#define LOCOMO_ACC 0x54 - -/* SPI interface */ -#define LOCOMO_SPIMD 0x60 /* SPI mode setting */ -#define LOCOMO_SPICT 0x64 /* SPI mode control */ -#define LOCOMO_SPIST 0x68 /* SPI status */ -#define LOCOMO_SPIIS 0x70 /* SPI interrupt status */ -#define LOCOMO_SPIWE 0x74 /* SPI interrupt status write enable */ -#define LOCOMO_SPIIE 0x78 /* SPI interrupt enable */ -#define LOCOMO_SPIIR 0x7c /* SPI interrupt request */ -#define LOCOMO_SPITD 0x80 /* SPI transfer data write */ -#define LOCOMO_SPIRD 0x84 /* SPI receive data read */ -#define LOCOMO_SPITS 0x88 /* SPI transfer data shift */ -#define LOCOMO_SPIRS 0x8C /* SPI receive data shift */ - -#define LOCOMO_SPI_TEND (1 << 3) /* Transfer end bit */ -#define LOCOMO_SPI_OVRN (1 << 2) /* Over Run bit */ -#define LOCOMO_SPI_RFW (1 << 1) /* write buffer bit */ -#define LOCOMO_SPI_RFR (1) /* read buffer bit */ - -/* GPIO */ -#define LOCOMO_GPD 0x90 /* GPIO direction */ -#define LOCOMO_GPE 0x94 /* GPIO input enable */ -#define LOCOMO_GPL 0x98 /* GPIO level */ -#define LOCOMO_GPO 0x9c /* GPIO out data setteing */ -#define LOCOMO_GRIE 0xa0 /* GPIO rise detection */ -#define LOCOMO_GFIE 0xa4 /* GPIO fall detection */ -#define LOCOMO_GIS 0xa8 /* GPIO edge detection status */ -#define LOCOMO_GWE 0xac /* GPIO status write enable */ -#define LOCOMO_GIE 0xb0 /* GPIO interrupt enable */ -#define LOCOMO_GIR 0xb4 /* GPIO interrupt request */ - -#define LOCOMO_GPIO0 (1<<0) -#define LOCOMO_GPIO1 (1<<1) -#define LOCOMO_GPIO2 (1<<2) -#define LOCOMO_GPIO3 (1<<3) -#define LOCOMO_GPIO4 (1<<4) -#define LOCOMO_GPIO5 (1<<5) -#define LOCOMO_GPIO6 (1<<6) -#define LOCOMO_GPIO7 (1<<7) -#define LOCOMO_GPIO8 (1<<8) -#define LOCOMO_GPIO9 (1<<9) -#define LOCOMO_GPIO10 (1<<10) -#define LOCOMO_GPIO11 (1<<11) -#define LOCOMO_GPIO12 (1<<12) -#define LOCOMO_GPIO13 (1<<13) -#define LOCOMO_GPIO14 (1<<14) -#define LOCOMO_GPIO15 (1<<15) - -/* Front light adjustment controller */ -#define LOCOMO_ALS 0xc8 /* Adjust light cycle */ -#define LOCOMO_ALD 0xcc /* Adjust light duty */ - -/* PCM audio interface */ -#define LOCOMO_PAIF 0xd0 /* Long time timer */ -#define LOCOMO_LTC 0xd8 /* LTC interrupt setting */ -#define LOCOMO_LTINT 0xdc /* LTC interrupt */ +#define LOCOMO_LTC 0xd8 /* LTC interrupt setting */ +#define LOCOMO_LTINT 0xdc /* LTC interrupt */ /* DAC control signal for LCD (COMADJ ) */ -#define LOCOMO_DAC 0xe0 - +#define LOCOMO_DAC 0xe0 /* DAC control */ #define LOCOMO_DAC_SCLOEB 0x08 /* SCL pin output data */ #define LOCOMO_DAC_TEST 0x04 /* Test bit */ #define LOCOMO_DAC_SDA 0x02 /* SDA pin level (read-only) */ #define LOCOMO_DAC_SDAOEB 0x01 /* SDA pin output data */ -/* LED controller */ -#define LOCOMO_LPT0 0xe8 /* LEDPWM0 timer */ -#define LOCOMO_LPT1 0xec /* LEDPWM1 timer */ +/* SPI interface */ +#define LOCOMO_SPIMD 0x60 /* SPI mode setting */ +#define LOCOMO_SPICT 0x64 /* SPI mode control */ +#define LOCOMO_SPIST 0x68 /* SPI status */ +#define LOCOMO_SPIIS 0x70 /* SPI interrupt status */ +#define LOCOMO_SPIWE 0x74 /* SPI interrupt status write enable */ +#define LOCOMO_SPIIE 0x78 /* SPI interrupt enable */ +#define LOCOMO_SPIIR 0x7c /* SPI interrupt request */ +#define LOCOMO_SPITD 0x80 /* SPI transfer data write */ +#define LOCOMO_SPIRD 0x84 /* SPI receive data read */ +#define LOCOMO_SPITS 0x88 /* SPI transfer data shift */ +#define LOCOMO_SPIRS 0x8C /* SPI receive data shift */ +#define LOCOMO_SPI_TEND (1 << 3) /* Transfer end bit */ +#define LOCOMO_SPI_OVRN (1 << 2) /* Over Run bit */ +#define LOCOMO_SPI_RFW (1 << 1) /* write buffer bit */ +#define LOCOMO_SPI_RFR (1) /* read buffer bit */ -#define LOCOMO_LPT_TOFH 0x80 /* */ -#define LOCOMO_LPT_TOFL 0x08 /* */ -#define LOCOMO_LPT_TOH(TOH) ((TOH & 0x7) << 4) /* */ -#define LOCOMO_LPT_TOL(TOL) ((TOL & 0x7)) /* */ +/* GPIO */ +#define LOCOMO_GPD 0x90 /* GPIO direction */ +#define LOCOMO_GPE 0x94 /* GPIO input enable */ +#define LOCOMO_GPL 0x98 /* GPIO level */ +#define LOCOMO_GPO 0x9c /* GPIO out data setteing */ +#define LOCOMO_GRIE 0xa0 /* GPIO rise detection */ +#define LOCOMO_GFIE 0xa4 /* GPIO fall detection */ +#define LOCOMO_GIS 0xa8 /* GPIO edge detection status */ +#define LOCOMO_GWE 0xac /* GPIO status write enable */ +#define LOCOMO_GIE 0xb0 /* GPIO interrupt enable */ +#define LOCOMO_GIR 0xb4 /* GPIO interrupt request */ +#define LOCOMO_GPIO(Nb) (0x01 << (Nb)) +#define LOCOMO_GPIO_RTS LOCOMO_GPIO(0) +#define LOCOMO_GPIO_CTS LOCOMO_GPIO(1) +#define LOCOMO_GPIO_DSR LOCOMO_GPIO(2) +#define LOCOMO_GPIO_DTR LOCOMO_GPIO(3) +#define LOCOMO_GPIO_LCD_VSHA_ON LOCOMO_GPIO(4) +#define LOCOMO_GPIO_LCD_VSHD_ON LOCOMO_GPIO(5) +#define LOCOMO_GPIO_LCD_VEE_ON LOCOMO_GPIO(6) +#define LOCOMO_GPIO_LCD_MOD LOCOMO_GPIO(7) +#define LOCOMO_GPIO_DAC_ON LOCOMO_GPIO(8) +#define LOCOMO_GPIO_FL_VR LOCOMO_GPIO(9) +#define LOCOMO_GPIO_DAC_SDATA LOCOMO_GPIO(10) +#define LOCOMO_GPIO_DAC_SCK LOCOMO_GPIO(11) +#define LOCOMO_GPIO_DAC_SLOAD LOCOMO_GPIO(12) + +/* Start the definitions of the devices. Each device has an initial + * base address and a series of offsets from that base address. */ + +/* Keyboard controller */ +#define LOCOMO_KEYBOARD 0x40 +#define LOCOMO_KIB 0x00 /* KIB level */ +#define LOCOMO_KSC 0x04 /* KSTRB control */ +#define LOCOMO_KCMD 0x08 /* KSTRB command */ +#define LOCOMO_KIC 0x0c /* Key interrupt */ +/* Front light adjustment controller */ +#define LOCOMO_FRONTLIGHT 0xc8 +#define LOCOMO_ALS 0x00 /* Adjust light cycle */ +#define LOCOMO_ALD 0x04 /* Adjust light duty */ + +/* Backlight controller: TFT signal */ +#define LOCOMO_BACKLIGHT 0x38 +#define LOCOMO_TC 0x00 /* TFT control signal */ +#define LOCOMO_CPSD 0x04 /* CPS delay */ + +/* Audio controller */ +#define LOCOMO_AUDIO 0x54 +#define LOCOMO_ACC 0x00 /* Audio clock */ +#define LOCOMO_PAIF 0x7C /* PCM audio interface */ /* Audio clock */ -#define LOCOMO_ACC_XON 0x80 /* */ -#define LOCOMO_ACC_XEN 0x40 /* */ -#define LOCOMO_ACC_XSEL0 0x00 /* */ -#define LOCOMO_ACC_XSEL1 0x20 /* */ -#define LOCOMO_ACC_MCLKEN 0x10 /* */ -#define LOCOMO_ACC_64FSEN 0x08 /* */ +#define LOCOMO_ACC_XON 0x80 +#define LOCOMO_ACC_XEN 0x40 +#define LOCOMO_ACC_XSEL0 0x00 +#define LOCOMO_ACC_XSEL1 0x20 +#define LOCOMO_ACC_MCLKEN 0x10 +#define LOCOMO_ACC_64FSEN 0x08 #define LOCOMO_ACC_CLKSEL000 0x00 /* mclk 2 */ #define LOCOMO_ACC_CLKSEL001 0x01 /* mclk 3 */ #define LOCOMO_ACC_CLKSEL010 0x02 /* mclk 4 */ #define LOCOMO_ACC_CLKSEL011 0x03 /* mclk 6 */ #define LOCOMO_ACC_CLKSEL100 0x04 /* mclk 8 */ #define LOCOMO_ACC_CLKSEL101 0x05 /* mclk 12 */ - /* PCM audio interface */ -#define LOCOMO_PAIF_SCINV 0x20 /* */ -#define LOCOMO_PAIF_SCEN 0x10 /* */ -#define LOCOMO_PAIF_LRCRST 0x08 /* */ -#define LOCOMO_PAIF_LRCEVE 0x04 /* */ -#define LOCOMO_PAIF_LRCINV 0x02 /* */ -#define LOCOMO_PAIF_LRCEN 0x01 /* */ +#define LOCOMO_PAIF_SCINV 0x20 +#define LOCOMO_PAIF_SCEN 0x10 +#define LOCOMO_PAIF_LRCRST 0x08 +#define LOCOMO_PAIF_LRCEVE 0x04 +#define LOCOMO_PAIF_LRCINV 0x02 +#define LOCOMO_PAIF_LRCEN 0x01 -/* GPIO */ -#define LOCOMO_GPIO(Nb) (0x01 << (Nb)) /* LoCoMo GPIO [0...15] */ -#define LOCOMO_GPIO_RTS LOCOMO_GPIO(0) /* LoCoMo GPIO [0] */ -#define LOCOMO_GPIO_CTS LOCOMO_GPIO(1) /* LoCoMo GPIO [1] */ -#define LOCOMO_GPIO_DSR LOCOMO_GPIO(2) /* LoCoMo GPIO [2] */ -#define LOCOMO_GPIO_DTR LOCOMO_GPIO(3) /* LoCoMo GPIO [3] */ -#define LOCOMO_GPIO_LCD_VSHA_ON LOCOMO_GPIO(4) /* LoCoMo GPIO [4] */ -#define LOCOMO_GPIO_LCD_VSHD_ON LOCOMO_GPIO(5) /* LoCoMo GPIO [5] */ -#define LOCOMO_GPIO_LCD_VEE_ON LOCOMO_GPIO(6) /* LoCoMo GPIO [6] */ -#define LOCOMO_GPIO_LCD_MOD LOCOMO_GPIO(7) /* LoCoMo GPIO [7] */ -#define LOCOMO_GPIO_DAC_ON LOCOMO_GPIO(8) /* LoCoMo GPIO [8] */ -#define LOCOMO_GPIO_FL_VR LOCOMO_GPIO(9) /* LoCoMo GPIO [9] */ -#define LOCOMO_GPIO_DAC_SDATA LOCOMO_GPIO(10) /* LoCoMo GPIO [10] */ -#define LOCOMO_GPIO_DAC_SCK LOCOMO_GPIO(11) /* LoCoMo GPIO [11] */ -#define LOCOMO_GPIO_DAC_SLOAD LOCOMO_GPIO(12) /* LoCoMo GPIO [12] */ +/* LED controller */ +#define LOCOMO_LED 0xe8 +#define LOCOMO_LPT0 0x00 +#define LOCOMO_LPT1 0x04 +/* LED control */ +#define LOCOMO_LPT_TOFH 0x80 +#define LOCOMO_LPT_TOFL 0x08 +#define LOCOMO_LPT_TOH(TOH) ((TOH & 0x7) << 4) +#define LOCOMO_LPT_TOL(TOL) ((TOL & 0x7)) extern struct bus_type locomo_bus_type; +#define LOCOMO_DEVID_KEYBOARD 0 +#define LOCOMO_DEVID_FRONTLIGHT 1 +#define LOCOMO_DEVID_BACKLIGHT 2 +#define LOCOMO_DEVID_AUDIO 3 +#define LOCOMO_DEVID_LED 4 +#define LOCOMO_DEVID_UART 5 + struct locomo_dev { struct device dev; unsigned int devid; - struct resource res; - void *mapbase; unsigned int irq[1]; + + void *mapbase; + unsigned long length; + u64 dma_mask; }; @@ -201,4 +194,13 @@ void locomo_lcd_power(struct locomo_dev *, int, unsigned int); int locomo_driver_register(struct locomo_driver *); void locomo_driver_unregister(struct locomo_driver *); +/* GPIO control functions */ +void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir); +unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits); +unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits); +void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set); + +/* M62332 control function */ +void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel); + #endif -- cgit v1.2.3 From 6d5611bb064c3d80984f8aaa865730e239732b47 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 3 Mar 2005 00:18:41 +0000 Subject: [ARM PATCH] 2467/1: S3C2440 - camera interface device Patch from Ben Dooks Add s3c2440 camera interface device definition Patch from Guillaume GOURAT Signed-off-by: Guillaume GOURAT Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/devs.c | 36 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-s3c2410/devs.h | 12 ++++++++++++ include/asm-arm/arch-s3c2410/irqs.h | 4 +++- include/asm-arm/arch-s3c2410/map.h | 5 +++++ 4 files changed, 56 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c index b1826df99159..d6f1fd8f9977 100644 --- a/arch/arm/mach-s3c2410/devs.c +++ b/arch/arm/mach-s3c2410/devs.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. * * Modifications: + * 10-Feb-2005 BJD Added camera from guillaume.gourat@nexvision.tv * 29-Aug-2004 BJD Added timers 0 through 3 * 29-Aug-2004 BJD Changed index of devices we only have one of to -1 * 21-Aug-2004 BJD Added IRQ_TICK to RTC resources @@ -446,3 +447,38 @@ struct platform_device s3c_device_timer3 = { }; EXPORT_SYMBOL(s3c_device_timer3); + +#ifdef CONFIG_CPU_S3C2440 + +/* Camif Controller */ + +static struct resource s3c_camif_resource[] = { + [0] = { + .start = S3C2440_PA_CAMIF, + .end = S3C2440_PA_CAMIF + S3C2440_SZ_CAMIF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_CAM, + .end = IRQ_CAM, + .flags = IORESOURCE_IRQ, + } + +}; + +static u64 s3c_device_camif_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_camif = { + .name = "s3c2440-camif", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_camif_resource), + .resource = s3c_camif_resource, + .dev = { + .dma_mask = &s3c_device_camif_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +EXPORT_SYMBOL(s3c_device_camif); + +#endif // CONFIG_CPU_S32440 diff --git a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h index 08a4416595f8..d6328f96728b 100644 --- a/arch/arm/mach-s3c2410/devs.h +++ b/arch/arm/mach-s3c2410/devs.h @@ -12,7 +12,11 @@ * Modifications: * 18-Aug-2004 BJD Created initial version * 27-Aug-2004 BJD Added timers 0 through 3 + * 10-Feb-2005 BJD Added camera from guillaume.gourat@nexvision.tv */ +#include + +extern struct platform_device *s3c24xx_uart_devs[]; extern struct platform_device s3c_device_usb; extern struct platform_device s3c_device_lcd; @@ -34,3 +38,11 @@ extern struct platform_device s3c_device_timer2; extern struct platform_device s3c_device_timer3; extern struct platform_device s3c_device_usbgadget; + +/* s3c2440 specific devices */ + +#ifdef CONFIG_CPU_S3C2440 + +extern struct platform_device s3c_device_camif; + +#endif diff --git a/include/asm-arm/arch-s3c2410/irqs.h b/include/asm-arm/arch-s3c2410/irqs.h index 0a05189899b9..e914da46c0e7 100644 --- a/include/asm-arm/arch-s3c2410/irqs.h +++ b/include/asm-arm/arch-s3c2410/irqs.h @@ -11,6 +11,7 @@ * 12-May-2003 BJD Created file * 08-Jan-2003 BJD Linux 2.6.0 version, moved BAST bits out * 12-Mar-2004 BJD Fixed bug in header protection + * 10-Feb-2005 BJD Added camera IRQ from guillaume.gourat@nexvision.tv */ @@ -35,7 +36,8 @@ #define IRQ_EINT3 S3C2410_IRQ(3) #define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */ #define IRQ_EINT8t23 S3C2410_IRQ(5) -#define IRQ_RESERVED6 S3C2410_IRQ(6) +#define IRQ_RESERVED6 S3C2410_IRQ(6) /* for s3c2410 */ +#define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440 */ #define IRQ_BATT_FLT S3C2410_IRQ(7) #define IRQ_TICK S3C2410_IRQ(8) /* 24 */ #define IRQ_WDT S3C2410_IRQ(9) diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h index 4be0bf44b5a0..17ea5fcdc38c 100644 --- a/include/asm-arm/arch-s3c2410/map.h +++ b/include/asm-arm/arch-s3c2410/map.h @@ -12,6 +12,7 @@ * Changelog: * 12-May-2003 BJD Created file * 06-Jan-2003 BJD Linux 2.6.0 version, moved bast specifics out + * 10-Feb-2005 BJD Added CAMIF definition from guillaume.gourat@nexvision.tv */ #ifndef __ASM_ARCH_MAP_H @@ -124,6 +125,10 @@ #define S3C2410_PA_SDI (0x5A000000) #define S3C2410_SZ_SDI SZ_1M +/* CAMIF */ +#define S3C2440_PA_CAMIF (0x4F000000) +#define S3C2440_SZ_CAMIF SZ_1M + /* ISA style IO, for each machine to sort out mappings for, if it * implements it. We reserve two 16M regions for ISA. */ -- cgit v1.2.3 From ff21ec427405a8dbd6961da051b54ebc9f4eea11 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 3 Mar 2005 00:37:40 +0000 Subject: [ARM PATCH] 2469/1: S3C2410 - add S3C2410_TCFG1_MUX4_SHIFT definition Patch from Ben Dooks Add missing S3C2410_TCFG1_MUX4_SHIFT Patch from Guillaume Gourat Signed-off-by: Guillaume GOURAT Signed-off-by: Ben Dooks Signed-off-by: Russell King --- include/asm-arm/arch-s3c2410/regs-timer.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/asm-arm/arch-s3c2410/regs-timer.h b/include/asm-arm/arch-s3c2410/regs-timer.h index b5b4aaf3dbf9..d93c35d7f690 100644 --- a/include/asm-arm/arch-s3c2410/regs-timer.h +++ b/include/asm-arm/arch-s3c2410/regs-timer.h @@ -13,6 +13,7 @@ * 05-06-2003 BJD Created file * 26-06-2003 BJD Added more timer definitions to mux / control * 12-03-2004 BJD Updated include protection + * 10-02-2005 BJD Added S3C2410_TCFG1_MUX4_SHIFT (Guillaume Gourat) */ @@ -38,6 +39,7 @@ #define S3C2410_TCFG1_MUX4_DIV16 (3<<16) #define S3C2410_TCFG1_MUX4_TCLK1 (4<<16) #define S3C2410_TCFG1_MUX4_MASK (15<<16) +#define S3C2410_TCFG1_MUX4_SHIFT (16) #define S3C2410_TCFG1_MUX3_DIV2 (0<<12) #define S3C2410_TCFG1_MUX3_DIV4 (1<<12) -- cgit v1.2.3 From 5063dd9d9f91c42bdf7081fb85a808c06baad895 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 3 Mar 2005 01:16:06 +0000 Subject: [ARM PATCH] 2482/1: IXP2000 - header cleanup Patch from Ben Dooks fix the following problems: lib/iomap.c:140: warning: passing arg 1 of `__raw_readsb' makes pointer from integer without a cast lib/iomap.c:156: warning: passing arg 1 of `__raw_writesb' makes pointer from integer without a cast include/asm-arm/arch-ixp2000/io.h modified to have (void __iomem *) in front of the alignment code include/asm/arch/system.h:22: warning: `cli' is deprecated (declared at include/linux/interrupt.h:65) cli() replace by local_irq_disable arch/arm/mach-ixp2000/ixdp2x01.c:116: warning: passing arg 1 of `ixp2000_reg_write' from incompatible pointer type arch/arm/mach-ixp2000/ixdp2x01.c:117: warning: passing arg 1 of `ixp2000_reg_write' from incompatible pointer type fixed definition of the cpld registers IXDP2X01_CPLD_VIRT_REG() Signed-off-by: Ben DooksLooks okay. Test-booted on ENP-2611, no problem. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- include/asm-arm/arch-ixp2000/io.h | 4 ++-- include/asm-arm/arch-ixp2000/ixdp2x01.h | 2 +- include/asm-arm/arch-ixp2000/system.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h index d6971efbd583..571dbbcd8521 100644 --- a/include/asm-arm/arch-ixp2000/io.h +++ b/include/asm-arm/arch-ixp2000/io.h @@ -27,8 +27,8 @@ * IXP2000 does not do proper byte-lane conversion for PCI addresses, * so we need to override standard functions. */ -#define alignb(addr) (((unsigned long)addr & ~3) + (3 - ((unsigned long)addr & 3))) -#define alignw(addr) (((unsigned long)addr & ~2) + (2 - ((unsigned long)addr & 2))) +#define alignb(addr) (void __iomem *)(((unsigned long)addr & ~3) + (3 - ((unsigned long)addr & 3))) +#define alignw(addr) (void __iomem *)(((unsigned long)addr & ~2) + (2 - ((unsigned long)addr & 2))) #define outb(v,p) __raw_writeb(v,alignb(___io(p))) #define outw(v,p) __raw_writew((v),alignw(___io(p))) diff --git a/include/asm-arm/arch-ixp2000/ixdp2x01.h b/include/asm-arm/arch-ixp2000/ixdp2x01.h index 46469c4d5ddc..24aa0b5ba6fa 100644 --- a/include/asm-arm/arch-ixp2000/ixdp2x01.h +++ b/include/asm-arm/arch-ixp2000/ixdp2x01.h @@ -21,7 +21,7 @@ #define IXDP2X01_VIRT_CPLD_BASE 0xfefdd000 #define IXDP2X01_CPLD_REGION_SIZE 0x1000 -#define IXDP2X01_CPLD_VIRT_REG(reg) (volatile u32*)(IXDP2X01_VIRT_CPLD_BASE | reg) +#define IXDP2X01_CPLD_VIRT_REG(reg) (volatile unsigned long*)(IXDP2X01_VIRT_CPLD_BASE | reg) #define IXDP2X01_CPLD_PHYS_REG(reg) (volatile u32*)(IXDP2X01_PHYS_CPLD_BASE | reg) #define IXDP2X01_UART1_VIRT_BASE IXDP2X01_CPLD_VIRT_REG(0x40) diff --git a/include/asm-arm/arch-ixp2000/system.h b/include/asm-arm/arch-ixp2000/system.h index f9eb8ad435fb..4f489cc0dfa5 100644 --- a/include/asm-arm/arch-ixp2000/system.h +++ b/include/asm-arm/arch-ixp2000/system.h @@ -19,7 +19,7 @@ static inline void arch_idle(void) static inline void arch_reset(char mode) { - cli(); + local_irq_disable(); /* * Reset flash banking register so that we are pointing at -- cgit v1.2.3 From 55935dfdb041156a27a2d2a033ba1e1fe3f6bb9e Mon Sep 17 00:00:00 2001 From: "cbrake@com.rmk.(none)" Date: Thu, 3 Mar 2005 01:52:00 +0000 Subject: [ARM PATCH] 2488/1: Update Vibren PXA255 IDP support Patch from Cliff Brake Changes to machine specific files and add defconfig so the CONFIG_ARCH_PXA_IDP machine will build and run. Changes are mostly related to the 2.6 driver model. Also removed code that is no longer required -- support for older versions of hardware, etc. Signed-off-by: Cliff Brake Signed-off-by: Russell King --- arch/arm/configs/pxa255-idp_defconfig | 765 ++++++++++++++++++++++++++++++++++ arch/arm/mach-pxa/idp.c | 160 ++++--- arch/arm/mach-pxa/leds-idp.c | 1 + include/asm-arm/arch-pxa/idp.h | 290 +------------ 4 files changed, 892 insertions(+), 324 deletions(-) create mode 100644 arch/arm/configs/pxa255-idp_defconfig (limited to 'include') diff --git a/arch/arm/configs/pxa255-idp_defconfig b/arch/arm/configs/pxa255-idp_defconfig new file mode 100644 index 000000000000..5f447c85a055 --- /dev/null +++ b/arch/arm/configs/pxa255-idp_defconfig @@ -0,0 +1,765 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11-rc3 +# Fri Feb 11 16:53:43 2005 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=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_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +CONFIG_ARCH_PXA=y +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set + +# +# Intel PXA2xx Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_MACH_MAINSTONE is not set +CONFIG_ARCH_PXA_IDP=y +# CONFIG_PXA_SHARPSL is not set +CONFIG_PXA25x=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_XSCALE=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5T=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_MINICACHE=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +CONFIG_XSCALE_PMU=y + +# +# General setup +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_XIP_KERNEL is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PC-card bridges +# + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_PM is not set +# CONFIG_PREEMPT is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=/dev/nfs ip=dhcp console=ttyS0,115200 mem=64M" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +# CONFIG_MTD_CFI_I1 is not set +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_XIP is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_SHARP_SL is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_SMC91X=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_IDE_GENERIC is not set +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_PXA=y +CONFIG_SERIAL_PXA_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_VFAT_FS is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_JFFS2_FS_NOR_ECC is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set +CONFIG_FB_PXA=y +# CONFIG_FB_PXA_PARAMETERS is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +# CONFIG_USB is not set +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 4333a0f19b32..c5a66bf4d3d5 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -10,13 +10,16 @@ * 2001-09-13: Cliff Brake * Initial code * - * Expected command line: mem=32M initrd=0xa1000000,4M root=/dev/ram ramdisk=8192 + * 2005-02-15: Cliff Brake + * + * Updated for 2.6 kernel + * */ -#include + #include -#include -#include #include +#include +#include #include #include @@ -29,68 +32,133 @@ #include #include +#include +#include +#include #include "generic.h" -#ifndef PXA_IDP_REV02 -/* shadow registers for write only registers */ -unsigned int idp_cpld_led_control_shadow = 0x1; -unsigned int idp_cpld_periph_pwr_shadow = 0xd; -unsigned int ipd_cpld_cir_shadow = 0; -unsigned int idp_cpld_kb_col_high_shadow = 0; -unsigned int idp_cpld_kb_col_low_shadow = 0; -unsigned int idp_cpld_pccard_en_shadow = 0xC3; -unsigned int idp_cpld_gpioh_dir_shadow = 0; -unsigned int idp_cpld_gpioh_value_shadow = 0; -unsigned int idp_cpld_gpiol_dir_shadow = 0; -unsigned int idp_cpld_gpiol_value_shadow = 0; - -/* - * enable all LCD signals -- they should still be on - * write protect flash - * enable all serial port transceivers +/* TODO: + * - add pxa2xx_audio_ops_t device structure + * - Ethernet interrupt */ -unsigned int idp_control_port_shadow = ((0x7 << 21) | /* LCD power */ - (0x1 << 19) | /* disable flash write enable */ - (0x7 << 9)); /* enable serial port transeivers */ +static struct resource smc91x_resources[] = { + [0] = { + .start = (IDP_ETH_PHYS + 0x300), + .end = (IDP_ETH_PHYS + 0xfffff), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO(4), + .end = IRQ_GPIO(4), + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static void idp_backlight_power(int on) +{ + if (on) { + IDP_CPLD_LCD |= (1<<1); + } else { + IDP_CPLD_LCD &= ~(1<<1); + } +} + +static void idp_vlcd(int on) +{ + if (on) { + IDP_CPLD_LCD |= (1<<2); + } else { + IDP_CPLD_LCD &= ~(1<<2); + } +} + +static void idp_lcd_power(int on) +{ + if (on) { + IDP_CPLD_LCD |= (1<<0); + } else { + IDP_CPLD_LCD &= ~(1<<0); + } + + /* call idp_vlcd for now as core driver does not support + * both power and vlcd hooks. Note, this is not technically + * the correct sequence, but seems to work. Disclaimer: + * this may eventually damage the display. + */ + + idp_vlcd(on); +} + +static struct pxafb_mach_info sharp_lm8v31 __initdata = { + .pixclock = 270000, + .xres = 640, + .yres = 480, + .bpp = 16, + .hsync_len = 1, + .left_margin = 3, + .right_margin = 3, + .vsync_len = 1, + .upper_margin = 0, + .lower_margin = 0, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .cmap_greyscale = 0, + .cmap_inverse = 0, + .cmap_static = 0, + .lccr0 = LCCR0_SDS, + .lccr3 = LCCR3_PCP | LCCR3_Acb(255), + .pxafb_backlight_power = &idp_backlight_power, + .pxafb_lcd_power = &idp_lcd_power +}; -#endif +static int idp_mci_init(struct device *dev, irqreturn_t (*idp_detect_int)(int, void *, struct pt_regs *), void *data) +{ + /* setup GPIO for PXA25x MMC controller */ + pxa_gpio_mode(GPIO6_MMCCLK_MD); + pxa_gpio_mode(GPIO8_MMCCS0_MD); + + return 0; +} + +static struct pxamci_platform_data idp_mci_platform_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .init = idp_mci_init, +}; static void __init idp_init(void) { printk("idp_init()\n"); + + platform_device_register(&smc91x_device); + //platform_device_register(&mst_audio_device); + set_pxa_fb_info(&sharp_lm8v31); + pxa_set_mci_info(&idp_mci_platform_data); } static void __init idp_init_irq(void) { + pxa_init_irq(); + + set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE); } static struct map_desc idp_io_desc[] __initdata = { /* virtual physical length type */ - -#ifndef PXA_IDP_REV02 - { IDP_CTRL_PORT_BASE, - IDP_CTRL_PORT_PHYS, - IDP_CTRL_PORT_SIZE, - MT_DEVICE }, -#endif - - { IDP_IDE_BASE, - IDP_IDE_PHYS, - IDP_IDE_SIZE, - MT_DEVICE }, - { IDP_ETH_BASE, - IDP_ETH_PHYS, - IDP_ETH_SIZE, - MT_DEVICE }, - { IDP_COREVOLT_BASE, + { IDP_COREVOLT_VIRT, IDP_COREVOLT_PHYS, IDP_COREVOLT_SIZE, MT_DEVICE }, - { IDP_CPLD_BASE, + { IDP_CPLD_VIRT, IDP_CPLD_PHYS, IDP_CPLD_SIZE, MT_DEVICE } @@ -101,8 +169,6 @@ static void __init idp_map_io(void) pxa_map_io(); iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc)); - set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE); - // serial ports 2 & 3 pxa_gpio_mode(GPIO42_BTRXD_MD); pxa_gpio_mode(GPIO43_BTTXD_MD); @@ -114,8 +180,8 @@ static void __init idp_map_io(void) } -MACHINE_START(PXA_IDP, "Accelent Xscale IDP") - MAINTAINER("Accelent Systems Inc.") +MACHINE_START(PXA_IDP, "Vibren PXA255 IDP") + MAINTAINER("Vibren Technologies") BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) MAPIO(idp_map_io) INITIRQ(idp_init_irq) diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c index adb108c6c2bb..18d414c5db8d 100644 --- a/arch/arm/mach-pxa/leds-idp.c +++ b/arch/arm/mach-pxa/leds-idp.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "leds.h" diff --git a/include/asm-arm/arch-pxa/idp.h b/include/asm-arm/arch-pxa/idp.h index e496ed7f496a..fed385632025 100644 --- a/include/asm-arm/arch-pxa/idp.h +++ b/include/asm-arm/arch-pxa/idp.h @@ -10,20 +10,20 @@ * 2001-09-13: Cliff Brake * Initial code * + * 2005-02-15: Cliff Brake + * + * Changes for 2.6 kernel. */ #include /* * Note: this file must be safe to include in assembly files + * + * Support for the Vibren PXA255 IDP requires rev04 or later + * IDP hardware. */ -/* comment out following if you have a rev01 board */ -#define PXA_IDP_REV02 1 - -#ifdef PXA_IDP_REV02 -//Use this as well for 0017-x004 and greater pcb's: -#define PXA_IDP_REV04 1 #define IDP_FLASH_PHYS (PXA_CS0_PHYS) #define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) @@ -38,26 +38,18 @@ * virtual memory map */ -#define IDP_IDE_BASE (0xf0000000) -#define IDP_IDE_SIZE (1*1024*1024) -#define IDE_REG_STRIDE 4 - -#define IDP_ETH_BASE (IDP_IDE_BASE + IDP_IDE_SIZE) -#define IDP_ETH_SIZE (1*1024*1024) -#define ETH_BASE IDP_ETH_BASE //smc9194 driver compatibility issue - -#define IDP_COREVOLT_BASE (IDP_ETH_BASE + IDP_ETH_SIZE) +#define IDP_COREVOLT_VIRT (0xf0000000) #define IDP_COREVOLT_SIZE (1*1024*1024) -#define IDP_CPLD_BASE (IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE) +#define IDP_CPLD_VIRT (IDP_COREVOLT_VIRT + IDP_COREVOLT_SIZE) #define IDP_CPLD_SIZE (1*1024*1024) -#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000 +#if (IDP_CPLD_VIRT + IDP_CPLD_SIZE) > 0xfc000000 #error Your custom IO space is getting a bit large !! #endif -#define CPLD_P2V(x) ((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE) -#define CPLD_V2P(x) ((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS) +#define CPLD_P2V(x) ((x) - IDP_CPLD_PHYS + IDP_CPLD_VIRT) +#define CPLD_V2P(x) ((x) - IDP_CPLD_VIRT + IDP_CPLD_PHYS) #ifndef __ASSEMBLY__ # define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x))) @@ -65,7 +57,7 @@ # define __CPLD_REG(x) CPLD_P2V(x) #endif -/* board level registers in the CPLD: (offsets from CPLD_BASE) */ +/* board level registers in the CPLD: (offsets from CPLD_VIRT) */ #define _IDP_CPLD_REV (IDP_CPLD_PHYS + 0x00) #define _IDP_CPLD_PERIPH_PWR (IDP_CPLD_PHYS + 0x04) @@ -142,32 +134,10 @@ #define PCC_DETECT(x) (GPLR(7 + (x)) & GPIO_bit(7 + (x))) -/* - * Macros for LCD Driver - */ - -#ifdef CONFIG_FB_PXA - -#define FB_BACKLIGHT_ON() (IDP_CPLD_LCD |= (1<<1)) -#define FB_BACKLIGHT_OFF() (IDP_CPLD_LCD &= ~(1<<1)) - -#define FB_PWR_ON() (IDP_CPLD_LCD |= (1<< 0)) -#define FB_PWR_OFF() (IDP_CPLD_LCD &= ~(1<<0)) - -#define FB_VLCD_ON() (IDP_CPLD_LCD |= (1<<2)) -#define FB_VLCD_OFF() (IDP_CPLD_LCD &= ~(1<<2)) - -#endif - /* A listing of interrupts used by external hardware devices */ -#ifdef PXA_IDP_REV04 #define TOUCH_PANEL_IRQ IRQ_GPIO(5) #define IDE_IRQ IRQ_GPIO(21) -#else -#define TOUCH_PANEL_IRQ IRQ_GPIO(21) -#define IDE_IRQ IRQ_GPIO(5) -#endif #define TOUCH_PANEL_IRQ_EDGE IRQT_FALLING @@ -196,7 +166,7 @@ #define IDP_LEDS_MASK (IDP_HB_LED | IDP_BUSY_LED) -#define IDP_WRITE_LEDS(value) (IDP_CPLD_LED_CONTROL = (IDP_CPLD_LED_CONTROL & (~(IDP_LEDS_MASK)) | value)) +#define IDP_WRITE_LEDS(value) (IDP_CPLD_LED_CONTROL = (IDP_CPLD_LED_CONTROL & ((~(IDP_LEDS_MASK)) | value))) /* * macros for MTD driver @@ -229,238 +199,4 @@ inputs = (IDP_CPLD_KB_ROW & 0x7f);\ } -#else - -/* - * following is for rev01 boards only - */ - -#define IDP_FLASH_PHYS (PXA_CS0_PHYS) -#define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) -#define IDP_MEDIAQ_PHYS (PXA_CS3_PHYS) -#define IDP_CTRL_PORT_PHYS (PXA_CS5_PHYS + 0x02C00000) -#define IDP_IDE_PHYS (PXA_CS5_PHYS + 0x03000000) -#define IDP_ETH_PHYS (PXA_CS5_PHYS + 0x03400000) -#define IDP_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000) -#define IDP_CPLD_PHYS (PXA_CS5_PHYS + 0x03C00000) - - -/* - * virtual memory map - */ - -#define IDP_CTRL_PORT_BASE (0xf0000000) -#define IDP_CTRL_PORT_SIZE (1*1024*1024) - -#define IDP_IDE_BASE (IDP_CTRL_PORT_BASE + IDP_CTRL_PORT_SIZE) -#define IDP_IDE_SIZE (1*1024*1024) -#define IDP_ETH_BASE (IDP_IDE_BASE + IDP_IDE_SIZE) -#define IDP_ETH_SIZE (1*1024*1024) - -#define IDP_COREVOLT_BASE (IDP_ETH_BASE + IDP_ETH_SIZE) -#define IDP_COREVOLT_SIZE (1*1024*1024) - -#define IDP_CPLD_BASE (IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE) -#define IDP_CPLD_SIZE (1*1024*1024) - -#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000 -#error Your custom IO space is getting a bit large !! -#endif - -#define CPLD_P2V(x) ((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE) -#define CPLD_V2P(x) ((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS) - -#ifndef __ASSEMBLY__ -# define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x))) -#else -# define __CPLD_REG(x) CPLD_P2V(x) -#endif - -/* board level registers in the CPLD: (offsets from CPLD_BASE) */ - -#define _IDP_CPLD_LED_CONTROL (IDP_CPLD_PHYS + 0x00) -#define _IDP_CPLD_PERIPH_PWR (IDP_CPLD_PHYS + 0x04) -#define _IDP_CPLD_CIR (IDP_CPLD_PHYS + 0x08) -#define _IDP_CPLD_KB_COL_HIGH (IDP_CPLD_PHYS + 0x0C) -#define _IDP_CPLD_KB_COL_LOW (IDP_CPLD_PHYS + 0x10) -#define _IDP_CPLD_PCCARD_EN (IDP_CPLD_PHYS + 0x14) -#define _IDP_CPLD_GPIOH_DIR (IDP_CPLD_PHYS + 0x18) -#define _IDP_CPLD_GPIOH_VALUE (IDP_CPLD_PHYS + 0x1C) -#define _IDP_CPLD_GPIOL_DIR (IDP_CPLD_PHYS + 0x20) -#define _IDP_CPLD_GPIOL_VALUE (IDP_CPLD_PHYS + 0x24) -#define _IDP_CPLD_MISC (IDP_CPLD_PHYS + 0x28) -#define _IDP_CPLD_PCCARD0_STATUS (IDP_CPLD_PHYS + 0x2C) -#define _IDP_CPLD_PCCARD1_STATUS (IDP_CPLD_PHYS + 0x30) - -/* FPGA register virtual addresses */ -#define IDP_CPLD_LED_CONTROL __CPLD_REG(_IDP_CPLD_LED_CONTROL) /* write only */ -#define IDP_CPLD_PERIPH_PWR __CPLD_REG(_IDP_CPLD_PERIPH_PWR) /* write only */ -#define IDP_CPLD_CIR __CPLD_REG(_IDP_CPLD_CIR) /* write only */ -#define IDP_CPLD_KB_COL_HIGH __CPLD_REG(_IDP_CPLD_KB_COL_HIGH) /* write only */ -#define IDP_CPLD_KB_COL_LOW __CPLD_REG(_IDP_CPLD_KB_COL_LOW) /* write only */ -#define IDP_CPLD_PCCARD_EN __CPLD_REG(_IDP_CPLD_PCCARD_EN) /* write only */ -#define IDP_CPLD_GPIOH_DIR __CPLD_REG(_IDP_CPLD_GPIOH_DIR) /* write only */ -#define IDP_CPLD_GPIOH_VALUE __CPLD_REG(_IDP_CPLD_GPIOH_VALUE) /* write only */ -#define IDP_CPLD_GPIOL_DIR __CPLD_REG(_IDP_CPLD_GPIOL_DIR) /* write only */ -#define IDP_CPLD_GPIOL_VALUE __CPLD_REG(_IDP_CPLD_GPIOL_VALUE) /* write only */ -#define IDP_CPLD_MISC __CPLD_REG(_IDP_CPLD_MISC) /* read only */ -#define IDP_CPLD_PCCARD0_STATUS __CPLD_REG(_IDP_CPLD_PCCARD0_STATUS) /* read only */ -#define IDP_CPLD_PCCARD1_STATUS __CPLD_REG(_IDP_CPLD_PCCARD1_STATUS) /* read only */ - - -#ifndef __ASSEMBLY__ - -/* shadow registers for write only registers */ -extern unsigned int idp_cpld_led_control_shadow; -extern unsigned int idp_cpld_periph_pwr_shadow; -extern unsigned int idp_cpld_cir_shadow; -extern unsigned int idp_cpld_kb_col_high_shadow; -extern unsigned int idp_cpld_kb_col_low_shadow; -extern unsigned int idp_cpld_pccard_en_shadow; -extern unsigned int idp_cpld_gpioh_dir_shadow; -extern unsigned int idp_cpld_gpioh_value_shadow; -extern unsigned int idp_cpld_gpiol_dir_shadow; -extern unsigned int idp_cpld_gpiol_value_shadow; - -extern unsigned int idp_control_port_shadow; - -/* - * macros to write to write only register - * - * none of these macros are protected from - * multiple drivers using them in interrupt context. - */ - -#define WRITE_IDP_CPLD_LED_CONTROL(value, mask) \ -{\ - idp_cpld_led_control_shadow = (((value & mask) | (idp_cpld_led_control_shadow & ~mask)));\ - IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\ -} -#define WRITE_IDP_CPLD_PERIPH_PWR(value, mask) \ -{\ - idp_cpld_periph_pwr_shadow = ((value & mask) | (idp_cpld_periph_pwr_shadow & ~mask));\ - IDP_CPLD_PERIPH_PWR = idp_cpld_periph_pwr_shadow;\ -} -#define WRITE_IDP_CPLD_CIR(value, mask) \ -{\ - idp_cpld_cir_shadow = ((value & mask) | (idp_cpld_cir_shadow & ~mask));\ - IDP_CPLD_CIR = idp_cpld_cir_shadow;\ -} -#define WRITE_IDP_CPLD_KB_COL_HIGH(value, mask) \ -{\ - idp_cpld_kb_col_high_shadow = ((value & mask) | (idp_cpld_kb_col_high_shadow & ~mask));\ - IDP_CPLD_KB_COL_HIGH = idp_cpld_kb_col_high_shadow;\ -} -#define WRITE_IDP_CPLD_KB_COL_LOW(value, mask) \ -{\ - idp_cpld_kb_col_low_shadow = ((value & mask) | (idp_cpld_kb_col_low_shadow & ~mask));\ - IDP_CPLD_KB_COL_LOW = idp_cpld_kb_col_low_shadow;\ -} -#define WRITE_IDP_CPLD_PCCARD_EN(value, mask) \ -{\ - idp_cpld_ = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\ - IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\ -} -#define WRITE_IDP_CPLD_GPIOH_DIR(value, mask) \ -{\ - idp_cpld_gpioh_dir_shadow = ((value & mask) | (idp_cpld_gpioh_dir_shadow & ~mask));\ - IDP_CPLD_GPIOH_DIR = idp_cpld_gpioh_dir_shadow;\ -} -#define WRITE_IDP_CPLD_GPIOH_VALUE(value, mask) \ -{\ - idp_cpld_gpioh_value_shadow = ((value & mask) | (idp_cpld_gpioh_value_shadow & ~mask));\ - IDP_CPLD_GPIOH_VALUE = idp_cpld_gpioh_value_shadow;\ -} -#define WRITE_IDP_CPLD_GPIOL_DIR(value, mask) \ -{\ - idp_cpld_gpiol_dir_shadow = ((value & mask) | (idp_cpld_gpiol_dir_shadow & ~mask));\ - IDP_CPLD_GPIOL_DIR = idp_cpld_gpiol_dir_shadow;\ -} -#define WRITE_IDP_CPLD_GPIOL_VALUE(value, mask) \ -{\ - idp_cpld_gpiol_value_shadow = ((value & mask) | (idp_cpld_gpiol_value_shadow & ~mask));\ - IDP_CPLD_GPIOL_VALUE = idp_cpld_gpiol_value_shadow;\ -} - -#define WRITE_IDP_CONTROL_PORT(value, mask) \ -{\ - idp_control_port_shadow = ((value & mask) | (idp_control_port_shadow & ~mask));\ - (*((volatile unsigned long *)IDP_CTRL_PORT_BASE)) = idp_control_port_shadow;\ -} - -#endif - -/* A listing of interrupts used by external hardware devices */ - -#define TOUCH_PANEL_IRQ IRQ_GPIO(21) -#define TOUCH_PANEL_IRQ_EGDE IRQT_FALLING - -#define ETHERNET_IRQ IRQ_GPIO(4) -#define ETHERNET_IRQ_EDGE IRQT_RISING - -/* - * Bit masks for various registers - */ - - -/* control port */ -#define IDP_CONTROL_PORT_PCSLOT0_0 (1 << 0) -#define IDP_CONTROL_PORT_PCSLOT0_1 (1 << 1) -#define IDP_CONTROL_PORT_PCSLOT0_2 (1 << 2) -#define IDP_CONTROL_PORT_PCSLOT0_3 (1 << 3) -#define IDP_CONTROL_PORT_PCSLOT1_1 (1 << 4) -#define IDP_CONTROL_PORT_PCSLOT1_2 (1 << 5) -#define IDP_CONTROL_PORT_PCSLOT1_3 (1 << 6) -#define IDP_CONTROL_PORT_PCSLOT1_4 (1 << 7) -#define IDP_CONTROL_PORT_SERIAL1_EN (1 << 9) -#define IDP_CONTROL_PORT_SERIAL2_EN (1 << 10) -#define IDP_CONTROL_PORT_SERIAL3_EN (1 << 11) -#define IDP_CONTROL_PORT_IRDA_FIR (1 << 12) -#define IDP_CONTROL_PORT_IRDA_M0 (1 << 13) -#define IDP_CONTROL_PORT_IRDA_M1 (1 << 14) -#define IDP_CONTROL_PORT_I2S_PWR (1 << 15) -#define IDP_CONTROL_PORT_FLASH_WP (1 << 19) -#define IDP_CONTROL_PORT_MILL_EN (1 << 20) -#define IDP_CONTROL_PORT_LCD_PWR (1 << 21) -#define IDP_CONTROL_PORT_LCD_BKLEN (1 << 22) -#define IDP_CONTROL_PORT_LCD_ENAVLCD (1 << 23) - -/* - * Macros for LCD Driver - */ - -#ifdef CONFIG_FB_PXA - -#define FB_BACKLIGHT_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_BKLEN, IDP_CONTROL_PORT_LCD_BKLEN) -#define FB_BACKLIGHT_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_BKLEN) - -#define FB_PWR_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_PWR, IDP_CONTROL_PORT_LCD_PWR) -#define FB_PWR_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_PWR) - -#define FB_VLCD_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_ENAVLCD, IDP_CONTROL_PORT_LCD_ENAVLCD) -#define FB_VLCD_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_ENAVLCD) - -#endif - - -/* - * Macros for LED Driver - */ - -/* leds 0 = ON */ -#define IDP_HB_LED 0x1 -#define IDP_BUSY_LED 0x2 - -#define IDP_LEDS_MASK (IDP_HB_LED | IDP_BUSY_LED) - -#define IDP_WRITE_LEDS(value) WRITE_IDP_CPLD_LED_CONTROL(value, IDP_LEDS_MASK) - -/* - * macros for MTD driver - */ - -#define FLASH_WRITE_PROTECT_DISABLE() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_FLASH_WP) -#define FLASH_WRITE_PROTECT_ENABLE() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_FLASH_WP, IDP_CONTROL_PORT_FLASH_WP) - -#endif -- cgit v1.2.3 From 5a2ddbe1afc638a80c1c0cda65e13c003349028a Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 3 Mar 2005 02:32:18 +0000 Subject: [ARM PATCH] 2500/1: S3C2410 - include/asm-arm/arch-s3c2410/regs-adc.h Patch from Ben Dooks S3C2410 ADC register definitions Patch from Shannon Holland Signed-off-by: Shannon Holland Signed-off-by: Ben Dooks Signed-off-by: Russell King --- include/asm-arm/arch-s3c2410/regs-adc.h | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 include/asm-arm/arch-s3c2410/regs-adc.h (limited to 'include') diff --git a/include/asm-arm/arch-s3c2410/regs-adc.h b/include/asm-arm/arch-s3c2410/regs-adc.h new file mode 100644 index 000000000000..15bfc2f5754e --- /dev/null +++ b/include/asm-arm/arch-s3c2410/regs-adc.h @@ -0,0 +1,63 @@ +/* linux/include/asm/arch-s3c2410/regs-adc.h + * + * Copyright (c) 2004 Shannon Holland + * + * This program is free software; yosu can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * S3C2410 ADC registers + * + * Changelog: + * 27-09-2004 SAH Created file +*/ + +#ifndef __ASM_ARCH_REGS_ADC_H +#define __ASM_ARCH_REGS_ADC_H "regs-adc.h" + +#define S3C2410_ADCREG(x) (x) + +#define S3C2410_ADCCON S3C2410_ADCREG(0x00) +#define S3C2410_ADCTSC S3C2410_ADCREG(0x04) +#define S3C2410_ADCDLY S3C2410_ADCREG(0x08) +#define S3C2410_ADCDAT0 S3C2410_ADCREG(0x0C) +#define S3C2410_ADCDAT1 S3C2410_ADCREG(0x10) + + +/* ADCCON Register Bits */ +#define S3C2410_ADCCON_ECFLG (1<<15) +#define S3C2410_ADCCON_PRSCEN (1<<14) +#define S3C2410_ADCCON_PRSCVL(x) (((x)&0xFF)<<6) +#define S3C2410_ADCCON_PRSCVLMASK (0xFF<<6) +#define S3C2410_ADCCON_SELMUX(x) (((x)&0x7)<<3) +#define S3C2410_ADCCON_MUXMASK (0x7<<3) +#define S3C2410_ADCCON_STDBM (1<<2) +#define S3C2410_ADCCON_READ_START (1<<1) +#define S3C2410_ADCCON_ENABLE_START (1<<0) +#define S3C2410_ADCCON_STARTMASK (0x3<<0) + + +/* ADCTSC Register Bits */ +#define S3C2410_ADCTSC_YM_SEN (1<<7) +#define S3C2410_ADCTSC_YP_SEN (1<<6) +#define S3C2410_ADCTSC_XM_SEN (1<<5) +#define S3C2410_ADCTSC_XP_SEN (1<<4) +#define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3) +#define S3C2410_ADCTSC_AUTO_PST (1<<2) +#define S3C2410_ADCTSC_XY_PST (0x3<<0) + +/* ADCDAT0 Bits */ +#define S3C2410_ADCDAT0_UPDOWN (1<<15) +#define S3C2410_ADCDAT0_AUTO_PST (1<<14) +#define S3C2410_ADCDAT0_XY_PST (0x3<<12) +#define S3C2410_ADCDAT0_XPDATA_MASK (0x03FF) + +/* ADCDAT1 Bits */ +#define S3C2410_ADCDAT1_UPDOWN (1<<15) +#define S3C2410_ADCDAT1_AUTO_PST (1<<14) +#define S3C2410_ADCDAT1_XY_PST (0x3<<12) +#define S3C2410_ADCDAT1_YPDATA_MASK (0x03FF) + +#endif /* __ASM_ARCH_REGS_ADC_H */ + + -- cgit v1.2.3 From 9bbbf278d2fd68a4796e825c3e4ae1d7d77c4874 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 3 Mar 2005 07:53:43 +0000 Subject: [ARM PATCH] 2502/1: S3C2410 - watchdog during kernel uncompression Patch from Ben Dooks Enable the watchdog at the start of the kernel uncompression stage, so that if any errors occur before the kernel reaches the stage where it can start running processes then the system will be reset. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/Kconfig | 20 ++++++++++ include/asm-arm/arch-s3c2410/uncompress.h | 63 +++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index b1b216ef0538..b236e9d8dc79 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -59,6 +59,26 @@ config CPU_S3C2440 help Support for S3C2440 Samsung Mobile CPU based systems. +comment "S3C2410 Boot" + +config S3C2410_BOOT_WATCHDOG + bool "S3C2410 Initialisation watchdog" + depends on ARCH_S3C2410 && S3C2410_WATCHDOG + help + Say y to enable the watchdog during the kernel decompression + stage. If the kernel fails to uncompress, then the watchdog + will trigger a reset and the system should restart. + + Although this uses the same hardware unit as the kernel watchdog + driver, it is not a replacement for it. If you use this option, + you will have to use the watchdg driver to either stop the timeout + or restart it. If you do not, then your kernel will reboot after + startup. + + The driver uses a fixed timeout value, so the exact time till the + system resets depends on the value of PCLK. The timeout on an + 200MHz s3c2410 should be about 30 seconds. + comment "S3C2410 Setup" config S3C2410_DMA diff --git a/include/asm-arm/arch-s3c2410/uncompress.h b/include/asm-arm/arch-s3c2410/uncompress.h index fa240af7f591..ad4252e27799 100644 --- a/include/asm-arm/arch-s3c2410/uncompress.h +++ b/include/asm-arm/arch-s3c2410/uncompress.h @@ -15,6 +15,7 @@ * 12-Mar-2004 BJD Updated header protection * 12-Oct-2004 BJD Take account of debug uart configuration * 15-Nov-2004 BJD Fixed uart configuration + * 22-Feb-2005 BJD Added watchdog to uncompress */ #ifndef __ASM_ARCH_UNCOMPRESS_H @@ -25,12 +26,16 @@ /* defines for UART registers */ #include "asm/arch/regs-serial.h" #include "asm/arch/regs-gpio.h" +#include "asm/arch/regs-watchdog.h" #include /* working in physical space... */ #undef S3C2410_GPIOREG +#undef S3C2410_WDOGREG + #define S3C2410_GPIOREG(x) ((S3C2410_PA_GPIO + (x))) +#define S3C2410_WDOGREG(x) ((S3C2410_PA_WATCHDOG + (x))) /* how many bytes we allow into the FIFO at a time in FIFO mode */ #define FIFO_MAX (14) @@ -56,21 +61,6 @@ uart_rd(unsigned int reg) } -/* currently we do not need the watchdog... */ -#define arch_decomp_wdog() - - -static void error(char *err); - -static void -arch_decomp_setup(void) -{ - /* we may need to setup the uart(s) here if we are not running - * on an BAST... the BAST will have left the uarts configured - * after calling linux. - */ -} - /* we can deal with the case the UARTs are being run * in FIFO mode, so that we don't hold up our execution * waiting for tx to happen... @@ -122,4 +112,47 @@ putstr(const char *ptr) } } +/* CONFIG_S3C2410_BOOT_WATCHDOG + * + * Simple boot-time watchdog setup, to reboot the system if there is + * any problem with the boot process +*/ + +#ifdef CONFIG_S3C2410_BOOT_WATCHDOG + +#define WDOG_COUNT (0xff00) + +#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0) + +static inline void arch_decomp_wdog(void) +{ + __raw_writel(WDOG_COUNT, S3C2410_WTCNT); +} + +static void arch_decomp_wdog_start(void) +{ + __raw_writel(WDOG_COUNT, S3C2410_WTDAT); + __raw_writel(WDOG_COUNT, S3C2410_WTCNT); + __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON); +} + +#else +#define arch_decomp_wdog_start() +#define arch_decomp_wdog() +#endif + +static void error(char *err); + +static void +arch_decomp_setup(void) +{ + /* we may need to setup the uart(s) here if we are not running + * on an BAST... the BAST will have left the uarts configured + * after calling linux. + */ + + arch_decomp_wdog_start(); +} + + #endif /* __ASM_ARCH_UNCOMPRESS_H */ -- cgit v1.2.3 From 357867277a0c7ab984dd2c2babaa3542f685e7dd Mon Sep 17 00:00:00 2001 From: John Lenz Date: Thu, 3 Mar 2005 21:35:52 +0000 Subject: [ARM PATCH] 2461/1: base support for poodle machine Patch from John Lenz Adds support for the Sharp Zaurus SL-5600 Add the ability to compile any collection of poodle and corgi support under the PXA_SHARPSL option. arch/arm/boot/compressed/head-sharpsl.S already has code to detect the poodle machine. Signed-off-by: John Lenz Signed-off-by: Russell King --- arch/arm/Kconfig | 2 +- arch/arm/mach-pxa/Kconfig | 19 +++- arch/arm/mach-pxa/Makefile | 3 +- arch/arm/mach-pxa/poodle.c | 181 ++++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-pxa/irqs.h | 32 +++++++ include/asm-arm/arch-pxa/poodle.h | 111 +++++++++++++++++++++++ 6 files changed, 343 insertions(+), 5 deletions(-) create mode 100644 arch/arm/mach-pxa/poodle.c create mode 100644 include/asm-arm/arch-pxa/poodle.h (limited to 'include') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1ef65fd36a99..a17af6122ad5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -231,7 +231,7 @@ config SA1111 config SHARP_LOCOMO bool - depends on SA1100_COLLIE + depends on SA1100_COLLIE || MACH_POODLE default y config SHARP_SCOOP diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index f09e49d30efa..617106ad446b 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -19,28 +19,36 @@ config ARCH_PXA_IDP select PXA25x config PXA_SHARPSL - bool "SHARP SL-C7xx Models (Corgi, Shepherd and Husky)" + bool "SHARP SL-5600 and SL-C7xx Models" select PXA25x help Say Y here if you intend to run this kernel on a - Sharp SL-C700 (Corgi), SL-C750 (Shepherd) or a - Sharp SL-C760 (Husky) handheld computer. + Sharp SL-5600 (Poodle), Sharp SL-C700 (Corgi), + SL-C750 (Shepherd) or a Sharp SL-C760 (Husky) + handheld computer. endchoice endmenu +config MACH_POODLE + bool "Enable Sharp SL-5600 (Poodle) Support" + depends PXA_SHARPSL + config MACH_CORGI bool "Enable Sharp SL-C700 (Corgi) Support" depends PXA_SHARPSL + select PXA_SHARP_C7xx config MACH_SHEPHERD bool "Enable Sharp SL-C750 (Shepherd) Support" depends PXA_SHARPSL + select PXA_SHARP_C7xx config MACH_HUSKY bool "Enable Sharp SL-C760 (Husky) Support" depends PXA_SHARPSL + select PXA_SHARP_C7xx config PXA25x bool @@ -57,4 +65,9 @@ config IWMMXT help Enable support for iWMMXt +config PXA_SHARP_C7xx + bool + help + Enable support for all Sharp C7xx models + endif diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index d480bd54c95d..c4e6d2523585 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -11,7 +11,8 @@ obj-$(CONFIG_PXA27x) += pxa27x.o obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o obj-$(CONFIG_ARCH_PXA_IDP) += idp.o -obj-$(CONFIG_PXA_SHARPSL) += corgi.o corgi_ssp.o ssp.o +obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o ssp.o +obj-$(CONFIG_MACH_POODLE) += poodle.o # Support for blinky lights led-y := leds.o diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c new file mode 100644 index 000000000000..d49bc5814022 --- /dev/null +++ b/arch/arm/mach-pxa/poodle.c @@ -0,0 +1,181 @@ +/* + * linux/arch/arm/mach-pxa/poodle.c + * + * Support for the SHARP Poodle Board. + * + * Based on: + * linux/arch/arm/mach-pxa/lubbock.c Author: Nicolas Pitre + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Change Log + * 12-Dec-2002 Sharp Corporation for Poodle + * John Lenz updates to 2.6 + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "generic.h" + +static struct resource poodle_scoop_resources[] = { + [0] = { + .start = 0x10800000, + .end = 0x10800fff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct scoop_config poodle_scoop_setup = { + .io_dir = POODLE_SCOOP_IO_DIR, + .io_out = POODLE_SCOOP_IO_OUT, +}; + +static struct platform_device poodle_scoop_device = { + .name = "sharp-scoop", + .id = -1, + .dev = { + .platform_data = &poodle_scoop_setup, + }, + .num_resources = ARRAY_SIZE(poodle_scoop_resources), + .resource = poodle_scoop_resources, +}; + + +/* LoCoMo device */ +static struct resource locomo_resources[] = { + [0] = { + .start = 0x10000000, + .end = 0x10001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO(10), + .end = IRQ_GPIO(10), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device locomo_device = { + .name = "locomo", + .id = 0, + .num_resources = ARRAY_SIZE(locomo_resources), + .resource = locomo_resources, +}; + +/* PXAFB device */ +static struct pxafb_mach_info poodle_fb_info __initdata = { + .pixclock = 144700, + + .xres = 320, + .yres = 240, + .bpp = 16, + + .hsync_len = 7, + .left_margin = 11, + .right_margin = 30, + + .vsync_len = 2, + .upper_margin = 2, + .lower_margin = 0, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Act | LCCR0_Sngl | LCCR0_Color, + .lccr3 = 0, + + .pxafb_backlight_power = NULL, + .pxafb_lcd_power = NULL, +}; + +static struct platform_device *devices[] __initdata = { + &locomo_device, + &poodle_scoop_device, +}; + +static void __init poodle_init(void) +{ + int ret = 0; + + /* cpu initialize */ + /* Pgsr Register */ + PGSR0 = 0x0146dd80; + PGSR1 = 0x03bf0890; + PGSR2 = 0x0001c000; + + /* Alternate Register */ + GAFR0_L = 0x01001000; + GAFR0_U = 0x591a8010; + GAFR1_L = 0x900a8451; + GAFR1_U = 0xaaa5aaaa; + GAFR2_L = 0x8aaaaaaa; + GAFR2_U = 0x00000002; + + /* Direction Register */ + GPDR0 = 0xd3f0904c; + GPDR1 = 0xfcffb7d3; + GPDR2 = 0x0001ffff; + + /* Output Register */ + GPCR0 = 0x00000000; + GPCR1 = 0x00000000; + GPCR2 = 0x00000000; + + GPSR0 = 0x00400000; + GPSR1 = 0x00000000; + GPSR2 = 0x00000000; + + set_pxa_fb_info(&poodle_fb_info); + + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); + if (ret) { + printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n"); + } +} + +static struct map_desc poodle_io_desc[] __initdata = { + /* virtual physical length */ + { 0xef800000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */ +}; + +static void __init poodle_map_io(void) +{ + pxa_map_io(); + iotable_init(poodle_io_desc, ARRAY_SIZE(poodle_io_desc)); + + /* setup sleep mode values */ + PWER = 0x00000002; + PFER = 0x00000000; + PRER = 0x00000002; + PGSR0 = 0x00008000; + PGSR1 = 0x003F0202; + PGSR2 = 0x0001C000; + PCFR |= PCFR_OPDE; +} + +MACHINE_START(POODLE, "SHARP Poodle") + BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) + MAPIO(poodle_map_io) + INITIRQ(pxa_init_irq) + .timer = &pxa_timer, + .init_machine = poodle_init, +MACHINE_END diff --git a/include/asm-arm/arch-pxa/irqs.h b/include/asm-arm/arch-pxa/irqs.h index 3d9b92a466ca..05c4b7027592 100644 --- a/include/asm-arm/arch-pxa/irqs.h +++ b/include/asm-arm/arch-pxa/irqs.h @@ -140,14 +140,41 @@ #define IRQ_S0_BVD1_STSCHG (IRQ_BOARD_END + 53) #define IRQ_S1_BVD1_STSCHG (IRQ_BOARD_END + 54) +#define IRQ_LOCOMO_START (IRQ_BOARD_END) +#define IRQ_LOCOMO_KEY (IRQ_BOARD_END + 0) +#define IRQ_LOCOMO_GPIO0 (IRQ_BOARD_END + 1) +#define IRQ_LOCOMO_GPIO1 (IRQ_BOARD_END + 2) +#define IRQ_LOCOMO_GPIO2 (IRQ_BOARD_END + 3) +#define IRQ_LOCOMO_GPIO3 (IRQ_BOARD_END + 4) +#define IRQ_LOCOMO_GPIO4 (IRQ_BOARD_END + 5) +#define IRQ_LOCOMO_GPIO5 (IRQ_BOARD_END + 6) +#define IRQ_LOCOMO_GPIO6 (IRQ_BOARD_END + 7) +#define IRQ_LOCOMO_GPIO7 (IRQ_BOARD_END + 8) +#define IRQ_LOCOMO_GPIO8 (IRQ_BOARD_END + 9) +#define IRQ_LOCOMO_GPIO9 (IRQ_BOARD_END + 10) +#define IRQ_LOCOMO_GPIO10 (IRQ_BOARD_END + 11) +#define IRQ_LOCOMO_GPIO11 (IRQ_BOARD_END + 12) +#define IRQ_LOCOMO_GPIO12 (IRQ_BOARD_END + 13) +#define IRQ_LOCOMO_GPIO13 (IRQ_BOARD_END + 14) +#define IRQ_LOCOMO_GPIO14 (IRQ_BOARD_END + 15) +#define IRQ_LOCOMO_GPIO15 (IRQ_BOARD_END + 16) +#define IRQ_LOCOMO_LT (IRQ_BOARD_END + 17) +#define IRQ_LOCOMO_SPI_RFR (IRQ_BOARD_END + 18) +#define IRQ_LOCOMO_SPI_RFW (IRQ_BOARD_END + 19) +#define IRQ_LOCOMO_SPI_OVRN (IRQ_BOARD_END + 20) +#define IRQ_LOCOMO_SPI_TEND (IRQ_BOARD_END + 21) + /* * Figure out the MAX IRQ number. * * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1. + * If we have an LoCoMo, the max IRQ is IRQ_LOCOMO_SPI_TEND+1 * Otherwise, we have the standard IRQs only. */ #ifdef CONFIG_SA1111 #define NR_IRQS (IRQ_S1_BVD1_STSCHG + 1) +#elif defined(CONFIG_SHARP_LOCOMO) +#define NR_IRQS (IRQ_LOCOMO_SPI_TEND + 1) #elif defined(CONFIG_ARCH_LUBBOCK) || \ defined(CONFIG_MACH_MAINSTONE) #define NR_IRQS (IRQ_BOARD_END) @@ -185,3 +212,8 @@ #define MAINSTONE_S1_STSCHG_IRQ MAINSTONE_IRQ(14) #define MAINSTONE_S1_IRQ MAINSTONE_IRQ(15) +/* LoCoMo Interrupts (CONFIG_SHARP_LOCOMO) */ +#define IRQ_LOCOMO_KEY_BASE (IRQ_BOARD_START + 0) +#define IRQ_LOCOMO_GPIO_BASE (IRQ_BOARD_START + 1) +#define IRQ_LOCOMO_LT_BASE (IRQ_BOARD_START + 2) +#define IRQ_LOCOMO_SPI_BASE (IRQ_BOARD_START + 3) diff --git a/include/asm-arm/arch-pxa/poodle.h b/include/asm-arm/arch-pxa/poodle.h new file mode 100644 index 000000000000..027573d38ee4 --- /dev/null +++ b/include/asm-arm/arch-pxa/poodle.h @@ -0,0 +1,111 @@ +/* + * linux/include/asm-arm/arch-pxa/poodle.h + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Based on: + * linux/include/asm-arm/arch-sa1100/collie.h + * + * ChangeLog: + * 04-06-2001 Lineo Japan, Inc. + * 04-16-2001 SHARP Corporation + * Update to 2.6 John Lenz + */ +#ifndef __ASM_ARCH_POODLE_H +#define __ASM_ARCH_POODLE_H 1 + +/* + * GPIOs + */ +/* PXA GPIOs */ +#define POODLE_GPIO_ON_KEY (0) +#define POODLE_GPIO_AC_IN (1) +#define POODLE_GPIO_CO 16 +#define POODLE_GPIO_TP_INT (5) +#define POODLE_GPIO_WAKEUP (11) /* change battery */ +#define POODLE_GPIO_GA_INT (10) +#define POODLE_GPIO_IR_ON (22) +#define POODLE_GPIO_HP_IN (4) +#define POODLE_GPIO_CF_IRQ (17) +#define POODLE_GPIO_CF_CD (14) +#define POODLE_GPIO_CF_STSCHG (14) +#define POODLE_GPIO_SD_PWR (33) +#define POODLE_GPIO_nSD_CLK (6) +#define POODLE_GPIO_nSD_WP (7) +#define POODLE_GPIO_nSD_INT (8) +#define POODLE_GPIO_nSD_DETECT (9) +#define POODLE_GPIO_MAIN_BAT_LOW (13) +#define POODLE_GPIO_BAT_COVER (13) +#define POODLE_GPIO_ADC_TEMP_ON (21) +#define POODLE_GPIO_BYPASS_ON (36) +#define POODLE_GPIO_CHRG_ON (38) +#define POODLE_GPIO_CHRG_FULL (16) + +/* PXA GPIOs */ +#define POODLE_IRQ_GPIO_ON_KEY IRQ_GPIO0 +#define POODLE_IRQ_GPIO_AC_IN IRQ_GPIO1 +#define POODLE_IRQ_GPIO_HP_IN IRQ_GPIO4 +#define POODLE_IRQ_GPIO_CO IRQ_GPIO16 +#define POODLE_IRQ_GPIO_TP_INT IRQ_GPIO5 +#define POODLE_IRQ_GPIO_WAKEUP IRQ_GPIO11 +#define POODLE_IRQ_GPIO_GA_INT IRQ_GPIO10 +#define POODLE_IRQ_GPIO_CF_IRQ IRQ_GPIO17 +#define POODLE_IRQ_GPIO_CF_CD IRQ_GPIO14 +#define POODLE_IRQ_GPIO_nSD_INT IRQ_GPIO8 +#define POODLE_IRQ_GPIO_nSD_DETECT IRQ_GPIO9 +#define POODLE_IRQ_GPIO_MAIN_BAT_LOW IRQ_GPIO13 + +/* SCOOP GPIOs */ +#define POODLE_SCOOP_CHARGE_ON SCOOP_GPCR_PA11 +#define POODLE_SCOOP_CP401 SCOOP_GPCR_PA13 +#define POODLE_SCOOP_VPEN SCOOP_GPCR_PA18 +#define POODLE_SCOOP_L_PCLK SCOOP_GPCR_PA20 +#define POODLE_SCOOP_L_LCLK SCOOP_GPCR_PA21 +#define POODLE_SCOOP_HS_OUT SCOOP_GPCR_PA22 + +#define POODLE_SCOOP_IO_DIR ( POODLE_SCOOP_VPEN | POODLE_SCOOP_HS_OUT ) +#define POODLE_SCOOP_IO_OUT ( 0 ) + +/* + * Flash Memory mappings + * + * We have the following mapping: + * phys virt + * boot ROM 00000000 ef800000 + */ +#define FLASH_MEM_BASE 0xa0000a00 +#define FLASH_DATA(adr) (*(volatile unsigned int*)(FLASH_MEM_BASE+(adr))) +#define FLASH_DATA_F(adr) (*(volatile float32 *)(FLASH_MEM_BASE+(adr))) +#define FLASH_MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a ) + +/* COMADJ */ +#define FLASH_COMADJ_MAJIC FLASH_MAGIC_CHG('C','M','A','D') +#define FLASH_COMADJ_MAGIC_ADR 0x00 +#define FLASH_COMADJ_DATA_ADR 0x04 + +/* UUID */ +#define FLASH_UUID_MAJIC FLASH_MAGIC_CHG('U','U','I','D') +#define FLASH_UUID_MAGIC_ADR 0x08 +#define FLASH_UUID_DATA_ADR 0x0C + +/* TOUCH PANEL */ +#define FLASH_TOUCH_MAJIC FLASH_MAGIC_CHG('T','U','C','H') +#define FLASH_TOUCH_MAGIC_ADR 0x1C +#define FLASH_TOUCH_XP_DATA_ADR 0x20 +#define FLASH_TOUCH_YP_DATA_ADR 0x24 +#define FLASH_TOUCH_XD_DATA_ADR 0x28 +#define FLASH_TOUCH_YD_DATA_ADR 0x2C + +/* AD */ +#define FLASH_AD_MAJIC FLASH_MAGIC_CHG('B','V','A','D') +#define FLASH_AD_MAGIC_ADR 0x30 +#define FLASH_AD_DATA_ADR 0x34 + +/* PHAD */ +#define FLASH_PHAD_MAJIC FLASH_MAGIC_CHG('P','H','A','D') +#define FLASH_PHAD_MAGIC_ADR 0x38 +#define FLASH_PHAD_DATA_ADR 0x3C + + +#endif /* __ASM_ARCH_POODLE_H */ -- cgit v1.2.3 From cd4ad67de87761060ea822c6ae2ce03816aa3711 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 3 Mar 2005 21:58:16 +0000 Subject: [ARM PATCH] 2491/1: make ixp2000 use section mappings for on-chip registers Patch from Lennert Buytenhek This patch makes the ixp2000 port use section mappings for on-chip registers. This has two advantages: 1. It saves some TLB entries. 2. It enables us to work around ixp2400 erratum #66, for which the suggested (and only) fix involves mapping all on-chip registers using XCB=101 instead of XCB=000. This patch was derived from an older patch for the same erratum (ARM patch ID 2265/1), made by Deepak Saxena. Note that this patch does not actually constitute a workaround for erratum #66, it merely lays the foundation for such a workaround. Signed-off-by: Lennert BuytenhekSigned-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-ixp2000/core.c | 37 +++---------------- include/asm-arm/arch-ixp2000/entry-macro.S | 7 ++-- include/asm-arm/arch-ixp2000/ixdp2x00.h | 2 +- include/asm-arm/arch-ixp2000/ixdp2x01.h | 4 +- include/asm-arm/arch-ixp2000/ixp2000-regs.h | 57 ++++++++++++++++------------- include/asm-arm/arch-ixp2000/vmalloc.h | 2 +- 6 files changed, 45 insertions(+), 64 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 36d9ecedaea9..042bd6420105 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -79,31 +79,11 @@ void ixp2000_release_slowport(struct slowport_cfg *old_cfg) /************************************************************************* * Chip specific mappings shared by all IXP2000 systems *************************************************************************/ -static struct map_desc ixp2000_small_io_desc[] __initdata = { +static struct map_desc ixp2000_io_desc[] __initdata = { { - .virtual = IXP2000_GLOBAL_REG_VIRT_BASE, - .physical = IXP2000_GLOBAL_REG_PHYS_BASE, - .length = IXP2000_GLOBAL_REG_SIZE, - .type = MT_DEVICE - }, { - .virtual = IXP2000_GPIO_VIRT_BASE, - .physical = IXP2000_GPIO_PHYS_BASE, - .length = IXP2000_GPIO_SIZE, - .type = MT_DEVICE - }, { - .virtual = IXP2000_TIMER_VIRT_BASE, - .physical = IXP2000_TIMER_PHYS_BASE, - .length = IXP2000_TIMER_SIZE, - .type = MT_DEVICE - }, { - .virtual = IXP2000_UART_VIRT_BASE, - .physical = IXP2000_UART_PHYS_BASE, - .length = IXP2000_UART_SIZE, - .type = MT_DEVICE - }, { - .virtual = IXP2000_SLOWPORT_CSR_VIRT_BASE, - .physical = IXP2000_SLOWPORT_CSR_PHYS_BASE, - .length = IXP2000_SLOWPORT_CSR_SIZE, + .virtual = IXP2000_CAP_VIRT_BASE, + .physical = IXP2000_CAP_PHYS_BASE, + .length = IXP2000_CAP_SIZE, .type = MT_DEVICE }, { .virtual = IXP2000_INTCTL_VIRT_BASE, @@ -115,11 +95,7 @@ static struct map_desc ixp2000_small_io_desc[] __initdata = { .physical = IXP2000_PCI_CREG_PHYS_BASE, .length = IXP2000_PCI_CREG_SIZE, .type = MT_DEVICE - } -}; - -static struct map_desc ixp2000_large_io_desc[] __initdata = { - { + }, { .virtual = IXP2000_PCI_CSR_VIRT_BASE, .physical = IXP2000_PCI_CSR_PHYS_BASE, .length = IXP2000_PCI_CSR_SIZE, @@ -157,8 +133,7 @@ static struct uart_port ixp2000_serial_port = { void __init ixp2000_map_io(void) { - iotable_init(ixp2000_small_io_desc, ARRAY_SIZE(ixp2000_small_io_desc)); - iotable_init(ixp2000_large_io_desc, ARRAY_SIZE(ixp2000_large_io_desc)); + iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); early_serial_setup(&ixp2000_serial_port); /* Set slowport to 8-bit mode. */ diff --git a/include/asm-arm/arch-ixp2000/entry-macro.S b/include/asm-arm/arch-ixp2000/entry-macro.S index 44db57c79c89..e3a4e4121298 100644 --- a/include/asm-arm/arch-ixp2000/entry-macro.S +++ b/include/asm-arm/arch-ixp2000/entry-macro.S @@ -15,8 +15,7 @@ mov \irqnr, #0x0 @clear out irqnr as default mov \base, #0xfe000000 - orr \base, \base, #0x00ff0000 - orr \base, \base, #0x0000a000 + orr \base, \base, #0x00e00000 orr \base, \base, #0x08 ldr \irqstat, [\base] @ get interrupts @@ -35,8 +34,8 @@ bne 1001f mov \base, #0xfe000000 - orr \base, \base, #0x00fd0000 - orr \base, \base, #0x0000e100 + orr \base, \base, #0x00c00000 + orr \base, \base, #0x00000100 orr \base, \base, #0x00000058 ldr \irqstat, [\base] diff --git a/include/asm-arm/arch-ixp2000/ixdp2x00.h b/include/asm-arm/arch-ixp2000/ixdp2x00.h index 84ca02781c84..3a398dfbf125 100644 --- a/include/asm-arm/arch-ixp2000/ixdp2x00.h +++ b/include/asm-arm/arch-ixp2000/ixdp2x00.h @@ -21,7 +21,7 @@ * On board CPLD memory map */ #define IXDP2X00_PHYS_CPLD_BASE 0xc7000000 -#define IXDP2X00_VIRT_CPLD_BASE 0xfefdd000 +#define IXDP2X00_VIRT_CPLD_BASE 0xfafff000 #define IXDP2X00_CPLD_SIZE 0x00001000 diff --git a/include/asm-arm/arch-ixp2000/ixdp2x01.h b/include/asm-arm/arch-ixp2000/ixdp2x01.h index 24aa0b5ba6fa..9e1672cd84cf 100644 --- a/include/asm-arm/arch-ixp2000/ixdp2x01.h +++ b/include/asm-arm/arch-ixp2000/ixdp2x01.h @@ -18,8 +18,8 @@ #define __IXDP2X01_H__ #define IXDP2X01_PHYS_CPLD_BASE 0xc6024000 -#define IXDP2X01_VIRT_CPLD_BASE 0xfefdd000 -#define IXDP2X01_CPLD_REGION_SIZE 0x1000 +#define IXDP2X01_VIRT_CPLD_BASE 0xfafff000 +#define IXDP2X01_CPLD_REGION_SIZE 0x00001000 #define IXDP2X01_CPLD_VIRT_REG(reg) (volatile unsigned long*)(IXDP2X01_VIRT_CPLD_BASE | reg) #define IXDP2X01_CPLD_PHYS_REG(reg) (volatile u32*)(IXDP2X01_PHYS_CPLD_BASE | reg) diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h index 99dd524eaecb..ba457468489b 100644 --- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h +++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h @@ -19,41 +19,49 @@ #define _IXP2000_REGS_H_ /* - * Static I/O regions. The manual defines each region as being several - * MB in size, but all the registers are within the first 4K, so there's - * no purpose in mapping the whole region in. + * Static I/O regions. + * + * Most of the registers are clumped in 4K regions spread throughout + * the 0xc000000 -> 0xc0100000 address range, but we just map in + * the whole range using a single 1 MB section instead of small + * 4K pages. This has two advantages for us: + * + * 1) We use only one TLB entry for large number of on-chip I/O devices. + * + * 2) We can easily set the Section attributes to XCB=101 on the IXP2400 + * as required per erratum #66. + * + * CAP stands for CSR Access Proxy */ -#define IXP2000_SLOWPORT_CSR_PHYS_BASE 0xc0080000 -#define IXP2000_SLOWPORT_CSR_VIRT_BASE 0xfefff000 -#define IXP2000_SLOWPORT_CSR_SIZE 0x1000 -#define IXP2000_GLOBAL_REG_PHYS_BASE 0xc0004000 -#define IXP2000_GLOBAL_REG_VIRT_BASE 0xfeffe000 -#define IXP2000_GLOBAL_REG_SIZE 0x1000 +#define IXP2000_CAP_PHYS_BASE 0xc0000000 +#define IXP2000_CAP_VIRT_BASE 0xfef00000 +#define IXP2000_CAP_SIZE 0x00100000 +/* + * Addresses for specific on-chip peripherals + */ +#define IXP2000_SLOWPORT_CSR_VIRT_BASE 0xfef80000 +#define IXP2000_GLOBAL_REG_VIRT_BASE 0xfef04000 #define IXP2000_UART_PHYS_BASE 0xc0030000 #define IXP2000_UART_VIRT_BASE 0xfef30000 -#define IXP2000_UART_SIZE 0x1000 - -#define IXP2000_TIMER_PHYS_BASE 0xc0020000 -#define IXP2000_TIMER_VIRT_BASE 0xfeffc000 -#define IXP2000_TIMER_SIZE 0x1000 - -#define IXP2000_GPIO_PHYS_BASE 0xc0010000 -#define IXP2000_GPIO_VIRT_BASE 0xfeffb000 -#define IXP2000_GPIO_SIZE 0x1000 +#define IXP2000_TIMER_VIRT_BASE 0xfef20000 +#define IXP2000_GPIO_VIRT_BASE 0Xfef10000 +/* + * Devices outside of the 0xc0000000 -> 0xc0100000 range + */ #define IXP2000_INTCTL_PHYS_BASE 0xd6000000 -#define IXP2000_INTCTL_VIRT_BASE 0xfeffa000 -#define IXP2000_INTCTL_SIZE 0x01000 +#define IXP2000_INTCTL_VIRT_BASE 0xfee00000 +#define IXP2000_INTCTL_SIZE 0x00100000 #define IXP2000_PCI_CREG_PHYS_BASE 0xde000000 -#define IXP2000_PCI_CREG_VIRT_BASE 0xfeff0000 -#define IXP2000_PCI_CREG_SIZE 0x1000 +#define IXP2000_PCI_CREG_VIRT_BASE 0xfed00000 +#define IXP2000_PCI_CREG_SIZE 0x00100000 #define IXP2000_PCI_CSR_PHYS_BASE 0xdf000000 -#define IXP2000_PCI_CSR_VIRT_BASE 0xfefde000 -#define IXP2000_PCI_CSR_SIZE 0x1000 +#define IXP2000_PCI_CSR_VIRT_BASE 0xfec00000 +#define IXP2000_PCI_CSR_SIZE 0x00100000 #define IXP2000_PCI_IO_PHYS_BASE 0xd8000000 #define IXP2000_PCI_IO_VIRT_BASE 0xfd000000 @@ -67,7 +75,6 @@ #define IXP2000_PCI_CFG1_VIRT_BASE 0xfb000000 #define IXP2000_PCI_CFG1_SIZE 0x01000000 - /* * Timers */ diff --git a/include/asm-arm/arch-ixp2000/vmalloc.h b/include/asm-arm/arch-ixp2000/vmalloc.h index f2705a85e1ff..2e4bcbcf31f0 100644 --- a/include/asm-arm/arch-ixp2000/vmalloc.h +++ b/include/asm-arm/arch-ixp2000/vmalloc.h @@ -20,4 +20,4 @@ #define VMALLOC_OFFSET (8*1024*1024) #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END 0xfb000000 +#define VMALLOC_END 0xfaffefff -- cgit v1.2.3 From f25b6a2703e6a03541335710b20c1b90e93301cc Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 3 Mar 2005 22:09:57 +0000 Subject: [ARM PATCH] 2508/1: S3C2440 - timer and irq device updates Patch from Ben Dooks The patch does a number of updates, which are inter-dependant on each other, for the s3c2440 support and some clean-ups for all s3c24xx architecture in general. 1) Remove the s3c24xx_{fclk,hclk,pclk} variables, and pass these values to the clock core on initialisation. This removes the needless double copy, as only the timer code uses these directly (see point 4). Add an over-all xtal clock to the clock core 2) Add a sysdev driver to the clock code to ensure all the s3c2440 clocks are added if an s3c2440 is present. 3) Add the new IRQs to irq.c, and initialise them if the sysdev for the s3c2440 is present. 4) Change the timer code to request the timer clk and use it to get the frequency. Depends on patch 2467/1 Thanks to Guillaume Gourat for the original patches that prompted this re-write. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/clock.c | 96 +++++++++++++++++--- arch/arm/mach-s3c2410/clock.h | 15 ++-- arch/arm/mach-s3c2410/cpu.c | 9 +- arch/arm/mach-s3c2410/cpu.h | 5 ++ arch/arm/mach-s3c2410/irq.c | 173 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-s3c2410/s3c2410.c | 17 ++-- arch/arm/mach-s3c2410/s3c2440.c | 72 +++++++-------- arch/arm/mach-s3c2410/time.c | 23 ++++- include/asm-arm/arch-s3c2410/irqs.h | 17 +++- 9 files changed, 344 insertions(+), 83 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index f6d7470fe531..e23f534d4e1d 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -1,7 +1,7 @@ /* linux/arch/arm/mach-s3c2410/clock.c * - * Copyright (c) 2004 Simtec Electronics - * Ben Dooks + * Copyright (c) 2004-2005 Simtec Electronics + * Ben Dooks * * S3C2410 Clock control support * @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -46,18 +47,13 @@ #include #include "clock.h" +#include "cpu.h" /* clock information */ -unsigned long s3c24xx_xtal = 12*1000*1000; /* default 12MHz */ -unsigned long s3c24xx_fclk; -unsigned long s3c24xx_hclk; -unsigned long s3c24xx_pclk; - static LIST_HEAD(clocks); static DECLARE_MUTEX(clocks_sem); - /* old functions */ void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable) @@ -206,6 +202,14 @@ EXPORT_SYMBOL(clk_get_parent); /* base clocks */ +static struct clk clk_xtal = { + .name = "xtal", + .id = -1, + .rate = 0, + .parent = NULL, + .ctrlbit = 0, +}; + static struct clk clk_f = { .name = "fclk", .id = -1, @@ -286,6 +290,7 @@ static struct clk init_clocks[] = { .ctrlbit = S3C2410_CLKCON_USBD }, { .name = "timers", + .id = -1, .parent = &clk_p, .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_PWMT @@ -378,19 +383,24 @@ int s3c24xx_register_clock(struct clk *clk) /* initalise all the clocks */ -int __init s3c24xx_setup_clocks(void) +int __init s3c24xx_setup_clocks(unsigned long xtal, + unsigned long fclk, + unsigned long hclk, + unsigned long pclk) { struct clk *clkp = init_clocks; int ptr; int ret; - printk(KERN_INFO "S3C2410 Clock control, (c) 2004 Simtec Electronics\n"); + printk(KERN_INFO "S3C2410 Clocks, (c) 2004 Simtec Electronics\n"); /* initialise the main system clocks */ - clk_h.rate = s3c24xx_hclk; - clk_p.rate = s3c24xx_pclk; - clk_f.rate = s3c24xx_fclk; + clk_xtal.rate = xtal; + + clk_h.rate = hclk; + clk_p.rate = pclk; + clk_f.rate = fclk; /* it looks like just setting the register here is not good * enough, and causes the odd hang at initial boot time, so @@ -414,6 +424,9 @@ int __init s3c24xx_setup_clocks(void) /* register our clocks */ + if (s3c24xx_register_clock(&clk_xtal) < 0) + printk(KERN_ERR "failed to register master xtal\n"); + if (s3c24xx_register_clock(&clk_f) < 0) printk(KERN_ERR "failed to register cpu fclk\n"); @@ -423,6 +436,8 @@ int __init s3c24xx_setup_clocks(void) if (s3c24xx_register_clock(&clk_p) < 0) printk(KERN_ERR "failed to register cpu pclk\n"); + /* register clocks from clock array */ + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { ret = s3c24xx_register_clock(clkp); if (ret < 0) { @@ -434,4 +449,59 @@ int __init s3c24xx_setup_clocks(void) return 0; } +/* S3C2440 extended clock support */ + +#ifdef CONFIG_CPU_S3C2440 + +static struct clk s3c2440_clk_upll = { + .name = "upll", + .id = -1, +}; + +static struct clk s3c2440_clk_cam = { + .name = "camif", + .parent = &clk_h, + .id = -1, + .enable = s3c24xx_clkcon_enable, + .ctrlbit = S3C2440_CLKCON_CAMERA, +}; + +static struct clk s3c2440_clk_ac97 = { + .name = "ac97", + .parent = &clk_p, + .id = -1, + .enable = s3c24xx_clkcon_enable, + .ctrlbit = S3C2440_CLKCON_CAMERA, +}; + +static int s3c2440_clk_add(struct sys_device *sysdev) +{ + unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); + + s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate) * 2; + + printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n", + print_mhz(s3c2440_clk_upll.rate)); + + s3c24xx_register_clock(&s3c2440_clk_ac97); + s3c24xx_register_clock(&s3c2440_clk_cam); + s3c24xx_register_clock(&s3c2440_clk_upll); + + clk_disable(&s3c2440_clk_ac97); + clk_disable(&s3c2440_clk_cam); + + return 0; +} + +static struct sysdev_driver s3c2440_clk_driver = { + .add = s3c2440_clk_add, +}; + +static int s3c24xx_clk_driver(void) +{ + return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_clk_driver); +} + +arch_initcall(s3c24xx_clk_driver); +#endif /* CONFIG_CPU_S3C2440 */ diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h index eae2c8337569..7953b6f397b9 100644 --- a/arch/arm/mach-s3c2410/clock.h +++ b/arch/arm/mach-s3c2410/clock.h @@ -1,7 +1,8 @@ /* * linux/arch/arm/mach-s3c2410/clock.h * - * Copyright (c) 2004 Simtec Electronics + * Copyright (c) 2004-2005 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ * Written by Ben Dooks, * * This program is free software; you can redistribute it and/or modify @@ -29,13 +30,6 @@ extern struct clk s3c24xx_clkout0; extern struct clk s3c24xx_clkout1; extern struct clk s3c24xx_uclk; -/* processor clock settings, in Hz */ - -extern unsigned long s3c24xx_xtal; -extern unsigned long s3c24xx_pclk; -extern unsigned long s3c24xx_hclk; -extern unsigned long s3c24xx_fclk; - /* exports for arch/arm/mach-s3c2410 * * Please DO NOT use these outside of arch/arm/mach-s3c2410 @@ -44,4 +38,7 @@ extern unsigned long s3c24xx_fclk; extern int s3c24xx_clkcon_enable(struct clk *clk, int enable); extern int s3c24xx_register_clock(struct clk *clk); -extern int s3c24xx_setup_clocks(void); +extern int s3c24xx_setup_clocks(unsigned long xtal, + unsigned long fclk, + unsigned long hclk, + unsigned long pclk); diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c index 0a66065360c8..ca366e9e264d 100644 --- a/arch/arm/mach-s3c2410/cpu.c +++ b/arch/arm/mach-s3c2410/cpu.c @@ -1,7 +1,8 @@ /* linux/arch/arm/mach-s3c2410/cpu.c * - * Copyright (c) 2004 Simtec Electronics - * Ben Dooks + * Copyright (c) 2004-2005 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks * * S3C24XX CPU Support * @@ -181,8 +182,8 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) void __init s3c24xx_init_clocks(int xtal) { - if (xtal != 0) - s3c24xx_xtal = xtal; + if (xtal == 0) + xtal = 12*1000*1000; if (cpu == NULL) panic("s3c24xx_init_clocks: no cpu setup?\n"); diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h index 4418be659fd1..30594b007a50 100644 --- a/arch/arm/mach-s3c2410/cpu.h +++ b/arch/arm/mach-s3c2410/cpu.h @@ -27,6 +27,7 @@ /* forward declaration */ struct s3c2410_uartcfg; +struct map_desc; /* core initialisation functions */ @@ -58,3 +59,7 @@ extern void s3c24xx_set_board(struct s3c24xx_board *board); struct sys_timer; extern struct sys_timer s3c24xx_timer; + +/* system device classes */ + +extern struct sysdev_class s3c2440_sysclass; diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 6b0b93e5aa41..257e5d70b6cd 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -57,6 +57,7 @@ #include #include +#include "cpu.h" #include "pm.h" #define irqdbf(x...) @@ -628,6 +629,7 @@ s3c_irq_demux_uart2(unsigned int irq, s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); } + /* s3c24xx_init_irq * * Initialise S3C2410 IRQ system @@ -771,3 +773,174 @@ void __init s3c24xx_init_irq(void) irqdbf("s3c2410: registered interrupt handlers\n"); } + +/* s3c2440 irq code +*/ + +#ifdef CONFIG_CPU_S3C2440 + +/* WDT/AC97 */ + +static void s3c_irq_demux_wdtac97(unsigned int irq, + struct irqdesc *desc, + struct pt_regs *regs) +{ + unsigned int subsrc, submsk; + struct irqdesc *mydesc; + + /* read the current pending interrupts, and the mask + * for what it is available */ + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + subsrc &= ~submsk; + subsrc >>= 13; + subsrc &= 3; + + if (subsrc != 0) { + if (subsrc & 1) { + mydesc = irq_desc + IRQ_S3C2440_WDT; + mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs); + } + if (subsrc & 2) { + mydesc = irq_desc + IRQ_S3C2440_AC97; + mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs); + } + } +} + + +#define INTMSK_WDT (1UL << (IRQ_WDT - IRQ_EINT0)) + +static void +s3c_irq_wdtac97_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13); +} + +static void +s3c_irq_wdtac97_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_WDT); +} + +static void +s3c_irq_wdtac97_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13); +} + +static struct irqchip s3c_irq_wdtac97 = { + .mask = s3c_irq_wdtac97_mask, + .unmask = s3c_irq_wdtac97_unmask, + .ack = s3c_irq_wdtac97_ack, +}; + +/* camera irq */ + +static void s3c_irq_demux_cam(unsigned int irq, + struct irqdesc *desc, + struct pt_regs *regs) +{ + unsigned int subsrc, submsk; + struct irqdesc *mydesc; + + /* read the current pending interrupts, and the mask + * for what it is available */ + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + subsrc &= ~submsk; + subsrc >>= 11; + subsrc &= 3; + + if (subsrc != 0) { + if (subsrc & 1) { + mydesc = irq_desc + IRQ_S3C2440_CAM_C; + mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs); + } + if (subsrc & 2) { + mydesc = irq_desc + IRQ_S3C2440_CAM_P; + mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs); + } + } +} + +#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) + +static void +s3c_irq_cam_mask(unsigned int irqno) +{ + s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11); +} + +static void +s3c_irq_cam_unmask(unsigned int irqno) +{ + s3c_irqsub_unmask(irqno, INTMSK_CAM); +} + +static void +s3c_irq_cam_ack(unsigned int irqno) +{ + s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11); +} + +static struct irqchip s3c_irq_cam = { + .mask = s3c_irq_cam_mask, + .unmask = s3c_irq_cam_unmask, + .ack = s3c_irq_cam_ack, +}; + +static int s3c2440_irq_add(struct sys_device *sysdev) +{ + unsigned int irqno; + + printk("S3C2440: IRQ Support\n"); + + set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip); + set_irq_handler(IRQ_NFCON, do_level_IRQ); + set_irq_flags(IRQ_NFCON, IRQF_VALID); + + /* add new chained handler for wdt, ac7 */ + + set_irq_chip(IRQ_WDT, &s3c_irq_level_chip); + set_irq_handler(IRQ_WDT, do_level_IRQ); + set_irq_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97); + + for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) { + set_irq_chip(irqno, &s3c_irq_wdtac97); + set_irq_handler(irqno, do_level_IRQ); + set_irq_flags(irqno, IRQF_VALID); + } + + /* add chained handler for camera */ + + set_irq_chip(IRQ_CAM, &s3c_irq_level_chip); + set_irq_handler(IRQ_CAM, do_level_IRQ); + set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam); + + for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) { + set_irq_chip(irqno, &s3c_irq_cam); + set_irq_handler(irqno, do_level_IRQ); + set_irq_flags(irqno, IRQF_VALID); + } + + return 0; +} + +static struct sysdev_driver s3c2440_irq_driver = { + .add = s3c2440_irq_add, +}; + +static int s3c24xx_irq_driver(void) +{ + return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver); +} + +arch_initcall(s3c24xx_irq_driver); + +#endif /* CONFIG_CPU_S3C2440 */ + diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index b8270f26b084..ff2f25409e44 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c @@ -17,7 +17,7 @@ * 21-Aug-2004 BJD Added new struct s3c2410_board handler * 28-Sep-2004 BJD Updates for new serial port bits * 04-Nov-2004 BJD Updated UART configuration process - * 10-Jan-2004 BJD Removed s3c2410_clock_tick_rate + * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate */ #include @@ -164,31 +164,32 @@ void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size) void __init s3c2410_init_clocks(int xtal) { unsigned long tmp; + unsigned long fclk; + unsigned long hclk; + unsigned long pclk; /* now we've got our machine bits initialised, work out what * clocks we've got */ - s3c24xx_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), - s3c24xx_xtal); + fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal); tmp = __raw_readl(S3C2410_CLKDIVN); /* work out clock scalings */ - s3c24xx_hclk = s3c24xx_fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1); - s3c24xx_pclk = s3c24xx_hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1); + hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1); + pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1); /* print brieft summary of clocks, etc */ printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", - print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk), - print_mhz(s3c24xx_pclk)); + print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); /* initialise the clocks here, to allow other things like the * console to use them */ - s3c24xx_setup_clocks(); + s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); } int __init s3c2410_init(void) diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c index 58146b8f6574..7799d8149461 100644 --- a/arch/arm/mach-s3c2410/s3c2440.c +++ b/arch/arm/mach-s3c2410/s3c2440.c @@ -109,7 +109,6 @@ static struct platform_device s3c_uart0 = { .resource = s3c_uart0_resource, }; - static struct platform_device s3c_uart1 = { .name = "s3c2440-uart", .id = 1, @@ -149,19 +148,6 @@ void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no) s3c2440_uart_count = uart; } -/* s3c2440 specific clock sources */ - -static struct clk s3c2440_clk_cam = { - .name = "camera", - .enable = s3c24xx_clkcon_enable, - .ctrlbit = S3C2440_CLKCON_CAMERA -}; - -static struct clk s3c2440_clk_ac97 = { - .name = "ac97", - .enable = s3c24xx_clkcon_enable, - .ctrlbit = S3C2440_CLKCON_CAMERA -}; #ifdef CONFIG_PM @@ -190,7 +176,7 @@ static int s3c2440_resume(struct sys_device *dev) #define s3c2440_resume NULL #endif -static struct sysdev_class s3c2440_sysclass = { +struct sysdev_class s3c2440_sysclass = { set_kset_name("s3c2440-core"), .suspend = s3c2440_suspend, .resume = s3c2440_resume @@ -209,19 +195,24 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size) /* rename any peripherals used differing from the s3c2410 */ s3c_device_i2c.name = "s3c2440-i2c"; + + /* change irq for watchdog */ + + s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT; + s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT; } void __init s3c2440_init_clocks(int xtal) { unsigned long clkdiv; unsigned long camdiv; - int s3c2440_hdiv = 1; + unsigned long hclk, fclk, pclk; + int hdiv = 1; /* now we've got our machine bits initialised, work out what * clocks we've got */ - s3c24xx_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), - s3c24xx_xtal) * 2; + fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2; clkdiv = __raw_readl(S3C2410_CLKDIVN); camdiv = __raw_readl(S3C2440_CAMDIVN); @@ -230,63 +221,60 @@ void __init s3c2440_init_clocks(int xtal) switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) { case S3C2440_CLKDIVN_HDIVN_1: - s3c2440_hdiv = 1; + hdiv = 1; break; case S3C2440_CLKDIVN_HDIVN_2: - s3c2440_hdiv = 1; + hdiv = 1; break; case S3C2440_CLKDIVN_HDIVN_4_8: - s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4; + hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4; break; case S3C2440_CLKDIVN_HDIVN_3_6: - s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3; + hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3; break; } - s3c24xx_hclk = s3c24xx_fclk / s3c2440_hdiv; - s3c24xx_pclk = s3c24xx_hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1); + hclk = fclk / hdiv; + pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1); /* print brief summary of clocks, etc */ printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", - print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk), - print_mhz(s3c24xx_pclk)); + print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); /* initialise the clocks here, to allow other things like the * console to use them, and to add new ones after the initialisation */ - s3c24xx_setup_clocks(); - - /* add s3c2440 specific clocks */ - - s3c2440_clk_cam.parent = clk_get(NULL, "hclk"); - s3c2440_clk_ac97.parent = clk_get(NULL, "pclk"); + s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); +} - s3c24xx_register_clock(&s3c2440_clk_ac97); - s3c24xx_register_clock(&s3c2440_clk_cam); +/* need to register class before we actually register the device, and + * we also need to ensure that it has been initialised before any of the + * drivers even try to use it (even if not on an s3c2440 based system) + * as a driver which may support both 2410 and 2440 may try and use it. +*/ - clk_disable(&s3c2440_clk_ac97); - clk_disable(&s3c2440_clk_cam); +int __init s3c2440_core_init(void) +{ + return sysdev_class_register(&s3c2440_sysclass); } +core_initcall(s3c2440_core_init); + int __init s3c2440_init(void) { int ret; printk("S3C2440: Initialising architecture\n"); - ret = sysdev_class_register(&s3c2440_sysclass); - if (ret == 0) - ret = sysdev_register(&s3c2440_sysdev); - + ret = sysdev_register(&s3c2440_sysdev); if (ret != 0) printk(KERN_ERR "failed to register sysdev for s3c2440\n"); - - if (ret == 0) + else ret = platform_add_devices(s3c24xx_uart_devs, s3c2440_uart_count); return ret; diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c index 715d65a40341..179f0e031af4 100644 --- a/arch/arm/mach-s3c2410/time.c +++ b/arch/arm/mach-s3c2410/time.c @@ -1,6 +1,6 @@ /* linux/arch/arm/mach-s3c2410/time.c * - * Copyright (C) 2003,2004 Simtec Electronics + * Copyright (C) 2003-2005 Simtec Electronics * Ben Dooks, * * This program is free software; you can redistribute it and/or modify @@ -23,6 +23,8 @@ #include #include #include +#include + #include #include #include @@ -33,6 +35,7 @@ #include #include #include +#include #include "clock.h" @@ -169,6 +172,9 @@ static void s3c2410_timer_setup (void) tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1; } else { + unsigned long pclk; + struct clk *clk; + /* for the h1940 (and others), we use the pclk from the core * to generate the timer values. since values around 50 to * 70MHz are not values we can directly generate the timer @@ -180,7 +186,18 @@ static void s3c2410_timer_setup (void) /* this is used as default if no other timer can be found */ - timer_usec_ticks = timer_mask_usec_ticks(6, s3c24xx_pclk); + clk = clk_get(NULL, "timers"); + if (IS_ERR(clk)) + panic("failed to get clock for system timer"); + + clk_use(clk); + clk_enable(clk); + + pclk = clk_get_rate(clk); + + /* configure clock tick */ + + timer_usec_ticks = timer_mask_usec_ticks(6, pclk); tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; tcfg1 |= S3C2410_TCFG1_MUX4_DIV2; @@ -188,7 +205,7 @@ static void s3c2410_timer_setup (void) tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT; - tcnt = (s3c24xx_pclk / 6) / HZ; + tcnt = (pclk / 6) / HZ; } /* timers reload after counting zero, so reduce the count by 1 */ diff --git a/include/asm-arm/arch-s3c2410/irqs.h b/include/asm-arm/arch-s3c2410/irqs.h index e914da46c0e7..d9773d697268 100644 --- a/include/asm-arm/arch-s3c2410/irqs.h +++ b/include/asm-arm/arch-s3c2410/irqs.h @@ -1,6 +1,6 @@ /* linux/include/asm-arm/arch-s3c2410/irqs.h * - * Copyright (c) 2003 Simtec Electronics + * Copyright (c) 2003-2005 Simtec Electronics * Ben Dooks * * This program is free software; you can redistribute it and/or modify @@ -12,6 +12,7 @@ * 08-Jan-2003 BJD Linux 2.6.0 version, moved BAST bits out * 12-Mar-2004 BJD Fixed bug in header protection * 10-Feb-2005 BJD Added camera IRQ from guillaume.gourat@nexvision.tv + * 28-Feb-2005 BJD Updated s3c2440 IRQs */ @@ -36,8 +37,8 @@ #define IRQ_EINT3 S3C2410_IRQ(3) #define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */ #define IRQ_EINT8t23 S3C2410_IRQ(5) -#define IRQ_RESERVED6 S3C2410_IRQ(6) /* for s3c2410 */ -#define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440 */ +#define IRQ_RESERVED6 S3C2410_IRQ(6) /* for s3c2410 */ +#define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440 */ #define IRQ_BATT_FLT S3C2410_IRQ(7) #define IRQ_TICK S3C2410_IRQ(8) /* 24 */ #define IRQ_WDT S3C2410_IRQ(9) @@ -56,6 +57,7 @@ #define IRQ_SPI0 S3C2410_IRQ(22) #define IRQ_UART1 S3C2410_IRQ(23) #define IRQ_RESERVED24 S3C2410_IRQ(24) /* 40 */ +#define IRQ_NFCON S3C2410_IRQ(24) /* for s3c2440 */ #define IRQ_USBD S3C2410_IRQ(25) #define IRQ_USBH S3C2410_IRQ(26) #define IRQ_IIC S3C2410_IRQ(27) @@ -111,7 +113,14 @@ #define IRQ_TC S3C2410_IRQ(63) #define IRQ_ADC S3C2410_IRQ(64) -#define NR_IRQS (IRQ_ADC+1) +/* extra irqs for s3c2440 */ + +#define IRQ_S3C2440_CAM_C S3C2410_IRQ(65) +#define IRQ_S3C2440_CAM_P S3C2410_IRQ(66) +#define IRQ_S3C2440_WDT S3C2410_IRQ(67) +#define IRQ_S3C2440_AC97 S3C2410_IRQ(68) + +#define NR_IRQS (IRQ_S3C2440_AC97+1) #endif /* __ASM_ARCH_IRQ_H */ -- cgit v1.2.3 From 1234c028b77dc57bd725017c08fb9ca4fe66efd6 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 3 Mar 2005 22:57:33 +0000 Subject: [ARM PATCH] 2512/1: S3C2410 - remove bast-cpld.h from include/asm-arm/arch-s3c2410/hardware.h Patch from Ben Dooks Remove the include of bast-cpld.h, as it shouldn't be here as it only defines some extra bast-specific registers, and does not affect the configuration of the hardware dependenat items. Ensure that the file is included in the one place it is needed and not included. This should discourage anyone else putting include files in which do not affect the over-all hardware definitions. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/mach-bast.c | 2 ++ include/asm-arm/arch-s3c2410/hardware.h | 6 +----- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index 96292e632343..792481c4dc89 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -23,6 +23,7 @@ * 04-Jan-2005 BJD New uart init call * 10-Jan-2005 BJD Removed include of s3c2410.h * 14-Jan-2005 BJD Add support for muitlple NAND devices + * 03-Mar-2005 BJD Ensured that bast-cpld.h is included */ #include @@ -39,6 +40,7 @@ #include #include +#include #include #include diff --git a/include/asm-arm/arch-s3c2410/hardware.h b/include/asm-arm/arch-s3c2410/hardware.h index 7b489fde8fdf..48a39918a760 100644 --- a/include/asm-arm/arch-s3c2410/hardware.h +++ b/include/asm-arm/arch-s3c2410/hardware.h @@ -97,11 +97,7 @@ extern unsigned int s3c2410_modify_misccr(unsigned int clr, unsigned int chg); #include #include -/* machine specific includes, such as the BAST */ - -#if defined(CONFIG_ARCH_BAST) -#include -#endif +/* machine specific hardware definitions should go after this */ /* currently here until moved into config (todo) */ #define CONFIG_NO_MULTIWORD_IO -- cgit v1.2.3 From 49ee1b77fa886dae22f7b901517a8049dc89a26a Mon Sep 17 00:00:00 2001 From: "George G. Davis" Date: Fri, 4 Mar 2005 18:19:21 +0000 Subject: [ARM PATCH] 2459/1: ARMv6 supersections for static kernel direct mapped memory regions [updated] Patch from George G. Davis Use ARMv6 supersections for 16MiB static kernel direct mapped memory regions when possible. Based on comments received for the first version of this patch, this version has added a comment to clarify that ARMv6 supersections are only valid for the domain == 0 case and moved the supersection address mask and size macros before the hardware page table definitions. Signed-off-by: George G. Davis Signed-off-by: Russell King --- arch/arm/mm/mm-armv.c | 44 +++++++++++++++++++++++++++++++++++++++++++- include/asm-arm/pgtable.h | 8 ++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index a9c9c33dfbc3..0bcdbd73e1f1 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -255,6 +255,23 @@ alloc_init_section(unsigned long virt, unsigned long phys, int prot) set_pmd(pmdp, __pmd(phys | prot)); } +/* + * Create a SUPER SECTION PGD between VIRT and PHYS with protection PROT + */ +static inline void +alloc_init_supersection(unsigned long virt, unsigned long phys, int prot) +{ + int i; + + for (i = 0; i < 16; i += 1) { + alloc_init_section(virt, phys & SUPERSECTION_MASK, + prot | PMD_SECT_SUPER); + + virt += (PGDIR_SIZE / 2); + phys += (PGDIR_SIZE / 2); + } +} + /* * Add a PAGE mapping between VIRT and PHYS in domain * DOMAIN with protection PROT. Note that due to the @@ -436,7 +453,8 @@ static void __init build_mem_type_table(void) * Create the page directory entries and any necessary * page tables for the mapping specified by `md'. We * are able to cope here with varying sizes and address - * offsets, and we take full advantage of sections. + * offsets, and we take full advantage of sections and + * supersections. */ static void __init create_mapping(struct map_desc *md) { @@ -483,6 +501,30 @@ static void __init create_mapping(struct map_desc *md) length -= PAGE_SIZE; } + /* N.B. ARMv6 supersections are only defined to work with domain 0. + * Since domain assignments can in fact be arbitrary, the + * 'domain == 0' check below is required to insure that ARMv6 + * supersections are only allocated for domain 0 regardless + * of the actual domain assignments in use. + */ + if (cpu_architecture() >= CPU_ARCH_ARMv6 && domain == 0) { + /* Align to supersection boundary */ + while ((virt & ~SUPERSECTION_MASK || (virt + off) & + ~SUPERSECTION_MASK) && length >= (PGDIR_SIZE / 2)) { + alloc_init_section(virt, virt + off, prot_sect); + + virt += (PGDIR_SIZE / 2); + length -= (PGDIR_SIZE / 2); + } + + while (length >= SUPERSECTION_SIZE) { + alloc_init_supersection(virt, virt + off, prot_sect); + + virt += SUPERSECTION_SIZE; + length -= SUPERSECTION_SIZE; + } + } + /* * A section mapping covers half a "pgdir" entry. */ diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h index 10d747ba0ce0..e2a4177c31d3 100644 --- a/include/asm-arm/pgtable.h +++ b/include/asm-arm/pgtable.h @@ -105,6 +105,13 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define FIRST_USER_PGD_NR 1 #define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR) +/* + * ARMv6 supersection address mask and size definitions. + */ +#define SUPERSECTION_SHIFT 24 +#define SUPERSECTION_SIZE (1UL << SUPERSECTION_SHIFT) +#define SUPERSECTION_MASK (~(SUPERSECTION_SIZE-1)) + /* * Hardware page table definitions. * @@ -129,6 +136,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define PMD_SECT_APX (1 << 15) /* v6 */ #define PMD_SECT_S (1 << 16) /* v6 */ #define PMD_SECT_nG (1 << 17) /* v6 */ +#define PMD_SECT_SUPER (1 << 18) /* v6 */ #define PMD_SECT_UNCACHED (0) #define PMD_SECT_BUFFERED (PMD_SECT_BUFFERABLE) -- cgit v1.2.3 From 6bf03de1d2686d5aafbbf40b2c328b5735ce672a Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Fri, 4 Mar 2005 17:13:22 -0800 Subject: [PATCH] nfsd: svcrpc: add a per-flavor set_client method Add a set_client method to the server rpc auth_ops struct, used to set the client (for the purposes of nfsd export authorization) using flavor-specific information. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svcauth.h | 2 ++ net/sunrpc/auth_gss/svcauth_gss.c | 14 ++++++++++++++ net/sunrpc/sunrpc_syms.c | 1 + net/sunrpc/svcauth.c | 5 +++++ net/sunrpc/svcauth_unix.c | 2 ++ 5 files changed, 24 insertions(+) (limited to 'include') diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index 5c16a7519c6c..29a1b14bb218 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h @@ -92,6 +92,7 @@ struct auth_ops { int (*accept)(struct svc_rqst *rq, u32 *authp); int (*release)(struct svc_rqst *rq); void (*domain_release)(struct auth_domain *); + int (*set_client)(struct svc_rqst *rq); }; #define SVC_GARBAGE 1 @@ -107,6 +108,7 @@ struct auth_ops { extern int svc_authenticate(struct svc_rqst *rqstp, u32 *authp); extern int svc_authorise(struct svc_rqst *rqstp); +extern int svc_set_client(struct svc_rqst *rqstp); extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops); extern void svc_auth_unregister(rpc_authflavor_t flavor); diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 1b4a111142e0..c74fa221a303 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -730,6 +730,19 @@ struct gss_svc_data { struct rsc *rsci; }; +static int +svcauth_gss_set_client(struct svc_rqst *rqstp) +{ + struct gss_svc_data *svcdata = rqstp->rq_auth_data; + struct rsc *rsci = svcdata->rsci; + struct rpc_gss_wire_cred *gc = &svcdata->clcred; + + rqstp->rq_client = find_gss_auth_domain(rsci->mechctx, gc->gc_svc); + if (rqstp->rq_client == NULL) + return SVC_DENIED; + return SVC_OK; +} + /* * Accept an rpcsec packet. * If context establishment, punt to user space @@ -1052,6 +1065,7 @@ static struct auth_ops svcauthops_gss = { .accept = svcauth_gss_accept, .release = svcauth_gss_release, .domain_release = svcauth_gss_domain_release, + .set_client = svcauth_gss_set_client, }; int diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 1876751172be..d4f26bf9e732 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -90,6 +90,7 @@ EXPORT_SYMBOL(svc_reserve); EXPORT_SYMBOL(svc_auth_register); EXPORT_SYMBOL(auth_domain_lookup); EXPORT_SYMBOL(svc_authenticate); +EXPORT_SYMBOL(svc_set_client); /* RPC statistics */ #ifdef CONFIG_PROC_FS diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index 0148c3310157..7fefed46d591 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c @@ -59,6 +59,11 @@ svc_authenticate(struct svc_rqst *rqstp, u32 *authp) return aops->accept(rqstp, authp); } +int svc_set_client(struct svc_rqst *rqstp) +{ + return rqstp->rq_authop->set_client(rqstp); +} + /* A request, which was authenticated, has now executed. * Time to finalise the the credentials and verifier * and release and resources diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 580eb7596d6c..01f26cf87586 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -429,6 +429,7 @@ struct auth_ops svcauth_null = { .flavour = RPC_AUTH_NULL, .accept = svcauth_null_accept, .release = svcauth_null_release, + .set_client = svcauth_unix_set_client, }; @@ -510,5 +511,6 @@ struct auth_ops svcauth_unix = { .accept = svcauth_unix_accept, .release = svcauth_unix_release, .domain_release = svcauth_unix_domain_release, + .set_client = svcauth_unix_set_client, }; -- cgit v1.2.3 From 6147285bf4c2328556f98a501fc97973f6a3a23f Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Fri, 4 Mar 2005 17:13:35 -0800 Subject: [PATCH] nfsd: svcrpc: rename pg_authenticate Later patches remove pg_authenticate and use the name for a different purpose; so rename it to pg_authenticate_obsolete for now. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/callback.c | 2 +- include/linux/sunrpc/svc.h | 2 +- net/sunrpc/svc.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index ad7677b4f21d..d4dc04fe01c6 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -321,5 +321,5 @@ static struct svc_program nfs4_callback_program = { .pg_name = "NFSv4 callback", /* service name */ .pg_class = "nfs", /* authentication class */ .pg_stats = &nfs4_callback_stats, - .pg_authenticate = nfs_callback_auth, + .pg_authenticate_obsolete = nfs_callback_auth, }; diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index f464260d6fdb..f2a9cb676329 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -252,7 +252,7 @@ struct svc_program { char * pg_class; /* class name: services sharing authentication */ struct svc_stat * pg_stats; /* rpc statistics */ /* Override authentication. NULL means use default */ - int (*pg_authenticate)(struct svc_rqst *, u32 *); + int (*pg_authenticate_obsolete)(struct svc_rqst *, u32 *); }; /* diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 8c5b0517db7f..3c89c744b795 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -311,8 +311,8 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) * We do this before anything else in order to get a decent * auth verifier. */ - if (progp->pg_authenticate != NULL) - auth_res = progp->pg_authenticate(rqstp, &auth_stat); + if (progp->pg_authenticate_obsolete != NULL) + auth_res = progp->pg_authenticate_obsolete(rqstp, &auth_stat); else auth_res = svc_authenticate(rqstp, &auth_stat); switch (auth_res) { -- cgit v1.2.3 From 556d600cd16d20949f6c9bbfe07c7ca2e8f85789 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Fri, 4 Mar 2005 17:13:48 -0800 Subject: [PATCH] nfsd: svcrpc: move export table checks to a per-program pg_add_client method svcauth_null_accept() and svcauth_unix_accept() are currently hard-wired to check the source ip address on an incoming request against the export table, which make sense for nfsd but not necessarily for other rpc-based services. So instead we have the accept() method call a program-specific pg_authenticate() method. We also move the call to this method into svc_process instead of calling it from the flavor-specific accept() routines. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc.c | 15 +++++++++++++++ fs/nfsd/nfssvc.c | 2 ++ include/linux/sunrpc/svc.h | 1 + net/sunrpc/auth_gss/svcauth_gss.c | 9 ++------- net/sunrpc/svc.c | 12 +++++++++++- net/sunrpc/svcauth_unix.c | 18 ++---------------- 6 files changed, 33 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index d3ee09c5196e..6cba9b0ee7ed 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -403,6 +403,20 @@ static int param_set_##name(const char *val, struct kernel_param *kp) \ return 0; \ } +static int lockd_authenticate(struct svc_rqst *rqstp) +{ + rqstp->rq_client = NULL; + switch (rqstp->rq_authop->flavour) { + case RPC_AUTH_NULL: + case RPC_AUTH_UNIX: + if (rqstp->rq_proc == 0) + return SVC_OK; + return svc_set_client(rqstp); + } + return SVC_DENIED; +} + + param_set_min_max(port, int, simple_strtol, 0, 65535) param_set_min_max(grace_period, unsigned long, simple_strtoul, nlm_grace_period_min, nlm_grace_period_max) @@ -483,4 +497,5 @@ static struct svc_program nlmsvc_program = { .pg_name = "lockd", /* service name */ .pg_class = "nfsd", /* share authentication with nfsd */ .pg_stats = &nlmsvc_stats, /* stats table */ + .pg_authenticate = &lockd_authenticate /* export authentication */ }; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 291dd8cd3214..2b360eb284a1 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -378,4 +378,6 @@ struct svc_program nfsd_program = { .pg_name = "nfsd", /* program name */ .pg_class = "nfsd", /* authentication class */ .pg_stats = &nfsd_svcstats, /* version table */ + .pg_authenticate = &svc_set_client, /* export authentication */ + }; diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index f2a9cb676329..08944c9f1754 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -253,6 +253,7 @@ struct svc_program { struct svc_stat * pg_stats; /* rpc statistics */ /* Override authentication. NULL means use default */ int (*pg_authenticate_obsolete)(struct svc_rqst *, u32 *); + int (*pg_authenticate)(struct svc_rqst *); }; /* diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index c74fa221a303..d806bafe106c 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -906,11 +906,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) svc_putu32(resv, rpc_success); goto complete; case RPC_GSS_PROC_DATA: - *authp = rpc_autherr_badcred; - rqstp->rq_client = - find_gss_auth_domain(rsci->mechctx, gc->gc_svc); - if (rqstp->rq_client == NULL) - goto auth_err; *authp = rpcsec_gsserr_ctxproblem; if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq)) goto auth_err; @@ -924,8 +919,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) if (unwrap_integ_data(&rqstp->rq_arg, gc->gc_seq, rsci->mechctx)) goto auth_err; - svcdata->rsci = rsci; - cache_get(&rsci->h); /* placeholders for length and seq. number: */ svcdata->body_start = resv->iov_base + resv->iov_len; svc_putu32(resv, 0); @@ -936,6 +929,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) default: goto auth_err; } + svcdata->rsci = rsci; + cache_get(&rsci->h); ret = SVC_OK; goto out; } diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 3c89c744b795..42344b166b5c 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -264,6 +264,7 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) u32 dir, prog, vers, proc, auth_stat, rpc_stat; int auth_res; + u32 *accept_statp; rpc_stat = rpc_success; @@ -299,6 +300,9 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) if (vers != 2) /* RPC version number */ goto err_bad_rpc; + /* Save position in case we later decide to reject: */ + accept_statp = resv->iov_base + resv->iov_len; + svc_putu32(resv, xdr_zero); /* ACCEPT */ rqstp->rq_prog = prog = ntohl(svc_getu32(argv)); /* program number */ @@ -315,6 +319,11 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) auth_res = progp->pg_authenticate_obsolete(rqstp, &auth_stat); else auth_res = svc_authenticate(rqstp, &auth_stat); + /* Also give the program a chance to reject this call: */ + if (auth_res == SVC_OK) { + auth_stat = rpc_autherr_badcred; + auth_res = progp->pg_authenticate(rqstp); + } switch (auth_res) { case SVC_OK: break; @@ -437,7 +446,8 @@ err_bad_rpc: err_bad_auth: dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); serv->sv_stats->rpcbadauth++; - resv->iov_len -= 4; + /* Restore write pointer to location of accept status: */ + xdr_ressize_check(rqstp, accept_statp); svc_putu32(resv, xdr_one); /* REJECT */ svc_putu32(resv, xdr_one); /* AUTH_ERROR */ svc_putu32(resv, auth_stat); /* status */ diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 01f26cf87586..2b99b4028d31 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -368,7 +368,6 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp) struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *resv = &rqstp->rq_res.head[0]; struct svc_cred *cred = &rqstp->rq_cred; - int rv=0; cred->cr_group_info = NULL; rqstp->rq_client = NULL; @@ -394,19 +393,11 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp) if (cred->cr_group_info == NULL) return SVC_DROP; /* kmalloc failure - client must retry */ - rv = svcauth_unix_set_client(rqstp); - if (rv == SVC_DENIED) - goto badcred; - /* Put NULL verifier */ svc_putu32(resv, RPC_AUTH_NULL); svc_putu32(resv, 0); - return rv; - -badcred: - *authp = rpc_autherr_badcred; - return SVC_DENIED; + return SVC_OK; } static int @@ -441,7 +432,6 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp) struct svc_cred *cred = &rqstp->rq_cred; u32 slen, i; int len = argv->iov_len; - int rv=0; cred->cr_group_info = NULL; rqstp->rq_client = NULL; @@ -473,15 +463,11 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp) return SVC_DENIED; } - rv = svcauth_unix_set_client(rqstp); - if (rv == SVC_DENIED) - goto badcred; - /* Put NULL verifier */ svc_putu32(resv, RPC_AUTH_NULL); svc_putu32(resv, 0); - return rv; + return SVC_OK; badcred: *authp = rpc_autherr_badcred; -- cgit v1.2.3 From c59e02e193f1206b57718d9c50160b489f20c258 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Fri, 4 Mar 2005 17:14:29 -0800 Subject: [PATCH] nfsd: nfsd: remove pg_authenticate field The pg_authenticate (now pg_authenticate_obsolete) callback was only being used by the nfs4 client callback code to circumvent the svcauth_unix code's insistence on checking all requests against the export table. With that problem solved, we no longer need it. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svc.h | 2 -- net/sunrpc/svc.c | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 08944c9f1754..37003970cf2e 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -251,8 +251,6 @@ struct svc_program { char * pg_name; /* service name */ char * pg_class; /* class name: services sharing authentication */ struct svc_stat * pg_stats; /* rpc statistics */ - /* Override authentication. NULL means use default */ - int (*pg_authenticate_obsolete)(struct svc_rqst *, u32 *); int (*pg_authenticate)(struct svc_rqst *); }; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 42344b166b5c..bb2d99f33315 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -315,10 +315,7 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) * We do this before anything else in order to get a decent * auth verifier. */ - if (progp->pg_authenticate_obsolete != NULL) - auth_res = progp->pg_authenticate_obsolete(rqstp, &auth_stat); - else - auth_res = svc_authenticate(rqstp, &auth_stat); + auth_res = svc_authenticate(rqstp, &auth_stat); /* Also give the program a chance to reject this call: */ if (auth_res == SVC_OK) { auth_stat = rpc_autherr_badcred; -- cgit v1.2.3 From edd9a0079e105fbd06b699c276d19fe4160dd1e7 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Fri, 4 Mar 2005 17:14:56 -0800 Subject: [PATCH] nfsd: change nfsd reply cache to use list.h lists also kmalloc the cache one entry at a time, instead of in one big slab. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfscache.c | 133 +++++++++++++++------------------------------ include/linux/nfsd/cache.h | 7 +-- 2 files changed, 47 insertions(+), 93 deletions(-) (limited to 'include') diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index a3236dfedf98..119e4d4495b8 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -30,15 +31,8 @@ #define HASHSIZE 64 #define REQHASH(xid) ((((xid) >> 24) ^ (xid)) & (HASHSIZE-1)) -struct nfscache_head { - struct svc_cacherep * next; - struct svc_cacherep * prev; -}; - -static struct nfscache_head * hash_list; -static struct svc_cacherep * lru_head; -static struct svc_cacherep * lru_tail; -static struct svc_cacherep * nfscache; +static struct hlist_head * hash_list; +static struct list_head lru_head; static int cache_disabled = 1; static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); @@ -54,46 +48,32 @@ void nfsd_cache_init(void) { struct svc_cacherep *rp; - struct nfscache_head *rh; - size_t i; - unsigned long order; - - - i = CACHESIZE * sizeof (struct svc_cacherep); - for (order = 0; (PAGE_SIZE << order) < i; order++) - ; - nfscache = (struct svc_cacherep *) - __get_free_pages(GFP_KERNEL, order); - if (!nfscache) { - printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for reply cache\n", i); - return; + int i; + + INIT_LIST_HEAD(&lru_head); + i = CACHESIZE; + while(i) { + rp = kmalloc(sizeof(*rp), GFP_KERNEL); + if (!rp) break; + list_add(&rp->c_lru, &lru_head); + rp->c_state = RC_UNUSED; + rp->c_type = RC_NOCACHE; + INIT_HLIST_NODE(&rp->c_hash); + i--; } - memset(nfscache, 0, i); - i = HASHSIZE * sizeof (struct nfscache_head); - hash_list = kmalloc (i, GFP_KERNEL); + if (i) + printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n", + CACHESIZE, CACHESIZE-i); + + hash_list = kmalloc (HASHSIZE * sizeof(struct hlist_head), GFP_KERNEL); if (!hash_list) { - free_pages ((unsigned long)nfscache, order); - nfscache = NULL; - printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n", i); + nfsd_cache_shutdown(); + printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n", + HASHSIZE * sizeof(struct hlist_head)); return; } - - for (i = 0, rh = hash_list; i < HASHSIZE; i++, rh++) - rh->next = rh->prev = (struct svc_cacherep *) rh; - - for (i = 0, rp = nfscache; i < CACHESIZE; i++, rp++) { - rp->c_state = RC_UNUSED; - rp->c_type = RC_NOCACHE; - rp->c_hash_next = - rp->c_hash_prev = rp; - rp->c_lru_next = rp + 1; - rp->c_lru_prev = rp - 1; - } - lru_head = nfscache; - lru_tail = nfscache + CACHESIZE - 1; - lru_head->c_lru_prev = NULL; - lru_tail->c_lru_next = NULL; + memset(hash_list, 0, HASHSIZE * sizeof(struct hlist_head)); cache_disabled = 0; } @@ -102,48 +82,30 @@ void nfsd_cache_shutdown(void) { struct svc_cacherep *rp; - size_t i; - unsigned long order; - for (rp = lru_head; rp; rp = rp->c_lru_next) { + while (!list_empty(&lru_head)) { + rp = list_entry(lru_head.next, struct svc_cacherep, c_lru); if (rp->c_state == RC_DONE && rp->c_type == RC_REPLBUFF) kfree(rp->c_replvec.iov_base); + list_del(&rp->c_lru); + kfree(rp); } cache_disabled = 1; - i = CACHESIZE * sizeof (struct svc_cacherep); - for (order = 0; (PAGE_SIZE << order) < i; order++) - ; - free_pages ((unsigned long)nfscache, order); - nfscache = NULL; - kfree (hash_list); + if (hash_list) + kfree (hash_list); hash_list = NULL; } /* - * Move cache entry to front of LRU list + * Move cache entry to end of LRU list */ static void -lru_put_front(struct svc_cacherep *rp) +lru_put_end(struct svc_cacherep *rp) { - struct svc_cacherep *prev = rp->c_lru_prev, - *next = rp->c_lru_next; - - if (prev) - prev->c_lru_next = next; - else - lru_head = next; - if (next) - next->c_lru_prev = prev; - else - lru_tail = prev; - - rp->c_lru_next = lru_head; - rp->c_lru_prev = NULL; - if (lru_head) - lru_head->c_lru_prev = rp; - lru_head = rp; + list_del(&rp->c_lru); + list_add_tail(&rp->c_lru, &lru_head); } /* @@ -152,17 +114,8 @@ lru_put_front(struct svc_cacherep *rp) static void hash_refile(struct svc_cacherep *rp) { - struct svc_cacherep *prev = rp->c_hash_prev, - *next = rp->c_hash_next; - struct nfscache_head *head = hash_list + REQHASH(rp->c_xid); - - prev->c_hash_next = next; - next->c_hash_prev = prev; - - rp->c_hash_next = head->next; - rp->c_hash_prev = (struct svc_cacherep *) head; - head->next->c_hash_prev = rp; - head->next = rp; + hlist_del_init(&rp->c_hash); + hlist_add_head(&rp->c_hash, hash_list + REQHASH(rp->c_xid)); } /* @@ -173,7 +126,9 @@ hash_refile(struct svc_cacherep *rp) int nfsd_cache_lookup(struct svc_rqst *rqstp, int type) { - struct svc_cacherep *rh, *rp; + struct hlist_node *hn; + struct hlist_head *rh; + struct svc_cacherep *rp; u32 xid = rqstp->rq_xid, proto = rqstp->rq_prot, vers = rqstp->rq_vers, @@ -190,8 +145,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) spin_lock(&cache_lock); rtn = RC_DOIT; - rp = rh = (struct svc_cacherep *) &hash_list[REQHASH(xid)]; - while ((rp = rp->c_hash_next) != rh) { + rh = &hash_list[REQHASH(xid)]; + hlist_for_each_entry(rp, hn, rh, c_hash) { if (rp->c_state != RC_UNUSED && xid == rp->c_xid && proc == rp->c_proc && proto == rp->c_prot && vers == rp->c_vers && @@ -206,7 +161,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) /* This loop shouldn't take more than a few iterations normally */ { int safe = 0; - for (rp = lru_tail; rp; rp = rp->c_lru_prev) { + list_for_each_entry(rp, &lru_head, c_lru) { if (rp->c_state != RC_INPROG) break; if (safe++ > CACHESIZE) { @@ -254,7 +209,7 @@ found_entry: /* We found a matching entry which is either in progress or done. */ age = jiffies - rp->c_timestamp; rp->c_timestamp = jiffies; - lru_put_front(rp); + lru_put_end(rp); rtn = RC_DROPIT; /* Request being processed or excessive rexmits */ @@ -343,7 +298,7 @@ nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, u32 *statp) break; } spin_lock(&cache_lock); - lru_put_front(rp); + lru_put_end(rp); rp->c_secure = rqstp->rq_secure; rp->c_type = cachetype; rp->c_state = RC_DONE; diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h index cfffc76fc1e1..c3a3557c2a5b 100644 --- a/include/linux/nfsd/cache.h +++ b/include/linux/nfsd/cache.h @@ -19,10 +19,9 @@ * be hash_next and hash_prev. */ struct svc_cacherep { - struct svc_cacherep * c_hash_next; - struct svc_cacherep * c_hash_prev; - struct svc_cacherep * c_lru_next; - struct svc_cacherep * c_lru_prev; + struct hlist_node c_hash; + struct list_head c_lru; + unsigned char c_state, /* unused, inprog, done */ c_type, /* status, buffer */ c_secure : 1; /* req came from port < 1024 */ -- cgit v1.2.3 From ba15d6aa95ae689b083a133a3689ff95f4c47321 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Fri, 4 Mar 2005 17:15:09 -0800 Subject: [PATCH] nfsd: discard CACHE_HASHED flag, keeping information in refcount instead. This patch should fix a problem that has been experienced on at-least one busy NFS server, but it has not had lots of testing yet. If -mm could provide that ..... The rpc auth cache currently differentiates between a reference due to being in a hash chain (signalled by CACHE_HASHED flag) and any other reference (counted in refcnt). This is an artificial difference due to an historical accident, and it makes cache_put unsafe. This patch removes the distinction so now existance in a hash chain is counted just like any other reference. Thus a race window in cache_put is closed. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/cache.h | 19 +++++-------------- net/sunrpc/cache.c | 4 +--- net/sunrpc/svcauth.c | 8 ++++---- 3 files changed, 10 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index b902425d2be5..6864063d1b9f 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -37,8 +37,7 @@ * Entries have a ref count and a 'hashed' flag which counts the existance * in the hash table. * We only expire entries when refcount is zero. - * Existance in the cache is not measured in refcount but rather in - * CACHE_HASHED flag. + * Existance in the cache is counted the refcount. */ /* Every cache item has a common header that is used @@ -57,7 +56,6 @@ struct cache_head { #define CACHE_VALID 0 /* Entry contains valid data */ #define CACHE_NEGATIVE 1 /* Negative entry - there is no match for the key */ #define CACHE_PENDING 2 /* An upcall has been sent but no reply received yet*/ -#define CACHE_HASHED 3 /* Entry is in a hash table */ #define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */ @@ -185,7 +183,6 @@ RTN *FNAME ARGS \ \ if (new) \ {INIT;} \ - cache_get(&tmp->MEMBER); \ if (set) { \ if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\ { /* need to swap in new */ \ @@ -194,8 +191,6 @@ RTN *FNAME ARGS \ new->MEMBER.next = tmp->MEMBER.next; \ *hp = &new->MEMBER; \ tmp->MEMBER.next = NULL; \ - set_bit(CACHE_HASHED, &new->MEMBER.flags); \ - clear_bit(CACHE_HASHED, &tmp->MEMBER.flags); \ t2 = tmp; tmp = new; new = t2; \ } \ if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags)) \ @@ -205,6 +200,7 @@ RTN *FNAME ARGS \ clear_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags); \ } \ } \ + cache_get(&tmp->MEMBER); \ if (set||new) write_unlock(&(DETAIL)->hash_lock); \ else read_unlock(&(DETAIL)->hash_lock); \ if (set) \ @@ -220,7 +216,7 @@ RTN *FNAME ARGS \ new->MEMBER.next = *head; \ *head = &new->MEMBER; \ (DETAIL)->entries ++; \ - set_bit(CACHE_HASHED, &new->MEMBER.flags); \ + cache_get(&new->MEMBER); \ if (set) { \ tmp = new; \ if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags)) \ @@ -268,15 +264,10 @@ static inline struct cache_head *cache_get(struct cache_head *h) static inline int cache_put(struct cache_head *h, struct cache_detail *cd) { - atomic_dec(&h->refcnt); - if (!atomic_read(&h->refcnt) && + if (atomic_read(&h->refcnt) <= 2 && h->expiry_time < cd->nextcheck) cd->nextcheck = h->expiry_time; - if (!test_bit(CACHE_HASHED, &h->flags) && - !atomic_read(&h->refcnt)) - return 1; - - return 0; + return atomic_dec_and_test(&h->refcnt); } extern void cache_init(struct cache_head *h); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index bf5a2dee8800..900f5bc7e336 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -321,12 +321,10 @@ static int cache_clean(void) if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) queue_loose(current_detail, ch); - if (!atomic_read(&ch->refcnt)) + if (atomic_read(&ch->refcnt) == 1) break; } if (ch) { - cache_get(ch); - clear_bit(CACHE_HASHED, &ch->flags); *cp = ch->next; ch->next = NULL; current_detail->entries--; diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index 7fefed46d591..bde8147ef2db 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c @@ -178,12 +178,12 @@ auth_domain_lookup(struct auth_domain *item, int set) tmp = container_of(*hp, struct auth_domain, h); if (!auth_domain_match(tmp, item)) continue; - cache_get(&tmp->h); - if (!set) + if (!set) { + cache_get(&tmp->h); goto out_noset; + } *hp = tmp->h.next; tmp->h.next = NULL; - clear_bit(CACHE_HASHED, &tmp->h.flags); auth_domain_drop(&tmp->h, &auth_domain_cache); goto out_set; } @@ -192,9 +192,9 @@ auth_domain_lookup(struct auth_domain *item, int set) goto out_nada; auth_domain_cache.entries++; out_set: - set_bit(CACHE_HASHED, &item->h.flags); item->h.next = *head; *head = &item->h; + cache_get(&item->h); write_unlock(&auth_domain_cache.hash_lock); cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time); cache_get(&item->h); -- cgit v1.2.3 From 818bcba580bbe96829fe776de526125205eb8c8b Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 4 Mar 2005 17:24:30 -0800 Subject: [PATCH] Randomisation: global sysctl This first patch of the series introduces a sysctl (default off) that enables/disables the randomisation feature globally. Since randomisation may make it harder to debug really tricky situations (reproducability goes down), the sysadmin needs a way to disable it globally. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 6 ++++++ include/linux/sysctl.h | 1 + kernel/sysctl.c | 11 +++++++++++ 3 files changed, 18 insertions(+) (limited to 'include') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 806491a0ab59..797d24c48a99 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -278,6 +278,12 @@ struct sysinfo { extern void BUILD_BUG(void); #define BUILD_BUG_ON(condition) do { if (condition) BUILD_BUG(); } while(0) +#ifdef CONFIG_SYSCTL +extern int randomize_va_space; +#else +#define randomize_va_space 0 +#endif + /* Trap pasters of __FUNCTION__ at compile-time */ #if __GNUC__ > 2 || __GNUC_MINOR__ >= 95 #define __FUNCTION__ (__func__) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 6b084680aaa1..230d7d4014d4 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -135,6 +135,7 @@ enum KERN_HZ_TIMER=65, /* int: hz timer on or off */ KERN_UNKNOWN_NMI_PANIC=66, /* int: unknown nmi panic flag */ KERN_BOOTLOADER_TYPE=67, /* int: boot loader type */ + KERN_RANDOMIZE=68, /* int: randomize virtual address space */ }; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index a72dd5677c8f..3f6b3fcf4309 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -121,6 +121,8 @@ extern int sysctl_hz_timer; extern int acct_parm[]; #endif +int randomize_va_space; + static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t, ctl_table *, void **); static int proc_doutsstring(ctl_table *table, int write, struct file *filp, @@ -632,6 +634,15 @@ static ctl_table kern_table[] = { .proc_handler = &proc_dointvec, }, #endif + { + .ctl_name = KERN_RANDOMIZE, + .procname = "randomize_va_space", + .data = &randomize_va_space, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = 0 } }; -- cgit v1.2.3 From 967423e87f9979166e815f9c281943325637b05e Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 4 Mar 2005 17:24:44 -0800 Subject: [PATCH] Randomisation: infrastructure The patch below introduces get_random_int() and randomize_range(), two helpers used in later patches in the series. get_random_int() shares the tcp/ip random number stuff so the CONFIG_INET ifdef needs to move slightly, and to reduce the damange due to that, secure_ip_id() needs to move inside random.c From: Frank Sorenson Acked-By: Jeff Dike The stack randomization patches that went into 2.6.11-rc3-mm1 broke compilation of ARCH=um. This patch fixes compiling by adding arch_align_stack back in. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Frank Sorenson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/process_kern.c | 9 +++++ drivers/char/random.c | 84 +++++++++++++++++++++++++++++++------------ include/linux/random.h | 3 ++ 3 files changed, 74 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 8d003f351eb3..1d719d5b4bb9 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -21,6 +21,7 @@ #include "linux/spinlock.h" #include "linux/proc_fs.h" #include "linux/ptrace.h" +#include "linux/random.h" #include "asm/unistd.h" #include "asm/mman.h" #include "asm/segment.h" @@ -479,6 +480,14 @@ int singlestepping(void * t) return 2; } +unsigned long arch_align_stack(unsigned long sp) +{ + if (randomize_va_space) + sp -= get_random_int() % 8192; + return sp & ~0xf; +} + + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/drivers/char/random.c b/drivers/char/random.c index 0fcbfa3a77df..4ba3f4185f3a 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1965,7 +1965,6 @@ static void sysctl_init_random(struct entropy_store *random_state) * ********************************************************************/ -#ifdef CONFIG_INET /* * TCP initial sequence number picking. This uses the random number * generator to pick an initial secret value. This value is hashed @@ -2202,6 +2201,31 @@ __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, EXPORT_SYMBOL(secure_tcpv6_sequence_number); #endif +/* The code below is shamelessly stolen from secure_tcp_sequence_number(). + * All blames to Andrey V. Savochkin . + */ +__u32 secure_ip_id(__u32 daddr) +{ + struct keydata *keyptr; + __u32 hash[4]; + + keyptr = get_keyptr(); + + /* + * Pick a unique starting offset for each IP destination. + * The dest ip address is placed in the starting vector, + * which is then hashed with random data. + */ + hash[0] = daddr; + hash[1] = keyptr->secret[9]; + hash[2] = keyptr->secret[10]; + hash[3] = keyptr->secret[11]; + + return halfMD4Transform(hash, keyptr->secret); +} + +#ifdef CONFIG_INET + __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport) { @@ -2242,28 +2266,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, EXPORT_SYMBOL(secure_tcp_sequence_number); -/* The code below is shamelessly stolen from secure_tcp_sequence_number(). - * All blames to Andrey V. Savochkin . - */ -__u32 secure_ip_id(__u32 daddr) -{ - struct keydata *keyptr; - __u32 hash[4]; - - keyptr = get_keyptr(); - - /* - * Pick a unique starting offset for each IP destination. - * The dest ip address is placed in the starting vector, - * which is then hashed with random data. - */ - hash[0] = daddr; - hash[1] = keyptr->secret[9]; - hash[2] = keyptr->secret[10]; - hash[3] = keyptr->secret[11]; - return halfMD4Transform(hash, keyptr->secret); -} /* Generate secure starting point for ephemeral TCP port search */ u32 secure_tcp_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport) @@ -2383,3 +2386,40 @@ __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, __u16 sport, } #endif #endif /* CONFIG_INET */ + + +/* + * Get a random word for internal kernel use only. Similar to urandom but + * with the goal of minimal entropy pool depletion. As a result, the random + * value is not cryptographically secure but for several uses the cost of + * depleting entropy is too high + */ +unsigned int get_random_int(void) +{ + /* + * Use IP's RNG. It suits our purpose perfectly: it re-keys itself + * every second, from the entropy pool (and thus creates a limited + * drain on it), and uses halfMD4Transform within the second. We + * also mix it with jiffies and the PID: + */ + return secure_ip_id(current->pid + jiffies); +} + +/* + * randomize_range() returns a start address such that + * + * [...... .....] + * start end + * + * a with size "len" starting at the return value is inside in the + * area defined by [start, end], but is otherwise randomized. + */ +unsigned long +randomize_range(unsigned long start, unsigned long end, unsigned long len) +{ + unsigned long range = end - len - start; + + if (end <= start + len) + return 0; + return PAGE_ALIGN(get_random_int() % range + start); +} diff --git a/include/linux/random.h b/include/linux/random.h index c6f95fc1de13..3ebd44b239f5 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -70,6 +70,9 @@ extern __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, extern struct file_operations random_fops, urandom_fops; #endif +unsigned int get_random_int(void); +unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len); + #endif /* __KERNEL___ */ #endif /* _LINUX_RANDOM_H */ -- cgit v1.2.3 From c518b108234a2418fb65a09e6219202eda316d6c Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 4 Mar 2005 17:24:57 -0800 Subject: [PATCH] Randomisation: add PF_RANDOMIZE Even though there is a global flag to disable randomisation, it's useful to have a per process flag too; the patch below introduces this per process flag and automatically sets it for "new" binaries. Eventually we will want to tie this to the legacy-va-space personality Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_elf.c | 2 ++ fs/exec.c | 1 + include/linux/sched.h | 1 + 3 files changed, 4 insertions(+) (limited to 'include') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 3be133aa4a79..1740bac44917 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -760,6 +760,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (elf_read_implies_exec(loc->elf_ex, executable_stack)) current->personality |= READ_IMPLIES_EXEC; + if (executable_stack == EXSTACK_DISABLE_X && randomize_va_space) + current->flags |= PF_RANDOMIZE; arch_pick_mmap_layout(current->mm); /* Do this so that we can load the interpreter, if need be. We will diff --git a/fs/exec.c b/fs/exec.c index ee58e91a9d7f..694e3c141012 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -877,6 +877,7 @@ int flush_old_exec(struct linux_binprm * bprm) tcomm[i] = '\0'; set_task_comm(current, tcomm); + current->flags &= ~PF_RANDOMIZE; flush_thread(); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || diff --git a/include/linux/sched.h b/include/linux/sched.h index 1f4ccd433ce9..2f249f8015e5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -735,6 +735,7 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) #define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */ #define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */ #define PF_BORROWED_MM 0x00400000 /* I am a kthread doing use_mm */ +#define PF_RANDOMIZE 0x00800000 /* randomize virtual address space */ /* * Only the _current_ task can read/write to tsk->flags, but other -- cgit v1.2.3 From ccc875c1d2fe18b50020d501f1005ef46fc55fed Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 4 Mar 2005 17:25:13 -0800 Subject: [PATCH] Randomisation: stack randomisation The patch below replaces the existing 8Kb randomisation of the userspace stack pointer (which is currently only done for Hyperthreaded P-IVs) with a more general randomisation over a 64Kb range. 64Kb is not a lot, but it's a start and once the dust settles we can increase this value to a more agressive value. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/process.c | 7 +++++++ arch/x86_64/kernel/process.c | 8 ++++++++ fs/binfmt_elf.c | 11 ++--------- fs/exec.c | 3 ++- include/asm-alpha/system.h | 2 ++ include/asm-arm/system.h | 2 ++ include/asm-arm26/system.h | 2 ++ include/asm-cris/system.h | 2 ++ include/asm-frv/system.h | 2 ++ include/asm-h8300/system.h | 2 ++ include/asm-i386/system.h | 2 ++ include/asm-ia64/system.h | 3 +++ include/asm-m32r/system.h | 2 ++ include/asm-m68k/system.h | 2 ++ include/asm-m68knommu/system.h | 1 + include/asm-mips/system.h | 2 ++ include/asm-parisc/system.h | 2 ++ include/asm-ppc/system.h | 2 ++ include/asm-ppc64/system.h | 2 ++ include/asm-s390/system.h | 2 ++ include/asm-sh/system.h | 2 ++ include/asm-sh64/system.h | 2 ++ include/asm-sparc/system.h | 2 ++ include/asm-sparc64/system.h | 2 ++ include/asm-v850/system.h | 2 ++ include/asm-x86_64/system.h | 2 ++ 26 files changed, 63 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 28b0d7bf0a84..5bdb839b2bb6 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -828,3 +829,9 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) return 0; } +unsigned long arch_align_stack(unsigned long sp) +{ + if (randomize_va_space) + sp -= get_random_int() % 8192; + return sp & ~0xf; +} diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 3a3522b9c885..0282960ddc91 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -749,3 +750,10 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) return 1; } + +unsigned long arch_align_stack(unsigned long sp) +{ + if (randomize_va_space) + sp -= get_random_int() % 8192; + return sp & ~0xf; +} diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 1740bac44917..91ad281f851d 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -165,21 +165,14 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, if (k_platform) { size_t len = strlen(k_platform) + 1; -#ifdef CONFIG_X86_HT /* * In some cases (e.g. Hyper-Threading), we want to avoid L1 * evictions by the processes running on the same package. One * thing we can do is to shuffle the initial stack for them. - * - * The conditionals here are unneeded, but kept in to make the - * code behaviour the same as pre change unless we have - * hyperthreaded processors. This should be cleaned up - * before 2.6 */ - if (smp_num_siblings > 1) - STACK_ALLOC(p, ((current->pid % 64) << 7)); -#endif + p = arch_align_stack(p); + u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); if (__copy_to_user(u_platform, k_platform, len)) return -EFAULT; diff --git a/fs/exec.c b/fs/exec.c index 694e3c141012..6e505b1b3db6 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -400,7 +400,8 @@ int setup_arg_pages(struct linux_binprm *bprm, while (i < MAX_ARG_PAGES) bprm->page[i++] = NULL; #else - stack_base = stack_top - MAX_ARG_PAGES * PAGE_SIZE; + stack_base = arch_align_stack(STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE); + stack_base = PAGE_ALIGN(stack_base); bprm->p += stack_base; mm->arg_start = bprm->p; arg_size = stack_top - (PAGE_MASK & (unsigned long) mm->arg_start); diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index bba276c50b15..c08ce970ff8c 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -621,4 +621,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) #endif /* __ASSEMBLY__ */ +#define arch_align_stack(x) (x) + #endif diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index 77d0dcf0b713..b5731290b4e5 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -383,6 +383,8 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size #endif /* __ASSEMBLY__ */ +#define arch_align_stack(x) (x) + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-arm26/system.h b/include/asm-arm26/system.h index 6361b6c71f8c..f23fac1938f3 100644 --- a/include/asm-arm26/system.h +++ b/include/asm-arm26/system.h @@ -245,6 +245,8 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size #endif /* __ASSEMBLY__ */ +#define arch_align_stack(x) (x) + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-cris/system.h b/include/asm-cris/system.h index f9cf80262574..e06739806d4e 100644 --- a/include/asm-cris/system.h +++ b/include/asm-cris/system.h @@ -69,4 +69,6 @@ extern inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz return x; } +#define arch_align_stack(x) (x) + #endif diff --git a/include/asm-frv/system.h b/include/asm-frv/system.h index 29cfa21ec2fe..d2aea70a5f64 100644 --- a/include/asm-frv/system.h +++ b/include/asm-frv/system.h @@ -123,4 +123,6 @@ do { \ extern void die_if_kernel(const char *, ...) __attribute__((format(printf, 1, 2))); extern void free_initmem(void); +#define arch_align_stack(x) (x) + #endif /* _ASM_SYSTEM_H */ diff --git a/include/asm-h8300/system.h b/include/asm-h8300/system.h index b91dae2a90c3..dfe96c7121cf 100644 --- a/include/asm-h8300/system.h +++ b/include/asm-h8300/system.h @@ -144,4 +144,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz asm("jmp @@0"); \ }) +#define arch_align_stack(x) (x) + #endif /* _H8300_SYSTEM_H */ diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index c705fa77b138..6f74d4c44a0e 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -468,4 +468,6 @@ void enable_hlt(void); extern int es7000_plat; void cpu_idle_wait(void); +extern unsigned long arch_align_stack(unsigned long sp); + #endif diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h index f28b920e9089..6f516e76d1f0 100644 --- a/include/asm-ia64/system.h +++ b/include/asm-ia64/system.h @@ -285,6 +285,9 @@ do { \ #define ia64_platform_is(x) (strcmp(x, platform_name) == 0) void cpu_idle_wait(void); + +#define arch_align_stack(x) (x) + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h index 5828af7d4122..73348c3f858b 100644 --- a/include/asm-m32r/system.h +++ b/include/asm-m32r/system.h @@ -294,4 +294,6 @@ static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, #define set_mb(var, value) do { xchg(&var, value); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) +#define arch_align_stack(x) (x) + #endif /* _ASM_M32R_SYSTEM_H */ diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h index f0f36fca11bb..64d3481df74c 100644 --- a/include/asm-m68k/system.h +++ b/include/asm-m68k/system.h @@ -194,6 +194,8 @@ static inline unsigned long __cmpxchg(volatile void *p, unsigned long old, (unsigned long)(n),sizeof(*(ptr)))) #endif +#define arch_align_stack(x) (x) + #endif /* __KERNEL__ */ #endif /* _M68K_SYSTEM_H */ diff --git a/include/asm-m68knommu/system.h b/include/asm-m68knommu/system.h index ce3f0b0226df..c341b66c147b 100644 --- a/include/asm-m68knommu/system.h +++ b/include/asm-m68knommu/system.h @@ -281,5 +281,6 @@ cmpxchg(volatile int *p, int old, int new) }) #endif #endif +#define arch_align_stack(x) (x) #endif /* _M68KNOMMU_SYSTEM_H */ diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index a421cdb1e0da..888fd8908467 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -433,4 +433,6 @@ do { \ #define finish_arch_switch(rq, prev) spin_unlock_irq(&(prev)->switch_lock) #define task_running(rq, p) ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock)) +#define arch_align_stack(x) (x) + #endif /* _ASM_SYSTEM_H */ diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h index 8aecb9e93fc0..d91428ed57d6 100644 --- a/include/asm-parisc/system.h +++ b/include/asm-parisc/system.h @@ -205,4 +205,6 @@ extern spinlock_t pa_tlb_lock; #endif +#define arch_align_stack(x) (x) + #endif diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 5cff9a0fd84b..25050b76db44 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -201,5 +201,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) (unsigned long)_n_, sizeof(*(ptr))); \ }) +#define arch_align_stack(x) (x) + #endif /* __KERNEL__ */ #endif /* __PPC_SYSTEM_H */ diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index 6785e69e8b9e..98d120ca8a91 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -300,5 +300,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) */ #define NET_IP_ALIGN 0 +#define arch_align_stack(x) (x) + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index 8565a8aee735..037b8d16e435 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -461,6 +461,8 @@ extern void (*_machine_restart)(char *command); extern void (*_machine_halt)(void); extern void (*_machine_power_off)(void); +#define arch_align_stack(x) (x) + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index 5e67caf8885e..28a3c2d8bcd7 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h @@ -259,4 +259,6 @@ static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int void disable_hlt(void); void enable_hlt(void); +#define arch_align_stack(x) (x) + #endif diff --git a/include/asm-sh64/system.h b/include/asm-sh64/system.h index 8b3a6f9e62fb..8aaabc92f9fb 100644 --- a/include/asm-sh64/system.h +++ b/include/asm-sh64/system.h @@ -191,4 +191,6 @@ extern void print_seg(char *file,int line); #define PL() printk("@ <%s,%s:%d>\n",__FILE__,__FUNCTION__,__LINE__) +#define arch_align_stack(x) (x) + #endif /* __ASM_SH64_SYSTEM_H */ diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h index a8e77ad1ea46..80cf20cfaee1 100644 --- a/include/asm-sparc/system.h +++ b/include/asm-sparc/system.h @@ -257,4 +257,6 @@ extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noret #endif /* __ASSEMBLY__ */ +#define arch_align_stack(x) (x) + #endif /* !(__SPARC_SYSTEM_H) */ diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index ef77358abf24..e8ba9d5277e1 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -341,4 +341,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) #endif /* !(__ASSEMBLY__) */ +#define arch_align_stack(x) (x) + #endif /* !(__SPARC64_SYSTEM_H) */ diff --git a/include/asm-v850/system.h b/include/asm-v850/system.h index 072a997dc5a9..20f4c738c04e 100644 --- a/include/asm-v850/system.h +++ b/include/asm-v850/system.h @@ -108,4 +108,6 @@ extern inline unsigned long __xchg (unsigned long with, return tmp; } +#define arch_align_stack(x) (x) + #endif /* __V850_SYSTEM_H__ */ diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h index c1710933828f..76165736e43a 100644 --- a/include/asm-x86_64/system.h +++ b/include/asm-x86_64/system.h @@ -338,4 +338,6 @@ void enable_hlt(void); #define HAVE_EAT_KEY void eat_key(void); +extern unsigned long arch_align_stack(unsigned long sp); + #endif -- cgit v1.2.3 From 3f06ae033fc51fd6163445f7bee505f0095404ec Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 4 Mar 2005 17:25:41 -0800 Subject: [PATCH] Randomisation: enable by default Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 2 +- kernel/sysctl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 797d24c48a99..de56b8b26cd5 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -281,7 +281,7 @@ extern void BUILD_BUG(void); #ifdef CONFIG_SYSCTL extern int randomize_va_space; #else -#define randomize_va_space 0 +#define randomize_va_space 1 #endif /* Trap pasters of __FUNCTION__ at compile-time */ diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 3f6b3fcf4309..cc93403f27a7 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -121,7 +121,7 @@ extern int sysctl_hz_timer; extern int acct_parm[]; #endif -int randomize_va_space; +int randomize_va_space = 1; static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t, ctl_table *, void **); -- cgit v1.2.3 From 8ec0defa78358ecae2b24146666e384af30950b5 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 4 Mar 2005 17:25:55 -0800 Subject: [PATCH] Randomisation: add ADDR_NO_RANDOMIZE personality Introduce a personality that disables randomisation, so that users can use setarch and related commands to run specific applications without randomisation. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_elf.c | 2 +- include/linux/personality.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 91ad281f851d..9fc7140228e8 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -753,7 +753,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (elf_read_implies_exec(loc->elf_ex, executable_stack)) current->personality |= READ_IMPLIES_EXEC; - if (executable_stack == EXSTACK_DISABLE_X && randomize_va_space) + if ( !(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) current->flags |= PF_RANDOMIZE; arch_pick_mmap_layout(current->mm); diff --git a/include/linux/personality.h b/include/linux/personality.h index 7cef4670ac05..80d780e5a8f5 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -18,6 +18,7 @@ extern int __set_personality(unsigned long); * These occupy the top three bytes. */ enum { + ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors * (signal handling) */ @@ -35,7 +36,7 @@ enum { * Security-relevant compatibility flags that must be * cleared upon setuid or setgid exec: */ -#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC) +#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC|ADDR_NO_RANDOMIZE) /* * Personality types. -- cgit v1.2.3 From 545a604c163b11bc625e7d031dbe1c02a520d6d6 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 4 Mar 2005 17:26:24 -0800 Subject: [PATCH] Move accounting function calls out of critical vm code paths In the 2.6.11 development cycle function calls have been added to lots of hot vm paths to do accounting. I think these should not go into the final 2.6.1 release because these statistics can be collected in a different way that does not require the updating of counters from frequently used vm code paths and is consistent with the methods use elsewhere in the kernel to obtain statistics. These function calls are acct_update_integrals -> Account for processes based on stime changes update_mem_hiwater -> takes rss and total_vm hiwater marks. acct_update_integrals is only useful to call if stime changes otherwise it will simply return. It is therefore best to relocate the function call to acct_update_integral into the function that updates stime which is account_system_time and remove it from the vm code paths. update_mem_hiwater finds the rss hiwater mark. We call that from timer context as well. This means that processes' high-water marks are now sampled statistically, at timer-interrupt time rather than deterministically. This may or may not be a problem.. This means that the rss limit is not always updated if rss is increased and thus not as accurate. But the benefit is that the rss checks do no pollute the vm paths and that it is consistent with the rss limit check. The following patch removes acct_update_integrals and update_mem_hiwater from the hot vm paths. Signed-off-by: Christoph Lameter From: Jay Lan The new "move-accounting-function-calls-out-of-critical-vm-code-paths" patch in 2.6.11-rc3-mm2 was different from the code i tested. In particular, it mistakenly dropped the accounting routine calls in fs/exec.c. The calls in do_execve() are needed to properly initialize accounting fields. Specifically, the tsk->acct_stimexpd needs to be initialized to tsk->stime. I have discussed this with Christoph Lameter and he gave me full blessings to bring the calls back. Signed-off-by: Jay Lan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exec.c | 4 ++-- include/linux/acct.h | 4 ++-- include/linux/mm.h | 2 +- kernel/acct.c | 4 +--- kernel/exit.c | 4 ++-- kernel/sched.c | 5 +++++ mm/memory.c | 19 +++---------------- mm/mmap.c | 7 ------- mm/mremap.c | 6 ------ mm/nommu.c | 4 +--- mm/rmap.c | 3 --- mm/swapfile.c | 3 --- 12 files changed, 17 insertions(+), 48 deletions(-) (limited to 'include') diff --git a/fs/exec.c b/fs/exec.c index 84427b0e2236..393605cdc101 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1193,8 +1193,8 @@ int do_execve(char * filename, /* execve success */ security_bprm_free(bprm); - acct_update_integrals(); - update_mem_hiwater(); + acct_update_integrals(current); + update_mem_hiwater(current); kfree(bprm); return retval; } diff --git a/include/linux/acct.h b/include/linux/acct.h index 39cd52f7f557..1993a3691768 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -120,12 +120,12 @@ struct acct_v3 struct super_block; extern void acct_auto_close(struct super_block *sb); extern void acct_process(long exitcode); -extern void acct_update_integrals(void); +extern void acct_update_integrals(struct task_struct *tsk); extern void acct_clear_integrals(struct task_struct *tsk); #else #define acct_auto_close(x) do { } while (0) #define acct_process(x) do { } while (0) -#define acct_update_integrals() do { } while (0) +#define acct_update_integrals(x) do { } while (0) #define acct_clear_integrals(task) do { } while (0) #endif diff --git a/include/linux/mm.h b/include/linux/mm.h index 3a8c47c5dc9c..418b928a6617 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -838,7 +838,7 @@ static inline void vm_stat_unaccount(struct vm_area_struct *vma) } /* update per process rss and vm hiwater data */ -extern void update_mem_hiwater(void); +extern void update_mem_hiwater(struct task_struct *tsk); #ifndef CONFIG_DEBUG_PAGEALLOC static inline void diff --git a/kernel/acct.c b/kernel/acct.c index 32e39accbb86..78ed87b13de6 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -534,10 +534,8 @@ void acct_process(long exitcode) * acct_update_integrals * - update mm integral fields in task_struct */ -void acct_update_integrals(void) +void acct_update_integrals(struct task_struct *tsk) { - struct task_struct *tsk = current; - if (likely(tsk->mm)) { long delta = tsk->stime - tsk->acct_stimexpd; diff --git a/kernel/exit.c b/kernel/exit.c index f40a50f69850..4173fa7536dc 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -806,8 +806,8 @@ fastcall NORET_TYPE void do_exit(long code) current->comm, current->pid, preempt_count()); - acct_update_integrals(); - update_mem_hiwater(); + acct_update_integrals(tsk); + update_mem_hiwater(tsk); group_dead = atomic_dec_and_test(&tsk->signal->live); if (group_dead) acct_process(code); diff --git a/kernel/sched.c b/kernel/sched.c index 95042b27d30c..f32101f5e31a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -2379,6 +2380,10 @@ void account_system_time(struct task_struct *p, int hardirq_offset, cpustat->iowait = cputime64_add(cpustat->iowait, tmp); else cpustat->idle = cputime64_add(cpustat->idle, tmp); + /* Account for system time used */ + acct_update_integrals(p); + /* Update rss highwater mark */ + update_mem_hiwater(p); } /* diff --git a/mm/memory.c b/mm/memory.c index 48cbd6b7b98b..e9b47f5ddb05 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include @@ -735,7 +734,6 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, tlb = tlb_gather_mmu(mm, 0); unmap_vmas(&tlb, mm, vma, address, end, &nr_accounted, details); tlb_finish_mmu(tlb, address, end); - acct_update_integrals(); spin_unlock(&mm->page_table_lock); } @@ -1338,11 +1336,9 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, if (likely(pte_same(*page_table, pte))) { if (PageAnon(old_page)) mm->anon_rss--; - if (PageReserved(old_page)) { + if (PageReserved(old_page)) ++mm->rss; - acct_update_integrals(); - update_mem_hiwater(); - } else + else page_remove_rmap(old_page); break_cow(vma, new_page, address, page_table); lru_cache_add_active(new_page); @@ -1747,9 +1743,6 @@ static int do_swap_page(struct mm_struct * mm, remove_exclusive_swap_page(page); mm->rss++; - acct_update_integrals(); - update_mem_hiwater(); - pte = mk_pte(page, vma->vm_page_prot); if (write_access && can_share_swap_page(page)) { pte = maybe_mkwrite(pte_mkdirty(pte), vma); @@ -1814,8 +1807,6 @@ do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, goto out; } mm->rss++; - acct_update_integrals(); - update_mem_hiwater(); entry = maybe_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)), vma); @@ -1932,8 +1923,6 @@ retry: if (pte_none(*page_table)) { if (!PageReserved(new_page)) ++mm->rss; - acct_update_integrals(); - update_mem_hiwater(); flush_icache_page(vma, new_page); entry = mk_pte(new_page, vma->vm_page_prot); @@ -2253,10 +2242,8 @@ EXPORT_SYMBOL(vmalloc_to_pfn); * update_mem_hiwater * - update per process rss and vm high water data */ -void update_mem_hiwater(void) +void update_mem_hiwater(struct task_struct *tsk) { - struct task_struct *tsk = current; - if (tsk->mm) { if (tsk->mm->hiwater_rss < tsk->mm->rss) tsk->mm->hiwater_rss = tsk->mm->rss; diff --git a/mm/mmap.c b/mm/mmap.c index b8af0c8db48d..a8990719c87a 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -1121,8 +1120,6 @@ out: pgoff, flags & MAP_NONBLOCK); down_write(&mm->mmap_sem); } - acct_update_integrals(); - update_mem_hiwater(); return addr; unmap_and_free_vma: @@ -1463,8 +1460,6 @@ static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, un if (vma->vm_flags & VM_LOCKED) mm->locked_vm += grow; __vm_stat_account(mm, vma->vm_flags, vma->vm_file, grow); - acct_update_integrals(); - update_mem_hiwater(); return 0; } @@ -1968,8 +1963,6 @@ out: mm->locked_vm += len >> PAGE_SHIFT; make_pages_present(addr, addr + len); } - acct_update_integrals(); - update_mem_hiwater(); return addr; } diff --git a/mm/mremap.c b/mm/mremap.c index ebdf621984ac..3c6d60454296 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -255,9 +254,6 @@ static unsigned long move_vma(struct vm_area_struct *vma, new_addr + new_len); } - acct_update_integrals(); - update_mem_hiwater(); - return new_addr; } @@ -394,8 +390,6 @@ unsigned long do_mremap(unsigned long addr, make_pages_present(addr + old_len, addr + new_len); } - acct_update_integrals(); - update_mem_hiwater(); ret = addr; goto out; } diff --git a/mm/nommu.c b/mm/nommu.c index 8e70b95a8d9f..f72d40c31a96 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -959,10 +959,8 @@ void arch_unmap_area(struct vm_area_struct *area) { } -void update_mem_hiwater(void) +void update_mem_hiwater(struct task_struct *tsk) { - struct task_struct *tsk = current; - if (likely(tsk->mm)) { if (tsk->mm->hiwater_rss < tsk->mm->rss) tsk->mm->hiwater_rss = tsk->mm->rss; diff --git a/mm/rmap.c b/mm/rmap.c index 4ff8183fa18e..9ff4bfc6adb6 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -51,7 +51,6 @@ #include #include #include -#include #include #include @@ -600,7 +599,6 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) } mm->rss--; - acct_update_integrals(); page_remove_rmap(page); page_cache_release(page); @@ -705,7 +703,6 @@ static void try_to_unmap_cluster(unsigned long cursor, page_remove_rmap(page); page_cache_release(page); - acct_update_integrals(); mm->rss--; (*mapcount)--; } diff --git a/mm/swapfile.c b/mm/swapfile.c index 547ecd9c060d..8f2a388911b1 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -437,8 +436,6 @@ unuse_pte(struct vm_area_struct *vma, unsigned long address, pte_t *dir, set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot))); page_add_anon_rmap(page, vma, address); swap_free(entry); - acct_update_integrals(); - update_mem_hiwater(); } /* vma->vm_mm->page_table_lock is held */ -- cgit v1.2.3 From 7afadfdc750969c3fd7128c4f03678232118d155 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 4 Mar 2005 17:26:38 -0800 Subject: [PATCH] invalidate range of pages after direct IO write Presently we invalidate all of a file's pages when writing to any part of that file with direct-IO. After a direct IO write only invalidate the pages that the write intersected. invalidate_inode_pages2_range(mapping, pgoff start, pgoff end) is added and called from generic_file_direct_IO(). While we're in there, invalidate_inode_pages2() was calling unmap_mapping_range() with the wrong convention in the single page case. It was providing the byte offset of the final page rather than the length of the hole being unmapped. This is also fixed. This was lightly tested with a 10k op fsx run with O_DIRECT on a 16MB file in ext3 on a junky old IDE drive. Totaling vmstat columns of blocks read and written during the runs shows that read traffic drops significantly. The run time seems to have gone down a little. Two runs before the patch gave the following user/real/sys times and total blocks in and out: 0m28.029s 0m20.093s 0m3.166s 16673 125107 0m27.949s 0m20.068s 0m3.227s 18426 126094 and after the patch: 0m26.775s 0m19.996s 0m3.060s 3505 124982 0m26.856s 0m19.935s 0m3.052s 3505 125279 akpm: - Don't look up more pages than we're going to use - Don't test page->index until we've locked the page - Check for the cursor wrapping at the end of the mapping. Signed-off-by: Zach Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 2 ++ mm/filemap.c | 5 ++++- mm/truncate.c | 51 +++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 43 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/linux/fs.h b/include/linux/fs.h index 30cb440cb6c8..dec81274016f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1353,6 +1353,8 @@ static inline void invalidate_remote_inode(struct inode *inode) invalidate_inode_pages(inode->i_mapping); } extern int invalidate_inode_pages2(struct address_space *mapping); +extern int invalidate_inode_pages2_range(struct address_space *mapping, + pgoff_t start, pgoff_t end); extern int write_inode_now(struct inode *, int); extern int filemap_fdatawrite(struct address_space *); extern int filemap_flush(struct address_space *); diff --git a/mm/filemap.c b/mm/filemap.c index 4f2fb2c40f78..11e372ec0934 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2283,7 +2283,10 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, retval = mapping->a_ops->direct_IO(rw, iocb, iov, offset, nr_segs); if (rw == WRITE && mapping->nrpages) { - int err = invalidate_inode_pages2(mapping); + pgoff_t end = (offset + iov_length(iov, nr_segs) - 1) + >> PAGE_CACHE_SHIFT; + int err = invalidate_inode_pages2_range(mapping, + offset >> PAGE_CACHE_SHIFT, end); if (err) retval = err; } diff --git a/mm/truncate.c b/mm/truncate.c index 9645008bd2f6..f1fa4bb2c1ea 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -241,54 +241,62 @@ unsigned long invalidate_inode_pages(struct address_space *mapping) EXPORT_SYMBOL(invalidate_inode_pages); /** - * invalidate_inode_pages2 - remove all pages from an address_space + * invalidate_inode_pages2_range - remove range of pages from an address_space * @mapping - the address_space + * @start: the page offset 'from' which to invalidate + * @end: the page offset 'to' which to invalidate (inclusive) * * Any pages which are found to be mapped into pagetables are unmapped prior to * invalidation. * * Returns -EIO if any pages could not be invalidated. */ -int invalidate_inode_pages2(struct address_space *mapping) +int invalidate_inode_pages2_range(struct address_space *mapping, + pgoff_t start, pgoff_t end) { struct pagevec pvec; - pgoff_t next = 0; + pgoff_t next; int i; int ret = 0; - int did_full_unmap = 0; + int did_range_unmap = 0; + int wrapped = 0; pagevec_init(&pvec, 0); - while (!ret && pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + next = start; + while (next <= end && !ret && !wrapped && + pagevec_lookup(&pvec, mapping, next, + min(end - next, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) { for (i = 0; !ret && i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; int was_dirty; lock_page(page); - if (page->mapping != mapping) { /* truncate race? */ + if (page->mapping != mapping || page->index > end) { unlock_page(page); continue; } wait_on_page_writeback(page); next = page->index + 1; + if (next == 0) + wrapped = 1; while (page_mapped(page)) { - if (!did_full_unmap) { + if (!did_range_unmap) { /* * Zap the rest of the file in one hit. - * FIXME: invalidate_inode_pages2() - * should take start/end offsets. */ unmap_mapping_range(mapping, - page->index << PAGE_CACHE_SHIFT, - -1, 0); - did_full_unmap = 1; + page->index << PAGE_CACHE_SHIFT, + (end - page->index + 1) + << PAGE_CACHE_SHIFT, + 0); + did_range_unmap = 1; } else { /* * Just zap this page */ unmap_mapping_range(mapping, page->index << PAGE_CACHE_SHIFT, - (page->index << PAGE_CACHE_SHIFT)+1, - 0); + PAGE_CACHE_SIZE, 0); } } was_dirty = test_clear_page_dirty(page); @@ -304,4 +312,19 @@ int invalidate_inode_pages2(struct address_space *mapping) } return ret; } +EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range); + +/** + * invalidate_inode_pages2 - remove all pages from an address_space + * @mapping - the address_space + * + * Any pages which are found to be mapped into pagetables are unmapped prior to + * invalidation. + * + * Returns -EIO if any pages could not be invalidated. + */ +int invalidate_inode_pages2(struct address_space *mapping) +{ + return invalidate_inode_pages2_range(mapping, 0, -1); +} EXPORT_SYMBOL_GPL(invalidate_inode_pages2); -- cgit v1.2.3 From daf70db8d1b99e28523baee92c6848ed794ea326 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 4 Mar 2005 17:26:52 -0800 Subject: [PATCH] write and wait on range before direct io read This adds filemap_write_and_wait_range(mapping, lstart, lend) which starts writeback and waits on a range of pages. We call this from __blkdev_direct_IO with just the range that is going to be read by the direct_IO read. It was lightly tested with fsx and ext3 and passed. Signed-off-by: Zach Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/direct-io.c | 7 +++++-- include/linux/fs.h | 2 ++ mm/filemap.c | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/direct-io.c b/fs/direct-io.c index 283268396a15..5a674a0c7146 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1206,7 +1206,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, */ dio->lock_type = dio_lock_type; if (dio_lock_type != DIO_NO_LOCKING) { - if (rw == READ) { + /* watch out for a 0 len io from a tricksy fs */ + if (rw == READ && end > offset) { struct address_space *mapping; mapping = iocb->ki_filp->f_mapping; @@ -1214,7 +1215,9 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, down(&inode->i_sem); reader_with_isem = 1; } - retval = filemap_write_and_wait(mapping); + + retval = filemap_write_and_wait_range(mapping, offset, + end - 1); if (retval) { kfree(dio); goto out; diff --git a/include/linux/fs.h b/include/linux/fs.h index dec81274016f..f07cb9f7977a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1360,6 +1360,8 @@ extern int filemap_fdatawrite(struct address_space *); extern int filemap_flush(struct address_space *); extern int filemap_fdatawait(struct address_space *); extern int filemap_write_and_wait(struct address_space *mapping); +extern int filemap_write_and_wait_range(struct address_space *mapping, + loff_t lstart, loff_t lend); extern void sync_supers(void); extern void sync_filesystems(int wait); extern void emergency_sync(void); diff --git a/mm/filemap.c b/mm/filemap.c index 11e372ec0934..9c5b2bf61a5d 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -336,6 +336,22 @@ int filemap_write_and_wait(struct address_space *mapping) return retval; } +int filemap_write_and_wait_range(struct address_space *mapping, + loff_t lstart, loff_t lend) +{ + int retval = 0; + + if (mapping->nrpages) { + retval = __filemap_fdatawrite_range(mapping, lstart, lend, + WB_SYNC_ALL); + if (retval == 0) + retval = wait_on_page_writeback_range(mapping, + lstart >> PAGE_CACHE_SHIFT, + lend >> PAGE_CACHE_SHIFT); + } + return retval; +} + /* * This function is used to add newly allocated pagecache pages: * the page is new, so we can just run SetPageLocked() against it. -- cgit v1.2.3 From 1eeae0158ecd0535a2bc257a53d3472cc37ceb15 Mon Sep 17 00:00:00 2001 From: "bill.irwin@oracle.com" Date: Fri, 4 Mar 2005 17:27:21 -0800 Subject: [PATCH] make mapping->tree_lock an rwlock Convert mapping->tree_lock to an rwlock. with: dd if=/dev/zero of=foo bs=1 count=2M 0.80s user 4.15s system 99% cpu 4.961 total dd if=/dev/zero of=foo bs=1 count=2M 0.73s user 4.26s system 100% cpu 4.987 total dd if=/dev/zero of=foo bs=1 count=2M 0.79s user 4.25s system 100% cpu 5.034 total dd if=foo of=/dev/null bs=1 0.80s user 3.12s system 99% cpu 3.928 total dd if=foo of=/dev/null bs=1 0.77s user 3.15s system 100% cpu 3.914 total dd if=foo of=/dev/null bs=1 0.92s user 3.02s system 100% cpu 3.935 total (3.926: 1.87 usecs) without: dd if=/dev/zero of=foo bs=1 count=2M 0.85s user 3.92s system 99% cpu 4.780 total dd if=/dev/zero of=foo bs=1 count=2M 0.78s user 4.02s system 100% cpu 4.789 total dd if=/dev/zero of=foo bs=1 count=2M 0.82s user 3.94s system 99% cpu 4.763 total dd if=/dev/zero of=foo bs=1 count=2M 0.71s user 4.10s system 99% cpu 4.810 tota dd if=foo of=/dev/null bs=1 0.76s user 2.68s system 100% cpu 3.438 total dd if=foo of=/dev/null bs=1 0.74s user 2.72s system 99% cpu 3.465 total dd if=foo of=/dev/null bs=1 0.67s user 2.82s system 100% cpu 3.489 total dd if=foo of=/dev/null bs=1 0.70s user 2.62s system 99% cpu 3.326 total (3.430: 1.635 usecs) So on a P4, the additional cost of the rwlock is ~240 nsecs for a one-byte-write(). On the other hand: From: Peter Chubb As part of the Gelato scalability focus group, we've been running OSDL's Re-AIM7 benchmark with an I/O intensive load with varying numbers of processors. The current kernel shows severe contention on the tree_lock in the address space structure when running on tmpfs or ext2 on a RAM disk. Lockstat output for a 12-way: SPINLOCKS HOLD WAIT UTIL CON MEAN( MAX ) MEAN( MAX )(% CPU) TOTAL NOWAIT SPIN RJECT NAME 5.5% 0.4us(3177us) 28us( 20ms)(44.2%) 131821954 94.5% 5.5% 0.00% *TOTAL* 72.3% 13.1% 0.5us( 9.5us) 29us( 20ms)(42.5%) 50542055 86.9% 13.1% 0% find_lock_page+0x30 23.8% 0% 385us(3177us) 0us 23235 100% 0% 0% exit_mmap+0x50 11.5% 0.82% 0.1us( 101us) 17us(5670us)( 1.6%) 50665658 99.2% 0.82% 0% dnotify_parent+0x70 Replacing the spinlock with a multi-reader lock fixes this problem, without unduly affecting anything else. Here are the benchmark results (jobs per minute at a 50-client level, average of 5 runs, standard deviation in parens) on an HP Olympia with 3 cells, 12 processors, and dnotify turned off (after this spinlock, the spinlock in dnotify_parent is the worst contended for this workload). tmpfs............... ext2............... #CPUs spinlock rwlock spinlock rwlock 1 7556(15) 7588(17) +0.42% 3744(20) 3791(16) +1.25% 2 13743(31) 13791(33) +0.35% 6405(30) 6413(24) +0.12% 4 23334(111) 22881(154) -2% 9648(51) 9595(50) -0.55% 8 33580(240) 36163(190) +7.7% 13183(63) 13070(68) -0.85% 12 28748(170) 44064(238)+53% 12681(49) 14504(105)+14% And on a pentium3 single processsor: 1 4177(4) 4169(2) -0.2% 3811(4) 3820(3) +0.23% I'm not sure what's happening in the 4-processor case. The important thing to note is that with a spinlock, the benchmark shows worse performance for a 12 than for an 8-way box; with the patch, the 12 way performs better, as expected. We've done some runs with 16-way as well; without the patch below, the 16-way performs worse than the 12-way. It's a tricky tradeoff, but large-smp is hurt a lot more by the spinlocks than small-smp is by the rwlocks. And I don't think we really want to implement compile-time either-or-locks. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mtd/devices/block2mtd.c | 8 ++++---- fs/buffer.c | 4 ++-- fs/inode.c | 2 +- include/asm-arm/cacheflush.h | 4 ++-- include/asm-parisc/cacheflush.h | 4 ++-- include/linux/fs.h | 2 +- mm/filemap.c | 32 ++++++++++++++++---------------- mm/page-writeback.c | 28 ++++++++++++++-------------- mm/readahead.c | 8 ++++---- mm/swap_state.c | 18 +++++++++--------- mm/swapfile.c | 12 ++++++------ mm/truncate.c | 6 +++--- mm/vmscan.c | 8 ++++---- 13 files changed, 68 insertions(+), 68 deletions(-) (limited to 'include') diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 1cbdfce588cb..cfe6ccf07972 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -59,7 +59,7 @@ void cache_readahead(struct address_space *mapping, int index) end_index = ((isize - 1) >> PAGE_CACHE_SHIFT); - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); for (i = 0; i < PAGE_READAHEAD; i++) { pagei = index + i; if (pagei > end_index) { @@ -71,16 +71,16 @@ void cache_readahead(struct address_space *mapping, int index) break; if (page) continue; - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); page = page_cache_alloc_cold(mapping); - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); if (!page) break; page->index = pagei; list_add(&page->lru, &page_pool); ret++; } - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); if (ret) read_cache_pages(mapping, &page_pool, filler, NULL); } diff --git a/fs/buffer.c b/fs/buffer.c index 3c40d6382925..ed6458f00d64 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -875,7 +875,7 @@ int __set_page_dirty_buffers(struct page *page) spin_unlock(&mapping->private_lock); if (!TestSetPageDirty(page)) { - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); if (page->mapping) { /* Race with truncate? */ if (!mapping->backing_dev_info->memory_backed) inc_page_state(nr_dirty); @@ -883,7 +883,7 @@ int __set_page_dirty_buffers(struct page *page) page_index(page), PAGECACHE_TAG_DIRTY); } - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); } diff --git a/fs/inode.c b/fs/inode.c index d76a6e4b3ee1..ff654a268331 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -196,7 +196,7 @@ void inode_init_once(struct inode *inode) sema_init(&inode->i_sem, 1); init_rwsem(&inode->i_alloc_sem); INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC); - spin_lock_init(&inode->i_data.tree_lock); + rwlock_init(&inode->i_data.tree_lock); spin_lock_init(&inode->i_data.i_mmap_lock); INIT_LIST_HEAD(&inode->i_data.private_list); spin_lock_init(&inode->i_data.private_lock); diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index d38a1cadf0b7..2abb52592613 100644 --- a/include/asm-arm/cacheflush.h +++ b/include/asm-arm/cacheflush.h @@ -312,9 +312,9 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr) extern void flush_dcache_page(struct page *); #define flush_dcache_mmap_lock(mapping) \ - spin_lock_irq(&(mapping)->tree_lock) + write_lock_irq(&(mapping)->tree_lock) #define flush_dcache_mmap_unlock(mapping) \ - spin_unlock_irq(&(mapping)->tree_lock) + write_unlock_irq(&(mapping)->tree_lock) #define flush_icache_user_range(vma,page,addr,len) \ flush_dcache_page(page) diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h index a3132a28a8f2..0cd86448fc4c 100644 --- a/include/asm-parisc/cacheflush.h +++ b/include/asm-parisc/cacheflush.h @@ -57,9 +57,9 @@ flush_user_icache_range(unsigned long start, unsigned long end) extern void flush_dcache_page(struct page *page); #define flush_dcache_mmap_lock(mapping) \ - spin_lock_irq(&(mapping)->tree_lock) + write_lock_irq(&(mapping)->tree_lock) #define flush_dcache_mmap_unlock(mapping) \ - spin_unlock_irq(&(mapping)->tree_lock) + write_unlock_irq(&(mapping)->tree_lock) #define flush_icache_page(vma,page) do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0) diff --git a/include/linux/fs.h b/include/linux/fs.h index f07cb9f7977a..c4081935da26 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -335,7 +335,7 @@ struct backing_dev_info; struct address_space { struct inode *host; /* owner: inode, block_device */ struct radix_tree_root page_tree; /* radix tree of all pages */ - spinlock_t tree_lock; /* and spinlock protecting it */ + rwlock_t tree_lock; /* and rwlock protecting it */ unsigned int i_mmap_writable;/* count VM_SHARED mappings */ struct prio_tree_root i_mmap; /* tree of private and shared mappings */ struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */ diff --git a/mm/filemap.c b/mm/filemap.c index 30a898b25099..1ed3ee004f24 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -126,9 +126,9 @@ void remove_from_page_cache(struct page *page) if (unlikely(!PageLocked(page))) PAGE_BUG(page); - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); __remove_from_page_cache(page); - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); } static int sync_page(void *word) @@ -365,7 +365,7 @@ int add_to_page_cache(struct page *page, struct address_space *mapping, int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); if (error == 0) { - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); error = radix_tree_insert(&mapping->page_tree, offset, page); if (!error) { page_cache_get(page); @@ -375,7 +375,7 @@ int add_to_page_cache(struct page *page, struct address_space *mapping, mapping->nrpages++; pagecache_acct(1); } - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); radix_tree_preload_end(); } return error; @@ -488,11 +488,11 @@ struct page * find_get_page(struct address_space *mapping, unsigned long offset) { struct page *page; - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); page = radix_tree_lookup(&mapping->page_tree, offset); if (page) page_cache_get(page); - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return page; } @@ -505,11 +505,11 @@ struct page *find_trylock_page(struct address_space *mapping, unsigned long offs { struct page *page; - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); page = radix_tree_lookup(&mapping->page_tree, offset); if (page && TestSetPageLocked(page)) page = NULL; - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return page; } @@ -531,15 +531,15 @@ struct page *find_lock_page(struct address_space *mapping, { struct page *page; - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); repeat: page = radix_tree_lookup(&mapping->page_tree, offset); if (page) { page_cache_get(page); if (TestSetPageLocked(page)) { - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); lock_page(page); - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); /* Has the page been truncated while we slept? */ if (page->mapping != mapping || page->index != offset) { @@ -549,7 +549,7 @@ repeat: } } } - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return page; } @@ -623,12 +623,12 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start, unsigned int i; unsigned int ret; - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); ret = radix_tree_gang_lookup(&mapping->page_tree, (void **)pages, start, nr_pages); for (i = 0; i < ret; i++) page_cache_get(pages[i]); - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return ret; } @@ -642,14 +642,14 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, unsigned int i; unsigned int ret; - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); ret = radix_tree_gang_lookup_tag(&mapping->page_tree, (void **)pages, *index, nr_pages, tag); for (i = 0; i < ret; i++) page_cache_get(pages[i]); if (ret) *index = pages[ret - 1]->index + 1; - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return ret; } diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 624ce500fb16..f80248a53a08 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -601,7 +601,7 @@ int __set_page_dirty_nobuffers(struct page *page) struct address_space *mapping2; if (mapping) { - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); mapping2 = page_mapping(page); if (mapping2) { /* Race with truncate? */ BUG_ON(mapping2 != mapping); @@ -610,7 +610,7 @@ int __set_page_dirty_nobuffers(struct page *page) radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); if (mapping->host) { /* !PageAnon && !swapper_space */ __mark_inode_dirty(mapping->host, @@ -685,17 +685,17 @@ int test_clear_page_dirty(struct page *page) unsigned long flags; if (mapping) { - spin_lock_irqsave(&mapping->tree_lock, flags); + write_lock_irqsave(&mapping->tree_lock, flags); if (TestClearPageDirty(page)) { radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + write_unlock_irqrestore(&mapping->tree_lock, flags); if (!mapping->backing_dev_info->memory_backed) dec_page_state(nr_dirty); return 1; } - spin_unlock_irqrestore(&mapping->tree_lock, flags); + write_unlock_irqrestore(&mapping->tree_lock, flags); return 0; } return TestClearPageDirty(page); @@ -742,15 +742,15 @@ int __clear_page_dirty(struct page *page) if (mapping) { unsigned long flags; - spin_lock_irqsave(&mapping->tree_lock, flags); + write_lock_irqsave(&mapping->tree_lock, flags); if (TestClearPageDirty(page)) { radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + write_unlock_irqrestore(&mapping->tree_lock, flags); return 1; } - spin_unlock_irqrestore(&mapping->tree_lock, flags); + write_unlock_irqrestore(&mapping->tree_lock, flags); return 0; } return TestClearPageDirty(page); @@ -764,13 +764,13 @@ int test_clear_page_writeback(struct page *page) if (mapping) { unsigned long flags; - spin_lock_irqsave(&mapping->tree_lock, flags); + write_lock_irqsave(&mapping->tree_lock, flags); ret = TestClearPageWriteback(page); if (ret) radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_WRITEBACK); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + write_unlock_irqrestore(&mapping->tree_lock, flags); } else { ret = TestClearPageWriteback(page); } @@ -785,7 +785,7 @@ int test_set_page_writeback(struct page *page) if (mapping) { unsigned long flags; - spin_lock_irqsave(&mapping->tree_lock, flags); + write_lock_irqsave(&mapping->tree_lock, flags); ret = TestSetPageWriteback(page); if (!ret) radix_tree_tag_set(&mapping->page_tree, @@ -795,7 +795,7 @@ int test_set_page_writeback(struct page *page) radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + write_unlock_irqrestore(&mapping->tree_lock, flags); } else { ret = TestSetPageWriteback(page); } @@ -813,9 +813,9 @@ int mapping_tagged(struct address_space *mapping, int tag) unsigned long flags; int ret; - spin_lock_irqsave(&mapping->tree_lock, flags); + read_lock_irqsave(&mapping->tree_lock, flags); ret = radix_tree_tagged(&mapping->page_tree, tag); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + read_unlock_irqrestore(&mapping->tree_lock, flags); return ret; } EXPORT_SYMBOL(mapping_tagged); diff --git a/mm/readahead.c b/mm/readahead.c index b7c3b746de67..24448a1d7e37 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -274,7 +274,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp, /* * Preallocate as many pages as we will need. */ - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); for (page_idx = 0; page_idx < nr_to_read; page_idx++) { unsigned long page_offset = offset + page_idx; @@ -285,16 +285,16 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp, if (page) continue; - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); page = page_cache_alloc_cold(mapping); - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); if (!page) break; page->index = page_offset; list_add(&page->lru, &page_pool); ret++; } - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); /* * Now start the IO. We ignore I/O errors - if the page is not diff --git a/mm/swap_state.c b/mm/swap_state.c index 7a8f03f21169..0f8ddb4d1c7b 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -35,7 +35,7 @@ static struct backing_dev_info swap_backing_dev_info = { struct address_space swapper_space = { .page_tree = RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN), - .tree_lock = SPIN_LOCK_UNLOCKED, + .tree_lock = RW_LOCK_UNLOCKED, .a_ops = &swap_aops, .i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear), .backing_dev_info = &swap_backing_dev_info, @@ -76,7 +76,7 @@ static int __add_to_swap_cache(struct page *page, BUG_ON(PagePrivate(page)); error = radix_tree_preload(gfp_mask); if (!error) { - spin_lock_irq(&swapper_space.tree_lock); + write_lock_irq(&swapper_space.tree_lock); error = radix_tree_insert(&swapper_space.page_tree, entry.val, page); if (!error) { @@ -87,7 +87,7 @@ static int __add_to_swap_cache(struct page *page, total_swapcache_pages++; pagecache_acct(1); } - spin_unlock_irq(&swapper_space.tree_lock); + write_unlock_irq(&swapper_space.tree_lock); radix_tree_preload_end(); } return error; @@ -214,9 +214,9 @@ void delete_from_swap_cache(struct page *page) entry.val = page->private; - spin_lock_irq(&swapper_space.tree_lock); + write_lock_irq(&swapper_space.tree_lock); __delete_from_swap_cache(page); - spin_unlock_irq(&swapper_space.tree_lock); + write_unlock_irq(&swapper_space.tree_lock); swap_free(entry); page_cache_release(page); @@ -315,13 +315,13 @@ struct page * lookup_swap_cache(swp_entry_t entry) { struct page *page; - spin_lock_irq(&swapper_space.tree_lock); + read_lock_irq(&swapper_space.tree_lock); page = radix_tree_lookup(&swapper_space.page_tree, entry.val); if (page) { page_cache_get(page); INC_CACHE_INFO(find_success); } - spin_unlock_irq(&swapper_space.tree_lock); + read_unlock_irq(&swapper_space.tree_lock); INC_CACHE_INFO(find_total); return page; } @@ -344,12 +344,12 @@ struct page *read_swap_cache_async(swp_entry_t entry, * called after lookup_swap_cache() failed, re-calling * that would confuse statistics. */ - spin_lock_irq(&swapper_space.tree_lock); + read_lock_irq(&swapper_space.tree_lock); found_page = radix_tree_lookup(&swapper_space.page_tree, entry.val); if (found_page) page_cache_get(found_page); - spin_unlock_irq(&swapper_space.tree_lock); + read_unlock_irq(&swapper_space.tree_lock); if (found_page) break; diff --git a/mm/swapfile.c b/mm/swapfile.c index 8f2a388911b1..783ec752c4fe 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -291,10 +291,10 @@ static int exclusive_swap_page(struct page *page) /* Is the only swap cache user the cache itself? */ if (p->swap_map[swp_offset(entry)] == 1) { /* Recheck the page count with the swapcache lock held.. */ - spin_lock_irq(&swapper_space.tree_lock); + write_lock_irq(&swapper_space.tree_lock); if (page_count(page) == 2) retval = 1; - spin_unlock_irq(&swapper_space.tree_lock); + write_unlock_irq(&swapper_space.tree_lock); } swap_info_put(p); } @@ -362,13 +362,13 @@ int remove_exclusive_swap_page(struct page *page) retval = 0; if (p->swap_map[swp_offset(entry)] == 1) { /* Recheck the page count with the swapcache lock held.. */ - spin_lock_irq(&swapper_space.tree_lock); + write_lock_irq(&swapper_space.tree_lock); if ((page_count(page) == 2) && !PageWriteback(page)) { __delete_from_swap_cache(page); SetPageDirty(page); retval = 1; } - spin_unlock_irq(&swapper_space.tree_lock); + write_unlock_irq(&swapper_space.tree_lock); } swap_info_put(p); @@ -392,12 +392,12 @@ void free_swap_and_cache(swp_entry_t entry) p = swap_info_get(entry); if (p) { if (swap_entry_free(p, swp_offset(entry)) == 1) { - spin_lock_irq(&swapper_space.tree_lock); + read_lock_irq(&swapper_space.tree_lock); page = radix_tree_lookup(&swapper_space.page_tree, entry.val); if (page && TestSetPageLocked(page)) page = NULL; - spin_unlock_irq(&swapper_space.tree_lock); + read_unlock_irq(&swapper_space.tree_lock); } swap_info_put(p); } diff --git a/mm/truncate.c b/mm/truncate.c index f1fa4bb2c1ea..dafd64ccb73d 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -76,15 +76,15 @@ invalidate_complete_page(struct address_space *mapping, struct page *page) if (PagePrivate(page) && !try_to_release_page(page, 0)) return 0; - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); if (PageDirty(page)) { - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); return 0; } BUG_ON(PagePrivate(page)); __remove_from_page_cache(page); - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); ClearPageUptodate(page); page_cache_release(page); /* pagecache ref */ return 1; diff --git a/mm/vmscan.c b/mm/vmscan.c index f8417ff769c4..62f1ad405eb6 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -475,7 +475,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) if (!mapping) goto keep_locked; /* truncate got there first */ - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); /* * The non-racy check for busy page. It is critical to check @@ -483,7 +483,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) * not in use by anybody. (pagecache + us == 2) */ if (page_count(page) != 2 || PageDirty(page)) { - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); goto keep_locked; } @@ -491,7 +491,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) if (PageSwapCache(page)) { swp_entry_t swap = { .val = page->private }; __delete_from_swap_cache(page); - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); swap_free(swap); __put_page(page); /* The pagecache ref */ goto free_it; @@ -499,7 +499,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) #endif /* CONFIG_SWAP */ __remove_from_page_cache(page); - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); __put_page(page); free_it: -- cgit v1.2.3 From b21d1ff22952382860b6a163ae9325ea5d3bc30b Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 4 Mar 2005 17:27:37 -0800 Subject: [PATCH] PPC/PPC64: Abstract cpu_feature checks. Abstract most manual mask checks of cpu_features with cpu_has_feature() Signed-off-by: Olof Johansson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/kernel/ppc_htab.c | 8 ++++---- arch/ppc/kernel/setup.c | 4 ++-- arch/ppc/kernel/temp.c | 2 +- arch/ppc/mm/mmu_decl.h | 2 +- arch/ppc/mm/ppc_mmu.c | 4 ++-- arch/ppc/platforms/pmac_cpufreq.c | 2 +- arch/ppc/platforms/pmac_setup.c | 2 +- arch/ppc/platforms/pmac_smp.c | 4 ++-- arch/ppc/platforms/sandpoint.c | 6 +++--- arch/ppc64/kernel/align.c | 2 +- arch/ppc64/kernel/iSeries_setup.c | 2 +- arch/ppc64/kernel/pSeries_lpar.c | 2 +- arch/ppc64/kernel/process.c | 4 ++-- arch/ppc64/kernel/setup.c | 6 +++--- arch/ppc64/kernel/smp.c | 2 +- arch/ppc64/kernel/sysfs.c | 22 +++++++++++----------- arch/ppc64/mm/hash_native.c | 14 +++++++------- arch/ppc64/mm/hash_utils.c | 2 +- arch/ppc64/mm/hugetlbpage.c | 2 +- arch/ppc64/mm/init.c | 10 +++++----- arch/ppc64/mm/slb.c | 4 ++-- arch/ppc64/mm/stab.c | 2 +- arch/ppc64/oprofile/op_model_power4.c | 2 +- arch/ppc64/oprofile/op_model_rs64.c | 2 +- arch/ppc64/xmon/xmon.c | 8 ++++---- drivers/macintosh/via-pmu.c | 2 +- drivers/md/raid6altivec.uc | 2 +- include/asm-ppc/cputable.h | 5 +++++ include/asm-ppc64/cacheflush.h | 2 +- include/asm-ppc64/cputable.h | 5 +++++ include/asm-ppc64/mmu_context.h | 4 ++-- include/asm-ppc64/page.h | 2 +- 32 files changed, 76 insertions(+), 66 deletions(-) (limited to 'include') diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index b5cd7e411e65..ca810025993f 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -108,7 +108,7 @@ static int ppc_htab_show(struct seq_file *m, void *v) PTE *ptr; #endif /* CONFIG_PPC_STD_MMU */ - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) { + if (cpu_has_feature(CPU_FTR_604_PERF_MON)) { mmcr0 = mfspr(SPRN_MMCR0); pmc1 = mfspr(SPRN_PMC1); pmc2 = mfspr(SPRN_PMC2); @@ -209,7 +209,7 @@ static ssize_t ppc_htab_write(struct file * file, const char __user * ubuffer, if ( !strncmp( buffer, "reset", 5) ) { - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) { + if (cpu_has_feature(CPU_FTR_604_PERF_MON)) { /* reset PMC1 and PMC2 */ mtspr(SPRN_PMC1, 0); mtspr(SPRN_PMC2, 0); @@ -221,7 +221,7 @@ static ssize_t ppc_htab_write(struct file * file, const char __user * ubuffer, } /* Everything below here requires the performance monitor feature. */ - if ( !cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON ) + if (!cpu_has_feature(CPU_FTR_604_PERF_MON)) return count; /* turn off performance monitoring */ @@ -339,7 +339,7 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp, "0.5", "1.0", "(reserved2)", "(reserved3)" }; - if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)) + if (!cpu_has_feature(CPU_FTR_L2CR)) return -EFAULT; if ( /*!table->maxlen ||*/ (*ppos && !write)) { diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 5e7ce4b8febc..fdcef4d23b9b 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -619,7 +619,7 @@ machine_init(unsigned long r3, unsigned long r4, unsigned long r5, /* Checks "l2cr=xxxx" command-line option */ int __init ppc_setup_l2cr(char *str) { - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) { + if (cpu_has_feature(CPU_FTR_L2CR)) { unsigned long val = simple_strtoul(str, NULL, 0); printk(KERN_INFO "l2cr set to %lx\n", val); _set_L2CR(0); /* force invalidate by disable cache */ @@ -720,7 +720,7 @@ void __init setup_arch(char **cmdline_p) * Systems with OF can look in the properties on the cpu node(s) * for a possibly more accurate value. */ - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_SPLIT_ID_CACHE) { + if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) { dcache_bsize = cur_cpu_spec[0]->dcache_bsize; icache_bsize = cur_cpu_spec[0]->icache_bsize; ucache_bsize = 0; diff --git a/arch/ppc/kernel/temp.c b/arch/ppc/kernel/temp.c index 8d4b226e1342..fe8bb634ead0 100644 --- a/arch/ppc/kernel/temp.c +++ b/arch/ppc/kernel/temp.c @@ -223,7 +223,7 @@ int __init TAU_init(void) /* We assume in SMP that if one CPU has TAU support, they * all have it --BenH */ - if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_TAU)) { + if (!cpu_has_feature(CPU_FTR_TAU)) { printk("Thermal assist unit not available\n"); tau_initialized = 0; return 1; diff --git a/arch/ppc/mm/mmu_decl.h b/arch/ppc/mm/mmu_decl.h index 4699d6f64005..ffcdb46997dc 100644 --- a/arch/ppc/mm/mmu_decl.h +++ b/arch/ppc/mm/mmu_decl.h @@ -75,7 +75,7 @@ static inline void flush_HPTE(unsigned context, unsigned long va, unsigned long pdval) { if ((Hash != 0) && - (cur_cpu_spec[0]->cpu_features & CPU_FTR_HPTE_TABLE)) + cpu_has_feature(CPU_FTR_HPTE_TABLE)) flush_hash_pages(0, va, pdval, 1); else _tlbie(va); diff --git a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c index 4fa5bf16fa1d..3643da9e1df5 100644 --- a/arch/ppc/mm/ppc_mmu.c +++ b/arch/ppc/mm/ppc_mmu.c @@ -138,7 +138,7 @@ void __init setbat(int index, unsigned long virt, unsigned long phys, union ubat *bat = BATS[index]; if (((flags & _PAGE_NO_CACHE) == 0) && - (cur_cpu_spec[0]->cpu_features & CPU_FTR_NEED_COHERENT)) + cpu_has_feature(CPU_FTR_NEED_COHERENT)) flags |= _PAGE_COHERENT; bl = (size >> 17) - 1; @@ -191,7 +191,7 @@ void __init MMU_init_hw(void) extern unsigned int hash_page[]; extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[]; - if ((cur_cpu_spec[0]->cpu_features & CPU_FTR_HPTE_TABLE) == 0) { + if (!cpu_has_feature(CPU_FTR_HPTE_TABLE)) { /* * Put a blr (procedure return) instruction at the * start of hash_page, since we can still get DSI diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c index 73843408c63d..c644ab8f0818 100644 --- a/arch/ppc/platforms/pmac_cpufreq.c +++ b/arch/ppc/platforms/pmac_cpufreq.c @@ -230,7 +230,7 @@ static int __pmac pmu_set_cpu_speed(int low_speed) enable_kernel_fp(); #ifdef CONFIG_ALTIVEC - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + if (cpu_has_feature(CPU_FTR_ALTIVEC)) enable_kernel_altivec(); #endif /* CONFIG_ALTIVEC */ diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c index 513952331986..6d46e8bd45bc 100644 --- a/arch/ppc/platforms/pmac_setup.c +++ b/arch/ppc/platforms/pmac_setup.c @@ -274,7 +274,7 @@ pmac_setup_arch(void) pmac_find_bridges(); /* Checks "l2cr-value" property in the registry */ - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) { + if (cpu_has_feature(CPU_FTR_L2CR)) { struct device_node *np = find_devices("cpus"); if (np == 0) np = find_type_devices("cpu"); diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c index d6624b018ed9..0ca3a6b69152 100644 --- a/arch/ppc/platforms/pmac_smp.c +++ b/arch/ppc/platforms/pmac_smp.c @@ -119,7 +119,7 @@ static volatile int sec_tb_reset = 0; static void __init core99_init_caches(int cpu) { - if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)) + if (!cpu_has_feature(CPU_FTR_L2CR)) return; if (cpu == 0) { @@ -132,7 +132,7 @@ static void __init core99_init_caches(int cpu) printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); } - if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR)) + if (!cpu_has_feature(CPU_FTR_L3CR)) return; if (cpu == 0){ diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c index b07f416cc0d4..8674b8761167 100644 --- a/arch/ppc/platforms/sandpoint.c +++ b/arch/ppc/platforms/sandpoint.c @@ -319,10 +319,10 @@ sandpoint_setup_arch(void) * We will do this now with good known values. Future versions * of DINK32 are supposed to get this correct. */ - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_SPEC7450) + if (cpu_has_feature(CPU_FTR_SPEC7450)) /* 745x is different. We only want to pass along enable. */ _set_L2CR(L2CR_L2E); - else if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) + else if (cpu_has_feature(CPU_FTR_L2CR)) /* All modules have 1MB of L2. We also assume that an * L2 divisor of 3 will work. */ @@ -330,7 +330,7 @@ sandpoint_setup_arch(void) | L2CR_L2RAM_PIPE | L2CR_L2OH_1_0 | L2CR_L2DF); #if 0 /* Untested right now. */ - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR) { + if (cpu_has_feature(CPU_FTR_L3CR)) { /* Magic value. */ _set_L3CR(0x8f032000); } diff --git a/arch/ppc64/kernel/align.c b/arch/ppc64/kernel/align.c index 853b3ae7435c..67002a89813f 100644 --- a/arch/ppc64/kernel/align.c +++ b/arch/ppc64/kernel/align.c @@ -238,7 +238,7 @@ fix_alignment(struct pt_regs *regs) dsisr = regs->dsisr; - if (cur_cpu_spec->cpu_features & CPU_FTR_NODSISRALIGN) { + if (cpu_has_feature(CPU_FTR_NODSISRALIGN)) { unsigned int real_instr; if (__get_user(real_instr, (unsigned int __user *)regs->nip)) return 0; diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 7191f57d8856..eac1348d80af 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -267,7 +267,7 @@ unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, unsigned long i; unsigned long mem_blocks = 0; - if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) + if (cpu_has_feature(CPU_FTR_SLB)) mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, max_entries); else diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c index 624acf0c8cec..c816f40919f0 100644 --- a/arch/ppc64/kernel/pSeries_lpar.c +++ b/arch/ppc64/kernel/pSeries_lpar.c @@ -505,7 +505,7 @@ void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number, int i; unsigned long flags = 0; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); - int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index d1c152db959b..d4d8d57705a6 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -388,12 +388,12 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, kregs = (struct pt_regs *) sp; sp -= STACK_FRAME_OVERHEAD; p->thread.ksp = sp; - if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) { + if (cpu_has_feature(CPU_FTR_SLB)) { unsigned long sp_vsid = get_kernel_vsid(sp); sp_vsid <<= SLB_VSID_SHIFT; sp_vsid |= SLB_VSID_KERNEL; - if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + if (cpu_has_feature(CPU_FTR_16M_PAGE)) sp_vsid |= SLB_VSID_L; p->thread.ksp_vsid = sp_vsid; diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 870c69ee8c59..ed2e166fd9d6 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -315,7 +315,7 @@ static void __init setup_cpu_maps(void) maxcpus = ireg[num_addr_cell + num_size_cell]; /* Double maxcpus for processors which have SMT capability */ - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) + if (cpu_has_feature(CPU_FTR_SMT)) maxcpus *= 2; if (maxcpus > NR_CPUS) { @@ -339,7 +339,7 @@ static void __init setup_cpu_maps(void) */ for_each_cpu(cpu) { cpu_set(cpu, cpu_sibling_map[cpu]); - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) + if (cpu_has_feature(CPU_FTR_SMT)) cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); } @@ -767,7 +767,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "unknown (%08x)", pvr); #ifdef CONFIG_ALTIVEC - if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC) + if (cpu_has_feature(CPU_FTR_ALTIVEC)) seq_printf(m, ", altivec supported"); #endif /* CONFIG_ALTIVEC */ diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 2eb4f5e6439c..d6ecf0727596 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -416,7 +416,7 @@ int __devinit __cpu_up(unsigned int cpu) paca[cpu].default_decr = tb_ticks_per_jiffy / decr_overclock; - if (!(cur_cpu_spec->cpu_features & CPU_FTR_SLB)) { + if (!cpu_has_feature(CPU_FTR_SLB)) { void *tmp; /* maximum of 48 CPUs on machines with a segment table */ diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c index 4eacd4fe4411..bbc9dcda17f7 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/ppc64/kernel/sysfs.c @@ -63,7 +63,7 @@ static int __init smt_setup(void) unsigned int *val; unsigned int cpu; - if (!cur_cpu_spec->cpu_features & CPU_FTR_SMT) + if (!cpu_has_feature(CPU_FTR_SMT)) return 1; options = find_path_device("/options"); @@ -86,7 +86,7 @@ static int __init setup_smt_snooze_delay(char *str) unsigned int cpu; int snooze; - if (!cur_cpu_spec->cpu_features & CPU_FTR_SMT) + if (!cpu_has_feature(CPU_FTR_SMT)) return 1; smt_snooze_cmdline = 1; @@ -167,7 +167,7 @@ void ppc64_enable_pmcs(void) * On SMT machines we have to set the run latch in the ctrl register * in order to make PMC6 spin. */ - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) { + if (cpu_has_feature(CPU_FTR_SMT)) { ctrl = mfspr(CTRLF); ctrl |= RUNLATCH; mtspr(CTRLT, ctrl); @@ -266,7 +266,7 @@ static void register_cpu_online(unsigned int cpu) struct sys_device *s = &c->sysdev; #ifndef CONFIG_PPC_ISERIES - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) + if (cpu_has_feature(CPU_FTR_SMT)) sysdev_create_file(s, &attr_smt_snooze_delay); #endif @@ -275,7 +275,7 @@ static void register_cpu_online(unsigned int cpu) sysdev_create_file(s, &attr_mmcr0); sysdev_create_file(s, &attr_mmcr1); - if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA) + if (cpu_has_feature(CPU_FTR_MMCRA)) sysdev_create_file(s, &attr_mmcra); sysdev_create_file(s, &attr_pmc1); @@ -285,12 +285,12 @@ static void register_cpu_online(unsigned int cpu) sysdev_create_file(s, &attr_pmc5); sysdev_create_file(s, &attr_pmc6); - if (cur_cpu_spec->cpu_features & CPU_FTR_PMC8) { + if (cpu_has_feature(CPU_FTR_PMC8)) { sysdev_create_file(s, &attr_pmc7); sysdev_create_file(s, &attr_pmc8); } - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) + if (cpu_has_feature(CPU_FTR_SMT)) sysdev_create_file(s, &attr_purr); } @@ -303,7 +303,7 @@ static void unregister_cpu_online(unsigned int cpu) BUG_ON(c->no_control); #ifndef CONFIG_PPC_ISERIES - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) + if (cpu_has_feature(CPU_FTR_SMT)) sysdev_remove_file(s, &attr_smt_snooze_delay); #endif @@ -312,7 +312,7 @@ static void unregister_cpu_online(unsigned int cpu) sysdev_remove_file(s, &attr_mmcr0); sysdev_remove_file(s, &attr_mmcr1); - if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA) + if (cpu_has_feature(CPU_FTR_MMCRA)) sysdev_remove_file(s, &attr_mmcra); sysdev_remove_file(s, &attr_pmc1); @@ -322,12 +322,12 @@ static void unregister_cpu_online(unsigned int cpu) sysdev_remove_file(s, &attr_pmc5); sysdev_remove_file(s, &attr_pmc6); - if (cur_cpu_spec->cpu_features & CPU_FTR_PMC8) { + if (cpu_has_feature(CPU_FTR_PMC8)) { sysdev_remove_file(s, &attr_pmc7); sysdev_remove_file(s, &attr_pmc8); } - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) + if (cpu_has_feature(CPU_FTR_SMT)) sysdev_remove_file(s, &attr_purr); } #endif /* CONFIG_HOTPLUG_CPU */ diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c index dfd24ad27b14..144657e0c3d5 100644 --- a/arch/ppc64/mm/hash_native.c +++ b/arch/ppc64/mm/hash_native.c @@ -217,10 +217,10 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, } /* Ensure it is out of the tlb too */ - if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { + if (cpu_has_feature(CPU_FTR_TLBIEL) && !large && local) { tlbiel(va); } else { - int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); if (lock_tlbie) spin_lock(&native_tlbie_lock); @@ -245,7 +245,7 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea) unsigned long vsid, va, vpn, flags = 0; long slot; HPTE *hptep; - int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); vsid = get_kernel_vsid(ea); va = (vsid << 28) | (ea & 0x0fffffff); @@ -273,7 +273,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, Hpte_dword0 dw0; unsigned long avpn = va >> 23; unsigned long flags; - int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); if (large) avpn &= ~0x1UL; @@ -292,7 +292,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, } /* Invalidate the tlb */ - if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { + if (cpu_has_feature(CPU_FTR_TLBIEL) && !large && local) { tlbiel(va); } else { if (lock_tlbie) @@ -360,7 +360,7 @@ static void native_flush_hash_range(unsigned long context, j++; } - if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { + if (cpu_has_feature(CPU_FTR_TLBIEL) && !large && local) { asm volatile("ptesync":::"memory"); for (i = 0; i < j; i++) @@ -368,7 +368,7 @@ static void native_flush_hash_range(unsigned long context, asm volatile("ptesync":::"memory"); } else { - int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); if (lock_tlbie) spin_lock(&native_tlbie_lock); diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c index 9b01f6fb6825..2453c57ec5c6 100644 --- a/arch/ppc64/mm/hash_utils.c +++ b/arch/ppc64/mm/hash_utils.c @@ -190,7 +190,7 @@ void __init htab_initialize(void) * _NOT_ map it to avoid cache paradoxes as it's remapped non * cacheable later on */ - if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + if (cpu_has_feature(CPU_FTR_16M_PAGE)) use_largepages = 1; /* create bolted the linear mapping in the hash table */ diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c index 3aa910f89369..6cfba682e8b5 100644 --- a/arch/ppc64/mm/hugetlbpage.c +++ b/arch/ppc64/mm/hugetlbpage.c @@ -709,7 +709,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, if (len & ~HPAGE_MASK) return -EINVAL; - if (!(cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE)) + if (!cpu_has_feature(CPU_FTR_16M_PAGE)) return -EINVAL; if (test_thread_flag(TIF_32BIT)) { diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index 4cb05a070c01..2ad8b0b00eec 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -752,7 +752,7 @@ void __init mem_init(void) */ void flush_dcache_page(struct page *page) { - if (cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE) + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) return; /* avoid an atomic op if possible */ if (test_bit(PG_arch_1, &page->flags)) @@ -763,7 +763,7 @@ void clear_user_page(void *page, unsigned long vaddr, struct page *pg) { clear_page(page); - if (cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE) + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) return; /* * We shouldnt have to do this, but some versions of glibc @@ -796,7 +796,7 @@ void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, return; #endif - if (cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE) + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) return; /* avoid an atomic op if possible */ @@ -832,8 +832,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea, unsigned long flags; /* handle i-cache coherency */ - if (!(cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE) && - !(cur_cpu_spec->cpu_features & CPU_FTR_NOEXECUTE)) { + if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && + !cpu_has_feature(CPU_FTR_NOEXECUTE)) { unsigned long pfn = pte_pfn(pte); if (pfn_valid(pfn)) { struct page *page = pfn_to_page(pfn); diff --git a/arch/ppc64/mm/slb.c b/arch/ppc64/mm/slb.c index 12493cad3b68..6a20773f695d 100644 --- a/arch/ppc64/mm/slb.c +++ b/arch/ppc64/mm/slb.c @@ -51,7 +51,7 @@ static void slb_flush_and_rebolt(void) WARN_ON(!irqs_disabled()); - if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + if (cpu_has_feature(CPU_FTR_16M_PAGE)) ksp_flags |= SLB_VSID_L; ksp_esid_data = mk_esid_data(get_paca()->kstack, 2); @@ -139,7 +139,7 @@ void slb_initialize(void) unsigned long flags = SLB_VSID_KERNEL; /* Invalidate the entire SLB (even slot 0) & all the ERATS */ - if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) + if (cpu_has_feature(CPU_FTR_16M_PAGE)) flags |= SLB_VSID_L; asm volatile("isync":::"memory"); diff --git a/arch/ppc64/mm/stab.c b/arch/ppc64/mm/stab.c index 38155a2554dc..31491131d5e4 100644 --- a/arch/ppc64/mm/stab.c +++ b/arch/ppc64/mm/stab.c @@ -227,7 +227,7 @@ void stab_initialize(unsigned long stab) { unsigned long vsid = get_kernel_vsid(KERNELBASE); - if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) { + if (cpu_has_feature(CPU_FTR_SLB)) { slb_initialize(); } else { asm volatile("isync; slbia; isync":::"memory"); diff --git a/arch/ppc64/oprofile/op_model_power4.c b/arch/ppc64/oprofile/op_model_power4.c index b1ca798f4c29..1ad37ca65d1f 100644 --- a/arch/ppc64/oprofile/op_model_power4.c +++ b/arch/ppc64/oprofile/op_model_power4.c @@ -54,7 +54,7 @@ static void power4_reg_setup(struct op_counter_config *ctr, * * It has been verified to work on POWER5 so we enable it there. */ - if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA_SIHV) + if (cpu_has_feature(CPU_FTR_MMCRA_SIHV)) mmcra_has_sihv = 1; /* diff --git a/arch/ppc64/oprofile/op_model_rs64.c b/arch/ppc64/oprofile/op_model_rs64.c index b3cddb7e03d0..bcec506c266a 100644 --- a/arch/ppc64/oprofile/op_model_rs64.c +++ b/arch/ppc64/oprofile/op_model_rs64.c @@ -114,7 +114,7 @@ static void rs64_cpu_setup(void *unused) /* reset MMCR1, MMCRA */ mtspr(SPRN_MMCR1, 0); - if (cur_cpu_spec->cpu_features & CPU_FTR_MMCRA) + if (cpu_has_feature(CPU_FTR_MMCRA)) mtspr(SPRN_MMCRA, 0); mmcr0 |= MMCR0_FCM1|MMCR0_PMXE|MMCR0_FCECE; diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c index b456e5763645..ee9c779be6a2 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/ppc64/xmon/xmon.c @@ -725,7 +725,7 @@ static void insert_cpu_bpts(void) { if (dabr.enabled) set_controlled_dabr(dabr.address | (dabr.enabled & 7)); - if (iabr && (cur_cpu_spec->cpu_features & CPU_FTR_IABR)) + if (iabr && cpu_has_feature(CPU_FTR_IABR)) set_iabr(iabr->address | (iabr->enabled & (BP_IABR|BP_IABR_TE))); } @@ -753,7 +753,7 @@ static void remove_bpts(void) static void remove_cpu_bpts(void) { set_controlled_dabr(0); - if ((cur_cpu_spec->cpu_features & CPU_FTR_IABR)) + if (cpu_has_feature(CPU_FTR_IABR)) set_iabr(0); } @@ -1100,7 +1100,7 @@ bpt_cmds(void) break; case 'i': /* bi - hardware instr breakpoint */ - if (!(cur_cpu_spec->cpu_features & CPU_FTR_IABR)) { + if (!cpu_has_feature(CPU_FTR_IABR)) { printf("Hardware instruction breakpoint " "not supported on this cpu\n"); break; @@ -2498,7 +2498,7 @@ void xmon_init(void) void dump_segments(void) { - if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) + if (cpu_has_feature(CPU_FTR_SLB)) dump_slb(); else dump_stab(); diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 019f4c4e3a94..8089181efbf1 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2389,7 +2389,7 @@ pmac_suspend_devices(void) enable_kernel_fp(); #ifdef CONFIG_ALTIVEC - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + if (cpu_has_feature(CPU_FTR_ALTIVEC)) enable_kernel_altivec(); #endif /* CONFIG_ALTIVEC */ diff --git a/drivers/md/raid6altivec.uc b/drivers/md/raid6altivec.uc index e21197a363c3..2c0e709a67e6 100644 --- a/drivers/md/raid6altivec.uc +++ b/drivers/md/raid6altivec.uc @@ -108,7 +108,7 @@ int raid6_have_altivec(void); int raid6_have_altivec(void) { /* This assumes either all CPUs have Altivec or none does */ - return cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC; + return cpu_has_feature(CPU_FTR_ALTIVEC): } #endif diff --git a/include/asm-ppc/cputable.h b/include/asm-ppc/cputable.h index 34f37ab61324..22de04fe1b4c 100644 --- a/include/asm-ppc/cputable.h +++ b/include/asm-ppc/cputable.h @@ -61,6 +61,11 @@ struct cpu_spec { extern struct cpu_spec cpu_specs[]; extern struct cpu_spec *cur_cpu_spec[]; +static inline unsigned int cpu_has_feature(unsigned int feature) +{ + return cur_cpu_spec[0]->cpu_features & feature; +} + #endif /* __ASSEMBLY__ */ /* CPU kernel features */ diff --git a/include/asm-ppc64/cacheflush.h b/include/asm-ppc64/cacheflush.h index d0f0dfd263d6..33d72572fdf4 100644 --- a/include/asm-ppc64/cacheflush.h +++ b/include/asm-ppc64/cacheflush.h @@ -40,7 +40,7 @@ extern void __flush_dcache_icache(void *page_va); static inline void flush_icache_range(unsigned long start, unsigned long stop) { - if (!(cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE)) + if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) __flush_icache_range(start, stop); } diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h index 6ef442318e46..cbbfbec78b6b 100644 --- a/include/asm-ppc64/cputable.h +++ b/include/asm-ppc64/cputable.h @@ -66,6 +66,11 @@ struct cpu_spec { extern struct cpu_spec cpu_specs[]; extern struct cpu_spec *cur_cpu_spec; +static inline unsigned long cpu_has_feature(unsigned long feature) +{ + return cur_cpu_spec->cpu_features & feature; +} + /* firmware feature bitmask values */ #define FIRMWARE_MAX_FEATURES 63 diff --git a/include/asm-ppc64/mmu_context.h b/include/asm-ppc64/mmu_context.h index 37f6ea055bf3..c2e8e0466383 100644 --- a/include/asm-ppc64/mmu_context.h +++ b/include/asm-ppc64/mmu_context.h @@ -59,11 +59,11 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, return; #ifdef CONFIG_ALTIVEC - if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC) + if (cpu_has_feature(CPU_FTR_ALTIVEC)) asm volatile ("dssall"); #endif /* CONFIG_ALTIVEC */ - if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) + if (cpu_has_feature(CPU_FTR_SLB)) switch_slb(tsk, next); else switch_stab(tsk, next); diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h index ca828e5aeb8a..ef16df988b62 100644 --- a/include/asm-ppc64/page.h +++ b/include/asm-ppc64/page.h @@ -67,7 +67,7 @@ #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA #define in_hugepage_area(context, addr) \ - ((cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) && \ + (cpu_has_feature(CPU_FTR_16M_PAGE) && \ ( (((addr) >= TASK_HPAGE_BASE) && ((addr) < TASK_HPAGE_END)) || \ ( ((addr) < 0x100000000L) && \ ((1 << GET_ESID(addr)) & (context).htlb_segs) ) ) ) -- cgit v1.2.3 From dee79019884900e08d748d2f9de20ca9491bb15b Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Fri, 4 Mar 2005 17:28:32 -0800 Subject: [PATCH] ppc32: Artesyn Katana platform update - Adds MTD support for the soldered FLASH - Adds cmdline parsing - Turns on the Blue LED when the system is halted - Moves some of the device window left by the firmware to proper alignments - Handles possibility of different frequencies for TCLK & SysCLK in 64460 - Misc. code clean up Signed-off-by: Mark A. Greer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/configs/katana_defconfig | 93 ++++++++++++++++-- arch/ppc/platforms/katana.c | 193 ++++++++++++++++++++++++++++---------- arch/ppc/platforms/katana.h | 45 ++++----- include/asm-ppc/mv64x60_defs.h | 4 +- 4 files changed, 251 insertions(+), 84 deletions(-) (limited to 'include') diff --git a/arch/ppc/configs/katana_defconfig b/arch/ppc/configs/katana_defconfig index 0134ae18c9b9..db0733b3152e 100644 --- a/arch/ppc/configs/katana_defconfig +++ b/arch/ppc/configs/katana_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc2 -# Tue Jan 25 16:31:13 2005 +# Linux kernel version: 2.6.11-rc4 +# Tue Feb 15 14:27:12 2005 # CONFIG_MMU=y CONFIG_GENERIC_HARDIRQS=y @@ -152,8 +152,8 @@ CONFIG_KERNEL_START=0xc0000000 CONFIG_TASK_SIZE=0x80000000 CONFIG_CONSISTENT_START_BOOL=y CONFIG_CONSISTENT_START=0xf0000000 -# CONFIG_CONSISTENT_SIZE_BOOL is not set -CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_CONSISTENT_SIZE_BOOL=y +CONFIG_CONSISTENT_SIZE=0x00400000 # CONFIG_BOOT_LOAD_BOOL is not set CONFIG_BOOT_LOAD=0x00800000 @@ -171,7 +171,82 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # Memory Technology Devices (MTD) # -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CONCAT=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +# CONFIG_MTD_CFI_I1 is not set +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_XIP is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0xe0000000 +CONFIG_MTD_PHYSMAP_LEN=0x0 +CONFIG_MTD_PHYSMAP_BANKWIDTH=4 + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_PHRAM=y +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set # # Parallel port support @@ -531,7 +606,6 @@ CONFIG_GEN_RTC=y # # CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -573,6 +647,10 @@ CONFIG_EXT2_FS=y # CONFIG_JBD is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set + +# +# XFS support +# # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -619,6 +697,8 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -637,7 +717,6 @@ CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y -# CONFIG_EXPORTFS is not set CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c index bad8f27fa614..ee33eda0d387 100644 --- a/arch/ppc/platforms/katana.c +++ b/arch/ppc/platforms/katana.c @@ -1,9 +1,10 @@ /* * arch/ppc/platforms/katana.c * - * Board setup routines for the Artesyn Katana 750 based boards. + * Board setup routines for the Artesyn Katana cPCI boards. * - * Tim Montgomery + * Athor: Tim Montgomery + * Maintained by: Mark A. Greer * * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il * Based on code done by - Mark A. Greer @@ -26,7 +27,8 @@ #include #include #include -#include +#include +#include #include #ifdef CONFIG_BOOTIMG #include @@ -36,13 +38,19 @@ #include #include #include +#include #include #include static struct mv64x60_handle bh; static katana_id_t katana_id; -static u32 cpld_base; -static u32 sram_base; +static void __iomem *cpld_base; +static void __iomem *sram_base; + +static u32 katana_flash_size_0; +static u32 katana_flash_size_1; + +unsigned char __res[sizeof(bd_t)]; /* PCI Interrupt routing */ static int __init @@ -105,7 +113,7 @@ katana_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) void __init katana_get_board_id(void) { - switch (in_8((volatile char *)(cpld_base + KATANA_CPLD_PRODUCT_ID))) { + switch (in_8(cpld_base + KATANA_CPLD_PRODUCT_ID)) { case KATANA_PRODUCT_ID_3750: katana_id = KATANA_ID_3750; break; @@ -170,7 +178,7 @@ katana_get_proc_num(void) static inline int katana_is_monarch(void) { - return in_8((volatile char *)(cpld_base + KATANA_CPLD_BD_CFG_3)) & + return in_8(cpld_base + KATANA_CPLD_BD_CFG_3) & KATANA_CPLD_BD_CFG_3_MONARCH; } @@ -180,18 +188,17 @@ katana_enable_ipmi(void) u8 reset_out; /* Enable access to IPMI ctlr by clearing IPMI PORTSEL bit in CPLD */ - reset_out = in_8((volatile char *)(cpld_base + KATANA_CPLD_RESET_OUT)); + reset_out = in_8(cpld_base + KATANA_CPLD_RESET_OUT); reset_out &= ~KATANA_CPLD_RESET_OUT_PORTSEL; - out_8((volatile void *)(cpld_base + KATANA_CPLD_RESET_OUT), reset_out); - return; + out_8(cpld_base + KATANA_CPLD_RESET_OUT, reset_out); } -static unsigned long +static u32 katana_bus_freq(void) { u8 bd_cfg_0; - bd_cfg_0 = in_8((volatile char *)(cpld_base + KATANA_CPLD_BD_CFG_0)); + bd_cfg_0 = in_8(cpld_base + KATANA_CPLD_BD_CFG_0); switch (bd_cfg_0 & KATANA_CPLD_BD_CFG_0_SYSCLK_MASK) { case KATANA_CPLD_BD_CFG_0_SYSCLK_200: @@ -263,13 +270,12 @@ katana_intr_setup(void) * BIT25 summarizes GPP interrupts 8-15 */ mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, (1<<25)); - return; } void __init katana_setup_peripherals(void) { - u32 base, size_0, size_1; + u32 base; /* Set up windows for boot CS, soldered & socketed flash, and CPLD */ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, @@ -277,19 +283,22 @@ katana_setup_peripherals(void) bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); /* Assume firmware set up window sizes correctly for dev 0 & 1 */ - mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, &base, &size_0); + mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, &base, + &katana_flash_size_0); - if (size_0 > 0) { + if (katana_flash_size_0 > 0) { mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, - KATANA_SOLDERED_FLASH_BASE, size_0, 0); + KATANA_SOLDERED_FLASH_BASE, katana_flash_size_0, 0); bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN); } - mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, &base, &size_1); + mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, &base, + &katana_flash_size_1); - if (size_1 > 0) { + if (katana_flash_size_1 > 0) { mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, - (KATANA_SOLDERED_FLASH_BASE + size_0), size_1, 0); + (KATANA_SOLDERED_FLASH_BASE + katana_flash_size_0), + katana_flash_size_1, 0); bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN); } @@ -300,12 +309,12 @@ katana_setup_peripherals(void) mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN, KATANA_CPLD_BASE, KATANA_CPLD_SIZE, 0); bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN); - cpld_base = (u32)ioremap(KATANA_CPLD_BASE, KATANA_CPLD_SIZE); + cpld_base = ioremap(KATANA_CPLD_BASE, KATANA_CPLD_SIZE); mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN, KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0); bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); - sram_base = (u32)ioremap(KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE); + sram_base = ioremap(KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE); /* Set up Enet->SRAM window */ mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN, @@ -339,13 +348,11 @@ katana_setup_peripherals(void) * internal data path in SRAM since it's first time accessing it * while after reset it's not configured. */ - memset((void *)sram_base, 0, MV64360_SRAM_SIZE); + memset(sram_base, 0, MV64360_SRAM_SIZE); /* Only processor zero [on 3750] is an PCI interrupt controller */ if (katana_get_proc_num() == 0) katana_intr_setup(); - - return; } static void __init @@ -356,7 +363,7 @@ katana_setup_bridge(void) memset(&si, 0, sizeof(si)); - si.phys_reg_base = KATANA_BRIDGE_REG_BASE; + si.phys_reg_base = CONFIG_MV64X60_NEW_BASE; si.pci_1.enable_bus = 1; si.pci_1.pci_io.cpu_base = KATANA_PCI1_IO_START_PROC_ADDR; @@ -410,10 +417,77 @@ katana_setup_bridge(void) mv64x60_set_bus(&bh, 1, 0); bh.hose_b->first_busno = 0; bh.hose_b->last_busno = 0xff; +} + +#ifdef CONFIG_MTD_PHYSMAP + +#ifndef MB +#define MB (1 << 20) +#endif + +/* + * MTD Layout depends on amount of soldered FLASH in system. Sizes in MB. + * + * FLASH Amount: 128 64 32 16 + * ------------- --- -- -- -- + * Monitor: 1 1 1 1 + * Primary Kernel: 1.5 1.5 1.5 1.5 + * Primary fs: 30 30 + * Secondary Kernel: 1.5 1.5 N/A N/A + * Secondary fs: N/A N/A + * User: + */ +static int __init +katana_setup_mtd(void) +{ + u32 size; + int ptbl_entries; + static struct mtd_partition *ptbl; + + size = katana_flash_size_0 + katana_flash_size_1; + if (!size) + return -ENOMEM; - return; + ptbl_entries = (size >= (64*MB)) ? 6 : 4; + + if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition), + GFP_KERNEL)) == NULL) { + + printk(KERN_WARNING "Can't alloc MTD partition table\n"); + return -ENOMEM; + } + memset(ptbl, 0, ptbl_entries * sizeof(struct mtd_partition)); + + ptbl[0].name = "Monitor"; + ptbl[0].size = KATANA_MTD_MONITOR_SIZE; + ptbl[1].name = "Primary Kernel"; + ptbl[1].offset = MTDPART_OFS_NXTBLK; + ptbl[1].size = 0x00180000; /* 1.5 MB */ + ptbl[2].name = "Primary Filesystem"; + ptbl[2].offset = MTDPART_OFS_APPEND; + ptbl[2].size = MTDPART_SIZ_FULL; /* Correct for 16 & 32 MB */ + ptbl[ptbl_entries-1].name = "User FLASH"; + ptbl[ptbl_entries-1].offset = KATANA_MTD_MONITOR_SIZE; + ptbl[ptbl_entries-1].size = MTDPART_SIZ_FULL; + + if (size >= (64*MB)) { + ptbl[2].size = 30*MB; + ptbl[3].name = "Secondary Kernel"; + ptbl[3].offset = MTDPART_OFS_NXTBLK; + ptbl[3].size = 0x00180000; /* 1.5 MB */ + ptbl[4].name = "Secondary Filesystem"; + ptbl[4].offset = MTDPART_OFS_APPEND; + ptbl[4].size = MTDPART_SIZ_FULL; + } + + physmap_map.size = size; + physmap_set_partitions(ptbl, ptbl_entries); + return 0; } +arch_initcall(katana_setup_mtd); +#endif + static void __init katana_setup_arch(void) { @@ -444,8 +518,7 @@ katana_setup_arch(void) printk(KERN_INFO "DD2.0 detected. Setting L2 cache" "to Writethrough mode\n"); _set_L2CR(L2CR_L2E | L2CR_L2PE | L2CR_L2WT); - } - else + } else _set_L2CR(L2CR_L2E | L2CR_L2PE); if (ppc_md.progress) @@ -458,7 +531,6 @@ katana_setup_arch(void) printk(KERN_INFO "Artesyn Communication Products, LLC - Katana(TM)\n"); if (ppc_md.progress) ppc_md.progress("katana_setup_arch: exit", 0); - return; } /* Platform device data fixup routines. */ @@ -473,9 +545,12 @@ katana_fixup_mpsc_pdata(struct platform_device *pdev) pdata->max_idle = 40; pdata->default_baud = KATANA_DEFAULT_BAUD; pdata->brg_clk_src = KATANA_MPSC_CLK_SRC; - pdata->brg_clk_freq = KATANA_MPSC_CLK_FREQ; - - return; + /* + * TCLK (not SysCLk) is routed to BRG, then to the MPSC. On most parts, + * TCLK == SysCLK but on 64460, they are separate pins. + * SysCLK can go up to 200 MHz but TCLK can only go up to 133 MHz. + */ + pdata->brg_clk_freq = min(katana_bus_freq(), MV64x60_TCLK_FREQ_MAX); } #endif @@ -548,11 +623,10 @@ katana_platform_notify(struct device *dev) static void katana_restart(char *cmd) { - volatile ulong i = 10000000; + ulong i = 10000000; /* issue hard reset to the reset command register */ - out_8((volatile char *)(cpld_base + KATANA_CPLD_RST_CMD), - KATANA_CPLD_RST_CMD_HR); + out_8(cpld_base + KATANA_CPLD_RST_CMD, KATANA_CPLD_RST_CMD_HR); while (i-- > 0) ; panic("restart failed\n"); @@ -561,6 +635,14 @@ katana_restart(char *cmd) static void katana_halt(void) { + u8 v; + + if (katana_id == KATANA_ID_752I) { + v = in_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF); + v |= HSL_PLD_HOT_SWAP_LED_BIT; + out_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF, v); + } + while (1) ; /* NOTREACHED */ } @@ -598,12 +680,13 @@ katana_show_cpuinfo(struct seq_file *m) } seq_printf(m, "product ID\t: 0x%x\n", - in_8((volatile char *)(cpld_base + KATANA_CPLD_PRODUCT_ID))); + in_8(cpld_base + KATANA_CPLD_PRODUCT_ID)); seq_printf(m, "hardware rev\t: 0x%x\n", - in_8((volatile char *)(cpld_base+KATANA_CPLD_HARDWARE_VER))); + in_8(cpld_base+KATANA_CPLD_HARDWARE_VER)); seq_printf(m, "PLD rev\t\t: 0x%x\n", - in_8((volatile char *)(cpld_base + KATANA_CPLD_PLD_VER))); - seq_printf(m, "PLB freq\t: %ldMhz\n", katana_bus_freq() / 1000000); + in_8(cpld_base + KATANA_CPLD_PLD_VER)); + seq_printf(m, "PLB freq\t: %ldMhz\n", + (long)katana_bus_freq() / 1000000); seq_printf(m, "PCI\t\t: %sMonarch\n", katana_is_monarch()? "" : "Non-"); return 0; @@ -612,23 +695,21 @@ katana_show_cpuinfo(struct seq_file *m) static void __init katana_calibrate_decr(void) { - ulong freq; + u32 freq; freq = katana_bus_freq() / 4; printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", - freq / 1000000, freq % 1000000); + (long)freq / 1000000, (long)freq % 1000000); tb_ticks_per_jiffy = freq / HZ; tb_to_us = mulhwu_scale_factor(freq, 1000000); - - return; } unsigned long __init katana_find_end_of_memory(void) { - return mv64x60_get_mem_size(KATANA_BRIDGE_REG_BASE, + return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE, MV64x60_TYPE_MV64360); } @@ -639,8 +720,6 @@ katana_set_bat(void) mtspr(DBAT2U, 0xf0001ffe); mtspr(DBAT2L, 0xf000002a); mb(); - - return; } #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE) @@ -657,6 +736,23 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, { parse_bootinfo(find_bootinfo()); + /* ASSUMPTION: If both r3 (bd_t pointer) and r6 (cmdline pointer) + * are non-zero, then we should use the board info from the bd_t + * structure and the cmdline pointed to by r6 instead of the + * information from birecs, if any. Otherwise, use the information + * from birecs as discovered by the preceeding call to + * parse_bootinfo(). This rule should work with both PPCBoot, which + * uses a bd_t board info structure, and the kernel boot wrapper, + * which uses birecs. + */ + if (r3 && r6) { + /* copy board info structure */ + memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); + /* copy command line */ + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + isa_mem_base = 0; ppc_md.setup_arch = katana_setup_arch; @@ -672,7 +768,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE) ppc_md.setup_io_mappings = katana_map_io; ppc_md.progress = mv64x60_mpsc_progress; - mv64x60_progress_init(KATANA_BRIDGE_REG_BASE); + mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE); #endif #if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH) @@ -680,5 +776,4 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #endif katana_set_bat(); /* Need for katana_find_end_of_memory and progress */ - return; } diff --git a/arch/ppc/platforms/katana.h b/arch/ppc/platforms/katana.h index 3b8ff9a95af8..2a120c2d5827 100644 --- a/arch/ppc/platforms/katana.h +++ b/arch/ppc/platforms/katana.h @@ -19,18 +19,17 @@ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space. * We'll only use one PCI MEM window on each PCI bus. * - * This is the CPU physical memory map (windows must be at least 1MB and start + * This is the CPU physical memory map (windows must be at least 64 KB and start * on a boundary that is a multiple of the window size): * * 0xff800000-0xffffffff - Boot window * 0xf8400000-0xf85fffff - Internal SRAM - * 0xf8200000-0xf823ffff - CPLD - * 0xf8100000-0xf810ffff - MV64360 Registers - * 0xf8000000-0xf80fffff - PLCC socket - * 0xf0000000-0xf01fffff - Consistent memory pool - * 0xe8000000-0xefffffff - soldered flash - * 0xc0000000-0xc0ffffff - PCI I/O - * 0x80000000-0xbfffffff - PCI MEM + * 0xf8200000-0xf83fffff - CPLD + * 0xf8100000-0xf810ffff - MV64360 Registers (CONFIG_MV64X60_NEW_BASE) + * 0xf8000000-0xf80fffff - Socketed FLASH + * 0xe0000000-0xefffffff - Soldered FLASH + * 0xc0000000-0xc3ffffff - PCI I/O (second hose) + * 0x80000000-0xbfffffff - PCI MEM (second hose) */ #ifndef __PPC_PLATFORMS_KATANA_H @@ -38,33 +37,22 @@ /* CPU Physical Memory Map setup. */ #define KATANA_BOOT_WINDOW_BASE 0xff800000 +#define KATANA_BOOT_WINDOW_SIZE 0x00800000 /* 8 MB */ #define KATANA_INTERNAL_SRAM_BASE 0xf8400000 #define KATANA_CPLD_BASE 0xf8200000 -#define KATANA_BRIDGE_REG_BASE 0xf8100000 +#define KATANA_CPLD_SIZE 0x00200000 /* 2 MB */ #define KATANA_SOCKET_BASE 0xf8000000 -#define KATANA_SOLDERED_FLASH_BASE 0xe8000000 - -#define KATANA_BOOT_WINDOW_SIZE_ACTUAL 0x00800000 /* 8MB */ -#define KATANA_CPLD_SIZE_ACTUAL 0x00020000 /* 128KB */ -#define KATANA_SOCKETED_FLASH_SIZE_ACTUAL 0x00080000 /* 512KB */ -#define KATANA_SOLDERED_FLASH_SIZE_ACTUAL 0x02000000 /* 32MB */ - -#define KATANA_BOOT_WINDOW_SIZE max(MV64360_WINDOW_SIZE_MIN, \ - KATANA_BOOT_WINDOW_SIZE_ACTUAL) -#define KATANA_CPLD_SIZE max(MV64360_WINDOW_SIZE_MIN, \ - KATANA_CPLD_SIZE_ACTUAL) -#define KATANA_SOCKETED_FLASH_SIZE max(MV64360_WINDOW_SIZE_MIN, \ - KATANA_SOCKETED_FLASH_SIZE_ACTUAL) -#define KATANA_SOLDERED_FLASH_SIZE max(MV64360_WINDOW_SIZE_MIN, \ - KATANA_SOLDERED_FLASH_SIZE_ACTUAL) +#define KATANA_SOCKETED_FLASH_SIZE 0x00100000 /* 1 MB */ +#define KATANA_SOLDERED_FLASH_BASE 0xe0000000 +#define KATANA_SOLDERED_FLASH_SIZE 0x10000000 /* 256 MB */ #define KATANA_PCI1_MEM_START_PROC_ADDR 0x80000000 #define KATANA_PCI1_MEM_START_PCI_HI_ADDR 0x00000000 #define KATANA_PCI1_MEM_START_PCI_LO_ADDR 0x80000000 -#define KATANA_PCI1_MEM_SIZE 0x40000000 +#define KATANA_PCI1_MEM_SIZE 0x40000000 /* 1 GB */ #define KATANA_PCI1_IO_START_PROC_ADDR 0xc0000000 #define KATANA_PCI1_IO_START_PCI_ADDR 0x00000000 -#define KATANA_PCI1_IO_SIZE 0x01000000 +#define KATANA_PCI1_IO_SIZE 0x04000000 /* 64 MB */ /* Board-specific IRQ info */ #define KATANA_PCI_INTA_IRQ_3750 64+8 @@ -138,6 +126,8 @@ #define HSL_PLD_J4SGA_REG_OFF 0 #define HSL_PLD_J4GA_REG_OFF 1 #define HSL_PLD_J2GA_REG_OFF 2 +#define HSL_PLD_HOT_SWAP_OFF 6 +#define HSL_PLD_HOT_SWAP_LED_BIT 0x1 #define GA_MASK 0x1f #define HSL_PLD_SIZE 0x1000 #define K3750_GPP_GEO_ADDR_PINS 0xf8000000 @@ -162,7 +152,8 @@ #define KATANA_DEFAULT_BAUD 9600 #define KATANA_MPSC_CLK_SRC 8 /* TCLK */ -#define KATANA_MPSC_CLK_FREQ 133333333 /* 133.3333... MHz */ + +#define KATANA_MTD_MONITOR_SIZE (1 << 20) /* 1 MB */ #define KATANA_ETH0_PHY_ADDR 12 #define KATANA_ETH1_PHY_ADDR 11 diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h index ebfef3f13363..71d9655ae0c8 100644 --- a/include/asm-ppc/mv64x60_defs.h +++ b/include/asm-ppc/mv64x60_defs.h @@ -36,6 +36,8 @@ #define GT64260_WINDOW_SIZE_MIN 0x00100000 #define MV64360_WINDOW_SIZE_MIN 0x00010000 +#define MV64x60_TCLK_FREQ_MAX 133333333U + /* IRQ's for embedded controllers */ #define MV64x60_IRQ_DEV 1 #define MV64x60_IRQ_CPU_ERR 3 @@ -303,7 +305,7 @@ #define MV64360_SRAM_ERR_DATA_HI 0x03a0 #define MV64360_SRAM_ERR_PARITY 0x03a8 -#define MV64360_SRAM_SIZE 0x00040000 /* 256 KB of SRAM */ +#define MV64360_SRAM_SIZE 0x00200000 /* 2 MB of SRAM */ /* ***************************************************************************** -- cgit v1.2.3 From b6e281b7513a7c043109a9ee37f965e7463d52f3 Mon Sep 17 00:00:00 2001 From: Eugene Surovegin Date: Fri, 4 Mar 2005 17:29:14 -0800 Subject: [PATCH] ppc32: Lindentify PPC4xx PIC driver This patch fixes whitespace in PPC4xx PIC driver. Signed-off-by: Eugene Surovegin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/syslib/ppc4xx_pic.c | 46 +++++++++++++++++++++++++------------------- include/asm-ppc/ppc4xx_pic.h | 8 ++++---- 2 files changed, 30 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c index 4ac2de28c28c..98a9bcf6962e 100644 --- a/arch/ppc/syslib/ppc4xx_pic.c +++ b/arch/ppc/syslib/ppc4xx_pic.c @@ -29,8 +29,9 @@ /* See comment in include/arch-ppc/ppc4xx_pic.h * for more info about these two variables */ -extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS] __attribute__((weak)); -extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__((weak)); +extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS] + __attribute__ ((weak)); +extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__ ((weak)); #define IRQ_MASK_UIC0(irq) (1 << (31 - (irq))) #define IRQ_MASK_UICx(irq) (1 << (31 - ((irq) & 0x1f))) @@ -63,11 +64,11 @@ static void ppc4xx_uic##n##_end(unsigned int irq) \ { \ unsigned int status = irq_desc[irq].status; \ u32 mask = IRQ_MASK_UIC##n(irq); \ - if (status & IRQ_LEVEL){ \ + if (status & IRQ_LEVEL) { \ mtdcr(DCRN_UIC_SR(UIC##n), mask); \ ACK_UIC##n##_PARENT \ } \ - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))){ \ + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { \ ppc_cached_irq_mask[n] |= mask; \ mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \ } \ @@ -86,7 +87,9 @@ static void ppc4xx_uic##n##_end(unsigned int irq) \ #define ACK_UIC0_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC); #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC); #define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC); -UIC_HANDLERS(0); UIC_HANDLERS(1); UIC_HANDLERS(2); +UIC_HANDLERS(0); +UIC_HANDLERS(1); +UIC_HANDLERS(2); static int ppc4xx_pic_get_irq(struct pt_regs *regs) { @@ -114,7 +117,8 @@ static void __init ppc4xx_pic_impl_init(void) #elif NR_UICS == 2 #define ACK_UIC0_PARENT #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC); -UIC_HANDLERS(0); UIC_HANDLERS(1); +UIC_HANDLERS(0); +UIC_HANDLERS(1); static int ppc4xx_pic_get_irq(struct pt_regs *regs) { @@ -143,18 +147,20 @@ static int ppc4xx_pic_get_irq(struct pt_regs *regs) return uic0 ? 32 - ffs(uic0) : -1; } -static inline void ppc4xx_pic_impl_init(void){} +static inline void ppc4xx_pic_impl_init(void) +{ +} #endif static struct ppc4xx_uic_impl { struct hw_interrupt_type decl; - int base; /* Base DCR number */ + int base; /* Base DCR number */ } __uic[] = { - { .decl = DECLARE_UIC(0), .base = UIC0 }, + { .decl = DECLARE_UIC(0), .base = UIC0 }, #if NR_UICS > 1 - { .decl = DECLARE_UIC(1), .base = UIC1 }, + { .decl = DECLARE_UIC(1), .base = UIC1 }, #if NR_UICS > 2 - { .decl = DECLARE_UIC(2), .base = UIC2 }, + { .decl = DECLARE_UIC(2), .base = UIC2 }, #endif #endif }; @@ -168,9 +174,9 @@ static inline int is_level_sensitive(int irq) void __init ppc4xx_pic_init(void) { int i; - unsigned char* eirqs = ppc4xx_uic_ext_irq_cfg; + unsigned char *eirqs = ppc4xx_uic_ext_irq_cfg; - for (i = 0; i < NR_UICS; ++i){ + for (i = 0; i < NR_UICS; ++i) { int base = __uic[i].base; /* Disable everything by default */ @@ -181,23 +187,23 @@ void __init ppc4xx_pic_init(void) mtdcr(DCRN_UIC_CR(base), 0); /* Configure polarity and triggering */ - if (ppc4xx_core_uic_cfg){ - struct ppc4xx_uic_settings* p = ppc4xx_core_uic_cfg + i; + if (ppc4xx_core_uic_cfg) { + struct ppc4xx_uic_settings *p = ppc4xx_core_uic_cfg + i; u32 mask = p->ext_irq_mask; u32 pr = mfdcr(DCRN_UIC_PR(base)) & mask; u32 tr = mfdcr(DCRN_UIC_TR(base)) & mask; /* "Fixed" interrupts (on-chip devices) */ - pr |= p->polarity & ~mask; + pr |= p->polarity & ~mask; tr |= p->triggering & ~mask; /* Merge external IRQs settings if board port * provided them */ - if (eirqs && mask){ + if (eirqs && mask) { pr &= ~mask; tr &= ~mask; - while (mask){ + while (mask) { /* Extract current external IRQ mask */ u32 eirq_mask = 1 << __ilog2(mask); @@ -227,8 +233,8 @@ void __init ppc4xx_pic_init(void) ppc4xx_pic_impl_init(); /* Attach low-level handlers */ - for (i = 0; i < (NR_UICS << 5); ++i){ - irq_desc[i].handler = &__uic[i >> 5].decl; + for (i = 0; i < (NR_UICS << 5); ++i) { + irq_desc[i].handler = &__uic[i >> 5].decl; if (is_level_sensitive(i)) irq_desc[i].status |= IRQ_LEVEL; } diff --git a/include/asm-ppc/ppc4xx_pic.h b/include/asm-ppc/ppc4xx_pic.h index 5141aad30621..c16c7f81cfd8 100644 --- a/include/asm-ppc/ppc4xx_pic.h +++ b/include/asm-ppc/ppc4xx_pic.h @@ -43,11 +43,11 @@ * */ struct ppc4xx_uic_settings { - u32 polarity; - u32 triggering; - u32 ext_irq_mask; + u32 polarity; + u32 triggering; + u32 ext_irq_mask; }; extern void ppc4xx_pic_init(void); -#endif /* __PPC4XX_PIC_H__ */ +#endif /* __PPC4XX_PIC_H__ */ -- cgit v1.2.3 From 241d932692fa8cea6fa6bf861e64a4743767939b Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Fri, 4 Mar 2005 17:29:42 -0800 Subject: [PATCH] ppc32: incorrect #define in include/asm-ppc/cpm2.h This patch fixes the incorrect definition of a macro that sets the transmit parity to even on a cpm uart device. Signed-off-by: Mark A. Greer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-ppc/cpm2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h index 2957e796b68d..5eabf416bb67 100644 --- a/include/asm-ppc/cpm2.h +++ b/include/asm-ppc/cpm2.h @@ -531,7 +531,7 @@ typedef struct scc_uart { #define SCU_PSMR_RPM ((ushort)0x000c) #define SCU_PSMR_REVP ((ushort)0x0008) #define SCU_PSMR_TPM ((ushort)0x0003) -#define SCU_PSMR_TEVP ((ushort)0x0003) +#define SCU_PSMR_TEVP ((ushort)0x0002) /* CPM Transparent mode SCC. */ -- cgit v1.2.3 From fddaeff6451949cd7dce90e57ca8c14628d617bf Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 4 Mar 2005 17:29:56 -0800 Subject: [PATCH] ppc32: Bogus definition of __cmpxchg_u32() This patch fix bogus types in the definition of __cmpxchg_u32() on ppc32. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-ppc/system.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 25050b76db44..82395f30004b 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -152,9 +152,9 @@ extern inline void * xchg_ptr(void * m, void * val) #define __HAVE_ARCH_CMPXCHG 1 static __inline__ unsigned long -__cmpxchg_u32(volatile int *p, int old, int new) +__cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new) { - int prev; + unsigned int prev; __asm__ __volatile__ ("\n\ 1: lwarx %0,0,%2 \n\ -- cgit v1.2.3 From b0a09f0c37e5f04ffeb725ae2f3c4bbd0f1447f9 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 4 Mar 2005 17:30:23 -0800 Subject: [PATCH] ppc32: Move from using #define SVR_ to cur_ppc_sys_spec name for 85xx platform Removes explicit defines for SVR_85xx and use the information in the ppc_sys_specs table in platform code. Changed the ppc_sys_name strings to be a bit more generic so we have a bit more flexilibity when we display them. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/platforms/85xx/mpc85xx_ads_common.c | 15 +++------------ arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 3 ++- arch/ppc/platforms/85xx/mpc85xx_sys.c | 12 ++++++------ arch/ppc/platforms/85xx/sbc85xx.c | 15 +++------------ arch/ppc/platforms/85xx/stx_gp3.c | 16 ++++------------ include/asm-ppc/reg.h | 6 ------ 6 files changed, 18 insertions(+), 49 deletions(-) (limited to 'include') diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c index cf5bcd94d027..546d145a1811 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -128,19 +129,9 @@ mpc85xx_ads_show_cpuinfo(struct seq_file *m) pvid = mfspr(PVR); svid = mfspr(SVR); + seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name); seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - - switch (svid & 0xffff0000) { - case SVR_8540: - seq_printf(m, "Machine\t\t: mpc8540ads\n"); - break; - case SVR_8560: - seq_printf(m, "Machine\t\t: mpc8560ads\n"); - break; - default: - seq_printf(m, "Machine\t\t: unknown\n"); - break; - } + seq_printf(m, "Machine\t\t: mpc%sads\n", cur_ppc_sys_spec->ppc_sys_name); seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000); seq_printf(m, "PVR\t\t: 0x%x\n", pvid); seq_printf(m, "SVR\t\t: 0x%x\n", svid); diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 5d85ff15444a..eae9f42de0ea 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -145,8 +145,9 @@ mpc85xx_cds_show_cpuinfo(struct seq_file *m) pvid = mfspr(PVR); svid = mfspr(SVR); + seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name); seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - seq_printf(m, "Machine\t\t: CDS (%x)\n", cadmus[CM_VER]); + seq_printf(m, "Machine\t\t: CDS - MPC%s (%x)\n", cur_ppc_sys_spec->ppc_sys_name, cadmus[CM_VER]); seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000); seq_printf(m, "PVR\t\t: 0x%x\n", pvid); seq_printf(m, "SVR\t\t: 0x%x\n", svid); diff --git a/arch/ppc/platforms/85xx/mpc85xx_sys.c b/arch/ppc/platforms/85xx/mpc85xx_sys.c index 9ba0255fb061..389c509d8582 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_sys.c +++ b/arch/ppc/platforms/85xx/mpc85xx_sys.c @@ -21,7 +21,7 @@ struct ppc_sys_spec *cur_ppc_sys_spec; struct ppc_sys_spec ppc_sys_specs[] = { { - .ppc_sys_name = "MPC8540", + .ppc_sys_name = "8540", .mask = 0xFFFF0000, .value = 0x80300000, .num_devices = 10, @@ -33,7 +33,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { }, }, { - .ppc_sys_name = "MPC8560", + .ppc_sys_name = "8560", .mask = 0xFFFF0000, .value = 0x80700000, .num_devices = 19, @@ -49,7 +49,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { }, }, { - .ppc_sys_name = "MPC8541", + .ppc_sys_name = "8541", .mask = 0xFFFF0000, .value = 0x80720000, .num_devices = 13, @@ -63,7 +63,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { }, }, { - .ppc_sys_name = "MPC8541E", + .ppc_sys_name = "8541E", .mask = 0xFFFF0000, .value = 0x807A0000, .num_devices = 14, @@ -77,7 +77,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { }, }, { - .ppc_sys_name = "MPC8555", + .ppc_sys_name = "8555", .mask = 0xFFFF0000, .value = 0x80710000, .num_devices = 20, @@ -94,7 +94,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { }, }, { - .ppc_sys_name = "MPC8555E", + .ppc_sys_name = "8555E", .mask = 0xFFFF0000, .value = 0x80790000, .num_devices = 21, diff --git a/arch/ppc/platforms/85xx/sbc85xx.c b/arch/ppc/platforms/85xx/sbc85xx.c index ddcca0d27e95..b7db50d2d96d 100644 --- a/arch/ppc/platforms/85xx/sbc85xx.c +++ b/arch/ppc/platforms/85xx/sbc85xx.c @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -128,19 +129,9 @@ sbc8560_show_cpuinfo(struct seq_file *m) pvid = mfspr(PVR); svid = mfspr(SVR); + seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name); seq_printf(m, "Vendor\t\t: Wind River\n"); - - switch (svid & 0xffff0000) { - case SVR_8540: - seq_printf(m, "Machine\t\t: hhmmm, this board isn't made yet!\n"); - break; - case SVR_8560: - seq_printf(m, "Machine\t\t: SBC8560\n"); - break; - default: - seq_printf(m, "Machine\t\t: unknown\n"); - break; - } + seq_printf(m, "Machine\t\t: SBC%s\n", cur_ppc_sys_spec->ppc_sys_name); seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000); seq_printf(m, "PVR\t\t: 0x%x\n", pvid); seq_printf(m, "SVR\t\t: 0x%x\n", svid); diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c index 8b637e69bc9d..5214a1d345da 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.c +++ b/arch/ppc/platforms/85xx/stx_gp3.c @@ -34,8 +34,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -266,19 +268,9 @@ gp3_show_cpuinfo(struct seq_file *m) memsize = total_memory; + seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name); seq_printf(m, "Vendor\t\t: RPC Electronics STx \n"); - - switch (svid & 0xffff0000) { - case SVR_8540: - seq_printf(m, "Machine\t\t: GP3 - MPC8540\n"); - break; - case SVR_8560: - seq_printf(m, "Machine\t\t: GP3 - MPC8560\n"); - break; - default: - seq_printf(m, "Machine\t\t: unknown\n"); - break; - } + seq_printf(m, "Machine\t\t: GP3 - MPC%s\n", cur_ppc_sys_spec->ppc_sys_name); seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000, freq % 1000000); seq_printf(m, "PVR\t\t: 0x%x\n", pvid); diff --git a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h index 43d865b97443..df2b51cc74a0 100644 --- a/include/asm-ppc/reg.h +++ b/include/asm-ppc/reg.h @@ -488,12 +488,6 @@ #define PVR_8245 0x80811014 #define PVR_8260 PVR_8240 -/* System Version Numbers */ -#define SVR_8540 0x80300000 -#define SVR_8541E 0x807A0000 -#define SVR_8555E 0x80790000 -#define SVR_8560 0x80700000 - #if 0 /* Segment Registers */ #define SR0 0 -- cgit v1.2.3 From e70a4fa1d5cda62644a30b145f23fe4638cab2c4 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Fri, 4 Mar 2005 17:30:37 -0800 Subject: [PATCH] ppc32: mv64360_pic non-zero irq base Add support for non-zero irq base to mv64360_pic code. - Fix mv64360 pic code to handle non-zero mv64x60_irq_base - Cleanup mv64360 entries in /proc/interrupts Signed-off-by: James Chapman Signed-off-by: Mark A. Greer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/syslib/mv64360_pic.c | 29 +++++++++++++++++------------ include/asm-ppc/mv64x60_defs.h | 1 + 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/arch/ppc/syslib/mv64360_pic.c b/arch/ppc/syslib/mv64360_pic.c index 7a8d7085dd96..74d8996418e9 100644 --- a/arch/ppc/syslib/mv64360_pic.c +++ b/arch/ppc/syslib/mv64360_pic.c @@ -64,7 +64,7 @@ static irqreturn_t mv64360_pci_error_int_handler(int, void *, struct pt_regs *); /* ========================== local declarations =========================== */ struct hw_interrupt_type mv64360_pic = { - .typename = " mv64360_pic ", + .typename = " mv64360 ", .enable = mv64360_unmask_irq, .disable = mv64360_mask_irq, .ack = mv64360_mask_irq, @@ -155,9 +155,10 @@ mv64360_get_irq(struct pt_regs *regs) */ int cpu_nr = smp_processor_id(); if (cpu_nr == 1) { - if (!(mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_LO) & (1 << 28))) + if (!(mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_LO) & + (1 << MV64x60_IRQ_DOORBELL))) return -1; - return 28; + return mv64360_irq_base + MV64x60_IRQ_DOORBELL; } #endif @@ -171,7 +172,7 @@ mv64360_get_irq(struct pt_regs *regs) if (irq == -1) irq = -2; /* bogus interrupt, should never happen */ else { - if ((irq >= 24) && (irq < 28)) { + if ((irq >= 24) && (irq < MV64x60_IRQ_DOORBELL)) { irq_gpp = mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE); irq_gpp = __ilog2(irq_gpp & @@ -217,8 +218,9 @@ mv64360_unmask_irq(unsigned int irq) { #ifdef CONFIG_SMP /* second CPU gets only doorbell interrupts */ - if ((irq - mv64360_irq_base) == 28) { - mv64x60_set_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO, (1 << 28)); + if ((irq - mv64360_irq_base) == MV64x60_IRQ_DOORBELL) { + mv64x60_set_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO, + (1 << MV64x60_IRQ_DOORBELL)); return; } #endif @@ -257,8 +259,9 @@ static void mv64360_mask_irq(unsigned int irq) { #ifdef CONFIG_SMP - if ((irq - mv64360_irq_base) == 28) { - mv64x60_clr_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO, (1 << 28)); + if ((irq - mv64360_irq_base) == MV64x60_IRQ_DOORBELL) { + mv64x60_clr_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO, + (1 << MV64x60_IRQ_DOORBELL)); return; } #endif @@ -371,7 +374,7 @@ mv64360_register_hdlrs(void) /* Clear old errors and register CPU interface error intr handler */ mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0); - if ((rc = request_irq(MV64x60_IRQ_CPU_ERR, + if ((rc = request_irq(MV64x60_IRQ_CPU_ERR + mv64360_irq_base, mv64360_cpu_error_int_handler, SA_INTERRUPT, CPU_INTR_STR, 0))) printk(KERN_WARNING "Can't register cpu error handler: %d", rc); @@ -380,7 +383,7 @@ mv64360_register_hdlrs(void) /* Clear old errors and register internal SRAM error intr handler */ mv64x60_write(&bh, MV64360_SRAM_ERR_CAUSE, 0); - if ((rc = request_irq(MV64360_IRQ_SRAM_PAR_ERR, + if ((rc = request_irq(MV64360_IRQ_SRAM_PAR_ERR + mv64360_irq_base, mv64360_sram_error_int_handler,SA_INTERRUPT,SRAM_INTR_STR, 0))) printk(KERN_WARNING "Can't register SRAM error handler: %d",rc); @@ -397,7 +400,8 @@ mv64360_register_hdlrs(void) /* Clear old errors and register PCI 0 error intr handler */ mv64x60_write(&bh, MV64x60_PCI0_ERR_CAUSE, 0); - if ((rc = request_irq(MV64360_IRQ_PCI0, mv64360_pci_error_int_handler, + if ((rc = request_irq(MV64360_IRQ_PCI0 + mv64360_irq_base, + mv64360_pci_error_int_handler, SA_INTERRUPT, PCI0_INTR_STR, (void *)0))) printk(KERN_WARNING "Can't register pci 0 error handler: %d", rc); @@ -407,7 +411,8 @@ mv64360_register_hdlrs(void) /* Clear old errors and register PCI 1 error intr handler */ mv64x60_write(&bh, MV64x60_PCI1_ERR_CAUSE, 0); - if ((rc = request_irq(MV64360_IRQ_PCI1, mv64360_pci_error_int_handler, + if ((rc = request_irq(MV64360_IRQ_PCI1 + mv64360_irq_base, + mv64360_pci_error_int_handler, SA_INTERRUPT, PCI1_INTR_STR, (void *)1))) printk(KERN_WARNING "Can't register pci 1 error handler: %d", rc); diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h index 71d9655ae0c8..9f0a63e55a8d 100644 --- a/include/asm-ppc/mv64x60_defs.h +++ b/include/asm-ppc/mv64x60_defs.h @@ -45,6 +45,7 @@ #define MV64x60_IRQ_TIMER_2_3 9 #define MV64x60_IRQ_TIMER_4_5 10 #define MV64x60_IRQ_TIMER_6_7 11 +#define MV64x60_IRQ_DOORBELL 28 #define MV64x60_IRQ_ETH_0 32 #define MV64x60_IRQ_ETH_1 33 #define MV64x60_IRQ_ETH_2 34 -- cgit v1.2.3 From 6bda0d53c19e918755b420bdc21c0c04cbe9af31 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Fri, 4 Mar 2005 17:30:51 -0800 Subject: [PATCH] ppc32: Add GPIO/IRQ definitions for mv64x60 parts Add mv64x60 GPP IO pin/IRQ register definitions Signed-off-by: James Chapman Signed-off-by: Mark A. Greer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-ppc/mv64x60_defs.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'include') diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h index 9f0a63e55a8d..16b184a72a83 100644 --- a/include/asm-ppc/mv64x60_defs.h +++ b/include/asm-ppc/mv64x60_defs.h @@ -45,6 +45,10 @@ #define MV64x60_IRQ_TIMER_2_3 9 #define MV64x60_IRQ_TIMER_4_5 10 #define MV64x60_IRQ_TIMER_6_7 11 +#define MV64x60_IRQ_P1_GPP_0_7 24 +#define MV64x60_IRQ_P1_GPP_8_15 25 +#define MV64x60_IRQ_P1_GPP_16_23 26 +#define MV64x60_IRQ_P1_GPP_24_31 27 #define MV64x60_IRQ_DOORBELL 28 #define MV64x60_IRQ_ETH_0 32 #define MV64x60_IRQ_ETH_1 33 @@ -55,12 +59,49 @@ #define MV64x60_IRQ_MPSC_0 40 #define MV64x60_IRQ_MPSC_1 42 #define MV64x60_IRQ_COMM 43 +#define MV64x60_IRQ_P0_GPP_0_7 56 +#define MV64x60_IRQ_P0_GPP_8_15 57 +#define MV64x60_IRQ_P0_GPP_16_23 58 +#define MV64x60_IRQ_P0_GPP_24_31 59 #define MV64360_IRQ_PCI0 12 #define MV64360_IRQ_SRAM_PAR_ERR 13 #define MV64360_IRQ_PCI1 16 #define MV64360_IRQ_SDMA_1 38 +#define MV64x60_IRQ_GPP0 64 +#define MV64x60_IRQ_GPP1 65 +#define MV64x60_IRQ_GPP2 66 +#define MV64x60_IRQ_GPP3 67 +#define MV64x60_IRQ_GPP4 68 +#define MV64x60_IRQ_GPP5 69 +#define MV64x60_IRQ_GPP6 70 +#define MV64x60_IRQ_GPP7 71 +#define MV64x60_IRQ_GPP8 72 +#define MV64x60_IRQ_GPP9 73 +#define MV64x60_IRQ_GPP10 74 +#define MV64x60_IRQ_GPP11 75 +#define MV64x60_IRQ_GPP12 76 +#define MV64x60_IRQ_GPP13 77 +#define MV64x60_IRQ_GPP14 78 +#define MV64x60_IRQ_GPP15 79 +#define MV64x60_IRQ_GPP16 80 +#define MV64x60_IRQ_GPP17 81 +#define MV64x60_IRQ_GPP18 82 +#define MV64x60_IRQ_GPP19 83 +#define MV64x60_IRQ_GPP20 84 +#define MV64x60_IRQ_GPP21 85 +#define MV64x60_IRQ_GPP22 86 +#define MV64x60_IRQ_GPP23 87 +#define MV64x60_IRQ_GPP24 88 +#define MV64x60_IRQ_GPP25 89 +#define MV64x60_IRQ_GPP26 90 +#define MV64x60_IRQ_GPP27 91 +#define MV64x60_IRQ_GPP28 92 +#define MV64x60_IRQ_GPP29 93 +#define MV64x60_IRQ_GPP30 94 +#define MV64x60_IRQ_GPP31 95 + /* Offsets for register blocks */ #define GT64260_ENET_PHY_ADDR 0x2000 #define GT64260_ENET_ESMIR 0x2010 -- cgit v1.2.3 From 5dbab45d23a0d0184b6cbfac8adfddebb0ca60da Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 4 Mar 2005 17:31:20 -0800 Subject: [PATCH] ppc32: Add support for the Dallas 1553 RTC/NVRAM This patch adds support for the Dallas 1553 RTC/NVRAM. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/syslib/todc_time.c | 4 ++++ include/asm-ppc/todc.h | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) (limited to 'include') diff --git a/arch/ppc/syslib/todc_time.c b/arch/ppc/syslib/todc_time.c index 0165e1834114..1323c641c19d 100644 --- a/arch/ppc/syslib/todc_time.c +++ b/arch/ppc/syslib/todc_time.c @@ -287,6 +287,7 @@ todc_get_rtc_time(void) limit = 1; switch (todc_info->rtc_type) { + case TODC_TYPE_DS1553: case TODC_TYPE_DS1557: case TODC_TYPE_DS1743: case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ @@ -322,6 +323,7 @@ todc_get_rtc_time(void) if (todc_info->rtc_type != TODC_TYPE_MC146818) { switch (todc_info->rtc_type) { + case TODC_TYPE_DS1553: case TODC_TYPE_DS1557: case TODC_TYPE_DS1743: case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ @@ -418,6 +420,7 @@ static unsigned char __init todc_read_timereg(int addr) unsigned char save_control = 0, val; switch (todc_info->rtc_type) { + case TODC_TYPE_DS1553: case TODC_TYPE_DS1557: case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ case TODC_TYPE_DS1747: @@ -432,6 +435,7 @@ static unsigned char __init todc_read_timereg(int addr) val = todc_read_val(addr); switch (todc_info->rtc_type) { + case TODC_TYPE_DS1553: case TODC_TYPE_DS1557: case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ case TODC_TYPE_DS1747: diff --git a/include/asm-ppc/todc.h b/include/asm-ppc/todc.h index 30abf319b425..84bae7d76814 100644 --- a/include/asm-ppc/todc.h +++ b/include/asm-ppc/todc.h @@ -98,6 +98,7 @@ typedef struct { #define TODC_TYPE_PC97307 10 /* PC97307 internal RTC */ #define TODC_TYPE_DS1557 11 /* Dallas DS1557 RTC */ #define TODC_TYPE_DS17285 12 /* Dallas DS17285 RTC */ +#define TODC_TYPE_DS1553 13 /* Dallas DS1553 RTC */ #define TODC_TYPE_MC146818 100 /* Leave room for m48txx's */ /* @@ -208,6 +209,28 @@ typedef struct { #define TODC_TYPE_DS1501_NVRAM_ADDR_REG 0x10 #define TODC_TYPE_DS1501_NVRAM_DATA_REG 0x13 +#define TODC_TYPE_DS1553_NVRAM_SIZE 0x1ff0 +#define TODC_TYPE_DS1553_SW_FLAGS 0 +#define TODC_TYPE_DS1553_YEAR 0x1fff +#define TODC_TYPE_DS1553_MONTH 0x1ffe +#define TODC_TYPE_DS1553_DOM 0x1ffd /* Day of Month */ +#define TODC_TYPE_DS1553_DOW 0x1ffc /* Day of Week */ +#define TODC_TYPE_DS1553_HOURS 0x1ffb +#define TODC_TYPE_DS1553_MINUTES 0x1ffa +#define TODC_TYPE_DS1553_SECONDS 0x1ff9 +#define TODC_TYPE_DS1553_CNTL_B 0x1ff9 +#define TODC_TYPE_DS1553_CNTL_A 0x1ff8 /* control_a R/W regs */ +#define TODC_TYPE_DS1553_WATCHDOG 0x1ff7 +#define TODC_TYPE_DS1553_INTERRUPTS 0x1ff6 +#define TODC_TYPE_DS1553_ALARM_DATE 0x1ff5 +#define TODC_TYPE_DS1553_ALARM_HOUR 0x1ff4 +#define TODC_TYPE_DS1553_ALARM_MINUTES 0x1ff3 +#define TODC_TYPE_DS1553_ALARM_SECONDS 0x1ff2 +#define TODC_TYPE_DS1553_CENTURY 0x1ff8 +#define TODC_TYPE_DS1553_FLAGS 0x1ff0 +#define TODC_TYPE_DS1553_NVRAM_ADDR_REG 0 +#define TODC_TYPE_DS1553_NVRAM_DATA_REG 0 + #define TODC_TYPE_DS1557_NVRAM_SIZE 0x7fff0 #define TODC_TYPE_DS1557_SW_FLAGS 0 #define TODC_TYPE_DS1557_YEAR 0x7ffff -- cgit v1.2.3 From f57efe0f1dcb3998153b7fad27add388ca678733 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 4 Mar 2005 17:32:03 -0800 Subject: [PATCH] ppc32: PowerQUICC II Pro subarch support Patch adds support for the initial PowerQUICC II Pro processors (MPC8343/E, MPC8347/E, and MPC8349/E) and the first reference platform (MPC834x SYS) from Freescale. The initial support is limited to existing drivers that overlap with the MPC85xx subarch (ethernet, I2C, uart). Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- CREDITS | 2 +- MAINTAINERS | 2 +- arch/ppc/Kconfig | 19 +- arch/ppc/Makefile | 1 + arch/ppc/configs/mpc834x_sys_defconfig | 644 +++++++++++++++++++++++++++++ arch/ppc/kernel/cputable.c | 12 + arch/ppc/kernel/ppc_ksyms.c | 3 +- arch/ppc/kernel/setup.c | 4 + arch/ppc/platforms/83xx/Kconfig | 30 ++ arch/ppc/platforms/83xx/Makefile | 6 + arch/ppc/platforms/83xx/mpc834x_sys.c | 290 ++++++++++++++ arch/ppc/platforms/83xx/mpc834x_sys.h | 51 +++ arch/ppc/platforms/83xx/mpc83xx_devices.c | 237 +++++++++++ arch/ppc/platforms/83xx/mpc83xx_sys.c | 100 +++++ arch/ppc/syslib/Makefile | 4 + arch/ppc/syslib/ipic.c | 646 ++++++++++++++++++++++++++++++ arch/ppc/syslib/ipic.h | 49 +++ arch/ppc/syslib/ppc83xx_setup.c | 138 +++++++ arch/ppc/syslib/ppc83xx_setup.h | 53 +++ drivers/net/Kconfig | 2 +- include/asm-ppc/io.h | 2 + include/asm-ppc/ipic.h | 85 ++++ include/asm-ppc/irq.h | 10 + include/asm-ppc/mpc83xx.h | 114 ++++++ include/asm-ppc/ppc_sys.h | 4 +- include/asm-ppc/ppcboot.h | 6 +- include/asm-ppc/serial.h | 2 + 27 files changed, 2500 insertions(+), 16 deletions(-) create mode 100644 arch/ppc/configs/mpc834x_sys_defconfig create mode 100644 arch/ppc/platforms/83xx/Kconfig create mode 100644 arch/ppc/platforms/83xx/Makefile create mode 100644 arch/ppc/platforms/83xx/mpc834x_sys.c create mode 100644 arch/ppc/platforms/83xx/mpc834x_sys.h create mode 100644 arch/ppc/platforms/83xx/mpc83xx_devices.c create mode 100644 arch/ppc/platforms/83xx/mpc83xx_sys.c create mode 100644 arch/ppc/syslib/ipic.c create mode 100644 arch/ppc/syslib/ipic.h create mode 100644 arch/ppc/syslib/ppc83xx_setup.c create mode 100644 arch/ppc/syslib/ppc83xx_setup.h create mode 100644 include/asm-ppc/ipic.h create mode 100644 include/asm-ppc/mpc83xx.h (limited to 'include') diff --git a/CREDITS b/CREDITS index 71aa0d4d6cd3..db9e7380c19f 100644 --- a/CREDITS +++ b/CREDITS @@ -1095,7 +1095,7 @@ S: Brazil N: Kumar Gala E: kumar.gala@freescale.com -D: Embedded PowerPC 6xx/7xx/74xx/82xx/85xx support +D: Embedded PowerPC 6xx/7xx/74xx/82xx/83xx/85xx support S: Austin, Texas 78729 S: USA diff --git a/MAINTAINERS b/MAINTAINERS index 90e31fed53dd..838079cd8cf0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1372,7 +1372,7 @@ W: http://www.penguinppc.org/ L: linuxppc-embedded@ozlabs.org S: Maintained -LINUX FOR POWERPC EMBEDDED PPC85XX +LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX P: Kumar Gala M: kumar.gala@freescale.com W: http://www.penguinppc.org/ diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 6fd6d12d7ceb..cc76420f3f9e 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -52,17 +52,17 @@ choice default 6xx config 6xx - bool "6xx/7xx/74xx/52xx/8260" + bool "6xx/7xx/74xx/52xx/82xx/83xx" help There are four types of PowerPC chips supported. The more common types (601, 603, 604, 740, 750, 7400), the Motorola embedded - versions (821, 823, 850, 855, 860, 52xx, 8260), the IBM embedded + versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the IBM embedded versions (403 and 405) and the high end 64 bit Power processors (POWER 3, POWER4, and IBM 970 also known as G5) Unless you are building a kernel for one of the embedded processor systems, 64 bit IBM RS/6000 or an Apple G5, choose 6xx. Note that the kernel runs in 32-bit mode even on 64-bit chips. - Also note that because the 52xx & 82xx family has a 603e core, + Also note that because the 52xx, 82xx, & 83xx family has a 603e core, specific support for that chipset is asked later on. config 40x @@ -109,7 +109,7 @@ config PHYS_64BIT config ALTIVEC bool "AltiVec Support" depends on 6xx || POWER4 - depends on !8260 + depends on !8260 && !83xx ---help--- This option enables kernel support for the Altivec extensions to the PowerPC processor. The kernel currently supports saving and restoring @@ -140,7 +140,7 @@ config SPE config TAU bool "Thermal Management Support" - depends on 6xx && !8260 + depends on 6xx && !8260 && !83xx help G3 and G4 processors have an on-chip temperature sensor called the 'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die @@ -228,6 +228,7 @@ config PPC601_SYNC_FIX If in doubt, say Y here. source arch/ppc/platforms/4xx/Kconfig +source arch/ppc/platforms/83xx/Kconfig source arch/ppc/platforms/85xx/Kconfig config PPC64BRIDGE @@ -475,7 +476,7 @@ endchoice choice prompt "Machine Type" - depends on 6xx || POWER3 || POWER4 + depends on (6xx && !83xx) || POWER3 || POWER4 default PPC_MULTIPLATFORM ---help--- Linux currently supports several different kinds of PowerPC-based @@ -660,7 +661,7 @@ config PPC_MPC52xx config 8260 bool "CPM2 Support" if WILLOW - depends on 6xx + depends on 6xx && !83xx default y if TQM8260 || RPX8260 || EST8260 || SBS8260 || SBC82xx || PQ2FADS help The MPC8260 is a typical embedded CPU made by Motorola. Selecting @@ -1079,8 +1080,8 @@ config MCA bool config PCI - bool "PCI support" if 40x || CPM2 || 85xx - default y if !40x && !CPM2 && !8xx && !APUS && !85xx + bool "PCI support" if 40x || CPM2 || 83xx || 85xx + default y if !40x && !CPM2 && !8xx && !APUS && !83xx && !85xx default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS default PCI_QSPAN if !4xx && !CPM2 && 8xx help diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 144c21219c97..80497b907833 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -57,6 +57,7 @@ head-$(CONFIG_POWER4) += arch/ppc/kernel/idle_power4.o core-y += arch/ppc/kernel/ arch/ppc/platforms/ \ arch/ppc/mm/ arch/ppc/lib/ arch/ppc/syslib/ core-$(CONFIG_4xx) += arch/ppc/platforms/4xx/ +core-$(CONFIG_83xx) += arch/ppc/platforms/83xx/ core-$(CONFIG_85xx) += arch/ppc/platforms/85xx/ core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ core-$(CONFIG_XMON) += arch/ppc/xmon/ diff --git a/arch/ppc/configs/mpc834x_sys_defconfig b/arch/ppc/configs/mpc834x_sys_defconfig new file mode 100644 index 000000000000..4a5522ca8207 --- /dev/null +++ b/arch/ppc/configs/mpc834x_sys_defconfig @@ -0,0 +1,644 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11-rc4 +# Thu Feb 17 16:12:23 2005 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Processor +# +CONFIG_6xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_E500 is not set +# CONFIG_CPU_FREQ is not set +CONFIG_PPC_GEN550=y +CONFIG_83xx=y + +# +# Freescale 83xx options +# +CONFIG_MPC834x_SYS=y +CONFIG_MPC834x=y +CONFIG_PPC_STD_MMU=y + +# +# Platform options +# +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_HIGHMEM is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_CMDLINE_BOOL is not set + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PC-card bridges +# + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_LBD is not set +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Macintosh device drivers +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y + +# +# Ethernet (1000 Mbit) +# +CONFIG_GIANFAR=y +# CONFIG_GFAR_NAPI is not set + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ISA is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c index c86b4b224306..8aa5e8c69009 100644 --- a/arch/ppc/kernel/cputable.c +++ b/arch/ppc/kernel/cputable.c @@ -560,6 +560,18 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .cpu_setup = __setup_cpu_603 }, + { /* e300 (a 603e core, plus some) on 83xx */ + .pvr_mask = 0x7fff0000, + .pvr_value = 0x00830000, + .cpu_name = "e300", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, + .cpu_user_features = COMMON_PPC, + .icache_bsize = 32, + .dcache_bsize = 32, + .cpu_setup = __setup_cpu_603 + }, { /* default match, we assume split I/D cache & TB (non-601)... */ .pvr_mask = 0x00000000, .pvr_value = 0x00000000, diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 1ee8c12bac75..2ccb58fe4fc3 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -319,7 +319,8 @@ EXPORT_SYMBOL(debugger_fault_handler); EXPORT_SYMBOL(cpm_install_handler); EXPORT_SYMBOL(cpm_free_handler); #endif /* CONFIG_8xx */ -#if defined(CONFIG_8xx) || defined(CONFIG_40x) || defined(CONFIG_85xx) +#if defined(CONFIG_8xx) || defined(CONFIG_40x) || defined(CONFIG_85xx) ||\ + defined(CONFIG_83xx) EXPORT_SYMBOL(__res); #endif diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index fdcef4d23b9b..062836ed4751 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -227,6 +227,10 @@ int show_cpuinfo(struct seq_file *m, void *v) maj = ((pvr >> 8) & 0xFF) - 1; min = pvr & 0xFF; break; + case 0x8083: /* e300 */ + maj = PVR_MAJ(pvr); + min = PVR_MIN(pvr); + break; case 0x8020: /* e500 */ maj = PVR_MAJ(pvr); min = PVR_MIN(pvr); diff --git a/arch/ppc/platforms/83xx/Kconfig b/arch/ppc/platforms/83xx/Kconfig new file mode 100644 index 000000000000..4e08562aa863 --- /dev/null +++ b/arch/ppc/platforms/83xx/Kconfig @@ -0,0 +1,30 @@ +config 83xx + bool "PowerQUICC II Pro (83xx) Support" + depends on 6xx + +menu "Freescale 83xx options" + depends on 83xx + +choice + prompt "Machine Type" + depends on 83xx + default MPC834x_SYS + +config MPC834x_SYS + bool "Freescale MPC834x SYS" + help + This option enables support for the MPC 834x SYS evaluation board. + +endchoice + +config MPC834x + bool + depends on MPC834x_SYS + default y + +config PPC_GEN550 + bool + depends on 83xx + default y + +endmenu diff --git a/arch/ppc/platforms/83xx/Makefile b/arch/ppc/platforms/83xx/Makefile new file mode 100644 index 000000000000..ef702e0ea3c6 --- /dev/null +++ b/arch/ppc/platforms/83xx/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the PowerPC 83xx linux kernel. +# +obj-$(CONFIG_83xx) += mpc83xx_sys.o mpc83xx_devices.o + +obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c new file mode 100644 index 000000000000..02a426edd9e6 --- /dev/null +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c @@ -0,0 +1,290 @@ +/* + * arch/ppc/platforms/83xx/mpc834x_sys.c + * + * MPC834x SYS board specific routines + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for linux/serial_core.h */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +extern unsigned long total_memory; /* in mm/init */ + +unsigned char __res[sizeof (bd_t)]; + +#ifdef CONFIG_PCI +#error "PCI is not supported" +/* NEED mpc83xx_map_irq & mpc83xx_exclude_device + see platforms/85xx/mpc85xx_ads_common.c */ +#endif /* CONFIG_PCI */ + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init +mpc834x_sys_setup_arch(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + struct gianfar_platform_data *pdata; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = freq / HZ; + +#ifdef CONFIG_PCI + /* setup PCI host bridges */ + mpc83xx_sys_setup_hose(); +#endif + mpc83xx_early_serial_map(); + + /* setup the board related information for the enet controllers */ + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC83xx_IRQ_EXT1; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC83xx_IRQ_EXT2; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +static void __init +mpc834x_sys_map_io(void) +{ + /* we steal the lowest ioremap addr for virt space */ + io_block_mapping(VIRT_IMMRBAR, immrbar, 1024*1024, _PAGE_IO); + io_block_mapping(BCSR_VIRT_ADDR, BCSR_PHYS_ADDR, BCSR_SIZE, _PAGE_IO); +} + +int +mpc834x_sys_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + pvid = mfspr(PVR); + svid = mfspr(SVR); + + seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name); + seq_printf(m, "Vendor\t\t: Freescale Inc.\n"); + seq_printf(m, "Machine\t\t: mpc%s sys\n", cur_ppc_sys_spec->ppc_sys_name); + seq_printf(m, "core clock\t: %d MHz\n" + "bus clock\t: %d MHz\n", + (int)(binfo->bi_intfreq / 1000000), + (int)(binfo->bi_busfreq / 1000000)); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", (int)(binfo->bi_memsize / (1024 * 1024))); + + return 0; +} + + +void __init +mpc834x_sys_init_IRQ(void) +{ + bd_t *binfo = (bd_t *) __res; + + u8 senses[8] = { + 0, /* EXT 0 */ + IRQ_SENSE_LEVEL, /* EXT 1 */ + IRQ_SENSE_LEVEL, /* EXT 2 */ + 0, /* EXT 3 */ + 0, /* EXT 4 */ + 0, /* EXT 5 */ + 0, /* EXT 6 */ + 0, /* EXT 7 */ + }; + + ipic_init(binfo->bi_immr_base + 0x00700, 0, MPC83xx_IPIC_IRQ_OFFSET, senses, 8); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +static __inline__ void +mpc834x_sys_set_bat(void) +{ + /* we steal the lowest ioremap addr for virt space */ + mb(); + mtspr(DBAT1U, VIRT_IMMRBAR | 0x1e); + mtspr(DBAT1L, immrbar | 0x2a); + mb(); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + bd_t *binfo = (bd_t *) __res; + + /* parse_bootinfo must always be called first */ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + } + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + immrbar = binfo->bi_immr_base; + + mpc834x_sys_set_bat(); + +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) + { + struct uart_port p; + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (unsigned char __iomem *)immrbar + 0x4500; + p.uartclk = binfo->bi_busfreq; + + gen550_init(0, &p); + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (unsigned char __iomem *)immrbar + 0x4500; + p.uartclk = binfo->bi_busfreq; + + gen550_init(1, &p); + } +#endif + + identify_ppc_sys_by_id(mfspr(SVR)); + + /* setup the PowerPC module struct */ + ppc_md.setup_arch = mpc834x_sys_setup_arch; + ppc_md.show_cpuinfo = mpc834x_sys_show_cpuinfo; + + ppc_md.init_IRQ = mpc834x_sys_init_IRQ; + ppc_md.get_irq = ipic_get_irq; + + ppc_md.restart = mpc83xx_restart; + ppc_md.power_off = mpc83xx_power_off; + ppc_md.halt = mpc83xx_halt; + + ppc_md.find_end_of_memory = mpc83xx_find_end_of_memory; + ppc_md.setup_io_mappings = mpc834x_sys_map_io; + + ppc_md.time_init = mpc83xx_time_init; + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.calibrate_decr = mpc83xx_calibrate_decr; + + ppc_md.early_serial_map = mpc83xx_early_serial_map; +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ + + if (ppc_md.progress) + ppc_md.progress("mpc834x_sys_init(): exit", 0); + + return; +} diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h new file mode 100644 index 000000000000..f4d055ae19c1 --- /dev/null +++ b/arch/ppc/platforms/83xx/mpc834x_sys.h @@ -0,0 +1,51 @@ +/* + * arch/ppc/platforms/83xx/mpc834x_sys.h + * + * MPC834X SYS common board definitions + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC83XX_SYS_H__ +#define __MACH_MPC83XX_SYS_H__ + +#include +#include +#include +#include +#include + +#define VIRT_IMMRBAR ((uint)0xfe000000) + +#define BCSR_PHYS_ADDR ((uint)0xf8000000) +#define BCSR_VIRT_ADDR ((uint)0xfe100000) +#define BCSR_SIZE ((uint)(32 * 1024)) + +#ifdef CONFIG_PCI +/* PCI interrupt controller */ +#define PIRQA MPC83xx_IRQ_IRQ4 +#define PIRQB MPC83xx_IRQ_IRQ5 +#define PIRQC MPC83xx_IRQ_IRQ6 +#define PIRQD MPC83xx_IRQ_IRQ7 + +#define MPC834x_SYS_PCI1_LOWER_IO 0x00000000 +#define MPC834x_SYS_PCI1_UPPER_IO 0x00ffffff + +#define MPC834x_SYS_PCI1_LOWER_MEM 0x80000000 +#define MPC834x_SYS_PCI1_UPPER_MEM 0x9fffffff + +#define MPC834x_SYS_PCI1_IO_BASE 0xe2000000 +#define MPC834x_SYS_PCI1_MEM_OFFSET 0x00000000 + +#define MPC834x_SYS_PCI1_IO_SIZE 0x01000000 +#endif /* CONFIG_PCI */ + +#endif /* __MACH_MPC83XX_SYS_H__ */ diff --git a/arch/ppc/platforms/83xx/mpc83xx_devices.c b/arch/ppc/platforms/83xx/mpc83xx_devices.c new file mode 100644 index 000000000000..5c1a919eaabf --- /dev/null +++ b/arch/ppc/platforms/83xx/mpc83xx_devices.c @@ -0,0 +1,237 @@ +/* + * arch/ppc/platforms/83xx/mpc83xx_devices.c + * + * MPC83xx Device descriptions + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* We use offsets for IORESOURCE_MEM since we do not know at compile time + * what IMMRBAR is, will get fixed up by mach_mpc83xx_fixup + */ + +static struct gianfar_platform_data mpc83xx_tsec1_pdata = { + .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR, + .phy_reg_addr = 0x24000, +}; + +static struct gianfar_platform_data mpc83xx_tsec2_pdata = { + .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR, + .phy_reg_addr = 0x24000, +}; + +static struct fsl_i2c_platform_data mpc83xx_fsl_i2c1_pdata = { + .device_flags = FSL_I2C_DEV_SEPARATE_DFSRR, +}; + +static struct fsl_i2c_platform_data mpc83xx_fsl_i2c2_pdata = { + .device_flags = FSL_I2C_DEV_SEPARATE_DFSRR, +}; + +static struct plat_serial8250_port serial_platform_data[] = { + [0] = { + .mapbase = 0x4500, + .irq = MPC83xx_IRQ_UART1, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + }, + [1] = { + .mapbase = 0x4600, + .irq = MPC83xx_IRQ_UART2, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + }, +}; + +struct platform_device ppc_sys_platform_devices[] = { + [MPC83xx_TSEC1] = { + .name = "fsl-gianfar", + .id = 1, + .dev.platform_data = &mpc83xx_tsec1_pdata, + .num_resources = 4, + .resource = (struct resource[]) { + { + .start = 0x24000, + .end = 0x24fff, + .flags = IORESOURCE_MEM, + }, + { + .name = "tx", + .start = MPC83xx_IRQ_TSEC1_TX, + .end = MPC83xx_IRQ_TSEC1_TX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "rx", + .start = MPC83xx_IRQ_TSEC1_RX, + .end = MPC83xx_IRQ_TSEC1_RX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "error", + .start = MPC83xx_IRQ_TSEC1_ERROR, + .end = MPC83xx_IRQ_TSEC1_ERROR, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC83xx_TSEC2] = { + .name = "fsl-gianfar", + .id = 2, + .dev.platform_data = &mpc83xx_tsec2_pdata, + .num_resources = 4, + .resource = (struct resource[]) { + { + .start = 0x25000, + .end = 0x25fff, + .flags = IORESOURCE_MEM, + }, + { + .name = "tx", + .start = MPC83xx_IRQ_TSEC2_TX, + .end = MPC83xx_IRQ_TSEC2_TX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "rx", + .start = MPC83xx_IRQ_TSEC2_RX, + .end = MPC83xx_IRQ_TSEC2_RX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "error", + .start = MPC83xx_IRQ_TSEC2_ERROR, + .end = MPC83xx_IRQ_TSEC2_ERROR, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC83xx_IIC1] = { + .name = "fsl-i2c", + .id = 1, + .dev.platform_data = &mpc83xx_fsl_i2c1_pdata, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = 0x3000, + .end = 0x30ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MPC83xx_IRQ_IIC1, + .end = MPC83xx_IRQ_IIC1, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC83xx_IIC2] = { + .name = "fsl-i2c", + .id = 2, + .dev.platform_data = &mpc83xx_fsl_i2c2_pdata, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = 0x3100, + .end = 0x31ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MPC83xx_IRQ_IIC2, + .end = MPC83xx_IRQ_IIC2, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC83xx_DUART] = { + .name = "serial8250", + .id = 0, + .dev.platform_data = serial_platform_data, + }, + [MPC83xx_SEC2] = { + .name = "fsl-sec2", + .id = 1, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = 0x30000, + .end = 0x3ffff, + .flags = IORESOURCE_MEM, + }, + { + .start = MPC83xx_IRQ_SEC2, + .end = MPC83xx_IRQ_SEC2, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC83xx_USB2_DR] = { + .name = "fsl-usb2-dr", + .id = 1, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = 0x22000, + .end = 0x22fff, + .flags = IORESOURCE_MEM, + }, + { + .start = MPC83xx_IRQ_USB2_DR, + .end = MPC83xx_IRQ_USB2_DR, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC83xx_USB2_MPH] = { + .name = "fsl-usb2-mph", + .id = 1, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = 0x23000, + .end = 0x23fff, + .flags = IORESOURCE_MEM, + }, + { + .start = MPC83xx_IRQ_USB2_MPH, + .end = MPC83xx_IRQ_USB2_MPH, + .flags = IORESOURCE_IRQ, + }, + }, + }, +}; + +static int __init mach_mpc83xx_fixup(struct platform_device *pdev) +{ + ppc_sys_fixup_mem_resource(pdev, immrbar); + return 0; +} + +static int __init mach_mpc83xx_init(void) +{ + if (ppc_md.progress) + ppc_md.progress("mach_mpc83xx_init:enter", 0); + ppc_sys_device_fixup = mach_mpc83xx_fixup; + return 0; +} + +postcore_initcall(mach_mpc83xx_init); diff --git a/arch/ppc/platforms/83xx/mpc83xx_sys.c b/arch/ppc/platforms/83xx/mpc83xx_sys.c new file mode 100644 index 000000000000..29aa63350025 --- /dev/null +++ b/arch/ppc/platforms/83xx/mpc83xx_sys.c @@ -0,0 +1,100 @@ +/* + * arch/ppc/platforms/83xx/mpc83xx_sys.c + * + * MPC83xx System descriptions + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +struct ppc_sys_spec *cur_ppc_sys_spec; +struct ppc_sys_spec ppc_sys_specs[] = { + { + .ppc_sys_name = "8349E", + .mask = 0xFFFF0000, + .value = 0x80500000, + .num_devices = 8, + .device_list = (enum ppc_sys_devices[]) + { + MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1, + MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2, + MPC83xx_USB2_DR, MPC83xx_USB2_MPH + }, + }, + { + .ppc_sys_name = "8349", + .mask = 0xFFFF0000, + .value = 0x80510000, + .num_devices = 7, + .device_list = (enum ppc_sys_devices[]) + { + MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1, + MPC83xx_IIC2, MPC83xx_DUART, + MPC83xx_USB2_DR, MPC83xx_USB2_MPH + }, + }, + { + .ppc_sys_name = "8347E", + .mask = 0xFFFF0000, + .value = 0x80520000, + .num_devices = 8, + .device_list = (enum ppc_sys_devices[]) + { + MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1, + MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2, + MPC83xx_USB2_DR, MPC83xx_USB2_MPH + }, + }, + { + .ppc_sys_name = "8347", + .mask = 0xFFFF0000, + .value = 0x80530000, + .num_devices = 7, + .device_list = (enum ppc_sys_devices[]) + { + MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1, + MPC83xx_IIC2, MPC83xx_DUART, + MPC83xx_USB2_DR, MPC83xx_USB2_MPH + }, + }, + { + .ppc_sys_name = "8343E", + .mask = 0xFFFF0000, + .value = 0x80540000, + .num_devices = 7, + .device_list = (enum ppc_sys_devices[]) + { + MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1, + MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2, + MPC83xx_USB2_DR, + }, + }, + { + .ppc_sys_name = "8343", + .mask = 0xFFFF0000, + .value = 0x80550000, + .num_devices = 6, + .device_list = (enum ppc_sys_devices[]) + { + MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1, + MPC83xx_IIC2, MPC83xx_DUART, + MPC83xx_USB2_DR, + }, + }, + { /* default match */ + .ppc_sys_name = "", + .mask = 0x00000000, + .value = 0x00000000, + }, +}; diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index e030bb97ce39..a85c0a97b3ae 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -99,5 +99,9 @@ obj-$(CONFIG_85xx) += open_pic.o ppc85xx_common.o ppc85xx_setup.o \ ifeq ($(CONFIG_85xx),y) obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o endif +obj-$(CONFIG_83xx) += ipic.o ppc83xx_setup.o ppc_sys.o +ifeq ($(CONFIG_83xx),y) +obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o +endif obj-$(CONFIG_MPC8555_CDS) += todc_time.o obj-$(CONFIG_PPC_MPC52xx) += mpc52xx_setup.o mpc52xx_pic.o diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c new file mode 100644 index 000000000000..acb2cde3171f --- /dev/null +++ b/arch/ppc/syslib/ipic.c @@ -0,0 +1,646 @@ +/* + * include/asm-ppc/ipic.c + * + * IPIC routines implementations. + * + * Copyright 2005 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ipic.h" + +static struct ipic p_ipic; +static struct ipic * primary_ipic; + +static struct ipic_info ipic_info[] = { + [9] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 24, + .prio_mask = 0, + }, + [10] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 25, + .prio_mask = 1, + }, + [11] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 26, + .prio_mask = 2, + }, + [14] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 29, + .prio_mask = 5, + }, + [15] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 30, + .prio_mask = 6, + }, + [16] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 31, + .prio_mask = 7, + }, + [17] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_A, + .force = IPIC_SEFCR, + .bit = 1, + .prio_mask = 5, + }, + [18] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_A, + .force = IPIC_SEFCR, + .bit = 2, + .prio_mask = 6, + }, + [19] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_A, + .force = IPIC_SEFCR, + .bit = 3, + .prio_mask = 7, + }, + [20] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_B, + .force = IPIC_SEFCR, + .bit = 4, + .prio_mask = 4, + }, + [21] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_B, + .force = IPIC_SEFCR, + .bit = 5, + .prio_mask = 5, + }, + [22] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_B, + .force = IPIC_SEFCR, + .bit = 6, + .prio_mask = 6, + }, + [23] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_B, + .force = IPIC_SEFCR, + .bit = 7, + .prio_mask = 7, + }, + [32] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 0, + .prio_mask = 0, + }, + [33] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 1, + .prio_mask = 1, + }, + [34] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 2, + .prio_mask = 2, + }, + [35] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 3, + .prio_mask = 3, + }, + [36] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 4, + .prio_mask = 4, + }, + [37] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 5, + .prio_mask = 5, + }, + [38] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 6, + .prio_mask = 6, + }, + [39] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 7, + .prio_mask = 7, + }, + [48] = { + .pend = IPIC_SEPNR, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_A, + .force = IPIC_SEFCR, + .bit = 0, + .prio_mask = 4, + }, + [64] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_A, + .force = IPIC_SIFCR_L, + .bit = 0, + .prio_mask = 0, + }, + [65] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_A, + .force = IPIC_SIFCR_L, + .bit = 1, + .prio_mask = 1, + }, + [66] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_A, + .force = IPIC_SIFCR_L, + .bit = 2, + .prio_mask = 2, + }, + [67] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_A, + .force = IPIC_SIFCR_L, + .bit = 3, + .prio_mask = 3, + }, + [68] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_B, + .force = IPIC_SIFCR_L, + .bit = 4, + .prio_mask = 0, + }, + [69] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_B, + .force = IPIC_SIFCR_L, + .bit = 5, + .prio_mask = 1, + }, + [70] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_B, + .force = IPIC_SIFCR_L, + .bit = 6, + .prio_mask = 2, + }, + [71] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_B, + .force = IPIC_SIFCR_L, + .bit = 7, + .prio_mask = 3, + }, + [72] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 8, + }, + [73] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 9, + }, + [74] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 10, + }, + [75] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 11, + }, + [76] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 12, + }, + [77] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 13, + }, + [78] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 14, + }, + [79] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 15, + }, + [80] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 16, + }, + [84] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 20, + }, + [85] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 21, + }, + [90] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 26, + }, + [91] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 27, + }, +}; + +static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg) +{ + return in_be32(base + (reg >> 2)); +} + +static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value) +{ + out_be32(base + (reg >> 2), value); +} + +static inline struct ipic * ipic_from_irq(unsigned int irq) +{ + return primary_ipic; +} + +static void ipic_enable_irq(unsigned int irq) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + temp = ipic_read(ipic->regs, ipic_info[src].mask); + temp |= (1 << (31 - ipic_info[src].bit)); + ipic_write(ipic->regs, ipic_info[src].mask, temp); +} + +static void ipic_disable_irq(unsigned int irq) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + temp = ipic_read(ipic->regs, ipic_info[src].mask); + temp &= ~(1 << (31 - ipic_info[src].bit)); + ipic_write(ipic->regs, ipic_info[src].mask, temp); +} + +static void ipic_disable_irq_and_ack(unsigned int irq) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + ipic_disable_irq(irq); + + temp = ipic_read(ipic->regs, ipic_info[src].pend); + temp |= (1 << (31 - ipic_info[src].bit)); + ipic_write(ipic->regs, ipic_info[src].pend, temp); +} + +static void ipic_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + ipic_enable_irq(irq); +} + +struct hw_interrupt_type ipic = { + .typename = " IPIC ", + .enable = ipic_enable_irq, + .disable = ipic_disable_irq, + .ack = ipic_disable_irq_and_ack, + .end = ipic_end_irq, +}; + +void __init ipic_init(phys_addr_t phys_addr, + unsigned int flags, + unsigned int irq_offset, + unsigned char *senses, + unsigned int senses_count) +{ + u32 i, temp = 0; + + primary_ipic = &p_ipic; + primary_ipic->regs = ioremap(phys_addr, MPC83xx_IPIC_SIZE); + + primary_ipic->irq_offset = irq_offset; + + ipic_write(primary_ipic->regs, IPIC_SICNR, 0x0); + + /* default priority scheme is grouped. If spread mode is required + * configure SICFR accordingly */ + if (flags & IPIC_SPREADMODE_GRP_A) + temp |= SICFR_IPSA; + if (flags & IPIC_SPREADMODE_GRP_D) + temp |= SICFR_IPSD; + if (flags & IPIC_SPREADMODE_MIX_A) + temp |= SICFR_MPSA; + if (flags & IPIC_SPREADMODE_MIX_B) + temp |= SICFR_MPSB; + + ipic_write(primary_ipic->regs, IPIC_SICNR, temp); + + /* handle MCP route */ + temp = 0; + if (flags & IPIC_DISABLE_MCP_OUT) + temp = SERCR_MCPR; + ipic_write(primary_ipic->regs, IPIC_SERCR, temp); + + /* handle routing of IRQ0 to MCP */ + temp = ipic_read(primary_ipic->regs, IPIC_SEMSR); + + if (flags & IPIC_IRQ0_MCP) + temp |= SEMSR_SIRQ0; + else + temp &= ~SEMSR_SIRQ0; + + ipic_write(primary_ipic->regs, IPIC_SEMSR, temp); + + for (i = 0 ; i < NR_IPIC_INTS ; i++) { + irq_desc[i+irq_offset].handler = &ipic; + irq_desc[i+irq_offset].status = IRQ_LEVEL; + } + + temp = 0; + for (i = 0 ; i < senses_count ; i++) { + if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) { + temp |= 1 << (16 - i); + if (i != 0) + irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0; + else + irq_desc[irq_offset + MPC83xx_IRQ_EXT0].status = 0; + } + } + ipic_write(primary_ipic->regs, IPIC_SECNR, temp); + + printk ("IPIC (%d IRQ sources, %d External IRQs) at %p\n", NR_IPIC_INTS, + senses_count, primary_ipic->regs); +} + +int ipic_set_priority(unsigned int irq, unsigned int priority) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + if (priority > 7) + return -EINVAL; + if (src > 127) + return -EINVAL; + if (ipic_info[src].prio == 0) + return -EINVAL; + + temp = ipic_read(ipic->regs, ipic_info[src].prio); + + if (priority < 4) { + temp &= ~(0x7 << (20 + (3 - priority) * 3)); + temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3); + } else { + temp &= ~(0x7 << (4 + (7 - priority) * 3)); + temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3); + } + + ipic_write(ipic->regs, ipic_info[src].prio, temp); + + return 0; +} + +void ipic_set_highest_priority(unsigned int irq) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + temp = ipic_read(ipic->regs, IPIC_SICFR); + + /* clear and set HPI */ + temp &= 0x7f000000; + temp |= (src & 0x7f) << 24; + + ipic_write(ipic->regs, IPIC_SICFR, temp); +} + +void ipic_set_default_priority(void) +{ + ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0); + ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1); + ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2); + ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3); + ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4); + ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5); + ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6); + ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7); + + ipic_set_priority(MPC83xx_IRQ_UART1, 0); + ipic_set_priority(MPC83xx_IRQ_UART2, 1); + ipic_set_priority(MPC83xx_IRQ_SEC2, 2); + ipic_set_priority(MPC83xx_IRQ_IIC1, 5); + ipic_set_priority(MPC83xx_IRQ_IIC2, 6); + ipic_set_priority(MPC83xx_IRQ_SPI, 7); + ipic_set_priority(MPC83xx_IRQ_RTC_SEC, 0); + ipic_set_priority(MPC83xx_IRQ_PIT, 1); + ipic_set_priority(MPC83xx_IRQ_PCI1, 2); + ipic_set_priority(MPC83xx_IRQ_PCI2, 3); + ipic_set_priority(MPC83xx_IRQ_EXT0, 4); + ipic_set_priority(MPC83xx_IRQ_EXT1, 5); + ipic_set_priority(MPC83xx_IRQ_EXT2, 6); + ipic_set_priority(MPC83xx_IRQ_EXT3, 7); + ipic_set_priority(MPC83xx_IRQ_RTC_ALR, 0); + ipic_set_priority(MPC83xx_IRQ_MU, 1); + ipic_set_priority(MPC83xx_IRQ_SBA, 2); + ipic_set_priority(MPC83xx_IRQ_DMA, 3); + ipic_set_priority(MPC83xx_IRQ_EXT4, 4); + ipic_set_priority(MPC83xx_IRQ_EXT5, 5); + ipic_set_priority(MPC83xx_IRQ_EXT6, 6); + ipic_set_priority(MPC83xx_IRQ_EXT7, 7); +} + +void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq) +{ + struct ipic *ipic = primary_ipic; + u32 temp; + + temp = ipic_read(ipic->regs, IPIC_SERMR); + temp |= (1 << (31 - mcp_irq)); + ipic_write(ipic->regs, IPIC_SERMR, temp); +} + +void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq) +{ + struct ipic *ipic = primary_ipic; + u32 temp; + + temp = ipic_read(ipic->regs, IPIC_SERMR); + temp &= (1 << (31 - mcp_irq)); + ipic_write(ipic->regs, IPIC_SERMR, temp); +} + +u32 ipic_get_mcp_status(void) +{ + return ipic_read(primary_ipic->regs, IPIC_SERMR); +} + +void ipic_clear_mcp_status(u32 mask) +{ + ipic_write(primary_ipic->regs, IPIC_SERMR, mask); +} + +/* Return an interrupt vector or -1 if no interrupt is pending. */ +int ipic_get_irq(struct pt_regs *regs) +{ + int irq; + + irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & 0x7f; + + if (irq == 0) /* 0 --> no irq is pending */ + irq = -1; + + return irq; +} + +static struct sysdev_class ipic_sysclass = { + set_kset_name("ipic"), +}; + +static struct sys_device device_ipic = { + .id = 0, + .cls = &ipic_sysclass, +}; + +static int __init init_ipic_sysfs(void) +{ + int rc; + + if (!primary_ipic->regs) + return -ENODEV; + printk(KERN_DEBUG "Registering ipic with sysfs...\n"); + + rc = sysdev_class_register(&ipic_sysclass); + if (rc) { + printk(KERN_ERR "Failed registering ipic sys class\n"); + return -ENODEV; + } + rc = sysdev_register(&device_ipic); + if (rc) { + printk(KERN_ERR "Failed registering ipic sys device\n"); + return -ENODEV; + } + return 0; +} + +subsys_initcall(init_ipic_sysfs); diff --git a/arch/ppc/syslib/ipic.h b/arch/ppc/syslib/ipic.h new file mode 100644 index 000000000000..2b56a4fcf373 --- /dev/null +++ b/arch/ppc/syslib/ipic.h @@ -0,0 +1,49 @@ +/* + * arch/ppc/kernel/ipic.h + * + * IPIC private definitions and structure. + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __IPIC_H__ +#define __IPIC_H__ + +#include + +#define MPC83xx_IPIC_SIZE (0x00100) + +/* System Global Interrupt Configuration Register */ +#define SICFR_IPSA 0x00010000 +#define SICFR_IPSD 0x00080000 +#define SICFR_MPSA 0x00200000 +#define SICFR_MPSB 0x00400000 + +/* System External Interrupt Mask Register */ +#define SEMSR_SIRQ0 0x00008000 + +/* System Error Control Register */ +#define SERCR_MCPR 0x00000001 + +struct ipic { + volatile u32 __iomem *regs; + unsigned int irq_offset; +}; + +struct ipic_info { + u8 pend; /* pending register offset from base */ + u8 mask; /* mask register offset from base */ + u8 prio; /* priority register offset from base */ + u8 force; /* force register offset from base */ + u8 bit; /* register bit position (as per doc) + bit mask = 1 << (31 - bit) */ + u8 prio_mask; /* priority mask value */ +}; + +#endif /* __IPIC_H__ */ diff --git a/arch/ppc/syslib/ppc83xx_setup.c b/arch/ppc/syslib/ppc83xx_setup.c new file mode 100644 index 000000000000..c28f9d679484 --- /dev/null +++ b/arch/ppc/syslib/ppc83xx_setup.c @@ -0,0 +1,138 @@ +/* + * arch/ppc/syslib/ppc83xx_setup.c + * + * MPC83XX common board code + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include /* for linux/serial_core.h */ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +phys_addr_t immrbar; + +/* Return the amount of memory */ +unsigned long __init +mpc83xx_find_end_of_memory(void) +{ + bd_t *binfo; + + binfo = (bd_t *) __res; + + return binfo->bi_memsize; +} + +long __init +mpc83xx_time_init(void) +{ +#define SPCR_OFFS 0x00000110 +#define SPCR_TBEN 0x00400000 + + bd_t *binfo = (bd_t *)__res; + u32 *spcr = ioremap(binfo->bi_immr_base + SPCR_OFFS, 4); + + *spcr |= SPCR_TBEN; + + iounmap(spcr); + + return 0; +} + +/* The decrementer counts at the system (internal) clock freq divided by 4 */ +void __init +mpc83xx_calibrate_decr(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq, divisor; + + freq = binfo->bi_busfreq; + divisor = 4; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); +} + +#ifdef CONFIG_SERIAL_8250 +void __init +mpc83xx_early_serial_map(void) +{ +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + struct uart_port serial_req; +#endif + struct plat_serial8250_port *pdata; + bd_t *binfo = (bd_t *) __res; + pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(MPC83xx_DUART); + + /* Setup serial port access */ + pdata[0].uartclk = binfo->bi_busfreq; + pdata[0].mapbase += binfo->bi_immr_base; + pdata[0].membase = ioremap(pdata[0].mapbase, 0x100); + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + memset(&serial_req, 0, sizeof (serial_req)); + serial_req.iotype = SERIAL_IO_MEM; + serial_req.mapbase = pdata[0].mapbase; + serial_req.membase = pdata[0].membase; + serial_req.regshift = 0; + + gen550_init(0, &serial_req); +#endif + + pdata[1].uartclk = binfo->bi_busfreq; + pdata[1].mapbase += binfo->bi_immr_base; + pdata[1].membase = ioremap(pdata[1].mapbase, 0x100); + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + /* Assume gen550_init() doesn't modify serial_req */ + serial_req.mapbase = pdata[1].mapbase; + serial_req.membase = pdata[1].membase; + + gen550_init(1, &serial_req); +#endif +} +#endif + +void +mpc83xx_restart(char *cmd) +{ + local_irq_disable(); + for(;;); +} + +void +mpc83xx_power_off(void) +{ + local_irq_disable(); + for(;;); +} + +void +mpc83xx_halt(void) +{ + local_irq_disable(); + for(;;); +} + +/* PCI SUPPORT DOES NOT EXIT, MODEL after ppc85xx_setup.c */ diff --git a/arch/ppc/syslib/ppc83xx_setup.h b/arch/ppc/syslib/ppc83xx_setup.h new file mode 100644 index 000000000000..683f179b746c --- /dev/null +++ b/arch/ppc/syslib/ppc83xx_setup.h @@ -0,0 +1,53 @@ +/* + * arch/ppc/syslib/ppc83xx_setup.h + * + * MPC83XX common board definitions + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __PPC_SYSLIB_PPC83XX_SETUP_H +#define __PPC_SYSLIB_PPC83XX_SETUP_H + +#include +#include +#include + +extern unsigned long mpc83xx_find_end_of_memory(void) __init; +extern long mpc83xx_time_init(void) __init; +extern void mpc83xx_calibrate_decr(void) __init; +extern void mpc83xx_early_serial_map(void) __init; +extern void mpc83xx_restart(char *cmd); +extern void mpc83xx_power_off(void); +extern void mpc83xx_halt(void); +extern void mpc83xx_setup_hose(void) __init; + +/* PCI config */ +#if 0 +#define PCI1_CFG_ADDR_OFFSET (FIXME) +#define PCI1_CFG_DATA_OFFSET (FIXME) + +#define PCI2_CFG_ADDR_OFFSET (FIXME) +#define PCI2_CFG_DATA_OFFSET (FIXME) +#endif + +/* Serial Config */ +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 2 +#endif + +#ifndef BASE_BAUD +#define BASE_BAUD 115200 +#endif + +#endif /* __PPC_SYSLIB_PPC83XX_SETUP_H */ diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index fd2a9290bc9b..1736c9d7f4b6 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2083,7 +2083,7 @@ config TIGON3 config GIANFAR tristate "Gianfar Ethernet" - depends on 85xx + depends on 85xx || 83xx help This driver supports the Gigabit TSEC on the MPC85xx family of chips, and the FEC on the 8540 diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index fb514f700e65..e0c38f4b90f0 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -30,6 +30,8 @@ #include #elif defined(CONFIG_8260) #include +#elif defined(CONFIG_83xx) +#include #elif defined(CONFIG_85xx) #include #elif defined(CONFIG_APUS) diff --git a/include/asm-ppc/ipic.h b/include/asm-ppc/ipic.h new file mode 100644 index 000000000000..9092b920997a --- /dev/null +++ b/include/asm-ppc/ipic.h @@ -0,0 +1,85 @@ +/* + * include/asm-ppc/ipic.h + * + * IPIC external definitions and structure. + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifdef __KERNEL__ +#ifndef __ASM_IPIC_H__ +#define __ASM_IPIC_H__ + +#include + +/* Flags when we init the IPIC */ +#define IPIC_SPREADMODE_GRP_A 0x00000001 +#define IPIC_SPREADMODE_GRP_D 0x00000002 +#define IPIC_SPREADMODE_MIX_A 0x00000004 +#define IPIC_SPREADMODE_MIX_B 0x00000008 +#define IPIC_DISABLE_MCP_OUT 0x00000010 +#define IPIC_IRQ0_MCP 0x00000020 + +/* IPIC registers offsets */ +#define IPIC_SICFR 0x00 /* System Global Interrupt Configuration Register */ +#define IPIC_SIVCR 0x04 /* System Global Interrupt Vector Register */ +#define IPIC_SIPNR_H 0x08 /* System Internal Interrupt Pending Register (HIGH) */ +#define IPIC_SIPNR_L 0x0C /* System Internal Interrupt Pending Register (LOW) */ +#define IPIC_SIPRR_A 0x10 /* System Internal Interrupt group A Priority Register */ +#define IPIC_SIPRR_B 0x14 /* System Internal Interrupt group B Priority Register */ +#define IPIC_SIPRR_C 0x18 /* System Internal Interrupt group C Priority Register */ +#define IPIC_SIPRR_D 0x1C /* System Internal Interrupt group D Priority Register */ +#define IPIC_SIMSR_H 0x20 /* System Internal Interrupt Mask Register (HIGH) */ +#define IPIC_SIMSR_L 0x24 /* System Internal Interrupt Mask Register (LOW) */ +#define IPIC_SICNR 0x28 /* System Internal Interrupt Control Register */ +#define IPIC_SEPNR 0x2C /* System External Interrupt Pending Register */ +#define IPIC_SMPRR_A 0x30 /* System Mixed Interrupt group A Priority Register */ +#define IPIC_SMPRR_B 0x34 /* System Mixed Interrupt group B Priority Register */ +#define IPIC_SEMSR 0x38 /* System External Interrupt Mask Register */ +#define IPIC_SECNR 0x3C /* System External Interrupt Control Register */ +#define IPIC_SERSR 0x40 /* System Error Status Register */ +#define IPIC_SERMR 0x44 /* System Error Mask Register */ +#define IPIC_SERCR 0x48 /* System Error Control Register */ +#define IPIC_SIFCR_H 0x50 /* System Internal Interrupt Force Register (HIGH) */ +#define IPIC_SIFCR_L 0x54 /* System Internal Interrupt Force Register (LOW) */ +#define IPIC_SEFCR 0x58 /* System External Interrupt Force Register */ +#define IPIC_SERFR 0x5C /* System Error Force Register */ +#define IPIC_SCVCR 0x60 /* System Critical Interrupt Vector Register */ +#define IPIC_SMVCR 0x64 /* System Management Interrupt Vector Register */ + +enum ipic_prio_grp { + IPIC_INT_GRP_A = IPIC_SIPRR_A, + IPIC_INT_GRP_D = IPIC_SIPRR_D, + IPIC_MIX_GRP_A = IPIC_SMPRR_A, + IPIC_MIX_GRP_B = IPIC_SMPRR_B, +}; + +enum ipic_mcp_irq { + IPIC_MCP_IRQ0 = 0, + IPIC_MCP_WDT = 1, + IPIC_MCP_SBA = 2, + IPIC_MCP_PCI1 = 5, + IPIC_MCP_PCI2 = 6, + IPIC_MCP_MU = 7, +}; + +extern void ipic_init(phys_addr_t phys_addr, unsigned int flags, + unsigned int irq_offset, + unsigned char *senses, unsigned int senses_count); +extern int ipic_set_priority(unsigned int irq, unsigned int priority); +extern void ipic_set_highest_priority(unsigned int irq); +extern void ipic_set_default_priority(void); +extern void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq); +extern void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq); +extern u32 ipic_get_mcp_status(void); +extern void ipic_clear_mcp_status(u32 mask); +extern int ipic_get_irq(struct pt_regs *regs); + +#endif /* __ASM_IPIC_H__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h index 8aae5e80c1e6..8e77baad0c4a 100644 --- a/include/asm-ppc/irq.h +++ b/include/asm-ppc/irq.h @@ -161,6 +161,16 @@ static __inline__ int irq_canonicalize(int irq) return irq; } +#elif defined(CONFIG_83xx) +#include + +static __inline__ int irq_canonicalize(int irq) +{ + return irq; +} + +#define NR_IRQS (NR_IPIC_INTS) + #elif defined(CONFIG_CPM2) && defined(CONFIG_85xx) /* Now include the board configuration specific associations. */ diff --git a/include/asm-ppc/mpc83xx.h b/include/asm-ppc/mpc83xx.h new file mode 100644 index 000000000000..bb1b0576c947 --- /dev/null +++ b/include/asm-ppc/mpc83xx.h @@ -0,0 +1,114 @@ +/* + * include/asm-ppc/mpc83xx.h + * + * MPC83xx definitions + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_MPC83xx_H__ +#define __ASM_MPC83xx_H__ + +#include +#include + +#ifdef CONFIG_83xx + +#ifdef CONFIG_MPC834x_SYS +#include +#endif + +#define _IO_BASE isa_io_base +#define _ISA_MEM_BASE isa_mem_base +#ifdef CONFIG_PCI +#define PCI_DRAM_OFFSET pci_dram_offset +#else +#define PCI_DRAM_OFFSET 0 +#endif + +/* + * The "residual" board information structure the boot loader passes + * into the kernel. + */ +extern unsigned char __res[]; + +/* Internal IRQs on MPC83xx OpenPIC */ +/* Not all of these exist on all MPC83xx implementations */ + +#ifndef MPC83xx_IPIC_IRQ_OFFSET +#define MPC83xx_IPIC_IRQ_OFFSET 0 +#endif + +#define NR_IPIC_INTS 128 + +#define MPC83xx_IRQ_UART1 ( 9 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_UART2 (10 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_SEC2 (11 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_IIC1 (14 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_IIC2 (15 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_SPI (16 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_EXT1 (17 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_EXT2 (18 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_EXT3 (19 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_EXT4 (20 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_EXT5 (21 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_EXT6 (22 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_EXT7 (23 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_TSEC1_TX (32 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_TSEC1_RX (33 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_TSEC1_ERROR (34 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_TSEC2_TX (35 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_TSEC2_RX (36 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_TSEC2_ERROR (37 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_USB2_DR (38 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_USB2_MPH (39 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_EXT0 (48 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_RTC_SEC (64 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_PIT (65 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_PCI1 (66 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_PCI2 (67 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_RTC_ALR (68 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_MU (69 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_SBA (70 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_DMA (71 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GTM4 (72 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GTM8 (73 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GPIO1 (74 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GPIO2 (75 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_DDR (76 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_LBC (77 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GTM2 (78 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GTM6 (79 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_PMC (80 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GTM3 (84 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GTM7 (85 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GTM1 (90 + MPC83xx_IPIC_IRQ_OFFSET) +#define MPC83xx_IRQ_GTM5 (91 + MPC83xx_IPIC_IRQ_OFFSET) + +#define MPC83xx_CCSRBAR_SIZE (1024*1024) + +/* Let modules/drivers get at immrbar (physical) */ +extern phys_addr_t immrbar; + +enum ppc_sys_devices { + MPC83xx_TSEC1, + MPC83xx_TSEC2, + MPC83xx_IIC1, + MPC83xx_IIC2, + MPC83xx_DUART, + MPC83xx_SEC2, + MPC83xx_USB2_DR, + MPC83xx_USB2_MPH, +}; + +#endif /* CONFIG_83xx */ +#endif /* __ASM_MPC83xx_H__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h index 6f5ab7625d6a..293e47f1d99a 100644 --- a/include/asm-ppc/ppc_sys.h +++ b/include/asm-ppc/ppc_sys.h @@ -21,7 +21,9 @@ #include #include -#if defined(CONFIG_85xx) +#if defined(CONFIG_83xx) +#include +#elif defined(CONFIG_85xx) #include #else #error "need definition of ppc_sys_devices" diff --git a/include/asm-ppc/ppcboot.h b/include/asm-ppc/ppcboot.h index c2a4b94e4f1e..fe24e4520208 100644 --- a/include/asm-ppc/ppcboot.h +++ b/include/asm-ppc/ppcboot.h @@ -38,7 +38,8 @@ typedef struct bd_info { unsigned long bi_flashoffset; /* reserved area for startup monitor */ unsigned long bi_sramstart; /* start of SRAM memory */ unsigned long bi_sramsize; /* size of SRAM memory */ -#if defined(CONFIG_8xx) || defined(CONFIG_CPM2) || defined(CONFIG_85xx) +#if defined(CONFIG_8xx) || defined(CONFIG_CPM2) || defined(CONFIG_85xx) ||\ + defined(CONFIG_83xx) unsigned long bi_immr_base; /* base of IMMR register */ #endif #if defined(CONFIG_PPC_MPC52xx) @@ -72,7 +73,8 @@ typedef struct bd_info { #if defined(CONFIG_HYMOD) hymod_conf_t bi_hymod_conf; /* hymod configuration information */ #endif -#if defined(CONFIG_EVB64260) || defined(CONFIG_44x) || defined(CONFIG_85xx) +#if defined(CONFIG_EVB64260) || defined(CONFIG_44x) || defined(CONFIG_85xx) ||\ + defined(CONFIG_83xx) /* second onboard ethernet port */ unsigned char bi_enet1addr[6]; #endif diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h index f4eadce930d0..deee992463ca 100644 --- a/include/asm-ppc/serial.h +++ b/include/asm-ppc/serial.h @@ -32,6 +32,8 @@ #include #elif defined(CONFIG_4xx) #include +#elif defined(CONFIG_83xx) +#include #elif defined(CONFIG_85xx) #include #else -- cgit v1.2.3 From 8e9014435180c54811db0ad446941bb33b1e5e26 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 4 Mar 2005 17:32:31 -0800 Subject: [PATCH] ppc64: collect and export low-level cpu usage statistics POWER5 machines have a per-hardware-thread register which counts at a rate which is proportional to the percentage of cycles on which the cpu dispatches an instruction for this thread (if the thread gets all the dispatch cycles it counts at the same rate as the timebase register). This register is also context-switched by the hypervisor. Thus it gives a fine-grained measure of the actual cpu usage by the thread over time. This patch adds code to read this register every timer interrupt and on every context switch. The total over all virtual processors is available through the existing /proc/ppc64/lparcfg file, giving a way to measure the total cpu usage over the whole partition. Signed-off-by: Manish Ahuja Signed-off-by: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/lparcfg.c | 18 +++++++++++++----- arch/ppc64/kernel/process.c | 18 ++++++++++++++++++ arch/ppc64/kernel/time.c | 8 ++++++++ include/asm-ppc64/processor.h | 4 +++- include/asm-ppc64/time.h | 9 +++++++++ 5 files changed, 51 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c index 860dea50599b..a8fd32df848b 100644 --- a/arch/ppc64/kernel/lparcfg.c +++ b/arch/ppc64/kernel/lparcfg.c @@ -33,8 +33,9 @@ #include #include #include +#include -#define MODULE_VERS "1.5" +#define MODULE_VERS "1.6" #define MODULE_NAME "lparcfg" /* #define LPARCFG_DEBUG */ @@ -214,13 +215,20 @@ static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs) } static unsigned long get_purr(void); -/* ToDo: get sum of purr across all processors. The purr collection code - * is coming, but at this time is still problematic, so for now this - * function will return 0. - */ + +/* Track sum of all purrs across all processors. This is used to further */ +/* calculate usage values by different applications */ + static unsigned long get_purr(void) { unsigned long sum_purr = 0; + int cpu; + struct cpu_usage *cu; + + for_each_cpu(cpu) { + cu = &per_cpu(cpu_usage_array, cpu); + sum_purr += cu->current_tb; + } return sum_purr; } diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index d4d8d57705a6..d6b36ad17c09 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -51,6 +51,7 @@ #include #include #include +#include #ifndef CONFIG_SMP struct task_struct *last_task_used_math = NULL; @@ -168,6 +169,8 @@ int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) #endif /* CONFIG_ALTIVEC */ +DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); + struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *new) { @@ -206,6 +209,21 @@ struct task_struct *__switch_to(struct task_struct *prev, new_thread = &new->thread; old_thread = ¤t->thread; +/* Collect purr utilization data per process and per processor wise */ +/* purr is nothing but processor time base */ + +#if defined(CONFIG_PPC_PSERIES) + if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { + struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); + long unsigned start_tb, current_tb; + start_tb = old_thread->start_tb; + cu->current_tb = current_tb = mfspr(SPRN_PURR); + old_thread->accum_tb += (current_tb - start_tb); + new_thread->start_tb = current_tb; + } +#endif + + local_irq_save(flags); last = _switch(old_thread, new_thread); diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 3d88a7086ad5..f843773f8b73 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -334,6 +334,14 @@ int timer_interrupt(struct pt_regs * regs) } #endif +/* collect purr register values often, for accurate calculations */ +#if defined(CONFIG_PPC_PSERIES) + if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { + struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); + cu->current_tb = mfspr(SPRN_PURR); + } +#endif + irq_exit(); return 1; diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h index e524e77186db..ae3a5bb3ea98 100644 --- a/include/asm-ppc64/processor.h +++ b/include/asm-ppc64/processor.h @@ -562,7 +562,9 @@ struct thread_struct { double fpr[32]; /* Complete floating point set */ unsigned long fpscr; /* Floating point status (plus pad) */ unsigned long fpexc_mode; /* Floating-point exception mode */ - unsigned long pad[3]; /* was saved_msr, saved_softe */ + unsigned long start_tb; /* Start purr when proc switched in */ + unsigned long accum_tb; /* Total accumilated purr for process */ + unsigned long pad; /* was saved_msr, saved_softe */ #ifdef CONFIG_ALTIVEC /* Complete AltiVec register set */ vector128 vr[32] __attribute((aligned(16))); diff --git a/include/asm-ppc64/time.h b/include/asm-ppc64/time.h index 362d9d90acda..b7205e3b7193 100644 --- a/include/asm-ppc64/time.h +++ b/include/asm-ppc64/time.h @@ -102,5 +102,14 @@ static inline unsigned long tb_ticks_since(unsigned long tstamp) unsigned mulhwu_scale_factor(unsigned, unsigned); void div128_by_32( unsigned long dividend_high, unsigned long dividend_low, unsigned divisor, struct div_result *dr ); + +/* Used to store Processor Utilization register (purr) values */ + +struct cpu_usage { + u64 current_tb; /* Holds the current purr register values */ +}; + +DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); + #endif /* __KERNEL__ */ #endif /* __PPC64_TIME_H */ -- cgit v1.2.3 From ad826aafc674e081c49c6c426db284f926a52bd1 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 4 Mar 2005 17:32:46 -0800 Subject: [PATCH] ppc64: Move systemcfg out of head.S The "systemcfg" data structure in the ppc64 kernel is something that used to be defined to be at a hard-coded page number in the kernel image. This is not necessary (at least not any more) and is a possible problem with future developements. This patch removes that constraint, which also simplifies various bits of assembly in head.S that were dealing with it. This is the first step of a deeper cleanup of systemcfg definition of usage (and ultimately removal in it's current incarnation). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/LparData.c | 2 +- arch/ppc64/kernel/head.S | 32 +++++--------------------------- arch/ppc64/kernel/pacaData.c | 7 ++++++- arch/ppc64/kernel/proc_ppc64.c | 2 +- include/asm-ppc64/systemcfg.h | 5 ----- 5 files changed, 13 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c index bfda45cf801d..d5943e10ea9d 100644 --- a/arch/ppc64/kernel/LparData.c +++ b/arch/ppc64/kernel/LparData.c @@ -45,7 +45,7 @@ struct HvReleaseData hvReleaseData = { .xSize = sizeof(struct HvReleaseData), .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas), .xSlicNacaAddr = &naca, /* 64-bit Naca address */ - .xMsNucDataOffset = 0x6000, /* offset of LparMap within loadarea (see head.S) */ + .xMsNucDataOffset = 0x4800, /* offset of LparMap within loadarea (see head.S) */ .xTagsMode = 1, /* tags inactive */ .xAddressSize = 0, /* 64 bit */ .xNoSharedProcs = 0, /* shared processors */ diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index f62494bec4a9..a74d0bae6565 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -517,16 +517,7 @@ __end_interrupts: .globl naca naca: .llong itVpdAreas -#endif - - . = SYSTEMCFG_PHYS_ADDR - .globl __start_systemcfg -__start_systemcfg: - . = (SYSTEMCFG_PHYS_ADDR + PAGE_SIZE) - .globl __end_systemcfg -__end_systemcfg: -#ifdef CONFIG_PPC_ISERIES /* * The iSeries LPAR map is at this fixed address * so that the HvReleaseData structure can address @@ -536,6 +527,8 @@ __end_systemcfg: * VSID generation algorithm. See include/asm/mmu_context.h. */ + . = 0x4800 + .llong 2 /* # ESIDs to be mapped by hypervisor */ .llong 1 /* # memory ranges to be mapped by hypervisor */ .llong STAB0_PAGE /* Page # of segment table within load area */ @@ -1264,10 +1257,6 @@ _STATIC(__start_initialization_iSeries) addi r2,r2,0x4000 addi r2,r2,0x4000 - LOADADDR(r9,systemcfg) - SET_REG_TO_CONST(r4, SYSTEMCFG_VIRT_ADDR) - std r4,0(r9) /* set the systemcfg pointer */ - bl .iSeries_early_setup /* relocation is on at this point */ @@ -1772,7 +1761,7 @@ _GLOBAL(__secondary_start) sc /* HvCall_setASR */ #else /* set the ASR */ - li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ + ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ lwz r3,PLATFORM(r3) /* r3 = platform flags */ cmpldi r3,PLATFORM_PSERIES_LPAR bne 98f @@ -1861,12 +1850,6 @@ _STATIC(start_here_multiplatform) ori r6,r6,MSR_RI mtmsrd r6 /* RI on */ - /* setup the systemcfg pointer which is needed by *tab_initialize */ - LOADADDR(r6,systemcfg) - sub r6,r6,r26 /* addr of the variable systemcfg */ - li r27,SYSTEMCFG_PHYS_ADDR - std r27,0(r6) /* set the value of systemcfg */ - #ifdef CONFIG_HMT /* Start up the second thread on cpu 0 */ mfspr r3,PVR @@ -1941,7 +1924,7 @@ _STATIC(start_here_multiplatform) /* set the ASR */ ld r3,PACASTABREAL(r13) ori r4,r3,1 /* turn on valid bit */ - li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ + ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ lwz r3,PLATFORM(r3) /* r3 = platform flags */ cmpldi r3,PLATFORM_PSERIES_LPAR bne 98f @@ -1960,7 +1943,7 @@ _STATIC(start_here_multiplatform) mtasr r4 /* set the stab location */ 99: /* Set SDR1 (hash table pointer) */ - li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ + ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ lwz r3,PLATFORM(r3) /* r3 = platform flags */ /* Test if bit 0 is set (LPAR bit) */ andi. r3,r3,0x1 @@ -1998,11 +1981,6 @@ _STATIC(start_here_common) li r3,0 bl .do_cpu_ftr_fixups - /* setup the systemcfg pointer */ - LOADADDR(r9,systemcfg) - SET_REG_TO_CONST(r8, SYSTEMCFG_VIRT_ADDR) - std r8,0(r9) - LOADADDR(r26, boot_cpuid) lwz r26,0(r26) diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c index 0b18d17b94d4..9c979be47c5d 100644 --- a/arch/ppc64/kernel/pacaData.c +++ b/arch/ppc64/kernel/pacaData.c @@ -20,9 +20,14 @@ #include #include -struct systemcfg *systemcfg; +static union { + struct systemcfg data; + u8 page[PAGE_SIZE]; +} systemcfg_store __page_aligned; +struct systemcfg *systemcfg = &systemcfg_store.data; EXPORT_SYMBOL(systemcfg); + /* This symbol is provided by the linker - let it fill in the paca * field correctly */ extern unsigned long __toc_start; diff --git a/arch/ppc64/kernel/proc_ppc64.c b/arch/ppc64/kernel/proc_ppc64.c index d3bd869faa95..670d5bdd776a 100644 --- a/arch/ppc64/kernel/proc_ppc64.c +++ b/arch/ppc64/kernel/proc_ppc64.c @@ -89,7 +89,7 @@ static int __init proc_ppc64_init(void) return 1; pde->nlink = 1; pde->data = systemcfg; - pde->size = 4096; + pde->size = PAGE_SIZE; pde->proc_fops = &page_map_fops; #ifdef CONFIG_PPC_PSERIES diff --git a/include/asm-ppc64/systemcfg.h b/include/asm-ppc64/systemcfg.h index 13d96bfaf46d..ab328ad80b73 100644 --- a/include/asm-ppc64/systemcfg.h +++ b/include/asm-ppc64/systemcfg.h @@ -47,7 +47,6 @@ struct systemcfg { __u32 dcache_line_size; /* L1 d-cache line size 0x64 */ __u32 icache_size; /* L1 i-cache size 0x68 */ __u32 icache_line_size; /* L1 i-cache line size 0x6C */ - __u8 reserved0[3984]; /* Reserve rest of page 0x70 */ }; #ifdef __KERNEL__ @@ -56,8 +55,4 @@ extern struct systemcfg *systemcfg; #endif /* __ASSEMBLY__ */ -#define SYSTEMCFG_PAGE 0x5 -#define SYSTEMCFG_PHYS_ADDR (SYSTEMCFG_PAGE< Date: Fri, 4 Mar 2005 17:33:16 -0800 Subject: [PATCH] ppc64: distribute EXPORT_SYMBOLs This patch just moves as many as possible EXPORT_SYMBOL()s from arch/ppc64/kernel/ppc_ksyms.c to where the symbols are defined. This has been compiled on pSeries, iSeries and pmac. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/LparData.c | 1 + arch/ppc64/kernel/cputable.c | 3 ++ arch/ppc64/kernel/irq.c | 1 + arch/ppc64/kernel/pacaData.c | 1 + arch/ppc64/kernel/pci.c | 2 ++ arch/ppc64/kernel/ppc_ksyms.c | 68 ++----------------------------------------- arch/ppc64/kernel/process.c | 2 ++ arch/ppc64/kernel/prom.c | 10 +++++++ arch/ppc64/kernel/prom_init.c | 1 - arch/ppc64/kernel/semaphore.c | 5 ++++ arch/ppc64/kernel/setup.c | 1 + arch/ppc64/kernel/signal.c | 6 ++-- arch/ppc64/kernel/time.c | 1 + arch/ppc64/mm/init.c | 8 +++++ include/asm-ppc64/lmb.h | 2 -- 15 files changed, 40 insertions(+), 72 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c index d5943e10ea9d..badc5a443614 100644 --- a/arch/ppc64/kernel/LparData.c +++ b/arch/ppc64/kernel/LparData.c @@ -224,6 +224,7 @@ struct ItVpdAreas itVpdAreas = { }; struct msChunks msChunks; +EXPORT_SYMBOL(msChunks); /* Depending on whether this is called from iSeries or pSeries setup * code, the location of the msChunks struct may or may not have diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c index 44fa14e4f511..8644a8648058 100644 --- a/arch/ppc64/kernel/cputable.c +++ b/arch/ppc64/kernel/cputable.c @@ -17,9 +17,12 @@ #include #include #include +#include + #include struct cpu_spec* cur_cpu_spec = NULL; +EXPORT_SYMBOL(cur_cpu_spec); /* NOTE: * Unlike ppc32, ppc64 will only call this once for the boot CPU, it's diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c index 3a0f67c18998..0ea8016146a2 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/ppc64/kernel/irq.c @@ -61,6 +61,7 @@ extern void iSeries_smp_message_recv( struct pt_regs * ); #endif extern irq_desc_t irq_desc[NR_IRQS]; +EXPORT_SYMBOL(irq_desc); int distribute_irqs = 1; int __irq_offset_value; diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c index 9c979be47c5d..a3e0975c26c1 100644 --- a/arch/ppc64/kernel/pacaData.c +++ b/arch/ppc64/kernel/pacaData.c @@ -221,3 +221,4 @@ struct paca_struct paca[] = { #endif #endif }; +EXPORT_SYMBOL(paca); diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index c67b5c7b8456..bcdb128368b5 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -63,7 +63,9 @@ unsigned int pcibios_assign_all_busses(void) * page is mapped and isa_io_limit prevents access to it. */ unsigned long isa_io_base; /* NULL if no ISA bus */ +EXPORT_SYMBOL(isa_io_base); unsigned long pci_io_base; +EXPORT_SYMBOL(pci_io_base); void iSeries_pcibios_init(void); diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c index 38c0398d823c..6ced63a3439f 100644 --- a/arch/ppc64/kernel/ppc_ksyms.c +++ b/arch/ppc64/kernel/ppc_ksyms.c @@ -8,49 +8,18 @@ */ #include #include -#include -#include -#include -#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include +#include -#include -#include #include #include #include -#include -#include -#include -#include #include -#include -#include -#include -#include #include #include #include -#ifdef CONFIG_PPC_ISERIES #include -#include -#endif - -extern int do_signal(sigset_t *, struct pt_regs *); - -EXPORT_SYMBOL(do_signal); - -EXPORT_SYMBOL(isa_io_base); -EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strncpy); @@ -65,10 +34,6 @@ EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strncmp); -EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down); - EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial_copy_generic); EXPORT_SYMBOL(ip_fast_csum); @@ -79,11 +44,6 @@ EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strnlen_user); -EXPORT_SYMBOL(clear_user_page); - -#ifdef CONFIG_MSCHUNKS -EXPORT_SYMBOL(msChunks); -#endif EXPORT_SYMBOL(reloc_offset); #ifdef CONFIG_PPC_ISERIES @@ -107,11 +67,7 @@ EXPORT_SYMBOL(_insw_ns); EXPORT_SYMBOL(_outsw_ns); EXPORT_SYMBOL(_insl_ns); EXPORT_SYMBOL(_outsl_ns); -EXPORT_SYMBOL(ioremap); -EXPORT_SYMBOL(__ioremap); -EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(giveup_fpu); @@ -119,8 +75,7 @@ EXPORT_SYMBOL(giveup_fpu); EXPORT_SYMBOL(giveup_altivec); #endif EXPORT_SYMBOL(flush_icache_range); -EXPORT_SYMBOL(flush_icache_user_range); -EXPORT_SYMBOL(flush_dcache_page); + #ifdef CONFIG_SMP #ifdef CONFIG_PPC_ISERIES EXPORT_SYMBOL(local_get_flags); @@ -129,19 +84,6 @@ EXPORT_SYMBOL(local_irq_restore); #endif #endif -EXPORT_SYMBOL(ppc_md); - -#ifdef CONFIG_PPC_MULTIPLATFORM -EXPORT_SYMBOL(find_devices); -EXPORT_SYMBOL(find_type_devices); -EXPORT_SYMBOL(find_compatible_devices); -EXPORT_SYMBOL(find_path_device); -EXPORT_SYMBOL(device_is_compatible); -EXPORT_SYMBOL(machine_is_compatible); -EXPORT_SYMBOL(find_all_nodes); -EXPORT_SYMBOL(get_property); -#endif - EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memmove); @@ -150,10 +92,4 @@ EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(timer_interrupt); -EXPORT_SYMBOL(irq_desc); -EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); - -EXPORT_SYMBOL(tb_ticks_per_usec); -EXPORT_SYMBOL(paca); -EXPORT_SYMBOL(cur_cpu_spec); diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index d6b36ad17c09..8b0686122738 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -487,6 +487,7 @@ void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp) current->thread.used_vr = 0; #endif /* CONFIG_ALTIVEC */ } +EXPORT_SYMBOL(start_thread); int set_fpexc_mode(struct task_struct *tsk, unsigned int val) { @@ -625,6 +626,7 @@ unsigned long get_wchan(struct task_struct *p) } while (count++ < 16); return 0; } +EXPORT_SYMBOL(get_wchan); void show_stack(struct task_struct *p, unsigned long *_sp) { diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index eed1a707db88..ce4eefcbce6f 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c @@ -32,6 +32,8 @@ #include #include #include +#include + #include #include #include @@ -1138,6 +1140,7 @@ find_devices(const char *name) *prevp = NULL; return head; } +EXPORT_SYMBOL(find_devices); /** * Construct and return a list of the device_nodes with a given type. @@ -1157,6 +1160,7 @@ find_type_devices(const char *type) *prevp = NULL; return head; } +EXPORT_SYMBOL(find_type_devices); /** * Returns all nodes linked together @@ -1174,6 +1178,7 @@ find_all_nodes(void) *prevp = NULL; return head; } +EXPORT_SYMBOL(find_all_nodes); /** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property @@ -1197,6 +1202,7 @@ device_is_compatible(struct device_node *device, const char *compat) return 0; } +EXPORT_SYMBOL(device_is_compatible); /** @@ -1216,6 +1222,7 @@ machine_is_compatible(const char *compat) } return rc; } +EXPORT_SYMBOL(machine_is_compatible); /** * Construct and return a list of the device_nodes with a given type @@ -1239,6 +1246,7 @@ find_compatible_devices(const char *type, const char *compat) *prevp = NULL; return head; } +EXPORT_SYMBOL(find_compatible_devices); /** * Find the device_node with a given full_name. @@ -1253,6 +1261,7 @@ find_path_device(const char *path) return np; return NULL; } +EXPORT_SYMBOL(find_path_device); /******* * @@ -1872,6 +1881,7 @@ get_property(struct device_node *np, const char *name, int *lenp) } return NULL; } +EXPORT_SYMBOL(get_property); /* * Add a property to a node diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index e0e3e219dc8c..b08467019a6e 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -151,7 +151,6 @@ typedef u32 cell_t; extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); -extern unsigned long reloc_offset(void); extern void enter_prom(struct prom_args *args, unsigned long entry); extern void copy_and_flush(unsigned long dest, unsigned long src, unsigned long size, unsigned long offset); diff --git a/arch/ppc64/kernel/semaphore.c b/arch/ppc64/kernel/semaphore.c index d723632d59f3..a1c1db573e9c 100644 --- a/arch/ppc64/kernel/semaphore.c +++ b/arch/ppc64/kernel/semaphore.c @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -62,6 +64,7 @@ void __up(struct semaphore *sem) __sem_update_count(sem, 1); wake_up(&sem->wait); } +EXPORT_SYMBOL(__up); /* * Note that when we come in to __down or __down_interruptible, @@ -99,6 +102,7 @@ void __sched __down(struct semaphore *sem) */ wake_up(&sem->wait); } +EXPORT_SYMBOL(__down); int __sched __down_interruptible(struct semaphore * sem) { @@ -129,3 +133,4 @@ int __sched __down_interruptible(struct semaphore * sem) wake_up(&sem->wait); return retval; } +EXPORT_SYMBOL(__down_interruptible); diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index ed2e166fd9d6..a3a92863a0ac 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -129,6 +129,7 @@ int ucache_bsize; /* The main machine-dep calls structure */ struct machdep_calls ppc_md; +EXPORT_SYMBOL(ppc_md); #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY; diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index bea0bbcfe20f..52f8b4c718b0 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c @@ -27,6 +27,8 @@ #include #include #include +#include + #include #include #include @@ -566,6 +568,4 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) return 0; } - - - +EXPORT_SYMBOL(do_signal); diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index f843773f8b73..fd0ccdc26d12 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -85,6 +85,7 @@ static unsigned long first_settimeofday = 1; unsigned long tb_ticks_per_jiffy; unsigned long tb_ticks_per_usec = 100; /* sane default */ +EXPORT_SYMBOL(tb_ticks_per_usec); unsigned long tb_ticks_per_sec; unsigned long next_xtime_sync_tb; unsigned long xtime_sync_interval; diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index 2ad8b0b00eec..d876a18dbcf7 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -441,6 +442,10 @@ int iounmap_explicit(volatile void __iomem *start, unsigned long size) #endif +EXPORT_SYMBOL(ioremap); +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); + void free_initmem(void) { unsigned long addr; @@ -758,6 +763,7 @@ void flush_dcache_page(struct page *page) if (test_bit(PG_arch_1, &page->flags)) clear_bit(PG_arch_1, &page->flags); } +EXPORT_SYMBOL(flush_dcache_page); void clear_user_page(void *page, unsigned long vaddr, struct page *pg) { @@ -775,6 +781,7 @@ void clear_user_page(void *page, unsigned long vaddr, struct page *pg) if (test_bit(PG_arch_1, &pg->flags)) clear_bit(PG_arch_1, &pg->flags); } +EXPORT_SYMBOL(clear_user_page); void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg) @@ -812,6 +819,7 @@ void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK); flush_icache_range(maddr, maddr + len); } +EXPORT_SYMBOL(flush_icache_user_range); /* * This is called at the end of handling a user page fault, when the diff --git a/include/asm-ppc64/lmb.h b/include/asm-ppc64/lmb.h index f1c1f0a38ccd..3da661161cc5 100644 --- a/include/asm-ppc64/lmb.h +++ b/include/asm-ppc64/lmb.h @@ -16,8 +16,6 @@ #include #include -extern unsigned long reloc_offset(void); - #define MAX_LMB_REGIONS 128 #define LMB_ALLOC_ANYWHERE 0 -- cgit v1.2.3 From 054eb7153aeb84cc92da84210cf93b0e2a34811b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 4 Mar 2005 17:33:32 -0800 Subject: [PATCH] ppc64: Implement a vDSO and use it for signal trampoline This patch adds to the ppc64 kernel a virtual .so (vDSO) that is mapped into every process space, similar to the x86 vsyscall page. However, the implementation is very different (and doesn't use the gate area mecanism). Actually, it contains two implementations, a 32 bits and a 64 bits one. These vDSO's are currently mapped at 0x100000 (+1Mb) when possible (when a process load section isn't already there). In the future, we can randomize that address, or even imagine having a special phdr entry letting apps that wnat finer control over their address space to put it elsewhere (or not at all). The implementation adds a hook to binfmt_elf to let the architecture add a real VMA to the process space instead of using the gate area mecanism. This mecanism wasn't very suitable for ppc, we couldn't just "shove" PTE entries mapping kernel addresses into userland without expensive changes to our hash table management. Instead, I made the vDSO be a normal VMA which, additionally, means it supports copy-on-write semantics if made writable via ptrace/mprotect, thus allowing breakpoints in the vDSO code. The current implementation of the vDSOs contain the signal trampolines with appropriate DWARF informations, which enable us to use non-executable stacks (patches to come later) along with a few more functions that we hope glibc will soon make good use of (this is the "hard" part now :) Note that the symbols exposed by the vDSO aren't "normal" function symbols, apps can't be expected to link against them directly, the vDSO's are both seen as if they were linked at 0 and the symbols just contain offsets to the various functions. This is done on purpose to avoid a relocation step (ppc64 functions normally have descriptors with abs addresses in them). When glibc uses those functions, it's expected to use it's own trampolines that know how to reach them. In some cases, the vDSO contains several versions of a given function (for various CPUs), the kernel will "patch" the symbol table at boot to make it point to the appropriate one transparently. What is currently implemented is: - int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); This is a fully userland implementation of gettimeofday, with no barriers and no locks, and providing 100% equivalent results to the syscall version - void __kernel_sync_dicache(unsigned long start, unsigned long end) This function sync's the data and instruction caches (for making data executable), it is expected that userland loaders use this instead of doing it themselves, as the kernel will provide optimized versions for the current CPU. Currently, the vDSO procides a full one for all CPUs prior to POWER5 and a nop one for POWER5 which implements hardware snooping at the L1 level. In the future, an intermediate implementation may be done for the POWER4 and 970 which don't need the "dcbst" loop (the L1D cache is write-through on those). - void *__kernel_get_syscall_map(unsigned int *syscall_count); Returns a pointer to a map of implemented syscalls on the currently running kernel. The map is agnostic to the size of "long", unlike kernel bitops, it stores bits from top to bottom so that memory actually contains a linear bitmap check for syscall N by testing bit (0x80000000 >> (N & 0x1f)) of * 32 bits int at N >> 5. Note about backward compatibility issues: A bug in the ppc64 libgcc unwinder makes it unable to unwind stacks properly accross signals if the signal trampoline isn't on the stack. This has been fixed in CVS for gcc 4.0 and will be soon on the stable branch, but the problem exist will all currently used versions. That means that until glibc gets the patch to enable it's use of the vDSO symbols for the DWARF unwinder (rather trivial patch that will be pushed to glibc CVS soon hopefully), unwinding from a signal handler will not work for 64 bits applications. I consider this as a non-issue though as a patch is about to be produced, which can easily get pushed to "live" distros like debian, gentoo, fedora, etc... soon enough (it breaks compatilbity with kernels below 2.4.20 unfortunately as our signal stack layout changed, crap crap crap), as there are few 64 bits applications out there (expect gentoo), as it's only really an issue with C++ code relying on throwing exceptions out of signal handlers (extremely rare it seems), and as "release" distros like SLES or RHEL will probably have the vDSO enabled glibc _and_ the unwinder fix by the time they release a version with a 2.6.11 or 2.6.12 kernel anyway :) So far, I yet have to see an app failing because of that... Finally, many many many thanks to Alan Modra for writing the DWARF information of the signal handlers and debugging the libgcc issues ! Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/Makefile | 21 + arch/ppc64/boot/Makefile | 16 +- arch/ppc64/kernel/Makefile | 3 +- arch/ppc64/kernel/asm-offsets.c | 22 ++ arch/ppc64/kernel/head.S | 1 - arch/ppc64/kernel/setup.c | 31 ++ arch/ppc64/kernel/signal.c | 14 +- arch/ppc64/kernel/signal32.c | 27 +- arch/ppc64/kernel/smp.c | 2 +- arch/ppc64/kernel/time.c | 84 ++-- arch/ppc64/kernel/vdso.c | 614 ++++++++++++++++++++++++++++++ arch/ppc64/kernel/vdso32/Makefile | 36 ++ arch/ppc64/kernel/vdso32/cacheflush.S | 65 ++++ arch/ppc64/kernel/vdso32/datapage.S | 68 ++++ arch/ppc64/kernel/vdso32/gettimeofday.S | 139 +++++++ arch/ppc64/kernel/vdso32/sigtramp.S | 300 +++++++++++++++ arch/ppc64/kernel/vdso32/vdso32.lds.S | 111 ++++++ arch/ppc64/kernel/vdso32/vdso32_wrapper.S | 13 + arch/ppc64/kernel/vdso64/Makefile | 35 ++ arch/ppc64/kernel/vdso64/cacheflush.S | 64 ++++ arch/ppc64/kernel/vdso64/datapage.S | 68 ++++ arch/ppc64/kernel/vdso64/gettimeofday.S | 91 +++++ arch/ppc64/kernel/vdso64/sigtramp.S | 294 ++++++++++++++ arch/ppc64/kernel/vdso64/vdso64.lds.S | 110 ++++++ arch/ppc64/kernel/vdso64/vdso64_wrapper.S | 13 + arch/ppc64/mm/init.c | 3 + fs/binfmt_elf.c | 8 + include/asm-ppc64/a.out.h | 11 +- include/asm-ppc64/elf.h | 12 + include/asm-ppc64/page.h | 3 + include/asm-ppc64/processor.h | 6 +- include/asm-ppc64/systemcfg.h | 8 +- include/asm-ppc64/time.h | 2 +- include/asm-ppc64/vdso.h | 83 ++++ 34 files changed, 2314 insertions(+), 64 deletions(-) create mode 100644 arch/ppc64/kernel/vdso.c create mode 100644 arch/ppc64/kernel/vdso32/Makefile create mode 100644 arch/ppc64/kernel/vdso32/cacheflush.S create mode 100644 arch/ppc64/kernel/vdso32/datapage.S create mode 100644 arch/ppc64/kernel/vdso32/gettimeofday.S create mode 100644 arch/ppc64/kernel/vdso32/sigtramp.S create mode 100644 arch/ppc64/kernel/vdso32/vdso32.lds.S create mode 100644 arch/ppc64/kernel/vdso32/vdso32_wrapper.S create mode 100644 arch/ppc64/kernel/vdso64/Makefile create mode 100644 arch/ppc64/kernel/vdso64/cacheflush.S create mode 100644 arch/ppc64/kernel/vdso64/datapage.S create mode 100644 arch/ppc64/kernel/vdso64/gettimeofday.S create mode 100644 arch/ppc64/kernel/vdso64/sigtramp.S create mode 100644 arch/ppc64/kernel/vdso64/vdso64.lds.S create mode 100644 arch/ppc64/kernel/vdso64/vdso64_wrapper.S create mode 100644 include/asm-ppc64/vdso.h (limited to 'include') diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index e8f9cd714c4c..d3d23483f8b5 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -15,17 +15,38 @@ KERNELLOAD := 0xc000000000000000 +# Set default 32 bits cross compilers for vdso and boot wrapper +CROSS32_COMPILE ?= + +CROSS32CC := $(CROSS32_COMPILE)gcc +CROSS32AS := $(CROSS32_COMPILE)as +CROSS32LD := $(CROSS32_COMPILE)ld +CROSS32OBJCOPY := $(CROSS32_COMPILE)objcopy + +# If we have a biarch compiler, use it for 32 bits cross compile if +# CROSS32_COMPILE wasn't explicitely defined, and add proper explicit +# target type to target compilers + HAS_BIARCH := $(call cc-option-yn, -m64) ifeq ($(HAS_BIARCH),y) +ifeq ($(CROSS32_COMPILE),) +CROSS32CC := $(CC) -m32 +CROSS32AS := $(AS) -a32 +CROSS32LD := $(LD) -m elf32ppc +CROSS32OBJCOPY := $(OBJCOPY) +endif AS := $(AS) -a64 LD := $(LD) -m elf64ppc CC := $(CC) -m64 endif +export CROSS32CC CROSS32AS CROSS32LD CROSS32OBJCOPY + new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi) ifeq ($(new_nm),y) NM := $(NM) --synthetic + endif CHECKFLAGS += -m64 -D__powerpc__ diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile index 9963fedcc192..d87fd5a0d7e8 100644 --- a/arch/ppc64/boot/Makefile +++ b/arch/ppc64/boot/Makefile @@ -20,17 +20,11 @@ # CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE # in the toplevel makefile. -CROSS32_COMPILE ?= -#CROSS32_COMPILE = /usr/local/ppc/bin/powerpc-linux- -BOOTCC := $(CROSS32_COMPILE)gcc HOSTCC := gcc BOOTCFLAGS := $(HOSTCFLAGS) $(LINUXINCLUDE) -fno-builtin -BOOTAS := $(CROSS32_COMPILE)as BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -BOOTLD := $(CROSS32_COMPILE)ld BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(srctree)/$(src)/zImage.lds -BOOTOBJCOPY := $(CROSS32_COMPILE)objcopy OBJCOPYFLAGS := contents,alloc,load,readonly,data src-boot := crt0.S string.S prom.c main.c zlib.c imagesize.c div64.S @@ -38,10 +32,10 @@ src-boot := $(addprefix $(obj)/, $(src-boot)) obj-boot := $(addsuffix .o, $(basename $(src-boot))) quiet_cmd_bootcc = BOOTCC $@ - cmd_bootcc = $(BOOTCC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $< + cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $< quiet_cmd_bootas = BOOTAS $@ - cmd_bootas = $(BOOTCC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $< + cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $< $(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c $(call if_changed_dep,bootcc) @@ -77,15 +71,15 @@ vmlinux.strip: vmlinux FORCE $(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE $(call if_changed,ramdisk) -addsection = $(BOOTOBJCOPY) $(1) \ +addsection = $(CROSS32OBJCOPY) $(1) \ --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(patsubst %.o,%.gz, $(1)) \ --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(OBJCOPYFLAGS) quiet_cmd_addnote = ADDNOTE $@ - cmd_addnote = $(BOOTLD) $(BOOTLFLAGS) -o $@ $(obj-boot) && $(obj)/addnote $@ + cmd_addnote = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(obj-boot) && $(obj)/addnote $@ quiet_cmd_piggy = PIGGY $@ - cmd_piggy = $(obj)/piggyback $(@:.o=) < $< | $(BOOTAS) -o $@ + cmd_piggy = $(obj)/piggyback $(@:.o=) < $< | $(CROSS32AS) -o $@ $(call gz-sec, $(required)): $(obj)/kernel-%.gz: % FORCE $(call if_changed,gzip) diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 09ddd507418d..752c9d6a3f70 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -11,7 +11,8 @@ obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o init_task.o \ lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ - iommu.o sysfs.o + iommu.o sysfs.o vdso.o +obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c index 11a85558d0da..0094ac79a18c 100644 --- a/arch/ppc64/kernel/asm-offsets.c +++ b/arch/ppc64/kernel/asm-offsets.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include #include #include +#include +#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -167,5 +170,24 @@ int main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); + /* systemcfg offsets for use by vdso */ + DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct systemcfg, tb_orig_stamp)); + DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct systemcfg, tb_ticks_per_sec)); + DEFINE(CFG_TB_TO_XS, offsetof(struct systemcfg, tb_to_xs)); + DEFINE(CFG_STAMP_XSEC, offsetof(struct systemcfg, stamp_xsec)); + DEFINE(CFG_TB_UPDATE_COUNT, offsetof(struct systemcfg, tb_update_count)); + DEFINE(CFG_TZ_MINUTEWEST, offsetof(struct systemcfg, tz_minuteswest)); + DEFINE(CFG_TZ_DSTTIME, offsetof(struct systemcfg, tz_dsttime)); + DEFINE(CFG_SYSCALL_MAP32, offsetof(struct systemcfg, syscall_map_32)); + DEFINE(CFG_SYSCALL_MAP64, offsetof(struct systemcfg, syscall_map_64)); + + /* timeval/timezone offsets for use by vdso */ + DEFINE(TVAL64_TV_SEC, offsetof(struct timeval, tv_sec)); + DEFINE(TVAL64_TV_USEC, offsetof(struct timeval, tv_usec)); + DEFINE(TVAL32_TV_SEC, offsetof(struct compat_timeval, tv_sec)); + DEFINE(TVAL32_TV_USEC, offsetof(struct compat_timeval, tv_usec)); + DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest)); + DEFINE(TZONE_TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); + return 0; } diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index a74d0bae6565..39b23cd0774f 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -54,7 +54,6 @@ * 0x0100 - 0x2fff : pSeries Interrupt prologs * 0x3000 - 0x3fff : Interrupt support * 0x4000 - 0x4fff : NACA - * 0x5000 - 0x5fff : SystemCfg * 0x6000 : iSeries and common interrupt prologs * 0x9000 - 0x9fff : Initial segment table */ diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index a3a92863a0ac..d98c320828e5 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -990,6 +990,34 @@ static void __init emergency_stack_init(void) limit)) + PAGE_SIZE; } +/* + * Called from setup_arch to initialize the bitmap of available + * syscalls in the systemcfg page + */ +void __init setup_syscall_map(void) +{ + unsigned int i, count64 = 0, count32 = 0; + extern unsigned long *sys_call_table; + extern unsigned long *sys_call_table32; + extern unsigned long sys_ni_syscall; + + + for (i = 0; i < __NR_syscalls; i++) { + if (sys_call_table[i] == sys_ni_syscall) + continue; + count64++; + systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); + } + for (i = 0; i < __NR_syscalls; i++) { + if (sys_call_table32[i] == sys_ni_syscall) + continue; + count32++; + systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); + } + printk(KERN_INFO "Syscall map setup, %d 32 bits and %d 64 bits syscalls\n", + count32, count64); +} + /* * Called into from start_kernel, after lock_kernel has been called. * Initializes bootmem, which is unsed to manage page allocation until @@ -1028,6 +1056,9 @@ void __init setup_arch(char **cmdline_p) /* set up the bootmem stuff with available memory */ do_init_bootmem(); + /* initialize the syscall map in systemcfg */ + setup_syscall_map(); + ppc_md.setup_arch(); /* Select the correct idle loop for the platform. */ diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index 52f8b4c718b0..00e80e3e6986 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c @@ -36,6 +36,7 @@ #include #include #include +#include #define DEBUG_SIG 0 @@ -428,10 +429,14 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, goto badframe; /* Set up to return from userspace. */ - err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); - if (err) - goto badframe; - + if (vdso64_rt_sigtramp && current->thread.vdso_base) { + regs->link = current->thread.vdso_base + vdso64_rt_sigtramp; + } else { + err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); + if (err) + goto badframe; + regs->link = (unsigned long) &frame->tramp[0]; + } funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler; /* Allocate a dummy caller frame for the signal handler. */ @@ -440,7 +445,6 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, /* Set up "regs" so we "return" to the signal handler. */ err |= get_user(regs->nip, &funct_desc_ptr->entry); - regs->link = (unsigned long) &frame->tramp[0]; regs->gpr[1] = newsp; err |= get_user(regs->gpr[2], &funct_desc_ptr->toc); regs->gpr[3] = signr; diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index 145eac7ef8f4..b9093e9d2c72 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -31,6 +31,7 @@ #include #include #include +#include #define DEBUG_SIG 0 @@ -656,18 +657,24 @@ static int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, /* Save user registers on the stack */ frame = &rt_sf->uc.uc_mcontext; - if (save_user_regs(regs, frame, __NR_rt_sigreturn)) - goto badframe; - if (put_user(regs->gpr[1], (unsigned long __user *)newsp)) goto badframe; + + if (vdso32_rt_sigtramp && current->thread.vdso_base) { + if (save_user_regs(regs, frame, 0)) + goto badframe; + regs->link = current->thread.vdso_base + vdso32_rt_sigtramp; + } else { + if (save_user_regs(regs, frame, __NR_rt_sigreturn)) + goto badframe; + regs->link = (unsigned long) frame->tramp; + } regs->gpr[1] = (unsigned long) newsp; regs->gpr[3] = sig; regs->gpr[4] = (unsigned long) &rt_sf->info; regs->gpr[5] = (unsigned long) &rt_sf->uc; regs->gpr[6] = (unsigned long) rt_sf; regs->nip = (unsigned long) ka->sa.sa_handler; - regs->link = (unsigned long) frame->tramp; regs->trap = 0; regs->result = 0; @@ -825,8 +832,15 @@ static int handle_signal32(unsigned long sig, struct k_sigaction *ka, || __put_user(sig, &sc->signal)) goto badframe; - if (save_user_regs(regs, &frame->mctx, __NR_sigreturn)) - goto badframe; + if (vdso32_sigtramp && current->thread.vdso_base) { + if (save_user_regs(regs, &frame->mctx, 0)) + goto badframe; + regs->link = current->thread.vdso_base + vdso32_sigtramp; + } else { + if (save_user_regs(regs, &frame->mctx, __NR_sigreturn)) + goto badframe; + regs->link = (unsigned long) frame->mctx.tramp; + } if (put_user(regs->gpr[1], (unsigned long __user *)newsp)) goto badframe; @@ -834,7 +848,6 @@ static int handle_signal32(unsigned long sig, struct k_sigaction *ka, regs->gpr[3] = sig; regs->gpr[4] = (unsigned long) sc; regs->nip = (unsigned long) ka->sa.sa_handler; - regs->link = (unsigned long) frame->mctx.tramp; regs->trap = 0; regs->result = 0; diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index d6ecf0727596..a9e43792f8fe 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -383,7 +383,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) * For now we leave it which means the time can be some * number of msecs off until someone does a settimeofday() */ - do_gtod.tb_orig_stamp = tb_last_stamp; + do_gtod.varp->tb_orig_stamp = tb_last_stamp; systemcfg->tb_orig_stamp = tb_last_stamp; #endif diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index fd0ccdc26d12..77ded5a363b6 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -87,8 +87,6 @@ unsigned long tb_ticks_per_jiffy; unsigned long tb_ticks_per_usec = 100; /* sane default */ EXPORT_SYMBOL(tb_ticks_per_usec); unsigned long tb_ticks_per_sec; -unsigned long next_xtime_sync_tb; -unsigned long xtime_sync_interval; unsigned long tb_to_xs; unsigned tb_to_us; unsigned long processor_freq; @@ -159,8 +157,8 @@ static inline void __do_gettimeofday(struct timeval *tv, unsigned long tb_val) * The conversion to microseconds at the end is done * without a divide (and in fact, without a multiply) */ - tb_ticks = tb_val - do_gtod.tb_orig_stamp; temp_varp = do_gtod.varp; + tb_ticks = tb_val - temp_varp->tb_orig_stamp; temp_tb_to_xs = temp_varp->tb_to_xs; temp_stamp_xsec = temp_varp->stamp_xsec; tb_xsec = mulhdu( tb_ticks, temp_tb_to_xs ); @@ -186,17 +184,55 @@ static inline void timer_sync_xtime(unsigned long cur_tb) { struct timeval my_tv; - if (cur_tb > next_xtime_sync_tb) { - next_xtime_sync_tb = cur_tb + xtime_sync_interval; - __do_gettimeofday(&my_tv, cur_tb); + __do_gettimeofday(&my_tv, cur_tb); - if (xtime.tv_sec <= my_tv.tv_sec) { - xtime.tv_sec = my_tv.tv_sec; - xtime.tv_nsec = my_tv.tv_usec * 1000; - } + if (xtime.tv_sec <= my_tv.tv_sec) { + xtime.tv_sec = my_tv.tv_sec; + xtime.tv_nsec = my_tv.tv_usec * 1000; } } +/* + * When the timebase - tb_orig_stamp gets too big, we do a manipulation + * between tb_orig_stamp and stamp_xsec. The goal here is to keep the + * difference tb - tb_orig_stamp small enough to always fit inside a + * 32 bits number. This is a requirement of our fast 32 bits userland + * implementation in the vdso. If we "miss" a call to this function + * (interrupt latency, CPU locked in a spinlock, ...) and we end up + * with a too big difference, then the vdso will fallback to calling + * the syscall + */ +static __inline__ void timer_recalc_offset(unsigned long cur_tb) +{ + struct gettimeofday_vars * temp_varp; + unsigned temp_idx; + unsigned long offset, new_stamp_xsec, new_tb_orig_stamp; + + if (((cur_tb - do_gtod.varp->tb_orig_stamp) & 0x80000000u) == 0) + return; + + temp_idx = (do_gtod.var_idx == 0); + temp_varp = &do_gtod.vars[temp_idx]; + + new_tb_orig_stamp = cur_tb; + offset = new_tb_orig_stamp - do_gtod.varp->tb_orig_stamp; + new_stamp_xsec = do_gtod.varp->stamp_xsec + mulhdu(offset, do_gtod.varp->tb_to_xs); + + temp_varp->tb_to_xs = do_gtod.varp->tb_to_xs; + temp_varp->tb_orig_stamp = new_tb_orig_stamp; + temp_varp->stamp_xsec = new_stamp_xsec; + mb(); + do_gtod.varp = temp_varp; + do_gtod.var_idx = temp_idx; + + ++(systemcfg->tb_update_count); + wmb(); + systemcfg->tb_orig_stamp = new_tb_orig_stamp; + systemcfg->stamp_xsec = new_stamp_xsec; + wmb(); + ++(systemcfg->tb_update_count); +} + #ifdef CONFIG_SMP unsigned long profile_pc(struct pt_regs *regs) { @@ -312,6 +348,7 @@ int timer_interrupt(struct pt_regs * regs) if (cpu == boot_cpuid) { write_seqlock(&xtime_lock); tb_last_stamp = lpaca->next_jiffy_update_tb; + timer_recalc_offset(lpaca->next_jiffy_update_tb); do_timer(regs); timer_sync_xtime(lpaca->next_jiffy_update_tb); timer_check_rtc(); @@ -407,7 +444,9 @@ int do_settimeofday(struct timespec *tv) time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - delta_xsec = mulhdu( (tb_last_stamp-do_gtod.tb_orig_stamp), do_gtod.varp->tb_to_xs ); + delta_xsec = mulhdu( (tb_last_stamp-do_gtod.varp->tb_orig_stamp), + do_gtod.varp->tb_to_xs ); + new_xsec = (new_nsec * XSEC_PER_SEC) / NSEC_PER_SEC; new_xsec += new_sec * XSEC_PER_SEC; if ( new_xsec > delta_xsec ) { @@ -420,7 +459,7 @@ int do_settimeofday(struct timespec *tv) * before 1970 ... eg. we booted ten days ago, and we are setting * the time to Jan 5, 1970 */ do_gtod.varp->stamp_xsec = new_xsec; - do_gtod.tb_orig_stamp = tb_last_stamp; + do_gtod.varp->tb_orig_stamp = tb_last_stamp; systemcfg->stamp_xsec = new_xsec; systemcfg->tb_orig_stamp = tb_last_stamp; } @@ -473,9 +512,9 @@ void __init time_init(void) xtime.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); tb_last_stamp = get_tb(); - do_gtod.tb_orig_stamp = tb_last_stamp; do_gtod.varp = &do_gtod.vars[0]; do_gtod.var_idx = 0; + do_gtod.varp->tb_orig_stamp = tb_last_stamp; do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; do_gtod.varp->tb_to_xs = tb_to_xs; @@ -486,9 +525,6 @@ void __init time_init(void) systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; systemcfg->tb_to_xs = tb_to_xs; - xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8); - next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval; - time_freq = 0; xtime.tv_nsec = 0; @@ -593,12 +629,12 @@ void ppc_adjtimex(void) stamp_xsec which is the time (in 1/2^20 second units) corresponding to tb_orig_stamp. This new value of stamp_xsec compensates for the change in frequency (implied by the new tb_to_xs) which guarantees that the current time remains the same */ - tb_ticks = get_tb() - do_gtod.tb_orig_stamp; + write_seqlock_irqsave( &xtime_lock, flags ); + tb_ticks = get_tb() - do_gtod.varp->tb_orig_stamp; div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres ); new_tb_to_xs = divres.result_low; new_xsec = mulhdu( tb_ticks, new_tb_to_xs ); - write_seqlock_irqsave( &xtime_lock, flags ); old_xsec = mulhdu( tb_ticks, do_gtod.varp->tb_to_xs ); new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec; @@ -606,16 +642,12 @@ void ppc_adjtimex(void) values in do_gettimeofday. We alternate the copies and as long as a reasonable time elapses between changes, there will never be inconsistent values. ntpd has a minimum of one minute between updates */ - if (do_gtod.var_idx == 0) { - temp_varp = &do_gtod.vars[1]; - temp_idx = 1; - } - else { - temp_varp = &do_gtod.vars[0]; - temp_idx = 0; - } + temp_idx = (do_gtod.var_idx == 0); + temp_varp = &do_gtod.vars[temp_idx]; + temp_varp->tb_to_xs = new_tb_to_xs; temp_varp->stamp_xsec = new_stamp_xsec; + temp_varp->tb_orig_stamp = do_gtod.varp->tb_orig_stamp; mb(); do_gtod.varp = temp_varp; do_gtod.var_idx = temp_idx; diff --git a/arch/ppc64/kernel/vdso.c b/arch/ppc64/kernel/vdso.c new file mode 100644 index 000000000000..8c4597224b71 --- /dev/null +++ b/arch/ppc64/kernel/vdso.c @@ -0,0 +1,614 @@ +/* + * linux/arch/ppc64/kernel/vdso.c + * + * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt...) printk(fmt) +#else +#define DBG(fmt...) +#endif + + +/* + * The vDSOs themselves are here + */ +extern char vdso64_start, vdso64_end; +extern char vdso32_start, vdso32_end; + +static void *vdso64_kbase = &vdso64_start; +static void *vdso32_kbase = &vdso32_start; + +unsigned int vdso64_pages; +unsigned int vdso32_pages; + +/* Signal trampolines user addresses */ + +unsigned long vdso64_rt_sigtramp; +unsigned long vdso32_sigtramp; +unsigned long vdso32_rt_sigtramp; + +/* Format of the patch table */ +struct vdso_patch_def +{ + u32 pvr_mask, pvr_value; + const char *gen_name; + const char *fix_name; +}; + +/* Table of functions to patch based on the CPU type/revision + * + * TODO: Improve by adding whole lists for each entry + */ +static struct vdso_patch_def vdso_patches[] = { + { + 0xffff0000, 0x003a0000, /* POWER5 */ + "__kernel_sync_dicache", "__kernel_sync_dicache_p5" + }, + { + 0xffff0000, 0x003b0000, /* POWER5 */ + "__kernel_sync_dicache", "__kernel_sync_dicache_p5" + }, +}; + +/* + * Some infos carried around for each of them during parsing at + * boot time. + */ +struct lib32_elfinfo +{ + Elf32_Ehdr *hdr; /* ptr to ELF */ + Elf32_Sym *dynsym; /* ptr to .dynsym section */ + unsigned long dynsymsize; /* size of .dynsym section */ + char *dynstr; /* ptr to .dynstr section */ + unsigned long text; /* offset of .text section in .so */ +}; + +struct lib64_elfinfo +{ + Elf64_Ehdr *hdr; + Elf64_Sym *dynsym; + unsigned long dynsymsize; + char *dynstr; + unsigned long text; +}; + + +#ifdef __DEBUG +static void dump_one_vdso_page(struct page *pg, struct page *upg) +{ + printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT), + page_count(pg), + pg->flags); + if (upg/* && pg != upg*/) { + printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg) << PAGE_SHIFT), + page_count(upg), + upg->flags); + } + printk("\n"); +} + +static void dump_vdso_pages(struct vm_area_struct * vma) +{ + int i; + + if (!vma || test_thread_flag(TIF_32BIT)) { + printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase); + for (i=0; ivm_mm) ? + follow_page(vma->vm_mm, vma->vm_start + i*PAGE_SIZE, 0) + : NULL; + dump_one_vdso_page(pg, upg); + } + } + if (!vma || !test_thread_flag(TIF_32BIT)) { + printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase); + for (i=0; ivm_mm) ? + follow_page(vma->vm_mm, vma->vm_start + i*PAGE_SIZE, 0) + : NULL; + dump_one_vdso_page(pg, upg); + } + } +} +#endif /* DEBUG */ + +/* + * Keep a dummy vma_close for now, it will prevent VMA merging. + */ +static void vdso_vma_close(struct vm_area_struct * vma) +{ +} + +/* + * Our nopage() function, maps in the actual vDSO kernel pages, they will + * be mapped read-only by do_no_page(), and eventually COW'ed, either + * right away for an initial write access, or by do_wp_page(). + */ +static struct page * vdso_vma_nopage(struct vm_area_struct * vma, + unsigned long address, int *type) +{ + unsigned long offset = address - vma->vm_start; + struct page *pg; + void *vbase = test_thread_flag(TIF_32BIT) ? vdso32_kbase : vdso64_kbase; + + DBG("vdso_vma_nopage(current: %s, address: %016lx, off: %lx)\n", + current->comm, address, offset); + + if (address < vma->vm_start || address > vma->vm_end) + return NOPAGE_SIGBUS; + + /* + * Last page is systemcfg, special handling here, no get_page() a + * this is a reserved page + */ + if ((vma->vm_end - address) <= PAGE_SIZE) + return virt_to_page(systemcfg); + + pg = virt_to_page(vbase + offset); + get_page(pg); + DBG(" ->page count: %d\n", page_count(pg)); + + return pg; +} + +static struct vm_operations_struct vdso_vmops = { + .close = vdso_vma_close, + .nopage = vdso_vma_nopage, +}; + +/* + * This is called from binfmt_elf, we create the special vma for the + * vDSO and insert it into the mm struct tree + */ +int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long vdso_pages; + unsigned long vdso_base; + + if (test_thread_flag(TIF_32BIT)) { + vdso_pages = vdso32_pages; + vdso_base = VDSO32_MBASE; + } else { + vdso_pages = vdso64_pages; + vdso_base = VDSO64_MBASE; + } + + /* vDSO has a problem and was disabled, just don't "enable" it for the + * process + */ + if (vdso_pages == 0) { + current->thread.vdso_base = 0; + return 0; + } + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma == NULL) + return -ENOMEM; + if (security_vm_enough_memory(vdso_pages)) { + kmem_cache_free(vm_area_cachep, vma); + return -ENOMEM; + } + memset(vma, 0, sizeof(*vma)); + + /* + * pick a base address for the vDSO in process space. We have a default + * base of 1Mb on which we had a random offset up to 1Mb. + * XXX: Add possibility for a program header to specify that location + */ + current->thread.vdso_base = vdso_base; + /* + ((unsigned long)vma & 0x000ff000); */ + + vma->vm_mm = mm; + vma->vm_start = current->thread.vdso_base; + + /* + * the VMA size is one page more than the vDSO since systemcfg + * is mapped in the last one + */ + vma->vm_end = vma->vm_start + ((vdso_pages + 1) << PAGE_SHIFT); + + /* + * our vma flags don't have VM_WRITE so by default, the process isn't allowed + * to write those pages. + * gdb can break that with ptrace interface, and thus trigger COW on those + * pages but it's then your responsibility to never do that on the "data" page + * of the vDSO or you'll stop getting kernel updates and your nice userland + * gettimeofday will be totally dead. It's fine to use that for setting + * breakpoints in the vDSO code pages though + */ + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; + vma->vm_flags |= mm->def_flags; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; + vma->vm_ops = &vdso_vmops; + + down_write(&mm->mmap_sem); + insert_vm_struct(mm, vma); + mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + up_write(&mm->mmap_sem); + + return 0; +} + +static void * __init find_section32(Elf32_Ehdr *ehdr, const char *secname, + unsigned long *size) +{ + Elf32_Shdr *sechdrs; + unsigned int i; + char *secnames; + + /* Grab section headers and strings so we can tell who is who */ + sechdrs = (void *)ehdr + ehdr->e_shoff; + secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset; + + /* Find the section they want */ + for (i = 1; i < ehdr->e_shnum; i++) { + if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) { + if (size) + *size = sechdrs[i].sh_size; + return (void *)ehdr + sechdrs[i].sh_offset; + } + } + *size = 0; + return NULL; +} + +static void * __init find_section64(Elf64_Ehdr *ehdr, const char *secname, + unsigned long *size) +{ + Elf64_Shdr *sechdrs; + unsigned int i; + char *secnames; + + /* Grab section headers and strings so we can tell who is who */ + sechdrs = (void *)ehdr + ehdr->e_shoff; + secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset; + + /* Find the section they want */ + for (i = 1; i < ehdr->e_shnum; i++) { + if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) { + if (size) + *size = sechdrs[i].sh_size; + return (void *)ehdr + sechdrs[i].sh_offset; + } + } + if (size) + *size = 0; + return NULL; +} + +static Elf32_Sym * __init find_symbol32(struct lib32_elfinfo *lib, const char *symname) +{ + unsigned int i; + char name[32], *c; + + for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) { + if (lib->dynsym[i].st_name == 0) + continue; + strlcpy(name, lib->dynstr + lib->dynsym[i].st_name, 32); + c = strchr(name, '@'); + if (c) + *c = 0; + if (strcmp(symname, name) == 0) + return &lib->dynsym[i]; + } + return NULL; +} + +static Elf64_Sym * __init find_symbol64(struct lib64_elfinfo *lib, const char *symname) +{ + unsigned int i; + char name[32], *c; + + for (i = 0; i < (lib->dynsymsize / sizeof(Elf64_Sym)); i++) { + if (lib->dynsym[i].st_name == 0) + continue; + strlcpy(name, lib->dynstr + lib->dynsym[i].st_name, 32); + c = strchr(name, '@'); + if (c) + *c = 0; + if (strcmp(symname, name) == 0) + return &lib->dynsym[i]; + } + return NULL; +} + +/* Note that we assume the section is .text and the symbol is relative to + * the library base + */ +static unsigned long __init find_function32(struct lib32_elfinfo *lib, const char *symname) +{ + Elf32_Sym *sym = find_symbol32(lib, symname); + + if (sym == NULL) { + printk(KERN_WARNING "vDSO32: function %s not found !\n", symname); + return 0; + } + return sym->st_value - VDSO32_LBASE; +} + +/* Note that we assume the section is .text and the symbol is relative to + * the library base + */ +static unsigned long __init find_function64(struct lib64_elfinfo *lib, const char *symname) +{ + Elf64_Sym *sym = find_symbol64(lib, symname); + + if (sym == NULL) { + printk(KERN_WARNING "vDSO64: function %s not found !\n", symname); + return 0; + } +#ifdef VDS64_HAS_DESCRIPTORS + return *((u64 *)(vdso64_kbase + sym->st_value - VDSO64_LBASE)) - VDSO64_LBASE; +#else + return sym->st_value - VDSO64_LBASE; +#endif +} + + +static __init int vdso_do_find_sections(struct lib32_elfinfo *v32, + struct lib64_elfinfo *v64) +{ + void *sect; + + /* + * Locate symbol tables & text section + */ + + v32->dynsym = find_section32(v32->hdr, ".dynsym", &v32->dynsymsize); + v32->dynstr = find_section32(v32->hdr, ".dynstr", NULL); + if (v32->dynsym == NULL || v32->dynstr == NULL) { + printk(KERN_ERR "vDSO32: a required symbol section was not found\n"); + return -1; + } + sect = find_section32(v32->hdr, ".text", NULL); + if (sect == NULL) { + printk(KERN_ERR "vDSO32: the .text section was not found\n"); + return -1; + } + v32->text = sect - vdso32_kbase; + + v64->dynsym = find_section64(v64->hdr, ".dynsym", &v64->dynsymsize); + v64->dynstr = find_section64(v64->hdr, ".dynstr", NULL); + if (v64->dynsym == NULL || v64->dynstr == NULL) { + printk(KERN_ERR "vDSO64: a required symbol section was not found\n"); + return -1; + } + sect = find_section64(v64->hdr, ".text", NULL); + if (sect == NULL) { + printk(KERN_ERR "vDSO64: the .text section was not found\n"); + return -1; + } + v64->text = sect - vdso64_kbase; + + return 0; +} + +static __init void vdso_setup_trampolines(struct lib32_elfinfo *v32, + struct lib64_elfinfo *v64) +{ + /* + * Find signal trampolines + */ + + vdso64_rt_sigtramp = find_function64(v64, "__kernel_sigtramp_rt64"); + vdso32_sigtramp = find_function32(v32, "__kernel_sigtramp32"); + vdso32_rt_sigtramp = find_function32(v32, "__kernel_sigtramp_rt32"); +} + +static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32, + struct lib64_elfinfo *v64) +{ + Elf32_Sym *sym32; + Elf64_Sym *sym64; + + sym32 = find_symbol32(v32, "__kernel_datapage_offset"); + if (sym32 == NULL) { + printk(KERN_ERR "vDSO32: Can't find symbol __kernel_datapage_offset !\n"); + return -1; + } + *((int *)(vdso32_kbase + (sym32->st_value - VDSO32_LBASE))) = + (vdso32_pages << PAGE_SHIFT) - (sym32->st_value - VDSO32_LBASE); + + sym64 = find_symbol64(v64, "__kernel_datapage_offset"); + if (sym64 == NULL) { + printk(KERN_ERR "vDSO64: Can't find symbol __kernel_datapage_offset !\n"); + return -1; + } + *((int *)(vdso64_kbase + sym64->st_value - VDSO64_LBASE)) = + (vdso64_pages << PAGE_SHIFT) - (sym64->st_value - VDSO64_LBASE); + + return 0; +} + +static int vdso_do_func_patch32(struct lib32_elfinfo *v32, + struct lib64_elfinfo *v64, + const char *orig, const char *fix) +{ + Elf32_Sym *sym32_gen, *sym32_fix; + + sym32_gen = find_symbol32(v32, orig); + if (sym32_gen == NULL) { + printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", orig); + return -1; + } + sym32_fix = find_symbol32(v32, fix); + if (sym32_fix == NULL) { + printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", fix); + return -1; + } + sym32_gen->st_value = sym32_fix->st_value; + sym32_gen->st_size = sym32_fix->st_size; + sym32_gen->st_info = sym32_fix->st_info; + sym32_gen->st_other = sym32_fix->st_other; + sym32_gen->st_shndx = sym32_fix->st_shndx; + + return 0; +} + +static int vdso_do_func_patch64(struct lib32_elfinfo *v32, + struct lib64_elfinfo *v64, + const char *orig, const char *fix) +{ + Elf64_Sym *sym64_gen, *sym64_fix; + + sym64_gen = find_symbol64(v64, orig); + if (sym64_gen == NULL) { + printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", orig); + return -1; + } + sym64_fix = find_symbol64(v64, fix); + if (sym64_fix == NULL) { + printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", fix); + return -1; + } + sym64_gen->st_value = sym64_fix->st_value; + sym64_gen->st_size = sym64_fix->st_size; + sym64_gen->st_info = sym64_fix->st_info; + sym64_gen->st_other = sym64_fix->st_other; + sym64_gen->st_shndx = sym64_fix->st_shndx; + + return 0; +} + +static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32, + struct lib64_elfinfo *v64) +{ + u32 pvr; + int i; + + pvr = mfspr(SPRN_PVR); + for (i = 0; i < ARRAY_SIZE(vdso_patches); i++) { + struct vdso_patch_def *patch = &vdso_patches[i]; + int match = (pvr & patch->pvr_mask) == patch->pvr_value; + + DBG("patch %d (mask: %x, pvr: %x) : %s\n", + i, patch->pvr_mask, patch->pvr_value, match ? "match" : "skip"); + + if (!match) + continue; + + DBG("replacing %s with %s...\n", patch->gen_name, patch->fix_name); + + /* + * Patch the 32 bits and 64 bits symbols. Note that we do not patch + * the "." symbol on 64 bits. It would be easy to do, but doesn't + * seem to be necessary, patching the OPD symbol is enough. + */ + vdso_do_func_patch32(v32, v64, patch->gen_name, patch->fix_name); + vdso_do_func_patch64(v32, v64, patch->gen_name, patch->fix_name); + } + + return 0; +} + + +static __init int vdso_setup(void) +{ + struct lib32_elfinfo v32; + struct lib64_elfinfo v64; + + v32.hdr = vdso32_kbase; + v64.hdr = vdso64_kbase; + + if (vdso_do_find_sections(&v32, &v64)) + return -1; + + if (vdso_fixup_datapage(&v32, &v64)) + return -1; + + if (vdso_fixup_alt_funcs(&v32, &v64)) + return -1; + + vdso_setup_trampolines(&v32, &v64); + + return 0; +} + +void __init vdso_init(void) +{ + int i; + + vdso64_pages = (&vdso64_end - &vdso64_start) >> PAGE_SHIFT; + vdso32_pages = (&vdso32_end - &vdso32_start) >> PAGE_SHIFT; + + DBG("vdso64_kbase: %p, 0x%x pages, vdso32_kbase: %p, 0x%x pages\n", + vdso64_kbase, vdso64_pages, vdso32_kbase, vdso32_pages); + + /* + * Initialize the vDSO images in memory, that is do necessary + * fixups of vDSO symbols, locate trampolines, etc... + */ + if (vdso_setup()) { + printk(KERN_ERR "vDSO setup failure, not enabled !\n"); + /* XXX should free pages here ? */ + vdso64_pages = vdso32_pages = 0; + return; + } + + /* Make sure pages are in the correct state */ + for (i = 0; i < vdso64_pages; i++) { + struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE); + ClearPageReserved(pg); + get_page(pg); + } + for (i = 0; i < vdso32_pages; i++) { + struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE); + ClearPageReserved(pg); + get_page(pg); + } +} + +int in_gate_area_no_task(unsigned long addr) +{ + return 0; +} + +int in_gate_area(struct task_struct *task, unsigned long addr) +{ + return 0; +} + +struct vm_area_struct *get_gate_vma(struct task_struct *tsk) +{ + return NULL; +} + diff --git a/arch/ppc64/kernel/vdso32/Makefile b/arch/ppc64/kernel/vdso32/Makefile new file mode 100644 index 000000000000..ede2f7e477c2 --- /dev/null +++ b/arch/ppc64/kernel/vdso32/Makefile @@ -0,0 +1,36 @@ + +# List of files in the vdso, has to be asm only for now + +obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o + +# Build rules + +targets := $(obj-vdso32) vdso32.so +obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32)) + + +EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin +EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 +EXTRA_AFLAGS := -D__VDSO32__ -s + +obj-y += vdso32_wrapper.o +extra-y += vdso32.lds +CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) + +# Force dependency (incbin is bad) +$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so + +# link rule for the .so file, .lds has to be first +$(obj)/vdso32.so: $(src)/vdso32.lds $(obj-vdso32) + $(call if_changed,vdso32ld) + +# assembly rules for the .S files +$(obj-vdso32): %.o: %.S + $(call if_changed_dep,vdso32as) + +# actual build commands +quiet_cmd_vdso32ld = VDSO32L $@ + cmd_vdso32ld = $(CROSS32CC) $(c_flags) -Wl,-T $^ -o $@ +quiet_cmd_vdso32as = VDSO32A $@ + cmd_vdso32as = $(CROSS32CC) $(a_flags) -c -o $@ $< + diff --git a/arch/ppc64/kernel/vdso32/cacheflush.S b/arch/ppc64/kernel/vdso32/cacheflush.S new file mode 100644 index 000000000000..c74fddb6afd4 --- /dev/null +++ b/arch/ppc64/kernel/vdso32/cacheflush.S @@ -0,0 +1,65 @@ +/* + * vDSO provided cache flush routines + * + * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), + * IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include + + .text + +/* + * Default "generic" version of __kernel_sync_dicache. + * + * void __kernel_sync_dicache(unsigned long start, unsigned long end) + * + * Flushes the data cache & invalidate the instruction cache for the + * provided range [start, end[ + * + * Note: all CPUs supported by this kernel have a 128 bytes cache + * line size so we don't have to peek that info from the datapage + */ +V_FUNCTION_BEGIN(__kernel_sync_dicache) + .cfi_startproc + li r5,127 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + srwi. r8,r8,7 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 + mr r3,r6 +1: dcbst 0,r3 + addi r3,r3,128 + bdnz 1b + sync + mtctr r8 +1: icbi 0,r6 + addi r6,r6,128 + bdnz 1b + isync + blr + .cfi_endproc +V_FUNCTION_END(__kernel_sync_dicache) + + +/* + * POWER5 version of __kernel_sync_dicache + */ +V_FUNCTION_BEGIN(__kernel_sync_dicache_p5) + .cfi_startproc + sync + isync + blr + .cfi_endproc +V_FUNCTION_END(__kernel_sync_dicache_p5) + diff --git a/arch/ppc64/kernel/vdso32/datapage.S b/arch/ppc64/kernel/vdso32/datapage.S new file mode 100644 index 000000000000..29b6bd32e1f1 --- /dev/null +++ b/arch/ppc64/kernel/vdso32/datapage.S @@ -0,0 +1,68 @@ +/* + * Access to the shared data page by the vDSO & syscall map + * + * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + + .text +V_FUNCTION_BEGIN(__get_datapage) + .cfi_startproc + /* We don't want that exposed or overridable as we want other objects + * to be able to bl directly to here + */ + .protected __get_datapage + .hidden __get_datapage + + mflr r0 + .cfi_register lr,r0 + + bcl 20,31,1f + .global __kernel_datapage_offset; +__kernel_datapage_offset: + .long 0 +1: + mflr r3 + mtlr r0 + lwz r0,0(r3) + add r3,r0,r3 + blr + .cfi_endproc +V_FUNCTION_END(__get_datapage) + +/* + * void *__kernel_get_syscall_map(unsigned int *syscall_count) ; + * + * returns a pointer to the syscall map. the map is agnostic to the + * size of "long", unlike kernel bitops, it stores bits from top to + * bottom so that memory actually contains a linear bitmap + * check for syscall N by testing bit (0x80000000 >> (N & 0x1f)) of + * 32 bits int at N >> 5. + */ +V_FUNCTION_BEGIN(__kernel_get_syscall_map) + .cfi_startproc + mflr r12 + .cfi_register lr,r12 + + mr r4,r3 + bl __get_datapage@local + mtlr r12 + addi r3,r3,CFG_SYSCALL_MAP32 + cmpli cr0,r4,0 + beqlr + li r0,__NR_syscalls + stw r0,0(r4) + blr + .cfi_endproc +V_FUNCTION_END(__kernel_get_syscall_map) diff --git a/arch/ppc64/kernel/vdso32/gettimeofday.S b/arch/ppc64/kernel/vdso32/gettimeofday.S new file mode 100644 index 000000000000..ca7f415195c4 --- /dev/null +++ b/arch/ppc64/kernel/vdso32/gettimeofday.S @@ -0,0 +1,139 @@ +/* + * Userland implementation of gettimeofday() for 32 bits processes in a + * ppc64 kernel for use in the vDSO + * + * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include + + .text +/* + * Exact prototype of gettimeofday + * + * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); + * + */ +V_FUNCTION_BEGIN(__kernel_gettimeofday) + .cfi_startproc + mflr r12 + .cfi_register lr,r12 + + mr r10,r3 /* r10 saves tv */ + mr r11,r4 /* r11 saves tz */ + bl __get_datapage@local /* get data page */ + mr r9, r3 /* datapage ptr in r9 */ + bl __do_get_xsec@local /* get xsec from tb & kernel */ + bne- 2f /* out of line -> do syscall */ + + /* seconds are xsec >> 20 */ + rlwinm r5,r4,12,20,31 + rlwimi r5,r3,12,0,19 + stw r5,TVAL32_TV_SEC(r10) + + /* get remaining xsec and convert to usec. we scale + * up remaining xsec by 12 bits and get the top 32 bits + * of the multiplication + */ + rlwinm r5,r4,12,0,19 + lis r6,1000000@h + ori r6,r6,1000000@l + mulhwu r5,r5,r6 + stw r5,TVAL32_TV_USEC(r10) + + cmpli cr0,r11,0 /* check if tz is NULL */ + beq 1f + lwz r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */ + lwz r5,CFG_TZ_DSTTIME(r9) + stw r4,TZONE_TZ_MINWEST(r11) + stw r5,TZONE_TZ_DSTTIME(r11) + +1: mtlr r12 + blr + +2: mr r3,r10 + mr r4,r11 + li r0,__NR_gettimeofday + sc + b 1b + .cfi_endproc +V_FUNCTION_END(__kernel_gettimeofday) + +/* + * This is the core of gettimeofday(), it returns the xsec + * value in r3 & r4 and expects the datapage ptr (non clobbered) + * in r9. clobbers r0,r4,r5,r6,r7,r8 +*/ +__do_get_xsec: + .cfi_startproc + /* Check for update count & load values. We use the low + * order 32 bits of the update count + */ +1: lwz r8,(CFG_TB_UPDATE_COUNT+4)(r9) + andi. r0,r8,1 /* pending update ? loop */ + bne- 1b + xor r0,r8,r8 /* create dependency */ + add r9,r9,r0 + + /* Load orig stamp (offset to TB) */ + lwz r5,CFG_TB_ORIG_STAMP(r9) + lwz r6,(CFG_TB_ORIG_STAMP+4)(r9) + + /* Get a stable TB value */ +2: mftbu r3 + mftbl r4 + mftbu r0 + cmpl cr0,r3,r0 + bne- 2b + + /* Substract tb orig stamp. If the high part is non-zero, we jump to the + * slow path which call the syscall. If it's ok, then we have our 32 bits + * tb_ticks value in r7 + */ + subfc r7,r6,r4 + subfe. r0,r5,r3 + bne- 3f + + /* Load scale factor & do multiplication */ + lwz r5,CFG_TB_TO_XS(r9) /* load values */ + lwz r6,(CFG_TB_TO_XS+4)(r9) + mulhwu r4,r7,r5 + mulhwu r6,r7,r6 + mullw r6,r7,r5 + addc r6,r6,r0 + + /* At this point, we have the scaled xsec value in r4 + XER:CA + * we load & add the stamp since epoch + */ + lwz r5,CFG_STAMP_XSEC(r9) + lwz r6,(CFG_STAMP_XSEC+4)(r9) + adde r4,r4,r6 + addze r3,r5 + + /* We now have our result in r3,r4. We create a fake dependency + * on that result and re-check the counter + */ + xor r0,r4,r4 + add r9,r9,r0 + lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9) + cmpl cr0,r8,r0 /* check if updated */ + bne- 1b + + /* Warning ! The caller expects CR:EQ to be set to indicate a + * successful calculation (so it won't fallback to the syscall + * method). We have overriden that CR bit in the counter check, + * but fortunately, the loop exit condition _is_ CR:EQ set, so + * we can exit safely here. If you change this code, be careful + * of that side effect. + */ +3: blr + .cfi_endproc diff --git a/arch/ppc64/kernel/vdso32/sigtramp.S b/arch/ppc64/kernel/vdso32/sigtramp.S new file mode 100644 index 000000000000..e04642781917 --- /dev/null +++ b/arch/ppc64/kernel/vdso32/sigtramp.S @@ -0,0 +1,300 @@ +/* + * Signal trampolines for 32 bits processes in a ppc64 kernel for + * use in the vDSO + * + * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp. + * Copyright (C) 2004 Alan Modra (amodra@au.ibm.com)), IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include + + .text + +/* The nop here is a hack. The dwarf2 unwind routines subtract 1 from + the return address to get an address in the middle of the presumed + call instruction. Since we don't have a call here, we artifically + extend the range covered by the unwind info by adding a nop before + the real start. */ + nop +V_FUNCTION_BEGIN(__kernel_sigtramp32) +.Lsig_start = . - 4 + li r0,__NR_sigreturn + sc +.Lsig_end: +V_FUNCTION_END(__kernel_sigtramp32) + +.Lsigrt_start: + nop +V_FUNCTION_BEGIN(__kernel_sigtramp_rt32) + li r0,__NR_rt_sigreturn + sc +.Lsigrt_end: +V_FUNCTION_END(__kernel_sigtramp_rt32) + + .section .eh_frame,"a",@progbits + +/* Register r1 can be found at offset 4 of a pt_regs structure. + A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */ +#define cfa_save \ + .byte 0x0f; /* DW_CFA_def_cfa_expression */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x23; .uleb128 RSIZE; /* DW_OP_plus_uconst */ \ + .byte 0x06; /* DW_OP_deref */ \ +9: + +/* Register REGNO can be found at offset OFS of a pt_regs structure. + A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */ +#define rsave(regno, ofs) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ + .byte 0x06; /* DW_OP_deref */ \ + .ifne ofs; \ + .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \ + .endif; \ +9: + +/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16 + of the VMX reg struct. The VMX reg struct is at offset VREGS of + the pt_regs struct. This macro is for REGNO == 0, and contains + 'subroutines' that the other macros jump to. */ +#define vsave_msr0(regno) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno + 77; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x30 + regno; /* DW_OP_lit0 */ \ +2: \ + .byte 0x40; /* DW_OP_lit16 */ \ + .byte 0x1e; /* DW_OP_mul */ \ +3: \ + .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x12; /* DW_OP_dup */ \ + .byte 0x23; /* DW_OP_plus_uconst */ \ + .uleb128 33*RSIZE; /* msr offset */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x0c; .long 1 << 25; /* DW_OP_const4u */ \ + .byte 0x1a; /* DW_OP_and */ \ + .byte 0x12; /* DW_OP_dup, ret 0 if bra taken */ \ + .byte 0x30; /* DW_OP_lit0 */ \ + .byte 0x29; /* DW_OP_eq */ \ + .byte 0x28; .short 0x7fff; /* DW_OP_bra to end */ \ + .byte 0x13; /* DW_OP_drop, pop the 0 */ \ + .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \ + .byte 0x22; /* DW_OP_plus */ \ + .byte 0x2f; .short 0x7fff; /* DW_OP_skip to end */ \ +9: + +/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16 + of the VMX reg struct. REGNO is 1 thru 31. */ +#define vsave_msr1(regno) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno + 77; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x30 + regno; /* DW_OP_lit n */ \ + .byte 0x2f; .short 2b - 9f; /* DW_OP_skip */ \ +9: + +/* If msr bit 1<<25 is set, then VMX register REGNO is at offset OFS of + the VMX save block. */ +#define vsave_msr2(regno, ofs) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno + 77; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x0a; .short ofs; /* DW_OP_const2u */ \ + .byte 0x2f; .short 3b - 9f; /* DW_OP_skip */ \ +9: + +/* VMX register REGNO is at offset OFS of the VMX save area. */ +#define vsave(regno, ofs) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno + 77; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \ + .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \ +9: + +/* This is where the pt_regs pointer can be found on the stack. */ +#define PTREGS 64+28 + +/* Size of regs. */ +#define RSIZE 4 + +/* This is the offset of the VMX regs. */ +#define VREGS 48*RSIZE+34*8 + +/* Describe where general purpose regs are saved. */ +#define EH_FRAME_GEN \ + cfa_save; \ + rsave ( 0, 0*RSIZE); \ + rsave ( 2, 2*RSIZE); \ + rsave ( 3, 3*RSIZE); \ + rsave ( 4, 4*RSIZE); \ + rsave ( 5, 5*RSIZE); \ + rsave ( 6, 6*RSIZE); \ + rsave ( 7, 7*RSIZE); \ + rsave ( 8, 8*RSIZE); \ + rsave ( 9, 9*RSIZE); \ + rsave (10, 10*RSIZE); \ + rsave (11, 11*RSIZE); \ + rsave (12, 12*RSIZE); \ + rsave (13, 13*RSIZE); \ + rsave (14, 14*RSIZE); \ + rsave (15, 15*RSIZE); \ + rsave (16, 16*RSIZE); \ + rsave (17, 17*RSIZE); \ + rsave (18, 18*RSIZE); \ + rsave (19, 19*RSIZE); \ + rsave (20, 20*RSIZE); \ + rsave (21, 21*RSIZE); \ + rsave (22, 22*RSIZE); \ + rsave (23, 23*RSIZE); \ + rsave (24, 24*RSIZE); \ + rsave (25, 25*RSIZE); \ + rsave (26, 26*RSIZE); \ + rsave (27, 27*RSIZE); \ + rsave (28, 28*RSIZE); \ + rsave (29, 29*RSIZE); \ + rsave (30, 30*RSIZE); \ + rsave (31, 31*RSIZE); \ + rsave (67, 32*RSIZE); /* ap, used as temp for nip */ \ + rsave (65, 36*RSIZE); /* lr */ \ + rsave (70, 38*RSIZE) /* cr */ + +/* Describe where the FP regs are saved. */ +#define EH_FRAME_FP \ + rsave (32, 48*RSIZE + 0*8); \ + rsave (33, 48*RSIZE + 1*8); \ + rsave (34, 48*RSIZE + 2*8); \ + rsave (35, 48*RSIZE + 3*8); \ + rsave (36, 48*RSIZE + 4*8); \ + rsave (37, 48*RSIZE + 5*8); \ + rsave (38, 48*RSIZE + 6*8); \ + rsave (39, 48*RSIZE + 7*8); \ + rsave (40, 48*RSIZE + 8*8); \ + rsave (41, 48*RSIZE + 9*8); \ + rsave (42, 48*RSIZE + 10*8); \ + rsave (43, 48*RSIZE + 11*8); \ + rsave (44, 48*RSIZE + 12*8); \ + rsave (45, 48*RSIZE + 13*8); \ + rsave (46, 48*RSIZE + 14*8); \ + rsave (47, 48*RSIZE + 15*8); \ + rsave (48, 48*RSIZE + 16*8); \ + rsave (49, 48*RSIZE + 17*8); \ + rsave (50, 48*RSIZE + 18*8); \ + rsave (51, 48*RSIZE + 19*8); \ + rsave (52, 48*RSIZE + 20*8); \ + rsave (53, 48*RSIZE + 21*8); \ + rsave (54, 48*RSIZE + 22*8); \ + rsave (55, 48*RSIZE + 23*8); \ + rsave (56, 48*RSIZE + 24*8); \ + rsave (57, 48*RSIZE + 25*8); \ + rsave (58, 48*RSIZE + 26*8); \ + rsave (59, 48*RSIZE + 27*8); \ + rsave (60, 48*RSIZE + 28*8); \ + rsave (61, 48*RSIZE + 29*8); \ + rsave (62, 48*RSIZE + 30*8); \ + rsave (63, 48*RSIZE + 31*8) + +/* Describe where the VMX regs are saved. */ +#ifdef CONFIG_ALTIVEC +#define EH_FRAME_VMX \ + vsave_msr0 ( 0); \ + vsave_msr1 ( 1); \ + vsave_msr1 ( 2); \ + vsave_msr1 ( 3); \ + vsave_msr1 ( 4); \ + vsave_msr1 ( 5); \ + vsave_msr1 ( 6); \ + vsave_msr1 ( 7); \ + vsave_msr1 ( 8); \ + vsave_msr1 ( 9); \ + vsave_msr1 (10); \ + vsave_msr1 (11); \ + vsave_msr1 (12); \ + vsave_msr1 (13); \ + vsave_msr1 (14); \ + vsave_msr1 (15); \ + vsave_msr1 (16); \ + vsave_msr1 (17); \ + vsave_msr1 (18); \ + vsave_msr1 (19); \ + vsave_msr1 (20); \ + vsave_msr1 (21); \ + vsave_msr1 (22); \ + vsave_msr1 (23); \ + vsave_msr1 (24); \ + vsave_msr1 (25); \ + vsave_msr1 (26); \ + vsave_msr1 (27); \ + vsave_msr1 (28); \ + vsave_msr1 (29); \ + vsave_msr1 (30); \ + vsave_msr1 (31); \ + vsave_msr2 (33, 32*16+12); \ + vsave (32, 32*16) +#else +#define EH_FRAME_VMX +#endif + +.Lcie: + .long .Lcie_end - .Lcie_start +.Lcie_start: + .long 0 /* CIE ID */ + .byte 1 /* Version number */ + .string "zR" /* NUL-terminated augmentation string */ + .uleb128 4 /* Code alignment factor */ + .sleb128 -4 /* Data alignment factor */ + .byte 67 /* Return address register column, ap */ + .uleb128 1 /* Augmentation value length */ + .byte 0x1b /* DW_EH_PE_pcrel | DW_EH_PE_sdata4. */ + .byte 0x0c,1,0 /* DW_CFA_def_cfa: r1 ofs 0 */ + .balign 4 +.Lcie_end: + + .long .Lfde0_end - .Lfde0_start +.Lfde0_start: + .long .Lfde0_start - .Lcie /* CIE pointer. */ + .long .Lsig_start - . /* PC start, length */ + .long .Lsig_end - .Lsig_start + .uleb128 0 /* Augmentation */ + EH_FRAME_GEN + EH_FRAME_FP + EH_FRAME_VMX + .balign 4 +.Lfde0_end: + +/* We have a different stack layout for rt_sigreturn. */ +#undef PTREGS +#define PTREGS 64+16+128+20+28 + + .long .Lfde1_end - .Lfde1_start +.Lfde1_start: + .long .Lfde1_start - .Lcie /* CIE pointer. */ + .long .Lsigrt_start - . /* PC start, length */ + .long .Lsigrt_end - .Lsigrt_start + .uleb128 0 /* Augmentation */ + EH_FRAME_GEN + EH_FRAME_FP + EH_FRAME_VMX + .balign 4 +.Lfde1_end: diff --git a/arch/ppc64/kernel/vdso32/vdso32.lds.S b/arch/ppc64/kernel/vdso32/vdso32.lds.S new file mode 100644 index 000000000000..cca27bd03a57 --- /dev/null +++ b/arch/ppc64/kernel/vdso32/vdso32.lds.S @@ -0,0 +1,111 @@ + +/* + * This is the infamous ld script for the 32 bits vdso + * library + */ +#include + +/* Default link addresses for the vDSOs */ +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH(powerpc:common) +ENTRY(_start) + +SECTIONS +{ + . = VDSO32_LBASE + SIZEOF_HEADERS; + .hash : { *(.hash) } :text + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + . = ALIGN (16); + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + /* Other stuff is appended to the text segment: */ + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + .gcc_except_table : { *(.gcc_except_table) } + .fixup : { *(.fixup) } + + .got ALIGN(4) : { *(.got.plt) *(.got) } + + .dynamic : { *(.dynamic) } :text :dynamic + + _end = .; + __end = .; + PROVIDE (end = .); + + + /* Stabs debugging sections are here too + */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + /DISCARD/ : { *(.note.GNU-stack) } + /DISCARD/ : { *(.data .data.* .gnu.linkonce.d.* .sdata*) } + /DISCARD/ : { *(.bss .sbss .dynbss .dynsbss) } +} + + +PHDRS +{ + text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ +} + + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + VDSO_VERSION_STRING { + global: + __kernel_datapage_offset; /* Has to be there for the kernel to find it */ + __kernel_get_syscall_map; + __kernel_gettimeofday; + __kernel_sync_dicache; + __kernel_sync_dicache_p5; + __kernel_sigtramp32; + __kernel_sigtramp_rt32; + local: *; + }; +} diff --git a/arch/ppc64/kernel/vdso32/vdso32_wrapper.S b/arch/ppc64/kernel/vdso32/vdso32_wrapper.S new file mode 100644 index 000000000000..76ca28e09d29 --- /dev/null +++ b/arch/ppc64/kernel/vdso32/vdso32_wrapper.S @@ -0,0 +1,13 @@ +#include +#include + + .section ".data.page_aligned" + + .globl vdso32_start, vdso32_end + .balign PAGE_SIZE +vdso32_start: + .incbin "arch/ppc64/kernel/vdso32/vdso32.so" + .balign PAGE_SIZE +vdso32_end: + + .previous diff --git a/arch/ppc64/kernel/vdso64/Makefile b/arch/ppc64/kernel/vdso64/Makefile new file mode 100644 index 000000000000..bd3f70b1a384 --- /dev/null +++ b/arch/ppc64/kernel/vdso64/Makefile @@ -0,0 +1,35 @@ +# List of files in the vdso, has to be asm only for now + +obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o + +# Build rules + +targets := $(obj-vdso64) vdso64.so +obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64)) + +EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin +EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1 +EXTRA_AFLAGS := -D__VDSO64__ -s + +obj-y += vdso64_wrapper.o +extra-y += vdso64.lds +CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) + +# Force dependency (incbin is bad) +$(obj)/vdso64_wrapper.o : $(obj)/vdso64.so + +# link rule for the .so file, .lds has to be first +$(obj)/vdso64.so: $(src)/vdso64.lds $(obj-vdso64) + $(call if_changed,vdso64ld) + +# assembly rules for the .S files +$(obj-vdso64): %.o: %.S + $(call if_changed_dep,vdso64as) + +# actual build commands +quiet_cmd_vdso64ld = VDSO64L $@ + cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ +quiet_cmd_vdso64as = VDSO64A $@ + cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $< + + diff --git a/arch/ppc64/kernel/vdso64/cacheflush.S b/arch/ppc64/kernel/vdso64/cacheflush.S new file mode 100644 index 000000000000..d9696ffcf334 --- /dev/null +++ b/arch/ppc64/kernel/vdso64/cacheflush.S @@ -0,0 +1,64 @@ +/* + * vDSO provided cache flush routines + * + * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), + * IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include + + .text + +/* + * Default "generic" version of __kernel_sync_dicache. + * + * void __kernel_sync_dicache(unsigned long start, unsigned long end) + * + * Flushes the data cache & invalidate the instruction cache for the + * provided range [start, end[ + * + * Note: all CPUs supported by this kernel have a 128 bytes cache + * line size so we don't have to peek that info from the datapage + */ +V_FUNCTION_BEGIN(__kernel_sync_dicache) + .cfi_startproc + li r5,127 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + srwi. r8,r8,7 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 + mr r3,r6 +1: dcbst 0,r3 + addi r3,r3,128 + bdnz 1b + sync + mtctr r8 +1: icbi 0,r6 + addi r6,r6,128 + bdnz 1b + isync + blr + .cfi_endproc +V_FUNCTION_END(__kernel_sync_dicache) + + +/* + * POWER5 version of __kernel_sync_dicache + */ +V_FUNCTION_BEGIN(__kernel_sync_dicache_p5) + .cfi_startproc + sync + isync + blr + .cfi_endproc +V_FUNCTION_END(__kernel_sync_dicache_p5) diff --git a/arch/ppc64/kernel/vdso64/datapage.S b/arch/ppc64/kernel/vdso64/datapage.S new file mode 100644 index 000000000000..18afd971c9d9 --- /dev/null +++ b/arch/ppc64/kernel/vdso64/datapage.S @@ -0,0 +1,68 @@ +/* + * Access to the shared data page by the vDSO & syscall map + * + * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + + .text +V_FUNCTION_BEGIN(__get_datapage) + .cfi_startproc + /* We don't want that exposed or overridable as we want other objects + * to be able to bl directly to here + */ + .protected __get_datapage + .hidden __get_datapage + + mflr r0 + .cfi_register lr,r0 + + bcl 20,31,1f + .global __kernel_datapage_offset; +__kernel_datapage_offset: + .long 0 +1: + mflr r3 + mtlr r0 + lwz r0,0(r3) + add r3,r0,r3 + blr + .cfi_endproc +V_FUNCTION_END(__get_datapage) + +/* + * void *__kernel_get_syscall_map(unsigned int *syscall_count) ; + * + * returns a pointer to the syscall map. the map is agnostic to the + * size of "long", unlike kernel bitops, it stores bits from top to + * bottom so that memory actually contains a linear bitmap + * check for syscall N by testing bit (0x80000000 >> (N & 0x1f)) of + * 32 bits int at N >> 5. + */ +V_FUNCTION_BEGIN(__kernel_get_syscall_map) + .cfi_startproc + mflr r12 + .cfi_register lr,r12 + + mr r4,r3 + bl V_LOCAL_FUNC(__get_datapage) + mtlr r12 + addi r3,r3,CFG_SYSCALL_MAP64 + cmpli cr0,r4,0 + beqlr + li r0,__NR_syscalls + stw r0,0(r4) + blr + .cfi_endproc +V_FUNCTION_END(__kernel_get_syscall_map) diff --git a/arch/ppc64/kernel/vdso64/gettimeofday.S b/arch/ppc64/kernel/vdso64/gettimeofday.S new file mode 100644 index 000000000000..ed3f970ff05e --- /dev/null +++ b/arch/ppc64/kernel/vdso64/gettimeofday.S @@ -0,0 +1,91 @@ +/* + * Userland implementation of gettimeofday() for 64 bits processes in a + * ppc64 kernel for use in the vDSO + * + * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), + * IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include + + .text +/* + * Exact prototype of gettimeofday + * + * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); + * + */ +V_FUNCTION_BEGIN(__kernel_gettimeofday) + .cfi_startproc + mflr r12 + .cfi_register lr,r12 + + mr r11,r3 /* r11 holds tv */ + mr r10,r4 /* r10 holds tz */ + bl V_LOCAL_FUNC(__get_datapage) /* get data page */ + bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ + lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ + ori r7,r7,16960 + rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ + rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ + std r5,TVAL64_TV_SEC(r11) /* store sec in tv */ + subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */ + mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) / XSEC_PER_SEC */ + rldicl r0,r0,44,20 + cmpldi cr0,r10,0 /* check if tz is NULL */ + std r0,TVAL64_TV_USEC(r11) /* store usec in tv */ + beq 1f + lwz r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */ + lwz r5,CFG_TZ_DSTTIME(r3) + stw r4,TZONE_TZ_MINWEST(r10) + stw r5,TZONE_TZ_DSTTIME(r10) +1: mtlr r12 + li r3,0 /* always success */ + blr + .cfi_endproc +V_FUNCTION_END(__kernel_gettimeofday) + + +/* + * This is the core of gettimeofday(), it returns the xsec + * value in r4 and expects the datapage ptr (non clobbered) + * in r3. clobbers r0,r4,r5,r6,r7,r8 +*/ +V_FUNCTION_BEGIN(__do_get_xsec) + .cfi_startproc + /* check for update count & load values */ +1: ld r7,CFG_TB_UPDATE_COUNT(r3) + andi. r0,r4,1 /* pending update ? loop */ + bne- 1b + xor r0,r4,r4 /* create dependency */ + add r3,r3,r0 + + /* Get TB & offset it */ + mftb r8 + ld r9,CFG_TB_ORIG_STAMP(r3) + subf r8,r9,r8 + + /* Scale result */ + ld r5,CFG_TB_TO_XS(r3) + mulhdu r8,r8,r5 + + /* Add stamp since epoch */ + ld r6,CFG_STAMP_XSEC(r3) + add r4,r6,r8 + + xor r0,r4,r4 + add r3,r3,r0 + ld r0,CFG_TB_UPDATE_COUNT(r3) + cmpld cr0,r0,r7 /* check if updated */ + bne- 1b + blr + .cfi_endproc +V_FUNCTION_END(__do_get_xsec) diff --git a/arch/ppc64/kernel/vdso64/sigtramp.S b/arch/ppc64/kernel/vdso64/sigtramp.S new file mode 100644 index 000000000000..8ae8f205e470 --- /dev/null +++ b/arch/ppc64/kernel/vdso64/sigtramp.S @@ -0,0 +1,294 @@ +/* + * Signal trampoline for 64 bits processes in a ppc64 kernel for + * use in the vDSO + * + * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp. + * Copyright (C) 2004 Alan Modra (amodra@au.ibm.com)), IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include + + .text + +/* The nop here is a hack. The dwarf2 unwind routines subtract 1 from + the return address to get an address in the middle of the presumed + call instruction. Since we don't have a call here, we artifically + extend the range covered by the unwind info by padding before the + real start. */ + nop + .balign 8 +V_FUNCTION_BEGIN(__kernel_sigtramp_rt64) +.Lsigrt_start = . - 4 + addi r1, r1, __SIGNAL_FRAMESIZE + li r0,__NR_rt_sigreturn + sc +.Lsigrt_end: +V_FUNCTION_END(__kernel_sigtramp_rt64) +/* The ".balign 8" above and the following zeros mimic the old stack + trampoline layout. The last magic value is the ucontext pointer, + chosen in such a way that older libgcc unwind code returns a zero + for a sigcontext pointer. */ + .long 0,0,0 + .quad 0,-21*8 + +/* Register r1 can be found at offset 8 of a pt_regs structure. + A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */ +#define cfa_save \ + .byte 0x0f; /* DW_CFA_def_cfa_expression */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x23; .uleb128 RSIZE; /* DW_OP_plus_uconst */ \ + .byte 0x06; /* DW_OP_deref */ \ +9: + +/* Register REGNO can be found at offset OFS of a pt_regs structure. + A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */ +#define rsave(regno, ofs) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ + .byte 0x06; /* DW_OP_deref */ \ + .ifne ofs; \ + .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \ + .endif; \ +9: + +/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16 + of the VMX reg struct. A pointer to the VMX reg struct is at VREGS in + the pt_regs struct. This macro is for REGNO == 0, and contains + 'subroutines' that the other macros jump to. */ +#define vsave_msr0(regno) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno + 77; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x30 + regno; /* DW_OP_lit0 */ \ +2: \ + .byte 0x40; /* DW_OP_lit16 */ \ + .byte 0x1e; /* DW_OP_mul */ \ +3: \ + .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x12; /* DW_OP_dup */ \ + .byte 0x23; /* DW_OP_plus_uconst */ \ + .uleb128 33*RSIZE; /* msr offset */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x0c; .long 1 << 25; /* DW_OP_const4u */ \ + .byte 0x1a; /* DW_OP_and */ \ + .byte 0x12; /* DW_OP_dup, ret 0 if bra taken */ \ + .byte 0x30; /* DW_OP_lit0 */ \ + .byte 0x29; /* DW_OP_eq */ \ + .byte 0x28; .short 0x7fff; /* DW_OP_bra to end */ \ + .byte 0x13; /* DW_OP_drop, pop the 0 */ \ + .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x22; /* DW_OP_plus */ \ + .byte 0x2f; .short 0x7fff; /* DW_OP_skip to end */ \ +9: + +/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16 + of the VMX reg struct. REGNO is 1 thru 31. */ +#define vsave_msr1(regno) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno + 77; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x30 + regno; /* DW_OP_lit n */ \ + .byte 0x2f; .short 2b - 9f; /* DW_OP_skip */ \ +9: + +/* If msr bit 1<<25 is set, then VMX register REGNO is at offset OFS of + the VMX save block. */ +#define vsave_msr2(regno, ofs) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno + 77; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x0a; .short ofs; /* DW_OP_const2u */ \ + .byte 0x2f; .short 3b - 9f; /* DW_OP_skip */ \ +9: + +/* VMX register REGNO is at offset OFS of the VMX save area. */ +#define vsave(regno, ofs) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno + 77; /* regno */ \ + .uleb128 9f - 1f; /* length */ \ +1: \ + .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \ + .byte 0x06; /* DW_OP_deref */ \ + .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \ +9: + +/* This is where the pt_regs pointer can be found on the stack. */ +#define PTREGS 128+168+56 + +/* Size of regs. */ +#define RSIZE 8 + +/* This is the offset of the VMX reg pointer. */ +#define VREGS 48*RSIZE+33*8 + +/* Describe where general purpose regs are saved. */ +#define EH_FRAME_GEN \ + cfa_save; \ + rsave ( 0, 0*RSIZE); \ + rsave ( 2, 2*RSIZE); \ + rsave ( 3, 3*RSIZE); \ + rsave ( 4, 4*RSIZE); \ + rsave ( 5, 5*RSIZE); \ + rsave ( 6, 6*RSIZE); \ + rsave ( 7, 7*RSIZE); \ + rsave ( 8, 8*RSIZE); \ + rsave ( 9, 9*RSIZE); \ + rsave (10, 10*RSIZE); \ + rsave (11, 11*RSIZE); \ + rsave (12, 12*RSIZE); \ + rsave (13, 13*RSIZE); \ + rsave (14, 14*RSIZE); \ + rsave (15, 15*RSIZE); \ + rsave (16, 16*RSIZE); \ + rsave (17, 17*RSIZE); \ + rsave (18, 18*RSIZE); \ + rsave (19, 19*RSIZE); \ + rsave (20, 20*RSIZE); \ + rsave (21, 21*RSIZE); \ + rsave (22, 22*RSIZE); \ + rsave (23, 23*RSIZE); \ + rsave (24, 24*RSIZE); \ + rsave (25, 25*RSIZE); \ + rsave (26, 26*RSIZE); \ + rsave (27, 27*RSIZE); \ + rsave (28, 28*RSIZE); \ + rsave (29, 29*RSIZE); \ + rsave (30, 30*RSIZE); \ + rsave (31, 31*RSIZE); \ + rsave (67, 32*RSIZE); /* ap, used as temp for nip */ \ + rsave (65, 36*RSIZE); /* lr */ \ + rsave (70, 38*RSIZE) /* cr */ + +/* Describe where the FP regs are saved. */ +#define EH_FRAME_FP \ + rsave (32, 48*RSIZE + 0*8); \ + rsave (33, 48*RSIZE + 1*8); \ + rsave (34, 48*RSIZE + 2*8); \ + rsave (35, 48*RSIZE + 3*8); \ + rsave (36, 48*RSIZE + 4*8); \ + rsave (37, 48*RSIZE + 5*8); \ + rsave (38, 48*RSIZE + 6*8); \ + rsave (39, 48*RSIZE + 7*8); \ + rsave (40, 48*RSIZE + 8*8); \ + rsave (41, 48*RSIZE + 9*8); \ + rsave (42, 48*RSIZE + 10*8); \ + rsave (43, 48*RSIZE + 11*8); \ + rsave (44, 48*RSIZE + 12*8); \ + rsave (45, 48*RSIZE + 13*8); \ + rsave (46, 48*RSIZE + 14*8); \ + rsave (47, 48*RSIZE + 15*8); \ + rsave (48, 48*RSIZE + 16*8); \ + rsave (49, 48*RSIZE + 17*8); \ + rsave (50, 48*RSIZE + 18*8); \ + rsave (51, 48*RSIZE + 19*8); \ + rsave (52, 48*RSIZE + 20*8); \ + rsave (53, 48*RSIZE + 21*8); \ + rsave (54, 48*RSIZE + 22*8); \ + rsave (55, 48*RSIZE + 23*8); \ + rsave (56, 48*RSIZE + 24*8); \ + rsave (57, 48*RSIZE + 25*8); \ + rsave (58, 48*RSIZE + 26*8); \ + rsave (59, 48*RSIZE + 27*8); \ + rsave (60, 48*RSIZE + 28*8); \ + rsave (61, 48*RSIZE + 29*8); \ + rsave (62, 48*RSIZE + 30*8); \ + rsave (63, 48*RSIZE + 31*8) + +/* Describe where the VMX regs are saved. */ +#ifdef CONFIG_ALTIVEC +#define EH_FRAME_VMX \ + vsave_msr0 ( 0); \ + vsave_msr1 ( 1); \ + vsave_msr1 ( 2); \ + vsave_msr1 ( 3); \ + vsave_msr1 ( 4); \ + vsave_msr1 ( 5); \ + vsave_msr1 ( 6); \ + vsave_msr1 ( 7); \ + vsave_msr1 ( 8); \ + vsave_msr1 ( 9); \ + vsave_msr1 (10); \ + vsave_msr1 (11); \ + vsave_msr1 (12); \ + vsave_msr1 (13); \ + vsave_msr1 (14); \ + vsave_msr1 (15); \ + vsave_msr1 (16); \ + vsave_msr1 (17); \ + vsave_msr1 (18); \ + vsave_msr1 (19); \ + vsave_msr1 (20); \ + vsave_msr1 (21); \ + vsave_msr1 (22); \ + vsave_msr1 (23); \ + vsave_msr1 (24); \ + vsave_msr1 (25); \ + vsave_msr1 (26); \ + vsave_msr1 (27); \ + vsave_msr1 (28); \ + vsave_msr1 (29); \ + vsave_msr1 (30); \ + vsave_msr1 (31); \ + vsave_msr2 (33, 32*16+12); \ + vsave (32, 33*16) +#else +#define EH_FRAME_VMX +#endif + + .section .eh_frame,"a",@progbits +.Lcie: + .long .Lcie_end - .Lcie_start +.Lcie_start: + .long 0 /* CIE ID */ + .byte 1 /* Version number */ + .string "zR" /* NUL-terminated augmentation string */ + .uleb128 4 /* Code alignment factor */ + .sleb128 -8 /* Data alignment factor */ + .byte 67 /* Return address register column, ap */ + .uleb128 1 /* Augmentation value length */ + .byte 0x14 /* DW_EH_PE_pcrel | DW_EH_PE_udata8. */ + .byte 0x0c,1,0 /* DW_CFA_def_cfa: r1 ofs 0 */ + .balign 8 +.Lcie_end: + + .long .Lfde0_end - .Lfde0_start +.Lfde0_start: + .long .Lfde0_start - .Lcie /* CIE pointer. */ + .quad .Lsigrt_start - . /* PC start, length */ + .quad .Lsigrt_end - .Lsigrt_start + .uleb128 0 /* Augmentation */ + EH_FRAME_GEN + EH_FRAME_FP + EH_FRAME_VMX +# Do we really need to describe the frame at this point? ie. will +# we ever have some call chain that returns somewhere past the addi? +# I don't think so, since gcc doesn't support async signals. +# .byte 0x41 /* DW_CFA_advance_loc 1*4 */ +#undef PTREGS +#define PTREGS 168+56 +# EH_FRAME_GEN +# EH_FRAME_FP +# EH_FRAME_VMX + .balign 8 +.Lfde0_end: diff --git a/arch/ppc64/kernel/vdso64/vdso64.lds.S b/arch/ppc64/kernel/vdso64/vdso64.lds.S new file mode 100644 index 000000000000..942c815c7bc7 --- /dev/null +++ b/arch/ppc64/kernel/vdso64/vdso64.lds.S @@ -0,0 +1,110 @@ +/* + * This is the infamous ld script for the 64 bits vdso + * library + */ +#include + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) +ENTRY(_start) + +SECTIONS +{ + . = VDSO64_LBASE + SIZEOF_HEADERS; + .hash : { *(.hash) } :text + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + . = ALIGN (16); + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.sfpr .glink) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + /* Other stuff is appended to the text segment: */ + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + .gcc_except_table : { *(.gcc_except_table) } + + .opd ALIGN(8) : { KEEP (*(.opd)) } + .got ALIGN(8) : { *(.got .toc) } + .rela.dyn ALIGN(8) : { *(.rela.dyn) } + + .dynamic : { *(.dynamic) } :text :dynamic + + _end = .; + PROVIDE (end = .); + + /* Stabs debugging sections are here too + */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sectio/ns. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + /DISCARD/ : { *(.note.GNU-stack) } + /DISCARD/ : { *(.branch_lt) } + /DISCARD/ : { *(.data .data.* .gnu.linkonce.d.*) } + /DISCARD/ : { *(.bss .sbss .dynbss .dynsbss) } +} + +PHDRS +{ + text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + VDSO_VERSION_STRING { + global: + __kernel_datapage_offset; /* Has to be there for the kernel to find it */ + __kernel_get_syscall_map; + __kernel_gettimeofday; + __kernel_sync_dicache; + __kernel_sync_dicache_p5; + __kernel_sigtramp_rt64; + local: *; + }; +} diff --git a/arch/ppc64/kernel/vdso64/vdso64_wrapper.S b/arch/ppc64/kernel/vdso64/vdso64_wrapper.S new file mode 100644 index 000000000000..771c2741c492 --- /dev/null +++ b/arch/ppc64/kernel/vdso64/vdso64_wrapper.S @@ -0,0 +1,13 @@ +#include +#include + + .section ".data.page_aligned" + + .globl vdso64_start, vdso64_end + .balign PAGE_SIZE +vdso64_start: + .incbin "arch/ppc64/kernel/vdso64/vdso64.so" + .balign PAGE_SIZE +vdso64_end: + + .previous diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index d876a18dbcf7..968222827dbe 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -63,6 +63,7 @@ #include #include #include +#include int mem_init_done; unsigned long ioremap_bot = IMALLOC_BASE; @@ -748,6 +749,8 @@ void __init mem_init(void) #ifdef CONFIG_PPC_ISERIES iommu_vio_init(); #endif + /* Initialize the vDSO */ + vdso_init(); } /* diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 3ad9cef2cd28..4c873236d06a 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -782,6 +782,14 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) goto out_free_dentry; } +#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES + retval = arch_setup_additional_pages(bprm, executable_stack); + if (retval < 0) { + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } +#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ + current->mm->start_stack = bprm->p; /* Now we do a little grungy work by mmaping the ELF image into diff --git a/include/asm-ppc64/a.out.h b/include/asm-ppc64/a.out.h index 7e2b95f3cdce..802338efcb19 100644 --- a/include/asm-ppc64/a.out.h +++ b/include/asm-ppc64/a.out.h @@ -30,14 +30,11 @@ struct exec #ifdef __KERNEL__ -#define STACK_TOP_USER64 (TASK_SIZE_USER64) +#define STACK_TOP_USER64 TASK_SIZE_USER64 +#define STACK_TOP_USER32 TASK_SIZE_USER32 -/* Give 32-bit user space a full 4G address space to live in. */ -#define STACK_TOP_USER32 (TASK_SIZE_USER32) - -#define STACK_TOP ((test_thread_flag(TIF_32BIT) || \ - (ppcdebugset(PPCDBG_BINFMT_32ADDR))) ? \ - STACK_TOP_USER32 : STACK_TOP_USER64) +#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \ + STACK_TOP_USER32 : STACK_TOP_USER64) #endif /* __KERNEL__ */ diff --git a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h index b7530725026e..d815b9c89145 100644 --- a/include/asm-ppc64/elf.h +++ b/include/asm-ppc64/elf.h @@ -238,10 +238,20 @@ do { \ /* A special ignored type value for PPC, for glibc compatibility. */ #define AT_IGNOREPPC 22 +/* The vDSO location. We have to use the same value as x86 for glibc's + * sake :-) + */ +#define AT_SYSINFO_EHDR 33 + extern int dcache_bsize; extern int icache_bsize; extern int ucache_bsize; +/* We do have an arch_setup_additional_pages for vDSO matters */ +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES +struct linux_binprm; +extern int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack); + /* * The requirements here are: * - keep the final alignment of sp (sp & 0xf) @@ -260,6 +270,8 @@ do { \ NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \ NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \ NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \ + /* vDSO base */ \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, current->thread.vdso_base); \ } while (0) /* PowerPC64 relocations defined by the ABIs */ diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h index ef16df988b62..4db453081fe3 100644 --- a/include/asm-ppc64/page.h +++ b/include/asm-ppc64/page.h @@ -185,6 +185,9 @@ extern int page_is_ram(unsigned long pfn); extern u64 ppc64_pft_size; /* Log 2 of page table size */ +/* We do define AT_SYSINFO_EHDR but don't use the gate mecanism */ +#define __HAVE_ARCH_GATE_AREA 1 + #endif /* __ASSEMBLY__ */ #ifdef MODULE diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h index ae3a5bb3ea98..80c5eb8de01f 100644 --- a/include/asm-ppc64/processor.h +++ b/include/asm-ppc64/processor.h @@ -544,8 +544,8 @@ extern struct task_struct *last_task_used_altivec; /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ -#define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(STACK_TOP_USER32 / 4)) -#define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(STACK_TOP_USER64 / 4)) +#define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(TASK_SIZE_USER32 / 4)) +#define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(TASK_SIZE_USER64 / 4)) #define TASK_UNMAPPED_BASE ((test_thread_flag(TIF_32BIT)||(ppcdebugset(PPCDBG_BINFMT_32ADDR))) ? \ TASK_UNMAPPED_BASE_USER32 : TASK_UNMAPPED_BASE_USER64 ) @@ -564,7 +564,7 @@ struct thread_struct { unsigned long fpexc_mode; /* Floating-point exception mode */ unsigned long start_tb; /* Start purr when proc switched in */ unsigned long accum_tb; /* Total accumilated purr for process */ - unsigned long pad; /* was saved_msr, saved_softe */ + unsigned long vdso_base; /* base of the vDSO library */ #ifdef CONFIG_ALTIVEC /* Complete AltiVec register set */ vector128 vr[32] __attribute((aligned(16))); diff --git a/include/asm-ppc64/systemcfg.h b/include/asm-ppc64/systemcfg.h index ab328ad80b73..9b86b53129aa 100644 --- a/include/asm-ppc64/systemcfg.h +++ b/include/asm-ppc64/systemcfg.h @@ -20,10 +20,14 @@ * Minor version changes are a hint. */ #define SYSTEMCFG_MAJOR 1 -#define SYSTEMCFG_MINOR 0 +#define SYSTEMCFG_MINOR 1 #ifndef __ASSEMBLY__ +#include + +#define SYSCALL_MAP_SIZE ((__NR_syscalls + 31) / 32) + struct systemcfg { __u8 eye_catcher[16]; /* Eyecatcher: SYSTEMCFG:PPC64 0x00 */ struct { /* Systemcfg version numbers */ @@ -47,6 +51,8 @@ struct systemcfg { __u32 dcache_line_size; /* L1 d-cache line size 0x64 */ __u32 icache_size; /* L1 i-cache size 0x68 */ __u32 icache_line_size; /* L1 i-cache line size 0x6C */ + __u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of available syscalls 0x70 */ + __u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of available syscalls */ }; #ifdef __KERNEL__ diff --git a/include/asm-ppc64/time.h b/include/asm-ppc64/time.h index b7205e3b7193..8d6e3760ee10 100644 --- a/include/asm-ppc64/time.h +++ b/include/asm-ppc64/time.h @@ -43,10 +43,10 @@ extern time_t last_rtc_update; struct gettimeofday_vars { unsigned long tb_to_xs; unsigned long stamp_xsec; + unsigned long tb_orig_stamp; }; struct gettimeofday_struct { - unsigned long tb_orig_stamp; unsigned long tb_ticks_per_sec; struct gettimeofday_vars vars[2]; struct gettimeofday_vars * volatile varp; diff --git a/include/asm-ppc64/vdso.h b/include/asm-ppc64/vdso.h new file mode 100644 index 000000000000..c745e0d96e87 --- /dev/null +++ b/include/asm-ppc64/vdso.h @@ -0,0 +1,83 @@ +#ifndef __PPC64_VDSO_H__ +#define __PPC64_VDSO_H__ + +#ifdef __KERNEL__ + +/* Default link addresses for the vDSOs */ +#define VDSO32_LBASE 0 +#define VDSO64_LBASE 0 + +/* Default map addresses */ +#define VDSO32_MBASE 0x100000 +#define VDSO64_MBASE 0x100000 + +#define VDSO_VERSION_STRING LINUX_2.6.11 + +/* Define if 64 bits VDSO has procedure descriptors */ +#undef VDS64_HAS_DESCRIPTORS + +#ifndef __ASSEMBLY__ + +extern unsigned int vdso64_pages; +extern unsigned int vdso32_pages; + +/* Offsets relative to thread->vdso_base */ +extern unsigned long vdso64_rt_sigtramp; +extern unsigned long vdso32_sigtramp; +extern unsigned long vdso32_rt_sigtramp; + +extern void vdso_init(void); + +#else /* __ASSEMBLY__ */ + +#ifdef __VDSO64__ +#ifdef VDS64_HAS_DESCRIPTORS +#define V_FUNCTION_BEGIN(name) \ + .globl name; \ + .section ".opd","a"; \ + .align 3; \ + name: \ + .quad .name,.TOC.@tocbase,0; \ + .previous; \ + .globl .name; \ + .type .name,@function; \ + .name: \ + +#define V_FUNCTION_END(name) \ + .size .name,.-.name; + +#define V_LOCAL_FUNC(name) (.name) + +#else /* VDS64_HAS_DESCRIPTORS */ + +#define V_FUNCTION_BEGIN(name) \ + .globl name; \ + name: \ + +#define V_FUNCTION_END(name) \ + .size name,.-name; + +#define V_LOCAL_FUNC(name) (name) + +#endif /* VDS64_HAS_DESCRIPTORS */ +#endif /* __VDSO64__ */ + +#ifdef __VDSO32__ + +#define V_FUNCTION_BEGIN(name) \ + .globl name; \ + .type name,@function; \ + name: \ + +#define V_FUNCTION_END(name) \ + .size name,.-name; + +#define V_LOCAL_FUNC(name) (name) + +#endif /* __VDSO32__ */ + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* __PPC64_VDSO_H__ */ -- cgit v1.2.3 From 4d1c8cd737fd7835f57c228d8c696f0b18f68ee1 Mon Sep 17 00:00:00 2001 From: Zwane Mwaikambo Date: Fri, 4 Mar 2005 17:34:00 -0800 Subject: [PATCH] ppc64: generic hotplug cpu support Patch provides a generic hotplug cpu implementation, with the only current user being pmac. This doesn't replace real hotplug code as is currently used by LPAR systems. Ben i can add the additional pmac specific code to put the processor into a sleeping state seperately. Thanks to Nathan for testing. Signed-off-by: Zwane Mwaikambo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/Kconfig | 2 +- arch/ppc64/kernel/idle.c | 4 ++ arch/ppc64/kernel/irq.c | 29 ++++++++++++++ arch/ppc64/kernel/pSeries_setup.c | 5 ++- arch/ppc64/kernel/pmac_setup.c | 3 ++ arch/ppc64/kernel/pmac_smp.c | 5 +++ arch/ppc64/kernel/setup.c | 3 -- arch/ppc64/kernel/smp.c | 80 +++++++++++++++++++++++++++++++++++++++ arch/ppc64/kernel/sysfs.c | 6 +-- include/asm-ppc64/machdep.h | 1 + include/asm-ppc64/smp.h | 9 ++++- 11 files changed, 136 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index a7933ab62e98..861f4460ad02 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -313,7 +313,7 @@ source "drivers/pci/Kconfig" config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" - depends on SMP && EXPERIMENTAL && PPC_PSERIES + depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC) select HOTPLUG ---help--- Say Y here to be able to turn CPUs off and on. diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c index 398b4682127b..51eb6af14a8f 100644 --- a/arch/ppc64/kernel/idle.c +++ b/arch/ppc64/kernel/idle.c @@ -293,6 +293,10 @@ static int native_idle(void) power4_idle(); if (need_resched()) schedule(); + + if (cpu_is_offline(smp_processor_id()) && + system_state == SYSTEM_RUNNING) + cpu_die(); } return 0; } diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c index 0ea8016146a2..4fd7f203c1e3 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/ppc64/kernel/irq.c @@ -116,6 +116,35 @@ skip: return 0; } +#ifdef CONFIG_HOTPLUG_CPU +void fixup_irqs(cpumask_t map) +{ + unsigned int irq; + static int warned; + + for_each_irq(irq) { + cpumask_t mask; + + if (irq_desc[irq].status & IRQ_PER_CPU) + continue; + + cpus_and(mask, irq_affinity[irq], map); + if (any_online_cpu(mask) == NR_CPUS) { + printk("Breaking affinity for irq %i\n", irq); + mask = map; + } + if (irq_desc[irq].handler->set_affinity) + irq_desc[irq].handler->set_affinity(irq, mask); + else if (irq_desc[irq].action && !(warned++)) + printk("Cannot set affinity for irq %i\n", irq); + } + + local_irq_enable(); + mdelay(1); + local_irq_disable(); +} +#endif + extern int noirqdebug; /* diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index f603397b7b04..0426892749c6 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -320,8 +320,9 @@ static void __init pSeries_discover_pic(void) } } -static void pSeries_cpu_die(void) +static void pSeries_mach_cpu_die(void) { + idle_task_exit(); local_irq_disable(); /* Some hardware requires clearing the CPPR, while other hardware does not * it is safe either way @@ -599,7 +600,7 @@ struct machdep_calls __initdata pSeries_md = { .power_off = rtas_power_off, .halt = rtas_halt, .panic = rtas_os_term, - .cpu_die = pSeries_cpu_die, + .cpu_die = pSeries_mach_cpu_die, .get_boot_time = pSeries_get_boot_time, .get_rtc_time = pSeries_get_rtc_time, .set_rtc_time = pSeries_set_rtc_time, diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index 41fa6e95a06f..5c56fc956245 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -439,6 +439,9 @@ static int __init pmac_probe(int platform) } struct machdep_calls __initdata pmac_md = { +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = generic_mach_cpu_die, +#endif .probe = pmac_probe, .setup_arch = pmac_setup_arch, .init_early = pmac_init_early, diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c index e0b37079943c..c27588ede2fe 100644 --- a/arch/ppc64/kernel/pmac_smp.c +++ b/arch/ppc64/kernel/pmac_smp.c @@ -308,4 +308,9 @@ struct smp_ops_t core99_smp_ops __pmacdata = { void __init pmac_setup_smp(void) { smp_ops = &core99_smp_ops; +#ifdef CONFIG_HOTPLUG_CPU + smp_ops->cpu_enable = generic_cpu_enable; + smp_ops->cpu_disable = generic_cpu_disable; + smp_ops->cpu_die = generic_cpu_die; +#endif } diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index d98c320828e5..078c3551ce8a 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -1377,9 +1377,6 @@ early_param("xmon", early_xmon); void cpu_die(void) { - idle_task_exit(); if (ppc_md.cpu_die) ppc_md.cpu_die(); - local_irq_disable(); - for (;;); } diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index a9e43792f8fe..cde1947432a1 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -406,10 +407,89 @@ void __devinit smp_prepare_boot_cpu(void) current_set[boot_cpuid] = current->thread_info; } +#ifdef CONFIG_HOTPLUG_CPU +/* State of each CPU during hotplug phases */ +DEFINE_PER_CPU(int, cpu_state) = { 0 }; + +int generic_cpu_disable(void) +{ + unsigned int cpu = smp_processor_id(); + + if (cpu == boot_cpuid) + return -EBUSY; + + systemcfg->processorCount--; + cpu_clear(cpu, cpu_online_map); + fixup_irqs(cpu_online_map); + return 0; +} + +int generic_cpu_enable(unsigned int cpu) +{ + /* Do the normal bootup if we haven't + * already bootstrapped. */ + if (system_state != SYSTEM_RUNNING) + return -ENOSYS; + + /* get the target out of it's holding state */ + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; + wmb(); + + while (!cpu_online(cpu)) + cpu_relax(); + + fixup_irqs(cpu_online_map); + /* counter the irq disable in fixup_irqs */ + local_irq_enable(); + return 0; +} + +void generic_cpu_die(unsigned int cpu) +{ + int i; + + for (i = 0; i < 100; i++) { + rmb(); + if (per_cpu(cpu_state, cpu) == CPU_DEAD) + return; + msleep(100); + } + printk(KERN_ERR "CPU%d didn't die...\n", cpu); +} + +void generic_mach_cpu_die(void) +{ + unsigned int cpu; + + local_irq_disable(); + cpu = smp_processor_id(); + printk(KERN_DEBUG "CPU%d offline\n", cpu); + __get_cpu_var(cpu_state) = CPU_DEAD; + wmb(); + while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) + cpu_relax(); + + flush_tlb_pending(); + cpu_set(cpu, cpu_online_map); + local_irq_enable(); +} +#endif + +static int __devinit cpu_enable(unsigned int cpu) +{ + if (smp_ops->cpu_enable) + return smp_ops->cpu_enable(cpu); + + return -ENOSYS; +} + int __devinit __cpu_up(unsigned int cpu) { int c; + if (!cpu_enable(cpu)) + return 0; + /* At boot, don't bother with non-present cpus -JSCHOPP */ if (system_state < SYSTEM_RUNNING && !cpu_present(cpu)) return -ENOENT; diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c index bbc9dcda17f7..0925694c3ce5 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/ppc64/kernel/sysfs.c @@ -18,7 +18,7 @@ #include #include #include - +#include static DEFINE_PER_CPU(struct cpu, cpu_devices); @@ -413,9 +413,7 @@ static int __init topology_init(void) * CPU. For instance, the boot cpu might never be valid * for hotplugging. */ -#ifdef CONFIG_HOTPLUG_CPU - if (systemcfg->platform != PLATFORM_PSERIES_LPAR) -#endif + if (!ppc_md.cpu_die) c->no_control = 1; if (cpu_online(cpu) || (c->no_control == 0)) { diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h index 476d2185ffd1..03fe499c7604 100644 --- a/include/asm-ppc64/machdep.h +++ b/include/asm-ppc64/machdep.h @@ -30,6 +30,7 @@ struct smp_ops_t { void (*setup_cpu)(int nr); void (*take_timebase)(void); void (*give_timebase)(void); + int (*cpu_enable)(unsigned int nr); int (*cpu_disable)(void); void (*cpu_die)(unsigned int nr); }; diff --git a/include/asm-ppc64/smp.h b/include/asm-ppc64/smp.h index 965980bbbb57..c8646fa999c2 100644 --- a/include/asm-ppc64/smp.h +++ b/include/asm-ppc64/smp.h @@ -29,7 +29,7 @@ extern int boot_cpuid; extern int boot_cpuid_phys; -extern void cpu_die(void) __attribute__((noreturn)); +extern void cpu_die(void); #ifdef CONFIG_SMP @@ -37,6 +37,13 @@ extern void smp_send_debugger_break(int cpu); struct pt_regs; extern void smp_message_recv(int, struct pt_regs *); +#ifdef CONFIG_HOTPLUG_CPU +extern void fixup_irqs(cpumask_t map); +int generic_cpu_disable(void); +int generic_cpu_enable(unsigned int cpu); +void generic_cpu_die(unsigned int cpu); +void generic_mach_cpu_die(void); +#endif #define __smp_processor_id() (get_paca()->paca_index) #define hard_smp_processor_id() (get_paca()->hw_cpu_id) -- cgit v1.2.3 From e7becb964e374e84ed564b4832f4a966d9878668 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 4 Mar 2005 17:34:58 -0800 Subject: [PATCH] ppc64: functions to reserve performance monitor hardware The PPC64 interrupt code includes a hook to call when an exception from the performance monitor unit occurs. However, there's no way of reserving the hook properly, so if more than one bit of code tries to use it things will get ugly. Currently oprofile is the only user, but there are likely to be more in future e.g. perfctr, if and when it reaches a fit state for merging. This patch creates functions to reserve and release the performance monitor hardware (including its interrupt), and makes oprofile use them. It also creates a new arch/ppc64/kernel/pmc.c, in which we can put any future helper functions for handling the performance monitor counters. Signed-off-by: David Gibson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/Makefile | 2 +- arch/ppc64/kernel/pmc.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ arch/ppc64/kernel/traps.c | 14 ++-------- arch/ppc64/oprofile/common.c | 18 +++++-------- include/asm-ppc64/pmc.h | 29 ++++++++++++++++++++ 5 files changed, 103 insertions(+), 24 deletions(-) create mode 100644 arch/ppc64/kernel/pmc.c create mode 100644 include/asm-ppc64/pmc.h (limited to 'include') diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 752c9d6a3f70..995beec794d9 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -11,7 +11,7 @@ obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o init_task.o \ lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ - iommu.o sysfs.o vdso.o + iommu.o sysfs.o vdso.o pmc.o obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o diff --git a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c new file mode 100644 index 000000000000..cd951cbd1e0d --- /dev/null +++ b/arch/ppc64/kernel/pmc.c @@ -0,0 +1,64 @@ +/* + * linux/arch/ppc64/kernel/pmc.c + * + * Copyright (C) 2004 David Gibson, IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include + +#include +#include + +/* Ensure exceptions are disabled */ +static void dummy_perf(struct pt_regs *regs) +{ + unsigned int mmcr0 = mfspr(SPRN_MMCR0); + + mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO); + mtspr(SPRN_MMCR0, mmcr0); +} + +static spinlock_t pmc_owner_lock = SPIN_LOCK_UNLOCKED; +static void *pmc_owner_caller; /* mostly for debugging */ +perf_irq_t perf_irq = dummy_perf; + +int reserve_pmc_hardware(perf_irq_t new_perf_irq) +{ + int err = 0; + + spin_lock(&pmc_owner_lock); + + if (pmc_owner_caller) { + printk(KERN_WARNING "reserve_pmc_hardware: " + "PMC hardware busy (reserved by caller %p)\n", + pmc_owner_caller); + err = -EBUSY; + goto out; + } + + pmc_owner_caller = __builtin_return_address(0); + perf_irq = new_perf_irq ? : dummy_perf; + + out: + spin_unlock(&pmc_owner_lock); + return err; +} + +void release_pmc_hardware(void) +{ + spin_lock(&pmc_owner_lock); + + WARN_ON(! pmc_owner_caller); + + pmc_owner_caller = NULL; + perf_irq = dummy_perf; + + spin_unlock(&pmc_owner_lock); +} diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c index bc245a22b435..d7f1304adb89 100644 --- a/arch/ppc64/kernel/traps.c +++ b/arch/ppc64/kernel/traps.c @@ -41,6 +41,7 @@ #include #include #include +#include #ifdef CONFIG_DEBUGGER int (*__debugger)(struct pt_regs *regs); @@ -450,18 +451,7 @@ void altivec_unavailable_exception(struct pt_regs *regs) die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); } -/* Ensure exceptions are disabled */ -static void dummy_perf(struct pt_regs *regs) -{ - unsigned int mmcr0 = mfspr(SPRN_MMCR0); - - mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO); - mtspr(SPRN_MMCR0, mmcr0); -} - -void (*perf_irq)(struct pt_regs *) = dummy_perf; - -EXPORT_SYMBOL(perf_irq); +extern perf_irq_t perf_irq; void performance_monitor_exception(struct pt_regs *regs) { diff --git a/arch/ppc64/oprofile/common.c b/arch/ppc64/oprofile/common.c index a9a47caa5552..b28bfda23d94 100644 --- a/arch/ppc64/oprofile/common.c +++ b/arch/ppc64/oprofile/common.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "op_impl.h" @@ -22,9 +23,6 @@ extern struct op_ppc64_model op_model_rs64; extern struct op_ppc64_model op_model_power4; static struct op_ppc64_model *model; -extern void (*perf_irq)(struct pt_regs *); -static void (*save_perf_irq)(struct pt_regs *); - static struct op_counter_config ctr[OP_MAX_COUNTER]; static struct op_system_config sys; @@ -35,11 +33,12 @@ static void op_handle_interrupt(struct pt_regs *regs) static int op_ppc64_setup(void) { - /* Install our interrupt handler into the existing hook. */ - save_perf_irq = perf_irq; - perf_irq = op_handle_interrupt; + int err; - mb(); + /* Grab the hardware */ + err = reserve_pmc_hardware(op_handle_interrupt); + if (err) + return err; /* Pre-compute the values to stuff in the hardware registers. */ model->reg_setup(ctr, &sys, model->num_counters); @@ -52,10 +51,7 @@ static int op_ppc64_setup(void) static void op_ppc64_shutdown(void) { - mb(); - - /* Remove our interrupt handler. We may be removing this module. */ - perf_irq = save_perf_irq; + release_pmc_hardware(); } static void op_ppc64_cpu_start(void *dummy) diff --git a/include/asm-ppc64/pmc.h b/include/asm-ppc64/pmc.h new file mode 100644 index 000000000000..c924748c0bea --- /dev/null +++ b/include/asm-ppc64/pmc.h @@ -0,0 +1,29 @@ +/* + * pmc.h + * Copyright (C) 2004 David Gibson, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _PPC64_PMC_H +#define _PPC64_PMC_H + +#include + +typedef void (*perf_irq_t)(struct pt_regs *); + +int reserve_pmc_hardware(perf_irq_t new_perf_irq); +void release_pmc_hardware(void); + +#endif /* _PPC64_PMC_H */ -- cgit v1.2.3 From ce4ddcb1b0f3c04f2d115281d97db417a1853a69 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Fri, 4 Mar 2005 17:36:48 -0800 Subject: [PATCH] mips: calculate clock at any time This patch changes bcu.c to calculate clock at any time. Because clock can be changed. Moreover, EXPORT_SYMBOL_GPLs are added to it. Signed-off-by: Yoichi Yuasa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/mips/vr41xx/common/bcu.c | 25 ++++++++++--------------- arch/mips/vr41xx/common/init.c | 17 ++++++++++++++++- arch/mips/vr41xx/common/ksyms.c | 3 --- include/asm-mips/vr41xx/vr41xx.h | 1 + 4 files changed, 27 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/arch/mips/vr41xx/common/bcu.c b/arch/mips/vr41xx/common/bcu.c index d14dae150b8a..cdfa4273a1c5 100644 --- a/arch/mips/vr41xx/common/bcu.c +++ b/arch/mips/vr41xx/common/bcu.c @@ -3,7 +3,7 @@ * * Copyright (C) 2002 MontaVista Software Inc. * Author: Yoichi Yuasa - * Copyright (C) 2003-2004 Yoichi Yuasa + * Copyright (C) 2003-2005 Yoichi Yuasa * * 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 @@ -28,20 +28,16 @@ * Yoichi Yuasa * - Added support for NEC VR4133. */ -#include -#include #include +#include #include #include #include #include -#define IO_MEM_RESOURCE_START 0UL -#define IO_MEM_RESOURCE_END 0x1fffffffUL - -#define CLKSPEEDREG_TYPE1 KSEG1ADDR(0x0b000014) -#define CLKSPEEDREG_TYPE2 KSEG1ADDR(0x0f000014) +#define CLKSPEEDREG_TYPE1 (void __iomem *)KSEG1ADDR(0x0b000014) +#define CLKSPEEDREG_TYPE2 (void __iomem *)KSEG1ADDR(0x0f000014) #define CLKSP(x) ((x) & 0x001f) #define CLKSP_VR4133(x) ((x) & 0x0007) @@ -63,11 +59,15 @@ unsigned long vr41xx_get_vtclock_frequency(void) return vr41xx_vtclock; } +EXPORT_SYMBOL_GPL(vr41xx_get_vtclock_frequency); + unsigned long vr41xx_get_tclock_frequency(void) { return vr41xx_tclock; } +EXPORT_SYMBOL_GPL(vr41xx_get_tclock_frequency); + static inline uint16_t read_clkspeed(void) { switch (current_cpu_data.cputype) { @@ -207,7 +207,7 @@ static inline unsigned long calculate_tclock(uint16_t clkspeed, unsigned long pc return tclock; } -static int __init vr41xx_bcu_init(void) +void vr41xx_calculate_clock_frequency(void) { unsigned long pclock; uint16_t clkspeed; @@ -217,11 +217,6 @@ static int __init vr41xx_bcu_init(void) pclock = calculate_pclock(clkspeed); vr41xx_vtclock = calculate_vtclock(clkspeed, pclock); vr41xx_tclock = calculate_tclock(clkspeed, pclock, vr41xx_vtclock); - - iomem_resource.start = IO_MEM_RESOURCE_START; - iomem_resource.end = IO_MEM_RESOURCE_END; - - return 0; } -early_initcall(vr41xx_bcu_init); +EXPORT_SYMBOL_GPL(vr41xx_calculate_clock_frequency); diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c index ffc8e1c36b67..c189b0df5071 100644 --- a/arch/mips/vr41xx/common/init.c +++ b/arch/mips/vr41xx/common/init.c @@ -1,7 +1,7 @@ /* * init.c, Common initialization routines for NEC VR4100 series. * - * Copyright (C) 2003-2004 Yoichi Yuasa + * Copyright (C) 2003-2005 Yoichi Yuasa * * 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 @@ -18,9 +18,20 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include #include +#include + +#define IO_MEM_RESOURCE_START 0UL +#define IO_MEM_RESOURCE_END 0x1fffffffUL + +static void __init iomem_resource_init(void) +{ + iomem_resource.start = IO_MEM_RESOURCE_START; + iomem_resource.end = IO_MEM_RESOURCE_END; +} void __init prom_init(void) { @@ -35,6 +46,10 @@ void __init prom_init(void) if (i < (argc - 1)) strcat(arcs_cmdline, " "); } + + vr41xx_calculate_clock_frequency(); + + iomem_resource_init(); } unsigned long __init prom_free_prom_memory (void) diff --git a/arch/mips/vr41xx/common/ksyms.c b/arch/mips/vr41xx/common/ksyms.c index a2014106360d..c8c0d0a727d2 100644 --- a/arch/mips/vr41xx/common/ksyms.c +++ b/arch/mips/vr41xx/common/ksyms.c @@ -22,9 +22,6 @@ #include -EXPORT_SYMBOL(vr41xx_get_vtclock_frequency); -EXPORT_SYMBOL(vr41xx_get_tclock_frequency); - EXPORT_SYMBOL(vr41xx_set_rtclong1_cycle); EXPORT_SYMBOL(vr41xx_read_rtclong1_counter); EXPORT_SYMBOL(vr41xx_set_rtclong2_cycle); diff --git a/include/asm-mips/vr41xx/vr41xx.h b/include/asm-mips/vr41xx/vr41xx.h index c57c8dca6117..8ac8487e2790 100644 --- a/include/asm-mips/vr41xx/vr41xx.h +++ b/include/asm-mips/vr41xx/vr41xx.h @@ -45,6 +45,7 @@ /* * Bus Control Uint */ +extern unsigned long vr41xx_calculate_clock_frequency(void); extern unsigned long vr41xx_get_vtclock_frequency(void); extern unsigned long vr41xx_get_tclock_frequency(void); -- cgit v1.2.3