Merge branch 'next/generic' into mips-for-linux-next
Ralf Baechle [Wed, 11 Jan 2012 14:41:47 +0000 (15:41 +0100)]
52 files changed:
arch/mips/alchemy/common/dbdma.c
arch/mips/alchemy/common/time.c
arch/mips/alchemy/devboards/db1200/platform.c
arch/mips/cavium-octeon/setup.c
arch/mips/dec/setup.c
arch/mips/include/asm/bootinfo.h
arch/mips/include/asm/gio_device.h [new file with mode: 0644]
arch/mips/include/asm/hugetlb.h
arch/mips/include/asm/mach-generic/floppy.h
arch/mips/include/asm/mach-jazz/floppy.h
arch/mips/include/asm/page.h
arch/mips/include/asm/pgtable-32.h
arch/mips/jazz/irq.c
arch/mips/kernel/cevt-bcm1480.c
arch/mips/kernel/cevt-ds1287.c
arch/mips/kernel/cevt-gt641xx.c
arch/mips/kernel/cevt-r4k.c
arch/mips/kernel/cevt-sb1250.c
arch/mips/kernel/cevt-txx9.c
arch/mips/kernel/i8253.c
arch/mips/kernel/rtlx.c
arch/mips/kernel/setup.c
arch/mips/kernel/smtc.c
arch/mips/lantiq/irq.c
arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
arch/mips/mm/Makefile
arch/mips/mm/gup.c [new file with mode: 0644]
arch/mips/mm/init.c
arch/mips/mm/tlb-r4k.c
arch/mips/mti-malta/malta-int.c
arch/mips/pci/ops-pmcmsp.c
arch/mips/pci/ops-tx3927.c
arch/mips/pci/pci-tx4927.c
arch/mips/pci/pci-tx4938.c
arch/mips/pci/pci-tx4939.c
arch/mips/pci/pci.c
arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
arch/mips/pmc-sierra/msp71xx/msp_smp.c
arch/mips/pnx8550/common/int.c
arch/mips/pnx8550/common/time.c
arch/mips/sgi-ip22/Makefile
arch/mips/sgi-ip22/ip22-gio.c [new file with mode: 0644]
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip22/ip22-mc.c
arch/mips/sgi-ip22/ip22-setup.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sni/irq.c
arch/mips/sni/time.c
arch/mips/txx9/generic/pci.c
drivers/video/console/newport_con.c

index 0e63ee4..9ba407b 100644 (file)
@@ -1019,8 +1019,7 @@ static int __init dbdma_setup(unsigned int irq, dbdev_tab_t *idtable)
        dbdma_gptr->ddma_inten = 0xffff;
        au_sync();
 
