diff options
Diffstat (limited to 'arch')
64 files changed, 817 insertions, 416 deletions
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index e1c4707..ee07dce 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -465,7 +465,7 @@ EXPORT_SYMBOL(pci_free_consistent); Write dma_length of each leader with the combined lengths of the mergable followers. */ -#define SG_ENT_VIRT_ADDRESS(SG) (page_address((SG)->page) + (SG)->offset) +#define SG_ENT_VIRT_ADDRESS(SG) (sg_virt((SG))) #define SG_ENT_PHYS_ADDRESS(SG) __pa(SG_ENT_VIRT_ADDRESS(SG)) static void diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 44ab0da..9d371e4 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -442,7 +442,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, BUG_ON(dir == DMA_NONE); for (i = 0; i < nents; i++, sg++) { - struct page *page = sg->page; + struct page *page = sg_page(sg); unsigned int offset = sg->offset; unsigned int length = sg->length; void *ptr = page_address(page) + offset; diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c index 94d7b11..a16cb03 100644 --- a/arch/blackfin/kernel/dma-mapping.c +++ b/arch/blackfin/kernel/dma-mapping.c @@ -160,8 +160,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, BUG_ON(direction == DMA_NONE); for (i = 0; i < nents; i++, sg++) { - sg->dma_address = (dma_addr_t)(page_address(sg->page) + - sg->offset); + sg->dma_address = (dma_addr_t) sg_virt(sg); invalidate_dcache_range(sg_dma_address(sg), sg_dma_address(sg) + diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 3c95f41..bc859a3 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -246,7 +246,7 @@ static int reserve_sba_gart = 1; static SBA_INLINE void sba_mark_invalid(struct ioc *, dma_addr_t, size_t); static SBA_INLINE void sba_free_range(struct ioc *, dma_addr_t, size_t); -#define sba_sg_address(sg) (page_address((sg)->page) + (sg)->offset) +#define sba_sg_address(sg) sg_virt((sg)) #ifdef FULL_VALID_PDIR static u64 prefetch_spill_page; diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c index a3a558a..6ef9b52 100644 --- a/arch/ia64/hp/sim/simscsi.c +++ b/arch/ia64/hp/sim/simscsi.c @@ -131,7 +131,7 @@ simscsi_sg_readwrite (struct scsi_cmnd *sc, int mode, unsigned long offset) stat.fd = desc[sc->device->id]; scsi_for_each_sg(sc, sl, scsi_sg_count(sc), i) { - req.addr = __pa(page_address(sl->page) + sl->offset); + req.addr = __pa(sg_virt(sl)); req.len = sl->length; if (DBG) printk("simscsi_sg_%s @ %lx (off %lx) use_sg=%d len=%d\n", @@ -212,7 +212,7 @@ static void simscsi_fillresult(struct scsi_cmnd *sc, char *buf, unsigned len) if (!len) break; thislen = min(len, slp->length); - memcpy(page_address(slp->page) + slp->offset, buf, thislen); + memcpy(sg_virt(slp), buf, thislen); len -= thislen; } } diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 8e4894b..3f7ea13 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -1090,7 +1090,8 @@ efi_memmap_init(unsigned long *s, unsigned long *e) void efi_initialize_iomem_resources(struct resource *code_resource, - struct resource *data_resource) + struct resource *data_resource, + struct resource *bss_resource) { struct resource *res; void *efi_map_start, *efi_map_end, *p; @@ -1171,6 +1172,7 @@ efi_initialize_iomem_resources(struct resource *code_resource, */ insert_resource(res, code_resource); insert_resource(res, data_resource); + insert_resource(res, bss_resource); #ifdef CONFIG_KEXEC insert_resource(res, &efi_memmap_res); insert_resource(res, &boot_param_res); diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index cbf67f1..ae6c3c0 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -90,7 +90,12 @@ static struct resource code_resource = { .name = "Kernel code", .flags = IORESOURCE_BUSY | IORESOURCE_MEM }; -extern char _text[], _end[], _etext[]; + +static struct resource bss_resource = { + .name = "Kernel bss", + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; +extern char _text[], _end[], _etext[], _edata[], _bss[]; unsigned long ia64_max_cacheline_size; @@ -200,8 +205,11 @@ static int __init register_memory(void) code_resource.start = ia64_tpa(_text); code_resource.end = ia64_tpa(_etext) - 1; data_resource.start = ia64_tpa(_etext); - data_resource.end = ia64_tpa(_end) - 1; - efi_initialize_iomem_resources(&code_resource, &data_resource); + data_resource.end = ia64_tpa(_edata) - 1; + bss_resource.start = ia64_tpa(_bss); + bss_resource.end = ia64_tpa(_end) - 1; + efi_initialize_iomem_resources(&code_resource, &data_resource, + &bss_resource); return 0; } diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index ecd8a52..511db2f 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -16,7 +16,7 @@ #include <asm/sn/pcidev.h> #include <asm/sn/sn_sal.h> -#define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) +#define SG_ENT_VIRT_ADDRESS(sg) (sg_virt((sg))) #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) /** diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c index 9d4e4b5..ef490e1 100644 --- a/arch/m68k/kernel/dma.c +++ b/arch/m68k/kernel/dma.c @@ -121,7 +121,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int i; for (i = 0; i < nents; sg++, i++) { - sg->dma_address = page_to_phys(sg->page) + sg->offset; + sg->dma_address = sg_phys(sg); dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir); } return nents; diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 3ecff5e..61262c5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -66,6 +66,7 @@ config BCM47XX config MIPS_COBALT bool "Cobalt Server" select CEVT_R4K + select CEVT_GT641XX select DMA_NONCOHERENT select HW_HAS_PCI select I8253 @@ -729,6 +730,9 @@ config ARCH_MAY_HAVE_PC_FDC config BOOT_RAW bool +config CEVT_GT641XX + bool + config CEVT_R4K bool diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index 3efe117..fd7124c 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -6,18 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT source "lib/Kconfig.debug" -config CROSSCOMPILE - bool "Are you using a crosscompiler" - help - Say Y here if you are compiling the kernel on a different - architecture than the one it is intended to run on. This is just a - convenience option which will select the appropriate value for - the CROSS_COMPILE make variable which otherwise has to be passed on - the command line from mips-linux-, mipsel-linux-, mips64-linux- and - mips64el-linux- as appropriate for a particular kernel configuration. - You will have to pass the value for CROSS_COMPILE manually if the - name prefix for your tools is different. - config CMDLINE string "Default kernel command string" default "" diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 14164c2..23c1775 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -18,15 +18,15 @@ cflags-y := # Select the object file format to substitute into the linker script. # ifdef CONFIG_CPU_LITTLE_ENDIAN -32bit-tool-prefix = mipsel-linux- -64bit-tool-prefix = mips64el-linux- +32bit-tool-archpref = mipsel +64bit-tool-archpref = mips64el 32bit-bfd = elf32-tradlittlemips 64bit-bfd = elf64-tradlittlemips 32bit-emul = elf32ltsmip 64bit-emul = elf64ltsmip else -32bit-tool-prefix = mips-linux- -64bit-tool-prefix = mips64-linux- +32bit-tool-archpref = mips +64bit-tool-archpref = mips64 32bit-bfd = elf32-tradbigmips 64bit-bfd = elf64-tradbigmips 32bit-emul = elf32btsmip @@ -34,16 +34,18 @@ else endif ifdef CONFIG_32BIT -tool-prefix = $(32bit-tool-prefix) +tool-archpref = $(32bit-tool-archpref) UTS_MACHINE := mips endif ifdef CONFIG_64BIT -tool-prefix = $(64bit-tool-prefix) +tool-archpref = $(64bit-tool-archpref) UTS_MACHINE := mips64 endif -ifdef CONFIG_CROSSCOMPILE -CROSS_COMPILE := $(tool-prefix) +ifneq ($(SUBARCH),$(ARCH)) + ifeq ($(CROSS_COMPILE),) + CROSS_COMPILE := $(call cc-cross-prefix, $(tool-archpref)-linux- $(tool-archpref)-gnu-linux- $(tool-archpref)-unknown-gnu-linux-) + endif endif ifdef CONFIG_32BIT diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile index 6b83f4d..d73833b 100644 --- a/arch/mips/cobalt/Makefile +++ b/arch/mips/cobalt/Makefile @@ -2,7 +2,7 @@ # Makefile for the Cobalt micro systems family specific parts of the kernel # -obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o +obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o time.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_EARLY_PRINTK) += console.o diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index d11bb1b..dd23beb 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -9,19 +9,17 @@ * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv) * */ -#include <linux/interrupt.h> #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> #include <linux/pm.h> #include <asm/bootinfo.h> -#include <asm/time.h> -#include <asm/i8253.h> -#include <asm/io.h> #include <asm/reboot.h> #include <asm/gt64120.h> #include <cobalt.h> -#include <irq.h> extern void cobalt_machine_restart(char *command); extern void cobalt_machine_halt(void); @@ -41,17 +39,6 @@ const char *get_system_type(void) return "MIPS Cobalt"; } -void __init plat_timer_setup(struct irqaction *irq) -{ - /* Load timer value for HZ (TCLK is 50MHz) */ - GT_WRITE(GT_TC0_OFS, 50*1000*1000 / HZ); - - /* Enable timer0 */ - GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); - - setup_irq(GT641XX_TIMER0_IRQ, irq); -} - /* * Cobalt doesn't have PS/2 keyboard/mouse interfaces, * keyboard conntroller is never used. @@ -84,11 +71,6 @@ static struct resource cobalt_reserved_resources[] = { }, }; -void __init plat_time_init(void) -{ - setup_pit_timer(); -} - void __init plat_mem_setup(void) { int i; diff --git a/arch/mips/cobalt/time.c b/arch/mips/cobalt/time.c new file mode 100644 index 0000000..fa819fc --- /dev/null +++ b/arch/mips/cobalt/time.c @@ -0,0 +1,35 @@ +/* + * Cobalt time initialization. + * + * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <linux/init.h> + +#include <asm/gt64120.h> +#include <asm/i8253.h> +#include <asm/time.h> + +#define GT641XX_BASE_CLOCK 50000000 /* 50MHz */ + +void __init plat_time_init(void) +{ + setup_pit_timer(); + + gt641xx_set_base_clock(GT641XX_BASE_CLOCK); + + mips_timer_state = gt641xx_timer0_state; +} diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index a3afa39..d7745c8 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -9,6 +9,7 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ time.o topology.o traps.o unaligned.o obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o +obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ irix5sys.o sysirix.o diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c new file mode 100644 index 0000000..4c651b2 --- /dev/null +++ b/arch/mips/kernel/cevt-gt641xx.c @@ -0,0 +1,144 @@ +/* + * GT641xx clockevent routines. + * + * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <linux/clockchips.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> + +#include <asm/gt64120.h> +#include <asm/time.h> + +#include <irq.h> + +static DEFINE_SPINLOCK(gt641xx_timer_lock); +static unsigned int gt641xx_base_clock; + +void gt641xx_set_base_clock(unsigned int clock) +{ + gt641xx_base_clock = clock; +} + +int gt641xx_timer0_state(void) +{ + if (GT_READ(GT_TC0_OFS)) + return 0; + + GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ); + GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK); + + return 1; +} + +static int gt641xx_timer0_set_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(>641xx_timer_lock, flags); + + ctrl = GT_READ(GT_TC_CONTROL_OFS); + ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); + ctrl |= GT_TC_CONTROL_ENTC0_MSK; + + GT_WRITE(GT_TC0_OFS, delta); + GT_WRITE(GT_TC_CONTROL_OFS, ctrl); + + spin_unlock_irqrestore(>641xx_timer_lock, flags); + + return 0; +} + +static void gt641xx_timer0_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(>641xx_timer_lock, flags); + + ctrl = GT_READ(GT_TC_CONTROL_OFS); + ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; + break; + case CLOCK_EVT_MODE_ONESHOT: + ctrl |= GT_TC_CONTROL_ENTC0_MSK; + break; + default: + break; + } + + GT_WRITE(GT_TC_CONTROL_OFS, ctrl); + + spin_unlock_irqrestore(>641xx_timer_lock, flags); +} + +static void gt641xx_timer0_event_handler(struct clock_event_device *dev) +{ +} + +static struct clock_event_device gt641xx_timer0_clockevent = { + .name = "gt641xx-timer0", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .cpumask = CPU_MASK_CPU0, + .irq = GT641XX_TIMER0_IRQ, + .set_next_event = gt641xx_timer0_set_next_event, + .set_mode = gt641xx_timer0_set_mode, + .event_handler = gt641xx_timer0_event_handler, +}; + +static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *cd = >641xx_timer0_clockevent; + + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +static struct irqaction gt641xx_timer0_irqaction = { + .handler = gt641xx_timer0_interrupt, + .flags = IRQF_DISABLED | IRQF_PERCPU, + .name = "gt641xx_timer0", +}; + +static int __init gt641xx_timer0_clockevent_init(void) +{ + struct clock_event_device *cd; + + if (!gt641xx_base_clock) + return 0; + + GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ); + + cd = >641xx_timer0_clockevent; + cd->rating = 200 + gt641xx_base_clock / 10000000; + cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + clockevent_set_clock(cd, gt641xx_base_clock); + + clockevents_register_device(>641xx_timer0_clockevent); + + return setup_irq(GT641XX_TIMER0_IRQ, >641xx_timer0_irqaction); +} +arch_initcall(gt641xx_timer0_clockevent_init); diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index a915e56..ae2984f 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -186,7 +186,7 @@ static int c0_compare_int_usable(void) * IP7 already pending? Try to clear it by acking the timer. */ if (c0_compare_int_pending()) { - write_c0_compare(read_c0_compare()); + write_c0_compare(read_c0_count()); irq_disable_hazard(); if (c0_compare_int_pending()) return 0; @@ -202,7 +202,7 @@ static int c0_compare_int_usable(void) if (!c0_compare_int_pending()) return 0; - write_c0_compare(read_c0_compare()); + write_c0_compare(read_c0_count()); irq_disable_hazard(); if (c0_compare_int_pending()) return 0; diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index c4e6866..6c6849a 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -195,8 +195,8 @@ void __cpuinit clockevent_set_clock(struct clock_event_device *cd, /* Find a shift value */ for (shift = 32; shift > 0; shift--) { - temp = (u64) NSEC_PER_SEC << shift; - do_div(temp, clock); + temp = (u64) clock << shift; + do_div(temp, NSEC_PER_SEC); if ((temp >> 32) == 0) break; } diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 1d00b77..9d6243a 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -147,21 +147,8 @@ void __init plat_time_init(void) #endif } -//static irqreturn_t mips_perf_interrupt(int irq, void *dev_id) -//{ -// return perf_irq(); -//} - -//static struct irqaction perf_irqaction = { -// .handler = mips_perf_interrupt, -// .flags = IRQF_DISABLED | IRQF_PERCPU, -// .name = "performance", -//}; - void __init plat_perf_setup(void) { -// struct irqaction *irq = &perf_irqaction; - cp0_perfcount_irq = -1; #ifdef MSC01E_INT_BASE diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 98b5e5b..b0b034c 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -165,12 +165,11 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, for (i = 0; i < nents; i++, sg++) { unsigned long addr; - addr = (unsigned long) page_address(sg->page); + addr = (unsigned long) sg_virt(sg); if (!plat_device_is_coherent(dev) && addr) - __dma_sync(addr + sg->offset, sg->length, direction); + __dma_sync(addr, sg->length, direction); sg->dma_address = plat_map_dma_mem(dev, - (void *)(addr + sg->offset), - sg->length); + (void *)addr, sg->length); } return nents; @@ -223,10 +222,9 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, for (i = 0; i < nhwentries; i++, sg++) { if (!plat_device_is_coherent(dev) && direction != DMA_TO_DEVICE) { - addr = (unsigned long) page_address(sg->page); + addr = (unsigned long) sg_virt(sg); if (addr) - __dma_sync(addr + sg->offset, sg->length, - direction); + __dma_sync(addr, sg->length, direction); } plat_unmap_dma_mem(sg->dma_address); } @@ -304,7 +302,7 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, /* Make sure that gcc doesn't leave the empty loop body. */ for (i = 0; i < nelems; i++, sg++) { if (cpu_is_noncoherent_r10000(dev)) - __dma_sync((unsigned long)page_address(sg->page), + __dma_sync((unsigned long)page_address(sg_page(sg)), sg->length, direction); plat_unmap_dma_mem(sg->dma_address); } @@ -322,7 +320,7 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nele /* Make sure that gcc doesn't leave the empty loop body. */ for (i = 0; i < nelems; i++, sg++) { if (!plat_device_is_coherent(dev)) - __dma_sync((unsigned long)page_address(sg->page), + __dma_sync((unsigned long)page_address(sg_page(sg)), sg->length, direction); plat_unmap_dma_mem(sg->dma_address); } diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c index 681b593..3305fa9 100644 --- a/arch/mips/sgi-ip27/ip27-init.c +++ b/arch/mips/sgi-ip27/ip27-init.c @@ -110,7 +110,7 @@ static void __init per_hub_init(cnodeid_t cnode) } } -void __init per_cpu_init(void) +void __cpuinit per_cpu_init(void) { int cpu = smp_processor_id(); int slice = LOCAL_HUB_L(PI_CPU_NUM); diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index d467bf4..f5dccf0 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -111,8 +111,24 @@ unsigned long read_persistent_clock(void) return mktime(year, month, date, hour, min, sec); } -static int rt_set_next_event(unsigned long delta, - struct clock_event_device *evt) +static void enable_rt_irq(unsigned int irq) +{ +} + +static void disable_rt_irq(unsigned int irq) +{ +} + +static struct irq_chip rt_irq_type = { + .name = "SN HUB RT timer", + .ack = disable_rt_irq, + .mask = disable_rt_irq, + .mask_ack = disable_rt_irq, + .unmask = enable_rt_irq, + .eoi = enable_rt_irq, +}; + +static int rt_next_event(unsigned long delta, struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); int slice = cputoslice(cpu) == 0; @@ -129,50 +145,24 @@ static void rt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: + case CLOCK_EVT_MODE_ONESHOT: /* The only mode supported */ break; + case CLOCK_EVT_MODE_PERIODIC: case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_ONESHOT: case CLOCK_EVT_MODE_RESUME: /* Nothing to do */ break; } } -struct clock_event_device rt_clock_event_device = { - .name = "HUB-RT", - .features = CLOCK_EVT_FEAT_ONESHOT, - - .rating = 300, - .set_next_event = rt_set_next_event, - .set_mode = rt_set_mode, -}; - -static void enable_rt_irq(unsigned int irq) -{ -} - -static void disable_rt_irq(unsigned int irq) -{ -} - -static struct irq_chip rt_irq_type = { - .name = "SN HUB RT timer", - .ack = disable_rt_irq, - .mask = disable_rt_irq, - .mask_ack = disable_rt_irq, - .unmask = enable_rt_irq, - .eoi = enable_rt_irq, -}; - unsigned int rt_timer_irq; -static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id) +static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id) { - struct clock_event_device *cd = &rt_clock_event_device; + struct clock_event_device *cd = dev_id; unsigned int cpu = smp_processor_id(); int slice = cputoslice(cpu) == 0; @@ -182,11 +172,10 @@ static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction rt_irqaction = { - .handler = (irq_handler_t) ip27_rt_timer_interrupt, - .flags = IRQF_DISABLED, - .mask = CPU_MASK_NONE, - .name = "timer" +struct irqaction hub_rt_irqaction = { + .handler = hub_rt_counter_handler, + .flags = IRQF_DISABLED | IRQF_PERCPU, + .name = "hub-rt", }; /* @@ -200,32 +189,48 @@ static struct irqaction rt_irqaction = { #define NSEC_PER_CYCLE 800 #define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE) -static void __init ip27_rt_clock_event_init(void) +static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent); +static DEFINE_PER_CPU(char [11], hub_rt_name); + +static void __cpuinit hub_rt_clock_event_init(void) { - struct clock_event_device *cd = &rt_clock_event_device; unsigned int cpu = smp_processor_id(); - int irq = allocate_irqno(); - - if (irq < 0) - panic("Can't allocate interrupt number for timer interrupt"); - - rt_timer_irq = irq; - + struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu); + unsigned char *name = per_cpu(hub_rt_name, cpu); + int irq = rt_timer_irq; + + sprintf(name, "hub-rt %d", cpu); + cd->name = "HUB-RT", + cd->features = CLOCK_EVT_FEAT_ONESHOT, + clockevent_set_clock(cd, CYCLES_PER_SEC); + cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + cd->rating = 200, cd->irq = irq, cd->cpumask = cpumask_of_cpu(cpu), - - /* - * Calculate the min / max delta - */ - cd->mult = - div_sc((unsigned long) CYCLES_PER_SEC, NSEC_PER_SEC, 32); - cd->shift = 32; - cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); - cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + cd->rating = 300, + cd->set_next_event = rt_next_event, + cd->set_mode = rt_set_mode, clockevents_register_device(cd); +} + +static void __init hub_rt_clock_event_global_init(void) +{ + unsigned int irq; + + do { + smp_wmb(); + irq = rt_timer_irq; + if (irq) + break; + + irq = allocate_irqno(); + if (irq < 0) + panic("Allocation of irq number for timer failed"); + } while (xchg(&rt_timer_irq, irq)); set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq); - setup_irq(irq, &rt_irqaction); + setup_irq(irq, &hub_rt_irqaction); } static cycle_t hub_rt_read(void) @@ -233,27 +238,29 @@ static cycle_t hub_rt_read(void) return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); } -struct clocksource ht_rt_clocksource = { +struct clocksource hub_rt_clocksource = { .name = "HUB-RT", .rating = 200, .read = hub_rt_read, .mask = CLOCKSOURCE_MASK(52), - .shift = 32, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static void __init ip27_rt_clocksource_init(void) +static void __init hub_rt_clocksource_init(void) { - clocksource_register(&ht_rt_clocksource); + struct clocksource *cs = &hub_rt_clocksource; + + clocksource_set_clock(cs, CYCLES_PER_SEC); + clocksource_register(cs); } void __init plat_time_init(void) { - ip27_rt_clock_event_init(); - ip27_rt_clocksource_init(); + hub_rt_clocksource_init(); + hub_rt_clock_event_global_init(); } -void __init cpu_time_init(void) +void __cpuinit cpu_time_init(void) { lboard_t *board; klcpu_t *cpu; @@ -271,6 +278,7 @@ void __init cpu_time_init(void) printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed); + hub_rt_clock_event_init(); set_c0_status(SRB_TIMOCLK); } diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index 7aa79bf..10299ba 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c @@ -452,6 +452,43 @@ static void bcm1480_kgdb_interrupt(void) extern void bcm1480_mailbox_interrupt(void); +static inline void dispatch_ip4(void) +{ + int cpu = smp_processor_id(); + int irq = K_BCM1480_INT_TIMER_0 + cpu; + + /* Reset the timer */ + __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, + IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); + + do_IRQ(irq); +} + +static inline void dispatch_ip2(void) +{ + unsigned long long mask_h, mask_l; + unsigned int cpu = smp_processor_id(); + unsigned long base; + + /* + * Default...we've hit an IP[2] interrupt, which means we've got to + * check the 1480 interrupt registers to figure out what to do. Need + * to detect which CPU we're on, now that smp_affinity is supported. + */ + base = A_BCM1480_IMR_MAPPER(cpu); + mask_h = __raw_readq( + IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H)); + mask_l = __raw_readq( + IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L)); + + if (mask_h) { + if (mask_h ^ 1) + do_IRQ(fls64(mask_h) - 1); + else if (mask_l) + do_IRQ(63 + fls64(mask_l)); + } +} + asmlinkage void plat_irq_dispatch(void) { unsigned int pending; @@ -469,17 +506,8 @@ asmlinkage void plat_irq_dispatch(void) else #endif - if (pending & CAUSEF_IP4) { - int cpu = smp_processor_id(); - int irq = K_BCM1480_INT_TIMER_0 + cpu; - - /* Reset the timer */ - __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - - do_IRQ(irq); - } - + if (pending & CAUSEF_IP4) + dispatch_ip4(); #ifdef CONFIG_SMP else if (pending & CAUSEF_IP3) bcm1480_mailbox_interrupt(); @@ -490,27 +518,6 @@ asmlinkage void plat_irq_dispatch(void) bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */ #endif - else if (pending & CAUSEF_IP2) { - unsigned long long mask_h, mask_l; - unsigned long base; - - /* - * Default...we've hit an IP[2] interrupt, which means we've - * got to check the 1480 interrupt registers to figure out what - * to do. Need to detect which CPU we're on, now that - * smp_affinity is supported. - */ - base = A_BCM1480_IMR_MAPPER(smp_processor_id()); - mask_h = __raw_readq( - IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H)); - mask_l = __raw_readq( - IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L)); - - if (mask_h) { - if (mask_h ^ 1) - do_IRQ(fls64(mask_h) - 1); - else - do_IRQ(63 + fls64(mask_l)); - } - } + else if (pending & CAUSEF_IP2) + dispatch_ip2(); } diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c index 02b266a..436ba78 100644 --- a/arch/mips/sibyte/bcm1480/smp.c +++ b/arch/mips/sibyte/bcm1480/smp.c @@ -58,7 +58,7 @@ static void *mailbox_0_regs[] = { /* * SMP init and finish on secondary CPUs */ -void bcm1480_smp_init(void) +void __cpuinit bcm1480_smp_init(void) { unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | STATUSF_IP1 | STATUSF_IP0; @@ -67,7 +67,7 @@ void bcm1480_smp_init(void) change_c0_status(ST0_IM, imask); } -void bcm1480_smp_finish(void) +void __cpuinit bcm1480_smp_finish(void) { extern void sb1480_clockevent_init(void); diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index c730744..610f025 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -15,22 +15,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* - * These are routines to set up and handle interrupts from the - * bcm1480 general purpose timer 0. We're using the timer as a - * system clock, so we set it up to run at 100 Hz. On every - * interrupt, we update our idea of what the time of day is, - * then call do_timer() in the architecture-independent kernel - * code to do general bookkeeping (e.g. update jiffies, run - * bottom halves, etc.) - */ #include <linux/clockchips.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/percpu.h> #include <linux/spinlock.h> -#include <asm/irq.h> #include <asm/addrspace.h> #include <asm/time.h> #include <asm/io.h> @@ -47,33 +37,10 @@ #define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 #define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 -#ifdef CONFIG_SIMULATION -#define BCM1480_HPT_VALUE 50000 -#else -#define BCM1480_HPT_VALUE 1000000 -#endif - extern int bcm1480_steal_irq(int irq); -void __init plat_time_init(void) -{ - unsigned int cpu = smp_processor_id(); - unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; - - BUG_ON(cpu > 3); /* Only have 4 general purpose timers */ - - bcm1480_mask_irq(cpu, irq); - - /* Map the timer interrupt to ip[4] of this cpu */ - __raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) - + (irq<<3))); - - bcm1480_unmask_irq(cpu, irq); - bcm1480_steal_irq(irq); -} - /* - * The general purpose timer ticks at 1 Mhz independent if + * The general purpose timer ticks at 1MHz independent if * the rest of the system */ static void sibyte_set_mode(enum clock_event_mode mode, @@ -88,7 +55,7 @@ static void sibyte_set_mode(enum clock_event_mode mode, switch (mode) { case CLOCK_EVT_MODE_PERIODIC: __raw_writeq(0, timer_cfg); - __raw_writeq(BCM1480_HPT_VALUE / HZ - 1, timer_init); + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init); __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, timer_cfg); break; @@ -121,80 +88,96 @@ static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) return res; } -static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); - static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) { unsigned int cpu = smp_processor_id(); - struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); + struct clock_event_device *cd = dev_id; + void __iomem *timer_cfg; + + timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); /* Reset the timer */ __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); + timer_cfg); cd->event_handler(cd); return IRQ_HANDLED; } -static struct irqaction sibyte_counter_irqaction = { - .handler = sibyte_counter_handler, - .flags = IRQF_DISABLED | IRQF_PERCPU, - .name = "timer", -}; +static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); +static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction); +static DEFINE_PER_CPU(char [18], sibyte_hpt_name); -/* - * This interrupt is "special" in that it doesn't use the request_irq - * way to hook the irq line. The timer interrupt is initialized early - * enough to make this a major pain, and it's also firing enough to - * warrant a bit of special case code. bcm1480_timer_interrupt is - * called directly from irq_handler.S when IP[4] is set during an - * interrupt - */ void __cpuinit sb1480_clockevent_init(void) { unsigned int cpu = smp_processor_id(); unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; + struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu); struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); + unsigned char *name = per_cpu(sibyte_hpt_name, cpu); + + BUG_ON(cpu > 3); /* Only have 4 general purpose timers */ - cd->name = "bcm1480-counter"; + sprintf(name, "bcm1480-counter %d", cpu); + cd->name = name; cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_MODE_ONESHOT; + clockevent_set_clock(cd, V_SCD_TIMER_FREQ); + cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd); + cd->min_delta_ns = clockevent_delta2ns(1, cd); + cd->rating = 200; + cd->irq = irq; + cd->cpumask = cpumask_of_cpu(cpu); cd->set_next_event = sibyte_next_event; cd->set_mode = sibyte_set_mode; - cd->irq = irq; - clockevent_set_clock(cd, BCM1480_HPT_VALUE); + clockevents_register_device(cd); + + bcm1480_mask_irq(cpu, irq); + + /* + * Map timer interrupt to IP[4] of this cpu + */ + __raw_writeq(IMR_IP4_VAL, + IOADDR(A_BCM1480_IMR_REGISTER(cpu, + R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (irq << 3))); - setup_irq(irq, &sibyte_counter_irqaction); + bcm1480_unmask_irq(cpu, irq); + bcm1480_steal_irq(irq); + + action->handler = sibyte_counter_handler; + action->flags = IRQF_DISABLED | IRQF_PERCPU; + action->name = name; + action->dev_id = cd; + setup_irq(irq, action); } static cycle_t bcm1480_hpt_read(void) { - /* We assume this function is called xtime_lock held. */ - unsigned long count = - __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT))); - return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count; + return (cycle_t) __raw_readq(IOADDR(A_SCD_ZBBUS_CYCLE_COUNT)); } struct clocksource bcm1480_clocksource = { - .name = "MIPS", + .name = "zbbus-cycles", .rating = 200, .read = bcm1480_hpt_read, - .mask = CLOCKSOURCE_MASK(32), - .shift = 32, + .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; void __init sb1480_clocksource_init(void) { struct clocksource *cs = &bcm1480_clocksource; + unsigned int plldiv; + unsigned long zbbus; - clocksource_set_clock(cs, BCM1480_HPT_VALUE); + plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG))); + zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000); + clocksource_set_clock(cs, zbbus); clocksource_register(cs); } -void __init bcm1480_hpt_setup(void) +void __init plat_time_init(void) { - mips_hpt_frequency = BCM1480_HPT_VALUE; sb1480_clocksource_init(); sb1480_clockevent_init(); } diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index 500d17e..53780a1 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c @@ -402,6 +402,22 @@ static void sb1250_kgdb_interrupt(void) extern void sb1250_mailbox_interrupt(void); +static inline void dispatch_ip2(void) +{ + unsigned int cpu = smp_processor_id(); + unsigned long long mask; + + /* + * Default...we've hit an IP[2] interrupt, which means we've got to + * check the 1250 interrupt registers to figure out what to do. Need + * to detect which CPU we're on, now that smp_affinity is supported. + */ + mask = __raw_readq(IOADDR(A_IMR_REGISTER(cpu, + R_IMR_INTERRUPT_STATUS_BASE))); + if (mask) + do_IRQ(fls64(mask) - 1); +} + asmlinkage void plat_irq_dispatch(void) { unsigned int cpu = smp_processor_id(); @@ -434,21 +450,8 @@ asmlinkage void plat_irq_dispatch(void) sb1250_kgdb_interrupt(); #endif - else if (pending & CAUSEF_IP2) { - unsigned long long mask; - - /* - * Default...we've hit an IP[2] interrupt, which means we've - * got to check the 1250 interrupt registers to figure out what - * to do. Need to detect which CPU we're on, now that - * smp_affinity is supported. - */ - mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(), - R_IMR_INTERRUPT_STATUS_BASE))); - if (mask) - do_IRQ(fls64(mask) - 1); - else - spurious_interrupt(); - } else + else if (pending & CAUSEF_IP2) + dispatch_ip2(); + else spurious_interrupt(); } diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c index aaa4f30..3f52c95 100644 --- a/arch/mips/sibyte/sb1250/smp.c +++ b/arch/mips/sibyte/sb1250/smp.c @@ -46,7 +46,7 @@ static void *mailbox_regs[] = { /* * SMP init and finish on secondary CPUs */ -void sb1250_smp_init(void) +void __cpuinit sb1250_smp_init(void) { unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | STATUSF_IP1 | STATUSF_IP0; @@ -55,7 +55,7 @@ void sb1250_smp_init(void) change_c0_status(ST0_IM, imask); } -void sb1250_smp_finish(void) +void __cpuinit sb1250_smp_finish(void) { extern void sb1250_clockevent_init(void); diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 9ef5462..a41e908 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -52,26 +52,6 @@ extern int sb1250_steal_irq(int irq); -static cycle_t sb1250_hpt_read(void); - -void __init sb1250_hpt_setup(void) -{ - int cpu = smp_processor_id(); - - if (!cpu) { - /* Setup hpt using timer #3 but do not enable irq for it */ - __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); - __raw_writeq(SB1250_HPT_VALUE, - IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT))); - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); - - mips_hpt_frequency = V_SCD_TIMER_FREQ; - clocksource_mips.read = sb1250_hpt_read; - clocksource_mips.mask = M_SCD_TIMER_INIT; - } -} - /* * The general purpose timer ticks at 1 Mhz independent if * the rest of the system @@ -121,18 +101,14 @@ sibyte_next_event(unsigned long delta, struct clock_event_device *evt) return 0; } -struct clock_event_device sibyte_hpt_clockevent = { - .name = "sb1250-counter", - .features = CLOCK_EVT_FEAT_PERIODIC, - .set_mode = sibyte_set_mode, - .set_next_event = sibyte_next_event, - .shift = 32, - .irq = 0, -}; - static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) { - struct clock_event_device *cd = &sibyte_hpt_clockevent; + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd = dev_id; + + /* ACK interrupt */ + ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); cd->event_handler(cd); @@ -145,15 +121,35 @@ static struct irqaction sibyte_irqaction = { .name = "timer", }; +static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); +static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction); +static DEFINE_PER_CPU(char [18], sibyte_hpt_name); + void __cpuinit sb1250_clockevent_init(void) { - struct clock_event_device *cd = &sibyte_hpt_clockevent; unsigned int cpu = smp_processor_id(); - int irq = K_INT_TIMER_0 + cpu; + unsigned int irq = K_INT_TIMER_0 + cpu; + struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu); + struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); + unsigned char *name = per_cpu(sibyte_hpt_name, cpu); /* Only have 4 general purpose timers, and we use last one as hpt */ BUG_ON(cpu > 2); + sprintf(name, "bcm1480-counter %d", cpu); + cd->name = name; + cd->features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_MODE_ONESHOT; + clockevent_set_clock(cd, V_SCD_TIMER_FREQ); + cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd); + cd->min_delta_ns = clockevent_delta2ns(1, cd); + cd->rating = 200; + cd->irq = irq; + cd->cpumask = cpumask_of_cpu(cpu); + cd->set_next_event = sibyte_next_event; + cd->set_mode = sibyte_set_mode; + clockevents_register_device(cd); + sb1250_mask_irq(cpu, irq); /* Map the timer interrupt to ip[4] of this cpu */ @@ -165,17 +161,11 @@ void __cpuinit sb1250_clockevent_init(void) sb1250_unmask_irq(cpu, irq); sb1250_steal_irq(irq); - /* - * This interrupt is "special" in that it doesn't use the request_irq - * way to hook the irq line. The timer interrupt is initialized early - * enough to make this a major pain, and it's also firing enough to - * warrant a bit of special case code. sb1250_timer_interrupt is - * called directly from irq_handler.S when IP[4] is set during an - * interrupt - */ + action->handler = sibyte_counter_handler; + action->flags = IRQF_DISABLED | IRQF_PERCPU; + action->name = name; + action->dev_id = cd; setup_irq(irq, &sibyte_irqaction); - - clockevents_register_device(cd); } /* @@ -195,8 +185,7 @@ struct clocksource bcm1250_clocksource = { .name = "MIPS", .rating = 200, .read = sb1250_hpt_read, - .mask = CLOCKSOURCE_MASK(32), - .shift = 32, + .mask = CLOCKSOURCE_MASK(23), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -204,6 +193,17 @@ void __init sb1250_clocksource_init(void) { struct clocksource *cs = &bcm1250_clocksource; + /* Setup hpt using timer #3 but do not enable irq for it */ + __raw_writeq(0, + IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, + R_SCD_TIMER_CFG))); + __raw_writeq(SB1250_HPT_VALUE, + IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, + R_SCD_TIMER_INIT))); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, + R_SCD_TIMER_CFG))); + clocksource_set_clock(cs, V_SCD_TIMER_FREQ); clocksource_register(cs); } diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts index bc45f5f..6731763 100644 --- a/arch/powerpc/boot/dts/lite5200.dts +++ b/arch/powerpc/boot/dts/lite5200.dts @@ -70,18 +70,16 @@ }; gpt@600 { // General Purpose Timer - compatible = "mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200-gpt"; cell-index = <0>; reg = <600 10>; interrupts = <1 9 0>; interrupt-parent = <&mpc5200_pic>; - has-wdt; + fsl,has-wdt; }; gpt@610 { // General Purpose Timer - compatible = "mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200-gpt"; cell-index = <1>; reg = <610 10>; interrupts = <1 a 0>; @@ -89,8 +87,7 @@ }; gpt@620 { // General Purpose Timer - compatible = "mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200-gpt"; cell-index = <2>; reg = <620 10>; interrupts = <1 b 0>; @@ -98,8 +95,7 @@ }; gpt@630 { // General Purpose Timer - compatible = "mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200-gpt"; cell-index = <3>; reg = <630 10>; interrupts = <1 c 0>; @@ -107,8 +103,7 @@ }; gpt@640 { // General Purpose Timer - compatible = "mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200-gpt"; cell-index = <4>; reg = <640 10>; interrupts = <1 d 0>; @@ -116,8 +111,7 @@ }; gpt@650 { // General Purpose Timer - compatible = "mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200-gpt"; cell-index = <5>; reg = <650 10>; interrupts = <1 e 0>; @@ -125,8 +119,7 @@ }; gpt@660 { // General Purpose Timer - compatible = "mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200-gpt"; cell-index = <6>; reg = <660 10>; interrupts = <1 f 0>; @@ -134,8 +127,7 @@ }; gpt@670 { // General Purpose Timer - compatible = "mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200-gpt"; cell-index = <7>; reg = <670 10>; interrupts = <1 10 0>; diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts index 6582c9a..b540388 100644 --- a/arch/powerpc/boot/dts/lite5200b.dts +++ b/arch/powerpc/boot/dts/lite5200b.dts @@ -70,18 +70,16 @@ }; gpt@600 { // General Purpose Timer - compatible = "mpc5200b-gpt","mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt"; cell-index = <0>; reg = <600 10>; interrupts = <1 9 0>; interrupt-parent = <&mpc5200_pic>; - has-wdt; + fsl,has-wdt; }; gpt@610 { // General Purpose Timer - compatible = "mpc5200b-gpt","mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt"; cell-index = <1>; reg = <610 10>; interrupts = <1 a 0>; @@ -89,8 +87,7 @@ }; gpt@620 { // General Purpose Timer - compatible = "mpc5200b-gpt","mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt"; cell-index = <2>; reg = <620 10>; interrupts = <1 b 0>; @@ -98,8 +95,7 @@ }; gpt@630 { // General Purpose Timer - compatible = "mpc5200b-gpt","mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt"; cell-index = <3>; reg = <630 10>; interrupts = <1 c 0>; @@ -107,8 +103,7 @@ }; gpt@640 { // General Purpose Timer - compatible = "mpc5200b-gpt","mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt"; cell-index = <4>; reg = <640 10>; interrupts = <1 d 0>; @@ -116,8 +111,7 @@ }; gpt@650 { // General Purpose Timer - compatible = "mpc5200b-gpt","mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt"; cell-index = <5>; reg = <650 10>; interrupts = <1 e 0>; @@ -125,8 +119,7 @@ }; gpt@660 { // General Purpose Timer - compatible = "mpc5200b-gpt","mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt"; cell-index = <6>; reg = <660 10>; interrupts = <1 f 0>; @@ -134,8 +127,7 @@ }; gpt@670 { // General Purpose Timer - compatible = "mpc5200b-gpt","mpc5200-gpt"; - device_type = "gpt"; + compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt"; cell-index = <7>; reg = <670 10>; interrupts = <1 10 0>; diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c index 9001104..14206e3 100644 --- a/arch/powerpc/kernel/dma_64.c +++ b/arch/powerpc/kernel/dma_64.c @@ -161,8 +161,7 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int i; for_each_sg(sgl, sg, nents, i) { - sg->dma_address = (page_to_phys(sg->page) + sg->offset) | - dma_direct_offset; + sg->dma_address = sg_phys(sg) | dma_direct_offset; sg->dma_length = sg->length; } diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 289d7e9..72fd871 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -102,8 +102,7 @@ static int ibmebus_map_sg(struct device *dev, int i; for_each_sg(sgl, sg, nents, i) { - sg->dma_address = (dma_addr_t)page_address(sg->page) - + sg->offset; + sg->dma_address = (dma_addr_t) sg_virt(sg); sg->dma_length = sg->length; } diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 306a6f7..2d0c9ef 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -307,7 +307,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, continue; } /* Allocate iommu entries for that segment */ - vaddr = (unsigned long)page_address(s->page) + s->offset; + vaddr = (unsigned long) sg_virt(s); npages = iommu_num_pages(vaddr, slen); entry = iommu_range_alloc(tbl, npages, &handle, mask >> IOMMU_PAGE_SHIFT, 0); diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 65b7ae4..25d2bfa 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -145,6 +145,9 @@ static void __init lite5200_setup_arch(void) /* Some mpc5200 & mpc5200b related configuration */ mpc5200_setup_xlb_arbiter(); + /* Map wdt for mpc52xx_restart() */ + mpc52xx_map_wdt(); + #ifdef CONFIG_PM mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; mpc52xx_suspend.board_resume_finish = lite5200_resume_finish; @@ -183,5 +186,6 @@ define_machine(lite5200) { .init = mpc52xx_declare_of_platform_devices, .init_IRQ = mpc52xx_init_irq, .get_irq = mpc52xx_get_irq, + .restart = mpc52xx_restart, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 3bc201e0..9850685 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -18,15 +18,20 @@ #include <asm/prom.h> #include <asm/mpc52xx.h> +/* + * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart(). + * Permanent mapping is required because mpc52xx_restart() can be called + * from interrupt context while node mapping (which calls ioremap()) + * cannot be used at such point. + */ +static volatile struct mpc52xx_gpt *mpc52xx_wdt = NULL; -void __iomem * -mpc52xx_find_and_map(const char *compatible) +static void __iomem * +mpc52xx_map_node(struct device_node *ofn) { - struct device_node *ofn; const u32 *regaddr_p; u64 regaddr64, size64; - ofn = of_find_compatible_node(NULL, NULL, compatible); if (!ofn) return NULL; @@ -42,8 +47,23 @@ mpc52xx_find_and_map(const char *compatible) return ioremap((u32)regaddr64, (u32)size64); } + +void __iomem * +mpc52xx_find_and_map(const char *compatible) +{ + return mpc52xx_map_node( + of_find_compatible_node(NULL, NULL, compatible)); +} + EXPORT_SYMBOL(mpc52xx_find_and_map); +void __iomem * +mpc52xx_find_and_map_path(const char *path) +{ + return mpc52xx_map_node(of_find_node_by_path(path)); +} + +EXPORT_SYMBOL(mpc52xx_find_and_map_path); /** * mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device @@ -113,3 +133,46 @@ mpc52xx_declare_of_platform_devices(void) "Error while probing of_platform bus\n"); } +void __init +mpc52xx_map_wdt(void) +{ + const void *has_wdt; + struct device_node *np; + + /* mpc52xx_wdt is mapped here and used in mpc52xx_restart, + * possibly from a interrupt context. wdt is only implement + * on a gpt0, so check has-wdt property before mapping. + */ + for_each_compatible_node(np, NULL, "fsl,mpc5200-gpt") { + has_wdt = of_get_property(np, "fsl,has-wdt", NULL); + if (has_wdt) { + mpc52xx_wdt = mpc52xx_map_node(np); + return; + } + } + for_each_compatible_node(np, NULL, "mpc5200-gpt") { + has_wdt = of_get_property(np, "has-wdt", NULL); + if (has_wdt) { + mpc52xx_wdt = mpc52xx_map_node(np); + return; + } + } +} + +void +mpc52xx_restart(char *cmd) +{ + local_irq_disable(); + + /* Turn on the watchdog and wait for it to expire. + * It effectively does a reset. */ + if (mpc52xx_wdt) { + out_be32(&mpc52xx_wdt->mode, 0x00000000); + out_be32(&mpc52xx_wdt->count, 0x000000ff); + out_be32(&mpc52xx_wdt->mode, 0x00009004); + } else + printk("mpc52xx_restart: Can't access wdt. " + "Restart impossible, system halted.\n"); + + while (1); +} diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 07e64b4..6405f4a 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -628,9 +628,8 @@ static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sgl, int i; for_each_sg(sgl, sg, nents, i) { - int result = ps3_dma_map(dev->d_region, - page_to_phys(sg->page) + sg->offset, sg->length, - &sg->dma_address, 0); + int result = ps3_dma_map(dev->d_region, sg_phys(sg), + sg->length, &sg->dma_address, 0); if (result) { pr_debug("%s:%d: ps3_dma_map failed (%d)\n", diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c index 48492a8..740ad73 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.c +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c @@ -269,6 +269,7 @@ bcom_engine_init(void) int task; phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; unsigned int tdt_size, ctx_size, var_size, fdt_size; + u16 regval; /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); @@ -319,9 +320,11 @@ bcom_engine_init(void) /* Init 'always' initiator */ out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); - /* Disable COMM Bus Prefetch, apparently it's not reliable yet */ - /* FIXME: This should be done on 5200 and not 5200B ... */ - out_be16(&bcom_eng->regs->PtdCntrl, in_be16(&bcom_eng->regs->PtdCntrl) | 1); + /* Disable COMM Bus Prefetch on the original 5200; it's broken */ + if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) { + regval = in_be16(&bcom_eng->regs->PtdCntrl); + out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); + } /* Init lock */ spin_lock_init(&bcom_eng->lock); diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 9c3ed88..97aa50d 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -727,9 +727,8 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, BUG_ON(direction == PCI_DMA_NONE); /* IIep is write-through, not flushing. */ for_each_sg(sgl, sg, nents, n) { - BUG_ON(page_address(sg->page) == NULL); - sg->dvma_address = - virt_to_phys(page_address(sg->page)) + sg->offset; + BUG_ON(page_address(sg_page(sg)) == NULL); + sg->dvma_address = virt_to_phys(sg_virt(sg)); sg->dvma_length = sg->length; } return nents; @@ -748,9 +747,9 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, BUG_ON(direction == PCI_DMA_NONE); if (direction != PCI_DMA_TODEVICE) { for_each_sg(sgl, sg, nents, n) { - BUG_ON(page_address(sg->page) == NULL); + BUG_ON(page_address(sg_page(sg)) == NULL); mmu_inval_dma_area( - (unsigned long) page_address(sg->page), + (unsigned long) page_address(sg_page(sg)), (sg->length + PAGE_SIZE-1) & PAGE_MASK); } } @@ -798,9 +797,9 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sgl, int BUG_ON(direction == PCI_DMA_NONE); if (direction != PCI_DMA_TODEVICE) { for_each_sg(sgl, sg, nents, n) { - BUG_ON(page_address(sg->page) == NULL); + BUG_ON(page_address(sg_page(sg)) == NULL); mmu_inval_dma_area( - (unsigned long) page_address(sg->page), + (unsigned long) page_address(sg_page(sg)), (sg->length + PAGE_SIZE-1) & PAGE_MASK); } } @@ -814,9 +813,9 @@ void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sgl, BUG_ON(direction == PCI_DMA_NONE); if (direction != PCI_DMA_TODEVICE) { for_each_sg(sgl, sg, nents, n) { - BUG_ON(page_address(sg->page) == NULL); + BUG_ON(page_address(sg_page(sg)) == NULL); mmu_inval_dma_area( - (unsigned long) page_address(sg->page), + (unsigned long) page_address(sg_page(sg)), (sg->length + PAGE_SIZE-1) & PAGE_MASK); } } diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index 375b4db..1666087 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -144,7 +144,7 @@ static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus spin_lock_irqsave(&iounit->lock, flags); while (sz != 0) { --sz; - sg->dvma_address = iounit_get_area(iounit, (unsigned long)page_address(sg->page) + sg->offset, sg->length); + sg->dvma_address = iounit_get_area(iounit, sg_virt(sg), sg->length); sg->dvma_length = sg->length; sg = sg_next(sg); } diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 283656d..4b93427 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -238,7 +238,7 @@ static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sb while (sz != 0) { --sz; n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; - sg->dvma_address = iommu_get_one(sg->page, n, sbus) + sg->offset; + sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset; sg->dvma_length = (__u32) sg->length; sg = sg_next(sg); } @@ -252,7 +252,7 @@ static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbu while (sz != 0) { --sz; n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; - sg->dvma_address = iommu_get_one(sg->page, n, sbus) + sg->offset; + sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset; sg->dvma_length = (__u32) sg->length; sg = sg_next(sg); } @@ -273,7 +273,7 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu * XXX Is this a good assumption? * XXX What if someone else unmaps it here and races us? */ - if ((page = (unsigned long) page_address(sg->page)) != 0) { + if ((page = (unsigned long) page_address(sg_page(sg))) != 0) { for (i = 0; i < n; i++) { if (page != oldpage) { /* Already flushed? */ flush_page_for_dma(page); @@ -283,7 +283,7 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu } } - sg->dvma_address = iommu_get_one(sg->page, n, sbus) + sg->offset; + sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset; sg->dvma_length = (__u32) sg->length; sg = sg_next(sg); } diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index ee6708f..a2cc141 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1228,7 +1228,7 @@ static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus * { while (sz != 0) { --sz; - sg->dvma_address = (__u32)sun4c_lockarea(page_address(sg->page) + sg->offset, sg->length); + sg->dvma_address = (__u32)sun4c_lockarea(sg_virt(sg), sg->length); sg->dvma_length = sg->length; sg = sg_next(sg); } diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c index 29af777..070a484 100644 --- a/arch/sparc64/kernel/iommu.c +++ b/arch/sparc64/kernel/iommu.c @@ -472,8 +472,7 @@ static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr, spin_unlock_irqrestore(&iommu->lock, flags); } -#define SG_ENT_PHYS_ADDRESS(SG) \ - (__pa(page_address((SG)->page)) + (SG)->offset) +#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG)))) static void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, int nelems, @@ -565,9 +564,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, /* Fast path single entry scatterlists. */ if (nelems == 1) { sglist->dma_address = - dma_4u_map_single(dev, - (page_address(sglist->page) + - sglist->offset), + dma_4u_map_single(dev, sg_virt(sglist), sglist->length, direction); if (unlikely(sglist->dma_address == DMA_ERROR_CODE)) return 0; diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c index d7ca900..78e8277 100644 --- a/arch/sparc64/kernel/iommu_common.c +++ b/arch/sparc64/kernel/iommu_common.c @@ -73,7 +73,7 @@ static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, daddr = dma_sg->dma_address; sglen = sg->length; - sgaddr = (unsigned long) (page_address(sg->page) + sg->offset); + sgaddr = (unsigned long) sg_virt(sg); while (dlen > 0) { unsigned long paddr; @@ -123,7 +123,7 @@ static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, sg = sg_next(sg); if (--nents <= 0) break; - sgaddr = (unsigned long) (page_address(sg->page) + sg->offset); + sgaddr = (unsigned long) sg_virt(sg); sglen = sg->length; } if (dlen < 0) { @@ -191,7 +191,7 @@ void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int np printk("sg(%d): page_addr(%p) off(%x) length(%x) " "dma_address[%016x] dma_length[%016x]\n", i, - page_address(sg->page), sg->offset, + page_address(sg_page(sg)), sg->offset, sg->length, sg->dma_address, sg->dma_length); } @@ -207,15 +207,14 @@ unsigned long prepare_sg(struct scatterlist *sg, int nents) unsigned long prev; u32 dent_addr, dent_len; - prev = (unsigned long) (page_address(sg->page) + sg->offset); + prev = (unsigned long) sg_virt(sg); prev += (unsigned long) (dent_len = sg->length); - dent_addr = (u32) ((unsigned long)(page_address(sg->page) + sg->offset) - & (IO_PAGE_SIZE - 1UL)); + dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL)); while (--nents) { unsigned long addr; sg = sg_next(sg); - addr = (unsigned long) (page_address(sg->page) + sg->offset); + addr = (unsigned long) sg_virt(sg); if (! VCONTIG(prev, addr)) { dma_sg->dma_address = dent_addr; dma_sg->dma_length = dent_len; diff --git a/arch/sparc64/kernel/ldc.c b/arch/sparc64/kernel/ldc.c index 85a2be0..c8313cb 100644 --- a/arch/sparc64/kernel/ldc.c +++ b/arch/sparc64/kernel/ldc.c @@ -2057,7 +2057,7 @@ static void fill_cookies(struct cookie_state *sp, unsigned long pa, static int sg_count_one(struct scatterlist *sg) { - unsigned long base = page_to_pfn(sg->page) << PAGE_SHIFT; + unsigned long base = page_to_pfn(sg_page(sg)) << PAGE_SHIFT; long len = sg->length; if ((sg->offset | len) & (8UL - 1)) diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index fe46ace..8c4875b 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -365,8 +365,7 @@ static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr, spin_unlock_irqrestore(&iommu->lock, flags); } -#define SG_ENT_PHYS_ADDRESS(SG) \ - (__pa(page_address((SG)->page)) + (SG)->offset) +#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG)))) static long fill_sg(long entry, struct device *dev, struct scatterlist *sg, @@ -477,9 +476,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, /* Fast path single entry scatterlists. */ if (nelems == 1) { sglist->dma_address = - dma_4v_map_single(dev, - (page_address(sglist->page) + - sglist->offset), + dma_4v_map_single(dev, sg_virt(sglist), sglist->length, direction); if (unlikely(sglist->dma_address == DMA_ERROR_CODE)) return 0; diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 25b248a..3a8cd3d 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1115,7 +1115,7 @@ static void do_ubd_request(struct request_queue *q) } prepare_request(req, io_req, (unsigned long long) req->sector << 9, - sg->offset, sg->length, sg->page); + sg->offset, sg->length, sg_page(sg)); last_sectors = sg->length >> 9; n = os_write_file(thread_fd, &io_req, diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index f35ea22..a0ae2e7 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -27,13 +27,22 @@ #include <asm/segment.h> #include <asm/page.h> #include <asm/boot.h> +#include <asm/asm-offsets.h> .section ".text.head","ax",@progbits .globl startup_32 startup_32: - cld - cli + /* check to see if KEEP_SEGMENTS flag is meaningful */ + cmpw $0x207, BP_version(%esi) + jb 1f + + /* test KEEP_SEGMENTS flag to see if the bootloader is asking + * us to not reload segments */ + testb $(1<<6), BP_loadflags(%esi) + jnz 2f + +1: cli movl $(__BOOT_DS),%eax movl %eax,%ds movl %eax,%es @@ -41,6 +50,8 @@ startup_32: movl %eax,%gs movl %eax,%ss +2: cld + /* Calculate the delta between where we were compiled to run * at and where we were actually loaded at. This can only be done * with a short local call on x86. Nothing else will tell us what diff --git a/arch/x86/boot/compressed/misc_32.c b/arch/x86/boot/compressed/misc_32.c index 1dc1e19..b74d60d 100644 --- a/arch/x86/boot/compressed/misc_32.c +++ b/arch/x86/boot/compressed/misc_32.c @@ -247,6 +247,9 @@ static void putstr(const char *s) int x,y,pos; char c; + if (RM_SCREEN_INFO.orig_video_mode == 0 && lines == 0 && cols == 0) + return; + x = RM_SCREEN_INFO.orig_x; y = RM_SCREEN_INFO.orig_y; diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index f3140e5..8353c81 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -119,7 +119,7 @@ _start: # Part 2 of the header, from the old setup.S .ascii "HdrS" # header signature - .word 0x0206 # header version number (>= 0x0105) + .word 0x0207 # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) .globl realmode_swtch realmode_swtch: .word 0, 0 # default_switch, SETUPSEG @@ -214,6 +214,11 @@ cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, #added with boot protocol #version 2.06 +hardware_subarch: .long 0 # subarchitecture, added with 2.07 + # default to 0 for normal x86 PC + +hardware_subarch_data: .quad 0 + # End of setup header ##################################################### .section ".inittext", "ax" diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c index f1b7cdd..f876471 100644 --- a/arch/x86/kernel/asm-offsets_32.c +++ b/arch/x86/kernel/asm-offsets_32.c @@ -15,6 +15,7 @@ #include <asm/fixmap.h> #include <asm/processor.h> #include <asm/thread_info.h> +#include <asm/bootparam.h> #include <asm/elf.h> #include <xen/interface/xen.h> @@ -146,4 +147,10 @@ void foo(void) OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode); OFFSET(LGUEST_PAGES_regs, lguest_pages, regs); #endif + + BLANK(); + OFFSET(BP_scratch, boot_params, scratch); + OFFSET(BP_loadflags, boot_params, hdr.loadflags); + OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch); + OFFSET(BP_version, boot_params, hdr.version); } diff --git a/arch/x86/kernel/e820_32.c b/arch/x86/kernel/e820_32.c index 58fd54e..18f500d 100644 --- a/arch/x86/kernel/e820_32.c +++ b/arch/x86/kernel/e820_32.c @@ -51,6 +51,13 @@ struct resource code_resource = { .flags = IORESOURCE_BUSY | IORESOURCE_MEM }; +struct resource bss_resource = { + .name = "Kernel bss", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + static struct resource system_rom_resource = { .name = "System ROM", .start = 0xf0000, @@ -254,7 +261,9 @@ static void __init probe_roms(void) * and also for regions reported as reserved by the e820. */ static void __init -legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource) +legacy_init_iomem_resources(struct resource *code_resource, + struct resource *data_resource, + struct resource *bss_resource) { int i; @@ -287,6 +296,7 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat */ request_resource(res, code_resource); request_resource(res, data_resource); + request_resource(res, bss_resource); #ifdef CONFIG_KEXEC if (crashk_res.start != crashk_res.end) request_resource(res, &crashk_res); @@ -307,9 +317,11 @@ static int __init request_standard_resources(void) printk("Setting up standard PCI resources\n"); if (efi_enabled) - efi_initialize_iomem_resources(&code_resource, &data_resource); + efi_initialize_iomem_resources(&code_resource, + &data_resource, &bss_resource); else - legacy_init_iomem_resources(&code_resource, &data_resource); + legacy_init_iomem_resources(&code_resource, + &data_resource, &bss_resource); /* EFI systems may still have VGA */ request_resource(&iomem_resource, &video_ram_resource); diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c index 5761686..04698e0 100644 --- a/arch/x86/kernel/e820_64.c +++ b/arch/x86/kernel/e820_64.c @@ -47,7 +47,7 @@ unsigned long end_pfn_map; */ static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT; -extern struct resource code_resource, data_resource; +extern struct resource code_resource, data_resource, bss_resource; /* Check for some hardcoded bad areas that early boot is not allowed to touch */ static inline int bad_addr(unsigned long *addrp, unsigned long size) @@ -225,6 +225,7 @@ void __init e820_reserve_resources(void) */ request_resource(res, &code_resource); request_resource(res, &data_resource); + request_resource(res, &bss_resource); #ifdef CONFIG_KEXEC if (crashk_res.start != crashk_res.end) request_resource(res, &crashk_res); @@ -729,3 +730,22 @@ __init void e820_setup_gap(void) printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n", pci_mem_start, gapstart, gapsize); } + +int __init arch_get_ram_range(int slot, u64 *addr, u64 *size) +{ + int i; + + if (slot < 0 || slot >= e820.nr_map) + return -1; + for (i = slot; i < e820.nr_map; i++) { + if (e820.map[i].type != E820_RAM) + continue; + break; + } + if (i == e820.nr_map || e820.map[i].addr > (max_pfn << PAGE_SHIFT)) + return -1; + *addr = e820.map[i].addr; + *size = min_t(u64, e820.map[i].size + e820.map[i].addr, + max_pfn << PAGE_SHIFT) - *addr; + return i + 1; +} diff --git a/arch/x86/kernel/efi_32.c b/arch/x86/kernel/efi_32.c index b42558c..e2be78f 100644 --- a/arch/x86/kernel/efi_32.c +++ b/arch/x86/kernel/efi_32.c @@ -603,7 +603,8 @@ void __init efi_enter_virtual_mode(void) void __init efi_initialize_iomem_resources(struct resource *code_resource, - struct resource *data_resource) + struct resource *data_resource, + struct resource *bss_resource) { struct resource *res; efi_memory_desc_t *md; @@ -675,6 +676,7 @@ efi_initialize_iomem_resources(struct resource *code_resource, if (md->type == EFI_CONVENTIONAL_MEMORY) { request_resource(res, code_resource); request_resource(res, data_resource); + request_resource(res, bss_resource); #ifdef CONFIG_KEXEC request_resource(res, &crashk_res); #endif diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index 3967796..00b1c2c 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -79,22 +79,30 @@ INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_ */ .section .text.head,"ax",@progbits ENTRY(startup_32) + /* check to see if KEEP_SEGMENTS flag is meaningful */ + cmpw $0x207, BP_version(%esi) + jb 1f + + /* test KEEP_SEGMENTS flag to see if the bootloader is asking + us to not reload segments */ + testb $(1<<6), BP_loadflags(%esi) + jnz 2f /* * Set segments to known values. */ - cld - lgdt boot_gdt_descr - __PAGE_OFFSET +1: lgdt boot_gdt_descr - __PAGE_OFFSET movl $(__BOOT_DS),%eax movl %eax,%ds movl %eax,%es movl %eax,%fs movl %eax,%gs +2: /* * Clear BSS first so that there are no surprises... - * No need to cld as DF is already clear from cld above... */ + cld xorl %eax,%eax movl $__bss_start - __PAGE_OFFSET,%edi movl $__bss_stop - __PAGE_OFFSET,%ecx @@ -128,6 +136,35 @@ ENTRY(startup_32) movsl 1: +#ifdef CONFIG_PARAVIRT + cmpw $0x207, (boot_params + BP_version - __PAGE_OFFSET) + jb default_entry + + /* Paravirt-compatible boot parameters. Look to see what architecture + we're booting under. */ + movl (boot_params + BP_hardware_subarch - __PAGE_OFFSET), %eax + cmpl $num_subarch_entries, %eax + jae bad_subarch + + movl subarch_entries - __PAGE_OFFSET(,%eax,4), %eax + subl $__PAGE_OFFSET, %eax + jmp *%eax + +bad_subarch: +WEAK(lguest_entry) +WEAK(xen_entry) + /* Unknown implementation; there's really + nothing we can do at this point. */ + ud2a +.data +subarch_entries: + .long default_entry /* normal x86/PC */ + .long lguest_entry /* lguest hypervisor */ + .long xen_entry /* Xen hypervisor */ +num_subarch_entries = (. - subarch_entries) / 4 +.previous +#endif /* CONFIG_PARAVIRT */ + /* * Initialize page tables. This creates a PDE and a set of page * tables, which are located immediately beyond _end. The variable @@ -140,6 +177,7 @@ ENTRY(startup_32) */ page_pde_offset = (__PAGE_OFFSET >> 20); +default_entry: movl $(pg0 - __PAGE_OFFSET), %edi movl $(swapper_pg_dir - __PAGE_OFFSET), %edx movl $0x007, %eax /* 0x007 = PRESENT+RW+USER */ diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c index b3c2d26..953328b 100644 --- a/arch/x86/kernel/io_apic_64.c +++ b/arch/x86/kernel/io_apic_64.c @@ -31,6 +31,7 @@ #include <linux/sysdev.h> #include <linux/msi.h> #include <linux/htirq.h> +#include <linux/dmar.h> #ifdef CONFIG_ACPI #include <acpi/acpi_bus.h> #endif @@ -2031,8 +2032,64 @@ void arch_teardown_msi_irq(unsigned int irq) destroy_irq(irq); } -#endif /* CONFIG_PCI_MSI */ +#ifdef CONFIG_DMAR +#ifdef CONFIG_SMP +static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask) +{ + struct irq_cfg *cfg = irq_cfg + irq; + struct msi_msg msg; + unsigned int dest; + cpumask_t tmp; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) + return; + + if (assign_irq_vector(irq, mask)) + return; + + cpus_and(tmp, cfg->domain, mask); + dest = cpu_mask_to_apicid(tmp); + + dmar_msi_read(irq, &msg); + + msg.data &= ~MSI_DATA_VECTOR_MASK; + msg.data |= MSI_DATA_VECTOR(cfg->vector); + msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; + msg.address_lo |= MSI_ADDR_DEST_ID(dest); + + dmar_msi_write(irq, &msg); + irq_desc[irq].affinity = mask; +} +#endif /* CONFIG_SMP */ + +struct irq_chip dmar_msi_type = { + .name = "DMAR_MSI", + .unmask = dmar_msi_unmask, + .mask = dmar_msi_mask, + .ack = ack_apic_edge, +#ifdef CONFIG_SMP + .set_affinity = dmar_msi_set_affinity, +#endif + .retrigger = ioapic_retrigger_irq, +}; + +int arch_setup_dmar_msi(unsigned int irq) +{ + int ret; + struct msi_msg msg; + + ret = msi_compose_msg(NULL, irq, &msg); + if (ret < 0) + return ret; + dmar_msi_write(irq, &msg); + set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq, + "edge"); + return 0; +} +#endif +#endif /* CONFIG_PCI_MSI */ /* * Hypertransport interrupt support */ diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 5098f58..1a20fe31 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -411,8 +411,10 @@ static int calgary_nontranslate_map_sg(struct device* dev, int i; for_each_sg(sg, s, nelems, i) { - BUG_ON(!s->page); - s->dma_address = virt_to_bus(page_address(s->page) +s->offset); + struct page *p = sg_page(s); + + BUG_ON(!p); + s->dma_address = virt_to_bus(sg_virt(s)); s->dma_length = s->length; } return nelems; @@ -432,9 +434,9 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg, return calgary_nontranslate_map_sg(dev, sg, nelems, direction); for_each_sg(sg, s, nelems, i) { - BUG_ON(!s->page); + BUG_ON(!sg_page(s)); - vaddr = (unsigned long)page_address(s->page) + s->offset; + vaddr = (unsigned long) sg_virt(s); npages = num_dma_pages(vaddr, s->length); entry = iommu_range_alloc(tbl, npages); diff --git a/arch/x86/kernel/pci-dma_64.c b/arch/x86/kernel/pci-dma_64.c index afaf9f1..393e272 100644 --- a/arch/x86/kernel/pci-dma_64.c +++ b/arch/x86/kernel/pci-dma_64.c @@ -7,6 +7,7 @@ #include <linux/string.h> #include <linux/pci.h> #include <linux/module.h> +#include <linux/dmar.h> #include <asm/io.h> #include <asm/iommu.h> #include <asm/calgary.h> @@ -305,6 +306,8 @@ void __init pci_iommu_alloc(void) detect_calgary(); #endif + detect_intel_iommu(); + #ifdef CONFIG_SWIOTLB pci_swiotlb_init(); #endif @@ -316,6 +319,8 @@ static int __init pci_iommu_init(void) calgary_iommu_init(); #endif + intel_iommu_init(); + #ifdef CONFIG_IOMMU gart_iommu_init(); #endif diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 5cdfab6..c56e9ee 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -302,7 +302,7 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, #endif for_each_sg(sg, s, nents, i) { - unsigned long addr = page_to_phys(s->page) + s->offset; + unsigned long addr = sg_phys(s); if (nonforced_iommu(dev, addr, s->length)) { addr = dma_map_area(dev, addr, s->length, dir); if (addr == bad_dma_address) { @@ -397,7 +397,7 @@ static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, start_sg = sgmap = sg; ps = NULL; /* shut up gcc */ for_each_sg(sg, s, nents, i) { - dma_addr_t addr = page_to_phys(s->page) + s->offset; + dma_addr_t addr = sg_phys(s); s->dma_address = addr; BUG_ON(s->length == 0); diff --git a/arch/x86/kernel/pci-nommu_64.c b/arch/x86/kernel/pci-nommu_64.c index e85d436..faf70bd 100644 --- a/arch/x86/kernel/pci-nommu_64.c +++ b/arch/x86/kernel/pci-nommu_64.c @@ -62,8 +62,8 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg, int i; for_each_sg(sg, s, nents, i) { - BUG_ON(!s->page); - s->dma_address = virt_to_bus(page_address(s->page) +s->offset); + BUG_ON(!sg_page(s)); + s->dma_address = virt_to_bus(sg_virt(s)); if (!check_addr("map_sg", hwdev, s->dma_address, s->length)) return 0; s->dma_length = s->length; diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c index ba2e165..cc0e914 100644 --- a/arch/x86/kernel/setup_32.c +++ b/arch/x86/kernel/setup_32.c @@ -60,6 +60,7 @@ #include <asm/vmi.h> #include <setup_arch.h> #include <bios_ebda.h> +#include <asm/cacheflush.h> /* This value is set up by the early boot code to point to the value immediately after the boot time page tables. It contains a *physical* @@ -73,6 +74,7 @@ int disable_pse __devinitdata = 0; */ extern struct resource code_resource; extern struct resource data_resource; +extern struct resource bss_resource; /* cpu data as detected by the assembly code in head.S */ struct cpuinfo_x86 new_cpu_data __cpuinitdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; @@ -600,6 +602,8 @@ void __init setup_arch(char **cmdline_p) code_resource.end = virt_to_phys(_etext)-1; data_resource.start = virt_to_phys(_etext); data_resource.end = virt_to_phys(_edata)-1; + bss_resource.start = virt_to_phys(&__bss_start); + bss_resource.end = virt_to_phys(&__bss_stop)-1; parse_early_param(); diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index 31322d4..e7a9e36 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c @@ -58,6 +58,7 @@ #include <asm/numa.h> #include <asm/sections.h> #include <asm/dmi.h> +#include <asm/cacheflush.h> /* * Machine setup.. @@ -133,6 +134,12 @@ struct resource code_resource = { .end = 0, .flags = IORESOURCE_RAM, }; +struct resource bss_resource = { + .name = "Kernel bss", + .start = 0, + .end = 0, + .flags = IORESOURCE_RAM, +}; #ifdef CONFIG_PROC_VMCORE /* elfcorehdr= specifies the location of elf core header @@ -276,6 +283,8 @@ void __init setup_arch(char **cmdline_p) code_resource.end = virt_to_phys(&_etext)-1; data_resource.start = virt_to_phys(&_etext); data_resource.end = virt_to_phys(&_edata)-1; + bss_resource.start = virt_to_phys(&__bss_start); + bss_resource.end = virt_to_phys(&__bss_stop)-1; early_identify_cpu(&boot_cpu_data); diff --git a/arch/x86/mm/pageattr_64.c b/arch/x86/mm/pageattr_64.c index c7b7dfe..c40afba 100644 --- a/arch/x86/mm/pageattr_64.c +++ b/arch/x86/mm/pageattr_64.c @@ -61,10 +61,10 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot, return base; } -static void cache_flush_page(void *adr) +void clflush_cache_range(void *adr, int size) { int i; - for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) + for (i = 0; i < size; i += boot_cpu_data.x86_clflush_size) clflush(adr+i); } @@ -80,7 +80,7 @@ static void flush_kernel_map(void *arg) asm volatile("wbinvd" ::: "memory"); else list_for_each_entry(pg, l, lru) { void *adr = page_address(pg); - cache_flush_page(adr); + clflush_cache_range(adr, PAGE_SIZE); } __flush_tlb_all(); } diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index aab25f3..c2d2499 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -750,6 +750,38 @@ config PCI_DOMAINS depends on PCI default y +config DMAR + bool "Support for DMA Remapping Devices (EXPERIMENTAL)" + depends on PCI_MSI && ACPI && EXPERIMENTAL + default y + help + DMA remapping (DMAR) devices support enables independent address + translations for Direct Memory Access (DMA) from devices. + These DMA remapping devices are reported via ACPI tables + and include PCI device scope covered by these DMA + remapping devices. + +config DMAR_GFX_WA + bool "Support for Graphics workaround" + depends on DMAR + default y + help + Current Graphics drivers tend to use physical address + for DMA and avoid using DMA APIs. Setting this config + option permits the IOMMU driver to set a unity map for + all the OS-visible memory. Hence the driver can continue + to use physical addresses for DMA. + +config DMAR_FLOPPY_WA + bool + depends on DMAR + default y + help + Floppy disk drivers are know to bypass DMA API calls + thereby failing to work when IOMMU is enabled. This + workaround will setup a 1:1 mapping for the first + 16M to make floppy (an ISA device) work. + source "drivers/pci/pcie/Kconfig" source "drivers/pci/Kconfig" |