Merge branch 'next/generic' into mips-for-linux-next
This commit is contained in:
		
						commit
						39b741431a
					
				| @ -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 { | ||||
|  | ||||
| @ -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, | ||||
| }; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -110,7 +110,6 @@ static struct irqaction fpuirq = { | ||||
| }; | ||||
| 
 | ||||
| static struct irqaction busirq = { | ||||
| 	.flags = IRQF_DISABLED, | ||||
| 	.name = "bus error", | ||||
| 	.flags = IRQF_NO_THREAD, | ||||
| }; | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										56
									
								
								arch/mips/include/asm/gio_device.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								arch/mips/include/asm/gio_device.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 *); | ||||
| @ -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) | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -38,6 +38,14 @@ | ||||
| #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__ | ||||
|  | ||||
| @ -19,17 +19,7 @@ | ||||
| #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 | ||||
|  | ||||
| @ -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", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -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", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -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, | ||||
| }; | ||||
|  | ||||
| @ -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" | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -473,7 +473,6 @@ static const struct file_operations rtlx_fops = { | ||||
| 
 | ||||
| static struct irqaction rtlx_irq = { | ||||
| 	.handler	= rtlx_interrupt, | ||||
| 	.flags		= IRQF_DISABLED, | ||||
| 	.name		= "RTLX", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Reserve usable memory. | ||||
| 		 */ | ||||
| 		if (boot_mem_map.map[i].type != BOOT_MEM_RAM) | ||||
| 			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); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Reserve usable memory. | ||||
| 		 */ | ||||
| 		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; | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * 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; | ||||
|  | ||||
| @ -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" | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -240,7 +240,6 @@ out: | ||||
| 
 | ||||
| static struct irqaction cascade = { | ||||
| 	.handler = no_action, | ||||
| 	.flags = IRQF_DISABLED, | ||||
| 	.name = "cascade", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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" | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										315
									
								
								arch/mips/mm/gup.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								arch/mips/mm/gup.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
| @ -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++; | ||||
|  | ||||
| @ -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(); | ||||
| 
 | ||||
|  | ||||
| @ -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 */ | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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"); | ||||
| } | ||||
|  | ||||
| @ -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"); | ||||
| } | ||||
|  | ||||
| @ -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"); | ||||
| } | ||||
|  | ||||
| @ -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"); | ||||
| } | ||||
|  | ||||
| @ -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 = ¤t_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); | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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" | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										428
									
								
								arch/mips/sgi-ip22/ip22-gio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										428
									
								
								arch/mips/sgi-ip22/ip22-gio.c
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| @ -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 | ||||
|  | ||||
| @ -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. */ | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
| @ -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", | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -25,14 +25,13 @@ | ||||
| #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"); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user