-       ret = request_irq(irq, dbdma_interrupt, IRQF_DISABLED, "dbdma",
-                         (void *)dbdma_gptr);
+       ret = request_irq(irq, dbdma_interrupt, 0, "dbdma", (void *)dbdma_gptr);
        if (ret)
                printk(KERN_ERR "Cannot grab DBDMA interrupt!\n");
        else {
index d5da6ad..146a5fa 100644 (file)
@@ -92,7 +92,7 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = {
 
 static struct irqaction au1x_rtcmatch2_irqaction = {
        .handler        = au1x_rtcmatch2_irq,
-       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .flags          = IRQF_TIMER,
        .name           = "timer",
        .dev_id         = &au1x_rtcmatch2_clockdev,
 };
index c61867c..78459c1 100644 (file)
@@ -276,12 +276,12 @@ static int db1200_mmc_cd_setup(void *mmc_host, int en)
 
        if (en) {
                ret = request_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd,
-                                 IRQF_DISABLED, "sd_insert", mmc_host);
+                                 0, "sd_insert", mmc_host);
                if (ret)
                        goto out;
 
                ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd,
-                                 IRQF_DISABLED, "sd_eject", mmc_host);
+                                 0, "sd_eject", mmc_host);
                if (ret) {
                        free_irq(DB1200_SD0_INSERT_INT, mmc_host);
                        goto out;
index 853bac4..260b273 100644 (file)
@@ -642,14 +642,6 @@ void __init plat_mem_setup(void)
 
        total = 0;
 
-       /* First add the init memory we will be returning.  */
-       memory = __pa_symbol(&__init_begin) & PAGE_MASK;
-       mem_alloc_size = (__pa_symbol(&__init_end) & PAGE_MASK) - memory;
-       if (mem_alloc_size > 0) {
-               add_memory_region(memory, mem_alloc_size, BOOT_MEM_RAM);
-               total += mem_alloc_size;
-       }
-
        /*
         * The Mips memory init uses the first memory location for
         * some memory vectors. When SPARSEMEM is in use, it doesn't
index f7b7ba6..b874acc 100644 (file)
@@ -110,7 +110,6 @@ static struct irqaction fpuirq = {
 };
 
 static struct irqaction busirq = {
-       .flags = IRQF_DISABLED,
        .name = "bus error",
        .flags = IRQF_NO_THREAD,
 };
index 35cd1ba..7a51d87 100644 (file)
@@ -86,6 +86,7 @@ extern unsigned long mips_machtype;
 #define BOOT_MEM_RAM           1
 #define BOOT_MEM_ROM_DATA      2
 #define BOOT_MEM_RESERVED      3
+#define BOOT_MEM_INIT_RAM      4
 
 /*
  * A memory map that's built upon what was determined
diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h
new file mode 100644 (file)
index 0000000..5437c84
--- /dev/null
@@ -0,0 +1,56 @@
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+struct gio_device_id {
+       __u8 id;
+};
+
+struct gio_device {
+       struct device   dev;
+       struct resource resource;
+       unsigned int    irq;
+       unsigned int    slotno;
+
+       const char      *name;
+       struct gio_device_id id;
+       unsigned        id32:1;
+       unsigned        gio64:1;
+};
+#define to_gio_device(d) container_of(d, struct gio_device, dev)
+
+struct gio_driver {
+       const char    *name;
+       struct module *owner;
+       const struct gio_device_id *id_table;
+
+       int  (*probe)(struct gio_device *, const struct gio_device_id *);
+       void (*remove)(struct gio_device *);
+       int  (*suspend)(struct gio_device *, pm_message_t);
+       int  (*resume)(struct gio_device *);
+       void (*shutdown)(struct gio_device *);
+
+       struct device_driver driver;
+};
+#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver)
+
+extern const struct gio_device_id *gio_match_device(const struct gio_device_id *,
+                                                   const struct gio_device *);
+extern struct gio_device *gio_dev_get(struct gio_device *);
+extern void gio_dev_put(struct gio_device *);
+
+extern int gio_device_register(struct gio_device *);
+extern void gio_device_unregister(struct gio_device *);
+extern void gio_release_dev(struct device *);
+
+static inline void gio_device_free(struct gio_device *dev)
+{
+       gio_release_dev(&dev->dev);
+}
+
+extern int gio_register_driver(struct gio_driver *);
+extern void gio_unregister_driver(struct gio_driver *);
+
+#define gio_get_drvdata(_dev)        drv_get_drvdata(&(_dev)->dev)
+#define gio_set_drvdata(_dev, data)  drv_set_drvdata(&(_dev)->dev, (data))
+
+extern void gio_set_master(struct gio_device *);
index c565b7c..58d3688 100644 (file)
@@ -70,7 +70,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
 static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
                                         unsigned long addr, pte_t *ptep)
 {
-       flush_tlb_mm(vma->vm_mm);
+       flush_tlb_page(vma, addr & huge_page_mask(hstate_vma(vma)));
 }
 
 static inline int huge_pte_none(pte_t pte)
index 001a8ce..a38f4d4 100644 (file)
@@ -98,7 +98,7 @@ static inline void fd_disable_irq(void)
 static inline int fd_request_irq(void)
 {
        return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                          IRQF_DISABLED, "floppy", NULL);
+                          0, "floppy", NULL);
 }
 
 static inline void fd_free_irq(void)
index 56e9ca6..88b5acb 100644 (file)
@@ -90,7 +90,7 @@ static inline void fd_disable_irq(void)
 static inline int fd_request_irq(void)
 {
        return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                          IRQF_DISABLED, "floppy", NULL);
+                          0, "floppy", NULL);
 }
 
 static inline void fd_free_irq(void)
index e59cd1a..d417909 100644 (file)
 #define HPAGE_SIZE     (_AC(1,UL) << HPAGE_SHIFT)
 #define HPAGE_MASK     (~(HPAGE_SIZE - 1))
 #define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
+#else /* !CONFIG_HUGETLB_PAGE */
+# ifndef BUILD_BUG
+#  define BUILD_BUG() do { extern void __build_bug(void); __build_bug(); } while (0)
+# endif
+#define HPAGE_SHIFT    ({BUILD_BUG(); 0; })
+#define HPAGE_SIZE     ({BUILD_BUG(); 0; })
+#define HPAGE_MASK     ({BUILD_BUG(); 0; })
+#define HUGETLB_PAGE_ORDER     ({BUILD_BUG(); 0; })
 #endif /* CONFIG_HUGETLB_PAGE */
 
 #ifndef __ASSEMBLY__
index 4693906..5d56bb2 100644 (file)
 #include <asm-generic/pgtable-nopmd.h>
 
 /*
- * - add_temporary_entry() add a temporary TLB entry. We use TLB entries
- *     starting at the top and working down. This is for populating the
- *     TLB before trap_init() puts the TLB miss handler in place. It
- *     should be used only for entries matching the actual page tables,
- *     to prevent inconsistencies.
- */
-extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
-                              unsigned long entryhi, unsigned long pagemask);
-
-
-/* Basically we have the same two-level (which is the logical three level
+ * Basically we have the same two-level (which is the logical three level
  * Linux page table layout folded) page tables as the i386.  Some day
  * when we have proper page coloring support we can have a 1% quicker
  * tlb refill handling mechanism, but for now it is a bit slower but
index 99ab86f..f21868b 100644 (file)
@@ -134,7 +134,7 @@ static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction r4030_timer_irqaction = {
        .handler        = r4030_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .flags          = IRQF_TIMER,
        .name           = "R4030 timer",
 };
 
index 36c3898..69bbfae 100644 (file)
@@ -145,7 +145,7 @@ void __cpuinit sb1480_clockevent_init(void)
        bcm1480_unmask_irq(cpu, irq);
 
        action->handler = sibyte_counter_handler;
-       action->flags   = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER;
+       action->flags   = IRQF_PERCPU | IRQF_TIMER;
        action->name    = name;
        action->dev_id  = cd;
 
index 939157e..ed648cb 100644 (file)
@@ -108,7 +108,7 @@ static irqreturn_t ds1287_interrupt(int irq, void *dev_id)
 
 static struct irqaction ds1287_irqaction = {
        .handler        = ds1287_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "ds1287",
 };
 
index 339f363..831b475 100644 (file)
@@ -114,7 +114,7 @@ static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
 
 static struct irqaction gt641xx_timer0_irqaction = {
        .handler        = gt641xx_timer0_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "gt641xx_timer0",
 };
 
index e2d8e19..51095dd 100644 (file)
@@ -84,7 +84,7 @@ out:
 
 struct irqaction c0_compare_irqaction = {
        .handler = c0_compare_interrupt,
-       .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags = IRQF_PERCPU | IRQF_TIMER,
        .name = "timer",
 };
 
index 590c54f..e73439f 100644 (file)
@@ -144,7 +144,7 @@ void __cpuinit sb1250_clockevent_init(void)
        sb1250_unmask_irq(cpu, irq);
 
        action->handler = sibyte_counter_handler;
-       action->flags   = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER;
+       action->flags   = IRQF_PERCPU | IRQF_TIMER;
        action->name    = name;
        action->dev_id  = cd;
 
index f0ab92a..e5c30b1 100644 (file)
@@ -146,7 +146,7 @@ static irqreturn_t txx9tmr_interrupt(int irq, void *dev_id)
 
 static struct irqaction txx9tmr_irq = {
        .handler        = txx9tmr_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "txx9tmr",
        .dev_id         = &txx9_clock_event_device,
 };
index 7047bff..c5bc344 100644 (file)
@@ -19,7 +19,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
+       .flags = IRQF_NOBALANCING | IRQF_TIMER,
        .name = "timer"
 };
 
index 933166f..a9d801d 100644 (file)
@@ -473,7 +473,6 @@ static const struct file_operations rtlx_fops = {
 
 static struct irqaction rtlx_irq = {
        .handler        = rtlx_interrupt,
-       .flags          = IRQF_DISABLED,
        .name           = "RTLX",
 };
 
index 84af26a..e86c2cf 100644 (file)
@@ -121,6 +121,9 @@ static void __init print_memory_map(void)
                case BOOT_MEM_RAM:
                        printk(KERN_CONT "(usable)\n");
                        break;
+               case BOOT_MEM_INIT_RAM:
+                       printk(KERN_CONT "(usable after init)\n");
+                       break;
                case BOOT_MEM_ROM_DATA:
                        printk(KERN_CONT "(ROM data)\n");
                        break;
@@ -361,15 +364,24 @@ static void __init bootmem_init(void)
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                unsigned long start, end, size;
 
+               start = PFN_UP(boot_mem_map.map[i].addr);
+               end   = PFN_DOWN(boot_mem_map.map[i].addr
+                                   + boot_mem_map.map[i].size);
+
                /*
                 * Reserve usable memory.
                 */
-               if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+               switch (boot_mem_map.map[i].type) {
+               case BOOT_MEM_RAM:
+                       break;
+               case BOOT_MEM_INIT_RAM:
+                       memory_present(0, start, end);
                        continue;
+               default:
+                       /* Not usable memory */
+                       continue;
+               }
 
-               start = PFN_UP(boot_mem_map.map[i].addr);
-               end   = PFN_DOWN(boot_mem_map.map[i].addr
-                                   + boot_mem_map.map[i].size);
                /*
                 * We are rounding up the start address of usable memory
                 * and at the end of the usable range downwards.
@@ -455,11 +467,33 @@ early_param("mem", early_parse_mem);
 
 static void __init arch_mem_init(char **cmdline_p)
 {
+       phys_t init_mem, init_end, init_size;
+
        extern void plat_mem_setup(void);
 
        /* call board setup routine */
        plat_mem_setup();
 
+       init_mem = PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT;
+       init_end = PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT;
+       init_size = init_end - init_mem;
+       if (init_size) {
+               /* Make sure it is in the boot_mem_map */
+               int i, found;
+               found = 0;
+               for (i = 0; i < boot_mem_map.nr_map; i++) {
+                       if (init_mem >= boot_mem_map.map[i].addr &&
+                           init_mem < (boot_mem_map.map[i].addr +
+                                       boot_mem_map.map[i].size)) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found)
+                       add_memory_region(init_mem, init_size,
+                                         BOOT_MEM_INIT_RAM);
+       }
+
        pr_info("Determined physical RAM map:\n");
        print_memory_map();
 
@@ -523,6 +557,7 @@ static void __init resource_init(void)
                res = alloc_bootmem(sizeof(struct resource));
                switch (boot_mem_map.map[i].type) {
                case BOOT_MEM_RAM:
+               case BOOT_MEM_INIT_RAM:
                case BOOT_MEM_ROM_DATA:
                        res->name = "System RAM";
                        break;
index b1eea63..0a42ff3 100644 (file)
@@ -1130,7 +1130,7 @@ static void ipi_irq_dispatch(void)
 
 static struct irqaction irq_ipi = {
        .handler        = ipi_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "SMTC_IPI"
 };
 
index 51fa0a4..d673731 100644 (file)
@@ -240,7 +240,6 @@ out:
 
 static struct irqaction cascade = {
        .handler = no_action,
-       .flags = IRQF_DISABLED,
        .name = "cascade",
 };
 
index 0cb1b97..5d1f48f 100644 (file)
@@ -111,7 +111,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq5 = {
        .handler = timer_interrupt,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
+       .flags = IRQF_NOBALANCING | IRQF_TIMER,
        .name = "timer"
 };
 
index 4d8c162..3ca2a06 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 obj-y                          += cache.o dma-default.o extable.o fault.o \
-                                  init.o mmap.o tlbex.o tlbex-fault.o uasm.o \
-                                  page.o
+                                  gup.o init.o mmap.o page.o tlbex.o \
+                                  tlbex-fault.o uasm.o
 
 obj-$(CONFIG_32BIT)            += ioremap.o pgtable-32.o
 obj-$(CONFIG_64BIT)            += pgtable-64.o
diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c
new file mode 100644 (file)
index 0000000..33aadbc
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Lockless get_user_pages_fast for MIPS
+ *
+ * Copyright (C) 2008 Nick Piggin
+ * Copyright (C) 2008 Novell Inc.
+ * Copyright (C) 2011 Ralf Baechle
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmstat.h>
+#include <linux/highmem.h>
+#include <linux/swap.h>
+#include <linux/hugetlb.h>
+
+#include <asm/pgtable.h>
+
+static inline pte_t gup_get_pte(pte_t *ptep)
+{
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+       pte_t pte;
+
+retry:
+       pte.pte_low = ptep->pte_low;
+       smp_rmb();
+       pte.pte_high = ptep->pte_high;
+       smp_rmb();
+       if (unlikely(pte.pte_low != ptep->pte_low))
+               goto retry;
+
+       return pte;
+#else
+       return ACCESS_ONCE(*ptep);
+#endif
+}
+
+static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       pte_t *ptep = pte_offset_map(&pmd, addr);
+       do {
+               pte_t pte = gup_get_pte(ptep);
+               struct page *page;
+
+               if (!pte_present(pte) ||
+                   pte_special(pte) || (write && !pte_write(pte))) {
+                       pte_unmap(ptep);
+                       return 0;
+               }
+               VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+               page = pte_page(pte);
+               get_page(page);
+               SetPageReferenced(page);
+               pages[*nr] = page;
+               (*nr)++;
+
+       } while (ptep++, addr += PAGE_SIZE, addr != end);
+
+       pte_unmap(ptep - 1);
+       return 1;
+}
+
+static inline void get_head_page_multiple(struct page *page, int nr)
+{
+       VM_BUG_ON(page != compound_head(page));
+       VM_BUG_ON(page_count(page) == 0);
+       atomic_add(nr, &page->_count);
+       SetPageReferenced(page);
+}
+
+static int gup_huge_pmd(pmd_t pmd, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       pte_t pte = *(pte_t *)&pmd;
+       struct page *head, *page;
+       int refs;
+
+       if (write && !pte_write(pte))
+               return 0;
+       /* hugepages are never "special" */
+       VM_BUG_ON(pte_special(pte));
+       VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+
+       refs = 0;
+       head = pte_page(pte);
+       page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+       do {
+               VM_BUG_ON(compound_head(page) != head);
+               pages[*nr] = page;
+               if (PageTail(page))
+                       get_huge_page_tail(page);
+               (*nr)++;
+               page++;
+               refs++;
+       } while (addr += PAGE_SIZE, addr != end);
+
+       get_head_page_multiple(head, refs);
+       return 1;
+}
+
+static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       unsigned long next;
+       pmd_t *pmdp;
+
+       pmdp = pmd_offset(&pud, addr);
+       do {
+               pmd_t pmd = *pmdp;
+
+               next = pmd_addr_end(addr, end);
+               /*
+                * The pmd_trans_splitting() check below explains why
+                * pmdp_splitting_flush has to flush the tlb, to stop
+                * this gup-fast code from running while we set the
+                * splitting bit in the pmd. Returning zero will take
+                * the slow path that will call wait_split_huge_page()
+                * if the pmd is still in splitting state. gup-fast
+                * can't because it has irq disabled and
+                * wait_split_huge_page() would never return as the
+                * tlb flush IPI wouldn't run.
+                */
+               if (pmd_none(pmd) || pmd_trans_splitting(pmd))
+                       return 0;
+               if (unlikely(pmd_huge(pmd))) {
+                       if (!gup_huge_pmd(pmd, addr, next, write, pages,nr))
+                               return 0;
+               } else {
+                       if (!gup_pte_range(pmd, addr, next, write, pages,nr))
+                               return 0;
+               }
+       } while (pmdp++, addr = next, addr != end);
+
+       return 1;
+}
+
+static int gup_huge_pud(pud_t pud, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       pte_t pte = *(pte_t *)&pud;
+       struct page *head, *page;
+       int refs;
+
+       if (write && !pte_write(pte))
+               return 0;
+       /* hugepages are never "special" */
+       VM_BUG_ON(pte_special(pte));
+       VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+
+       refs = 0;
+       head = pte_page(pte);
+       page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
+       do {
+               VM_BUG_ON(compound_head(page) != head);
+               pages[*nr] = page;
+               (*nr)++;
+               page++;
+               refs++;
+       } while (addr += PAGE_SIZE, addr != end);
+
+       get_head_page_multiple(head, refs);
+       return 1;
+}
+
+static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       unsigned long next;
+       pud_t *pudp;
+
+       pudp = pud_offset(&pgd, addr);
+       do {
+               pud_t pud = *pudp;
+
+               next = pud_addr_end(addr, end);
+               if (pud_none(pud))
+                       return 0;
+               if (unlikely(pud_huge(pud))) {
+                       if (!gup_huge_pud(pud, addr, next, write, pages,nr))
+                               return 0;
+               } else {
+                       if (!gup_pmd_range(pud, addr, next, write, pages,nr))
+                               return 0;
+               }
+       } while (pudp++, addr = next, addr != end);
+
+       return 1;
+}
+
+/*
+ * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
+ * back to the regular GUP.
+ */
+int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
+                         struct page **pages)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr, len, end;
+       unsigned long next;
+       unsigned long flags;
+       pgd_t *pgdp;
+       int nr = 0;
+
+       start &= PAGE_MASK;
+       addr = start;
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+       end = start + len;
+       if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
+                                       (void __user *)start, len)))
+               return 0;
+
+       /*
+        * XXX: batch / limit 'nr', to avoid large irq off latency
+        * needs some instrumenting to determine the common sizes used by
+        * important workloads (eg. DB2), and whether limiting the batch
+        * size will decrease performance.
+        *
+        * It seems like we're in the clear for the moment. Direct-IO is
+        * the main guy that batches up lots of get_user_pages, and even
+        * they are limited to 64-at-a-time which is not so many.
+        */
+       /*
+        * This doesn't prevent pagetable teardown, but does prevent
+        * the pagetables and pages from being freed.
+        *
+        * So long as we atomically load page table pointers versus teardown,
+        * we can follow the address down to the page and take a ref on it.
+        */
+       local_irq_save(flags);
+       pgdp = pgd_offset(mm, addr);
+       do {
+               pgd_t pgd = *pgdp;
+
+               next = pgd_addr_end(addr, end);
+               if (pgd_none(pgd))
+                       break;
+               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+                       break;
+       } while (pgdp++, addr = next, addr != end);
+       local_irq_restore(flags);
+
+       return nr;
+}
+
+/**
+ * get_user_pages_fast() - pin user pages in memory
+ * @start:     starting user address
+ * @nr_pages:  number of pages from start to pin
+ * @write:     whether pages will be written to
+ * @pages:     array that receives pointers to the pages pinned.
+ *             Should be at least nr_pages long.
+ *
+ * Attempt to pin user pages in memory without taking mm->mmap_sem.
+ * If not successful, it will fall back to taking the lock and
+ * calling get_user_pages().
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno.
+ */
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+                       struct page **pages)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr, len, end;
+       unsigned long next;
+       pgd_t *pgdp;
+       int ret, nr = 0;
+
+       start &= PAGE_MASK;
+       addr = start;
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+
+       end = start + len;
+       if (end < start)
+               goto slow_irqon;
+
+       /* XXX: batch / limit 'nr' */
+       local_irq_disable();
+       pgdp = pgd_offset(mm, addr);
+       do {
+               pgd_t pgd = *pgdp;
+
+               next = pgd_addr_end(addr, end);
+               if (pgd_none(pgd))
+                       goto slow;
+               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+                       goto slow;
+       } while (pgdp++, addr = next, addr != end);
+       local_irq_enable();
+
+       VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
+       return nr;
+slow:
+       local_irq_enable();
+
+slow_irqon:
+       /* Try to get the remaining pages with get_user_pages */
+       start += nr << PAGE_SHIFT;
+       pages += nr;
+
+       down_read(&mm->mmap_sem);
+       ret = get_user_pages(current, mm, start,
+                               (end - start) >> PAGE_SHIFT,
+                               write, 0, pages, NULL);
+       up_read(&mm->mmap_sem);
+
+       /* Have to be a bit careful with return values */
+       if (nr > 0) {
+               if (ret < 0)
+                       ret = nr;
+               else
+                       ret += nr;
+       }
+       return ret;
+}
index b7ebc4f..3b3ffd4 100644 (file)
@@ -304,9 +304,14 @@ int page_is_ram(unsigned long pagenr)
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                unsigned long addr, end;
 
-               if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+               switch (boot_mem_map.map[i].type) {
+               case BOOT_MEM_RAM:
+               case BOOT_MEM_INIT_RAM:
+                       break;
+               default:
                        /* not usable memory */
                        continue;
+               }
 
                addr = PFN_UP(boot_mem_map.map[i].addr);
                end = PFN_DOWN(boot_mem_map.map[i].addr +
@@ -379,7 +384,7 @@ void __init mem_init(void)
 
        reservedpages = ram = 0;
        for (tmp = 0; tmp < max_low_pfn; tmp++)
-               if (page_is_ram(tmp)) {
+               if (page_is_ram(tmp) && pfn_valid(tmp)) {
                        ram++;
                        if (PageReserved(pfn_to_page(tmp)))
                                reservedpages++;
index d163455..2dc6253 100644 (file)
@@ -121,22 +121,30 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 
        if (cpu_context(cpu, mm) != 0) {
                unsigned long size, flags;
+               int huge = is_vm_hugetlb_page(vma);
 
                ENTER_CRITICAL(flags);
-               size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-               size = (size + 1) >> 1;
+               if (huge) {
+                       start = round_down(start, HPAGE_SIZE);
+                       end = round_up(end, HPAGE_SIZE);
+                       size = (end - start) >> HPAGE_SHIFT;
+               } else {
+                       start = round_down(start, PAGE_SIZE << 1);
+                       end = round_up(end, PAGE_SIZE << 1);
+                       size = (end - start) >> (PAGE_SHIFT + 1);
+               }
                if (size <= current_cpu_data.tlbsize/2) {
                        int oldpid = read_c0_entryhi();
                        int newpid = cpu_asid(cpu, mm);
 
-                       start &= (PAGE_MASK << 1);
-                       end += ((PAGE_SIZE << 1) - 1);
-                       end &= (PAGE_MASK << 1);
                        while (start < end) {
                                int idx;
 
                                write_c0_entryhi(start | newpid);
-                               start += (PAGE_SIZE << 1);
+                               if (huge)
+                                       start += HPAGE_SIZE;
+                               else
+                                       start += (PAGE_SIZE << 1);
                                mtc0_tlbw_hazard();
                                tlb_probe();
                                tlb_probe_hazard();
@@ -369,51 +377,6 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
        EXIT_CRITICAL(flags);
 }
 
-/*
- * Used for loading TLB entries before trap_init() has started, when we
- * don't actually want to add a wired entry which remains throughout the
- * lifetime of the system
- */
-
-static int temp_tlb_entry __cpuinitdata;
-
-__init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
-                              unsigned long entryhi, unsigned long pagemask)
-{
-       int ret = 0;
-       unsigned long flags;
-       unsigned long wired;
-       unsigned long old_pagemask;
-       unsigned long old_ctx;
-
-       ENTER_CRITICAL(flags);
-       /* Save old context and create impossible VPN2 value */
-       old_ctx = read_c0_entryhi();
-       old_pagemask = read_c0_pagemask();
-       wired = read_c0_wired();
-       if (--temp_tlb_entry < wired) {
-               printk(KERN_WARNING
-                      "No TLB space left for add_temporary_entry\n");
-               ret = -ENOSPC;
-               goto out;
-       }
-
-       write_c0_index(temp_tlb_entry);
-       write_c0_pagemask(pagemask);
-       write_c0_entryhi(entryhi);
-       write_c0_entrylo0(entrylo0);
-       write_c0_entrylo1(entrylo1);
-       mtc0_tlbw_hazard();
-       tlb_write_indexed();
-       tlbw_use_hazard();
-
-       write_c0_entryhi(old_ctx);
-       write_c0_pagemask(old_pagemask);
-out:
-       EXIT_CRITICAL(flags);
-       return ret;
-}
-
 static int __cpuinitdata ntlb;
 static int __init set_ntlb(char *str)
 {
@@ -451,8 +414,6 @@ void __cpuinit tlb_init(void)
                write_c0_pagegrain(pg);
        }
 
-       temp_tlb_entry = current_cpu_data.tlbsize - 1;
-
         /* From this point on the ARC firmware is dead.  */
        local_flush_tlb_all();
 
index d53ff91..a588b5c 100644 (file)
@@ -322,13 +322,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq_resched = {
        .handler        = ipi_resched_interrupt,
-       .flags          = IRQF_DISABLED|IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "IPI_resched"
 };
 
 static struct irqaction irq_call = {
        .handler        = ipi_call_interrupt,
-       .flags          = IRQF_DISABLED|IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "IPI_call"
 };
 #endif /* CONFIG_MIPS_MT_SMP */
index 8fbfbf2..389bf66 100644 (file)
@@ -405,7 +405,7 @@ int msp_pcibios_config_access(unsigned char access_type,
        if (pciirqflag == 0) {
                ret = request_irq(MSP_INT_PCI,/* Hardcoded internal MSP7120 wiring */
                                bpci_interrupt,
-                               IRQF_SHARED | IRQF_DISABLED,
+                               IRQF_SHARED,
                                "PMC MSP PCI Host",
                                preg);
                if (ret != 0)
index 6a3bdb5..02d64f7 100644 (file)
@@ -225,7 +225,7 @@ void __init tx3927_setup_pcierr_irq(void)
 {
        if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI,
                        tx3927_pcierr_interrupt,
-                       IRQF_DISABLED, "PCI error",
+                       0, "PCI error",
                        (void *)TX3927_PCIC_REG))
                printk(KERN_WARNING "Failed to request irq for PCIERR\n");
 }
index a580740..a032ae0 100644 (file)
@@ -85,7 +85,7 @@ void __init tx4927_setup_pcierr_irq(void)
 {
        if (request_irq(TXX9_IRQ_BASE + TX4927_IR_PCIERR,
                        tx4927_pcierr_interrupt,
-                       IRQF_DISABLED, "PCI error",
+                       0, "PCI error",
                        (void *)TX4927_PCIC_REG))
                printk(KERN_WARNING "Failed to request irq for PCIERR\n");
 }
index 20e45f3..141bba5 100644 (file)
@@ -136,7 +136,7 @@ void __init tx4938_setup_pcierr_irq(void)
 {
        if (request_irq(TXX9_IRQ_BASE + TX4938_IR_PCIERR,
                        tx4927_pcierr_interrupt,
-                       IRQF_DISABLED, "PCI error",
+                       0, "PCI error",
                        (void *)TX4927_PCIC_REG))
                printk(KERN_WARNING "Failed to request irq for PCIERR\n");
 }
index 9ef8406..c10fbf2 100644 (file)
@@ -101,7 +101,7 @@ void __init tx4939_setup_pcierr_irq(void)
 {
        if (request_irq(TXX9_IRQ_BASE + TX4939_IR_PCIERR,
                        tx4927_pcierr_interrupt,
-                       IRQF_DISABLED, "PCI error",
+                       0, "PCI error",
                        (void *)TX4939_PCIC_REG))
                pr_warning("Failed to request irq for PCIERR\n");
 }
index 41af7fa..8ac0d48 100644 (file)
@@ -4,8 +4,11 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  *
- * Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2003, 04, 11 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2011 Wind River Systems,
+ *   written by Ralf Baechle (ralf@linux-mips.org)
  */
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/bootmem.h>
@@ -14,6 +17,8 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 
+#include <asm/cpu-info.h>
+
 /*
  * Indicate whether we respect the PCI setup left by the firmware.
  *
@@ -150,10 +155,32 @@ out:
               "Skipping PCI bus scan due to resource conflict\n");
 }
 
+static void __init pcibios_set_cache_line_size(void)
+{
+       struct cpuinfo_mips *c = &current_cpu_data;
+       unsigned int lsize;
+
+       /*
+        * Set PCI cacheline size to that of the highest level in the
+        * cache hierarchy.
+        */
+       lsize = c->dcache.linesz;
+       lsize = c->scache.linesz ? : lsize;
+       lsize = c->tcache.linesz ? : lsize;
+
+       BUG_ON(!lsize);
+
+       pci_dfl_cache_line_size = lsize >> 2;
+
+       pr_debug("PCI: pci_cache_line_size set to %d bytes\n", lsize);
+}
+
 static int __init pcibios_init(void)
 {
        struct pci_controller *hose;
 
+       pcibios_set_cache_line_size();
+
        /* Scan all of the recorded PCI controllers.  */
        for (hose = hose_head; hose; hose = hose->next)
                pcibios_scanbus(hose);
index c841f08..bb57ed9 100644 (file)
@@ -149,7 +149,7 @@ static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)
                CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
        *CIC_EXT_CFG_REG = cic_ext;
 
-       return request_irq(hirq->irq, hwbutton_handler, IRQF_DISABLED,
+       return request_irq(hirq->irq, hwbutton_handler, 0,
                           hirq->name, hirq);
 }
 
index bec1790..1017058 100644 (file)
@@ -51,13 +51,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq_resched = {
        .handler        = ipi_resched_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "IPI_resched"
 };
 
 static struct irqaction irq_call = {
        .handler        = ipi_call_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "IPI_call"
 };
 
index 1ebe22b..ec684b8 100644 (file)
@@ -167,13 +167,13 @@ static struct irq_chip level_irq_type = {
 
 static struct irqaction gic_action = {
        .handler =      no_action,
-       .flags =        IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags =        IRQF_NO_THREAD,
        .name =         "GIC",
 };
 
 static struct irqaction timer_action = {
        .handler =      no_action,
-       .flags =        IRQF_DISABLED | IRQF_TIMER,
+       .flags =        IRQF_TIMER,
        .name =         "Timer",
 };
 
index 8836c62..831d6b3 100644 (file)
@@ -59,7 +59,7 @@ static irqreturn_t pnx8xxx_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction pnx8xxx_timer_irq = {
        .handler        = pnx8xxx_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "pnx8xxx_timer",
 };
 
@@ -72,7 +72,7 @@ static irqreturn_t monotonic_interrupt(int irq, void *dev_id)
 
 static struct irqaction monotonic_irqaction = {
        .handler = monotonic_interrupt,
-       .flags = IRQF_DISABLED | IRQF_TIMER,
+       .flags = IRQF_TIMER,
        .name = "Monotonic timer",
 };
 
index cc53849..411cda9 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 obj-y  += ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
-          ip22-platform.o ip22-reset.o ip22-setup.o
+          ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o
 
 obj-$(CONFIG_SGI_IP22) += ip22-berr.o
 obj-$(CONFIG_SGI_IP28) += ip28-berr.o
diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c
new file mode 100644 (file)
index 0000000..f5ebc09
--- /dev/null
@@ -0,0 +1,428 @@
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include <asm/addrspace.h>
+#include <asm/paccess.h>
+#include <asm/gio_device.h>
+#include <asm/sgi/gio.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/mc.h>
+#include <asm/sgi/ip22.h>
+
+static struct bus_type gio_bus_type;
+
+static struct {
+       const char *name;
+       __u8       id;
+} gio_name_table[] = {
+       { .name = "SGI Impact", .id = 0x10 },
+       { .name = "Phobos G160", .id = 0x35 },
+       /* fake IDs */
+       { .name = "SGI Newport", .id = 0x7e },
+       { .name = "SGI GR2/GR3", .id = 0x7f },
+};
+
+static struct device gio_bus = {
+       .init_name = "gio",
+};
+
+/**
+ * gio_match_device - Tell if an of_device structure has a matching
+ * gio_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
+                    const struct gio_device *dev)
+{
+       const struct gio_device_id *ids;
+
+       for (ids = match; ids->id != 0xff; ids++)
+               if (ids->id == dev->id.id)
+                       return ids;
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(gio_match_device);
+
+struct gio_device *gio_dev_get(struct gio_device *dev)
+{
+       struct device *tmp;
+
+       if (!dev)
+               return NULL;
+       tmp = get_device(&dev->dev);
+       if (tmp)
+               return to_gio_device(tmp);
+       else
+               return NULL;
+}
+EXPORT_SYMBOL_GPL(gio_dev_get);
+
+void gio_dev_put(struct gio_device *dev)
+{
+       if (dev)
+               put_device(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_dev_put);
+
+/**
+ * gio_release_dev - free an gio device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this gio device are
+ * done.
+ */
+void gio_release_dev(struct device *dev)
+{
+       struct gio_device *giodev;
+
+       giodev = to_gio_device(dev);
+       kfree(giodev);
+}
+EXPORT_SYMBOL_GPL(gio_release_dev);
+
+int gio_device_register(struct gio_device *giodev)
+{
+       giodev->dev.bus = &gio_bus_type;
+       giodev->dev.parent = &gio_bus;
+       return device_register(&giodev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_device_register);
+
+void gio_device_unregister(struct gio_device *giodev)
+{
+       device_unregister(&giodev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_device_unregister);
+
+static int gio_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *gio_drv = to_gio_driver(drv);
+
+       return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
+}
+
+static int gio_device_probe(struct device *dev)
+{
+       int error = -ENODEV;
+       struct gio_driver *drv;
+       struct gio_device *gio_dev;
+       const struct gio_device_id *match;
+
+       drv = to_gio_driver(dev->driver);
+       gio_dev = to_gio_device(dev);
+
+       if (!drv->probe)
+               return error;
+
+       gio_dev_get(gio_dev);
+
+       match = gio_match_device(drv->id_table, gio_dev);
+       if (match)
+               error = drv->probe(gio_dev, match);
+       if (error)
+               gio_dev_put(gio_dev);
+
+       return error;
+}
+
+static int gio_device_remove(struct device *dev)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *drv = to_gio_driver(dev->driver);
+
+       if (dev->driver && drv->remove)
+               drv->remove(gio_dev);
+       return 0;
+}
+
+static int gio_device_suspend(struct device *dev, pm_message_t state)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *drv = to_gio_driver(dev->driver);
+       int error = 0;
+
+       if (dev->driver && drv->suspend)
+               error = drv->suspend(gio_dev, state);
+       return error;
+}
+
+static int gio_device_resume(struct device *dev)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *drv = to_gio_driver(dev->driver);
+       int error = 0;
+
+       if (dev->driver && drv->resume)
+               error = drv->resume(gio_dev);
+       return error;
+}
+
+static void gio_device_shutdown(struct device *dev)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *drv = to_gio_driver(dev->driver);
+
+       if (dev->driver && drv->shutdown)
+               drv->shutdown(gio_dev);
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+                            char *buf)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       int len = snprintf(buf, PAGE_SIZE, "gio:%x\n", gio_dev->id.id);
+
+       return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static ssize_t name_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct gio_device *giodev;
+
+       giodev = to_gio_device(dev);
+       return sprintf(buf, "%s", giodev->name);
+}
+
+static ssize_t id_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
+{
+       struct gio_device *giodev;
+
+       giodev = to_gio_device(dev);
+       return sprintf(buf, "%x", giodev->id.id);
+}
+
+static struct device_attribute gio_dev_attrs[] = {
+       __ATTR_RO(modalias),
+       __ATTR_RO(name),
+       __ATTR_RO(id),
+       __ATTR_NULL,
+};
+
+static int gio_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+
+       add_uevent_var(env, "MODALIAS=gio:%x", gio_dev->id.id);
+       return 0;
+}
+
+int gio_register_driver(struct gio_driver *drv)
+{
+       /* initialize common driver fields */
+       if (!drv->driver.name)
+               drv->driver.name = drv->name;
+       if (!drv->driver.owner)
+               drv->driver.owner = drv->owner;
+       drv->driver.bus = &gio_bus_type;
+
+       /* register with core */
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(gio_register_driver);
+
+void gio_unregister_driver(struct gio_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(gio_unregister_driver);
+
+void gio_set_master(struct gio_device *dev)
+{
+       u32 tmp = sgimc->giopar;
+
+       switch (dev->slotno) {
+       case 0:
+               tmp |= SGIMC_GIOPAR_MASTERGFX;
+               break;
+       case 1:
+               tmp |= SGIMC_GIOPAR_MASTEREXP0;
+               break;
+       case 2:
+               tmp |= SGIMC_GIOPAR_MASTEREXP1;
+               break;
+       }
+       sgimc->giopar = tmp;
+}
+EXPORT_SYMBOL_GPL(gio_set_master);
+
+void ip22_gio_set_64bit(int slotno)
+{
+       u32 tmp = sgimc->giopar;
+
+       switch (slotno) {
+       case 0:
+               tmp |= SGIMC_GIOPAR_GFX64;
+               break;
+       case 1:
+               tmp |= SGIMC_GIOPAR_EXP064;
+               break;
+       case 2:
+               tmp |= SGIMC_GIOPAR_EXP164;
+               break;
+       }
+       sgimc->giopar = tmp;
+}
+
+static int ip22_gio_id(unsigned long addr, u32 *res)
+{
+       u8 tmp8;
+       u8 tmp16;
+       u32 tmp32;
+       u8 *ptr8;
+       u16 *ptr16;
+       u32 *ptr32;
+
+       ptr32 = (void *)CKSEG1ADDR(addr);
+       if (!get_dbe(tmp32, ptr32)) {
+               /*
+                * We got no DBE, but this doesn't mean anything.
+                * If GIO is pipelined (which can't be disabled
+                * for GFX slot) we don't get a DBE, but we see
+                * the transfer size as data. So we do an 8bit
+                * and a 16bit access and check whether the common
+                * data matches
+                */
+               ptr8 = (void *)CKSEG1ADDR(addr + 3);
+               get_dbe(tmp8, ptr8);
+               ptr16 = (void *)CKSEG1ADDR(addr + 2);
+               get_dbe(tmp16, ptr16);
+               if (tmp8 == (tmp16 & 0xff) &&
+                   tmp8 == (tmp32 & 0xff) &&
+                   tmp16 == (tmp32 & 0xffff)) {
+                       *res = tmp32;
+                       return 1;
+               }
+       }
+       return 0; /* nothing here */
+}
+
+#define HQ2_MYSTERY_OFFS       0x6A07C
+#define NEWPORT_USTATUS_OFFS   0xF133C
+
+static int ip22_is_gr2(unsigned long addr)
+{
+       u32 tmp;
+       u32 *ptr;
+
+       /* HQ2 only allows 32bit accesses */
+       ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
+       if (!get_dbe(tmp, ptr)) {
+               if (tmp == 0xdeadbeef)
+                       return 1;
+       }
+       return 0;
+}
+
+
+static void ip22_check_gio(int slotno, unsigned long addr)
+{
+       const char *name = "Unknown";
+       struct gio_device *gio_dev;
+       u32 tmp;
+       __u8 id;
+       int i;
+
+       /* first look for GR2/GR3 by checking mystery register */
+       if (ip22_is_gr2(addr))
+               tmp = 0x7f;
+       else {
+               if (!ip22_gio_id(addr, &tmp)) {
+                       /*
+                        * no GIO signature at start address of slot, but
+                        * Newport doesn't have one, so let's check usea
+                        * status register
+                        */
+                       if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
+                               tmp = 0x7e;
+                       else
+                               tmp = 0;
+               }
+       }
+       if (tmp) {
+               id = GIO_ID(tmp);
+               if (tmp & GIO_32BIT_ID) {
+                       if (tmp & GIO_64BIT_IFACE)
+                               ip22_gio_set_64bit(slotno);
+               }
+               for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
+                       if (id == gio_name_table[i].id) {
+                               name = gio_name_table[i].name;
+                               break;
+                       }
+               }
+               printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
+                      slotno, name, id);
+               gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
+               gio_dev->name = name;
+               gio_dev->slotno = slotno;
+               gio_dev->id.id = id;
+               gio_dev->resource.start = addr;
+               gio_dev->resource.end = addr + 0x3fffff;
+               gio_dev->resource.flags = IORESOURCE_MEM;
+               dev_set_name(&gio_dev->dev, "%d", slotno);
+               gio_device_register(gio_dev);
+       } else
+               printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
+}
+
+static struct bus_type gio_bus_type = {
+       .name      = "gio",
+       .dev_attrs = gio_dev_attrs,
+       .match     = gio_bus_match,
+       .probe     = gio_device_probe,
+       .remove    = gio_device_remove,
+       .suspend   = gio_device_suspend,
+       .resume    = gio_device_resume,
+       .shutdown  = gio_device_shutdown,
+       .uevent    = gio_device_uevent,
+};
+
+static struct resource gio_bus_resource = {
+       .start = GIO_SLOT_GFX_BASE,
+       .end   = GIO_SLOT_GFX_BASE + 0x9fffff,
+       .name  = "GIO Bus",
+       .flags = IORESOURCE_MEM,
+};
+
+int __init ip22_gio_init(void)
+{
+       unsigned int pbdma __maybe_unused;
+       int ret;
+
+       ret = device_register(&gio_bus);
+       if (ret)
+               return ret;
+
+       ret = bus_register(&gio_bus_type);
+       if (!ret) {
+               request_resource(&iomem_resource, &gio_bus_resource);
+               printk(KERN_INFO "GIO: Probing bus...\n");
+
+               if (ip22_is_fullhouse() ||
+                   !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) {
+                       /* Indigo2 and ChallengeS */
+                       ip22_check_gio(0, GIO_SLOT_GFX_BASE);
+                       ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
+               } else {
+                       /* Indy */
+                       ip22_check_gio(0, GIO_SLOT_GFX_BASE);
+                       ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
+                       ip22_check_gio(2, GIO_SLOT_EXP1_BASE);
+               }
+       } else
+               device_unregister(&gio_bus);
+
+       return ret;
+}
+
+subsys_initcall(ip22_gio_init);
index f72c336..3f2b763 100644 (file)
@@ -155,32 +155,32 @@ static void __irq_entry indy_buserror_irq(void)
 
 static struct irqaction local0_cascade = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "local0 cascade",
 };
 
 static struct irqaction local1_cascade = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "local1 cascade",
 };
 
 static struct irqaction buserr = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "Bus Error",
 };
 
 static struct irqaction map0_cascade = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "mapable0 cascade",
 };
 
 #ifdef USE_LIO3_IRQ
 static struct irqaction map1_cascade = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "mapable1 cascade",
 };
 #define SGI_INTERRUPTS SGINT_END
index d22262e..75ada8a 100644 (file)
@@ -139,11 +139,11 @@ void __init sgimc_init(void)
         *         zero.
         */
        /* don't touch parity settings for IP28 */
-#ifndef CONFIG_SGI_IP28
        tmp = sgimc->cpuctrl0;
-       tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
-               SGIMC_CCTRL0_R4KNOCHKPARR);
+#ifndef CONFIG_SGI_IP28
+       tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM;
 #endif
+       tmp |= SGIMC_CCTRL0_R4KNOCHKPARR;
        sgimc->cpuctrl0 = tmp;
 
        /* Step 3: Setup the MC write buffer depth, this is controlled
@@ -178,7 +178,8 @@ void __init sgimc_init(void)
         */
 
        /* First the basic invariants across all GIO64 implementations. */
-       tmp = SGIMC_GIOPAR_HPC64;       /* All 1st HPC's interface at 64bits */
+       tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */
+       tmp |= SGIMC_GIOPAR_HPC64;      /* All 1st HPC's interface at 64bits */
        tmp |= SGIMC_GIOPAR_ONEBUS;     /* Only one physical GIO bus exists */
 
        if (ip22_is_fullhouse()) {
@@ -193,7 +194,6 @@ void __init sgimc_init(void)
                        tmp |= SGIMC_GIOPAR_PLINEEXP0;  /* exp[01] pipelined */
                        tmp |= SGIMC_GIOPAR_PLINEEXP1;
                        tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA masters */
-                       tmp |= SGIMC_GIOPAR_GFX64;      /* GFX at 64 bits */
                }
        } else {
                /* Guiness specific settings. */
index 5e66213..c7bdfe4 100644 (file)
@@ -26,9 +26,6 @@
 #include <asm/sgi/hpc3.h>
 #include <asm/sgi/ip22.h>
 
-unsigned long sgi_gfxaddr;
-EXPORT_SYMBOL_GPL(sgi_gfxaddr);
-
 extern void ip22_be_init(void) __init;
 
 void __init plat_mem_setup(void)
@@ -78,22 +75,4 @@ void __init plat_mem_setup(void)
                prom_flags |= PROM_FLAG_USE_AS_CONSOLE;
                add_preferred_console("arc", 0, NULL);
        }
-
-#if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE)
-       {
-               ULONG *gfxinfo;
-               ULONG * (*__vec)(void) = (void *) (long)
-                       *((_PULONG *)(long)((PROMBLOCK)->pvector + 0x20));
-
-               gfxinfo = __vec();
-               sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000
-                              && gfxinfo[1] <= 0xc0000000)
-                              ? gfxinfo[1] - 0xa0000000 : 0);
-
-               /* newport addresses? */
-               if (sgi_gfxaddr == 0x1f0f0000 || sgi_gfxaddr == 0x1f4f0000) {
-                       conswitchp = &newport_con;
-               }
-       }
-#endif
 }
index ec3782d..2364223 100644 (file)
@@ -116,7 +116,7 @@ static int ms1bit(unsigned long x)
 }
 
 /*
- * This code is unnecessarily complex, because we do IRQF_DISABLED
+ * This code is unnecessarily complex, because we do
  * intr enabling. Basically, once we grab the set of intrs we need
  * to service, we must mask _all_ these interrupts; firstly, to make
  * sure the same intr does not intr again, causing recursion that
index ef74f32..13cfeab 100644 (file)
@@ -91,7 +91,7 @@ static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
 
 struct irqaction hub_rt_irqaction = {
        .handler        = hub_rt_counter_handler,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "hub-rt",
 };
 
index c65ea76..a092860 100644 (file)
@@ -113,13 +113,11 @@ extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
 
 static struct irqaction memerr_irq = {
        .handler = crime_memerr_intr,
-       .flags = IRQF_DISABLED,
        .name = "CRIME memory error",
 };
 
 static struct irqaction cpuerr_irq = {
        .handler = crime_cpuerr_intr,
-       .flags = IRQF_DISABLED,
        .name = "CRIME CPU error",
 };
 
index e8e72bb..5a4ec75 100644 (file)
@@ -42,7 +42,7 @@ static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
 struct irqaction sni_isa_irq = {
        .handler = sni_isa_irq_handler,
        .name = "ISA",
-       .flags = IRQF_SHARED | IRQF_DISABLED
+       .flags = IRQF_SHARED
 };
 
 /*
index ec0be14..494c9e7 100644 (file)
@@ -68,7 +68,7 @@ static irqreturn_t a20r_interrupt(int irq, void *dev_id)
 
 static struct irqaction a20r_irqaction = {
        .handler        = a20r_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "a20r-timer",
 };
 
index 85a87de..682efb0 100644 (file)
@@ -262,7 +262,7 @@ txx9_i8259_irq_setup(int irq)
        int err;
 
        init_i8259_irqs();
-       err = request_irq(irq, &i8259_interrupt, IRQF_DISABLED|IRQF_SHARED,
+       err = request_irq(irq, &i8259_interrupt, IRQF_SHARED,
                          "cascade(i8259)", (void *)(long)irq);
        if (!err)
                printk(KERN_INFO "PCI-ISA bridge PIC (irq %d)\n", irq);
index 93317b5..a122d92 100644 (file)
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/gio_device.h>
+
 #include <video/newport.h>
 
 #include <linux/linux_logo.h>
 #include <linux/font.h>
 
-
-extern unsigned long sgi_gfxaddr;
-
 #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
 
 /* borrowed from fbcon.c */
@@ -304,12 +303,6 @@ static const char *newport_startup(void)
 {
        int i;
 
-       if (!sgi_gfxaddr)
-               return NULL;
-
-       if (!npregs)
-               npregs = (struct newport_regs *)/* ioremap cannot fail */
-                       ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
        npregs->cset.config = NPORT_CFG_GD0;
 
        if (newport_wait(npregs))
@@ -743,26 +736,58 @@ const struct consw newport_con = {
        .con_save_screen  = DUMMY
 };
 
-#ifdef MODULE
-static int __init newport_console_init(void)
+static int newport_probe(struct gio_device *dev,
+                        const struct gio_device_id *id)
 {
-       if (!sgi_gfxaddr)
-               return 0;
+       unsigned long newport_addr;
 
-       if (!npregs)
-               npregs = (struct newport_regs *)/* ioremap cannot fail */
-                       ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+       if (!dev->resource.start)
+               return -EINVAL;
+
+       if (npregs)
+               return -EBUSY; /* we only support one Newport as console */
+
+       newport_addr = dev->resource.start + 0xF0000;
+       if (!request_mem_region(newport_addr, 0x10000, "Newport"))
+               return -ENODEV;
+
+       npregs = (struct newport_regs *)/* ioremap cannot fail */
+               ioremap(newport_addr, sizeof(struct newport_regs));
 
        return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
 }
-module_init(newport_console_init);
 
-static void __exit newport_console_exit(void)
+static void newport_remove(struct gio_device *dev)
 {
        give_up_console(&newport_con);
        iounmap((void *)npregs);
 }
+
+static struct gio_device_id newport_ids[] = {
+       { .id = 0x7e },
+       { .id = 0xff }
+};
+
+MODULE_ALIAS("gio:7e");
+
+static struct gio_driver newport_driver = {
+       .name = "newport",
+       .id_table = newport_ids,
+       .probe = newport_probe,
+       .remove = newport_remove,
+};
+
+int __init newport_console_init(void)
+{
+       return gio_register_driver(&newport_driver);
+}
+
+void __exit newport_console_exit(void)
+{
+       gio_unregister_driver(&newport_driver);
+}
+
+module_init(newport_console_init);
 module_exit(newport_console_exit);
-#endif
 
 MODULE_LICENSE("GPL");