Merge /spare/repo/netdev-2.6 branch 'ieee80211'
This commit is contained in:
		
				commit
				
					
						aa8f6dfd35
					
				
			
		
					 322 changed files with 19316 additions and 15355 deletions
				
			
		
							
								
								
									
										176
									
								
								Documentation/block/ioprio.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								Documentation/block/ioprio.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,176 @@
 | 
			
		|||
Block io priorities
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Intro
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
 | 
			
		||||
priorities is supported for reads on files. This enables users to io nice
 | 
			
		||||
processes or process groups, similar to what has been possible to cpu
 | 
			
		||||
scheduling for ages. This document mainly details the current possibilites
 | 
			
		||||
with cfq, other io schedulers do not support io priorities so far.
 | 
			
		||||
 | 
			
		||||
Scheduling classes
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
CFQ implements three generic scheduling classes that determine how io is
 | 
			
		||||
served for a process.
 | 
			
		||||
 | 
			
		||||
IOPRIO_CLASS_RT: This is the realtime io class. This scheduling class is given
 | 
			
		||||
higher priority than any other in the system, processes from this class are
 | 
			
		||||
given first access to the disk every time. Thus it needs to be used with some
 | 
			
		||||
care, one io RT process can starve the entire system. Within the RT class,
 | 
			
		||||
there are 8 levels of class data that determine exactly how much time this
 | 
			
		||||
process needs the disk for on each service. In the future this might change
 | 
			
		||||
to be more directly mappable to performance, by passing in a wanted data
 | 
			
		||||
rate instead.
 | 
			
		||||
 | 
			
		||||
IOPRIO_CLASS_BE: This is the best-effort scheduling class, which is the default
 | 
			
		||||
for any process that hasn't set a specific io priority. The class data
 | 
			
		||||
determines how much io bandwidth the process will get, it's directly mappable
 | 
			
		||||
to the cpu nice levels just more coarsely implemented. 0 is the highest
 | 
			
		||||
BE prio level, 7 is the lowest. The mapping between cpu nice level and io
 | 
			
		||||
nice level is determined as: io_nice = (cpu_nice + 20) / 5.
 | 
			
		||||
 | 
			
		||||
IOPRIO_CLASS_IDLE: This is the idle scheduling class, processes running at this
 | 
			
		||||
level only get io time when no one else needs the disk. The idle class has no
 | 
			
		||||
class data, since it doesn't really apply here.
 | 
			
		||||
 | 
			
		||||
Tools
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
See below for a sample ionice tool. Usage:
 | 
			
		||||
 | 
			
		||||
# ionice -c<class> -n<level> -p<pid>
 | 
			
		||||
 | 
			
		||||
If pid isn't given, the current process is assumed. IO priority settings
 | 
			
		||||
are inherited on fork, so you can use ionice to start the process at a given
 | 
			
		||||
level:
 | 
			
		||||
 | 
			
		||||
# ionice -c2 -n0 /bin/ls
 | 
			
		||||
 | 
			
		||||
will run ls at the best-effort scheduling class at the highest priority.
 | 
			
		||||
For a running process, you can give the pid instead:
 | 
			
		||||
 | 
			
		||||
# ionice -c1 -n2 -p100
 | 
			
		||||
 | 
			
		||||
will change pid 100 to run at the realtime scheduling class, at priority 2.
 | 
			
		||||
 | 
			
		||||
---> snip ionice.c tool <---
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/ptrace.h>
 | 
			
		||||
#include <asm/unistd.h>
 | 
			
		||||
 | 
			
		||||
extern int sys_ioprio_set(int, int, int);
 | 
			
		||||
extern int sys_ioprio_get(int, int);
 | 
			
		||||
 | 
			
		||||
#if defined(__i386__)
 | 
			
		||||
#define __NR_ioprio_set		289
 | 
			
		||||
#define __NR_ioprio_get		290
 | 
			
		||||
#elif defined(__ppc__)
 | 
			
		||||
#define __NR_ioprio_set		273
 | 
			
		||||
#define __NR_ioprio_get		274
 | 
			
		||||
#elif defined(__x86_64__)
 | 
			
		||||
#define __NR_ioprio_set		251
 | 
			
		||||
#define __NR_ioprio_get		252
 | 
			
		||||
#elif defined(__ia64__)
 | 
			
		||||
#define __NR_ioprio_set		1274
 | 
			
		||||
#define __NR_ioprio_get		1275
 | 
			
		||||
#else
 | 
			
		||||
#error "Unsupported arch"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
_syscall3(int, ioprio_set, int, which, int, who, int, ioprio);
 | 
			
		||||
_syscall2(int, ioprio_get, int, which, int, who);
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	IOPRIO_CLASS_NONE,
 | 
			
		||||
	IOPRIO_CLASS_RT,
 | 
			
		||||
	IOPRIO_CLASS_BE,
 | 
			
		||||
	IOPRIO_CLASS_IDLE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	IOPRIO_WHO_PROCESS = 1,
 | 
			
		||||
	IOPRIO_WHO_PGRP,
 | 
			
		||||
	IOPRIO_WHO_USER,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define IOPRIO_CLASS_SHIFT	13
 | 
			
		||||
 | 
			
		||||
const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	int ioprio = 4, set = 0, ioprio_class = IOPRIO_CLASS_BE;
 | 
			
		||||
	int c, pid = 0;
 | 
			
		||||
 | 
			
		||||
	while ((c = getopt(argc, argv, "+n:c:p:")) != EOF) {
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'n':
 | 
			
		||||
			ioprio = strtol(optarg, NULL, 10);
 | 
			
		||||
			set = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'c':
 | 
			
		||||
			ioprio_class = strtol(optarg, NULL, 10);
 | 
			
		||||
			set = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'p':
 | 
			
		||||
			pid = strtol(optarg, NULL, 10);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (ioprio_class) {
 | 
			
		||||
		case IOPRIO_CLASS_NONE:
 | 
			
		||||
			ioprio_class = IOPRIO_CLASS_BE;
 | 
			
		||||
			break;
 | 
			
		||||
		case IOPRIO_CLASS_RT:
 | 
			
		||||
		case IOPRIO_CLASS_BE:
 | 
			
		||||
			break;
 | 
			
		||||
		case IOPRIO_CLASS_IDLE:
 | 
			
		||||
			ioprio = 7;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			printf("bad prio class %d\n", ioprio_class);
 | 
			
		||||
			return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!set) {
 | 
			
		||||
		if (!pid && argv[optind])
 | 
			
		||||
			pid = strtol(argv[optind], NULL, 10);
 | 
			
		||||
 | 
			
		||||
		ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
 | 
			
		||||
 | 
			
		||||
		printf("pid=%d, %d\n", pid, ioprio);
 | 
			
		||||
 | 
			
		||||
		if (ioprio == -1)
 | 
			
		||||
			perror("ioprio_get");
 | 
			
		||||
		else {
 | 
			
		||||
			ioprio_class = ioprio >> IOPRIO_CLASS_SHIFT;
 | 
			
		||||
			ioprio = ioprio & 0xff;
 | 
			
		||||
			printf("%s: prio %d\n", to_prio[ioprio_class], ioprio);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio | ioprio_class << IOPRIO_CLASS_SHIFT) == -1) {
 | 
			
		||||
			perror("ioprio_set");
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (argv[optind])
 | 
			
		||||
			execvp(argv[optind], &argv[optind]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
---> snip ionice.c tool <---
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
March 11 2005, Jens Axboe <axboe@suse.de>
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +17,7 @@ This driver is known to work with the following cards:
 | 
			
		|||
	* SA P600
 | 
			
		||||
	* SA P800
 | 
			
		||||
	* SA E400
 | 
			
		||||
	* SA E300
 | 
			
		||||
 | 
			
		||||
If nodes are not already created in the /dev/cciss directory, run as root:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1115,7 +1115,7 @@ running once the system is up.
 | 
			
		|||
			See Documentation/ramdisk.txt.
 | 
			
		||||
 | 
			
		||||
	psmouse.proto=  [HW,MOUSE] Highest PS2 mouse protocol extension to
 | 
			
		||||
			probe for (bare|imps|exps).
 | 
			
		||||
			probe for (bare|imps|exps|lifebook|any).
 | 
			
		||||
	psmouse.rate=	[HW,MOUSE] Set desired mouse report rate, in reports
 | 
			
		||||
			per second.
 | 
			
		||||
	psmouse.resetafter=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1156,7 +1156,7 @@ S:	Maintained
 | 
			
		|||
 | 
			
		||||
INFINIBAND SUBSYSTEM
 | 
			
		||||
P:	Roland Dreier
 | 
			
		||||
M:	roland@topspin.com
 | 
			
		||||
M:	rolandd@cisco.com
 | 
			
		||||
P:	Sean Hefty
 | 
			
		||||
M:	mshefty@ichips.intel.com
 | 
			
		||||
P:	Hal Rosenstock
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,7 @@
 | 
			
		|||
#include <asm/leds.h>
 | 
			
		||||
#include <asm/processor.h>
 | 
			
		||||
#include <asm/uaccess.h>
 | 
			
		||||
#include <asm/mach/time.h>
 | 
			
		||||
 | 
			
		||||
extern const char *processor_modes[];
 | 
			
		||||
extern void setup_mm_for_reboot(char mode);
 | 
			
		||||
| 
						 | 
				
			
			@ -85,8 +86,10 @@ EXPORT_SYMBOL(pm_power_off);
 | 
			
		|||
void default_idle(void)
 | 
			
		||||
{
 | 
			
		||||
	local_irq_disable();
 | 
			
		||||
	if (!need_resched() && !hlt_counter)
 | 
			
		||||
	if (!need_resched() && !hlt_counter) {
 | 
			
		||||
		timer_dyn_reprogram();
 | 
			
		||||
		arch_idle();
 | 
			
		||||
	}
 | 
			
		||||
	local_irq_enable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -424,15 +424,19 @@ static int timer_dyn_tick_disable(void)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Reprogram the system timer for at least the calculated time interval.
 | 
			
		||||
 * This function should be called from the idle thread with IRQs disabled,
 | 
			
		||||
 * immediately before sleeping.
 | 
			
		||||
 */
 | 
			
		||||
void timer_dyn_reprogram(void)
 | 
			
		||||
{
 | 
			
		||||
	struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	write_seqlock_irqsave(&xtime_lock, flags);
 | 
			
		||||
	write_seqlock(&xtime_lock);
 | 
			
		||||
	if (dyn_tick->state & DYN_TICK_ENABLED)
 | 
			
		||||
		dyn_tick->reprogram(next_timer_interrupt() - jiffies);
 | 
			
		||||
	write_sequnlock_irqrestore(&xtime_lock, flags);
 | 
			
		||||
	write_sequnlock(&xtime_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								arch/arm/mach-aaec2000/Makefile.boot
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								arch/arm/mach-aaec2000/Makefile.boot
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
	zreladdr-y := 0xf0008000
 | 
			
		||||
| 
						 | 
				
			
			@ -288,8 +288,8 @@ static void usb_release(struct device *dev)
 | 
			
		|||
static struct resource udc_resources[] = {
 | 
			
		||||
	/* order is significant! */
 | 
			
		||||
	{		/* registers */
 | 
			
		||||
		.start		= IO_ADDRESS(UDC_BASE),
 | 
			
		||||
		.end		= IO_ADDRESS(UDC_BASE + 0xff),
 | 
			
		||||
		.start		= UDC_BASE,
 | 
			
		||||
		.end		= UDC_BASE + 0xff,
 | 
			
		||||
		.flags		= IORESOURCE_MEM,
 | 
			
		||||
	}, {		/* general IRQ */
 | 
			
		||||
		.start		= IH2_BASE + 20,
 | 
			
		||||
| 
						 | 
				
			
			@ -355,8 +355,8 @@ static struct platform_device ohci_device = {
 | 
			
		|||
static struct resource otg_resources[] = {
 | 
			
		||||
	/* order is significant! */
 | 
			
		||||
	{
 | 
			
		||||
		.start		= IO_ADDRESS(OTG_BASE),
 | 
			
		||||
		.end		= IO_ADDRESS(OTG_BASE + 0xff),
 | 
			
		||||
		.start		= OTG_BASE,
 | 
			
		||||
		.end		= OTG_BASE + 0xff,
 | 
			
		||||
		.flags		= IORESOURCE_MEM,
 | 
			
		||||
	}, {
 | 
			
		||||
		.start		= IH2_BASE + 8,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -522,6 +522,69 @@ static inline void free_area(unsigned long addr, unsigned long end, char *s)
 | 
			
		|||
		printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
 | 
			
		||||
{
 | 
			
		||||
	struct page *start_pg, *end_pg;
 | 
			
		||||
	unsigned long pg, pgend;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Convert start_pfn/end_pfn to a struct page pointer.
 | 
			
		||||
	 */
 | 
			
		||||
	start_pg = pfn_to_page(start_pfn);
 | 
			
		||||
	end_pg = pfn_to_page(end_pfn);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Convert to physical addresses, and
 | 
			
		||||
	 * round start upwards and end downwards.
 | 
			
		||||
	 */
 | 
			
		||||
	pg = PAGE_ALIGN(__pa(start_pg));
 | 
			
		||||
	pgend = __pa(end_pg) & PAGE_MASK;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If there are free pages between these,
 | 
			
		||||
	 * free the section of the memmap array.
 | 
			
		||||
	 */
 | 
			
		||||
	if (pg < pgend)
 | 
			
		||||
		free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The mem_map array can get very big.  Free the unused area of the memory map.
 | 
			
		||||
 */
 | 
			
		||||
static void __init free_unused_memmap_node(int node, struct meminfo *mi)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long bank_start, prev_bank_end = 0;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * [FIXME] This relies on each bank being in address order.  This
 | 
			
		||||
	 * may not be the case, especially if the user has provided the
 | 
			
		||||
	 * information on the command line.
 | 
			
		||||
	 */
 | 
			
		||||
	for (i = 0; i < mi->nr_banks; i++) {
 | 
			
		||||
		if (mi->bank[i].size == 0 || mi->bank[i].node != node)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		bank_start = mi->bank[i].start >> PAGE_SHIFT;
 | 
			
		||||
		if (bank_start < prev_bank_end) {
 | 
			
		||||
			printk(KERN_ERR "MEM: unordered memory banks.  "
 | 
			
		||||
				"Not freeing memmap.\n");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If we had a previous bank, and there is a space
 | 
			
		||||
		 * between the current bank and the previous, free it.
 | 
			
		||||
		 */
 | 
			
		||||
		if (prev_bank_end && prev_bank_end != bank_start)
 | 
			
		||||
			free_memmap(node, prev_bank_end, bank_start);
 | 
			
		||||
 | 
			
		||||
		prev_bank_end = (mi->bank[i].start +
 | 
			
		||||
				 mi->bank[i].size) >> PAGE_SHIFT;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * mem_init() marks the free areas in the mem_map and tells us how much
 | 
			
		||||
 * memory is free.  This is done after various parts of the system have
 | 
			
		||||
| 
						 | 
				
			
			@ -540,16 +603,12 @@ void __init mem_init(void)
 | 
			
		|||
	max_mapnr   = virt_to_page(high_memory) - mem_map;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * We may have non-contiguous memory.
 | 
			
		||||
	 */
 | 
			
		||||
	if (meminfo.nr_banks != 1)
 | 
			
		||||
		create_memmap_holes(&meminfo);
 | 
			
		||||
 | 
			
		||||
	/* this will put all unused low memory onto the freelists */
 | 
			
		||||
	for_each_online_node(node) {
 | 
			
		||||
		pg_data_t *pgdat = NODE_DATA(node);
 | 
			
		||||
 | 
			
		||||
		free_unused_memmap_node(node, &meminfo);
 | 
			
		||||
 | 
			
		||||
		if (pgdat->node_spanned_pages != 0)
 | 
			
		||||
			totalram_pages += free_all_bootmem_node(pgdat);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,7 +169,14 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
 | 
			
		|||
 | 
			
		||||
	memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Copy over the kernel and IO PGD entries
 | 
			
		||||
	 */
 | 
			
		||||
	init_pgd = pgd_offset_k(0);
 | 
			
		||||
	memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
 | 
			
		||||
		       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
 | 
			
		||||
 | 
			
		||||
	clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
 | 
			
		||||
 | 
			
		||||
	if (!vectors_high()) {
 | 
			
		||||
		/*
 | 
			
		||||
| 
						 | 
				
			
			@ -198,14 +205,6 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
 | 
			
		|||
		spin_unlock(&mm->page_table_lock);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Copy over the kernel and IO PGD entries
 | 
			
		||||
	 */
 | 
			
		||||
	memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
 | 
			
		||||
		       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
 | 
			
		||||
 | 
			
		||||
	clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
 | 
			
		||||
 | 
			
		||||
	return new_pgd;
 | 
			
		||||
 | 
			
		||||
no_pte:
 | 
			
		||||
| 
						 | 
				
			
			@ -698,75 +697,3 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
 | 
			
		|||
	for (i = 0; i < nr; i++)
 | 
			
		||||
		create_mapping(io_desc + i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
 | 
			
		||||
{
 | 
			
		||||
	struct page *start_pg, *end_pg;
 | 
			
		||||
	unsigned long pg, pgend;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Convert start_pfn/end_pfn to a struct page pointer.
 | 
			
		||||
	 */
 | 
			
		||||
	start_pg = pfn_to_page(start_pfn);
 | 
			
		||||
	end_pg = pfn_to_page(end_pfn);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Convert to physical addresses, and
 | 
			
		||||
	 * round start upwards and end downwards.
 | 
			
		||||
	 */
 | 
			
		||||
	pg = PAGE_ALIGN(__pa(start_pg));
 | 
			
		||||
	pgend = __pa(end_pg) & PAGE_MASK;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If there are free pages between these,
 | 
			
		||||
	 * free the section of the memmap array.
 | 
			
		||||
	 */
 | 
			
		||||
	if (pg < pgend)
 | 
			
		||||
		free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void free_unused_memmap_node(int node, struct meminfo *mi)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long bank_start, prev_bank_end = 0;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * [FIXME] This relies on each bank being in address order.  This
 | 
			
		||||
	 * may not be the case, especially if the user has provided the
 | 
			
		||||
	 * information on the command line.
 | 
			
		||||
	 */
 | 
			
		||||
	for (i = 0; i < mi->nr_banks; i++) {
 | 
			
		||||
		if (mi->bank[i].size == 0 || mi->bank[i].node != node)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		bank_start = mi->bank[i].start >> PAGE_SHIFT;
 | 
			
		||||
		if (bank_start < prev_bank_end) {
 | 
			
		||||
			printk(KERN_ERR "MEM: unordered memory banks.  "
 | 
			
		||||
				"Not freeing memmap.\n");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If we had a previous bank, and there is a space
 | 
			
		||||
		 * between the current bank and the previous, free it.
 | 
			
		||||
		 */
 | 
			
		||||
		if (prev_bank_end && prev_bank_end != bank_start)
 | 
			
		||||
			free_memmap(node, prev_bank_end, bank_start);
 | 
			
		||||
 | 
			
		||||
		prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
 | 
			
		||||
					   mi->bank[i].size) >> PAGE_SHIFT;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The mem_map array can get very big.  Free
 | 
			
		||||
 * the unused area of the memory map.
 | 
			
		||||
 */
 | 
			
		||||
void __init create_memmap_holes(struct meminfo *mi)
 | 
			
		||||
{
 | 
			
		||||
	int node;
 | 
			
		||||
 | 
			
		||||
	for_each_online_node(node)
 | 
			
		||||
		free_unused_memmap_node(node, mi);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@
 | 
			
		|||
# To add an entry into this database, please see Documentation/arm/README,
 | 
			
		||||
# or contact rmk@arm.linux.org.uk
 | 
			
		||||
#
 | 
			
		||||
# Last update: Thu Mar 24 14:34:50 2005
 | 
			
		||||
# Last update: Thu Jun 23 20:19:33 2005
 | 
			
		||||
#
 | 
			
		||||
# machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -243,7 +243,7 @@ yoho			ARCH_YOHO		YOHO			231
 | 
			
		|||
jasper			ARCH_JASPER		JASPER			232
 | 
			
		||||
dsc25			ARCH_DSC25		DSC25			233
 | 
			
		||||
omap_innovator		MACH_OMAP_INNOVATOR	OMAP_INNOVATOR		234
 | 
			
		||||
ramses			ARCH_RAMSES		RAMSES			235
 | 
			
		||||
mnci			ARCH_RAMSES		RAMSES			235
 | 
			
		||||
s28x			ARCH_S28X		S28X			236
 | 
			
		||||
mport3			ARCH_MPORT3		MPORT3			237
 | 
			
		||||
pxa_eagle250		ARCH_PXA_EAGLE250	PXA_EAGLE250		238
 | 
			
		||||
| 
						 | 
				
			
			@ -323,7 +323,7 @@ nimbra29x		ARCH_NIMBRA29X		NIMBRA29X		311
 | 
			
		|||
nimbra210		ARCH_NIMBRA210		NIMBRA210		312
 | 
			
		||||
hhp_d95xx		ARCH_HHP_D95XX		HHP_D95XX		313
 | 
			
		||||
labarm			ARCH_LABARM		LABARM			314
 | 
			
		||||
m825xx			ARCH_M825XX		M825XX			315
 | 
			
		||||
comcerto		ARCH_M825XX		M825XX			315
 | 
			
		||||
m7100			SA1100_M7100		M7100			316
 | 
			
		||||
nipc2			ARCH_NIPC2		NIPC2			317
 | 
			
		||||
fu7202			ARCH_FU7202		FU7202			318
 | 
			
		||||
| 
						 | 
				
			
			@ -724,3 +724,66 @@ lpc22xx			MACH_LPC22XX		LPC22XX			715
 | 
			
		|||
omap_comet3		MACH_COMET3		COMET3			716
 | 
			
		||||
omap_comet4		MACH_COMET4		COMET4			717
 | 
			
		||||
csb625			MACH_CSB625		CSB625			718
 | 
			
		||||
fortunet2		MACH_FORTUNET2		FORTUNET2		719
 | 
			
		||||
s5h2200			MACH_S5H2200		S5H2200			720
 | 
			
		||||
optorm920		MACH_OPTORM920		OPTORM920		721
 | 
			
		||||
adsbitsyxb		MACH_ADSBITSYXB		ADSBITSYXB		722
 | 
			
		||||
adssphere		MACH_ADSSPHERE		ADSSPHERE		723
 | 
			
		||||
adsportal		MACH_ADSPORTAL		ADSPORTAL		724
 | 
			
		||||
ln2410sbc		MACH_LN2410SBC		LN2410SBC		725
 | 
			
		||||
cb3rufc			MACH_CB3RUFC		CB3RUFC			726
 | 
			
		||||
mp2usb			MACH_MP2USB		MP2USB			727
 | 
			
		||||
ntnp425c		MACH_NTNP425C		NTNP425C		728
 | 
			
		||||
colibri			MACH_COLIBRI		COLIBRI			729
 | 
			
		||||
pcm7220			MACH_PCM7220		PCM7220			730
 | 
			
		||||
gateway7001		MACH_GATEWAY7001	GATEWAY7001		731
 | 
			
		||||
pcm027			MACH_PCM027		PCM027			732
 | 
			
		||||
cmpxa			MACH_CMPXA		CMPXA			733
 | 
			
		||||
anubis			MACH_ANUBIS		ANUBIS			734
 | 
			
		||||
ite8152			MACH_ITE8152		ITE8152			735
 | 
			
		||||
lpc3xxx			MACH_LPC3XXX		LPC3XXX			736
 | 
			
		||||
puppeteer		MACH_PUPPETEER		PUPPETEER		737
 | 
			
		||||
vt001			MACH_MACH_VADATECH	MACH_VADATECH		738
 | 
			
		||||
e570			MACH_E570		E570			739
 | 
			
		||||
x50			MACH_X50		X50			740
 | 
			
		||||
recon			MACH_RECON		RECON			741
 | 
			
		||||
xboardgp8		MACH_XBOARDGP8		XBOARDGP8		742
 | 
			
		||||
fpic2			MACH_FPIC2		FPIC2			743
 | 
			
		||||
akita			MACH_AKITA		AKITA			744
 | 
			
		||||
a81			MACH_A81		A81			745
 | 
			
		||||
svm_sc25x		MACH_SVM_SC25X		SVM_SC25X		746
 | 
			
		||||
vt020			MACH_VADATECH020	VADATECH020		747
 | 
			
		||||
tli			MACH_TLI		TLI			748
 | 
			
		||||
edb9315lc		MACH_EDB9315LC		EDB9315LC		749
 | 
			
		||||
passec			MACH_PASSEC		PASSEC			750
 | 
			
		||||
ds_tiger		MACH_DS_TIGER		DS_TIGER		751
 | 
			
		||||
e310			MACH_E310		E310			752
 | 
			
		||||
e330			MACH_E330		E330			753
 | 
			
		||||
rt3000			MACH_RT3000		RT3000			754
 | 
			
		||||
nokia770		MACH_NOKIA770		NOKIA770		755
 | 
			
		||||
pnx0106			MACH_PNX0106		PNX0106			756
 | 
			
		||||
hx21xx			MACH_HX21XX		HX21XX			757
 | 
			
		||||
faraday			MACH_FARADAY		FARADAY			758
 | 
			
		||||
sbc9312			MACH_SBC9312		SBC9312			759
 | 
			
		||||
batman			MACH_BATMAN		BATMAN			760
 | 
			
		||||
jpd201			MACH_JPD201		JPD201			761
 | 
			
		||||
mipsa			MACH_MIPSA		MIPSA			762
 | 
			
		||||
kacom			MACH_KACOM		KACOM			763
 | 
			
		||||
swarcocpu		MACH_SWARCOCPU		SWARCOCPU		764
 | 
			
		||||
swarcodsl		MACH_SWARCODSL		SWARCODSL		765
 | 
			
		||||
blueangel		MACH_BLUEANGEL		BLUEANGEL		766
 | 
			
		||||
hairygrama		MACH_HAIRYGRAMA		HAIRYGRAMA		767
 | 
			
		||||
banff			MACH_BANFF		BANFF			768
 | 
			
		||||
carmeva			MACH_CARMEVA		CARMEVA			769
 | 
			
		||||
sam255			MACH_SAM255		SAM255			770
 | 
			
		||||
ppm10			MACH_PPM10		PPM10			771
 | 
			
		||||
edb9315a		MACH_EDB9315A		EDB9315A		772
 | 
			
		||||
sunset			MACH_SUNSET		SUNSET			773
 | 
			
		||||
stargate2		MACH_STARGATE2		STARGATE2		774
 | 
			
		||||
intelmote2		MACH_INTELMOTE2		INTELMOTE2		775
 | 
			
		||||
trizeps4		MACH_TRIZEPS4		TRIZEPS4		776
 | 
			
		||||
mainstone2		MACH_MAINSTONE2		MAINSTONE2		777
 | 
			
		||||
ez_ixp42x		MACH_EZ_IXP42X		EZ_IXP42X		778
 | 
			
		||||
tapwave_zodiac		MACH_TAPWAVE_ZODIAC	TAPWAVE_ZODIAC		779
 | 
			
		||||
universalmeter		MACH_UNIVERSALMETER	UNIVERSALMETER		780
 | 
			
		||||
hicoarm9		MACH_HICOARM9		HICOARM9		781
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -127,50 +127,25 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 | 
			
		|||
		regs->eip = (unsigned long)&p->ainsn.insn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct task_struct  *arch_get_kprobe_task(void *ptr)
 | 
			
		||||
{
 | 
			
		||||
	return ((struct thread_info *) (((unsigned long) ptr) &
 | 
			
		||||
					(~(THREAD_SIZE -1))))->task;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long *sara = (unsigned long *)®s->esp;
 | 
			
		||||
        struct kretprobe_instance *ri;
 | 
			
		||||
	static void *orig_ret_addr;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Save the return address when the return probe hits
 | 
			
		||||
	 * the first time, and use it to populate the (krprobe
 | 
			
		||||
	 * instance)->ret_addr for subsequent return probes at
 | 
			
		||||
	 * the same addrress since stack address would have
 | 
			
		||||
	 * the kretprobe_trampoline by then.
 | 
			
		||||
	 */
 | 
			
		||||
	if (((void*) *sara) != kretprobe_trampoline)
 | 
			
		||||
		orig_ret_addr = (void*) *sara;
 | 
			
		||||
 | 
			
		||||
        if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
			
		||||
                ri->rp = rp;
 | 
			
		||||
		ri->stack_addr = sara;
 | 
			
		||||
		ri->ret_addr = orig_ret_addr;
 | 
			
		||||
		add_rp_inst(ri);
 | 
			
		||||
                ri->task = current;
 | 
			
		||||
		ri->ret_addr = (kprobe_opcode_t *) *sara;
 | 
			
		||||
 | 
			
		||||
		/* Replace the return addr with trampoline addr */
 | 
			
		||||
		*sara = (unsigned long) &kretprobe_trampoline;
 | 
			
		||||
 | 
			
		||||
                add_rp_inst(ri);
 | 
			
		||||
        } else {
 | 
			
		||||
                rp->nmissed++;
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_kprobe_flush_task(struct task_struct *tk)
 | 
			
		||||
{
 | 
			
		||||
	struct kretprobe_instance *ri;
 | 
			
		||||
	while ((ri = get_rp_inst_tsk(tk)) != NULL) {
 | 
			
		||||
		*((unsigned long *)(ri->stack_addr)) =
 | 
			
		||||
					(unsigned long) ri->ret_addr;
 | 
			
		||||
		recycle_rp_inst(ri);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Interrupts are disabled on entry as trap3 is an interrupt gate and they
 | 
			
		||||
 * remain disabled thorough out this function.
 | 
			
		||||
| 
						 | 
				
			
			@ -286,36 +261,59 @@ no_kprobe:
 | 
			
		|||
 */
 | 
			
		||||
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	struct task_struct *tsk;
 | 
			
		||||
	struct kretprobe_instance *ri;
 | 
			
		||||
        struct kretprobe_instance *ri = NULL;
 | 
			
		||||
        struct hlist_head *head;
 | 
			
		||||
	struct hlist_node *node;
 | 
			
		||||
	unsigned long *sara = ((unsigned long *) ®s->esp) - 1;
 | 
			
		||||
        struct hlist_node *node, *tmp;
 | 
			
		||||
	unsigned long orig_ret_address = 0;
 | 
			
		||||
	unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 | 
			
		||||
 | 
			
		||||
	tsk = arch_get_kprobe_task(sara);
 | 
			
		||||
	head = kretprobe_inst_table_head(tsk);
 | 
			
		||||
        head = kretprobe_inst_table_head(current);
 | 
			
		||||
 | 
			
		||||
	hlist_for_each_entry(ri, node, head, hlist) {
 | 
			
		||||
		if (ri->stack_addr == sara && ri->rp) {
 | 
			
		||||
			if (ri->rp->handler)
 | 
			
		||||
	/*
 | 
			
		||||
	 * It is possible to have multiple instances associated with a given
 | 
			
		||||
	 * task either because an multiple functions in the call path
 | 
			
		||||
	 * have a return probe installed on them, and/or more then one return
 | 
			
		||||
	 * return probe was registered for a target function.
 | 
			
		||||
	 *
 | 
			
		||||
	 * We can handle this because:
 | 
			
		||||
	 *     - instances are always inserted at the head of the list
 | 
			
		||||
	 *     - when multiple return probes are registered for the same
 | 
			
		||||
         *       function, the first instance's ret_addr will point to the
 | 
			
		||||
	 *       real return address, and all the rest will point to
 | 
			
		||||
	 *       kretprobe_trampoline
 | 
			
		||||
	 */
 | 
			
		||||
	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 | 
			
		||||
                if (ri->task != current)
 | 
			
		||||
			/* another task is sharing our hash bucket */
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
		if (ri->rp && ri->rp->handler)
 | 
			
		||||
			ri->rp->handler(ri, regs);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
 | 
			
		||||
						unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	struct kretprobe_instance *ri;
 | 
			
		||||
	/* RA already popped */
 | 
			
		||||
	unsigned long *sara = ((unsigned long *)®s->esp) - 1;
 | 
			
		||||
 | 
			
		||||
	while ((ri = get_rp_inst(sara))) {
 | 
			
		||||
		regs->eip = (unsigned long)ri->ret_addr;
 | 
			
		||||
		orig_ret_address = (unsigned long)ri->ret_addr;
 | 
			
		||||
		recycle_rp_inst(ri);
 | 
			
		||||
 | 
			
		||||
		if (orig_ret_address != trampoline_address)
 | 
			
		||||
			/*
 | 
			
		||||
			 * This is the real return address. Any other
 | 
			
		||||
			 * instances associated with this task are for
 | 
			
		||||
			 * other calls deeper on the call stack
 | 
			
		||||
			 */
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	regs->eflags &= ~TF_MASK;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
 | 
			
		||||
	regs->eip = orig_ret_address;
 | 
			
		||||
 | 
			
		||||
	unlock_kprobes();
 | 
			
		||||
	preempt_enable_no_resched();
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * By returning a non-zero value, we are telling
 | 
			
		||||
         * kprobe_handler() that we have handled unlocking
 | 
			
		||||
         * and re-enabling preemption.
 | 
			
		||||
         */
 | 
			
		||||
        return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -403,7 +401,6 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
 | 
			
		|||
		current_kprobe->post_handler(current_kprobe, regs, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (current_kprobe->post_handler != trampoline_post_handler)
 | 
			
		||||
	resume_execution(current_kprobe, regs);
 | 
			
		||||
	regs->eflags |= kprobe_saved_eflags;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -534,3 +531,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 | 
			
		|||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct kprobe trampoline_p = {
 | 
			
		||||
	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
 | 
			
		||||
	.pre_handler = trampoline_probe_handler
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int __init arch_init(void)
 | 
			
		||||
{
 | 
			
		||||
	return register_kprobe(&trampoline_p);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -616,6 +616,33 @@ handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss)
 | 
			
		|||
	tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This function selects if the context switch from prev to next
 | 
			
		||||
 * has to tweak the TSC disable bit in the cr4.
 | 
			
		||||
 */
 | 
			
		||||
static inline void disable_tsc(struct task_struct *prev_p,
 | 
			
		||||
			       struct task_struct *next_p)
 | 
			
		||||
{
 | 
			
		||||
	struct thread_info *prev, *next;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * gcc should eliminate the ->thread_info dereference if
 | 
			
		||||
	 * has_secure_computing returns 0 at compile time (SECCOMP=n).
 | 
			
		||||
	 */
 | 
			
		||||
	prev = prev_p->thread_info;
 | 
			
		||||
	next = next_p->thread_info;
 | 
			
		||||
 | 
			
		||||
	if (has_secure_computing(prev) || has_secure_computing(next)) {
 | 
			
		||||
		/* slow path here */
 | 
			
		||||
		if (has_secure_computing(prev) &&
 | 
			
		||||
		    !has_secure_computing(next)) {
 | 
			
		||||
			write_cr4(read_cr4() & ~X86_CR4_TSD);
 | 
			
		||||
		} else if (!has_secure_computing(prev) &&
 | 
			
		||||
			   has_secure_computing(next))
 | 
			
		||||
			write_cr4(read_cr4() | X86_CR4_TSD);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *	switch_to(x,yn) should switch tasks from x to y.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -695,6 +722,8 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
 | 
			
		|||
	if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr))
 | 
			
		||||
		handle_io_bitmap(next, tss);
 | 
			
		||||
 | 
			
		||||
	disable_tsc(prev_p, next_p);
 | 
			
		||||
 | 
			
		||||
	return prev_p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -289,3 +289,5 @@ ENTRY(sys_call_table)
 | 
			
		|||
	.long sys_add_key
 | 
			
		||||
	.long sys_request_key
 | 
			
		||||
	.long sys_keyctl
 | 
			
		||||
	.long sys_ioprio_set
 | 
			
		||||
	.long sys_ioprio_get		/* 290 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1577,8 +1577,8 @@ sys_call_table:
 | 
			
		|||
	data8 sys_add_key
 | 
			
		||||
	data8 sys_request_key
 | 
			
		||||
	data8 sys_keyctl
 | 
			
		||||
	data8 sys_ni_syscall
 | 
			
		||||
	data8 sys_ni_syscall			// 1275
 | 
			
		||||
	data8 sys_ioprio_set
 | 
			
		||||
	data8 sys_ioprio_get			// 1275
 | 
			
		||||
	data8 sys_set_zone_reclaim
 | 
			
		||||
	data8 sys_ni_syscall
 | 
			
		||||
	data8 sys_ni_syscall
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@
 | 
			
		|||
 | 
			
		||||
#include <asm/pgtable.h>
 | 
			
		||||
#include <asm/kdebug.h>
 | 
			
		||||
#include <asm/sections.h>
 | 
			
		||||
 | 
			
		||||
extern void jprobe_inst_return(void);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -263,13 +264,33 @@ static inline void get_kprobe_inst(bundle_t *bundle, uint slot,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Returns non-zero if the addr is in the Interrupt Vector Table */
 | 
			
		||||
static inline int in_ivt_functions(unsigned long addr)
 | 
			
		||||
{
 | 
			
		||||
	return (addr >= (unsigned long)__start_ivt_text
 | 
			
		||||
		&& addr < (unsigned long)__end_ivt_text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int valid_kprobe_addr(int template, int slot, unsigned long addr)
 | 
			
		||||
{
 | 
			
		||||
	if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
 | 
			
		||||
		printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n",
 | 
			
		||||
				addr);
 | 
			
		||||
		printk(KERN_WARNING "Attempting to insert unaligned kprobe "
 | 
			
		||||
				"at 0x%lx\n", addr);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 	if (in_ivt_functions(addr)) {
 | 
			
		||||
 		printk(KERN_WARNING "Kprobes can't be inserted inside "
 | 
			
		||||
				"IVT functions at 0x%lx\n", addr);
 | 
			
		||||
 		return -EINVAL;
 | 
			
		||||
 	}
 | 
			
		||||
 | 
			
		||||
	if (slot == 1 && bundle_encoding[template][1] != L) {
 | 
			
		||||
		printk(KERN_WARNING "Inserting kprobes on slot #1 "
 | 
			
		||||
		       "is not supported\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -290,6 +311,94 @@ static inline void set_current_kprobe(struct kprobe *p)
 | 
			
		|||
	current_kprobe = p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void kretprobe_trampoline(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * At this point the target function has been tricked into
 | 
			
		||||
 * returning into our trampoline.  Lookup the associated instance
 | 
			
		||||
 * and then:
 | 
			
		||||
 *    - call the handler function
 | 
			
		||||
 *    - cleanup by marking the instance as unused
 | 
			
		||||
 *    - long jump back to the original return address
 | 
			
		||||
 */
 | 
			
		||||
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	struct kretprobe_instance *ri = NULL;
 | 
			
		||||
	struct hlist_head *head;
 | 
			
		||||
	struct hlist_node *node, *tmp;
 | 
			
		||||
	unsigned long orig_ret_address = 0;
 | 
			
		||||
	unsigned long trampoline_address =
 | 
			
		||||
		((struct fnptr *)kretprobe_trampoline)->ip;
 | 
			
		||||
 | 
			
		||||
        head = kretprobe_inst_table_head(current);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * It is possible to have multiple instances associated with a given
 | 
			
		||||
	 * task either because an multiple functions in the call path
 | 
			
		||||
	 * have a return probe installed on them, and/or more then one return
 | 
			
		||||
	 * return probe was registered for a target function.
 | 
			
		||||
	 *
 | 
			
		||||
	 * We can handle this because:
 | 
			
		||||
	 *     - instances are always inserted at the head of the list
 | 
			
		||||
	 *     - when multiple return probes are registered for the same
 | 
			
		||||
	 *       function, the first instance's ret_addr will point to the
 | 
			
		||||
	 *       real return address, and all the rest will point to
 | 
			
		||||
	 *       kretprobe_trampoline
 | 
			
		||||
	 */
 | 
			
		||||
	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 | 
			
		||||
                if (ri->task != current)
 | 
			
		||||
			/* another task is sharing our hash bucket */
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
		if (ri->rp && ri->rp->handler)
 | 
			
		||||
			ri->rp->handler(ri, regs);
 | 
			
		||||
 | 
			
		||||
		orig_ret_address = (unsigned long)ri->ret_addr;
 | 
			
		||||
		recycle_rp_inst(ri);
 | 
			
		||||
 | 
			
		||||
		if (orig_ret_address != trampoline_address)
 | 
			
		||||
			/*
 | 
			
		||||
			 * This is the real return address. Any other
 | 
			
		||||
			 * instances associated with this task are for
 | 
			
		||||
			 * other calls deeper on the call stack
 | 
			
		||||
			 */
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
 | 
			
		||||
	regs->cr_iip = orig_ret_address;
 | 
			
		||||
 | 
			
		||||
	unlock_kprobes();
 | 
			
		||||
	preempt_enable_no_resched();
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * By returning a non-zero value, we are telling
 | 
			
		||||
         * kprobe_handler() that we have handled unlocking
 | 
			
		||||
         * and re-enabling preemption.
 | 
			
		||||
         */
 | 
			
		||||
        return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	struct kretprobe_instance *ri;
 | 
			
		||||
 | 
			
		||||
	if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
			
		||||
		ri->rp = rp;
 | 
			
		||||
		ri->task = current;
 | 
			
		||||
		ri->ret_addr = (kprobe_opcode_t *)regs->b0;
 | 
			
		||||
 | 
			
		||||
		/* Replace the return addr with trampoline addr */
 | 
			
		||||
		regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
 | 
			
		||||
 | 
			
		||||
		add_rp_inst(ri);
 | 
			
		||||
	} else {
 | 
			
		||||
		rp->nmissed++;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int arch_prepare_kprobe(struct kprobe *p)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long addr = (unsigned long) p->addr;
 | 
			
		||||
| 
						 | 
				
			
			@ -492,8 +601,8 @@ static int pre_kprobes_handler(struct die_args *args)
 | 
			
		|||
	if (p->pre_handler && p->pre_handler(p, regs))
 | 
			
		||||
		/*
 | 
			
		||||
		 * Our pre-handler is specifically requesting that we just
 | 
			
		||||
		 * do a return.  This is handling the case where the
 | 
			
		||||
		 * pre-handler is really our special jprobe pre-handler.
 | 
			
		||||
		 * do a return.  This is used for both the jprobe pre-handler
 | 
			
		||||
		 * and the kretprobe trampoline
 | 
			
		||||
		 */
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -599,3 +708,14 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 | 
			
		|||
	*regs = jprobe_saved_regs;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct kprobe trampoline_p = {
 | 
			
		||||
	.pre_handler = trampoline_probe_handler
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int __init arch_init(void)
 | 
			
		||||
{
 | 
			
		||||
	trampoline_p.addr =
 | 
			
		||||
		(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;
 | 
			
		||||
	return register_kprobe(&trampoline_p);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,6 +27,7 @@
 | 
			
		|||
#include <linux/efi.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/kprobes.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/cpu.h>
 | 
			
		||||
#include <asm/delay.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -707,6 +708,13 @@ kernel_thread_helper (int (*fn)(void *), void *arg)
 | 
			
		|||
void
 | 
			
		||||
flush_thread (void)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * Remove function-return probe instances associated with this task
 | 
			
		||||
	 * and put them back on the free list. Do not insert an exit probe for
 | 
			
		||||
	 * this function, it will be disabled by kprobe_flush_task if you do.
 | 
			
		||||
	 */
 | 
			
		||||
	kprobe_flush_task(current);
 | 
			
		||||
 | 
			
		||||
	/* drop floating-point and debug-register state if it exists: */
 | 
			
		||||
	current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID);
 | 
			
		||||
	ia64_drop_fpu(current);
 | 
			
		||||
| 
						 | 
				
			
			@ -721,6 +729,14 @@ flush_thread (void)
 | 
			
		|||
void
 | 
			
		||||
exit_thread (void)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Remove function-return probe instances associated with this task
 | 
			
		||||
	 * and put them back on the free list. Do not insert an exit probe for
 | 
			
		||||
	 * this function, it will be disabled by kprobe_flush_task if you do.
 | 
			
		||||
	 */
 | 
			
		||||
	kprobe_flush_task(current);
 | 
			
		||||
 | 
			
		||||
	ia64_drop_fpu(current);
 | 
			
		||||
#ifdef CONFIG_PERFMON
 | 
			
		||||
       /* if needed, stop monitoring and flush state to perfmon context */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,11 @@
 | 
			
		|||
#define LOAD_OFFSET	(KERNEL_START - KERNEL_TR_PAGE_SIZE)
 | 
			
		||||
#include <asm-generic/vmlinux.lds.h>
 | 
			
		||||
 | 
			
		||||
#define IVT_TEXT							\
 | 
			
		||||
		VMLINUX_SYMBOL(__start_ivt_text) = .;			\
 | 
			
		||||
		*(.text.ivt)						\
 | 
			
		||||
		VMLINUX_SYMBOL(__end_ivt_text) = .;
 | 
			
		||||
 | 
			
		||||
OUTPUT_FORMAT("elf64-ia64-little")
 | 
			
		||||
OUTPUT_ARCH(ia64)
 | 
			
		||||
ENTRY(phys_start)
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +44,7 @@ SECTIONS
 | 
			
		|||
 | 
			
		||||
  .text : AT(ADDR(.text) - LOAD_OFFSET)
 | 
			
		||||
    {
 | 
			
		||||
	*(.text.ivt)
 | 
			
		||||
	IVT_TEXT
 | 
			
		||||
	*(.text)
 | 
			
		||||
	SCHED_TEXT
 | 
			
		||||
	LOCK_TEXT
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -457,7 +457,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs)
 | 
			
		|||
	if (!user_mode(regs))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (try_to_freeze(0))
 | 
			
		||||
	if (try_to_freeze())
 | 
			
		||||
		goto no_signal;
 | 
			
		||||
 | 
			
		||||
	if (!oldset)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1449,3 +1449,5 @@ _GLOBAL(sys_call_table)
 | 
			
		|||
	.long sys_request_key		/* 270 */
 | 
			
		||||
	.long sys_keyctl
 | 
			
		||||
	.long sys_waitid
 | 
			
		||||
	.long sys_ioprio_set
 | 
			
		||||
	.long sys_ioprio_get
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -606,9 +606,19 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
 | 
			
		|||
		struct page *page = pfn_to_page(pfn);
 | 
			
		||||
		if (!PageReserved(page)
 | 
			
		||||
		    && !test_bit(PG_arch_1, &page->flags)) {
 | 
			
		||||
			if (vma->vm_mm == current->active_mm)
 | 
			
		||||
			if (vma->vm_mm == current->active_mm) {
 | 
			
		||||
#ifdef CONFIG_8xx
 | 
			
		||||
			/* On 8xx, cache control instructions (particularly 
 | 
			
		||||
		 	 * "dcbst" from flush_dcache_icache) fault as write 
 | 
			
		||||
			 * operation if there is an unpopulated TLB entry 
 | 
			
		||||
			 * for the address in question. To workaround that, 
 | 
			
		||||
			 * we invalidate the TLB here, thus avoiding dcbst 
 | 
			
		||||
			 * misbehaviour.
 | 
			
		||||
			 */
 | 
			
		||||
				_tlbie(address);
 | 
			
		||||
#endif
 | 
			
		||||
				__flush_dcache_icache((void *) address);
 | 
			
		||||
			else
 | 
			
		||||
			} else
 | 
			
		||||
				flush_dcache_icache_page(page);
 | 
			
		||||
			set_bit(PG_arch_1, &page->flags);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,7 @@
 | 
			
		|||
	.section .text
 | 
			
		||||
	.align	5
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC)
 | 
			
		||||
#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
 | 
			
		||||
 | 
			
		||||
/* This gets called by via-pmu.c late during the sleep process.
 | 
			
		||||
 * The PMU was already send the sleep command and will shut us down
 | 
			
		||||
| 
						 | 
				
			
			@ -382,7 +382,7 @@ turn_on_mmu:
 | 
			
		|||
	isync
 | 
			
		||||
	rfi
 | 
			
		||||
 | 
			
		||||
#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */
 | 
			
		||||
#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */
 | 
			
		||||
 | 
			
		||||
	.section .data
 | 
			
		||||
	.balign	L1_CACHE_LINE_SIZE
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -206,7 +206,7 @@ via_calibrate_decr(void)
 | 
			
		|||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
/*
 | 
			
		||||
 * Reset the time after a sleep.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -238,7 +238,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when)
 | 
			
		|||
static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
 | 
			
		||||
	time_sleep_notify, SLEEP_LEVEL_MISC,
 | 
			
		||||
};
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif /* CONFIG_PM */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Query the OF and get the decr frequency.
 | 
			
		||||
| 
						 | 
				
			
			@ -251,9 +251,9 @@ pmac_calibrate_decr(void)
 | 
			
		|||
	struct device_node *cpu;
 | 
			
		||||
	unsigned int freq, *fp;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
	pmu_register_sleep_notifier(&time_sleep_notifier);
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif /* CONFIG_PM */
 | 
			
		||||
 | 
			
		||||
	/* We assume MacRISC2 machines have correct device-tree
 | 
			
		||||
	 * calibration. That's better since the VIA itself seems
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -324,6 +324,7 @@ sandpoint_setup_arch(void)
 | 
			
		|||
			pdata[1].irq = 0;
 | 
			
		||||
			pdata[1].mapbase = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n");
 | 
			
		||||
	printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -370,8 +370,9 @@ void __init openpic_init(int offset)
 | 
			
		|||
	/* Initialize IPI interrupts */
 | 
			
		||||
	if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
 | 
			
		||||
	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
 | 
			
		||||
		/* Disabled, Priority 10..13 */
 | 
			
		||||
		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
 | 
			
		||||
		/* Disabled, increased priorities 10..13 */
 | 
			
		||||
		openpic_initipi(i, OPENPIC_PRIORITY_IPI_BASE+i,
 | 
			
		||||
				OPENPIC_VEC_IPI+i+offset);
 | 
			
		||||
		/* IPIs are per-CPU */
 | 
			
		||||
		irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
 | 
			
		||||
		irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
 | 
			
		||||
| 
						 | 
				
			
			@ -399,8 +400,9 @@ void __init openpic_init(int offset)
 | 
			
		|||
		if (sense & IRQ_SENSE_MASK)
 | 
			
		||||
			irq_desc[i+offset].status = IRQ_LEVEL;
 | 
			
		||||
 | 
			
		||||
		/* Enabled, Priority 8 */
 | 
			
		||||
		openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
 | 
			
		||||
		/* Enabled, Default priority */
 | 
			
		||||
		openpic_initirq(i, OPENPIC_PRIORITY_DEFAULT, i+offset,
 | 
			
		||||
				(sense & IRQ_POLARITY_MASK),
 | 
			
		||||
				(sense & IRQ_SENSE_MASK));
 | 
			
		||||
		/* Processor 0 */
 | 
			
		||||
		openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
 | 
			
		||||
| 
						 | 
				
			
			@ -655,6 +657,18 @@ static void __init openpic_maptimer(u_int timer, cpumask_t cpumask)
 | 
			
		|||
		      cpus_addr(phys)[0]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Change the priority of an interrupt
 | 
			
		||||
 */
 | 
			
		||||
void __init
 | 
			
		||||
openpic_set_irq_priority(u_int irq, u_int pri)
 | 
			
		||||
{
 | 
			
		||||
	check_arg_irq(irq);
 | 
			
		||||
	openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
 | 
			
		||||
				OPENPIC_PRIORITY_MASK,
 | 
			
		||||
				pri << OPENPIC_PRIORITY_SHIFT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Initalize the interrupt source which will generate an NMI.
 | 
			
		||||
 * This raises the interrupt's priority from 8 to 9.
 | 
			
		||||
| 
						 | 
				
			
			@ -665,9 +679,7 @@ void __init
 | 
			
		|||
openpic_init_nmi_irq(u_int irq)
 | 
			
		||||
{
 | 
			
		||||
	check_arg_irq(irq);
 | 
			
		||||
	openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
 | 
			
		||||
				OPENPIC_PRIORITY_MASK,
 | 
			
		||||
				9 << OPENPIC_PRIORITY_SHIFT);
 | 
			
		||||
	openpic_set_irq_priority(irq, OPENPIC_PRIORITY_NMI);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,8 @@
 | 
			
		|||
#include <asm/kdebug.h>
 | 
			
		||||
#include <asm/sstep.h>
 | 
			
		||||
 | 
			
		||||
static DECLARE_MUTEX(kprobe_mutex);
 | 
			
		||||
 | 
			
		||||
static struct kprobe *current_kprobe;
 | 
			
		||||
static unsigned long kprobe_status, kprobe_saved_msr;
 | 
			
		||||
static struct kprobe *kprobe_prev;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +56,15 @@ int arch_prepare_kprobe(struct kprobe *p)
 | 
			
		|||
		printk("Cannot register a kprobe on rfid or mtmsrd\n");
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* insn must be on a special executable page on ppc64 */
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
		up(&kprobe_mutex);
 | 
			
		||||
		p->ainsn.insn = get_insn_slot();
 | 
			
		||||
		down(&kprobe_mutex);
 | 
			
		||||
		if (!p->ainsn.insn)
 | 
			
		||||
			ret = -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -79,16 +90,22 @@ void arch_disarm_kprobe(struct kprobe *p)
 | 
			
		|||
 | 
			
		||||
void arch_remove_kprobe(struct kprobe *p)
 | 
			
		||||
{
 | 
			
		||||
	up(&kprobe_mutex);
 | 
			
		||||
	free_insn_slot(p->ainsn.insn);
 | 
			
		||||
	down(&kprobe_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	kprobe_opcode_t insn = *p->ainsn.insn;
 | 
			
		||||
 | 
			
		||||
	regs->msr |= MSR_SE;
 | 
			
		||||
	/*single step inline if it a breakpoint instruction*/
 | 
			
		||||
	if (p->opcode == BREAKPOINT_INSTRUCTION)
 | 
			
		||||
 | 
			
		||||
	/* single step inline if it is a trap variant */
 | 
			
		||||
	if (IS_TW(insn) || IS_TD(insn) || IS_TWI(insn) || IS_TDI(insn))
 | 
			
		||||
		regs->nip = (unsigned long)p->addr;
 | 
			
		||||
	else
 | 
			
		||||
		regs->nip = (unsigned long)&p->ainsn.insn;
 | 
			
		||||
		regs->nip = (unsigned long)p->ainsn.insn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void save_previous_kprobe(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +122,23 @@ static inline void restore_previous_kprobe(void)
 | 
			
		|||
	kprobe_saved_msr = kprobe_saved_msr_prev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	struct kretprobe_instance *ri;
 | 
			
		||||
 | 
			
		||||
	if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
			
		||||
		ri->rp = rp;
 | 
			
		||||
		ri->task = current;
 | 
			
		||||
		ri->ret_addr = (kprobe_opcode_t *)regs->link;
 | 
			
		||||
 | 
			
		||||
		/* Replace the return addr with trampoline addr */
 | 
			
		||||
		regs->link = (unsigned long)kretprobe_trampoline;
 | 
			
		||||
		add_rp_inst(ri);
 | 
			
		||||
	} else {
 | 
			
		||||
		rp->nmissed++;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int kprobe_handler(struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	struct kprobe *p;
 | 
			
		||||
| 
						 | 
				
			
			@ -194,6 +228,78 @@ no_kprobe:
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Function return probe trampoline:
 | 
			
		||||
 * 	- init_kprobes() establishes a probepoint here
 | 
			
		||||
 * 	- When the probed function returns, this probe
 | 
			
		||||
 * 		causes the handlers to fire
 | 
			
		||||
 */
 | 
			
		||||
void kretprobe_trampoline_holder(void)
 | 
			
		||||
{
 | 
			
		||||
	asm volatile(".global kretprobe_trampoline\n"
 | 
			
		||||
			"kretprobe_trampoline:\n"
 | 
			
		||||
			"nop\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Called when the probe at kretprobe trampoline is hit
 | 
			
		||||
 */
 | 
			
		||||
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
        struct kretprobe_instance *ri = NULL;
 | 
			
		||||
        struct hlist_head *head;
 | 
			
		||||
        struct hlist_node *node, *tmp;
 | 
			
		||||
	unsigned long orig_ret_address = 0;
 | 
			
		||||
	unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 | 
			
		||||
 | 
			
		||||
        head = kretprobe_inst_table_head(current);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * It is possible to have multiple instances associated with a given
 | 
			
		||||
	 * task either because an multiple functions in the call path
 | 
			
		||||
	 * have a return probe installed on them, and/or more then one return
 | 
			
		||||
	 * return probe was registered for a target function.
 | 
			
		||||
	 *
 | 
			
		||||
	 * We can handle this because:
 | 
			
		||||
	 *     - instances are always inserted at the head of the list
 | 
			
		||||
	 *     - when multiple return probes are registered for the same
 | 
			
		||||
         *       function, the first instance's ret_addr will point to the
 | 
			
		||||
	 *       real return address, and all the rest will point to
 | 
			
		||||
	 *       kretprobe_trampoline
 | 
			
		||||
	 */
 | 
			
		||||
	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 | 
			
		||||
                if (ri->task != current)
 | 
			
		||||
			/* another task is sharing our hash bucket */
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
		if (ri->rp && ri->rp->handler)
 | 
			
		||||
			ri->rp->handler(ri, regs);
 | 
			
		||||
 | 
			
		||||
		orig_ret_address = (unsigned long)ri->ret_addr;
 | 
			
		||||
		recycle_rp_inst(ri);
 | 
			
		||||
 | 
			
		||||
		if (orig_ret_address != trampoline_address)
 | 
			
		||||
			/*
 | 
			
		||||
			 * This is the real return address. Any other
 | 
			
		||||
			 * instances associated with this task are for
 | 
			
		||||
			 * other calls deeper on the call stack
 | 
			
		||||
			 */
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
 | 
			
		||||
	regs->nip = orig_ret_address;
 | 
			
		||||
 | 
			
		||||
	unlock_kprobes();
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * By returning a non-zero value, we are telling
 | 
			
		||||
         * kprobe_handler() that we have handled unlocking
 | 
			
		||||
         * and re-enabling preemption.
 | 
			
		||||
         */
 | 
			
		||||
        return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Called after single-stepping.  p->addr is the address of the
 | 
			
		||||
 * instruction whose first byte has been replaced by the "breakpoint"
 | 
			
		||||
| 
						 | 
				
			
			@ -205,9 +311,10 @@ no_kprobe:
 | 
			
		|||
static void resume_execution(struct kprobe *p, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	unsigned int insn = *p->ainsn.insn;
 | 
			
		||||
 | 
			
		||||
	regs->nip = (unsigned long)p->addr;
 | 
			
		||||
	ret = emulate_step(regs, p->ainsn.insn[0]);
 | 
			
		||||
	ret = emulate_step(regs, insn);
 | 
			
		||||
	if (ret == 0)
 | 
			
		||||
		regs->nip = (unsigned long)p->addr + 4;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -331,3 +438,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 | 
			
		|||
	memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct kprobe trampoline_p = {
 | 
			
		||||
	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
 | 
			
		||||
	.pre_handler = trampoline_probe_handler
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int __init arch_init(void)
 | 
			
		||||
{
 | 
			
		||||
	return register_kprobe(&trampoline_p);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,6 +75,7 @@ EXPORT_SYMBOL(giveup_fpu);
 | 
			
		|||
EXPORT_SYMBOL(giveup_altivec);
 | 
			
		||||
#endif
 | 
			
		||||
EXPORT_SYMBOL(__flush_icache_range);
 | 
			
		||||
EXPORT_SYMBOL(flush_dcache_range);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_SMP
 | 
			
		||||
#ifdef CONFIG_PPC_ISERIES
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@
 | 
			
		|||
#include <linux/kallsyms.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/utsname.h>
 | 
			
		||||
#include <linux/kprobes.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/pgtable.h>
 | 
			
		||||
#include <asm/uaccess.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -307,6 +308,8 @@ void show_regs(struct pt_regs * regs)
 | 
			
		|||
 | 
			
		||||
void exit_thread(void)
 | 
			
		||||
{
 | 
			
		||||
	kprobe_flush_task(current);
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_SMP
 | 
			
		||||
	if (last_task_used_math == current)
 | 
			
		||||
		last_task_used_math = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -321,6 +324,7 @@ void flush_thread(void)
 | 
			
		|||
{
 | 
			
		||||
	struct thread_info *t = current_thread_info();
 | 
			
		||||
 | 
			
		||||
	kprobe_flush_task(current);
 | 
			
		||||
	if (t->flags & _TIF_ABI_PENDING)
 | 
			
		||||
		t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,6 +91,7 @@ unsigned long tb_to_xs;
 | 
			
		|||
unsigned      tb_to_us;
 | 
			
		||||
unsigned long processor_freq;
 | 
			
		||||
DEFINE_SPINLOCK(rtc_lock);
 | 
			
		||||
EXPORT_SYMBOL_GPL(rtc_lock);
 | 
			
		||||
 | 
			
		||||
unsigned long tb_to_ns_scale;
 | 
			
		||||
unsigned long tb_to_ns_shift;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@
 | 
			
		|||
#include <linux/string.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/preempt.h>
 | 
			
		||||
#include <linux/moduleloader.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/cacheflush.h>
 | 
			
		||||
#include <asm/pgtable.h>
 | 
			
		||||
#include <asm/kdebug.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -51,8 +51,6 @@ static struct kprobe *kprobe_prev;
 | 
			
		|||
static unsigned long kprobe_status_prev, kprobe_old_rflags_prev, kprobe_saved_rflags_prev;
 | 
			
		||||
static struct pt_regs jprobe_saved_regs;
 | 
			
		||||
static long *jprobe_saved_rsp;
 | 
			
		||||
static kprobe_opcode_t *get_insn_slot(void);
 | 
			
		||||
static void free_insn_slot(kprobe_opcode_t *slot);
 | 
			
		||||
void jprobe_return_end(void);
 | 
			
		||||
 | 
			
		||||
/* copy of the kernel stack at the probe fire time */
 | 
			
		||||
| 
						 | 
				
			
			@ -274,50 +272,25 @@ static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 | 
			
		|||
		regs->rip = (unsigned long)p->ainsn.insn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct task_struct  *arch_get_kprobe_task(void *ptr)
 | 
			
		||||
{
 | 
			
		||||
	return ((struct thread_info *) (((unsigned long) ptr) &
 | 
			
		||||
					(~(THREAD_SIZE -1))))->task;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long *sara = (unsigned long *)regs->rsp;
 | 
			
		||||
        struct kretprobe_instance *ri;
 | 
			
		||||
	static void *orig_ret_addr;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Save the return address when the return probe hits
 | 
			
		||||
	 * the first time, and use it to populate the (krprobe
 | 
			
		||||
	 * instance)->ret_addr for subsequent return probes at
 | 
			
		||||
	 * the same addrress since stack address would have
 | 
			
		||||
	 * the kretprobe_trampoline by then.
 | 
			
		||||
	 */
 | 
			
		||||
	if (((void*) *sara) != kretprobe_trampoline)
 | 
			
		||||
		orig_ret_addr = (void*) *sara;
 | 
			
		||||
 | 
			
		||||
        if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
			
		||||
                ri->rp = rp;
 | 
			
		||||
		ri->stack_addr = sara;
 | 
			
		||||
		ri->ret_addr = orig_ret_addr;
 | 
			
		||||
		add_rp_inst(ri);
 | 
			
		||||
                ri->task = current;
 | 
			
		||||
		ri->ret_addr = (kprobe_opcode_t *) *sara;
 | 
			
		||||
 | 
			
		||||
		/* Replace the return addr with trampoline addr */
 | 
			
		||||
		*sara = (unsigned long) &kretprobe_trampoline;
 | 
			
		||||
 | 
			
		||||
                add_rp_inst(ri);
 | 
			
		||||
        } else {
 | 
			
		||||
                rp->nmissed++;
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_kprobe_flush_task(struct task_struct *tk)
 | 
			
		||||
{
 | 
			
		||||
	struct kretprobe_instance *ri;
 | 
			
		||||
	while ((ri = get_rp_inst_tsk(tk)) != NULL) {
 | 
			
		||||
		*((unsigned long *)(ri->stack_addr)) =
 | 
			
		||||
					(unsigned long) ri->ret_addr;
 | 
			
		||||
		recycle_rp_inst(ri);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Interrupts are disabled on entry as trap3 is an interrupt gate and they
 | 
			
		||||
 * remain disabled thorough out this function.
 | 
			
		||||
| 
						 | 
				
			
			@ -428,36 +401,59 @@ no_kprobe:
 | 
			
		|||
 */
 | 
			
		||||
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	struct task_struct *tsk;
 | 
			
		||||
	struct kretprobe_instance *ri;
 | 
			
		||||
        struct kretprobe_instance *ri = NULL;
 | 
			
		||||
        struct hlist_head *head;
 | 
			
		||||
	struct hlist_node *node;
 | 
			
		||||
	unsigned long *sara = (unsigned long *)regs->rsp - 1;
 | 
			
		||||
        struct hlist_node *node, *tmp;
 | 
			
		||||
	unsigned long orig_ret_address = 0;
 | 
			
		||||
	unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 | 
			
		||||
 | 
			
		||||
	tsk = arch_get_kprobe_task(sara);
 | 
			
		||||
	head = kretprobe_inst_table_head(tsk);
 | 
			
		||||
        head = kretprobe_inst_table_head(current);
 | 
			
		||||
 | 
			
		||||
	hlist_for_each_entry(ri, node, head, hlist) {
 | 
			
		||||
		if (ri->stack_addr == sara && ri->rp) {
 | 
			
		||||
			if (ri->rp->handler)
 | 
			
		||||
	/*
 | 
			
		||||
	 * It is possible to have multiple instances associated with a given
 | 
			
		||||
	 * task either because an multiple functions in the call path
 | 
			
		||||
	 * have a return probe installed on them, and/or more then one return
 | 
			
		||||
	 * return probe was registered for a target function.
 | 
			
		||||
	 *
 | 
			
		||||
	 * We can handle this because:
 | 
			
		||||
	 *     - instances are always inserted at the head of the list
 | 
			
		||||
	 *     - when multiple return probes are registered for the same
 | 
			
		||||
         *       function, the first instance's ret_addr will point to the
 | 
			
		||||
	 *       real return address, and all the rest will point to
 | 
			
		||||
	 *       kretprobe_trampoline
 | 
			
		||||
	 */
 | 
			
		||||
	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 | 
			
		||||
                if (ri->task != current)
 | 
			
		||||
			/* another task is sharing our hash bucket */
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
		if (ri->rp && ri->rp->handler)
 | 
			
		||||
			ri->rp->handler(ri, regs);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
 | 
			
		||||
						unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	struct kretprobe_instance *ri;
 | 
			
		||||
	/* RA already popped */
 | 
			
		||||
	unsigned long *sara = ((unsigned long *)regs->rsp) - 1;
 | 
			
		||||
 | 
			
		||||
	while ((ri = get_rp_inst(sara))) {
 | 
			
		||||
		regs->rip = (unsigned long)ri->ret_addr;
 | 
			
		||||
		orig_ret_address = (unsigned long)ri->ret_addr;
 | 
			
		||||
		recycle_rp_inst(ri);
 | 
			
		||||
 | 
			
		||||
		if (orig_ret_address != trampoline_address)
 | 
			
		||||
			/*
 | 
			
		||||
			 * This is the real return address. Any other
 | 
			
		||||
			 * instances associated with this task are for
 | 
			
		||||
			 * other calls deeper on the call stack
 | 
			
		||||
			 */
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	regs->eflags &= ~TF_MASK;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
 | 
			
		||||
	regs->rip = orig_ret_address;
 | 
			
		||||
 | 
			
		||||
	unlock_kprobes();
 | 
			
		||||
	preempt_enable_no_resched();
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * By returning a non-zero value, we are telling
 | 
			
		||||
         * kprobe_handler() that we have handled unlocking
 | 
			
		||||
         * and re-enabling preemption.
 | 
			
		||||
         */
 | 
			
		||||
        return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -550,7 +546,6 @@ int post_kprobe_handler(struct pt_regs *regs)
 | 
			
		|||
		current_kprobe->post_handler(current_kprobe, regs, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (current_kprobe->post_handler != trampoline_post_handler)
 | 
			
		||||
	resume_execution(current_kprobe, regs);
 | 
			
		||||
	regs->eflags |= kprobe_saved_rflags;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -682,111 +677,12 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * kprobe->ainsn.insn points to the copy of the instruction to be single-stepped.
 | 
			
		||||
 * By default on x86_64, pages we get from kmalloc or vmalloc are not
 | 
			
		||||
 * executable.  Single-stepping an instruction on such a page yields an
 | 
			
		||||
 * oops.  So instead of storing the instruction copies in their respective
 | 
			
		||||
 * kprobe objects, we allocate a page, map it executable, and store all the
 | 
			
		||||
 * instruction copies there.  (We can allocate additional pages if somebody
 | 
			
		||||
 * inserts a huge number of probes.)  Each page can hold up to INSNS_PER_PAGE
 | 
			
		||||
 * instruction slots, each of which is MAX_INSN_SIZE*sizeof(kprobe_opcode_t)
 | 
			
		||||
 * bytes.
 | 
			
		||||
 */
 | 
			
		||||
#define INSNS_PER_PAGE (PAGE_SIZE/(MAX_INSN_SIZE*sizeof(kprobe_opcode_t)))
 | 
			
		||||
struct kprobe_insn_page {
 | 
			
		||||
	struct hlist_node hlist;
 | 
			
		||||
	kprobe_opcode_t *insns;		/* page of instruction slots */
 | 
			
		||||
	char slot_used[INSNS_PER_PAGE];
 | 
			
		||||
	int nused;
 | 
			
		||||
static struct kprobe trampoline_p = {
 | 
			
		||||
	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
 | 
			
		||||
	.pre_handler = trampoline_probe_handler
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct hlist_head kprobe_insn_pages;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * get_insn_slot() - Find a slot on an executable page for an instruction.
 | 
			
		||||
 * We allocate an executable page if there's no room on existing ones.
 | 
			
		||||
 */
 | 
			
		||||
static kprobe_opcode_t *get_insn_slot(void)
 | 
			
		||||
int __init arch_init(void)
 | 
			
		||||
{
 | 
			
		||||
	struct kprobe_insn_page *kip;
 | 
			
		||||
	struct hlist_node *pos;
 | 
			
		||||
 | 
			
		||||
	hlist_for_each(pos, &kprobe_insn_pages) {
 | 
			
		||||
		kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
 | 
			
		||||
		if (kip->nused < INSNS_PER_PAGE) {
 | 
			
		||||
			int i;
 | 
			
		||||
			for (i = 0; i < INSNS_PER_PAGE; i++) {
 | 
			
		||||
				if (!kip->slot_used[i]) {
 | 
			
		||||
					kip->slot_used[i] = 1;
 | 
			
		||||
					kip->nused++;
 | 
			
		||||
					return kip->insns + (i*MAX_INSN_SIZE);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			/* Surprise!  No unused slots.  Fix kip->nused. */
 | 
			
		||||
			kip->nused = INSNS_PER_PAGE;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* All out of space.  Need to allocate a new page. Use slot 0.*/
 | 
			
		||||
	kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
 | 
			
		||||
	if (!kip) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * For the %rip-relative displacement fixups to be doable, we
 | 
			
		||||
	 * need our instruction copy to be within +/- 2GB of any data it
 | 
			
		||||
	 * might access via %rip.  That is, within 2GB of where the
 | 
			
		||||
	 * kernel image and loaded module images reside.  So we allocate
 | 
			
		||||
	 * a page in the module loading area.
 | 
			
		||||
	 */
 | 
			
		||||
	kip->insns = module_alloc(PAGE_SIZE);
 | 
			
		||||
	if (!kip->insns) {
 | 
			
		||||
		kfree(kip);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	INIT_HLIST_NODE(&kip->hlist);
 | 
			
		||||
	hlist_add_head(&kip->hlist, &kprobe_insn_pages);
 | 
			
		||||
	memset(kip->slot_used, 0, INSNS_PER_PAGE);
 | 
			
		||||
	kip->slot_used[0] = 1;
 | 
			
		||||
	kip->nused = 1;
 | 
			
		||||
	return kip->insns;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * free_insn_slot() - Free instruction slot obtained from get_insn_slot().
 | 
			
		||||
 */
 | 
			
		||||
static void free_insn_slot(kprobe_opcode_t *slot)
 | 
			
		||||
{
 | 
			
		||||
	struct kprobe_insn_page *kip;
 | 
			
		||||
	struct hlist_node *pos;
 | 
			
		||||
 | 
			
		||||
	hlist_for_each(pos, &kprobe_insn_pages) {
 | 
			
		||||
		kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
 | 
			
		||||
		if (kip->insns <= slot
 | 
			
		||||
		    && slot < kip->insns+(INSNS_PER_PAGE*MAX_INSN_SIZE)) {
 | 
			
		||||
			int i = (slot - kip->insns) / MAX_INSN_SIZE;
 | 
			
		||||
			kip->slot_used[i] = 0;
 | 
			
		||||
			kip->nused--;
 | 
			
		||||
			if (kip->nused == 0) {
 | 
			
		||||
				/*
 | 
			
		||||
				 * Page is no longer in use.  Free it unless
 | 
			
		||||
				 * it's the last one.  We keep the last one
 | 
			
		||||
				 * so as not to have to set it up again the
 | 
			
		||||
				 * next time somebody inserts a probe.
 | 
			
		||||
				 */
 | 
			
		||||
				hlist_del(&kip->hlist);
 | 
			
		||||
				if (hlist_empty(&kprobe_insn_pages)) {
 | 
			
		||||
					INIT_HLIST_NODE(&kip->hlist);
 | 
			
		||||
					hlist_add_head(&kip->hlist,
 | 
			
		||||
						&kprobe_insn_pages);
 | 
			
		||||
				} else {
 | 
			
		||||
					module_free(NULL, kip->insns);
 | 
			
		||||
					kfree(kip);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return register_kprobe(&trampoline_p);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -481,6 +481,33 @@ out:
 | 
			
		|||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This function selects if the context switch from prev to next
 | 
			
		||||
 * has to tweak the TSC disable bit in the cr4.
 | 
			
		||||
 */
 | 
			
		||||
static inline void disable_tsc(struct task_struct *prev_p,
 | 
			
		||||
			       struct task_struct *next_p)
 | 
			
		||||
{
 | 
			
		||||
	struct thread_info *prev, *next;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * gcc should eliminate the ->thread_info dereference if
 | 
			
		||||
	 * has_secure_computing returns 0 at compile time (SECCOMP=n).
 | 
			
		||||
	 */
 | 
			
		||||
	prev = prev_p->thread_info;
 | 
			
		||||
	next = next_p->thread_info;
 | 
			
		||||
 | 
			
		||||
	if (has_secure_computing(prev) || has_secure_computing(next)) {
 | 
			
		||||
		/* slow path here */
 | 
			
		||||
		if (has_secure_computing(prev) &&
 | 
			
		||||
		    !has_secure_computing(next)) {
 | 
			
		||||
			write_cr4(read_cr4() & ~X86_CR4_TSD);
 | 
			
		||||
		} else if (!has_secure_computing(prev) &&
 | 
			
		||||
			   has_secure_computing(next))
 | 
			
		||||
			write_cr4(read_cr4() | X86_CR4_TSD);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This special macro can be used to load a debugging register
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -599,6 +626,8 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disable_tsc(prev_p, next_p);
 | 
			
		||||
 | 
			
		||||
	return prev_p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1806,7 +1806,8 @@ static void as_put_request(request_queue_t *q, struct request *rq)
 | 
			
		|||
	rq->elevator_private = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
 | 
			
		||||
static int as_set_request(request_queue_t *q, struct request *rq,
 | 
			
		||||
			  struct bio *bio, int gfp_mask)
 | 
			
		||||
{
 | 
			
		||||
	struct as_data *ad = q->elevator->elevator_data;
 | 
			
		||||
	struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
 | 
			
		||||
| 
						 | 
				
			
			@ -1827,7 +1828,7 @@ static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
 | 
			
		|||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int as_may_queue(request_queue_t *q, int rw)
 | 
			
		||||
static int as_may_queue(request_queue_t *q, int rw, struct bio *bio)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ELV_MQUEUE_MAY;
 | 
			
		||||
	struct as_data *ad = q->elevator->elevator_data;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*
 | 
			
		||||
 *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
 | 
			
		||||
 *    Copyright 2000, 2002 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
 *    Copyright 2000, 2005 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
 *
 | 
			
		||||
 *    This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 *    it under the terms of the GNU General Public License as published by
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +54,7 @@
 | 
			
		|||
MODULE_AUTHOR("Hewlett-Packard Company");
 | 
			
		||||
MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
 | 
			
		||||
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
 | 
			
		||||
			" SA6i P600 P800 E400");
 | 
			
		||||
			" SA6i P600 P800 E400 E300");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
 | 
			
		||||
#include "cciss_cmd.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -85,8 +85,10 @@ static const struct pci_device_id cciss_pci_device_id[] = {
 | 
			
		|||
		0x103C, 0x3225, 0, 0, 0},
 | 
			
		||||
	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
 | 
			
		||||
		0x103c, 0x3223, 0, 0, 0},
 | 
			
		||||
	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
 | 
			
		||||
	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
 | 
			
		||||
		0x103c, 0x3231, 0, 0, 0},
 | 
			
		||||
	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
 | 
			
		||||
		0x103c, 0x3233, 0, 0, 0},
 | 
			
		||||
	{0,}
 | 
			
		||||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 | 
			
		||||
| 
						 | 
				
			
			@ -110,6 +112,7 @@ static struct board_type products[] = {
 | 
			
		|||
	{ 0x3225103C, "Smart Array P600", &SA5_access},
 | 
			
		||||
	{ 0x3223103C, "Smart Array P800", &SA5_access},
 | 
			
		||||
	{ 0x3231103C, "Smart Array E400", &SA5_access},
 | 
			
		||||
	{ 0x3233103C, "Smart Array E300", &SA5_access},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* How long to wait (in millesconds) for board to go into simple mode */
 | 
			
		||||
| 
						 | 
				
			
			@ -635,6 +638,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 | 
			
		|||
		cciss_pci_info_struct pciinfo;
 | 
			
		||||
 | 
			
		||||
		if (!arg) return -EINVAL;
 | 
			
		||||
		pciinfo.domain = pci_domain_nr(host->pdev->bus);
 | 
			
		||||
		pciinfo.bus = host->pdev->bus->number;
 | 
			
		||||
		pciinfo.dev_fn = host->pdev->devfn;
 | 
			
		||||
		pciinfo.board_id = host->board_id;
 | 
			
		||||
| 
						 | 
				
			
			@ -787,13 +791,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 | 
			
		|||
 		luninfo.LunID = drv->LunID;
 | 
			
		||||
 		luninfo.num_opens = drv->usage_count;
 | 
			
		||||
 		luninfo.num_parts = 0;
 | 
			
		||||
 		/* count partitions 1 to 15 with sizes > 0 */
 | 
			
		||||
 		for (i = 0; i < MAX_PART - 1; i++) {
 | 
			
		||||
			if (!disk->part[i])
 | 
			
		||||
				continue;
 | 
			
		||||
			if (disk->part[i]->nr_sects != 0)
 | 
			
		||||
				luninfo.num_parts++;
 | 
			
		||||
		}
 | 
			
		||||
 		if (copy_to_user(argp, &luninfo,
 | 
			
		||||
 				sizeof(LogvolInfo_struct)))
 | 
			
		||||
 			return -EFAULT;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -760,7 +760,8 @@ static void deadline_put_request(request_queue_t *q, struct request *rq)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
deadline_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
 | 
			
		||||
deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
 | 
			
		||||
		     int gfp_mask)
 | 
			
		||||
{
 | 
			
		||||
	struct deadline_data *dd = q->elevator->elevator_data;
 | 
			
		||||
	struct deadline_rq *drq;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -486,12 +486,13 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq)
 | 
			
		|||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
 | 
			
		||||
int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
 | 
			
		||||
		    int gfp_mask)
 | 
			
		||||
{
 | 
			
		||||
	elevator_t *e = q->elevator;
 | 
			
		||||
 | 
			
		||||
	if (e->ops->elevator_set_req_fn)
 | 
			
		||||
		return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
 | 
			
		||||
		return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask);
 | 
			
		||||
 | 
			
		||||
	rq->elevator_private = NULL;
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -505,12 +506,12 @@ void elv_put_request(request_queue_t *q, struct request *rq)
 | 
			
		|||
		e->ops->elevator_put_req_fn(q, rq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elv_may_queue(request_queue_t *q, int rw)
 | 
			
		||||
int elv_may_queue(request_queue_t *q, int rw, struct bio *bio)
 | 
			
		||||
{
 | 
			
		||||
	elevator_t *e = q->elevator;
 | 
			
		||||
 | 
			
		||||
	if (e->ops->elevator_may_queue_fn)
 | 
			
		||||
		return e->ops->elevator_may_queue_fn(q, rw);
 | 
			
		||||
		return e->ops->elevator_may_queue_fn(q, rw, bio);
 | 
			
		||||
 | 
			
		||||
	return ELV_MQUEUE_MAY;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -276,6 +276,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq)
 | 
			
		|||
	rq->errors = 0;
 | 
			
		||||
	rq->rq_status = RQ_ACTIVE;
 | 
			
		||||
	rq->bio = rq->biotail = NULL;
 | 
			
		||||
	rq->ioprio = 0;
 | 
			
		||||
	rq->buffer = NULL;
 | 
			
		||||
	rq->ref_count = 1;
 | 
			
		||||
	rq->q = q;
 | 
			
		||||
| 
						 | 
				
			
			@ -1442,10 +1443,6 @@ void __generic_unplug_device(request_queue_t *q)
 | 
			
		|||
	if (!blk_remove_plug(q))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * was plugged, fire request_fn if queue has stuff to do
 | 
			
		||||
	 */
 | 
			
		||||
	if (elv_next_request(q))
 | 
			
		||||
	q->request_fn(q);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__generic_unplug_device);
 | 
			
		||||
| 
						 | 
				
			
			@ -1776,8 +1773,8 @@ static inline void blk_free_request(request_queue_t *q, struct request *rq)
 | 
			
		|||
	mempool_free(rq, q->rq.rq_pool);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
 | 
			
		||||
						int gfp_mask)
 | 
			
		||||
static inline struct request *
 | 
			
		||||
blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask)
 | 
			
		||||
{
 | 
			
		||||
	struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1790,7 +1787,7 @@ static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
 | 
			
		|||
	 */
 | 
			
		||||
	rq->flags = rw;
 | 
			
		||||
 | 
			
		||||
	if (!elv_set_request(q, rq, gfp_mask))
 | 
			
		||||
	if (!elv_set_request(q, rq, bio, gfp_mask))
 | 
			
		||||
		return rq;
 | 
			
		||||
 | 
			
		||||
	mempool_free(rq, q->rq.rq_pool);
 | 
			
		||||
| 
						 | 
				
			
			@ -1872,7 +1869,8 @@ static void freed_request(request_queue_t *q, int rw)
 | 
			
		|||
/*
 | 
			
		||||
 * Get a free request, queue_lock must not be held
 | 
			
		||||
 */
 | 
			
		||||
static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
 | 
			
		||||
static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
 | 
			
		||||
				   int gfp_mask)
 | 
			
		||||
{
 | 
			
		||||
	struct request *rq = NULL;
 | 
			
		||||
	struct request_list *rl = &q->rq;
 | 
			
		||||
| 
						 | 
				
			
			@ -1895,7 +1893,7 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (elv_may_queue(q, rw)) {
 | 
			
		||||
	switch (elv_may_queue(q, rw, bio)) {
 | 
			
		||||
		case ELV_MQUEUE_NO:
 | 
			
		||||
			goto rq_starved;
 | 
			
		||||
		case ELV_MQUEUE_MAY:
 | 
			
		||||
| 
						 | 
				
			
			@ -1920,7 +1918,7 @@ get_rq:
 | 
			
		|||
		set_queue_congested(q, rw);
 | 
			
		||||
	spin_unlock_irq(q->queue_lock);
 | 
			
		||||
 | 
			
		||||
	rq = blk_alloc_request(q, rw, gfp_mask);
 | 
			
		||||
	rq = blk_alloc_request(q, rw, bio, gfp_mask);
 | 
			
		||||
	if (!rq) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Allocation failed presumably due to memory. Undo anything
 | 
			
		||||
| 
						 | 
				
			
			@ -1961,7 +1959,8 @@ out:
 | 
			
		|||
 * No available requests for this queue, unplug the device and wait for some
 | 
			
		||||
 * requests to become available.
 | 
			
		||||
 */
 | 
			
		||||
static struct request *get_request_wait(request_queue_t *q, int rw)
 | 
			
		||||
static struct request *get_request_wait(request_queue_t *q, int rw,
 | 
			
		||||
					struct bio *bio)
 | 
			
		||||
{
 | 
			
		||||
	DEFINE_WAIT(wait);
 | 
			
		||||
	struct request *rq;
 | 
			
		||||
| 
						 | 
				
			
			@ -1972,7 +1971,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw)
 | 
			
		|||
		prepare_to_wait_exclusive(&rl->wait[rw], &wait,
 | 
			
		||||
				TASK_UNINTERRUPTIBLE);
 | 
			
		||||
 | 
			
		||||
		rq = get_request(q, rw, GFP_NOIO);
 | 
			
		||||
		rq = get_request(q, rw, bio, GFP_NOIO);
 | 
			
		||||
 | 
			
		||||
		if (!rq) {
 | 
			
		||||
			struct io_context *ioc;
 | 
			
		||||
| 
						 | 
				
			
			@ -2003,9 +2002,9 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask)
 | 
			
		|||
	BUG_ON(rw != READ && rw != WRITE);
 | 
			
		||||
 | 
			
		||||
	if (gfp_mask & __GFP_WAIT)
 | 
			
		||||
		rq = get_request_wait(q, rw);
 | 
			
		||||
		rq = get_request_wait(q, rw, NULL);
 | 
			
		||||
	else
 | 
			
		||||
		rq = get_request(q, rw, gfp_mask);
 | 
			
		||||
		rq = get_request(q, rw, NULL, gfp_mask);
 | 
			
		||||
 | 
			
		||||
	return rq;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2333,7 +2332,6 @@ static void __blk_put_request(request_queue_t *q, struct request *req)
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	req->rq_status = RQ_INACTIVE;
 | 
			
		||||
	req->q = NULL;
 | 
			
		||||
	req->rl = NULL;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -2462,6 +2460,8 @@ static int attempt_merge(request_queue_t *q, struct request *req,
 | 
			
		|||
		req->rq_disk->in_flight--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	req->ioprio = ioprio_best(req->ioprio, next->ioprio);
 | 
			
		||||
 | 
			
		||||
	__blk_put_request(q, next);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2514,11 +2514,13 @@ static int __make_request(request_queue_t *q, struct bio *bio)
 | 
			
		|||
{
 | 
			
		||||
	struct request *req, *freereq = NULL;
 | 
			
		||||
	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
 | 
			
		||||
	unsigned short prio;
 | 
			
		||||
	sector_t sector;
 | 
			
		||||
 | 
			
		||||
	sector = bio->bi_sector;
 | 
			
		||||
	nr_sectors = bio_sectors(bio);
 | 
			
		||||
	cur_nr_sectors = bio_cur_sectors(bio);
 | 
			
		||||
	prio = bio_prio(bio);
 | 
			
		||||
 | 
			
		||||
	rw = bio_data_dir(bio);
 | 
			
		||||
	sync = bio_sync(bio);
 | 
			
		||||
| 
						 | 
				
			
			@ -2559,6 +2561,7 @@ again:
 | 
			
		|||
			req->biotail->bi_next = bio;
 | 
			
		||||
			req->biotail = bio;
 | 
			
		||||
			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
 | 
			
		||||
			req->ioprio = ioprio_best(req->ioprio, prio);
 | 
			
		||||
			drive_stat_acct(req, nr_sectors, 0);
 | 
			
		||||
			if (!attempt_back_merge(q, req))
 | 
			
		||||
				elv_merged_request(q, req);
 | 
			
		||||
| 
						 | 
				
			
			@ -2583,6 +2586,7 @@ again:
 | 
			
		|||
			req->hard_cur_sectors = cur_nr_sectors;
 | 
			
		||||
			req->sector = req->hard_sector = sector;
 | 
			
		||||
			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
 | 
			
		||||
			req->ioprio = ioprio_best(req->ioprio, prio);
 | 
			
		||||
			drive_stat_acct(req, nr_sectors, 0);
 | 
			
		||||
			if (!attempt_front_merge(q, req))
 | 
			
		||||
				elv_merged_request(q, req);
 | 
			
		||||
| 
						 | 
				
			
			@ -2610,7 +2614,7 @@ get_rq:
 | 
			
		|||
		freereq = NULL;
 | 
			
		||||
	} else {
 | 
			
		||||
		spin_unlock_irq(q->queue_lock);
 | 
			
		||||
		if ((freereq = get_request(q, rw, GFP_ATOMIC)) == NULL) {
 | 
			
		||||
		if ((freereq = get_request(q, rw, bio, GFP_ATOMIC)) == NULL) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * READA bit set
 | 
			
		||||
			 */
 | 
			
		||||
| 
						 | 
				
			
			@ -2618,7 +2622,7 @@ get_rq:
 | 
			
		|||
			if (bio_rw_ahead(bio))
 | 
			
		||||
				goto end_io;
 | 
			
		||||
	
 | 
			
		||||
			freereq = get_request_wait(q, rw);
 | 
			
		||||
			freereq = get_request_wait(q, rw, bio);
 | 
			
		||||
		}
 | 
			
		||||
		goto again;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2646,6 +2650,7 @@ get_rq:
 | 
			
		|||
	req->buffer = bio_data(bio);	/* see ->buffer comment above */
 | 
			
		||||
	req->waiting = NULL;
 | 
			
		||||
	req->bio = req->biotail = bio;
 | 
			
		||||
	req->ioprio = prio;
 | 
			
		||||
	req->rq_disk = bio->bi_bdev->bd_disk;
 | 
			
		||||
	req->start_time = jiffies;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2674,7 +2679,7 @@ static inline void blk_partition_remap(struct bio *bio)
 | 
			
		|||
	if (bdev != bdev->bd_contains) {
 | 
			
		||||
		struct hd_struct *p = bdev->bd_part;
 | 
			
		||||
 | 
			
		||||
		switch (bio->bi_rw) {
 | 
			
		||||
		switch (bio_data_dir(bio)) {
 | 
			
		||||
		case READ:
 | 
			
		||||
			p->read_sectors += bio_sectors(bio);
 | 
			
		||||
			p->reads++;
 | 
			
		||||
| 
						 | 
				
			
			@ -2693,6 +2698,7 @@ void blk_finish_queue_drain(request_queue_t *q)
 | 
			
		|||
{
 | 
			
		||||
	struct request_list *rl = &q->rq;
 | 
			
		||||
	struct request *rq;
 | 
			
		||||
	int requeued = 0;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irq(q->queue_lock);
 | 
			
		||||
	clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags);
 | 
			
		||||
| 
						 | 
				
			
			@ -2701,9 +2707,13 @@ void blk_finish_queue_drain(request_queue_t *q)
 | 
			
		|||
		rq = list_entry_rq(q->drain_list.next);
 | 
			
		||||
 | 
			
		||||
		list_del_init(&rq->queuelist);
 | 
			
		||||
		__elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
 | 
			
		||||
		elv_requeue_request(q, rq);
 | 
			
		||||
		requeued++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (requeued)
 | 
			
		||||
		q->request_fn(q);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irq(q->queue_lock);
 | 
			
		||||
 | 
			
		||||
	wake_up(&rl->wait[0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -2900,7 +2910,7 @@ void submit_bio(int rw, struct bio *bio)
 | 
			
		|||
 | 
			
		||||
	BIO_BUG_ON(!bio->bi_size);
 | 
			
		||||
	BIO_BUG_ON(!bio->bi_io_vec);
 | 
			
		||||
	bio->bi_rw = rw;
 | 
			
		||||
	bio->bi_rw |= rw;
 | 
			
		||||
	if (rw & WRITE)
 | 
			
		||||
		mod_page_state(pgpgout, count);
 | 
			
		||||
	else
 | 
			
		||||
| 
						 | 
				
			
			@ -3257,8 +3267,11 @@ void exit_io_context(void)
 | 
			
		|||
	struct io_context *ioc;
 | 
			
		||||
 | 
			
		||||
	local_irq_save(flags);
 | 
			
		||||
	task_lock(current);
 | 
			
		||||
	ioc = current->io_context;
 | 
			
		||||
	current->io_context = NULL;
 | 
			
		||||
	ioc->task = NULL;
 | 
			
		||||
	task_unlock(current);
 | 
			
		||||
	local_irq_restore(flags);
 | 
			
		||||
 | 
			
		||||
	if (ioc->aic && ioc->aic->exit)
 | 
			
		||||
| 
						 | 
				
			
			@ -3293,12 +3306,12 @@ struct io_context *get_io_context(int gfp_flags)
 | 
			
		|||
	ret = kmem_cache_alloc(iocontext_cachep, gfp_flags);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		atomic_set(&ret->refcount, 1);
 | 
			
		||||
		ret->pid = tsk->pid;
 | 
			
		||||
		ret->task = current;
 | 
			
		||||
		ret->set_ioprio = NULL;
 | 
			
		||||
		ret->last_waited = jiffies; /* doesn't matter... */
 | 
			
		||||
		ret->nr_batch_requests = 0; /* because this is 0 */
 | 
			
		||||
		ret->aic = NULL;
 | 
			
		||||
		ret->cic = NULL;
 | 
			
		||||
		spin_lock_init(&ret->lock);
 | 
			
		||||
 | 
			
		||||
		local_irq_save(flags);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -253,7 +253,7 @@ static int floppy_revalidate(struct gendisk *disk);
 | 
			
		|||
static int swim3_add_device(struct device_node *swims);
 | 
			
		||||
int swim3_init(void);
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifndef CONFIG_PMAC_MEDIABAY
 | 
			
		||||
#define check_media_bay(which, what)	1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -297,9 +297,11 @@ static void do_fd_request(request_queue_t * q)
 | 
			
		|||
	int i;
 | 
			
		||||
	for(i=0;i<floppy_count;i++)
 | 
			
		||||
	{
 | 
			
		||||
#ifdef CONFIG_PMAC_MEDIABAY
 | 
			
		||||
		if (floppy_states[i].media_bay &&
 | 
			
		||||
			check_media_bay(floppy_states[i].media_bay, MB_FD))
 | 
			
		||||
			continue;
 | 
			
		||||
#endif /* CONFIG_PMAC_MEDIABAY */
 | 
			
		||||
		start_request(&floppy_states[i]);
 | 
			
		||||
	}
 | 
			
		||||
	sti();
 | 
			
		||||
| 
						 | 
				
			
			@ -856,8 +858,10 @@ static int floppy_ioctl(struct inode *inode, struct file *filp,
 | 
			
		|||
	if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
 | 
			
		||||
		return -EPERM;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_MEDIABAY
 | 
			
		||||
	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 | 
			
		||||
		return -ENXIO;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	switch (cmd) {
 | 
			
		||||
	case FDEJECT:
 | 
			
		||||
| 
						 | 
				
			
			@ -881,8 +885,10 @@ static int floppy_open(struct inode *inode, struct file *filp)
 | 
			
		|||
	int n, err = 0;
 | 
			
		||||
 | 
			
		||||
	if (fs->ref_count == 0) {
 | 
			
		||||
#ifdef CONFIG_PMAC_MEDIABAY
 | 
			
		||||
		if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 | 
			
		||||
			return -ENXIO;
 | 
			
		||||
#endif
 | 
			
		||||
		out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
 | 
			
		||||
		out_8(&sw->control_bic, 0xff);
 | 
			
		||||
		out_8(&sw->mode, 0x95);
 | 
			
		||||
| 
						 | 
				
			
			@ -967,8 +973,10 @@ static int floppy_revalidate(struct gendisk *disk)
 | 
			
		|||
	struct swim3 __iomem *sw;
 | 
			
		||||
	int ret, n;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_MEDIABAY
 | 
			
		||||
	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 | 
			
		||||
		return -ENXIO;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	sw = fs->swim3;
 | 
			
		||||
	grab_drive(fs, revalidating, 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@
 | 
			
		|||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/time.h>
 | 
			
		||||
#include <linux/hdreg.h>
 | 
			
		||||
#include <linux/dma-mapping.h>
 | 
			
		||||
#include <asm/io.h>
 | 
			
		||||
#include <asm/semaphore.h>
 | 
			
		||||
#include <asm/uaccess.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -1582,9 +1583,9 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 | 
			
		|||
		goto err_out;
 | 
			
		||||
 | 
			
		||||
#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
 | 
			
		||||
	rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
 | 
			
		||||
	rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
 | 
			
		||||
	if (!rc) {
 | 
			
		||||
		rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
 | 
			
		||||
		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
 | 
			
		||||
		if (rc) {
 | 
			
		||||
			printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
 | 
			
		||||
				pci_name(pdev));
 | 
			
		||||
| 
						 | 
				
			
			@ -1593,7 +1594,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 | 
			
		|||
		pci_dac = 1;
 | 
			
		||||
	} else {
 | 
			
		||||
#endif
 | 
			
		||||
		rc = pci_set_dma_mask(pdev, 0xffffffffULL);
 | 
			
		||||
		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 | 
			
		||||
		if (rc) {
 | 
			
		||||
			printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
 | 
			
		||||
				pci_name(pdev));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -308,9 +308,6 @@ static int __init misc_init(void)
 | 
			
		|||
#endif
 | 
			
		||||
#ifdef CONFIG_BVME6000
 | 
			
		||||
	rtc_DP8570A_init();
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
	pmu_device_init();
 | 
			
		||||
#endif
 | 
			
		||||
	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 | 
			
		||||
		printk("unable to get major %d for misc devices\n",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1324,9 +1324,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 | 
			
		|||
	/* XXX FIXME: Media bay stuff need re-organizing */
 | 
			
		||||
	if (np->parent && np->parent->name
 | 
			
		||||
	    && strcasecmp(np->parent->name, "media-bay") == 0) {
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PMAC_MEDIABAY
 | 
			
		||||
		media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index);
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif /* CONFIG_PMAC_MEDIABAY */
 | 
			
		||||
		pmif->mediabay = 1;
 | 
			
		||||
		if (!bidp)
 | 
			
		||||
			pmif->aapl_bus_id = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -1382,10 +1382,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 | 
			
		|||
	       hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
 | 
			
		||||
	       pmif->mediabay ? " (mediabay)" : "", hwif->irq);
 | 
			
		||||
			
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PMAC_MEDIABAY
 | 
			
		||||
	if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
 | 
			
		||||
		hwif->noprobe = 0;
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif /* CONFIG_PMAC_MEDIABAY */
 | 
			
		||||
 | 
			
		||||
	hwif->sg_max_nents = MAX_DCMDS;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3538,8 +3538,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
 | 
			
		|||
 | 
			
		||||
static int ohci1394_pci_resume (struct pci_dev *pdev)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
	{
 | 
			
		||||
#ifdef CONFIG_PPC_PMAC
 | 
			
		||||
	if (_machine == _MACH_Pmac) {
 | 
			
		||||
		struct device_node *of_node;
 | 
			
		||||
 | 
			
		||||
		/* Re-enable 1394 */
 | 
			
		||||
| 
						 | 
				
			
			@ -3547,7 +3547,7 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
 | 
			
		|||
		if (of_node)
 | 
			
		||||
			pmac_call_feature (PMAC_FTR_1394_ENABLE, of_node, 0, 1);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* CONFIG_PPC_PMAC */
 | 
			
		||||
 | 
			
		||||
	pci_enable_device(pdev);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3557,8 +3557,8 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
 | 
			
		|||
 | 
			
		||||
static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
	{
 | 
			
		||||
#ifdef CONFIG_PPC_PMAC
 | 
			
		||||
	if (_machine == _MACH_Pmac) {
 | 
			
		||||
		struct device_node *of_node;
 | 
			
		||||
 | 
			
		||||
		/* Disable 1394 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,7 +96,7 @@ void ib_pack(const struct ib_field        *desc,
 | 
			
		|||
			else
 | 
			
		||||
				val = 0;
 | 
			
		||||
 | 
			
		||||
			mask = cpu_to_be64(((1ull << desc[i].size_bits) - 1) << shift);
 | 
			
		||||
			mask = cpu_to_be64((~0ull >> (64 - desc[i].size_bits)) << shift);
 | 
			
		||||
			addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words);
 | 
			
		||||
			*addr = (*addr & ~mask) | (cpu_to_be64(val) & mask);
 | 
			
		||||
		} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +176,7 @@ void ib_unpack(const struct ib_field        *desc,
 | 
			
		|||
			__be64 *addr;
 | 
			
		||||
 | 
			
		||||
			shift = 64 - desc[i].offset_bits - desc[i].size_bits;
 | 
			
		||||
			mask = ((1ull << desc[i].size_bits) - 1) << shift;
 | 
			
		||||
			mask = (~0ull >> (64 - desc[i].size_bits)) << shift;
 | 
			
		||||
			addr = (__be64 *) buf + desc[i].offset_words;
 | 
			
		||||
			val = (be64_to_cpup(addr) & mask) >> shift;
 | 
			
		||||
			value_write(desc[i].struct_offset_bytes,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -507,7 +507,13 @@ retry:
 | 
			
		|||
		spin_unlock_irqrestore(&idr_lock, flags);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
	/*
 | 
			
		||||
	 * It's not safe to dereference query any more, because the
 | 
			
		||||
	 * send may already have completed and freed the query in
 | 
			
		||||
	 * another context.  So use wr.wr_id, which has a copy of the
 | 
			
		||||
	 * query's id.
 | 
			
		||||
	 */
 | 
			
		||||
	return ret ? ret : wr.wr_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
 | 
			
		||||
| 
						 | 
				
			
			@ -598,14 +604,15 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
 | 
			
		|||
		rec, query->sa_query.mad->data);
 | 
			
		||||
 | 
			
		||||
	*sa_query = &query->sa_query;
 | 
			
		||||
 | 
			
		||||
	ret = send_mad(&query->sa_query, timeout_ms);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		*sa_query = NULL;
 | 
			
		||||
		kfree(query->sa_query.mad);
 | 
			
		||||
		kfree(query);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret ? ret : query->sa_query.id;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(ib_sa_path_rec_get);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -674,14 +681,15 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
 | 
			
		|||
		rec, query->sa_query.mad->data);
 | 
			
		||||
 | 
			
		||||
	*sa_query = &query->sa_query;
 | 
			
		||||
 | 
			
		||||
	ret = send_mad(&query->sa_query, timeout_ms);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		*sa_query = NULL;
 | 
			
		||||
		kfree(query->sa_query.mad);
 | 
			
		||||
		kfree(query);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret ? ret : query->sa_query.id;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2004 Topspin Communications.  All rights reserved.
 | 
			
		||||
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software is available to you under a choice of one of two
 | 
			
		||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -431,6 +431,36 @@ static int mthca_cmd_imm(struct mthca_dev *dev,
 | 
			
		|||
				      timeout, status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_cmd_init(struct mthca_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	sema_init(&dev->cmd.hcr_sem, 1);
 | 
			
		||||
	sema_init(&dev->cmd.poll_sem, 1);
 | 
			
		||||
	dev->cmd.use_events = 0;
 | 
			
		||||
 | 
			
		||||
	dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
 | 
			
		||||
			   MTHCA_HCR_SIZE);
 | 
			
		||||
	if (!dev->hcr) {
 | 
			
		||||
		mthca_err(dev, "Couldn't map command register.");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev->cmd.pool = pci_pool_create("mthca_cmd", dev->pdev,
 | 
			
		||||
					MTHCA_MAILBOX_SIZE,
 | 
			
		||||
					MTHCA_MAILBOX_SIZE, 0);
 | 
			
		||||
	if (!dev->cmd.pool) {
 | 
			
		||||
		iounmap(dev->hcr);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mthca_cmd_cleanup(struct mthca_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	pci_pool_destroy(dev->cmd.pool);
 | 
			
		||||
	iounmap(dev->hcr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Switch to using events to issue FW commands (should be called after
 | 
			
		||||
 * event queue to command events has been initialized).
 | 
			
		||||
| 
						 | 
				
			
			@ -489,6 +519,33 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
 | 
			
		|||
	up(&dev->cmd.poll_sem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
 | 
			
		||||
					  unsigned int gfp_mask)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof *mailbox, gfp_mask);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	mailbox->buf = pci_pool_alloc(dev->cmd.pool, gfp_mask, &mailbox->dma);
 | 
			
		||||
	if (!mailbox->buf) {
 | 
			
		||||
		kfree(mailbox);
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return mailbox;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox)
 | 
			
		||||
{
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma);
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_SYS_EN(struct mthca_dev *dev, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	u64 out;
 | 
			
		||||
| 
						 | 
				
			
			@ -513,20 +570,20 @@ int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status)
 | 
			
		|||
static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 | 
			
		||||
			 u64 virt, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	u32 *inbox;
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	struct mthca_icm_iter iter;
 | 
			
		||||
	__be64 *pages;
 | 
			
		||||
	int lg;
 | 
			
		||||
	int nent = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	int ts = 0, tc = 0;
 | 
			
		||||
 | 
			
		||||
	inbox = pci_alloc_consistent(dev->pdev, PAGE_SIZE, &indma);
 | 
			
		||||
	if (!inbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	memset(inbox, 0, PAGE_SIZE);
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	memset(mailbox->buf, 0, MTHCA_MAILBOX_SIZE);
 | 
			
		||||
	pages = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	for (mthca_icm_first(icm, &iter);
 | 
			
		||||
	     !mthca_icm_last(&iter);
 | 
			
		||||
| 
						 | 
				
			
			@ -546,19 +603,17 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 | 
			
		|||
		}
 | 
			
		||||
		for (i = 0; i < mthca_icm_size(&iter) / (1 << lg); ++i, ++nent) {
 | 
			
		||||
			if (virt != -1) {
 | 
			
		||||
				*((__be64 *) (inbox + nent * 4)) =
 | 
			
		||||
					cpu_to_be64(virt);
 | 
			
		||||
				pages[nent * 2] = cpu_to_be64(virt);
 | 
			
		||||
				virt += 1 << lg;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			*((__be64 *) (inbox + nent * 4 + 2)) =
 | 
			
		||||
				cpu_to_be64((mthca_icm_addr(&iter) +
 | 
			
		||||
			pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
 | 
			
		||||
							   (i << lg)) | (lg - 12));
 | 
			
		||||
			ts += 1 << (lg - 10);
 | 
			
		||||
			++tc;
 | 
			
		||||
 | 
			
		||||
			if (nent == PAGE_SIZE / 16) {
 | 
			
		||||
				err = mthca_cmd(dev, indma, nent, 0, op,
 | 
			
		||||
			if (nent == MTHCA_MAILBOX_SIZE / 16) {
 | 
			
		||||
				err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
 | 
			
		||||
						CMD_TIME_CLASS_B, status);
 | 
			
		||||
				if (err || *status)
 | 
			
		||||
					goto out;
 | 
			
		||||
| 
						 | 
				
			
			@ -568,7 +623,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (nent)
 | 
			
		||||
		err = mthca_cmd(dev, indma, nent, 0, op,
 | 
			
		||||
		err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
 | 
			
		||||
				CMD_TIME_CLASS_B, status);
 | 
			
		||||
 | 
			
		||||
	switch (op) {
 | 
			
		||||
| 
						 | 
				
			
			@ -585,7 +640,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	pci_free_consistent(dev->pdev, PAGE_SIZE, inbox, indma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -606,8 +661,8 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
 | 
			
		|||
 | 
			
		||||
int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u32 *outbox;
 | 
			
		||||
	dma_addr_t outdma;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	u8 lg;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -625,12 +680,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 | 
			
		|||
#define QUERY_FW_EQ_ARM_BASE_OFFSET    0x40
 | 
			
		||||
#define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48
 | 
			
		||||
 | 
			
		||||
	outbox = pci_alloc_consistent(dev->pdev, QUERY_FW_OUT_SIZE, &outdma);
 | 
			
		||||
	if (!outbox) {
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	outbox = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_FW,
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_FW,
 | 
			
		||||
			    CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -681,15 +736,15 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	pci_free_consistent(dev->pdev, QUERY_FW_OUT_SIZE, outbox, outdma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u8 info;
 | 
			
		||||
	u32 *outbox;
 | 
			
		||||
	dma_addr_t outdma;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
#define ENABLE_LAM_OUT_SIZE         0x100
 | 
			
		||||
| 
						 | 
				
			
			@ -700,11 +755,12 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 | 
			
		|||
#define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4)
 | 
			
		||||
#define ENABLE_LAM_INFO_ECC_MASK    0x3
 | 
			
		||||
 | 
			
		||||
	outbox = pci_alloc_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, &outdma);
 | 
			
		||||
	if (!outbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	outbox = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_ENABLE_LAM,
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_ENABLE_LAM,
 | 
			
		||||
			    CMD_TIME_CLASS_C, status);
 | 
			
		||||
 | 
			
		||||
	if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -733,7 +789,7 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 | 
			
		|||
		  (unsigned long long) dev->ddr_end);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	pci_free_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, outbox, outdma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -744,9 +800,9 @@ int mthca_DISABLE_LAM(struct mthca_dev *dev, u8 *status)
 | 
			
		|||
 | 
			
		||||
int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u8 info;
 | 
			
		||||
	u32 *outbox;
 | 
			
		||||
	dma_addr_t outdma;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
#define QUERY_DDR_OUT_SIZE         0x100
 | 
			
		||||
| 
						 | 
				
			
			@ -757,11 +813,12 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 | 
			
		|||
#define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4)
 | 
			
		||||
#define QUERY_DDR_INFO_ECC_MASK    0x3
 | 
			
		||||
 | 
			
		||||
	outbox = pci_alloc_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, &outdma);
 | 
			
		||||
	if (!outbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	outbox = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DDR,
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DDR,
 | 
			
		||||
			    CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -787,15 +844,15 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 | 
			
		|||
		  (unsigned long long) dev->ddr_end);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	pci_free_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, outbox, outdma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 | 
			
		||||
			struct mthca_dev_lim *dev_lim, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u32 *outbox;
 | 
			
		||||
	dma_addr_t outdma;
 | 
			
		||||
	u8 field;
 | 
			
		||||
	u16 size;
 | 
			
		||||
	int err;
 | 
			
		||||
| 
						 | 
				
			
			@ -860,11 +917,12 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 | 
			
		|||
#define QUERY_DEV_LIM_LAMR_OFFSET           0x9f
 | 
			
		||||
#define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET     0xa0
 | 
			
		||||
 | 
			
		||||
	outbox = pci_alloc_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, &outdma);
 | 
			
		||||
	if (!outbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	outbox = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DEV_LIM,
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DEV_LIM,
 | 
			
		||||
			    CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -1020,15 +1078,15 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
 | 
			
		||||
			struct mthca_adapter *adapter, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u32 *outbox;
 | 
			
		||||
	dma_addr_t outdma;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
#define QUERY_ADAPTER_OUT_SIZE             0x100
 | 
			
		||||
| 
						 | 
				
			
			@ -1037,11 +1095,12 @@ int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
 | 
			
		|||
#define QUERY_ADAPTER_REVISION_ID_OFFSET   0x08
 | 
			
		||||
#define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
 | 
			
		||||
 | 
			
		||||
	outbox = pci_alloc_consistent(dev->pdev, QUERY_ADAPTER_OUT_SIZE, &outdma);
 | 
			
		||||
	if (!outbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	outbox = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_ADAPTER,
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_ADAPTER,
 | 
			
		||||
			    CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -1053,7 +1112,7 @@ int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
 | 
			
		|||
	MTHCA_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1061,8 +1120,8 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
 | 
			
		|||
		   struct mthca_init_hca_param *param,
 | 
			
		||||
		   u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u32 *inbox;
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
#define INIT_HCA_IN_SIZE             	 0x200
 | 
			
		||||
| 
						 | 
				
			
			@ -1102,9 +1161,10 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
 | 
			
		|||
#define  INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10)
 | 
			
		||||
#define  INIT_HCA_UAR_CTX_BASE_OFFSET    (INIT_HCA_UAR_OFFSET + 0x18)
 | 
			
		||||
 | 
			
		||||
	inbox = pci_alloc_consistent(dev->pdev, INIT_HCA_IN_SIZE, &indma);
 | 
			
		||||
	if (!inbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	inbox = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	memset(inbox, 0, INIT_HCA_IN_SIZE);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1167,10 +1227,9 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
 | 
			
		|||
		MTHCA_PUT(inbox, param->uarc_base,   INIT_HCA_UAR_CTX_BASE_OFFSET);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd(dev, indma, 0, 0, CMD_INIT_HCA,
 | 
			
		||||
			HZ, status);
 | 
			
		||||
	err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, HZ, status);
 | 
			
		||||
 | 
			
		||||
	pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1178,8 +1237,8 @@ int mthca_INIT_IB(struct mthca_dev *dev,
 | 
			
		|||
		  struct mthca_init_ib_param *param,
 | 
			
		||||
		  int port, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u32 *inbox;
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int err;
 | 
			
		||||
	u32 flags;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1199,9 +1258,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
 | 
			
		|||
#define INIT_IB_NODE_GUID_OFFSET 0x18
 | 
			
		||||
#define INIT_IB_SI_GUID_OFFSET   0x20
 | 
			
		||||
 | 
			
		||||
	inbox = pci_alloc_consistent(dev->pdev, INIT_IB_IN_SIZE, &indma);
 | 
			
		||||
	if (!inbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	inbox = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	memset(inbox, 0, INIT_IB_IN_SIZE);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1221,10 +1281,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
 | 
			
		|||
	MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET);
 | 
			
		||||
	MTHCA_PUT(inbox, param->si_guid,   INIT_IB_SI_GUID_OFFSET);
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd(dev, indma, port, 0, CMD_INIT_IB,
 | 
			
		||||
	err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_INIT_IB,
 | 
			
		||||
			CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1241,8 +1301,8 @@ int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status)
 | 
			
		|||
int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
 | 
			
		||||
		 int port, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u32 *inbox;
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int err;
 | 
			
		||||
	u32 flags = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1253,9 +1313,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
 | 
			
		|||
#define SET_IB_CAP_MASK_OFFSET 0x04
 | 
			
		||||
#define SET_IB_SI_GUID_OFFSET  0x08
 | 
			
		||||
 | 
			
		||||
	inbox = pci_alloc_consistent(dev->pdev, SET_IB_IN_SIZE, &indma);
 | 
			
		||||
	if (!inbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	inbox = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	memset(inbox, 0, SET_IB_IN_SIZE);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1266,10 +1327,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
 | 
			
		|||
	MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET);
 | 
			
		||||
	MTHCA_PUT(inbox, param->si_guid,  SET_IB_SI_GUID_OFFSET);
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd(dev, indma, port, 0, CMD_SET_IB,
 | 
			
		||||
	err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_SET_IB,
 | 
			
		||||
			CMD_TIME_CLASS_B, status);
 | 
			
		||||
 | 
			
		||||
	pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1280,20 +1341,22 @@ int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *st
 | 
			
		|||
 | 
			
		||||
int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u64 *inbox;
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	inbox = pci_alloc_consistent(dev->pdev, 16, &indma);
 | 
			
		||||
	if (!inbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	inbox = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	inbox[0] = cpu_to_be64(virt);
 | 
			
		||||
	inbox[1] = cpu_to_be64(dma_addr);
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd(dev, indma, 1, 0, CMD_MAP_ICM, CMD_TIME_CLASS_B, status);
 | 
			
		||||
	err = mthca_cmd(dev, mailbox->dma, 1, 0, CMD_MAP_ICM,
 | 
			
		||||
			CMD_TIME_CLASS_B, status);
 | 
			
		||||
 | 
			
		||||
	pci_free_consistent(dev->pdev, 16, inbox, indma);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
 | 
			
		||||
	if (!err)
 | 
			
		||||
		mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
 | 
			
		||||
| 
						 | 
				
			
			@ -1338,69 +1401,26 @@ int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
 | 
			
		||||
int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		    int mpt_index, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	indma = pci_map_single(dev->pdev, mpt_entry,
 | 
			
		||||
			       MTHCA_MPT_ENTRY_SIZE,
 | 
			
		||||
			       PCI_DMA_TODEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(indma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd(dev, indma, mpt_index, 0, CMD_SW2HW_MPT,
 | 
			
		||||
	return mthca_cmd(dev, mailbox->dma, mpt_index, 0, CMD_SW2HW_MPT,
 | 
			
		||||
			 CMD_TIME_CLASS_B, status);
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, indma,
 | 
			
		||||
			 MTHCA_MPT_ENTRY_SIZE, PCI_DMA_TODEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
 | 
			
		||||
int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		    int mpt_index, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t outdma = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (mpt_entry) {
 | 
			
		||||
		outdma = pci_map_single(dev->pdev, mpt_entry,
 | 
			
		||||
					MTHCA_MPT_ENTRY_SIZE,
 | 
			
		||||
					PCI_DMA_FROMDEVICE);
 | 
			
		||||
		if (pci_dma_mapping_error(outdma))
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, mpt_index, !mpt_entry,
 | 
			
		||||
			    CMD_HW2SW_MPT,
 | 
			
		||||
	return mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index,
 | 
			
		||||
			     !mailbox, CMD_HW2SW_MPT,
 | 
			
		||||
			     CMD_TIME_CLASS_B, status);
 | 
			
		||||
 | 
			
		||||
	if (mpt_entry)
 | 
			
		||||
		pci_unmap_single(dev->pdev, outdma,
 | 
			
		||||
				 MTHCA_MPT_ENTRY_SIZE,
 | 
			
		||||
				 PCI_DMA_FROMDEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
 | 
			
		||||
int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		    int num_mtt, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	indma = pci_map_single(dev->pdev, mtt_entry,
 | 
			
		||||
			       (num_mtt + 2) * 8,
 | 
			
		||||
			       PCI_DMA_TODEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(indma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd(dev, indma, num_mtt, 0, CMD_WRITE_MTT,
 | 
			
		||||
	return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT,
 | 
			
		||||
			 CMD_TIME_CLASS_B, status);
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, indma,
 | 
			
		||||
			 (num_mtt + 2) * 8, PCI_DMA_TODEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status)
 | 
			
		||||
| 
						 | 
				
			
			@ -1418,92 +1438,38 @@ int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
 | 
			
		|||
			 0, CMD_MAP_EQ, CMD_TIME_CLASS_B, status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
 | 
			
		||||
int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		   int eq_num, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	indma = pci_map_single(dev->pdev, eq_context,
 | 
			
		||||
			       MTHCA_EQ_CONTEXT_SIZE,
 | 
			
		||||
			       PCI_DMA_TODEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(indma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd(dev, indma, eq_num, 0, CMD_SW2HW_EQ,
 | 
			
		||||
	return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ,
 | 
			
		||||
			 CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, indma,
 | 
			
		||||
			 MTHCA_EQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
 | 
			
		||||
int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		   int eq_num, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t outdma = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	outdma = pci_map_single(dev->pdev, eq_context,
 | 
			
		||||
				MTHCA_EQ_CONTEXT_SIZE,
 | 
			
		||||
				PCI_DMA_FROMDEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(outdma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, eq_num, 0,
 | 
			
		||||
	return mthca_cmd_box(dev, 0, mailbox->dma, eq_num, 0,
 | 
			
		||||
			     CMD_HW2SW_EQ,
 | 
			
		||||
			     CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, outdma,
 | 
			
		||||
			 MTHCA_EQ_CONTEXT_SIZE,
 | 
			
		||||
			 PCI_DMA_FROMDEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
 | 
			
		||||
int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		   int cq_num, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	indma = pci_map_single(dev->pdev, cq_context,
 | 
			
		||||
			       MTHCA_CQ_CONTEXT_SIZE,
 | 
			
		||||
			       PCI_DMA_TODEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(indma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd(dev, indma, cq_num, 0, CMD_SW2HW_CQ,
 | 
			
		||||
	return mthca_cmd(dev, mailbox->dma, cq_num, 0, CMD_SW2HW_CQ,
 | 
			
		||||
			CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, indma,
 | 
			
		||||
			 MTHCA_CQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
 | 
			
		||||
int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		   int cq_num, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t outdma = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	outdma = pci_map_single(dev->pdev, cq_context,
 | 
			
		||||
				MTHCA_CQ_CONTEXT_SIZE,
 | 
			
		||||
				PCI_DMA_FROMDEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(outdma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, cq_num, 0,
 | 
			
		||||
	return mthca_cmd_box(dev, 0, mailbox->dma, cq_num, 0,
 | 
			
		||||
			     CMD_HW2SW_CQ,
 | 
			
		||||
			     CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, outdma,
 | 
			
		||||
			 MTHCA_CQ_CONTEXT_SIZE,
 | 
			
		||||
			 PCI_DMA_FROMDEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
			
		||||
		    int is_ee, void *qp_context, u32 optmask,
 | 
			
		||||
		    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
 | 
			
		||||
		    u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	static const u16 op[] = {
 | 
			
		||||
| 
						 | 
				
			
			@ -1520,36 +1486,34 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
			
		|||
		[MTHCA_TRANS_ANY2RST]   = CMD_ERR2RST_QPEE
 | 
			
		||||
	};
 | 
			
		||||
	u8 op_mod = 0;
 | 
			
		||||
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int my_mailbox = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (trans < 0 || trans >= ARRAY_SIZE(op))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (trans == MTHCA_TRANS_ANY2RST) {
 | 
			
		||||
		indma  = 0;
 | 
			
		||||
		op_mod = 3;	/* don't write outbox, any->reset */
 | 
			
		||||
 | 
			
		||||
		/* For debugging */
 | 
			
		||||
		qp_context = pci_alloc_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
 | 
			
		||||
						  &indma);
 | 
			
		||||
		if (!mailbox) {
 | 
			
		||||
			mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
			if (!IS_ERR(mailbox)) {
 | 
			
		||||
				my_mailbox = 1;
 | 
			
		||||
				op_mod     = 2;	/* write outbox, any->reset */
 | 
			
		||||
			} else
 | 
			
		||||
				mailbox = NULL;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		indma = pci_map_single(dev->pdev, qp_context,
 | 
			
		||||
				       MTHCA_QP_CONTEXT_SIZE,
 | 
			
		||||
				       PCI_DMA_TODEVICE);
 | 
			
		||||
		if (pci_dma_mapping_error(indma))
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		if (0) {
 | 
			
		||||
			int i;
 | 
			
		||||
			mthca_dbg(dev, "Dumping QP context:\n");
 | 
			
		||||
			printk("  opt param mask: %08x\n", be32_to_cpup(qp_context));
 | 
			
		||||
			printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
 | 
			
		||||
			for (i = 0; i < 0x100 / 4; ++i) {
 | 
			
		||||
				if (i % 8 == 0)
 | 
			
		||||
					printk("  [%02x] ", i * 4);
 | 
			
		||||
				printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
 | 
			
		||||
				printk(" %08x",
 | 
			
		||||
				       be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
 | 
			
		||||
				if ((i + 1) % 8 == 0)
 | 
			
		||||
					printk("\n");
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -1557,55 +1521,39 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (trans == MTHCA_TRANS_ANY2RST) {
 | 
			
		||||
		err = mthca_cmd_box(dev, 0, indma, (!!is_ee << 24) | num,
 | 
			
		||||
				    op_mod, op[trans], CMD_TIME_CLASS_C, status);
 | 
			
		||||
		err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
 | 
			
		||||
				    (!!is_ee << 24) | num, op_mod,
 | 
			
		||||
				    op[trans], CMD_TIME_CLASS_C, status);
 | 
			
		||||
 | 
			
		||||
		if (0) {
 | 
			
		||||
		if (0 && mailbox) {
 | 
			
		||||
			int i;
 | 
			
		||||
			mthca_dbg(dev, "Dumping QP context:\n");
 | 
			
		||||
			printk(" %08x\n", be32_to_cpup(qp_context));
 | 
			
		||||
			printk(" %08x\n", be32_to_cpup(mailbox->buf));
 | 
			
		||||
			for (i = 0; i < 0x100 / 4; ++i) {
 | 
			
		||||
				if (i % 8 == 0)
 | 
			
		||||
					printk("[%02x] ", i * 4);
 | 
			
		||||
				printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
 | 
			
		||||
				printk(" %08x",
 | 
			
		||||
				       be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
 | 
			
		||||
				if ((i + 1) % 8 == 0)
 | 
			
		||||
					printk("\n");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} else
 | 
			
		||||
		err = mthca_cmd(dev, indma, (!!is_ee << 24) | num,
 | 
			
		||||
		err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
 | 
			
		||||
				op_mod, op[trans], CMD_TIME_CLASS_C, status);
 | 
			
		||||
 | 
			
		||||
	if (trans != MTHCA_TRANS_ANY2RST)
 | 
			
		||||
		pci_unmap_single(dev->pdev, indma,
 | 
			
		||||
				 MTHCA_QP_CONTEXT_SIZE, PCI_DMA_TODEVICE);
 | 
			
		||||
	else
 | 
			
		||||
		pci_free_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
 | 
			
		||||
				    qp_context, indma);
 | 
			
		||||
	if (my_mailbox)
 | 
			
		||||
		mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
 | 
			
		||||
		   void *qp_context, u8 *status)
 | 
			
		||||
		   struct mthca_mailbox *mailbox, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t outdma = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	outdma = pci_map_single(dev->pdev, qp_context,
 | 
			
		||||
				MTHCA_QP_CONTEXT_SIZE,
 | 
			
		||||
				PCI_DMA_FROMDEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(outdma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, (!!is_ee << 24) | num, 0,
 | 
			
		||||
			    CMD_QUERY_QPEE,
 | 
			
		||||
			    CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, outdma,
 | 
			
		||||
			 MTHCA_QP_CONTEXT_SIZE,
 | 
			
		||||
			 PCI_DMA_FROMDEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
	return mthca_cmd_box(dev, 0, mailbox->dma, (!!is_ee << 24) | num, 0,
 | 
			
		||||
			     CMD_QUERY_QPEE, CMD_TIME_CLASS_A, status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
 | 
			
		||||
| 
						 | 
				
			
			@ -1638,8 +1586,8 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
			
		|||
		  int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
 | 
			
		||||
		  void *in_mad, void *response_mad, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	void *box;
 | 
			
		||||
	dma_addr_t dma;
 | 
			
		||||
	struct mthca_mailbox *inmailbox, *outmailbox;
 | 
			
		||||
	void *inbox;
 | 
			
		||||
	int err;
 | 
			
		||||
	u32 in_modifier = port;
 | 
			
		||||
	u8 op_modifier = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1653,11 +1601,18 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
			
		|||
#define MAD_IFC_PKEY_OFFSET   0x10e
 | 
			
		||||
#define MAD_IFC_GRH_OFFSET    0x140
 | 
			
		||||
 | 
			
		||||
	box = pci_alloc_consistent(dev->pdev, MAD_IFC_BOX_SIZE, &dma);
 | 
			
		||||
	if (!box)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(inmailbox))
 | 
			
		||||
		return PTR_ERR(inmailbox);
 | 
			
		||||
	inbox = inmailbox->buf;
 | 
			
		||||
 | 
			
		||||
	memcpy(box, in_mad, 256);
 | 
			
		||||
	outmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(outmailbox)) {
 | 
			
		||||
		mthca_free_mailbox(dev, inmailbox);
 | 
			
		||||
		return PTR_ERR(outmailbox);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(inbox, in_mad, 256);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Key check traps can't be generated unless we have in_wc to
 | 
			
		||||
| 
						 | 
				
			
			@ -1671,97 +1626,65 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
			
		|||
	if (in_wc) {
 | 
			
		||||
		u8 val;
 | 
			
		||||
 | 
			
		||||
		memset(box + 256, 0, 256);
 | 
			
		||||
		memset(inbox + 256, 0, 256);
 | 
			
		||||
 | 
			
		||||
		MTHCA_PUT(box, in_wc->qp_num, 	  MAD_IFC_MY_QPN_OFFSET);
 | 
			
		||||
		MTHCA_PUT(box, in_wc->src_qp, 	  MAD_IFC_RQPN_OFFSET);
 | 
			
		||||
		MTHCA_PUT(inbox, in_wc->qp_num,     MAD_IFC_MY_QPN_OFFSET);
 | 
			
		||||
		MTHCA_PUT(inbox, in_wc->src_qp,     MAD_IFC_RQPN_OFFSET);
 | 
			
		||||
 | 
			
		||||
		val = in_wc->sl << 4;
 | 
			
		||||
		MTHCA_PUT(box, val,               MAD_IFC_SL_OFFSET);
 | 
			
		||||
		MTHCA_PUT(inbox, val,               MAD_IFC_SL_OFFSET);
 | 
			
		||||
 | 
			
		||||
		val = in_wc->dlid_path_bits |
 | 
			
		||||
			(in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
 | 
			
		||||
		MTHCA_PUT(box, val,               MAD_IFC_GRH_OFFSET);
 | 
			
		||||
		MTHCA_PUT(inbox, val,               MAD_IFC_GRH_OFFSET);
 | 
			
		||||
 | 
			
		||||
		MTHCA_PUT(box, in_wc->slid,       MAD_IFC_RLID_OFFSET);
 | 
			
		||||
		MTHCA_PUT(box, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
 | 
			
		||||
		MTHCA_PUT(inbox, in_wc->slid,       MAD_IFC_RLID_OFFSET);
 | 
			
		||||
		MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
 | 
			
		||||
 | 
			
		||||
		if (in_grh)
 | 
			
		||||
			memcpy((u8 *) box + MAD_IFC_GRH_OFFSET, in_grh, 40);
 | 
			
		||||
			memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40);
 | 
			
		||||
 | 
			
		||||
		op_modifier |= 0x10;
 | 
			
		||||
 | 
			
		||||
		in_modifier |= in_wc->slid << 16;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, dma, dma + 512, in_modifier, op_modifier,
 | 
			
		||||
	err = mthca_cmd_box(dev, inmailbox->dma, outmailbox->dma,
 | 
			
		||||
			    in_modifier, op_modifier,
 | 
			
		||||
			    CMD_MAD_IFC, CMD_TIME_CLASS_C, status);
 | 
			
		||||
 | 
			
		||||
	if (!err && !*status)
 | 
			
		||||
		memcpy(response_mad, box + 512, 256);
 | 
			
		||||
		memcpy(response_mad, outmailbox->buf, 256);
 | 
			
		||||
 | 
			
		||||
	pci_free_consistent(dev->pdev, MAD_IFC_BOX_SIZE, box, dma);
 | 
			
		||||
	mthca_free_mailbox(dev, inmailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, outmailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
 | 
			
		||||
		   u8 *status)
 | 
			
		||||
int mthca_READ_MGM(struct mthca_dev *dev, int index,
 | 
			
		||||
		   struct mthca_mailbox *mailbox, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t outdma = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
	return mthca_cmd_box(dev, 0, mailbox->dma, index, 0,
 | 
			
		||||
			     CMD_READ_MGM, CMD_TIME_CLASS_A, status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	outdma = pci_map_single(dev->pdev, mgm,
 | 
			
		||||
				MTHCA_MGM_ENTRY_SIZE,
 | 
			
		||||
				PCI_DMA_FROMDEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(outdma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_box(dev, 0, outdma, index, 0,
 | 
			
		||||
			    CMD_READ_MGM,
 | 
			
		||||
int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
 | 
			
		||||
		    struct mthca_mailbox *mailbox, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	return mthca_cmd(dev, mailbox->dma, index, 0, CMD_WRITE_MGM,
 | 
			
		||||
			 CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, outdma,
 | 
			
		||||
			 MTHCA_MGM_ENTRY_SIZE,
 | 
			
		||||
			 PCI_DMA_FROMDEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
 | 
			
		||||
		    u8 *status)
 | 
			
		||||
int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		    u16 *hash, u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	indma = pci_map_single(dev->pdev, mgm,
 | 
			
		||||
			       MTHCA_MGM_ENTRY_SIZE,
 | 
			
		||||
			       PCI_DMA_TODEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(indma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd(dev, indma, index, 0, CMD_WRITE_MGM,
 | 
			
		||||
			CMD_TIME_CLASS_A, status);
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, indma,
 | 
			
		||||
			 MTHCA_MGM_ENTRY_SIZE, PCI_DMA_TODEVICE);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
 | 
			
		||||
		    u8 *status)
 | 
			
		||||
{
 | 
			
		||||
	dma_addr_t indma;
 | 
			
		||||
	u64 imm;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	indma = pci_map_single(dev->pdev, gid, 16, PCI_DMA_TODEVICE);
 | 
			
		||||
	if (pci_dma_mapping_error(indma))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = mthca_cmd_imm(dev, indma, &imm, 0, 0, CMD_MGID_HASH,
 | 
			
		||||
	err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH,
 | 
			
		||||
			    CMD_TIME_CLASS_A, status);
 | 
			
		||||
	*hash = imm;
 | 
			
		||||
 | 
			
		||||
	pci_unmap_single(dev->pdev, indma, 16, PCI_DMA_TODEVICE);
 | 
			
		||||
	*hash = imm;
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,8 +37,7 @@
 | 
			
		|||
 | 
			
		||||
#include <ib_verbs.h>
 | 
			
		||||
 | 
			
		||||
#define MTHCA_CMD_MAILBOX_ALIGN 16UL
 | 
			
		||||
#define MTHCA_CMD_MAILBOX_EXTRA (MTHCA_CMD_MAILBOX_ALIGN - 1)
 | 
			
		||||
#define MTHCA_MAILBOX_SIZE 4096
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	/* command completed successfully: */
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +111,11 @@ enum {
 | 
			
		|||
	DEV_LIM_FLAG_UD_MULTI           = 1 << 21,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mthca_mailbox {
 | 
			
		||||
	dma_addr_t dma;
 | 
			
		||||
	void      *buf;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mthca_dev_lim {
 | 
			
		||||
	int max_srq_sz;
 | 
			
		||||
	int max_qp_sz;
 | 
			
		||||
| 
						 | 
				
			
			@ -235,11 +239,17 @@ struct mthca_set_ib_param {
 | 
			
		|||
	u32 cap_mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int mthca_cmd_init(struct mthca_dev *dev);
 | 
			
		||||
void mthca_cmd_cleanup(struct mthca_dev *dev);
 | 
			
		||||
int mthca_cmd_use_events(struct mthca_dev *dev);
 | 
			
		||||
void mthca_cmd_use_polling(struct mthca_dev *dev);
 | 
			
		||||
void mthca_cmd_event(struct mthca_dev *dev, u16 token,
 | 
			
		||||
		     u8  status, u64 out_param);
 | 
			
		||||
 | 
			
		||||
struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
 | 
			
		||||
					  unsigned int gfp_mask);
 | 
			
		||||
void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox);
 | 
			
		||||
 | 
			
		||||
int mthca_SYS_EN(struct mthca_dev *dev, u8 *status);
 | 
			
		||||
int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status);
 | 
			
		||||
int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
 | 
			
		||||
| 
						 | 
				
			
			@ -270,41 +280,39 @@ int mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
 | 
			
		|||
int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status);
 | 
			
		||||
int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
 | 
			
		||||
		       u8 *status);
 | 
			
		||||
int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
 | 
			
		||||
int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		    int mpt_index, u8 *status);
 | 
			
		||||
int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
 | 
			
		||||
int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		    int mpt_index, u8 *status);
 | 
			
		||||
int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
 | 
			
		||||
int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		    int num_mtt, u8 *status);
 | 
			
		||||
int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status);
 | 
			
		||||
int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
 | 
			
		||||
		 int eq_num, u8 *status);
 | 
			
		||||
int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
 | 
			
		||||
int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		   int eq_num, u8 *status);
 | 
			
		||||
int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
 | 
			
		||||
int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		   int eq_num, u8 *status);
 | 
			
		||||
int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
 | 
			
		||||
int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		   int cq_num, u8 *status);
 | 
			
		||||
int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
 | 
			
		||||
int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		   int cq_num, u8 *status);
 | 
			
		||||
int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
			
		||||
		    int is_ee, void *qp_context, u32 optmask,
 | 
			
		||||
		    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
 | 
			
		||||
		    u8 *status);
 | 
			
		||||
int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
 | 
			
		||||
		   void *qp_context, u8 *status);
 | 
			
		||||
		   struct mthca_mailbox *mailbox, u8 *status);
 | 
			
		||||
int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
 | 
			
		||||
			  u8 *status);
 | 
			
		||||
int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
			
		||||
		  int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
 | 
			
		||||
		  void *in_mad, void *response_mad, u8 *status);
 | 
			
		||||
int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
 | 
			
		||||
		   u8 *status);
 | 
			
		||||
int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
 | 
			
		||||
		    u8 *status);
 | 
			
		||||
int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
 | 
			
		||||
		    u8 *status);
 | 
			
		||||
int mthca_READ_MGM(struct mthca_dev *dev, int index,
 | 
			
		||||
		   struct mthca_mailbox *mailbox, u8 *status);
 | 
			
		||||
int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
 | 
			
		||||
		    struct mthca_mailbox *mailbox, u8 *status);
 | 
			
		||||
int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
			
		||||
		    u16 *hash, u8 *status);
 | 
			
		||||
int mthca_NOP(struct mthca_dev *dev, u8 *status);
 | 
			
		||||
 | 
			
		||||
#define MAILBOX_ALIGN(x) ((void *) ALIGN((unsigned long) (x), MTHCA_CMD_MAILBOX_ALIGN))
 | 
			
		||||
 | 
			
		||||
#endif /* MTHCA_CMD_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
			
		||||
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software is available to you under a choice of one of two
 | 
			
		||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
			
		||||
| 
						 | 
				
			
			@ -171,6 +172,17 @@ static inline void set_cqe_hw(struct mthca_cqe *cqe)
 | 
			
		|||
	cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
 | 
			
		||||
{
 | 
			
		||||
	__be32 *cqe = cqe_ptr;
 | 
			
		||||
 | 
			
		||||
	(void) cqe;	/* avoid warning if mthca_dbg compiled away... */
 | 
			
		||||
	mthca_dbg(dev, "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
 | 
			
		||||
		  be32_to_cpu(cqe[0]), be32_to_cpu(cqe[1]), be32_to_cpu(cqe[2]),
 | 
			
		||||
		  be32_to_cpu(cqe[3]), be32_to_cpu(cqe[4]), be32_to_cpu(cqe[5]),
 | 
			
		||||
		  be32_to_cpu(cqe[6]), be32_to_cpu(cqe[7]));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index
 | 
			
		||||
 * should be correct before calling update_cons_index().
 | 
			
		||||
| 
						 | 
				
			
			@ -280,16 +292,12 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
 | 
			
		|||
	int dbd;
 | 
			
		||||
	u32 new_wqe;
 | 
			
		||||
 | 
			
		||||
	if (1 && cqe->syndrome != SYNDROME_WR_FLUSH_ERR) {
 | 
			
		||||
		int j;
 | 
			
		||||
 | 
			
		||||
		mthca_dbg(dev, "%x/%d: error CQE -> QPN %06x, WQE @ %08x\n",
 | 
			
		||||
			  cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
 | 
			
		||||
			  be32_to_cpu(cqe->wqe));
 | 
			
		||||
 | 
			
		||||
		for (j = 0; j < 8; ++j)
 | 
			
		||||
			printk(KERN_DEBUG "  [%2x] %08x\n",
 | 
			
		||||
			       j * 4, be32_to_cpu(((u32 *) cqe)[j]));
 | 
			
		||||
	if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) {
 | 
			
		||||
		mthca_dbg(dev, "local QP operation err "
 | 
			
		||||
			  "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n",
 | 
			
		||||
			  be32_to_cpu(cqe->my_qpn), be32_to_cpu(cqe->wqe),
 | 
			
		||||
			  cq->cqn, cq->cons_index);
 | 
			
		||||
		dump_cqe(dev, cqe);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -377,15 +385,6 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dump_cqe(struct mthca_cqe *cqe)
 | 
			
		||||
{
 | 
			
		||||
	int j;
 | 
			
		||||
 | 
			
		||||
	for (j = 0; j < 8; ++j)
 | 
			
		||||
		printk(KERN_DEBUG "  [%2x] %08x\n",
 | 
			
		||||
		       j * 4, be32_to_cpu(((u32 *) cqe)[j]));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int mthca_poll_one(struct mthca_dev *dev,
 | 
			
		||||
				 struct mthca_cq *cq,
 | 
			
		||||
				 struct mthca_qp **cur_qp,
 | 
			
		||||
| 
						 | 
				
			
			@ -414,8 +413,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
 | 
			
		|||
		mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n",
 | 
			
		||||
			  cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
 | 
			
		||||
			  be32_to_cpu(cqe->wqe));
 | 
			
		||||
 | 
			
		||||
		dump_cqe(cqe);
 | 
			
		||||
		dump_cqe(dev, cqe);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
 | 
			
		||||
| 
						 | 
				
			
			@ -638,7 +636,7 @@ static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
 | 
			
		|||
	int size;
 | 
			
		||||
 | 
			
		||||
	if (cq->is_direct)
 | 
			
		||||
		pci_free_consistent(dev->pdev,
 | 
			
		||||
		dma_free_coherent(&dev->pdev->dev,
 | 
			
		||||
				  (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
 | 
			
		||||
				  cq->queue.direct.buf,
 | 
			
		||||
				  pci_unmap_addr(&cq->queue.direct,
 | 
			
		||||
| 
						 | 
				
			
			@ -647,7 +645,7 @@ static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
 | 
			
		|||
		size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
 | 
			
		||||
		for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
 | 
			
		||||
			if (cq->queue.page_list[i].buf)
 | 
			
		||||
				pci_free_consistent(dev->pdev, PAGE_SIZE,
 | 
			
		||||
				dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
			
		||||
						  cq->queue.page_list[i].buf,
 | 
			
		||||
						  pci_unmap_addr(&cq->queue.page_list[i],
 | 
			
		||||
								 mapping));
 | 
			
		||||
| 
						 | 
				
			
			@ -670,8 +668,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
 | 
			
		|||
		npages        = 1;
 | 
			
		||||
		shift         = get_order(size) + PAGE_SHIFT;
 | 
			
		||||
 | 
			
		||||
		cq->queue.direct.buf = pci_alloc_consistent(dev->pdev,
 | 
			
		||||
							    size, &t);
 | 
			
		||||
		cq->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
 | 
			
		||||
							  size, &t, GFP_KERNEL);
 | 
			
		||||
		if (!cq->queue.direct.buf)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -709,7 +707,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
 | 
			
		|||
 | 
			
		||||
		for (i = 0; i < npages; ++i) {
 | 
			
		||||
			cq->queue.page_list[i].buf =
 | 
			
		||||
				pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
 | 
			
		||||
				dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
			
		||||
						   &t, GFP_KERNEL);
 | 
			
		||||
			if (!cq->queue.page_list[i].buf)
 | 
			
		||||
				goto err_free;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -746,7 +745,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 | 
			
		|||
		  struct mthca_cq *cq)
 | 
			
		||||
{
 | 
			
		||||
	int size = nent * MTHCA_CQ_ENTRY_SIZE;
 | 
			
		||||
	void *mailbox = NULL;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	struct mthca_cq_context *cq_context;
 | 
			
		||||
	int err = -ENOMEM;
 | 
			
		||||
	u8 status;
 | 
			
		||||
| 
						 | 
				
			
			@ -780,12 +779,11 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 | 
			
		|||
			goto err_out_ci;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
 | 
			
		||||
			  GFP_KERNEL);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
		goto err_out_mailbox;
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		goto err_out_arm;
 | 
			
		||||
 | 
			
		||||
	cq_context = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
	cq_context = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	err = mthca_alloc_cq_buf(dev, size, cq);
 | 
			
		||||
	if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -816,7 +814,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 | 
			
		|||
		cq_context->state_db = cpu_to_be32(cq->arm_db_index);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_SW2HW_CQ(dev, cq_context, cq->cqn, &status);
 | 
			
		||||
	err = mthca_SW2HW_CQ(dev, mailbox, cq->cqn, &status);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err);
 | 
			
		||||
		goto err_out_free_mr;
 | 
			
		||||
| 
						 | 
				
			
			@ -840,7 +838,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 | 
			
		|||
 | 
			
		||||
	cq->cons_index = 0;
 | 
			
		||||
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -849,8 +847,9 @@ err_out_free_mr:
 | 
			
		|||
	mthca_free_cq_buf(dev, cq);
 | 
			
		||||
 | 
			
		||||
err_out_mailbox:
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
 | 
			
		||||
err_out_arm:
 | 
			
		||||
	if (mthca_is_memfree(dev))
 | 
			
		||||
		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -870,28 +869,26 @@ err_out:
 | 
			
		|||
void mthca_free_cq(struct mthca_dev *dev,
 | 
			
		||||
		   struct mthca_cq *cq)
 | 
			
		||||
{
 | 
			
		||||
	void *mailbox;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	int err;
 | 
			
		||||
	u8 status;
 | 
			
		||||
 | 
			
		||||
	might_sleep();
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
 | 
			
		||||
			  GFP_KERNEL);
 | 
			
		||||
	if (!mailbox) {
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox)) {
 | 
			
		||||
		mthca_warn(dev, "No memory for mailbox to free CQ.\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_HW2SW_CQ(dev, MAILBOX_ALIGN(mailbox), cq->cqn, &status);
 | 
			
		||||
	err = mthca_HW2SW_CQ(dev, mailbox, cq->cqn, &status);
 | 
			
		||||
	if (err)
 | 
			
		||||
		mthca_warn(dev, "HW2SW_CQ failed (%d)\n", err);
 | 
			
		||||
	else if (status)
 | 
			
		||||
		mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n",
 | 
			
		||||
			   status);
 | 
			
		||||
		mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n", status);
 | 
			
		||||
 | 
			
		||||
	if (0) {
 | 
			
		||||
		u32 *ctx = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
		u32 *ctx = mailbox->buf;
 | 
			
		||||
		int j;
 | 
			
		||||
 | 
			
		||||
		printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
 | 
			
		||||
| 
						 | 
				
			
			@ -919,11 +916,11 @@ void mthca_free_cq(struct mthca_dev *dev,
 | 
			
		|||
	if (mthca_is_memfree(dev)) {
 | 
			
		||||
		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
 | 
			
		||||
		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
 | 
			
		||||
		mthca_table_put(dev, dev->cq_table.table, cq->cqn);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mthca_table_put(dev, dev->cq_table.table, cq->cqn);
 | 
			
		||||
	mthca_free(&dev->cq_table.alloc, cq->cqn);
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int __devinit mthca_init_cq_table(struct mthca_dev *dev)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
			
		||||
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software is available to you under a choice of one of two
 | 
			
		||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
			
		||||
| 
						 | 
				
			
			@ -46,8 +47,8 @@
 | 
			
		|||
 | 
			
		||||
#define DRV_NAME	"ib_mthca"
 | 
			
		||||
#define PFX		DRV_NAME ": "
 | 
			
		||||
#define DRV_VERSION	"0.06-pre"
 | 
			
		||||
#define DRV_RELDATE	"November 8, 2004"
 | 
			
		||||
#define DRV_VERSION	"0.06"
 | 
			
		||||
#define DRV_RELDATE	"June 23, 2005"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -98,6 +99,7 @@ enum {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
struct mthca_cmd {
 | 
			
		||||
	struct pci_pool          *pool;
 | 
			
		||||
	int                       use_events;
 | 
			
		||||
	struct semaphore          hcr_sem;
 | 
			
		||||
	struct semaphore 	  poll_sem;
 | 
			
		||||
| 
						 | 
				
			
			@ -379,6 +381,12 @@ void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
 | 
			
		|||
int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
 | 
			
		||||
void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
 | 
			
		||||
 | 
			
		||||
struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size);
 | 
			
		||||
void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt);
 | 
			
		||||
int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
 | 
			
		||||
		    int start_index, u64 *buffer_list, int list_len);
 | 
			
		||||
int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
 | 
			
		||||
		   u64 iova, u64 total_size, u32 access, struct mthca_mr *mr);
 | 
			
		||||
int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
 | 
			
		||||
			   u32 access, struct mthca_mr *mr);
 | 
			
		||||
int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2004 Topspin Communications.  All rights reserved.
 | 
			
		||||
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software is available to you under a choice of one of two
 | 
			
		||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -469,7 +469,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
			
		|||
		PAGE_SIZE;
 | 
			
		||||
	u64 *dma_list = NULL;
 | 
			
		||||
	dma_addr_t t;
 | 
			
		||||
	void *mailbox = NULL;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	struct mthca_eq_context *eq_context;
 | 
			
		||||
	int err = -ENOMEM;
 | 
			
		||||
	int i;
 | 
			
		||||
| 
						 | 
				
			
			@ -494,17 +494,16 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
			
		|||
	if (!dma_list)
 | 
			
		||||
		goto err_out_free;
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof *eq_context + MTHCA_CMD_MAILBOX_EXTRA,
 | 
			
		||||
			  GFP_KERNEL);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		goto err_out_free;
 | 
			
		||||
	eq_context = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
	eq_context = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < npages; ++i) {
 | 
			
		||||
		eq->page_list[i].buf = pci_alloc_consistent(dev->pdev,
 | 
			
		||||
							    PAGE_SIZE, &t);
 | 
			
		||||
		eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
 | 
			
		||||
							  PAGE_SIZE, &t, GFP_KERNEL);
 | 
			
		||||
		if (!eq->page_list[i].buf)
 | 
			
		||||
			goto err_out_free;
 | 
			
		||||
			goto err_out_free_pages;
 | 
			
		||||
 | 
			
		||||
		dma_list[i] = t;
 | 
			
		||||
		pci_unmap_addr_set(&eq->page_list[i], mapping, t);
 | 
			
		||||
| 
						 | 
				
			
			@ -517,7 +516,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
			
		|||
 | 
			
		||||
	eq->eqn = mthca_alloc(&dev->eq_table.alloc);
 | 
			
		||||
	if (eq->eqn == -1)
 | 
			
		||||
		goto err_out_free;
 | 
			
		||||
		goto err_out_free_pages;
 | 
			
		||||
 | 
			
		||||
	err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
 | 
			
		||||
				  dma_list, PAGE_SHIFT, npages,
 | 
			
		||||
| 
						 | 
				
			
			@ -548,7 +547,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
			
		|||
	eq_context->intr            = intr;
 | 
			
		||||
	eq_context->lkey            = cpu_to_be32(eq->mr.ibmr.lkey);
 | 
			
		||||
 | 
			
		||||
	err = mthca_SW2HW_EQ(dev, eq_context, eq->eqn, &status);
 | 
			
		||||
	err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		mthca_warn(dev, "SW2HW_EQ failed (%d)\n", err);
 | 
			
		||||
		goto err_out_free_mr;
 | 
			
		||||
| 
						 | 
				
			
			@ -561,7 +560,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	kfree(dma_list);
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
 | 
			
		||||
	eq->eqn_mask   = swab32(1 << eq->eqn);
 | 
			
		||||
	eq->cons_index = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -579,17 +578,19 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
			
		|||
 err_out_free_eq:
 | 
			
		||||
	mthca_free(&dev->eq_table.alloc, eq->eqn);
 | 
			
		||||
 | 
			
		||||
 err_out_free:
 | 
			
		||||
 err_out_free_pages:
 | 
			
		||||
	for (i = 0; i < npages; ++i)
 | 
			
		||||
		if (eq->page_list[i].buf)
 | 
			
		||||
			pci_free_consistent(dev->pdev, PAGE_SIZE,
 | 
			
		||||
			dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
			
		||||
					  eq->page_list[i].buf,
 | 
			
		||||
					  pci_unmap_addr(&eq->page_list[i],
 | 
			
		||||
							 mapping));
 | 
			
		||||
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
 | 
			
		||||
 err_out_free:
 | 
			
		||||
	kfree(eq->page_list);
 | 
			
		||||
	kfree(dma_list);
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
 | 
			
		||||
 err_out:
 | 
			
		||||
	return err;
 | 
			
		||||
| 
						 | 
				
			
			@ -598,25 +599,22 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
			
		|||
static void mthca_free_eq(struct mthca_dev *dev,
 | 
			
		||||
			  struct mthca_eq *eq)
 | 
			
		||||
{
 | 
			
		||||
	void *mailbox = NULL;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	int err;
 | 
			
		||||
	u8 status;
 | 
			
		||||
	int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
 | 
			
		||||
		PAGE_SIZE;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof (struct mthca_eq_context) + MTHCA_CMD_MAILBOX_EXTRA,
 | 
			
		||||
			  GFP_KERNEL);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	err = mthca_HW2SW_EQ(dev, MAILBOX_ALIGN(mailbox),
 | 
			
		||||
			     eq->eqn, &status);
 | 
			
		||||
	err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status);
 | 
			
		||||
	if (err)
 | 
			
		||||
		mthca_warn(dev, "HW2SW_EQ failed (%d)\n", err);
 | 
			
		||||
	if (status)
 | 
			
		||||
		mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n",
 | 
			
		||||
			   status);
 | 
			
		||||
		mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n", status);
 | 
			
		||||
 | 
			
		||||
	dev->eq_table.arm_mask &= ~eq->eqn_mask;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -625,7 +623,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
 | 
			
		|||
		for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) {
 | 
			
		||||
			if (i % 4 == 0)
 | 
			
		||||
				printk("[%02x] ", i * 4);
 | 
			
		||||
			printk(" %08x", be32_to_cpup(MAILBOX_ALIGN(mailbox) + i * 4));
 | 
			
		||||
			printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
 | 
			
		||||
			if ((i + 1) % 4 == 0)
 | 
			
		||||
				printk("\n");
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -638,7 +636,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
 | 
			
		|||
				    pci_unmap_addr(&eq->page_list[i], mapping));
 | 
			
		||||
 | 
			
		||||
	kfree(eq->page_list);
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void mthca_free_irqs(struct mthca_dev *dev)
 | 
			
		||||
| 
						 | 
				
			
			@ -709,8 +707,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
 | 
			
		|||
		if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
 | 
			
		||||
					dev->fw.arbel.eq_arm_base) + 4, 4,
 | 
			
		||||
				  &dev->eq_regs.arbel.eq_arm)) {
 | 
			
		||||
			mthca_err(dev, "Couldn't map interrupt clear register, "
 | 
			
		||||
				  "aborting.\n");
 | 
			
		||||
			mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
 | 
			
		||||
			mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
 | 
			
		||||
					dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
 | 
			
		||||
					dev->clr_base);
 | 
			
		||||
| 
						 | 
				
			
			@ -721,8 +718,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
 | 
			
		|||
				  dev->fw.arbel.eq_set_ci_base,
 | 
			
		||||
				  MTHCA_EQ_SET_CI_SIZE,
 | 
			
		||||
				  &dev->eq_regs.arbel.eq_set_ci_base)) {
 | 
			
		||||
			mthca_err(dev, "Couldn't map interrupt clear register, "
 | 
			
		||||
				  "aborting.\n");
 | 
			
		||||
			mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
 | 
			
		||||
			mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
 | 
			
		||||
					      dev->fw.arbel.eq_arm_base) + 4, 4,
 | 
			
		||||
					dev->eq_regs.arbel.eq_arm);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
			
		||||
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software is available to you under a choice of one of two
 | 
			
		||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +70,7 @@ MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
 | 
			
		|||
#endif /* CONFIG_PCI_MSI */
 | 
			
		||||
 | 
			
		||||
static const char mthca_version[] __devinitdata =
 | 
			
		||||
	"ib_mthca: Mellanox InfiniBand HCA driver v"
 | 
			
		||||
	DRV_NAME ": Mellanox InfiniBand HCA driver v"
 | 
			
		||||
	DRV_VERSION " (" DRV_RELDATE ")\n";
 | 
			
		||||
 | 
			
		||||
static struct mthca_profile default_profile = {
 | 
			
		||||
| 
						 | 
				
			
			@ -927,13 +928,13 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
 | 
			
		|||
	 */
 | 
			
		||||
	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
 | 
			
		||||
	    pci_resource_len(pdev, 0) != 1 << 20) {
 | 
			
		||||
		dev_err(&pdev->dev, "Missing DCS, aborting.");
 | 
			
		||||
		dev_err(&pdev->dev, "Missing DCS, aborting.\n");
 | 
			
		||||
		err = -ENODEV;
 | 
			
		||||
		goto err_disable_pdev;
 | 
			
		||||
	}
 | 
			
		||||
	if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM) ||
 | 
			
		||||
	    pci_resource_len(pdev, 2) != 1 << 23) {
 | 
			
		||||
		dev_err(&pdev->dev, "Missing UAR, aborting.");
 | 
			
		||||
		dev_err(&pdev->dev, "Missing UAR, aborting.\n");
 | 
			
		||||
		err = -ENODEV;
 | 
			
		||||
		goto err_disable_pdev;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1004,25 +1005,18 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
 | 
			
		|||
	    !pci_enable_msi(pdev))
 | 
			
		||||
		mdev->mthca_flags |= MTHCA_FLAG_MSI;
 | 
			
		||||
 | 
			
		||||
	sema_init(&mdev->cmd.hcr_sem, 1);
 | 
			
		||||
	sema_init(&mdev->cmd.poll_sem, 1);
 | 
			
		||||
	mdev->cmd.use_events = 0;
 | 
			
		||||
 | 
			
		||||
	mdev->hcr = ioremap(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);
 | 
			
		||||
	if (!mdev->hcr) {
 | 
			
		||||
		mthca_err(mdev, "Couldn't map command register, "
 | 
			
		||||
			  "aborting.\n");
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
	if (mthca_cmd_init(mdev)) {
 | 
			
		||||
		mthca_err(mdev, "Failed to init command interface, aborting.\n");
 | 
			
		||||
		goto err_free_dev;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_tune_pci(mdev);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err_iounmap;
 | 
			
		||||
		goto err_cmd;
 | 
			
		||||
 | 
			
		||||
	err = mthca_init_hca(mdev);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err_iounmap;
 | 
			
		||||
		goto err_cmd;
 | 
			
		||||
 | 
			
		||||
	if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
 | 
			
		||||
		mthca_warn(mdev, "HCA FW version %x.%x.%x is old (%x.%x.%x is current).\n",
 | 
			
		||||
| 
						 | 
				
			
			@ -1070,8 +1064,8 @@ err_cleanup:
 | 
			
		|||
err_close:
 | 
			
		||||
	mthca_close_hca(mdev);
 | 
			
		||||
 | 
			
		||||
err_iounmap:
 | 
			
		||||
	iounmap(mdev->hcr);
 | 
			
		||||
err_cmd:
 | 
			
		||||
	mthca_cmd_cleanup(mdev);
 | 
			
		||||
 | 
			
		||||
err_free_dev:
 | 
			
		||||
	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 | 
			
		||||
| 
						 | 
				
			
			@ -1118,10 +1112,8 @@ static void __devexit mthca_remove_one(struct pci_dev *pdev)
 | 
			
		|||
		iounmap(mdev->kar);
 | 
			
		||||
		mthca_uar_free(mdev, &mdev->driver_uar);
 | 
			
		||||
		mthca_cleanup_uar_table(mdev);
 | 
			
		||||
 | 
			
		||||
		mthca_close_hca(mdev);
 | 
			
		||||
 | 
			
		||||
		iounmap(mdev->hcr);
 | 
			
		||||
		mthca_cmd_cleanup(mdev);
 | 
			
		||||
 | 
			
		||||
		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 | 
			
		||||
			pci_disable_msix(pdev);
 | 
			
		||||
| 
						 | 
				
			
			@ -1163,7 +1155,7 @@ static struct pci_device_id mthca_pci_table[] = {
 | 
			
		|||
MODULE_DEVICE_TABLE(pci, mthca_pci_table);
 | 
			
		||||
 | 
			
		||||
static struct pci_driver mthca_driver = {
 | 
			
		||||
	.name		= "ib_mthca",
 | 
			
		||||
	.name		= DRV_NAME,
 | 
			
		||||
	.id_table	= mthca_pci_table,
 | 
			
		||||
	.probe		= mthca_init_one,
 | 
			
		||||
	.remove		= __devexit_p(mthca_remove_one)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,22 +66,23 @@ static const u8 zero_gid[16];	/* automatically initialized to 0 */
 | 
			
		|||
 * entry in hash chain and *mgm holds end of hash chain.
 | 
			
		||||
 */
 | 
			
		||||
static int find_mgm(struct mthca_dev *dev,
 | 
			
		||||
		    u8 *gid, struct mthca_mgm *mgm,
 | 
			
		||||
		    u8 *gid, struct mthca_mailbox *mgm_mailbox,
 | 
			
		||||
		    u16 *hash, int *prev, int *index)
 | 
			
		||||
{
 | 
			
		||||
	void *mailbox;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	struct mthca_mgm *mgm = mgm_mailbox->buf;
 | 
			
		||||
	u8 *mgid;
 | 
			
		||||
	int err;
 | 
			
		||||
	u8 status;
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(16 + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mgid = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
	mgid = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	memcpy(mgid, gid, 16);
 | 
			
		||||
 | 
			
		||||
	err = mthca_MGID_HASH(dev, mgid, hash, &status);
 | 
			
		||||
	err = mthca_MGID_HASH(dev, mailbox, hash, &status);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +104,7 @@ static int find_mgm(struct mthca_dev *dev,
 | 
			
		|||
	*prev  = -1;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		err = mthca_READ_MGM(dev, *index, mgm, &status);
 | 
			
		||||
		err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto out;
 | 
			
		||||
		if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -129,14 +130,14 @@ static int find_mgm(struct mthca_dev *dev,
 | 
			
		|||
	*index = -1;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_dev *dev = to_mdev(ibqp->device);
 | 
			
		||||
	void *mailbox;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	struct mthca_mgm *mgm;
 | 
			
		||||
	u16 hash;
 | 
			
		||||
	int index, prev;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,15 +146,15 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
	int err;
 | 
			
		||||
	u8 status;
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mgm = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	mgm = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	if (down_interruptible(&dev->mcg_table.sem))
 | 
			
		||||
		return -EINTR;
 | 
			
		||||
 | 
			
		||||
	err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
 | 
			
		||||
	err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +171,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = mthca_READ_MGM(dev, index, mgm, &status);
 | 
			
		||||
		err = mthca_READ_MGM(dev, index, mailbox, &status);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto out;
 | 
			
		||||
		if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +196,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_WRITE_MGM(dev, index, mgm, &status);
 | 
			
		||||
	err = mthca_WRITE_MGM(dev, index, mailbox, &status);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -206,7 +207,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
	if (!link)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	err = mthca_READ_MGM(dev, prev, mgm, &status);
 | 
			
		||||
	err = mthca_READ_MGM(dev, prev, mailbox, &status);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -217,7 +218,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
 | 
			
		||||
	mgm->next_gid_index = cpu_to_be32(index << 5);
 | 
			
		||||
 | 
			
		||||
	err = mthca_WRITE_MGM(dev, prev, mgm, &status);
 | 
			
		||||
	err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -227,14 +228,14 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
 | 
			
		||||
 out:
 | 
			
		||||
	up(&dev->mcg_table.sem);
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_dev *dev = to_mdev(ibqp->device);
 | 
			
		||||
	void *mailbox;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	struct mthca_mgm *mgm;
 | 
			
		||||
	u16 hash;
 | 
			
		||||
	int prev, index;
 | 
			
		||||
| 
						 | 
				
			
			@ -242,15 +243,15 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
	int err;
 | 
			
		||||
	u8 status;
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mgm = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	mgm = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	if (down_interruptible(&dev->mcg_table.sem))
 | 
			
		||||
		return -EINTR;
 | 
			
		||||
 | 
			
		||||
	err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
 | 
			
		||||
	err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -285,7 +286,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
	mgm->qp[loc]   = mgm->qp[i - 1];
 | 
			
		||||
	mgm->qp[i - 1] = 0;
 | 
			
		||||
 | 
			
		||||
	err = mthca_WRITE_MGM(dev, index, mgm, &status);
 | 
			
		||||
	err = mthca_WRITE_MGM(dev, index, mailbox, &status);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -304,7 +305,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
		if (be32_to_cpu(mgm->next_gid_index) >> 5) {
 | 
			
		||||
			err = mthca_READ_MGM(dev,
 | 
			
		||||
					     be32_to_cpu(mgm->next_gid_index) >> 5,
 | 
			
		||||
					     mgm, &status);
 | 
			
		||||
					     mailbox, &status);
 | 
			
		||||
			if (err)
 | 
			
		||||
				goto out;
 | 
			
		||||
			if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -316,7 +317,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
		} else
 | 
			
		||||
			memset(mgm->gid, 0, 16);
 | 
			
		||||
 | 
			
		||||
		err = mthca_WRITE_MGM(dev, index, mgm, &status);
 | 
			
		||||
		err = mthca_WRITE_MGM(dev, index, mailbox, &status);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto out;
 | 
			
		||||
		if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -327,7 +328,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
	} else {
 | 
			
		||||
		/* Remove entry from AMGM */
 | 
			
		||||
		index = be32_to_cpu(mgm->next_gid_index) >> 5;
 | 
			
		||||
		err = mthca_READ_MGM(dev, prev, mgm, &status);
 | 
			
		||||
		err = mthca_READ_MGM(dev, prev, mailbox, &status);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto out;
 | 
			
		||||
		if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -338,7 +339,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
 | 
			
		||||
		mgm->next_gid_index = cpu_to_be32(index << 5);
 | 
			
		||||
 | 
			
		||||
		err = mthca_WRITE_MGM(dev, prev, mgm, &status);
 | 
			
		||||
		err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto out;
 | 
			
		||||
		if (status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -350,7 +351,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
			
		|||
 | 
			
		||||
 out:
 | 
			
		||||
	up(&dev->mcg_table.sem);
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,9 +179,14 @@ out:
 | 
			
		|||
 | 
			
		||||
void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
 | 
			
		||||
{
 | 
			
		||||
	int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
 | 
			
		||||
	int i;
 | 
			
		||||
	u8 status;
 | 
			
		||||
 | 
			
		||||
	if (!mthca_is_memfree(dev))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
 | 
			
		||||
 | 
			
		||||
	down(&table->mutex);
 | 
			
		||||
 | 
			
		||||
	if (--table->icm[i]->refcount == 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -256,6 +261,9 @@ void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
 | 
			
		|||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!mthca_is_memfree(dev))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size)
 | 
			
		||||
		mthca_table_put(dev, table, i);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,12 @@
 | 
			
		|||
#include "mthca_cmd.h"
 | 
			
		||||
#include "mthca_memfree.h"
 | 
			
		||||
 | 
			
		||||
struct mthca_mtt {
 | 
			
		||||
	struct mthca_buddy *buddy;
 | 
			
		||||
	int                 order;
 | 
			
		||||
	u32                 first_seg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -173,7 +179,7 @@ static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy)
 | 
			
		|||
	kfree(buddy->bits);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
 | 
			
		||||
static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order,
 | 
			
		||||
				 struct mthca_buddy *buddy)
 | 
			
		||||
{
 | 
			
		||||
	u32 seg = mthca_buddy_alloc(buddy, order);
 | 
			
		||||
| 
						 | 
				
			
			@ -191,14 +197,102 @@ static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
 | 
			
		|||
	return seg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order,
 | 
			
		||||
static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size,
 | 
			
		||||
					   struct mthca_buddy *buddy)
 | 
			
		||||
{
 | 
			
		||||
	mthca_buddy_free(buddy, seg, order);
 | 
			
		||||
	struct mthca_mtt *mtt;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (mthca_is_memfree(dev))
 | 
			
		||||
		mthca_table_put_range(dev, dev->mr_table.mtt_table, seg,
 | 
			
		||||
				      seg + (1 << order) - 1);
 | 
			
		||||
	if (size <= 0)
 | 
			
		||||
		return ERR_PTR(-EINVAL);
 | 
			
		||||
 | 
			
		||||
	mtt = kmalloc(sizeof *mtt, GFP_KERNEL);
 | 
			
		||||
	if (!mtt)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	mtt->buddy = buddy;
 | 
			
		||||
	mtt->order = 0;
 | 
			
		||||
	for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1)
 | 
			
		||||
		++mtt->order;
 | 
			
		||||
 | 
			
		||||
	mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy);
 | 
			
		||||
	if (mtt->first_seg == -1) {
 | 
			
		||||
		kfree(mtt);
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return mtt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size)
 | 
			
		||||
{
 | 
			
		||||
	return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt)
 | 
			
		||||
{
 | 
			
		||||
	if (!mtt)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order);
 | 
			
		||||
 | 
			
		||||
	mthca_table_put_range(dev, dev->mr_table.mtt_table,
 | 
			
		||||
			      mtt->first_seg,
 | 
			
		||||
			      mtt->first_seg + (1 << mtt->order) - 1);
 | 
			
		||||
 | 
			
		||||
	kfree(mtt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
 | 
			
		||||
		    int start_index, u64 *buffer_list, int list_len)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u64 *mtt_entry;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	u8 status;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	mtt_entry = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	while (list_len > 0) {
 | 
			
		||||
		mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
 | 
			
		||||
					   mtt->first_seg * MTHCA_MTT_SEG_SIZE +
 | 
			
		||||
					   start_index * 8);
 | 
			
		||||
		mtt_entry[1] = 0;
 | 
			
		||||
		for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i)
 | 
			
		||||
			mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
 | 
			
		||||
						       MTHCA_MTT_FLAG_PRESENT);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If we have an odd number of entries to write, add
 | 
			
		||||
		 * one more dummy entry for firmware efficiency.
 | 
			
		||||
		 */
 | 
			
		||||
		if (i & 1)
 | 
			
		||||
			mtt_entry[i + 2] = 0;
 | 
			
		||||
 | 
			
		||||
		err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status);
 | 
			
		||||
		if (err) {
 | 
			
		||||
			mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		if (status) {
 | 
			
		||||
			mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
 | 
			
		||||
				   status);
 | 
			
		||||
			err = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		list_len    -= i;
 | 
			
		||||
		start_index += i;
 | 
			
		||||
		buffer_list += i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 tavor_hw_index_to_key(u32 ind)
 | 
			
		||||
| 
						 | 
				
			
			@ -237,91 +331,18 @@ static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key)
 | 
			
		|||
		return tavor_key_to_hw_index(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
 | 
			
		||||
			   u32 access, struct mthca_mr *mr)
 | 
			
		||||
int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
 | 
			
		||||
		   u64 iova, u64 total_size, u32 access, struct mthca_mr *mr)
 | 
			
		||||
{
 | 
			
		||||
	void *mailbox = NULL;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	struct mthca_mpt_entry *mpt_entry;
 | 
			
		||||
	u32 key;
 | 
			
		||||
	int i;
 | 
			
		||||
	int err;
 | 
			
		||||
	u8 status;
 | 
			
		||||
 | 
			
		||||
	might_sleep();
 | 
			
		||||
 | 
			
		||||
	mr->order = -1;
 | 
			
		||||
	key = mthca_alloc(&dev->mr_table.mpt_alloc);
 | 
			
		||||
	if (key == -1)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
 | 
			
		||||
 | 
			
		||||
	if (mthca_is_memfree(dev)) {
 | 
			
		||||
		err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto err_out_mpt_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
 | 
			
		||||
			  GFP_KERNEL);
 | 
			
		||||
	if (!mailbox) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err_out_table;
 | 
			
		||||
	}
 | 
			
		||||
	mpt_entry = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
 | 
			
		||||
	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 | 
			
		||||
				       MTHCA_MPT_FLAG_MIO         |
 | 
			
		||||
				       MTHCA_MPT_FLAG_PHYSICAL    |
 | 
			
		||||
				       MTHCA_MPT_FLAG_REGION      |
 | 
			
		||||
				       access);
 | 
			
		||||
	mpt_entry->page_size = 0;
 | 
			
		||||
	mpt_entry->key       = cpu_to_be32(key);
 | 
			
		||||
	mpt_entry->pd        = cpu_to_be32(pd);
 | 
			
		||||
	mpt_entry->start     = 0;
 | 
			
		||||
	mpt_entry->length    = ~0ULL;
 | 
			
		||||
 | 
			
		||||
	memset(&mpt_entry->lkey, 0,
 | 
			
		||||
	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
 | 
			
		||||
 | 
			
		||||
	err = mthca_SW2HW_MPT(dev, mpt_entry,
 | 
			
		||||
			      key & (dev->limits.num_mpts - 1),
 | 
			
		||||
			      &status);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
 | 
			
		||||
		goto err_out_table;
 | 
			
		||||
	} else if (status) {
 | 
			
		||||
		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
 | 
			
		||||
			   status);
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err_out_table;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
 | 
			
		||||
err_out_table:
 | 
			
		||||
	if (mthca_is_memfree(dev))
 | 
			
		||||
		mthca_table_put(dev, dev->mr_table.mpt_table, key);
 | 
			
		||||
 | 
			
		||||
err_out_mpt_free:
 | 
			
		||||
	mthca_free(&dev->mr_table.mpt_alloc, key);
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
			
		||||
			u64 *buffer_list, int buffer_size_shift,
 | 
			
		||||
			int list_len, u64 iova, u64 total_size,
 | 
			
		||||
			u32 access, struct mthca_mr *mr)
 | 
			
		||||
{
 | 
			
		||||
	void *mailbox;
 | 
			
		||||
	u64 *mtt_entry;
 | 
			
		||||
	struct mthca_mpt_entry *mpt_entry;
 | 
			
		||||
	u32 key;
 | 
			
		||||
	int err = -ENOMEM;
 | 
			
		||||
	u8 status;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	might_sleep();
 | 
			
		||||
	WARN_ON(buffer_size_shift >= 32);
 | 
			
		||||
 | 
			
		||||
	key = mthca_alloc(&dev->mr_table.mpt_alloc);
 | 
			
		||||
| 
						 | 
				
			
			@ -335,75 +356,33 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
			
		|||
			goto err_out_mpt_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
 | 
			
		||||
	     i < list_len;
 | 
			
		||||
	     i <<= 1, ++mr->order)
 | 
			
		||||
		; /* nothing */
 | 
			
		||||
 | 
			
		||||
	mr->first_seg = mthca_alloc_mtt(dev, mr->order,
 | 
			
		||||
				       	&dev->mr_table.mtt_buddy);
 | 
			
		||||
	if (mr->first_seg == -1)
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox)) {
 | 
			
		||||
		err = PTR_ERR(mailbox);
 | 
			
		||||
		goto err_out_table;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If list_len is odd, we add one more dummy entry for
 | 
			
		||||
	 * firmware efficiency.
 | 
			
		||||
	 */
 | 
			
		||||
	mailbox = kmalloc(max(sizeof *mpt_entry,
 | 
			
		||||
			      (size_t) 8 * (list_len + (list_len & 1) + 2)) +
 | 
			
		||||
			  MTHCA_CMD_MAILBOX_EXTRA,
 | 
			
		||||
			  GFP_KERNEL);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
		goto err_out_free_mtt;
 | 
			
		||||
 | 
			
		||||
	mtt_entry = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
 | 
			
		||||
	mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
 | 
			
		||||
				   mr->first_seg * MTHCA_MTT_SEG_SIZE);
 | 
			
		||||
	mtt_entry[1] = 0;
 | 
			
		||||
	for (i = 0; i < list_len; ++i)
 | 
			
		||||
		mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
 | 
			
		||||
					       MTHCA_MTT_FLAG_PRESENT);
 | 
			
		||||
	if (list_len & 1) {
 | 
			
		||||
		mtt_entry[i + 2] = 0;
 | 
			
		||||
		++list_len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (0) {
 | 
			
		||||
		mthca_dbg(dev, "Dumping MPT entry\n");
 | 
			
		||||
		for (i = 0; i < list_len + 2; ++i)
 | 
			
		||||
			printk(KERN_ERR "[%2d] %016llx\n",
 | 
			
		||||
			       i, (unsigned long long) be64_to_cpu(mtt_entry[i]));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_WRITE_MTT(dev, mtt_entry, list_len, &status);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
 | 
			
		||||
		goto err_out_mailbox_free;
 | 
			
		||||
	}
 | 
			
		||||
	if (status) {
 | 
			
		||||
		mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
 | 
			
		||||
			   status);
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err_out_mailbox_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mpt_entry = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
	mpt_entry = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 | 
			
		||||
				       MTHCA_MPT_FLAG_MIO         |
 | 
			
		||||
				       MTHCA_MPT_FLAG_REGION      |
 | 
			
		||||
				       access);
 | 
			
		||||
	if (!mr->mtt)
 | 
			
		||||
		mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL);
 | 
			
		||||
 | 
			
		||||
	mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);
 | 
			
		||||
	mpt_entry->key       = cpu_to_be32(key);
 | 
			
		||||
	mpt_entry->pd        = cpu_to_be32(pd);
 | 
			
		||||
	mpt_entry->start     = cpu_to_be64(iova);
 | 
			
		||||
	mpt_entry->length    = cpu_to_be64(total_size);
 | 
			
		||||
 | 
			
		||||
	memset(&mpt_entry->lkey, 0,
 | 
			
		||||
	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
 | 
			
		||||
	mpt_entry->mtt_seg   = cpu_to_be64(dev->mr_table.mtt_base +
 | 
			
		||||
					   mr->first_seg * MTHCA_MTT_SEG_SIZE);
 | 
			
		||||
 | 
			
		||||
	if (mr->mtt)
 | 
			
		||||
		mpt_entry->mtt_seg =
 | 
			
		||||
			cpu_to_be64(dev->mr_table.mtt_base +
 | 
			
		||||
				    mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE);
 | 
			
		||||
 | 
			
		||||
	if (0) {
 | 
			
		||||
		mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
 | 
			
		||||
| 
						 | 
				
			
			@ -416,28 +395,26 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_SW2HW_MPT(dev, mpt_entry,
 | 
			
		||||
	err = mthca_SW2HW_MPT(dev, mailbox,
 | 
			
		||||
			      key & (dev->limits.num_mpts - 1),
 | 
			
		||||
			      &status);
 | 
			
		||||
	if (err)
 | 
			
		||||
	if (err) {
 | 
			
		||||
		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
 | 
			
		||||
	else if (status) {
 | 
			
		||||
		goto err_out_mailbox;
 | 
			
		||||
	} else if (status) {
 | 
			
		||||
		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
 | 
			
		||||
			   status);
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err_out_mailbox;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return err;
 | 
			
		||||
 | 
			
		||||
err_out_mailbox_free:
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
 | 
			
		||||
err_out_free_mtt:
 | 
			
		||||
	mthca_free_mtt(dev, mr->first_seg, mr->order, &dev->mr_table.mtt_buddy);
 | 
			
		||||
err_out_mailbox:
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
 | 
			
		||||
err_out_table:
 | 
			
		||||
	if (mthca_is_memfree(dev))
 | 
			
		||||
	mthca_table_put(dev, dev->mr_table.mpt_table, key);
 | 
			
		||||
 | 
			
		||||
err_out_mpt_free:
 | 
			
		||||
| 
						 | 
				
			
			@ -445,14 +422,41 @@ err_out_mpt_free:
 | 
			
		|||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Free mr or fmr */
 | 
			
		||||
static void mthca_free_region(struct mthca_dev *dev, u32 lkey, int order,
 | 
			
		||||
			      u32 first_seg, struct mthca_buddy *buddy)
 | 
			
		||||
int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
 | 
			
		||||
			   u32 access, struct mthca_mr *mr)
 | 
			
		||||
{
 | 
			
		||||
	if (order >= 0)
 | 
			
		||||
		mthca_free_mtt(dev, first_seg, order, buddy);
 | 
			
		||||
	mr->mtt = NULL;
 | 
			
		||||
	return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	if (mthca_is_memfree(dev))
 | 
			
		||||
int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
			
		||||
			u64 *buffer_list, int buffer_size_shift,
 | 
			
		||||
			int list_len, u64 iova, u64 total_size,
 | 
			
		||||
			u32 access, struct mthca_mr *mr)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	mr->mtt = mthca_alloc_mtt(dev, list_len);
 | 
			
		||||
	if (IS_ERR(mr->mtt))
 | 
			
		||||
		return PTR_ERR(mr->mtt);
 | 
			
		||||
 | 
			
		||||
	err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		mthca_free_mtt(dev, mr->mtt);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova,
 | 
			
		||||
			     total_size, access, mr);
 | 
			
		||||
	if (err)
 | 
			
		||||
		mthca_free_mtt(dev, mr->mtt);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Free mr or fmr */
 | 
			
		||||
static void mthca_free_region(struct mthca_dev *dev, u32 lkey)
 | 
			
		||||
{
 | 
			
		||||
	mthca_table_put(dev, dev->mr_table.mpt_table,
 | 
			
		||||
			arbel_key_to_hw_index(lkey));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -476,15 +480,15 @@ void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
 | 
			
		|||
		mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",
 | 
			
		||||
			   status);
 | 
			
		||||
 | 
			
		||||
	mthca_free_region(dev, mr->ibmr.lkey, mr->order, mr->first_seg,
 | 
			
		||||
			  &dev->mr_table.mtt_buddy);
 | 
			
		||||
	mthca_free_region(dev, mr->ibmr.lkey);
 | 
			
		||||
	mthca_free_mtt(dev, mr->mtt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 | 
			
		||||
		    u32 access, struct mthca_fmr *mr)
 | 
			
		||||
{
 | 
			
		||||
	struct mthca_mpt_entry *mpt_entry;
 | 
			
		||||
	void *mailbox;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	u64 mtt_seg;
 | 
			
		||||
	u32 key, idx;
 | 
			
		||||
	u8 status;
 | 
			
		||||
| 
						 | 
				
			
			@ -522,31 +526,24 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 | 
			
		|||
		mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
 | 
			
		||||
		       	sizeof *(mr->mem.tavor.mpt) * idx;
 | 
			
		||||
 | 
			
		||||
	for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
 | 
			
		||||
	     i < list_len;
 | 
			
		||||
	     i <<= 1, ++mr->order)
 | 
			
		||||
		; /* nothing */
 | 
			
		||||
 | 
			
		||||
	mr->first_seg = mthca_alloc_mtt(dev, mr->order,
 | 
			
		||||
				       	dev->mr_table.fmr_mtt_buddy);
 | 
			
		||||
	if (mr->first_seg == -1)
 | 
			
		||||
	mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
 | 
			
		||||
	if (IS_ERR(mr->mtt))
 | 
			
		||||
		goto err_out_table;
 | 
			
		||||
 | 
			
		||||
	mtt_seg = mr->first_seg * MTHCA_MTT_SEG_SIZE;
 | 
			
		||||
	mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
 | 
			
		||||
 | 
			
		||||
	if (mthca_is_memfree(dev)) {
 | 
			
		||||
		mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
 | 
			
		||||
						      mr->first_seg);
 | 
			
		||||
						      mr->mtt->first_seg);
 | 
			
		||||
		BUG_ON(!mr->mem.arbel.mtts);
 | 
			
		||||
	} else
 | 
			
		||||
		mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
 | 
			
		||||
			  GFP_KERNEL);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		goto err_out_free_mtt;
 | 
			
		||||
 | 
			
		||||
	mpt_entry = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
	mpt_entry = mailbox->buf;
 | 
			
		||||
 | 
			
		||||
	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 | 
			
		||||
				       MTHCA_MPT_FLAG_MIO         |
 | 
			
		||||
| 
						 | 
				
			
			@ -571,7 +568,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_SW2HW_MPT(dev, mpt_entry,
 | 
			
		||||
	err = mthca_SW2HW_MPT(dev, mailbox,
 | 
			
		||||
			      key & (dev->limits.num_mpts - 1),
 | 
			
		||||
			      &status);
 | 
			
		||||
	if (err) {
 | 
			
		||||
| 
						 | 
				
			
			@ -585,18 +582,16 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 | 
			
		|||
		goto err_out_mailbox_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_out_mailbox_free:
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
 | 
			
		||||
err_out_free_mtt:
 | 
			
		||||
	mthca_free_mtt(dev, mr->first_seg, mr->order,
 | 
			
		||||
		       dev->mr_table.fmr_mtt_buddy);
 | 
			
		||||
	mthca_free_mtt(dev, mr->mtt);
 | 
			
		||||
 | 
			
		||||
err_out_table:
 | 
			
		||||
	if (mthca_is_memfree(dev))
 | 
			
		||||
	mthca_table_put(dev, dev->mr_table.mpt_table, key);
 | 
			
		||||
 | 
			
		||||
err_out_mpt_free:
 | 
			
		||||
| 
						 | 
				
			
			@ -609,8 +604,9 @@ int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr)
 | 
			
		|||
	if (fmr->maps)
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	mthca_free_region(dev, fmr->ibmr.lkey, fmr->order, fmr->first_seg,
 | 
			
		||||
			  dev->mr_table.fmr_mtt_buddy);
 | 
			
		||||
	mthca_free_region(dev, fmr->ibmr.lkey);
 | 
			
		||||
	mthca_free_mtt(dev, fmr->mtt);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -826,7 +822,8 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
 | 
			
		|||
	if (dev->limits.reserved_mtts) {
 | 
			
		||||
		i = fls(dev->limits.reserved_mtts - 1);
 | 
			
		||||
 | 
			
		||||
		if (mthca_alloc_mtt(dev, i, dev->mr_table.fmr_mtt_buddy) == -1) {
 | 
			
		||||
		if (mthca_alloc_mtt_range(dev, i,
 | 
			
		||||
					  dev->mr_table.fmr_mtt_buddy) == -1) {
 | 
			
		||||
			mthca_warn(dev, "MTT table of order %d is too small.\n",
 | 
			
		||||
				  dev->mr_table.fmr_mtt_buddy->max_order);
 | 
			
		||||
			err = -ENOMEM;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
			
		||||
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software is available to you under a choice of one of two
 | 
			
		||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +53,7 @@ static int mthca_query_device(struct ib_device *ibdev,
 | 
			
		|||
	if (!in_mad || !out_mad)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	memset(props, 0, sizeof props);
 | 
			
		||||
	memset(props, 0, sizeof *props);
 | 
			
		||||
 | 
			
		||||
	props->fw_ver              = mdev->fw_ver;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -558,6 +559,7 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd       *pd,
 | 
			
		|||
				  convert_access(acc), mr);
 | 
			
		||||
 | 
			
		||||
	if (err) {
 | 
			
		||||
		kfree(page_list);
 | 
			
		||||
		kfree(mr);
 | 
			
		||||
		return ERR_PTR(err);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,17 +54,17 @@ struct mthca_uar {
 | 
			
		|||
	int           index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mthca_mtt;
 | 
			
		||||
 | 
			
		||||
struct mthca_mr {
 | 
			
		||||
	struct ib_mr      ibmr;
 | 
			
		||||
	int order;
 | 
			
		||||
	u32 first_seg;
 | 
			
		||||
	struct mthca_mtt *mtt;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mthca_fmr {
 | 
			
		||||
	struct ib_fmr      ibmr;
 | 
			
		||||
	struct ib_fmr_attr attr;
 | 
			
		||||
	int order;
 | 
			
		||||
	u32 first_seg;
 | 
			
		||||
	struct mthca_mtt  *mtt;
 | 
			
		||||
	int                maps;
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -357,6 +357,9 @@ static const struct {
 | 
			
		|||
				[UD]  = (IB_QP_PKEY_INDEX |
 | 
			
		||||
					 IB_QP_PORT       |
 | 
			
		||||
					 IB_QP_QKEY),
 | 
			
		||||
				[UC]  = (IB_QP_PKEY_INDEX |
 | 
			
		||||
					 IB_QP_PORT       |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS),
 | 
			
		||||
				[RC]  = (IB_QP_PKEY_INDEX |
 | 
			
		||||
					 IB_QP_PORT       |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS),
 | 
			
		||||
| 
						 | 
				
			
			@ -378,6 +381,9 @@ static const struct {
 | 
			
		|||
				[UD]  = (IB_QP_PKEY_INDEX |
 | 
			
		||||
					 IB_QP_PORT       |
 | 
			
		||||
					 IB_QP_QKEY),
 | 
			
		||||
				[UC]  = (IB_QP_PKEY_INDEX |
 | 
			
		||||
					 IB_QP_PORT       |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS),
 | 
			
		||||
				[RC]  = (IB_QP_PKEY_INDEX |
 | 
			
		||||
					 IB_QP_PORT       |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS),
 | 
			
		||||
| 
						 | 
				
			
			@ -388,6 +394,11 @@ static const struct {
 | 
			
		|||
		[IB_QPS_RTR]   = {
 | 
			
		||||
			.trans = MTHCA_TRANS_INIT2RTR,
 | 
			
		||||
			.req_param = {
 | 
			
		||||
				[UC]  = (IB_QP_AV                  |
 | 
			
		||||
					 IB_QP_PATH_MTU            |
 | 
			
		||||
					 IB_QP_DEST_QPN            |
 | 
			
		||||
					 IB_QP_RQ_PSN              |
 | 
			
		||||
					 IB_QP_MAX_DEST_RD_ATOMIC),
 | 
			
		||||
				[RC]  = (IB_QP_AV                  |
 | 
			
		||||
					 IB_QP_PATH_MTU            |
 | 
			
		||||
					 IB_QP_DEST_QPN            |
 | 
			
		||||
| 
						 | 
				
			
			@ -398,6 +409,9 @@ static const struct {
 | 
			
		|||
			.opt_param = {
 | 
			
		||||
				[UD]  = (IB_QP_PKEY_INDEX |
 | 
			
		||||
					 IB_QP_QKEY),
 | 
			
		||||
				[UC]  = (IB_QP_ALT_PATH     |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS |
 | 
			
		||||
					 IB_QP_PKEY_INDEX),
 | 
			
		||||
				[RC]  = (IB_QP_ALT_PATH     |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS |
 | 
			
		||||
					 IB_QP_PKEY_INDEX),
 | 
			
		||||
| 
						 | 
				
			
			@ -413,6 +427,8 @@ static const struct {
 | 
			
		|||
			.trans = MTHCA_TRANS_RTR2RTS,
 | 
			
		||||
			.req_param = {
 | 
			
		||||
				[UD]  = IB_QP_SQ_PSN,
 | 
			
		||||
				[UC]  = (IB_QP_SQ_PSN            |
 | 
			
		||||
					 IB_QP_MAX_QP_RD_ATOMIC),
 | 
			
		||||
				[RC]  = (IB_QP_TIMEOUT           |
 | 
			
		||||
					 IB_QP_RETRY_CNT         |
 | 
			
		||||
					 IB_QP_RNR_RETRY         |
 | 
			
		||||
| 
						 | 
				
			
			@ -423,6 +439,11 @@ static const struct {
 | 
			
		|||
			.opt_param = {
 | 
			
		||||
				[UD]  = (IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_QKEY),
 | 
			
		||||
				[UC]  = (IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_ALT_PATH              |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS          |
 | 
			
		||||
					 IB_QP_PKEY_INDEX            |
 | 
			
		||||
					 IB_QP_PATH_MIG_STATE),
 | 
			
		||||
				[RC]  = (IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_ALT_PATH              |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS          |
 | 
			
		||||
| 
						 | 
				
			
			@ -442,6 +463,9 @@ static const struct {
 | 
			
		|||
			.opt_param = {
 | 
			
		||||
				[UD]  = (IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_QKEY),
 | 
			
		||||
				[UC]  = (IB_QP_ACCESS_FLAGS          |
 | 
			
		||||
					 IB_QP_ALT_PATH              |
 | 
			
		||||
					 IB_QP_PATH_MIG_STATE),
 | 
			
		||||
				[RC]  = (IB_QP_ACCESS_FLAGS          |
 | 
			
		||||
					 IB_QP_ALT_PATH              |
 | 
			
		||||
					 IB_QP_PATH_MIG_STATE        |
 | 
			
		||||
| 
						 | 
				
			
			@ -462,6 +486,10 @@ static const struct {
 | 
			
		|||
			.opt_param = {
 | 
			
		||||
				[UD]  = (IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_QKEY),
 | 
			
		||||
				[UC]  = (IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_ALT_PATH              |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS          |
 | 
			
		||||
					 IB_QP_PATH_MIG_STATE),
 | 
			
		||||
				[RC]  = (IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_ALT_PATH              |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS          |
 | 
			
		||||
| 
						 | 
				
			
			@ -476,6 +504,14 @@ static const struct {
 | 
			
		|||
			.opt_param = {
 | 
			
		||||
				[UD]  = (IB_QP_PKEY_INDEX            |
 | 
			
		||||
					 IB_QP_QKEY),
 | 
			
		||||
				[UC]  = (IB_QP_AV                    |
 | 
			
		||||
					 IB_QP_MAX_QP_RD_ATOMIC      |
 | 
			
		||||
					 IB_QP_MAX_DEST_RD_ATOMIC    |
 | 
			
		||||
					 IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_ALT_PATH              |
 | 
			
		||||
					 IB_QP_ACCESS_FLAGS          |
 | 
			
		||||
					 IB_QP_PKEY_INDEX            |
 | 
			
		||||
					 IB_QP_PATH_MIG_STATE),
 | 
			
		||||
				[RC]  = (IB_QP_AV                    |
 | 
			
		||||
					 IB_QP_TIMEOUT               |
 | 
			
		||||
					 IB_QP_RETRY_CNT             |
 | 
			
		||||
| 
						 | 
				
			
			@ -501,6 +537,7 @@ static const struct {
 | 
			
		|||
			.opt_param = {
 | 
			
		||||
				[UD]  = (IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_QKEY),
 | 
			
		||||
				[UC]  = (IB_QP_CUR_STATE),
 | 
			
		||||
				[RC]  = (IB_QP_CUR_STATE             |
 | 
			
		||||
					 IB_QP_MIN_RNR_TIMER),
 | 
			
		||||
				[MLX] = (IB_QP_CUR_STATE             |
 | 
			
		||||
| 
						 | 
				
			
			@ -552,7 +589,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
	struct mthca_dev *dev = to_mdev(ibqp->device);
 | 
			
		||||
	struct mthca_qp *qp = to_mqp(ibqp);
 | 
			
		||||
	enum ib_qp_state cur_state, new_state;
 | 
			
		||||
	void *mailbox = NULL;
 | 
			
		||||
	struct mthca_mailbox *mailbox;
 | 
			
		||||
	struct mthca_qp_param *qp_param;
 | 
			
		||||
	struct mthca_qp_context *qp_context;
 | 
			
		||||
	u32 req_param, opt_param;
 | 
			
		||||
| 
						 | 
				
			
			@ -609,10 +646,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mailbox = kmalloc(sizeof (*qp_param) + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
 | 
			
		||||
	if (!mailbox)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	qp_param = MAILBOX_ALIGN(mailbox);
 | 
			
		||||
	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
			
		||||
	if (IS_ERR(mailbox))
 | 
			
		||||
		return PTR_ERR(mailbox);
 | 
			
		||||
	qp_param = mailbox->buf;
 | 
			
		||||
	qp_context = &qp_param->context;
 | 
			
		||||
	memset(qp_param, 0, sizeof *qp_param);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -683,7 +720,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
	if (attr_mask & IB_QP_AV) {
 | 
			
		||||
		qp_context->pri_path.g_mylmc     = attr->ah_attr.src_path_bits & 0x7f;
 | 
			
		||||
		qp_context->pri_path.rlid        = cpu_to_be16(attr->ah_attr.dlid);
 | 
			
		||||
		qp_context->pri_path.static_rate = (!!attr->ah_attr.static_rate) << 3;
 | 
			
		||||
		qp_context->pri_path.static_rate = !!attr->ah_attr.static_rate;
 | 
			
		||||
		if (attr->ah_attr.ah_flags & IB_AH_GRH) {
 | 
			
		||||
			qp_context->pri_path.g_mylmc |= 1 << 7;
 | 
			
		||||
			qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index;
 | 
			
		||||
| 
						 | 
				
			
			@ -724,9 +761,9 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RETRY_COUNT);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
 | 
			
		||||
		qp_context->params1 |= cpu_to_be32(min(attr->max_dest_rd_atomic ?
 | 
			
		||||
						       ffs(attr->max_dest_rd_atomic) - 1 : 0,
 | 
			
		||||
	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
 | 
			
		||||
		qp_context->params1 |= cpu_to_be32(min(attr->max_rd_atomic ?
 | 
			
		||||
						       ffs(attr->max_rd_atomic) - 1 : 0,
 | 
			
		||||
						       7) << 21);
 | 
			
		||||
		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -764,10 +801,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
		qp->atomic_rd_en = attr->qp_access_flags;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
 | 
			
		||||
	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
 | 
			
		||||
		u8 rra_max;
 | 
			
		||||
 | 
			
		||||
		if (qp->resp_depth && !attr->max_rd_atomic) {
 | 
			
		||||
		if (qp->resp_depth && !attr->max_dest_rd_atomic) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * Lowering our responder resources to zero.
 | 
			
		||||
			 * Turn off RDMA/atomics as responder.
 | 
			
		||||
| 
						 | 
				
			
			@ -778,7 +815,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
								MTHCA_QP_OPTPAR_RAE);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!qp->resp_depth && attr->max_rd_atomic) {
 | 
			
		||||
		if (!qp->resp_depth && attr->max_dest_rd_atomic) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * Increasing our responder resources from
 | 
			
		||||
			 * zero.  Turn on RDMA/atomics as appropriate.
 | 
			
		||||
| 
						 | 
				
			
			@ -799,7 +836,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		for (rra_max = 0;
 | 
			
		||||
		     1 << rra_max < attr->max_rd_atomic &&
 | 
			
		||||
		     1 << rra_max < attr->max_dest_rd_atomic &&
 | 
			
		||||
			     rra_max < dev->qp_table.rdb_shift;
 | 
			
		||||
		     ++rra_max)
 | 
			
		||||
			; /* nothing */
 | 
			
		||||
| 
						 | 
				
			
			@ -807,7 +844,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
		qp_context->params2      |= cpu_to_be32(rra_max << 21);
 | 
			
		||||
		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX);
 | 
			
		||||
 | 
			
		||||
		qp->resp_depth = attr->max_rd_atomic;
 | 
			
		||||
		qp->resp_depth = attr->max_dest_rd_atomic;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
 | 
			
		||||
| 
						 | 
				
			
			@ -835,7 +872,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
 | 
			
		||||
			      qp->qpn, 0, qp_param, 0, &status);
 | 
			
		||||
			      qp->qpn, 0, mailbox, 0, &status);
 | 
			
		||||
	if (status) {
 | 
			
		||||
		mthca_warn(dev, "modify QP %d returned status %02x.\n",
 | 
			
		||||
			   state_table[cur_state][new_state].trans, status);
 | 
			
		||||
| 
						 | 
				
			
			@ -845,7 +882,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
			
		|||
	if (!err)
 | 
			
		||||
		qp->state = new_state;
 | 
			
		||||
 | 
			
		||||
	kfree(mailbox);
 | 
			
		||||
	mthca_free_mailbox(dev, mailbox);
 | 
			
		||||
 | 
			
		||||
	if (is_sqp(dev, qp))
 | 
			
		||||
		store_attrs(to_msqp(qp), attr, attr_mask);
 | 
			
		||||
| 
						 | 
				
			
			@ -934,7 +971,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
 | 
			
		|||
			mthca_dbg(dev, "Creating direct QP of size %d (shift %d)\n",
 | 
			
		||||
				  size, shift);
 | 
			
		||||
 | 
			
		||||
		qp->queue.direct.buf = pci_alloc_consistent(dev->pdev, size, &t);
 | 
			
		||||
		qp->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev, size,
 | 
			
		||||
							  &t, GFP_KERNEL);
 | 
			
		||||
		if (!qp->queue.direct.buf)
 | 
			
		||||
			goto err_out;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -973,7 +1011,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
 | 
			
		|||
 | 
			
		||||
		for (i = 0; i < npages; ++i) {
 | 
			
		||||
			qp->queue.page_list[i].buf =
 | 
			
		||||
				pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
 | 
			
		||||
				dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
			
		||||
						   &t, GFP_KERNEL);
 | 
			
		||||
			if (!qp->queue.page_list[i].buf)
 | 
			
		||||
				goto err_out_free;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -996,13 +1035,12 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
 | 
			
		|||
 | 
			
		||||
 err_out_free:
 | 
			
		||||
	if (qp->is_direct) {
 | 
			
		||||
		pci_free_consistent(dev->pdev, size,
 | 
			
		||||
				    qp->queue.direct.buf,
 | 
			
		||||
		dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
 | 
			
		||||
				  pci_unmap_addr(&qp->queue.direct, mapping));
 | 
			
		||||
	} else
 | 
			
		||||
		for (i = 0; i < npages; ++i) {
 | 
			
		||||
			if (qp->queue.page_list[i].buf)
 | 
			
		||||
				pci_free_consistent(dev->pdev, PAGE_SIZE,
 | 
			
		||||
				dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
			
		||||
						  qp->queue.page_list[i].buf,
 | 
			
		||||
						  pci_unmap_addr(&qp->queue.page_list[i],
 | 
			
		||||
								 mapping));
 | 
			
		||||
| 
						 | 
				
			
			@ -1073,12 +1111,13 @@ static void mthca_free_memfree(struct mthca_dev *dev,
 | 
			
		|||
	if (mthca_is_memfree(dev)) {
 | 
			
		||||
		mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
 | 
			
		||||
		mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mthca_table_put(dev, dev->qp_table.rdb_table,
 | 
			
		||||
			qp->qpn << dev->qp_table.rdb_shift);
 | 
			
		||||
	mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
 | 
			
		||||
	mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void mthca_wq_init(struct mthca_wq* wq)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1529,6 +1568,26 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 | 
			
		|||
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case UC:
 | 
			
		||||
			switch (wr->opcode) {
 | 
			
		||||
			case IB_WR_RDMA_WRITE:
 | 
			
		||||
			case IB_WR_RDMA_WRITE_WITH_IMM:
 | 
			
		||||
				((struct mthca_raddr_seg *) wqe)->raddr =
 | 
			
		||||
					cpu_to_be64(wr->wr.rdma.remote_addr);
 | 
			
		||||
				((struct mthca_raddr_seg *) wqe)->rkey =
 | 
			
		||||
					cpu_to_be32(wr->wr.rdma.rkey);
 | 
			
		||||
				((struct mthca_raddr_seg *) wqe)->reserved = 0;
 | 
			
		||||
				wqe += sizeof (struct mthca_raddr_seg);
 | 
			
		||||
				size += sizeof (struct mthca_raddr_seg) / 16;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				/* No extra segments required for sends */
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case UD:
 | 
			
		||||
			((struct mthca_tavor_ud_seg *) wqe)->lkey =
 | 
			
		||||
				cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
 | 
			
		||||
| 
						 | 
				
			
			@ -1814,9 +1873,29 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 | 
			
		|||
					sizeof (struct mthca_atomic_seg);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case IB_WR_RDMA_READ:
 | 
			
		||||
			case IB_WR_RDMA_WRITE:
 | 
			
		||||
			case IB_WR_RDMA_WRITE_WITH_IMM:
 | 
			
		||||
				((struct mthca_raddr_seg *) wqe)->raddr =
 | 
			
		||||
					cpu_to_be64(wr->wr.rdma.remote_addr);
 | 
			
		||||
				((struct mthca_raddr_seg *) wqe)->rkey =
 | 
			
		||||
					cpu_to_be32(wr->wr.rdma.rkey);
 | 
			
		||||
				((struct mthca_raddr_seg *) wqe)->reserved = 0;
 | 
			
		||||
				wqe += sizeof (struct mthca_raddr_seg);
 | 
			
		||||
				size += sizeof (struct mthca_raddr_seg) / 16;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				/* No extra segments required for sends */
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case UC:
 | 
			
		||||
			switch (wr->opcode) {
 | 
			
		||||
			case IB_WR_RDMA_WRITE:
 | 
			
		||||
			case IB_WR_RDMA_WRITE_WITH_IMM:
 | 
			
		||||
			case IB_WR_RDMA_READ:
 | 
			
		||||
				((struct mthca_raddr_seg *) wqe)->raddr =
 | 
			
		||||
					cpu_to_be64(wr->wr.rdma.remote_addr);
 | 
			
		||||
				((struct mthca_raddr_seg *) wqe)->rkey =
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,7 @@
 | 
			
		|||
#include <linux/smp_lock.h>
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
#include <linux/devfs_fs_kernel.h>
 | 
			
		||||
#include <linux/compat.h>
 | 
			
		||||
 | 
			
		||||
struct evdev {
 | 
			
		||||
	int exist;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
struct input_event_compat {
 | 
			
		||||
	struct compat_timeval time;
 | 
			
		||||
	__u16 type;
 | 
			
		||||
	__u16 code;
 | 
			
		||||
	__s32 value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_X86_64
 | 
			
		||||
#  define COMPAT_TEST test_thread_flag(TIF_IA32)
 | 
			
		||||
#elif defined(CONFIG_IA64)
 | 
			
		||||
#  define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
 | 
			
		||||
#elif defined(CONFIG_ARCH_S390)
 | 
			
		||||
#  define COMPAT_TEST test_thread_flag(TIF_31BIT)
 | 
			
		||||
#else
 | 
			
		||||
#  define COMPAT_TEST test_thread_flag(TIF_32BIT)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
 | 
			
		||||
{
 | 
			
		||||
	struct evdev_list *list = file->private_data;
 | 
			
		||||
	struct input_event_compat event;
 | 
			
		||||
	int retval = 0;
 | 
			
		||||
 | 
			
		||||
	while (retval < count) {
 | 
			
		||||
		if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
 | 
			
		||||
			return -EFAULT;
 | 
			
		||||
		input_event(list->evdev->handle.dev, event.type, event.code, event.value);
 | 
			
		||||
		retval += sizeof(struct input_event_compat);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
 | 
			
		||||
{
 | 
			
		||||
	struct evdev_list *list = file->private_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +189,11 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
 | 
			
		|||
 | 
			
		||||
	if (!list->evdev->exist) return -ENODEV;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
	if (COMPAT_TEST)
 | 
			
		||||
		return evdev_write_compat(file, buffer, count, ppos);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	while (retval < count) {
 | 
			
		||||
 | 
			
		||||
		if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
 | 
			
		||||
| 
						 | 
				
			
			@ -164,11 +205,56 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
 | 
			
		|||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 | 
			
		||||
{
 | 
			
		||||
	struct evdev_list *list = file->private_data;
 | 
			
		||||
	int retval;
 | 
			
		||||
 | 
			
		||||
	if (count < sizeof(struct input_event_compat))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
 | 
			
		||||
	retval = wait_event_interruptible(list->evdev->wait,
 | 
			
		||||
		list->head != list->tail || (!list->evdev->exist));
 | 
			
		||||
 | 
			
		||||
	if (retval)
 | 
			
		||||
		return retval;
 | 
			
		||||
 | 
			
		||||
	if (!list->evdev->exist)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) {
 | 
			
		||||
		struct input_event *event = (struct input_event *) list->buffer + list->tail;
 | 
			
		||||
		struct input_event_compat event_compat;
 | 
			
		||||
		event_compat.time.tv_sec = event->time.tv_sec;
 | 
			
		||||
		event_compat.time.tv_usec = event->time.tv_usec;
 | 
			
		||||
		event_compat.type = event->type;
 | 
			
		||||
		event_compat.code = event->code;
 | 
			
		||||
		event_compat.value = event->value;
 | 
			
		||||
 | 
			
		||||
		if (copy_to_user(buffer + retval, &event_compat,
 | 
			
		||||
			sizeof(struct input_event_compat))) return -EFAULT;
 | 
			
		||||
		list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
 | 
			
		||||
		retval += sizeof(struct input_event_compat);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 | 
			
		||||
{
 | 
			
		||||
	struct evdev_list *list = file->private_data;
 | 
			
		||||
	int retval;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
	if (COMPAT_TEST)
 | 
			
		||||
		return evdev_read_compat(file, buffer, count, ppos);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (count < sizeof(struct input_event))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -203,7 +289,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
 | 
			
		|||
		(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 | 
			
		||||
static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 | 
			
		||||
{
 | 
			
		||||
	struct evdev_list *list = file->private_data;
 | 
			
		||||
	struct evdev *evdev = list->evdev;
 | 
			
		||||
| 
						 | 
				
			
			@ -285,9 +371,11 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 | 
			
		|||
 | 
			
		||||
		default:
 | 
			
		||||
 | 
			
		||||
			if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
 | 
			
		||||
			if (_IOC_TYPE(cmd) != 'E')
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
 | 
			
		||||
			if (_IOC_DIR(cmd) == _IOC_READ) {
 | 
			
		||||
 | 
			
		||||
				if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
 | 
			
		||||
 | 
			
		||||
					long *bits;
 | 
			
		||||
| 
						 | 
				
			
			@ -370,6 +458,10 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 | 
			
		|||
					return 0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (_IOC_DIR(cmd) == _IOC_WRITE) {
 | 
			
		||||
 | 
			
		||||
				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 | 
			
		||||
 | 
			
		||||
					int t = _IOC_NR(cmd) & ABS_MAX;
 | 
			
		||||
| 
						 | 
				
			
			@ -386,9 +478,161 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 | 
			
		|||
					return 0;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
	}
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
 | 
			
		||||
#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
 | 
			
		||||
#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1)
 | 
			
		||||
#define OFF_COMPAT(x)  ((x)%BITS_PER_LONG_COMPAT)
 | 
			
		||||
#define BIT_COMPAT(x)  (1UL<<OFF_COMPAT(x))
 | 
			
		||||
#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT)
 | 
			
		||||
#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1)
 | 
			
		||||
 | 
			
		||||
#ifdef __BIG_ENDIAN
 | 
			
		||||
#define bit_to_user(bit, max) \
 | 
			
		||||
do { \
 | 
			
		||||
	int i; \
 | 
			
		||||
	int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
 | 
			
		||||
	if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
 | 
			
		||||
	for (i = 0; i < len / sizeof(compat_long_t); i++) \
 | 
			
		||||
		if (copy_to_user((compat_long_t*) p + i, \
 | 
			
		||||
				 (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \
 | 
			
		||||
				 sizeof(compat_long_t))) \
 | 
			
		||||
			return -EFAULT; \
 | 
			
		||||
	return len; \
 | 
			
		||||
} while (0)
 | 
			
		||||
#else
 | 
			
		||||
#define bit_to_user(bit, max) \
 | 
			
		||||
do { \
 | 
			
		||||
	int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
 | 
			
		||||
	if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
 | 
			
		||||
	return copy_to_user(p, (bit), len) ? -EFAULT : len; \
 | 
			
		||||
} while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 | 
			
		||||
{
 | 
			
		||||
	struct evdev_list *list = file->private_data;
 | 
			
		||||
	struct evdev *evdev = list->evdev;
 | 
			
		||||
	struct input_dev *dev = evdev->handle.dev;
 | 
			
		||||
	struct input_absinfo abs;
 | 
			
		||||
	void __user *p = compat_ptr(arg);
 | 
			
		||||
 | 
			
		||||
	if (!evdev->exist) return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	switch (cmd) {
 | 
			
		||||
 | 
			
		||||
		case EVIOCGVERSION:
 | 
			
		||||
		case EVIOCGID:
 | 
			
		||||
		case EVIOCGKEYCODE:
 | 
			
		||||
		case EVIOCSKEYCODE:
 | 
			
		||||
		case EVIOCSFF:
 | 
			
		||||
		case EVIOCRMFF:
 | 
			
		||||
		case EVIOCGEFFECTS:
 | 
			
		||||
		case EVIOCGRAB:
 | 
			
		||||
			return evdev_ioctl(file, cmd, (unsigned long) p);
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
 | 
			
		||||
			if (_IOC_TYPE(cmd) != 'E')
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
 | 
			
		||||
			if (_IOC_DIR(cmd) == _IOC_READ) {
 | 
			
		||||
 | 
			
		||||
				if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
 | 
			
		||||
					long *bits;
 | 
			
		||||
					int max;
 | 
			
		||||
 | 
			
		||||
					switch (_IOC_NR(cmd) & EV_MAX) {
 | 
			
		||||
						case      0: bits = dev->evbit;  max = EV_MAX;  break;
 | 
			
		||||
						case EV_KEY: bits = dev->keybit; max = KEY_MAX; break;
 | 
			
		||||
						case EV_REL: bits = dev->relbit; max = REL_MAX; break;
 | 
			
		||||
						case EV_ABS: bits = dev->absbit; max = ABS_MAX; break;
 | 
			
		||||
						case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break;
 | 
			
		||||
						case EV_LED: bits = dev->ledbit; max = LED_MAX; break;
 | 
			
		||||
						case EV_SND: bits = dev->sndbit; max = SND_MAX; break;
 | 
			
		||||
						case EV_FF:  bits = dev->ffbit;  max = FF_MAX;  break;
 | 
			
		||||
						default: return -EINVAL;
 | 
			
		||||
					}
 | 
			
		||||
					bit_to_user(bits, max);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
 | 
			
		||||
					bit_to_user(dev->key, KEY_MAX);
 | 
			
		||||
 | 
			
		||||
				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
 | 
			
		||||
					bit_to_user(dev->led, LED_MAX);
 | 
			
		||||
 | 
			
		||||
				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
 | 
			
		||||
					bit_to_user(dev->snd, SND_MAX);
 | 
			
		||||
 | 
			
		||||
				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
 | 
			
		||||
					int len;
 | 
			
		||||
					if (!dev->name) return -ENOENT;
 | 
			
		||||
					len = strlen(dev->name) + 1;
 | 
			
		||||
					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
			
		||||
					return copy_to_user(p, dev->name, len) ? -EFAULT : len;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
 | 
			
		||||
					int len;
 | 
			
		||||
					if (!dev->phys) return -ENOENT;
 | 
			
		||||
					len = strlen(dev->phys) + 1;
 | 
			
		||||
					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
			
		||||
					return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
 | 
			
		||||
					int len;
 | 
			
		||||
					if (!dev->uniq) return -ENOENT;
 | 
			
		||||
					len = strlen(dev->uniq) + 1;
 | 
			
		||||
					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
			
		||||
					return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 | 
			
		||||
 | 
			
		||||
					int t = _IOC_NR(cmd) & ABS_MAX;
 | 
			
		||||
 | 
			
		||||
					abs.value = dev->abs[t];
 | 
			
		||||
					abs.minimum = dev->absmin[t];
 | 
			
		||||
					abs.maximum = dev->absmax[t];
 | 
			
		||||
					abs.fuzz = dev->absfuzz[t];
 | 
			
		||||
					abs.flat = dev->absflat[t];
 | 
			
		||||
 | 
			
		||||
					if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
 | 
			
		||||
						return -EFAULT;
 | 
			
		||||
 | 
			
		||||
					return 0;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (_IOC_DIR(cmd) == _IOC_WRITE) {
 | 
			
		||||
 | 
			
		||||
				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 | 
			
		||||
 | 
			
		||||
					int t = _IOC_NR(cmd) & ABS_MAX;
 | 
			
		||||
 | 
			
		||||
					if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
 | 
			
		||||
						return -EFAULT;
 | 
			
		||||
 | 
			
		||||
					dev->abs[t] = abs.value;
 | 
			
		||||
					dev->absmin[t] = abs.minimum;
 | 
			
		||||
					dev->absmax[t] = abs.maximum;
 | 
			
		||||
					dev->absfuzz[t] = abs.fuzz;
 | 
			
		||||
					dev->absflat[t] = abs.flat;
 | 
			
		||||
 | 
			
		||||
					return 0;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
	}
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct file_operations evdev_fops = {
 | 
			
		||||
	.owner =	THIS_MODULE,
 | 
			
		||||
	.read =		evdev_read,
 | 
			
		||||
| 
						 | 
				
			
			@ -396,7 +640,10 @@ static struct file_operations evdev_fops = {
 | 
			
		|||
	.poll =		evdev_poll,
 | 
			
		||||
	.open =		evdev_open,
 | 
			
		||||
	.release =	evdev_release,
 | 
			
		||||
	.ioctl =	evdev_ioctl,
 | 
			
		||||
	.unlocked_ioctl = evdev_ioctl,
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
	.compat_ioctl =	evdev_ioctl_compat,
 | 
			
		||||
#endif
 | 
			
		||||
	.fasync =	evdev_fasync,
 | 
			
		||||
	.flush =	evdev_flush
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,22 +49,8 @@ config GAMEPORT_EMU10K1
 | 
			
		|||
	  To compile this driver as a module, choose M here: the
 | 
			
		||||
	  module will be called emu10k1-gp.
 | 
			
		||||
 | 
			
		||||
config GAMEPORT_VORTEX
 | 
			
		||||
	tristate "Aureal Vortex, Vortex 2 gameport support"
 | 
			
		||||
	depends on PCI
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here if you have an Aureal Vortex 1 or 2  card and want
 | 
			
		||||
	  to use its gameport.
 | 
			
		||||
 | 
			
		||||
	  To compile this driver as a module, choose M here: the
 | 
			
		||||
	  module will be called vortex.
 | 
			
		||||
 | 
			
		||||
config GAMEPORT_FM801
 | 
			
		||||
	tristate "ForteMedia FM801 gameport support"
 | 
			
		||||
	depends on PCI
 | 
			
		||||
 | 
			
		||||
config GAMEPORT_CS461X
 | 
			
		||||
	tristate "Crystal SoundFusion gameport support"
 | 
			
		||||
	depends on PCI
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,9 +5,7 @@
 | 
			
		|||
# Each configuration option enables a list of files.
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_GAMEPORT)		+= gameport.o
 | 
			
		||||
obj-$(CONFIG_GAMEPORT_CS461X)	+= cs461x.o
 | 
			
		||||
obj-$(CONFIG_GAMEPORT_EMU10K1)	+= emu10k1-gp.o
 | 
			
		||||
obj-$(CONFIG_GAMEPORT_FM801)	+= fm801-gp.o
 | 
			
		||||
obj-$(CONFIG_GAMEPORT_L4)	+= lightning.o
 | 
			
		||||
obj-$(CONFIG_GAMEPORT_NS558)	+= ns558.o
 | 
			
		||||
obj-$(CONFIG_GAMEPORT_VORTEX)	+= vortex.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,322 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
	The all defines and part of code (such as cs461x_*) are
 | 
			
		||||
	contributed from ALSA 0.5.8 sources.
 | 
			
		||||
	See http://www.alsa-project.org/ for sources
 | 
			
		||||
 | 
			
		||||
	Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <asm/io.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/ioport.h>
 | 
			
		||||
#include <linux/config.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/gameport.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/pci.h>
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Victor Krapivin");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	These options are experimental
 | 
			
		||||
 | 
			
		||||
#define CS461X_FULL_MAP
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef PCI_VENDOR_ID_CIRRUS
 | 
			
		||||
#define PCI_VENDOR_ID_CIRRUS            0x1013
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef PCI_DEVICE_ID_CIRRUS_4610
 | 
			
		||||
#define PCI_DEVICE_ID_CIRRUS_4610       0x6001
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef PCI_DEVICE_ID_CIRRUS_4612
 | 
			
		||||
#define PCI_DEVICE_ID_CIRRUS_4612       0x6003
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef PCI_DEVICE_ID_CIRRUS_4615
 | 
			
		||||
#define PCI_DEVICE_ID_CIRRUS_4615       0x6004
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Registers */
 | 
			
		||||
 | 
			
		||||
#define BA0_JSPT                                0x00000480
 | 
			
		||||
#define BA0_JSCTL                               0x00000484
 | 
			
		||||
#define BA0_JSC1                                0x00000488
 | 
			
		||||
#define BA0_JSC2                                0x0000048C
 | 
			
		||||
#define BA0_JSIO                                0x000004A0
 | 
			
		||||
 | 
			
		||||
/* Bits for JSPT */
 | 
			
		||||
 | 
			
		||||
#define JSPT_CAX                                0x00000001
 | 
			
		||||
#define JSPT_CAY                                0x00000002
 | 
			
		||||
#define JSPT_CBX                                0x00000004
 | 
			
		||||
#define JSPT_CBY                                0x00000008
 | 
			
		||||
#define JSPT_BA1                                0x00000010
 | 
			
		||||
#define JSPT_BA2                                0x00000020
 | 
			
		||||
#define JSPT_BB1                                0x00000040
 | 
			
		||||
#define JSPT_BB2                                0x00000080
 | 
			
		||||
 | 
			
		||||
/* Bits for JSCTL */
 | 
			
		||||
 | 
			
		||||
#define JSCTL_SP_MASK                           0x00000003
 | 
			
		||||
#define JSCTL_SP_SLOW                           0x00000000
 | 
			
		||||
#define JSCTL_SP_MEDIUM_SLOW                    0x00000001
 | 
			
		||||
#define JSCTL_SP_MEDIUM_FAST                    0x00000002
 | 
			
		||||
#define JSCTL_SP_FAST                           0x00000003
 | 
			
		||||
#define JSCTL_ARE                               0x00000004
 | 
			
		||||
 | 
			
		||||
/* Data register pairs masks */
 | 
			
		||||
 | 
			
		||||
#define JSC1_Y1V_MASK                           0x0000FFFF
 | 
			
		||||
#define JSC1_X1V_MASK                           0xFFFF0000
 | 
			
		||||
#define JSC1_Y1V_SHIFT                          0
 | 
			
		||||
#define JSC1_X1V_SHIFT                          16
 | 
			
		||||
#define JSC2_Y2V_MASK                           0x0000FFFF
 | 
			
		||||
#define JSC2_X2V_MASK                           0xFFFF0000
 | 
			
		||||
#define JSC2_Y2V_SHIFT                          0
 | 
			
		||||
#define JSC2_X2V_SHIFT                          16
 | 
			
		||||
 | 
			
		||||
/* JS GPIO */
 | 
			
		||||
 | 
			
		||||
#define JSIO_DAX                                0x00000001
 | 
			
		||||
#define JSIO_DAY                                0x00000002
 | 
			
		||||
#define JSIO_DBX                                0x00000004
 | 
			
		||||
#define JSIO_DBY                                0x00000008
 | 
			
		||||
#define JSIO_AXOE                               0x00000010
 | 
			
		||||
#define JSIO_AYOE                               0x00000020
 | 
			
		||||
#define JSIO_BXOE                               0x00000040
 | 
			
		||||
#define JSIO_BYOE                               0x00000080
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   The card initialization code is obfuscated; the module cs461x
 | 
			
		||||
   need to be loaded after ALSA modules initialized and something
 | 
			
		||||
   played on the CS 4610 chip (see sources for details of CS4610
 | 
			
		||||
   initialization code from ALSA)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/* Card specific definitions */
 | 
			
		||||
 | 
			
		||||
#define CS461X_BA0_SIZE         0x2000
 | 
			
		||||
#define CS461X_BA1_DATA0_SIZE   0x3000
 | 
			
		||||
#define CS461X_BA1_DATA1_SIZE   0x3800
 | 
			
		||||
#define CS461X_BA1_PRG_SIZE     0x7000
 | 
			
		||||
#define CS461X_BA1_REG_SIZE     0x0100
 | 
			
		||||
 | 
			
		||||
#define BA1_SP_DMEM0                            0x00000000
 | 
			
		||||
#define BA1_SP_DMEM1                            0x00010000
 | 
			
		||||
#define BA1_SP_PMEM                             0x00020000
 | 
			
		||||
#define BA1_SP_REG                              0x00030000
 | 
			
		||||
 | 
			
		||||
#define BA1_DWORD_SIZE          (13 * 1024 + 512)
 | 
			
		||||
#define BA1_MEMORY_COUNT        3
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Only one CS461x card is still suppoted; the code requires
 | 
			
		||||
   redesign to avoid this limitatuion.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
static unsigned long ba0_addr;
 | 
			
		||||
static unsigned int __iomem *ba0;
 | 
			
		||||
 | 
			
		||||
#ifdef CS461X_FULL_MAP
 | 
			
		||||
static unsigned long ba1_addr;
 | 
			
		||||
static union ba1_t {
 | 
			
		||||
        struct {
 | 
			
		||||
                unsigned int __iomem *data0;
 | 
			
		||||
                unsigned int __iomem *data1;
 | 
			
		||||
                unsigned int __iomem *pmem;
 | 
			
		||||
                unsigned int __iomem *reg;
 | 
			
		||||
        } name;
 | 
			
		||||
        unsigned int __iomem *idx[4];
 | 
			
		||||
} ba1;
 | 
			
		||||
 | 
			
		||||
static void cs461x_poke(unsigned long reg, unsigned int val)
 | 
			
		||||
{
 | 
			
		||||
        writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned int cs461x_peek(unsigned long reg)
 | 
			
		||||
{
 | 
			
		||||
        return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
 | 
			
		||||
{
 | 
			
		||||
        writel(val, &ba0[reg >> 2]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned int cs461x_peekBA0(unsigned long reg)
 | 
			
		||||
{
 | 
			
		||||
        return readl(&ba0[reg >> 2]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cs461x_free(struct pci_dev *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct gameport *port = pci_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	if (port)
 | 
			
		||||
	    gameport_unregister_port(port);
 | 
			
		||||
 | 
			
		||||
	if (ba0) iounmap(ba0);
 | 
			
		||||
#ifdef CS461X_FULL_MAP
 | 
			
		||||
	if (ba1.name.data0) iounmap(ba1.name.data0);
 | 
			
		||||
	if (ba1.name.data1) iounmap(ba1.name.data1);
 | 
			
		||||
	if (ba1.name.pmem)  iounmap(ba1.name.pmem);
 | 
			
		||||
	if (ba1.name.reg)   iounmap(ba1.name.reg);
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cs461x_gameport_trigger(struct gameport *gameport)
 | 
			
		||||
{
 | 
			
		||||
	cs461x_pokeBA0(BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned char cs461x_gameport_read(struct gameport *gameport)
 | 
			
		||||
{
 | 
			
		||||
	return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 | 
			
		||||
{
 | 
			
		||||
	unsigned js1, js2, jst;
 | 
			
		||||
 | 
			
		||||
	js1 = cs461x_peekBA0(BA0_JSC1);
 | 
			
		||||
	js2 = cs461x_peekBA0(BA0_JSC2);
 | 
			
		||||
	jst = cs461x_peekBA0(BA0_JSPT);
 | 
			
		||||
 | 
			
		||||
	*buttons = (~jst >> 4) & 0x0F;
 | 
			
		||||
 | 
			
		||||
	axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
 | 
			
		||||
	axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
 | 
			
		||||
	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
 | 
			
		||||
	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
 | 
			
		||||
 | 
			
		||||
	for(jst=0;jst<4;++jst)
 | 
			
		||||
		if(axes[jst]==0xFFFF) axes[jst] = -1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cs461x_gameport_open(struct gameport *gameport, int mode)
 | 
			
		||||
{
 | 
			
		||||
	switch (mode) {
 | 
			
		||||
		case GAMEPORT_MODE_COOKED:
 | 
			
		||||
		case GAMEPORT_MODE_RAW:
 | 
			
		||||
			return 0;
 | 
			
		||||
		default:
 | 
			
		||||
			return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct pci_device_id cs461x_pci_tbl[] = {
 | 
			
		||||
	{ PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
 | 
			
		||||
	{ PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
 | 
			
		||||
	{ PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
 | 
			
		||||
	{ 0, }
 | 
			
		||||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
 | 
			
		||||
 | 
			
		||||
static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	struct gameport* port;
 | 
			
		||||
 | 
			
		||||
	rc = pci_enable_device(pdev);
 | 
			
		||||
	if (rc) {
 | 
			
		||||
		printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
 | 
			
		||||
			pdev->bus->number, pdev->devfn, rc);
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ba0_addr = pci_resource_start(pdev, 0);
 | 
			
		||||
#ifdef CS461X_FULL_MAP
 | 
			
		||||
	ba1_addr = pci_resource_start(pdev, 1);
 | 
			
		||||
#endif
 | 
			
		||||
	if (ba0_addr == 0 || ba0_addr == ~0
 | 
			
		||||
#ifdef CS461X_FULL_MAP
 | 
			
		||||
            || ba1_addr == 0 || ba1_addr == ~0
 | 
			
		||||
#endif
 | 
			
		||||
	    ) {
 | 
			
		||||
                printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
 | 
			
		||||
#ifdef CS461X_FULL_MAP
 | 
			
		||||
                printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
 | 
			
		||||
#endif
 | 
			
		||||
		cs461x_free(pdev);
 | 
			
		||||
                return -ENOMEM;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
 | 
			
		||||
#ifdef CS461X_FULL_MAP
 | 
			
		||||
	ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
 | 
			
		||||
	ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
 | 
			
		||||
	ba1.name.pmem  = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
 | 
			
		||||
	ba1.name.reg   = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
 | 
			
		||||
 | 
			
		||||
	if (ba0 == NULL || ba1.name.data0 == NULL ||
 | 
			
		||||
            ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
 | 
			
		||||
            ba1.name.reg == NULL) {
 | 
			
		||||
		cs461x_free(pdev);
 | 
			
		||||
                return -ENOMEM;
 | 
			
		||||
        }
 | 
			
		||||
#else
 | 
			
		||||
	if (ba0 == NULL) {
 | 
			
		||||
		cs461x_free(pdev);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (!(port = gameport_allocate_port())) {
 | 
			
		||||
		printk(KERN_ERR "cs461x: Memory allocation failed\n");
 | 
			
		||||
		cs461x_free(pdev);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pci_set_drvdata(pdev, port);
 | 
			
		||||
 | 
			
		||||
	port->open = cs461x_gameport_open;
 | 
			
		||||
	port->trigger = cs461x_gameport_trigger;
 | 
			
		||||
	port->read = cs461x_gameport_read;
 | 
			
		||||
	port->cooked_read = cs461x_gameport_cooked_read;
 | 
			
		||||
 | 
			
		||||
	gameport_set_name(port, "CS416x");
 | 
			
		||||
	gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
 | 
			
		||||
	port->dev.parent = &pdev->dev;
 | 
			
		||||
 | 
			
		||||
	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
 | 
			
		||||
	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
 | 
			
		||||
 | 
			
		||||
	gameport_register_port(port);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
 | 
			
		||||
{
 | 
			
		||||
	cs461x_free(pdev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct pci_driver cs461x_pci_driver = {
 | 
			
		||||
        .name =         "CS461x_gameport",
 | 
			
		||||
        .id_table =     cs461x_pci_tbl,
 | 
			
		||||
        .probe =        cs461x_pci_probe,
 | 
			
		||||
        .remove =       __devexit_p(cs461x_pci_remove),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init cs461x_init(void)
 | 
			
		||||
{
 | 
			
		||||
        return pci_register_driver(&cs461x_pci_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __exit cs461x_exit(void)
 | 
			
		||||
{
 | 
			
		||||
        pci_unregister_driver(&cs461x_pci_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module_init(cs461x_init);
 | 
			
		||||
module_exit(cs461x_exit);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -258,18 +258,18 @@ static int __init ns558_init(void)
 | 
			
		|||
{
 | 
			
		||||
	int i = 0;
 | 
			
		||||
 | 
			
		||||
	if (pnp_register_driver(&ns558_pnp_driver) >= 0)
 | 
			
		||||
		pnp_registered = 1;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Probe ISA ports first so that PnP gets to choose free port addresses
 | 
			
		||||
 * not occupied by the ISA ports.
 | 
			
		||||
 * Probe ISA ports after PnP, so that PnP ports that are already
 | 
			
		||||
 * enabled get detected as PnP. This may be suboptimal in multi-device
 | 
			
		||||
 * configurations, but saves hassle with simple setups.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
	while (ns558_isa_portlist[i])
 | 
			
		||||
		ns558_isa_probe(ns558_isa_portlist[i++]);
 | 
			
		||||
 | 
			
		||||
	if (pnp_register_driver(&ns558_pnp_driver) >= 0)
 | 
			
		||||
		pnp_registered = 1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,186 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (c) 2000-2001 Vojtech Pavlik
 | 
			
		||||
 *
 | 
			
		||||
 *  Based on the work of:
 | 
			
		||||
 *	Raymond Ingles
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Trident 4DWave and Aureal Vortex gameport driver for Linux
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | 
			
		||||
 *
 | 
			
		||||
 * Should you need to contact me, the author, you can do so either by
 | 
			
		||||
 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
 | 
			
		||||
 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <asm/io.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/errno.h>
 | 
			
		||||
#include <linux/ioport.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/pci.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/gameport.h>
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 | 
			
		||||
MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
 | 
			
		||||
#define VORTEX_GCR		0x0c	/* Gameport control register */
 | 
			
		||||
#define VORTEX_LEG		0x08	/* Legacy port location */
 | 
			
		||||
#define VORTEX_AXD		0x10	/* Axes start */
 | 
			
		||||
#define VORTEX_DATA_WAIT	20	/* 20 ms */
 | 
			
		||||
 | 
			
		||||
struct vortex {
 | 
			
		||||
	struct gameport *gameport;
 | 
			
		||||
	struct pci_dev *dev;
 | 
			
		||||
	unsigned char __iomem *base;
 | 
			
		||||
	unsigned char __iomem *io;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static unsigned char vortex_read(struct gameport *gameport)
 | 
			
		||||
{
 | 
			
		||||
	struct vortex *vortex = gameport->port_data;
 | 
			
		||||
	return readb(vortex->io + VORTEX_LEG);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void vortex_trigger(struct gameport *gameport)
 | 
			
		||||
{
 | 
			
		||||
	struct vortex *vortex = gameport->port_data;
 | 
			
		||||
	writeb(0xff, vortex->io + VORTEX_LEG);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 | 
			
		||||
{
 | 
			
		||||
	struct vortex *vortex = gameport->port_data;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	*buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 4; i++) {
 | 
			
		||||
		axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
 | 
			
		||||
		if (axes[i] == 0x1fff) axes[i] = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int vortex_open(struct gameport *gameport, int mode)
 | 
			
		||||
{
 | 
			
		||||
	struct vortex *vortex = gameport->port_data;
 | 
			
		||||
 | 
			
		||||
	switch (mode) {
 | 
			
		||||
		case GAMEPORT_MODE_COOKED:
 | 
			
		||||
			writeb(0x40, vortex->io + VORTEX_GCR);
 | 
			
		||||
			msleep(VORTEX_DATA_WAIT);
 | 
			
		||||
			return 0;
 | 
			
		||||
		case GAMEPORT_MODE_RAW:
 | 
			
		||||
			writeb(0x00, vortex->io + VORTEX_GCR);
 | 
			
		||||
			return 0;
 | 
			
		||||
		default:
 | 
			
		||||
			return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
 | 
			
		||||
{
 | 
			
		||||
	struct vortex *vortex;
 | 
			
		||||
	struct gameport *port;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
 | 
			
		||||
	port = gameport_allocate_port();
 | 
			
		||||
	if (!vortex || !port) {
 | 
			
		||||
		printk(KERN_ERR "vortex: Memory allocation failed.\n");
 | 
			
		||||
		kfree(vortex);
 | 
			
		||||
		gameport_free_port(port);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 6; i++)
 | 
			
		||||
		if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
	pci_enable_device(dev);
 | 
			
		||||
 | 
			
		||||
	vortex->dev = dev;
 | 
			
		||||
	vortex->gameport = port;
 | 
			
		||||
	vortex->base = ioremap(pci_resource_start(vortex->dev, i),
 | 
			
		||||
				pci_resource_len(vortex->dev, i));
 | 
			
		||||
	vortex->io = vortex->base + id->driver_data;
 | 
			
		||||
 | 
			
		||||
	pci_set_drvdata(dev, vortex);
 | 
			
		||||
 | 
			
		||||
	port->port_data = vortex;
 | 
			
		||||
	port->fuzz = 64;
 | 
			
		||||
 | 
			
		||||
	gameport_set_name(port, "AU88x0");
 | 
			
		||||
	gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
 | 
			
		||||
	port->dev.parent = &dev->dev;
 | 
			
		||||
	port->read = vortex_read;
 | 
			
		||||
	port->trigger = vortex_trigger;
 | 
			
		||||
	port->cooked_read = vortex_cooked_read;
 | 
			
		||||
	port->open = vortex_open;
 | 
			
		||||
 | 
			
		||||
	gameport_register_port(port);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __devexit vortex_remove(struct pci_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct vortex *vortex = pci_get_drvdata(dev);
 | 
			
		||||
 | 
			
		||||
	gameport_unregister_port(vortex->gameport);
 | 
			
		||||
	iounmap(vortex->base);
 | 
			
		||||
	kfree(vortex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct pci_device_id vortex_id_table[] = {
 | 
			
		||||
	{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
 | 
			
		||||
	{ 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
 | 
			
		||||
	{ 0 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct pci_driver vortex_driver = {
 | 
			
		||||
	.name =		"vortex_gameport",
 | 
			
		||||
	.id_table =	vortex_id_table,
 | 
			
		||||
	.probe =	vortex_probe,
 | 
			
		||||
	.remove =	__devexit_p(vortex_remove),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init vortex_init(void)
 | 
			
		||||
{
 | 
			
		||||
	return pci_register_driver(&vortex_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __exit vortex_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	pci_unregister_driver(&vortex_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module_init(vortex_init);
 | 
			
		||||
module_exit(vortex_exit);
 | 
			
		||||
| 
						 | 
				
			
			@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle)
 | 
			
		|||
 | 
			
		||||
int input_open_device(struct input_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	struct input_dev *dev = handle->dev;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = down_interruptible(&dev->sem);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	handle->open++;
 | 
			
		||||
	if (handle->dev->open)
 | 
			
		||||
		return handle->dev->open(handle->dev);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
	if (!dev->users++ && dev->open)
 | 
			
		||||
		err = dev->open(dev);
 | 
			
		||||
 | 
			
		||||
	if (err)
 | 
			
		||||
		handle->open--;
 | 
			
		||||
 | 
			
		||||
	up(&dev->sem);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int input_flush_device(struct input_handle* handle, struct file* file)
 | 
			
		||||
| 
						 | 
				
			
			@ -235,10 +249,17 @@ int input_flush_device(struct input_handle* handle, struct file* file)
 | 
			
		|||
 | 
			
		||||
void input_close_device(struct input_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	struct input_dev *dev = handle->dev;
 | 
			
		||||
 | 
			
		||||
	input_release_device(handle);
 | 
			
		||||
	if (handle->dev->close)
 | 
			
		||||
		handle->dev->close(handle->dev);
 | 
			
		||||
 | 
			
		||||
	down(&dev->sem);
 | 
			
		||||
 | 
			
		||||
	if (!--dev->users && dev->close)
 | 
			
		||||
		dev->close(dev);
 | 
			
		||||
	handle->open--;
 | 
			
		||||
 | 
			
		||||
	up(&dev->sem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void input_link_handle(struct input_handle *handle)
 | 
			
		||||
| 
						 | 
				
			
			@ -415,6 +436,8 @@ void input_register_device(struct input_dev *dev)
 | 
			
		|||
 | 
			
		||||
	set_bit(EV_SYN, dev->evbit);
 | 
			
		||||
 | 
			
		||||
	init_MUTEX(&dev->sem);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If delay and period are pre-set by the driver, then autorepeating
 | 
			
		||||
	 * is handled by the driver itself and we don't do it in input.c.
 | 
			
		||||
| 
						 | 
				
			
			@ -674,6 +697,8 @@ static int input_handlers_read(char *buf, char **start, off_t pos, int count, in
 | 
			
		|||
	return (count > cnt) ? cnt : count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct file_operations input_fileops;
 | 
			
		||||
 | 
			
		||||
static int __init input_proc_init(void)
 | 
			
		||||
{
 | 
			
		||||
	struct proc_dir_entry *entry;
 | 
			
		||||
| 
						 | 
				
			
			@ -688,6 +713,8 @@ static int __init input_proc_init(void)
 | 
			
		|||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	entry->owner = THIS_MODULE;
 | 
			
		||||
	input_fileops = *entry->proc_fops;
 | 
			
		||||
	entry->proc_fops = &input_fileops;
 | 
			
		||||
	entry->proc_fops->poll = input_devices_poll;
 | 
			
		||||
	entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
 | 
			
		||||
	if (entry == NULL) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -285,48 +285,33 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
 | 
			
		|||
		(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 | 
			
		||||
static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
 | 
			
		||||
{
 | 
			
		||||
	struct joydev_list *list = file->private_data;
 | 
			
		||||
	struct joydev *joydev = list->joydev;
 | 
			
		||||
	struct input_dev *dev = joydev->handle.dev;
 | 
			
		||||
	void __user *argp = (void __user *)arg;
 | 
			
		||||
	int i, j;
 | 
			
		||||
 | 
			
		||||
	if (!joydev->exist) return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	switch (cmd) {
 | 
			
		||||
 | 
			
		||||
		case JS_SET_CAL:
 | 
			
		||||
			return copy_from_user(&joydev->glue.JS_CORR, argp,
 | 
			
		||||
				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
 | 
			
		||||
				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
 | 
			
		||||
		case JS_GET_CAL:
 | 
			
		||||
			return copy_to_user(argp, &joydev->glue.JS_CORR,
 | 
			
		||||
				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
 | 
			
		||||
				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
 | 
			
		||||
		case JS_SET_TIMEOUT:
 | 
			
		||||
			return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
 | 
			
		||||
			return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
 | 
			
		||||
		case JS_GET_TIMEOUT:
 | 
			
		||||
			return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
 | 
			
		||||
		case JS_SET_TIMELIMIT:
 | 
			
		||||
			return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
 | 
			
		||||
		case JS_GET_TIMELIMIT:
 | 
			
		||||
			return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
 | 
			
		||||
		case JS_SET_ALL:
 | 
			
		||||
			return copy_from_user(&joydev->glue, argp,
 | 
			
		||||
						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
 | 
			
		||||
		case JS_GET_ALL:
 | 
			
		||||
			return copy_to_user(argp, &joydev->glue,
 | 
			
		||||
						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
 | 
			
		||||
			return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
 | 
			
		||||
 | 
			
		||||
		case JSIOCGVERSION:
 | 
			
		||||
			return put_user(JS_VERSION, (__u32 __user *) arg);
 | 
			
		||||
			return put_user(JS_VERSION, (__u32 __user *) argp);
 | 
			
		||||
		case JSIOCGAXES:
 | 
			
		||||
			return put_user(joydev->nabs, (__u8 __user *) arg);
 | 
			
		||||
			return put_user(joydev->nabs, (__u8 __user *) argp);
 | 
			
		||||
		case JSIOCGBUTTONS:
 | 
			
		||||
			return put_user(joydev->nkey, (__u8 __user *) arg);
 | 
			
		||||
			return put_user(joydev->nkey, (__u8 __user *) argp);
 | 
			
		||||
		case JSIOCSCORR:
 | 
			
		||||
			if (copy_from_user(joydev->corr, argp,
 | 
			
		||||
				      sizeof(struct js_corr) * joydev->nabs))
 | 
			
		||||
				      sizeof(joydev->corr[0]) * joydev->nabs))
 | 
			
		||||
			    return -EFAULT;
 | 
			
		||||
			for (i = 0; i < joydev->nabs; i++) {
 | 
			
		||||
				j = joydev->abspam[i];
 | 
			
		||||
| 
						 | 
				
			
			@ -335,7 +320,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 | 
			
		|||
			return 0;
 | 
			
		||||
		case JSIOCGCORR:
 | 
			
		||||
			return copy_to_user(argp, joydev->corr,
 | 
			
		||||
						sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
 | 
			
		||||
						sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
 | 
			
		||||
		case JSIOCSAXMAP:
 | 
			
		||||
			if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
 | 
			
		||||
				return -EFAULT;
 | 
			
		||||
| 
						 | 
				
			
			@ -371,6 +356,84 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 | 
			
		|||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 | 
			
		||||
{
 | 
			
		||||
	struct joydev_list *list = file->private_data;
 | 
			
		||||
	struct joydev *joydev = list->joydev;
 | 
			
		||||
	void __user *argp = (void __user *)arg;
 | 
			
		||||
	s32 tmp32;
 | 
			
		||||
	struct JS_DATA_SAVE_TYPE_32 ds32;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (!joydev->exist) return -ENODEV;
 | 
			
		||||
	switch(cmd) {
 | 
			
		||||
	case JS_SET_TIMELIMIT:
 | 
			
		||||
		err = get_user(tmp32, (s32 __user *) arg);
 | 
			
		||||
		if (err == 0)
 | 
			
		||||
			joydev->glue.JS_TIMELIMIT = tmp32;
 | 
			
		||||
		break;
 | 
			
		||||
	case JS_GET_TIMELIMIT:
 | 
			
		||||
		tmp32 = joydev->glue.JS_TIMELIMIT;
 | 
			
		||||
		err = put_user(tmp32, (s32 __user *) arg);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case JS_SET_ALL:
 | 
			
		||||
		err = copy_from_user(&ds32, argp,
 | 
			
		||||
				     sizeof(ds32)) ? -EFAULT : 0;
 | 
			
		||||
		if (err == 0) {
 | 
			
		||||
			joydev->glue.JS_TIMEOUT    = ds32.JS_TIMEOUT;
 | 
			
		||||
			joydev->glue.BUSY          = ds32.BUSY;
 | 
			
		||||
			joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
 | 
			
		||||
			joydev->glue.JS_TIMELIMIT  = ds32.JS_TIMELIMIT;
 | 
			
		||||
			joydev->glue.JS_SAVE       = ds32.JS_SAVE;
 | 
			
		||||
			joydev->glue.JS_CORR       = ds32.JS_CORR;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case JS_GET_ALL:
 | 
			
		||||
		ds32.JS_TIMEOUT    = joydev->glue.JS_TIMEOUT;
 | 
			
		||||
		ds32.BUSY          = joydev->glue.BUSY;
 | 
			
		||||
		ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
 | 
			
		||||
		ds32.JS_TIMELIMIT  = joydev->glue.JS_TIMELIMIT;
 | 
			
		||||
		ds32.JS_SAVE       = joydev->glue.JS_SAVE;
 | 
			
		||||
		ds32.JS_CORR       = joydev->glue.JS_CORR;
 | 
			
		||||
 | 
			
		||||
		err = copy_to_user(argp, &ds32,
 | 
			
		||||
					  sizeof(ds32)) ? -EFAULT : 0;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		err = joydev_ioctl_common(joydev, cmd, argp);
 | 
			
		||||
	}
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_COMPAT */
 | 
			
		||||
 | 
			
		||||
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 | 
			
		||||
{
 | 
			
		||||
	struct joydev_list *list = file->private_data;
 | 
			
		||||
	struct joydev *joydev = list->joydev;
 | 
			
		||||
	void __user *argp = (void __user *)arg;
 | 
			
		||||
 | 
			
		||||
	if (!joydev->exist) return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	switch(cmd) {
 | 
			
		||||
		case JS_SET_TIMELIMIT:
 | 
			
		||||
			return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
 | 
			
		||||
		case JS_GET_TIMELIMIT:
 | 
			
		||||
			return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
 | 
			
		||||
		case JS_SET_ALL:
 | 
			
		||||
			return copy_from_user(&joydev->glue, argp,
 | 
			
		||||
						sizeof(joydev->glue)) ? -EFAULT : 0;
 | 
			
		||||
		case JS_GET_ALL:
 | 
			
		||||
			return copy_to_user(argp, &joydev->glue,
 | 
			
		||||
						sizeof(joydev->glue)) ? -EFAULT : 0;
 | 
			
		||||
		default:
 | 
			
		||||
			return joydev_ioctl_common(joydev, cmd, argp);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct file_operations joydev_fops = {
 | 
			
		||||
	.owner =	THIS_MODULE,
 | 
			
		||||
	.read =		joydev_read,
 | 
			
		||||
| 
						 | 
				
			
			@ -379,6 +442,9 @@ static struct file_operations joydev_fops = {
 | 
			
		|||
	.open =		joydev_open,
 | 
			
		||||
	.release =	joydev_release,
 | 
			
		||||
	.ioctl =	joydev_ioctl,
 | 
			
		||||
#ifdef CONFIG_COMPAT
 | 
			
		||||
	.compat_ioctl =	joydev_compat_ioctl,
 | 
			
		||||
#endif
 | 
			
		||||
	.fasync =	joydev_fasync,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
 | 
			
		|||
 | 
			
		||||
__obsolete_setup("amijoy=");
 | 
			
		||||
 | 
			
		||||
static int amijoy_used[2] = { 0, 0 };
 | 
			
		||||
static int amijoy_used;
 | 
			
		||||
static DECLARE_MUTEX(amijoy_sem);
 | 
			
		||||
static struct input_dev amijoy_dev[2];
 | 
			
		||||
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,26 +85,30 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
 | 
			
		|||
 | 
			
		||||
static int amijoy_open(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	int *used = dev->private;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if ((*used)++)
 | 
			
		||||
		return 0;
 | 
			
		||||
	err = down_interruptible(&amijoy_sem);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
 | 
			
		||||
		(*used)--;
 | 
			
		||||
	if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
 | 
			
		||||
		printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
		err = -EBUSY;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	amijoy_used++;
 | 
			
		||||
out:
 | 
			
		||||
	up(&amijoy_sem);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void amijoy_close(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	int *used = dev->private;
 | 
			
		||||
 | 
			
		||||
	if (!--(*used))
 | 
			
		||||
	down(&amijoysem);
 | 
			
		||||
	if (!--amijoy_used)
 | 
			
		||||
		free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
 | 
			
		||||
	up(&amijoy_sem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __init amijoy_init(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -138,8 +143,6 @@ static int __init amijoy_init(void)
 | 
			
		|||
			amijoy_dev[i].id.product = 0x0003;
 | 
			
		||||
			amijoy_dev[i].id.version = 0x0100;
 | 
			
		||||
 | 
			
		||||
			amijoy_dev[i].private = amijoy_used + i;
 | 
			
		||||
 | 
			
		||||
			input_register_device(amijoy_dev + i);
 | 
			
		||||
			printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,6 +98,7 @@ struct db9 {
 | 
			
		|||
	struct pardevice *pd;
 | 
			
		||||
	int mode;
 | 
			
		||||
	int used;
 | 
			
		||||
	struct semaphore sem;
 | 
			
		||||
	char phys[2][32];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
 | 
			
		|||
{
 | 
			
		||||
	struct db9 *db9 = dev->private;
 | 
			
		||||
	struct parport *port = db9->pd->port;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = down_interruptible(&db9->sem);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (!db9->used++) {
 | 
			
		||||
		parport_claim(db9->pd);
 | 
			
		||||
| 
						 | 
				
			
			@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
 | 
			
		|||
		mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	up(&db9->sem);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
 | 
			
		|||
	struct db9 *db9 = dev->private;
 | 
			
		||||
	struct parport *port = db9->pd->port;
 | 
			
		||||
 | 
			
		||||
	down(&db9->sem);
 | 
			
		||||
	if (!--db9->used) {
 | 
			
		||||
		del_timer(&db9->timer);
 | 
			
		||||
		del_timer_sync(&db9->timer);
 | 
			
		||||
		parport_write_control(port, 0x00);
 | 
			
		||||
		parport_data_forward(port);
 | 
			
		||||
		parport_release(db9->pd);
 | 
			
		||||
	}
 | 
			
		||||
	up(&db9->sem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct db9 __init *db9_probe(int *config, int nargs)
 | 
			
		||||
| 
						 | 
				
			
			@ -563,12 +572,12 @@ static struct db9 __init *db9_probe(int *config, int nargs)
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
 | 
			
		||||
	if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
 | 
			
		||||
		parport_put_port(pp);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	memset(db9, 0, sizeof(struct db9));
 | 
			
		||||
 | 
			
		||||
	init_MUTEX(&db9->sem);
 | 
			
		||||
	db9->mode = config[1];
 | 
			
		||||
	init_timer(&db9->timer);
 | 
			
		||||
	db9->timer.data = (long) db9;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,6 +81,7 @@ struct gc {
 | 
			
		|||
	struct timer_list timer;
 | 
			
		||||
	unsigned char pads[GC_MAX + 1];
 | 
			
		||||
	int used;
 | 
			
		||||
	struct semaphore sem;
 | 
			
		||||
	char phys[5][32];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -503,22 +504,33 @@ static void gc_timer(unsigned long private)
 | 
			
		|||
static int gc_open(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct gc *gc = dev->private;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = down_interruptible(&gc->sem);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (!gc->used++) {
 | 
			
		||||
		parport_claim(gc->pd);
 | 
			
		||||
		parport_write_control(gc->pd->port, 0x04);
 | 
			
		||||
		mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	up(&gc->sem);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gc_close(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct gc *gc = dev->private;
 | 
			
		||||
 | 
			
		||||
	down(&gc->sem);
 | 
			
		||||
	if (!--gc->used) {
 | 
			
		||||
		del_timer(&gc->timer);
 | 
			
		||||
		del_timer_sync(&gc->timer);
 | 
			
		||||
		parport_write_control(gc->pd->port, 0x00);
 | 
			
		||||
		parport_release(gc->pd);
 | 
			
		||||
	}
 | 
			
		||||
	up(&gc->sem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gc __init *gc_probe(int *config, int nargs)
 | 
			
		||||
| 
						 | 
				
			
			@ -542,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs)
 | 
			
		|||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) {
 | 
			
		||||
	if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
 | 
			
		||||
		parport_put_port(pp);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	memset(gc, 0, sizeof(struct gc));
 | 
			
		||||
 | 
			
		||||
	init_MUTEX(&gc->sem);
 | 
			
		||||
 | 
			
		||||
	gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,6 +78,7 @@ static struct iforce_device iforce_device[] = {
 | 
			
		|||
	{ 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
 | 
			
		||||
	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce }, //?
 | 
			
		||||
	{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce }, //?
 | 
			
		||||
	{ 0x06f8, 0x0004, "Gullemot Jet Leader 3D",			btn_joystick, abs_joystick, ff_iforce }, //?
 | 
			
		||||
	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -229,6 +229,7 @@ static struct usb_device_id iforce_usb_ids [] = {
 | 
			
		|||
	{ USB_DEVICE(0x061c, 0xc0a4) },         /* ACT LABS Force RS */
 | 
			
		||||
	{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
 | 
			
		||||
	{ USB_DEVICE(0x06f8, 0x0004) },		/* Guillemot Force Feedback Racing Wheel */
 | 
			
		||||
	{ USB_DEVICE(0x06f8, 0xa302) },		/* Guillemot Jet Leader 3D */
 | 
			
		||||
	{ }					/* Terminating entry */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,6 +84,7 @@ static struct tgfx {
 | 
			
		|||
	char phys[7][32];
 | 
			
		||||
	int sticks;
 | 
			
		||||
	int used;
 | 
			
		||||
	struct semaphore sem;
 | 
			
		||||
} *tgfx_base[3];
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -123,22 +124,33 @@ static void tgfx_timer(unsigned long private)
 | 
			
		|||
static int tgfx_open(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct tgfx *tgfx = dev->private;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = down_interruptible(&tgfx->sem);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (!tgfx->used++) {
 | 
			
		||||
		parport_claim(tgfx->pd);
 | 
			
		||||
		parport_write_control(tgfx->pd->port, 0x04);
 | 
			
		||||
		mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	up(&tgfx->sem);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void tgfx_close(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct tgfx *tgfx = dev->private;
 | 
			
		||||
 | 
			
		||||
	down(&tgfx->sem);
 | 
			
		||||
	if (!--tgfx->used) {
 | 
			
		||||
                del_timer(&tgfx->timer);
 | 
			
		||||
		del_timer_sync(&tgfx->timer);
 | 
			
		||||
		parport_write_control(tgfx->pd->port, 0x00);
 | 
			
		||||
		parport_release(tgfx->pd);
 | 
			
		||||
	}
 | 
			
		||||
	up(&tgfx->sem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -166,11 +178,12 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
 | 
			
		|||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) {
 | 
			
		||||
	if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
 | 
			
		||||
		parport_put_port(pp);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	memset(tgfx, 0, sizeof(struct tgfx));
 | 
			
		||||
 | 
			
		||||
	init_MUTEX(&tgfx->sem);
 | 
			
		||||
 | 
			
		||||
	tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,7 @@
 | 
			
		|||
#define CORGI_KEY_CALENDER	KEY_F1
 | 
			
		||||
#define CORGI_KEY_ADDRESS	KEY_F2
 | 
			
		||||
#define CORGI_KEY_FN		KEY_F3
 | 
			
		||||
#define CORGI_KEY_CANCEL	KEY_F4
 | 
			
		||||
#define CORGI_KEY_OFF		KEY_SUSPEND
 | 
			
		||||
#define CORGI_KEY_EXOK		KEY_F5
 | 
			
		||||
#define CORGI_KEY_EXCANCEL	KEY_F6
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +47,7 @@
 | 
			
		|||
#define CORGI_KEY_EXJOGUP	KEY_F8
 | 
			
		||||
#define CORGI_KEY_JAP1		KEY_LEFTCTRL
 | 
			
		||||
#define CORGI_KEY_JAP2		KEY_LEFTALT
 | 
			
		||||
#define CORGI_KEY_MAIL		KEY_F10
 | 
			
		||||
#define CORGI_KEY_OK		KEY_F11
 | 
			
		||||
#define CORGI_KEY_MENU		KEY_F12
 | 
			
		||||
#define CORGI_HINGE_0		KEY_KP0
 | 
			
		||||
| 
						 | 
				
			
			@ -59,8 +61,8 @@ static unsigned char corgikbd_keycode[NR_SCANCODES] = {
 | 
			
		|||
	KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0,                                 /* 33-48 */
 | 
			
		||||
	CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,         /* 49-64 */
 | 
			
		||||
	CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 	  /* 65-80 */
 | 
			
		||||
	KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
 | 
			
		||||
	KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
 | 
			
		||||
	CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
 | 
			
		||||
	KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
 | 
			
		||||
	CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0,   /* 113-124 */
 | 
			
		||||
	CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2	  /* 125-127 */
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,6 @@ struct dc_kbd {
 | 
			
		|||
	struct input_dev dev;
 | 
			
		||||
	unsigned char new[8];
 | 
			
		||||
	unsigned char old[8];
 | 
			
		||||
	int open;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -95,22 +94,6 @@ static void dc_kbd_callback(struct mapleq *mq)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int dc_kbd_open(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct dc_kbd *kbd = dev->private;
 | 
			
		||||
	kbd->open++;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void dc_kbd_close(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct dc_kbd *kbd = dev->private;
 | 
			
		||||
	kbd->open--;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int dc_kbd_connect(struct maple_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
| 
						 | 
				
			
			@ -133,9 +116,6 @@ static int dc_kbd_connect(struct maple_device *dev)
 | 
			
		|||
	clear_bit(0, kbd->dev.keybit);
 | 
			
		||||
 | 
			
		||||
	kbd->dev.private = kbd;
 | 
			
		||||
	kbd->dev.open = dc_kbd_open;
 | 
			
		||||
	kbd->dev.close = dc_kbd_close;
 | 
			
		||||
	kbd->dev.event = NULL;
 | 
			
		||||
 | 
			
		||||
	kbd->dev.name = dev->product_name;
 | 
			
		||||
	kbd->dev.id.bustype = BUS_MAPLE;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -298,10 +298,12 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz
 | 
			
		|||
	/* check if absmin/absmax/absfuzz/absflat are filled as
 | 
			
		||||
	 * told in Documentation/input/input-programming.txt */
 | 
			
		||||
	if (test_bit(EV_ABS, dev->evbit)) {
 | 
			
		||||
		retval = uinput_validate_absbits(dev);
 | 
			
		||||
		if (retval < 0)
 | 
			
		||||
		int err = uinput_validate_absbits(dev);
 | 
			
		||||
		if (err < 0) {
 | 
			
		||||
			retval = err;
 | 
			
		||||
			kfree(dev->name);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
exit:
 | 
			
		||||
	kfree(user_dev);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
 | 
			
		|||
obj-$(CONFIG_MOUSE_HIL)		+= hil_ptr.o
 | 
			
		||||
obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 | 
			
		||||
 | 
			
		||||
psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o
 | 
			
		||||
psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,10 +30,11 @@
 | 
			
		|||
 | 
			
		||||
#define ALPS_DUALPOINT	0x01
 | 
			
		||||
#define ALPS_WHEEL	0x02
 | 
			
		||||
#define ALPS_FW_BK	0x04
 | 
			
		||||
#define ALPS_FW_BK_1	0x04
 | 
			
		||||
#define ALPS_4BTN	0x08
 | 
			
		||||
#define ALPS_OLDPROTO	0x10
 | 
			
		||||
#define ALPS_PASS	0x20
 | 
			
		||||
#define ALPS_FW_BK_2	0x40
 | 
			
		||||
 | 
			
		||||
static struct alps_model_info alps_model_data[] = {
 | 
			
		||||
	{ { 0x33, 0x02, 0x0a },	0x88, 0xf8, ALPS_OLDPROTO },		/* UMAX-530T */
 | 
			
		||||
| 
						 | 
				
			
			@ -43,11 +44,11 @@ static struct alps_model_info alps_model_data[] = {
 | 
			
		|||
	{ { 0x63, 0x02, 0x14 },	0xf8, 0xf8, 0 },
 | 
			
		||||
	{ { 0x63, 0x02, 0x28 },	0xf8, 0xf8, 0 },
 | 
			
		||||
	{ { 0x63, 0x02, 0x3c },	0x8f, 0x8f, ALPS_WHEEL },		/* Toshiba Satellite S2400-103 */
 | 
			
		||||
	{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK },		/* NEC Versa L320 */
 | 
			
		||||
	{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK_1 },		/* NEC Versa L320 */
 | 
			
		||||
	{ { 0x63, 0x02, 0x64 },	0xf8, 0xf8, 0 },
 | 
			
		||||
	{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS },		/* Dell Latitude D800 */
 | 
			
		||||
	{ { 0x73, 0x02, 0x0a },	0xf8, 0xf8, 0 },
 | 
			
		||||
	{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, 0 },
 | 
			
		||||
	{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, ALPS_FW_BK_2 },		/* Ahtec Laptop */
 | 
			
		||||
	{ { 0x20, 0x02, 0x0e },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
 | 
			
		||||
	{ { 0x22, 0x02, 0x0a },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
 | 
			
		||||
	{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +82,7 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
 | 
			
		|||
	struct input_dev *dev = &psmouse->dev;
 | 
			
		||||
	struct input_dev *dev2 = &priv->dev2;
 | 
			
		||||
	int x, y, z, ges, fin, left, right, middle;
 | 
			
		||||
	int back = 0, forward = 0;
 | 
			
		||||
 | 
			
		||||
	input_regs(dev, regs);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +114,18 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
 | 
			
		|||
		z = packet[5];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (priv->i->flags & ALPS_FW_BK_1) {
 | 
			
		||||
		back = packet[2] & 4;
 | 
			
		||||
		forward = packet[0] & 0x10;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (priv->i->flags & ALPS_FW_BK_2) {
 | 
			
		||||
		back = packet[3] & 4;
 | 
			
		||||
		forward = packet[2] & 4;
 | 
			
		||||
		if ((middle = forward && back))
 | 
			
		||||
			forward = back = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ges = packet[2] & 1;
 | 
			
		||||
	fin = packet[2] & 2;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -155,13 +169,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
 | 
			
		|||
	input_report_abs(dev, ABS_PRESSURE, z);
 | 
			
		||||
	input_report_key(dev, BTN_TOOL_FINGER, z > 0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (priv->i->flags & ALPS_WHEEL)
 | 
			
		||||
		input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
 | 
			
		||||
 | 
			
		||||
	if (priv->i->flags & ALPS_FW_BK) {
 | 
			
		||||
		input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
 | 
			
		||||
		input_report_key(dev, BTN_BACK, packet[2] & 0x04);
 | 
			
		||||
	if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
 | 
			
		||||
		input_report_key(dev, BTN_FORWARD, forward);
 | 
			
		||||
		input_report_key(dev, BTN_BACK, back);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_sync(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -257,7 +270,6 @@ static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *vers
 | 
			
		|||
static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
 | 
			
		||||
{
 | 
			
		||||
	struct ps2dev *ps2dev = &psmouse->ps2dev;
 | 
			
		||||
	unsigned char param[3];
 | 
			
		||||
	int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
 | 
			
		||||
 | 
			
		||||
	if (ps2_command(ps2dev, NULL, cmd) ||
 | 
			
		||||
| 
						 | 
				
			
			@ -267,7 +279,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
 | 
			
		|||
		return -1;
 | 
			
		||||
 | 
			
		||||
	/* we may get 3 more bytes, just ignore them */
 | 
			
		||||
	ps2_command(ps2dev, param, 0x0300);
 | 
			
		||||
	ps2_drain(ps2dev, 3, 100);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -425,7 +437,7 @@ int alps_init(struct psmouse *psmouse)
 | 
			
		|||
		psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (priv->i->flags & ALPS_FW_BK) {
 | 
			
		||||
	if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
 | 
			
		||||
		psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
 | 
			
		||||
		psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -468,10 +480,8 @@ int alps_detect(struct psmouse *psmouse, int set_properties)
 | 
			
		|||
 | 
			
		||||
	if (set_properties) {
 | 
			
		||||
		psmouse->vendor = "ALPS";
 | 
			
		||||
		if (model->flags & ALPS_DUALPOINT) 
 | 
			
		||||
			psmouse->name = "DualPoint TouchPad";
 | 
			
		||||
		else
 | 
			
		||||
			psmouse->name = "GlidePoint";
 | 
			
		||||
		psmouse->name = model->flags & ALPS_DUALPOINT ?
 | 
			
		||||
				"DualPoint TouchPad" : "GlidePoint";
 | 
			
		||||
		psmouse->model = version;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 | 
			
		|||
MODULE_DESCRIPTION("Amiga mouse driver");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
 | 
			
		||||
static int amimouse_used = 0;
 | 
			
		||||
static int amimouse_lastx, amimouse_lasty;
 | 
			
		||||
static struct input_dev amimouse_dev;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -81,16 +80,12 @@ static int amimouse_open(struct input_dev *dev)
 | 
			
		|||
{
 | 
			
		||||
	unsigned short joy0dat;
 | 
			
		||||
 | 
			
		||||
        if (amimouse_used++)
 | 
			
		||||
                return 0;
 | 
			
		||||
 | 
			
		||||
	joy0dat = custom.joy0dat;
 | 
			
		||||
 | 
			
		||||
	amimouse_lastx = joy0dat & 0xff;
 | 
			
		||||
	amimouse_lasty = joy0dat >> 8;
 | 
			
		||||
 | 
			
		||||
	if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
 | 
			
		||||
                amimouse_used--;
 | 
			
		||||
                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
 | 
			
		||||
                return -EBUSY;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +95,6 @@ static int amimouse_open(struct input_dev *dev)
 | 
			
		|||
 | 
			
		||||
static void amimouse_close(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
        if (!--amimouse_used)
 | 
			
		||||
	free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,30 +87,24 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 | 
			
		|||
 | 
			
		||||
__obsolete_setup("inport_irq=");
 | 
			
		||||
 | 
			
		||||
static int inport_used;
 | 
			
		||||
 | 
			
		||||
static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 | 
			
		||||
 | 
			
		||||
static int inport_open(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (!inport_used++) {
 | 
			
		||||
	if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 | 
			
		||||
	outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void inport_close(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (!--inport_used) {
 | 
			
		||||
	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 | 
			
		||||
	outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
 | 
			
		||||
	free_irq(inport_irq, NULL);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct input_dev inport_dev = {
 | 
			
		||||
	.evbit	= { BIT(EV_KEY) | BIT(EV_REL) },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										134
									
								
								drivers/input/mouse/lifebook.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								drivers/input/mouse/lifebook.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,134 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Fujitsu B-series Lifebook PS/2 TouchScreen driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
 | 
			
		||||
 * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
 | 
			
		||||
 *
 | 
			
		||||
 * TouchScreen detection, absolute mode setting and packet layout is taken from
 | 
			
		||||
 * Harald Hoyer's description of the device.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License version 2 as published by
 | 
			
		||||
 * the Free Software Foundation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/input.h>
 | 
			
		||||
#include <linux/serio.h>
 | 
			
		||||
#include <linux/libps2.h>
 | 
			
		||||
#include <linux/dmi.h>
 | 
			
		||||
 | 
			
		||||
#include "psmouse.h"
 | 
			
		||||
#include "lifebook.h"
 | 
			
		||||
 | 
			
		||||
static struct dmi_system_id lifebook_dmi_table[] = {
 | 
			
		||||
       {
 | 
			
		||||
               .ident = "Lifebook B",
 | 
			
		||||
               .matches = {
 | 
			
		||||
                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
 | 
			
		||||
               },
 | 
			
		||||
       },
 | 
			
		||||
       { }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *packet = psmouse->packet;
 | 
			
		||||
	struct input_dev *dev = &psmouse->dev;
 | 
			
		||||
 | 
			
		||||
	if (psmouse->pktcnt != 3)
 | 
			
		||||
		return PSMOUSE_GOOD_DATA;
 | 
			
		||||
 | 
			
		||||
	input_regs(dev, regs);
 | 
			
		||||
 | 
			
		||||
	/* calculate X and Y */
 | 
			
		||||
	if ((packet[0] & 0x08) == 0x00) {
 | 
			
		||||
		input_report_abs(dev, ABS_X,
 | 
			
		||||
				 (packet[1] | ((packet[0] & 0x30) << 4)));
 | 
			
		||||
		input_report_abs(dev, ABS_Y,
 | 
			
		||||
				 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
 | 
			
		||||
	} else {
 | 
			
		||||
		input_report_rel(dev, REL_X,
 | 
			
		||||
				((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
 | 
			
		||||
		input_report_rel(dev, REL_Y,
 | 
			
		||||
				 -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
 | 
			
		||||
	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
 | 
			
		||||
	input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
 | 
			
		||||
 | 
			
		||||
	input_sync(dev);
 | 
			
		||||
 | 
			
		||||
	return PSMOUSE_FULL_PACKET;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lifebook_absolute_mode(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	struct ps2dev *ps2dev = &psmouse->ps2dev;
 | 
			
		||||
	unsigned char param;
 | 
			
		||||
 | 
			
		||||
	if (psmouse_reset(psmouse))
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	   Enable absolute output -- ps2_command fails always but if
 | 
			
		||||
	   you leave this call out the touchsreen will never send
 | 
			
		||||
	   absolute coordinates
 | 
			
		||||
	*/
 | 
			
		||||
	param = 0x07;
 | 
			
		||||
	ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char params[] = { 0, 1, 2, 2, 3 };
 | 
			
		||||
 | 
			
		||||
	if (resolution == 0 || resolution > 400)
 | 
			
		||||
		resolution = 400;
 | 
			
		||||
 | 
			
		||||
	ps2_command(&psmouse->ps2dev, ¶ms[resolution / 100], PSMOUSE_CMD_SETRES);
 | 
			
		||||
	psmouse->resolution = 50 << params[resolution / 100];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lifebook_disconnect(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	psmouse_reset(psmouse);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lifebook_detect(struct psmouse *psmouse, int set_properties)
 | 
			
		||||
{
 | 
			
		||||
        if (!dmi_check_system(lifebook_dmi_table))
 | 
			
		||||
                return -1;
 | 
			
		||||
 | 
			
		||||
	if (set_properties) {
 | 
			
		||||
		psmouse->vendor = "Fujitsu";
 | 
			
		||||
		psmouse->name = "Lifebook TouchScreen";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lifebook_init(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	if (lifebook_absolute_mode(psmouse))
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
 | 
			
		||||
	psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 | 
			
		||||
	psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
 | 
			
		||||
	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 | 
			
		||||
	input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0);
 | 
			
		||||
	input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0);
 | 
			
		||||
 | 
			
		||||
	psmouse->protocol_handler = lifebook_process_byte;
 | 
			
		||||
	psmouse->set_resolution = lifebook_set_resolution;
 | 
			
		||||
	psmouse->disconnect = lifebook_disconnect;
 | 
			
		||||
	psmouse->reconnect  = lifebook_absolute_mode;
 | 
			
		||||
	psmouse->pktsize = 3;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								drivers/input/mouse/lifebook.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								drivers/input/mouse/lifebook.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Fujitsu B-series Lifebook PS/2 TouchScreen driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2005 Vojtech Pavlik
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License version 2 as published by
 | 
			
		||||
 * the Free Software Foundation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LIFEBOOK_H
 | 
			
		||||
#define _LIFEBOOK_H
 | 
			
		||||
 | 
			
		||||
int lifebook_detect(struct psmouse *psmouse, int set_properties);
 | 
			
		||||
int lifebook_init(struct psmouse *psmouse);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -77,16 +77,11 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 | 
			
		|||
 | 
			
		||||
__obsolete_setup("logibm_irq=");
 | 
			
		||||
 | 
			
		||||
static int logibm_used = 0;
 | 
			
		||||
 | 
			
		||||
static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 | 
			
		||||
 | 
			
		||||
static int logibm_open(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (logibm_used++)
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
 | 
			
		||||
		logibm_used--;
 | 
			
		||||
		printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -96,8 +91,6 @@ static int logibm_open(struct input_dev *dev)
 | 
			
		|||
 | 
			
		||||
static void logibm_close(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (--logibm_used)
 | 
			
		||||
		return;
 | 
			
		||||
	outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
 | 
			
		||||
	free_irq(logibm_irq, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,18 +15,11 @@
 | 
			
		|||
MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
 | 
			
		||||
MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
 | 
			
		||||
 | 
			
		||||
struct dc_mouse {
 | 
			
		||||
	struct input_dev dev;
 | 
			
		||||
	int open;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void dc_mouse_callback(struct mapleq *mq)
 | 
			
		||||
{
 | 
			
		||||
	int buttons, relx, rely, relz;
 | 
			
		||||
	struct maple_device *mapledev = mq->dev;
 | 
			
		||||
	struct dc_mouse *mouse = mapledev->private_data;
 | 
			
		||||
	struct input_dev *dev = &mouse->dev;
 | 
			
		||||
	struct input_dev *dev = mapledev->private_data;
 | 
			
		||||
	unsigned char *res = mq->recvbuf;
 | 
			
		||||
 | 
			
		||||
	buttons = ~res[8];
 | 
			
		||||
| 
						 | 
				
			
			@ -43,52 +36,30 @@ static void dc_mouse_callback(struct mapleq *mq)
 | 
			
		|||
	input_sync(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int dc_mouse_open(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct dc_mouse *mouse = dev->private;
 | 
			
		||||
	mouse->open++;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void dc_mouse_close(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct dc_mouse *mouse = dev->private;
 | 
			
		||||
	mouse->open--;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int dc_mouse_connect(struct maple_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
 | 
			
		||||
	struct dc_mouse *mouse;
 | 
			
		||||
	struct input_dev *input_dev;
 | 
			
		||||
 | 
			
		||||
	if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
 | 
			
		||||
	if (!(input_dev = kmalloc(sizeof(struct input_dev), GFP_KERNEL)))
 | 
			
		||||
		return -1;
 | 
			
		||||
	memset(mouse, 0, sizeof(struct dc_mouse));
 | 
			
		||||
 | 
			
		||||
	dev->private_data = mouse;
 | 
			
		||||
	dev->private_data = input_dev;
 | 
			
		||||
 | 
			
		||||
	mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 | 
			
		||||
	mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
 | 
			
		||||
	mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
 | 
			
		||||
	memset(input_dev, 0, sizeof(struct dc_mouse));
 | 
			
		||||
	init_input_dev(input_dev);
 | 
			
		||||
	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 | 
			
		||||
	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
 | 
			
		||||
	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
 | 
			
		||||
 | 
			
		||||
	init_input_dev(&mouse->dev);
 | 
			
		||||
	input_dev->name = dev->product_name;
 | 
			
		||||
	input_dev->id.bustype = BUS_MAPLE;
 | 
			
		||||
 | 
			
		||||
	mouse->dev.private = mouse;
 | 
			
		||||
	mouse->dev.open = dc_mouse_open;
 | 
			
		||||
	mouse->dev.close = dc_mouse_close;
 | 
			
		||||
	mouse->dev.event = NULL;
 | 
			
		||||
 | 
			
		||||
	mouse->dev.name = dev->product_name;
 | 
			
		||||
	mouse->dev.id.bustype = BUS_MAPLE;
 | 
			
		||||
	
 | 
			
		||||
	input_register_device(&mouse->dev);
 | 
			
		||||
	input_register_device(input_dev);
 | 
			
		||||
 | 
			
		||||
	maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
 | 
			
		||||
 | 
			
		||||
	printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
 | 
			
		||||
	printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, input_dev->name);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -96,10 +67,10 @@ static int dc_mouse_connect(struct maple_device *dev)
 | 
			
		|||
 | 
			
		||||
static void dc_mouse_disconnect(struct maple_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct dc_mouse *mouse = dev->private_data;
 | 
			
		||||
	struct input_dev *input_dev = dev->private_data;
 | 
			
		||||
 | 
			
		||||
	input_unregister_device(&mouse->dev);
 | 
			
		||||
	kfree(mouse);
 | 
			
		||||
	input_unregister_device(input_dev);
 | 
			
		||||
	kfree(input_dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,6 @@ static int pc110pad_io = 0x15e0;
 | 
			
		|||
static struct input_dev pc110pad_dev;
 | 
			
		||||
static int pc110pad_data[3];
 | 
			
		||||
static int pc110pad_count;
 | 
			
		||||
static int pc110pad_used;
 | 
			
		||||
 | 
			
		||||
static char *pc110pad_name = "IBM PC110 TouchPad";
 | 
			
		||||
static char *pc110pad_phys = "isa15e0/input0";
 | 
			
		||||
| 
						 | 
				
			
			@ -90,15 +89,11 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
 | 
			
		|||
 | 
			
		||||
static void pc110pad_close(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (!--pc110pad_used)
 | 
			
		||||
	outb(PC110PAD_OFF, pc110pad_io + 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int pc110pad_open(struct input_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (pc110pad_used++)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	pc110pad_interrupt(0,NULL,NULL);
 | 
			
		||||
	pc110pad_interrupt(0,NULL,NULL);
 | 
			
		||||
	pc110pad_interrupt(0,NULL,NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@
 | 
			
		|||
#include "synaptics.h"
 | 
			
		||||
#include "logips2pp.h"
 | 
			
		||||
#include "alps.h"
 | 
			
		||||
#include "lifebook.h"
 | 
			
		||||
 | 
			
		||||
#define DRIVER_DESC	"PS/2 mouse driver"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,10 +32,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 | 
			
		|||
MODULE_DESCRIPTION(DRIVER_DESC);
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
 | 
			
		||||
static unsigned int psmouse_max_proto = -1U;
 | 
			
		||||
static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
 | 
			
		||||
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
 | 
			
		||||
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
 | 
			
		||||
static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
 | 
			
		||||
#define param_check_proto_abbrev(name, p)	__param_check(name, p, unsigned int)
 | 
			
		||||
#define param_set_proto_abbrev			psmouse_set_maxproto
 | 
			
		||||
#define param_get_proto_abbrev			psmouse_get_maxproto
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +57,7 @@ static unsigned int psmouse_resetafter;
 | 
			
		|||
module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 | 
			
		||||
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 | 
			
		||||
 | 
			
		||||
PSMOUSE_DEFINE_ATTR(protocol);
 | 
			
		||||
PSMOUSE_DEFINE_ATTR(rate);
 | 
			
		||||
PSMOUSE_DEFINE_ATTR(resolution);
 | 
			
		||||
PSMOUSE_DEFINE_ATTR(resetafter);
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +68,23 @@ __obsolete_setup("psmouse_smartscroll=");
 | 
			
		|||
__obsolete_setup("psmouse_resetafter=");
 | 
			
		||||
__obsolete_setup("psmouse_rate=");
 | 
			
		||||
 | 
			
		||||
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
 | 
			
		||||
/*
 | 
			
		||||
 * psmouse_sem protects all operations changing state of mouse
 | 
			
		||||
 * (connecting, disconnecting, changing rate or resolution via
 | 
			
		||||
 * sysfs). We could use a per-device semaphore but since there
 | 
			
		||||
 * rarely more than one PS/2 mouse connected and since semaphore
 | 
			
		||||
 * is taken in "slow" paths it is not worth it.
 | 
			
		||||
 */
 | 
			
		||||
static DECLARE_MUTEX(psmouse_sem);
 | 
			
		||||
 | 
			
		||||
struct psmouse_protocol {
 | 
			
		||||
	enum psmouse_type type;
 | 
			
		||||
	char *name;
 | 
			
		||||
	char *alias;
 | 
			
		||||
	int maxproto;
 | 
			
		||||
	int (*detect)(struct psmouse *, int);
 | 
			
		||||
	int (*init)(struct psmouse *);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * psmouse_process_byte() analyzes the PS/2 data stream and reports
 | 
			
		||||
| 
						 | 
				
			
			@ -407,12 +424,15 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
 | 
			
		|||
 */
 | 
			
		||||
static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
 | 
			
		||||
{
 | 
			
		||||
	if (set_properties) {
 | 
			
		||||
		if (!psmouse->vendor) psmouse->vendor = "Generic";
 | 
			
		||||
		if (!psmouse->name) psmouse->name = "Mouse";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
 | 
			
		||||
 * the mouse may have.
 | 
			
		||||
| 
						 | 
				
			
			@ -423,6 +443,17 @@ static int psmouse_extensions(struct psmouse *psmouse,
 | 
			
		|||
{
 | 
			
		||||
	int synaptics_hardware = 0;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * We always check for lifebook because it does not disturb mouse
 | 
			
		||||
 * (it only checks DMI information).
 | 
			
		||||
 */
 | 
			
		||||
	if (lifebook_detect(psmouse, set_properties) == 0) {
 | 
			
		||||
		if (max_proto > PSMOUSE_IMEX) {
 | 
			
		||||
			if (!set_properties || lifebook_init(psmouse) == 0)
 | 
			
		||||
				return PSMOUSE_LIFEBOOK;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Try Kensington ThinkingMouse (we try first, because synaptics probe
 | 
			
		||||
 * upsets the thinkingmouse).
 | 
			
		||||
| 
						 | 
				
			
			@ -506,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse,
 | 
			
		|||
	return PSMOUSE_PS2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct psmouse_protocol psmouse_protocols[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_PS2,
 | 
			
		||||
		.name		= "PS/2",
 | 
			
		||||
		.alias		= "bare",
 | 
			
		||||
		.maxproto	= 1,
 | 
			
		||||
		.detect		= ps2bare_detect,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_PS2PP,
 | 
			
		||||
		.name		= "PS2++",
 | 
			
		||||
		.alias		= "logitech",
 | 
			
		||||
		.detect		= ps2pp_init,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_THINKPS,
 | 
			
		||||
		.name		= "ThinkPS/2",
 | 
			
		||||
		.alias		= "thinkps",
 | 
			
		||||
		.detect		= thinking_detect,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_GENPS,
 | 
			
		||||
		.name		= "GenPS/2",
 | 
			
		||||
		.alias		= "genius",
 | 
			
		||||
		.detect		= genius_detect,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_IMPS,
 | 
			
		||||
		.name		= "ImPS/2",
 | 
			
		||||
		.alias		= "imps",
 | 
			
		||||
		.maxproto	= 1,
 | 
			
		||||
		.detect		= intellimouse_detect,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_IMEX,
 | 
			
		||||
		.name		= "ImExPS/2",
 | 
			
		||||
		.alias		= "exps",
 | 
			
		||||
		.maxproto	= 1,
 | 
			
		||||
		.detect		= im_explorer_detect,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_SYNAPTICS,
 | 
			
		||||
		.name		= "SynPS/2",
 | 
			
		||||
		.alias		= "synaptics",
 | 
			
		||||
		.detect		= synaptics_detect,
 | 
			
		||||
		.init		= synaptics_init,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_ALPS,
 | 
			
		||||
		.name		= "AlpsPS/2",
 | 
			
		||||
		.alias		= "alps",
 | 
			
		||||
		.detect		= alps_detect,
 | 
			
		||||
		.init		= alps_init,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_LIFEBOOK,
 | 
			
		||||
		.name		= "LBPS/2",
 | 
			
		||||
		.alias		= "lifebook",
 | 
			
		||||
		.init		= lifebook_init,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_AUTO,
 | 
			
		||||
		.name		= "auto",
 | 
			
		||||
		.alias		= "any",
 | 
			
		||||
		.maxproto	= 1,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++)
 | 
			
		||||
		if (psmouse_protocols[i].type == type)
 | 
			
		||||
			return &psmouse_protocols[i];
 | 
			
		||||
 | 
			
		||||
	WARN_ON(1);
 | 
			
		||||
	return &psmouse_protocols[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct psmouse_protocol *p;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
 | 
			
		||||
		p = &psmouse_protocols[i];
 | 
			
		||||
 | 
			
		||||
		if ((strlen(p->name) == len && !strncmp(p->name, name, len)) ||
 | 
			
		||||
		    (strlen(p->alias) == len && !strncmp(p->alias, name, len)))
 | 
			
		||||
			return &psmouse_protocols[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * psmouse_probe() probes for a PS/2 mouse.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -653,30 +781,84 @@ static void psmouse_cleanup(struct serio *serio)
 | 
			
		|||
 | 
			
		||||
static void psmouse_disconnect(struct serio *serio)
 | 
			
		||||
{
 | 
			
		||||
	struct psmouse *psmouse, *parent;
 | 
			
		||||
	struct psmouse *psmouse, *parent = NULL;
 | 
			
		||||
 | 
			
		||||
	psmouse = serio_get_drvdata(serio);
 | 
			
		||||
 | 
			
		||||
	device_remove_file(&serio->dev, &psmouse_attr_protocol);
 | 
			
		||||
	device_remove_file(&serio->dev, &psmouse_attr_rate);
 | 
			
		||||
	device_remove_file(&serio->dev, &psmouse_attr_resolution);
 | 
			
		||||
	device_remove_file(&serio->dev, &psmouse_attr_resetafter);
 | 
			
		||||
 | 
			
		||||
	psmouse = serio_get_drvdata(serio);
 | 
			
		||||
	down(&psmouse_sem);
 | 
			
		||||
 | 
			
		||||
	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 | 
			
		||||
 | 
			
		||||
	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
			
		||||
		parent = serio_get_drvdata(serio->parent);
 | 
			
		||||
		if (parent->pt_deactivate)
 | 
			
		||||
			parent->pt_deactivate(parent);
 | 
			
		||||
		psmouse_deactivate(parent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (psmouse->disconnect)
 | 
			
		||||
		psmouse->disconnect(psmouse);
 | 
			
		||||
 | 
			
		||||
	if (parent && parent->pt_deactivate)
 | 
			
		||||
		parent->pt_deactivate(parent);
 | 
			
		||||
 | 
			
		||||
	psmouse_set_state(psmouse, PSMOUSE_IGNORE);
 | 
			
		||||
 | 
			
		||||
	input_unregister_device(&psmouse->dev);
 | 
			
		||||
	serio_close(serio);
 | 
			
		||||
	serio_set_drvdata(serio, NULL);
 | 
			
		||||
	kfree(psmouse);
 | 
			
		||||
 | 
			
		||||
	if (parent)
 | 
			
		||||
		psmouse_activate(parent);
 | 
			
		||||
 | 
			
		||||
	up(&psmouse_sem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
 | 
			
		||||
{
 | 
			
		||||
	memset(&psmouse->dev, 0, sizeof(struct input_dev));
 | 
			
		||||
 | 
			
		||||
	init_input_dev(&psmouse->dev);
 | 
			
		||||
 | 
			
		||||
	psmouse->dev.private = psmouse;
 | 
			
		||||
	psmouse->dev.dev = &psmouse->ps2dev.serio->dev;
 | 
			
		||||
 | 
			
		||||
	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 | 
			
		||||
	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 | 
			
		||||
	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 | 
			
		||||
 | 
			
		||||
	psmouse->set_rate = psmouse_set_rate;
 | 
			
		||||
	psmouse->set_resolution = psmouse_set_resolution;
 | 
			
		||||
	psmouse->protocol_handler = psmouse_process_byte;
 | 
			
		||||
	psmouse->pktsize = 3;
 | 
			
		||||
 | 
			
		||||
	if (proto && (proto->detect || proto->init)) {
 | 
			
		||||
		if (proto->detect && proto->detect(psmouse, 1) < 0)
 | 
			
		||||
			return -1;
 | 
			
		||||
 | 
			
		||||
		if (proto->init && proto->init(psmouse) < 0)
 | 
			
		||||
			return -1;
 | 
			
		||||
 | 
			
		||||
		psmouse->type = proto->type;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
 | 
			
		||||
 | 
			
		||||
	sprintf(psmouse->devname, "%s %s %s",
 | 
			
		||||
		psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
 | 
			
		||||
 | 
			
		||||
	psmouse->dev.name = psmouse->devname;
 | 
			
		||||
	psmouse->dev.phys = psmouse->phys;
 | 
			
		||||
	psmouse->dev.id.bustype = BUS_I8042;
 | 
			
		||||
	psmouse->dev.id.vendor = 0x0002;
 | 
			
		||||
	psmouse->dev.id.product = psmouse->type;
 | 
			
		||||
	psmouse->dev.id.version = psmouse->model;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -688,6 +870,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
			
		|||
	struct psmouse *psmouse, *parent = NULL;
 | 
			
		||||
	int retval;
 | 
			
		||||
 | 
			
		||||
	down(&psmouse_sem);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If this is a pass-through port deactivate parent so the device
 | 
			
		||||
	 * connected to this port can be successfully identified
 | 
			
		||||
| 
						 | 
				
			
			@ -697,20 +881,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
			
		|||
		psmouse_deactivate(parent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
 | 
			
		||||
	if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
 | 
			
		||||
		retval = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memset(psmouse, 0, sizeof(struct psmouse));
 | 
			
		||||
 | 
			
		||||
	ps2_init(&psmouse->ps2dev, serio);
 | 
			
		||||
	sprintf(psmouse->phys, "%s/input0", serio->phys);
 | 
			
		||||
	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 | 
			
		||||
	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 | 
			
		||||
	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 | 
			
		||||
	psmouse->dev.private = psmouse;
 | 
			
		||||
	psmouse->dev.dev = &serio->dev;
 | 
			
		||||
 | 
			
		||||
	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 | 
			
		||||
 | 
			
		||||
	serio_set_drvdata(serio, psmouse);
 | 
			
		||||
| 
						 | 
				
			
			@ -734,25 +912,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
			
		|||
	psmouse->resolution = psmouse_resolution;
 | 
			
		||||
	psmouse->resetafter = psmouse_resetafter;
 | 
			
		||||
	psmouse->smartscroll = psmouse_smartscroll;
 | 
			
		||||
	psmouse->set_rate = psmouse_set_rate;
 | 
			
		||||
	psmouse->set_resolution = psmouse_set_resolution;
 | 
			
		||||
	psmouse->protocol_handler = psmouse_process_byte;
 | 
			
		||||
	psmouse->pktsize = 3;
 | 
			
		||||
 | 
			
		||||
	psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
 | 
			
		||||
 | 
			
		||||
	sprintf(psmouse->devname, "%s %s %s",
 | 
			
		||||
		psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
 | 
			
		||||
 | 
			
		||||
	psmouse->dev.name = psmouse->devname;
 | 
			
		||||
	psmouse->dev.phys = psmouse->phys;
 | 
			
		||||
	psmouse->dev.id.bustype = BUS_I8042;
 | 
			
		||||
	psmouse->dev.id.vendor = 0x0002;
 | 
			
		||||
	psmouse->dev.id.product = psmouse->type;
 | 
			
		||||
	psmouse->dev.id.version = psmouse->model;
 | 
			
		||||
	psmouse_switch_protocol(psmouse, NULL);
 | 
			
		||||
 | 
			
		||||
	input_register_device(&psmouse->dev);
 | 
			
		||||
 | 
			
		||||
	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 | 
			
		||||
 | 
			
		||||
	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 | 
			
		||||
| 
						 | 
				
			
			@ -762,6 +925,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
			
		|||
	if (parent && parent->pt_activate)
 | 
			
		||||
		parent->pt_activate(parent);
 | 
			
		||||
 | 
			
		||||
	device_create_file(&serio->dev, &psmouse_attr_protocol);
 | 
			
		||||
	device_create_file(&serio->dev, &psmouse_attr_rate);
 | 
			
		||||
	device_create_file(&serio->dev, &psmouse_attr_resolution);
 | 
			
		||||
	device_create_file(&serio->dev, &psmouse_attr_resetafter);
 | 
			
		||||
| 
						 | 
				
			
			@ -771,10 +935,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
			
		|||
	retval = 0;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	/* If this is a pass-through port the parent awaits to be activated */
 | 
			
		||||
	/* If this is a pass-through port the parent needs to be re-activated */
 | 
			
		||||
	if (parent)
 | 
			
		||||
		psmouse_activate(parent);
 | 
			
		||||
 | 
			
		||||
	up(&psmouse_sem);
 | 
			
		||||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -791,6 +956,8 @@ static int psmouse_reconnect(struct serio *serio)
 | 
			
		|||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	down(&psmouse_sem);
 | 
			
		||||
 | 
			
		||||
	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
			
		||||
		parent = serio_get_drvdata(serio->parent);
 | 
			
		||||
		psmouse_deactivate(parent);
 | 
			
		||||
| 
						 | 
				
			
			@ -823,6 +990,7 @@ out:
 | 
			
		|||
	if (parent)
 | 
			
		||||
		psmouse_activate(parent);
 | 
			
		||||
 | 
			
		||||
	up(&psmouse_sem);
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -893,26 +1061,109 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
 | 
			
		|||
 | 
			
		||||
	if (serio->drv != &psmouse_drv) {
 | 
			
		||||
		retval = -ENODEV;
 | 
			
		||||
		goto out;
 | 
			
		||||
		goto out_unpin;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	retval = down_interruptible(&psmouse_sem);
 | 
			
		||||
	if (retval)
 | 
			
		||||
		goto out_unpin;
 | 
			
		||||
 | 
			
		||||
	if (psmouse->state == PSMOUSE_IGNORE) {
 | 
			
		||||
		retval = -ENODEV;
 | 
			
		||||
		goto out_up;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
			
		||||
		parent = serio_get_drvdata(serio->parent);
 | 
			
		||||
		psmouse_deactivate(parent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	psmouse_deactivate(psmouse);
 | 
			
		||||
 | 
			
		||||
	retval = handler(psmouse, buf, count);
 | 
			
		||||
 | 
			
		||||
	if (retval != -ENODEV)
 | 
			
		||||
		psmouse_activate(psmouse);
 | 
			
		||||
 | 
			
		||||
	if (parent)
 | 
			
		||||
		psmouse_activate(parent);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
 out_up:
 | 
			
		||||
	up(&psmouse_sem);
 | 
			
		||||
 out_unpin:
 | 
			
		||||
	serio_unpin_driver(serio);
 | 
			
		||||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf)
 | 
			
		||||
{
 | 
			
		||||
	return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count)
 | 
			
		||||
{
 | 
			
		||||
	struct serio *serio = psmouse->ps2dev.serio;
 | 
			
		||||
	struct psmouse *parent = NULL;
 | 
			
		||||
	struct psmouse_protocol *proto;
 | 
			
		||||
	int retry = 0;
 | 
			
		||||
 | 
			
		||||
	if (!(proto = psmouse_protocol_by_name(buf, count)))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (psmouse->type == proto->type)
 | 
			
		||||
		return count;
 | 
			
		||||
 | 
			
		||||
	while (serio->child) {
 | 
			
		||||
		if (++retry > 3) {
 | 
			
		||||
			printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
 | 
			
		||||
			return -EIO;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		up(&psmouse_sem);
 | 
			
		||||
		serio_unpin_driver(serio);
 | 
			
		||||
		serio_unregister_child_port(serio);
 | 
			
		||||
		serio_pin_driver_uninterruptible(serio);
 | 
			
		||||
		down(&psmouse_sem);
 | 
			
		||||
 | 
			
		||||
		if (serio->drv != &psmouse_drv)
 | 
			
		||||
			return -ENODEV;
 | 
			
		||||
 | 
			
		||||
		if (psmouse->type == proto->type)
 | 
			
		||||
			return count; /* switched by other thread */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
			
		||||
		parent = serio_get_drvdata(serio->parent);
 | 
			
		||||
		if (parent->pt_deactivate)
 | 
			
		||||
			parent->pt_deactivate(parent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (psmouse->disconnect)
 | 
			
		||||
		psmouse->disconnect(psmouse);
 | 
			
		||||
 | 
			
		||||
	psmouse_set_state(psmouse, PSMOUSE_IGNORE);
 | 
			
		||||
	input_unregister_device(&psmouse->dev);
 | 
			
		||||
 | 
			
		||||
	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 | 
			
		||||
 | 
			
		||||
	if (psmouse_switch_protocol(psmouse, proto) < 0) {
 | 
			
		||||
		psmouse_reset(psmouse);
 | 
			
		||||
		/* default to PSMOUSE_PS2 */
 | 
			
		||||
		psmouse_switch_protocol(psmouse, &psmouse_protocols[0]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	psmouse_initialize(psmouse);
 | 
			
		||||
	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 | 
			
		||||
 | 
			
		||||
	input_register_device(&psmouse->dev);
 | 
			
		||||
	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 | 
			
		||||
 | 
			
		||||
	if (parent && parent->pt_activate)
 | 
			
		||||
		parent->pt_activate(parent);
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
 | 
			
		||||
{
 | 
			
		||||
	return sprintf(buf, "%d\n", psmouse->rate);
 | 
			
		||||
| 
						 | 
				
			
			@ -969,34 +1220,26 @@ static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *
 | 
			
		|||
 | 
			
		||||
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct psmouse_protocol *proto;
 | 
			
		||||
 | 
			
		||||
	if (!val)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (!strncmp(val, "any", 3)) {
 | 
			
		||||
		*((unsigned int *)kp->arg) = -1U;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	proto = psmouse_protocol_by_name(val, strlen(val));
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
 | 
			
		||||
		if (!psmouse_proto_abbrev[i])
 | 
			
		||||
			continue;
 | 
			
		||||
	if (!proto || !proto->maxproto)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
		if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
 | 
			
		||||
			*((unsigned int *)kp->arg) = i;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	*((unsigned int *)kp->arg) = proto->type;
 | 
			
		||||
 | 
			
		||||
	return -EINVAL;					\
 | 
			
		||||
	return 0;					\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	return sprintf(buffer, "%s\n",
 | 
			
		||||
			psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
 | 
			
		||||
				psmouse_proto_abbrev[psmouse_max_proto] : "any");
 | 
			
		||||
	int type = *((unsigned int *)kp->arg);
 | 
			
		||||
 | 
			
		||||
	return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __init psmouse_init(void)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,6 +77,8 @@ enum psmouse_type {
 | 
			
		|||
	PSMOUSE_IMEX,
 | 
			
		||||
	PSMOUSE_SYNAPTICS,
 | 
			
		||||
	PSMOUSE_ALPS,
 | 
			
		||||
	PSMOUSE_LIFEBOOK,
 | 
			
		||||
	PSMOUSE_AUTO		/* This one should always be last */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -220,6 +220,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
 | 
			
		|||
	struct mousedev_list *list;
 | 
			
		||||
	struct mousedev_motion *p;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int wake_readers = 0;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(list, &mousedev->list, node) {
 | 
			
		||||
		spin_lock_irqsave(&list->packet_lock, flags);
 | 
			
		||||
| 
						 | 
				
			
			@ -255,10 +256,13 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
 | 
			
		|||
 | 
			
		||||
		spin_unlock_irqrestore(&list->packet_lock, flags);
 | 
			
		||||
 | 
			
		||||
		if (list->ready)
 | 
			
		||||
		if (list->ready) {
 | 
			
		||||
			kill_fasync(&list->fasync, SIGIO, POLL_IN);
 | 
			
		||||
			wake_readers = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wake_readers)
 | 
			
		||||
		wake_up_interruptible(&mousedev->wait);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
 | 
			
		|||
 | 
			
		||||
EXPORT_SYMBOL(ps2_init);
 | 
			
		||||
EXPORT_SYMBOL(ps2_sendbyte);
 | 
			
		||||
EXPORT_SYMBOL(ps2_drain);
 | 
			
		||||
EXPORT_SYMBOL(ps2_command);
 | 
			
		||||
EXPORT_SYMBOL(ps2_schedule_command);
 | 
			
		||||
EXPORT_SYMBOL(ps2_handle_ack);
 | 
			
		||||
| 
						 | 
				
			
			@ -45,11 +46,11 @@ struct ps2work {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge.
 | 
			
		||||
 * It doesn't handle retransmission, though it could - because when there would
 | 
			
		||||
 * be need for retransmissions, the mouse has to be replaced anyway.
 | 
			
		||||
 * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
 | 
			
		||||
 * It doesn't handle retransmission, though it could - because if there
 | 
			
		||||
 * is a need for retransmissions device has to be replaced anyway.
 | 
			
		||||
 *
 | 
			
		||||
 * ps2_sendbyte() can only be called from a process context
 | 
			
		||||
 * ps2_sendbyte() can only be called from a process context.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +72,91 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
 | 
			
		|||
	return -ps2dev->nak;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ps2_drain() waits for device to transmit requested number of bytes
 | 
			
		||||
 * and discards them.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
 | 
			
		||||
{
 | 
			
		||||
	if (maxbytes > sizeof(ps2dev->cmdbuf)) {
 | 
			
		||||
		WARN_ON(1);
 | 
			
		||||
		maxbytes = sizeof(ps2dev->cmdbuf);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	down(&ps2dev->cmd_sem);
 | 
			
		||||
 | 
			
		||||
	serio_pause_rx(ps2dev->serio);
 | 
			
		||||
	ps2dev->flags = PS2_FLAG_CMD;
 | 
			
		||||
	ps2dev->cmdcnt = maxbytes;
 | 
			
		||||
	serio_continue_rx(ps2dev->serio);
 | 
			
		||||
 | 
			
		||||
	wait_event_timeout(ps2dev->wait,
 | 
			
		||||
			   !(ps2dev->flags & PS2_FLAG_CMD),
 | 
			
		||||
			   msecs_to_jiffies(timeout));
 | 
			
		||||
	up(&ps2dev->cmd_sem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ps2_is_keyboard_id() checks received ID byte against the list of
 | 
			
		||||
 * known keyboard IDs.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static inline int ps2_is_keyboard_id(char id_byte)
 | 
			
		||||
{
 | 
			
		||||
	static char keyboard_ids[] = {
 | 
			
		||||
		0xab,	/* Regular keyboards		*/
 | 
			
		||||
		0xac,	/* NCD Sun keyboard		*/
 | 
			
		||||
		0x2b,	/* Trust keyboard, translated	*/
 | 
			
		||||
		0x5d,	/* Trust keyboard		*/
 | 
			
		||||
		0x60,	/* NMB SGI keyboard, translated */
 | 
			
		||||
		0x47,	/* NMB SGI keyboard		*/
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ps2_adjust_timeout() is called after receiving 1st byte of command
 | 
			
		||||
 * response and tries to reduce remaining timeout to speed up command
 | 
			
		||||
 * completion.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
 | 
			
		||||
{
 | 
			
		||||
	switch (command) {
 | 
			
		||||
		case PS2_CMD_RESET_BAT:
 | 
			
		||||
			/*
 | 
			
		||||
			 * Device has sent the first response byte after
 | 
			
		||||
			 * reset command, reset is thus done, so we can
 | 
			
		||||
			 * shorten the timeout.
 | 
			
		||||
			 * The next byte will come soon (keyboard) or not
 | 
			
		||||
			 * at all (mouse).
 | 
			
		||||
			 */
 | 
			
		||||
			if (timeout > msecs_to_jiffies(100))
 | 
			
		||||
				timeout = msecs_to_jiffies(100);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case PS2_CMD_GETID:
 | 
			
		||||
			/*
 | 
			
		||||
			 * If device behind the port is not a keyboard there
 | 
			
		||||
			 * won't be 2nd byte of ID response.
 | 
			
		||||
			 */
 | 
			
		||||
			if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
 | 
			
		||||
				serio_pause_rx(ps2dev->serio);
 | 
			
		||||
				ps2dev->flags = ps2dev->cmdcnt = 0;
 | 
			
		||||
				serio_continue_rx(ps2dev->serio);
 | 
			
		||||
				timeout = 0;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return timeout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ps2_command() sends a command and its parameters to the mouse,
 | 
			
		||||
 * then waits for the response and puts it in the param array.
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +172,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 | 
			
		|||
	int rc = -1;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (receive > sizeof(ps2dev->cmdbuf)) {
 | 
			
		||||
		WARN_ON(1);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	down(&ps2dev->cmd_sem);
 | 
			
		||||
 | 
			
		||||
	serio_pause_rx(ps2dev->serio);
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +192,6 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 | 
			
		|||
	 * ACKing the reset command, and so it can take a long
 | 
			
		||||
	 * time before the ACK arrrives.
 | 
			
		||||
	 */
 | 
			
		||||
	if (command & 0xff)
 | 
			
		||||
	if (ps2_sendbyte(ps2dev, command & 0xff,
 | 
			
		||||
			 command == PS2_CMD_RESET_BAT ? 1000 : 200))
 | 
			
		||||
		goto out;
 | 
			
		||||
| 
						 | 
				
			
			@ -120,33 +210,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 | 
			
		|||
 | 
			
		||||
	if (ps2dev->cmdcnt && timeout > 0) {
 | 
			
		||||
 | 
			
		||||
		if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * Device has sent the first response byte
 | 
			
		||||
			 * after a reset command, reset is thus done,
 | 
			
		||||
			 * shorten the timeout. The next byte will come
 | 
			
		||||
			 * soon (keyboard) or not at all (mouse).
 | 
			
		||||
			 */
 | 
			
		||||
			timeout = msecs_to_jiffies(100);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (command == PS2_CMD_GETID &&
 | 
			
		||||
		    ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
 | 
			
		||||
		    ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
 | 
			
		||||
		    ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
 | 
			
		||||
		    ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
 | 
			
		||||
		    ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
 | 
			
		||||
		    ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
 | 
			
		||||
			/*
 | 
			
		||||
			 * Device behind the port is not a keyboard
 | 
			
		||||
			 * so we don't need to wait for the 2nd byte
 | 
			
		||||
			 * of ID response.
 | 
			
		||||
			 */
 | 
			
		||||
			serio_pause_rx(ps2dev->serio);
 | 
			
		||||
			ps2dev->flags = ps2dev->cmdcnt = 0;
 | 
			
		||||
			serio_continue_rx(ps2dev->serio);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		timeout = ps2_adjust_timeout(ps2dev, command, timeout);
 | 
			
		||||
		wait_event_timeout(ps2dev->wait,
 | 
			
		||||
				   !(ps2dev->flags & PS2_FLAG_CMD), timeout);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,7 +77,6 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
 | 
			
		|||
#define MK712_READ_ONE_POINT			0x20
 | 
			
		||||
#define MK712_POWERUP				0x40
 | 
			
		||||
 | 
			
		||||
static int mk712_used = 0;
 | 
			
		||||
static struct input_dev mk712_dev;
 | 
			
		||||
static DEFINE_SPINLOCK(mk712_lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -130,8 +129,6 @@ static int mk712_open(struct input_dev *dev)
 | 
			
		|||
 | 
			
		||||
	spin_lock_irqsave(&mk712_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (!mk712_used++) {
 | 
			
		||||
 | 
			
		||||
	outb(0, mk712_io + MK712_CONTROL); /* Reset */
 | 
			
		||||
 | 
			
		||||
	outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
 | 
			
		||||
| 
						 | 
				
			
			@ -140,7 +137,6 @@ static int mk712_open(struct input_dev *dev)
 | 
			
		|||
		MK712_POWERUP, mk712_io + MK712_CONTROL);
 | 
			
		||||
 | 
			
		||||
	outb(10, mk712_io + MK712_RATE); /* 187 points per second */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&mk712_lock, flags);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +149,6 @@ static void mk712_close(struct input_dev *dev)
 | 
			
		|||
 | 
			
		||||
	spin_lock_irqsave(&mk712_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (!--mk712_used)
 | 
			
		||||
	outb(0, mk712_io + MK712_CONTROL);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&mk712_lock, flags);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,33 +86,18 @@ config PMAC_SMU
 | 
			
		|||
	  on the "SMU" system control chip which replaces the old PMU.
 | 
			
		||||
	  If you don't know, say Y.
 | 
			
		||||
 | 
			
		||||
config PMAC_PBOOK
 | 
			
		||||
	bool "Power management support for PowerBooks"
 | 
			
		||||
	depends on ADB_PMU
 | 
			
		||||
	---help---
 | 
			
		||||
	  This provides support for putting a PowerBook to sleep; it also
 | 
			
		||||
	  enables media bay support.  Power management works on the
 | 
			
		||||
	  PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and
 | 
			
		||||
	  the Titanium Powerbook G4, as well as the iBooks.  You should get
 | 
			
		||||
	  the power management daemon, pmud, to make it work and you must have
 | 
			
		||||
	  the /dev/pmu device (see the pmud README).
 | 
			
		||||
 | 
			
		||||
	  Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
 | 
			
		||||
 | 
			
		||||
	  If you have a PowerBook, you should say Y here.
 | 
			
		||||
 | 
			
		||||
	  You may also want to compile the dma sound driver as a module and
 | 
			
		||||
	  have it autoloaded. The act of removing the module shuts down the
 | 
			
		||||
	  sound hardware for more power savings.
 | 
			
		||||
 | 
			
		||||
config PM
 | 
			
		||||
	bool
 | 
			
		||||
	depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
 | 
			
		||||
	default y
 | 
			
		||||
 | 
			
		||||
config PMAC_APM_EMU
 | 
			
		||||
	tristate "APM emulation"
 | 
			
		||||
	depends on PMAC_PBOOK
 | 
			
		||||
	depends on PPC_PMAC && PPC32 && PM
 | 
			
		||||
 | 
			
		||||
config PMAC_MEDIABAY
 | 
			
		||||
	bool "Support PowerBook hotswap media bay"
 | 
			
		||||
	depends on PPC_PMAC && PPC32
 | 
			
		||||
	help
 | 
			
		||||
	  This option adds support for older PowerBook's hotswap media bay
 | 
			
		||||
	  that can contains batteries, floppy drives, or IDE devices. PCI
 | 
			
		||||
	  devices are not fully supported in the bay as I never had one to
 | 
			
		||||
	  try with
 | 
			
		||||
 | 
			
		||||
# made a separate option since backlight may end up beeing used
 | 
			
		||||
# on non-powerbook machines (but only on PMU based ones AFAIK)
 | 
			
		||||
| 
						 | 
				
			
			@ -126,13 +111,6 @@ config PMAC_BACKLIGHT
 | 
			
		|||
	  events; also, the PowerBook button device will be enabled so you can
 | 
			
		||||
	  change the screen brightness.
 | 
			
		||||
 | 
			
		||||
config MAC_SERIAL
 | 
			
		||||
	tristate "Support for PowerMac serial ports (OBSOLETE DRIVER)"
 | 
			
		||||
	depends on PPC_PMAC && BROKEN
 | 
			
		||||
	help
 | 
			
		||||
	  This driver is obsolete. Use CONFIG_SERIAL_PMACZILOG in
 | 
			
		||||
	  "Character devices --> Serial drivers --> PowerMac z85c30" option.
 | 
			
		||||
 | 
			
		||||
config ADB_MACIO
 | 
			
		||||
	bool "Include MacIO (CHRP) ADB driver"
 | 
			
		||||
	depends on ADB && PPC_CHRP && !PPC_PMAC64
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,8 +6,7 @@
 | 
			
		|||
 | 
			
		||||
obj-$(CONFIG_PPC_PMAC)		+= macio_asic.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_PMAC_PBOOK)	+= mediabay.o
 | 
			
		||||
obj-$(CONFIG_MAC_SERIAL)	+= macserial.o
 | 
			
		||||
obj-$(CONFIG_PMAC_MEDIABAY)	+= mediabay.o
 | 
			
		||||
obj-$(CONFIG_MAC_EMUMOUSEBTN)	+= mac_hid.o
 | 
			
		||||
obj-$(CONFIG_INPUT_ADBHID)	+= adbhid.o
 | 
			
		||||
obj-$(CONFIG_ANSLCD)		+= ans-lcd.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ static int sleepy_trackpad;
 | 
			
		|||
static int autopoll_devs;
 | 
			
		||||
int __adb_probe_sync;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
 | 
			
		||||
static struct pmu_sleep_notifier adb_sleep_notifier = {
 | 
			
		||||
	adb_notify_sleep,
 | 
			
		||||
| 
						 | 
				
			
			@ -320,9 +320,9 @@ int __init adb_init(void)
 | 
			
		|||
		printk(KERN_WARNING "Warning: no ADB interface detected\n");
 | 
			
		||||
		adb_controller = NULL;
 | 
			
		||||
	} else {
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
		pmu_register_sleep_notifier(&adb_sleep_notifier);
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif /* CONFIG_PM */
 | 
			
		||||
#ifdef CONFIG_PPC
 | 
			
		||||
		if (machine_is_compatible("AAPL,PowerBook1998") ||
 | 
			
		||||
			machine_is_compatible("PowerBook1,1"))
 | 
			
		||||
| 
						 | 
				
			
			@ -337,7 +337,7 @@ int __init adb_init(void)
 | 
			
		|||
 | 
			
		||||
__initcall(adb_init);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
/*
 | 
			
		||||
 * notify clients before sleep and reset bus afterwards
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +378,7 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
 | 
			
		|||
	}
 | 
			
		||||
	return PBOOK_SLEEP_OK;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif /* CONFIG_PM */
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
do_adb_reset_bus(void)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -1,461 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * macserial.h: Definitions for the Macintosh Z8530 serial driver.
 | 
			
		||||
 *
 | 
			
		||||
 * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
 | 
			
		||||
 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 | 
			
		||||
 */
 | 
			
		||||
#ifndef _MACSERIAL_H
 | 
			
		||||
#define _MACSERIAL_H
 | 
			
		||||
 | 
			
		||||
#include <linux/spinlock.h>
 | 
			
		||||
 | 
			
		||||
#define NUM_ZSREGS    16
 | 
			
		||||
 | 
			
		||||
struct serial_struct {
 | 
			
		||||
	int	type;
 | 
			
		||||
	int	line;
 | 
			
		||||
	int	port;
 | 
			
		||||
	int	irq;
 | 
			
		||||
	int	flags;
 | 
			
		||||
	int	xmit_fifo_size;
 | 
			
		||||
	int	custom_divisor;
 | 
			
		||||
	int	baud_base;
 | 
			
		||||
	unsigned short	close_delay;
 | 
			
		||||
	char	reserved_char[2];
 | 
			
		||||
	int	hub6;
 | 
			
		||||
	unsigned short	closing_wait; /* time to wait before closing */
 | 
			
		||||
	unsigned short	closing_wait2; /* no longer used... */
 | 
			
		||||
	int	reserved[4];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * For the close wait times, 0 means wait forever for serial port to
 | 
			
		||||
 * flush its output.  65535 means don't wait at all.
 | 
			
		||||
 */
 | 
			
		||||
#define ZILOG_CLOSING_WAIT_INF	0
 | 
			
		||||
#define ZILOG_CLOSING_WAIT_NONE	65535
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Definitions for ZILOG_struct (and serial_struct) flags field
 | 
			
		||||
 */
 | 
			
		||||
#define ZILOG_HUP_NOTIFY	0x0001	/* Notify getty on hangups and closes 
 | 
			
		||||
				   	 * on the callout port */
 | 
			
		||||
#define ZILOG_FOURPORT 		0x0002	/* Set OU1, OUT2 per AST Fourport settings */
 | 
			
		||||
#define ZILOG_SAK		0x0004	/* Secure Attention Key (Orange book) */
 | 
			
		||||
#define ZILOG_SPLIT_TERMIOS	0x0008	/* Separate termios for dialin/callout */
 | 
			
		||||
 | 
			
		||||
#define ZILOG_SPD_MASK		0x0030
 | 
			
		||||
#define ZILOG_SPD_HI		0x0010	/* Use 56000 instead of 38400 bps */
 | 
			
		||||
 | 
			
		||||
#define ZILOG_SPD_VHI		0x0020  /* Use 115200 instead of 38400 bps */
 | 
			
		||||
#define ZILOG_SPD_CUST		0x0030  /* Use user-specified divisor */
 | 
			
		||||
 | 
			
		||||
#define ZILOG_SKIP_TEST		0x0040	/* Skip UART test during autoconfiguration */
 | 
			
		||||
#define ZILOG_AUTO_IRQ 		0x0080	/* Do automatic IRQ during autoconfiguration */
 | 
			
		||||
#define ZILOG_SESSION_LOCKOUT	0x0100	/* Lock out cua opens based on session */
 | 
			
		||||
#define ZILOG_PGRP_LOCKOUT	0x0200	/* Lock out cua opens based on pgrp */
 | 
			
		||||
#define ZILOG_CALLOUT_NOHUP	0x0400	/* Don't do hangups for cua device */
 | 
			
		||||
 | 
			
		||||
#define ZILOG_FLAGS		0x0FFF	/* Possible legal ZILOG flags */
 | 
			
		||||
#define ZILOG_USR_MASK		0x0430	/* Legal flags that non-privileged
 | 
			
		||||
					 * users can set or reset */
 | 
			
		||||
 | 
			
		||||
/* Internal flags used only by kernel/chr_drv/serial.c */
 | 
			
		||||
#define ZILOG_INITIALIZED	0x80000000 /* Serial port was initialized */
 | 
			
		||||
#define ZILOG_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
 | 
			
		||||
#define ZILOG_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
 | 
			
		||||
#define ZILOG_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
 | 
			
		||||
#define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
 | 
			
		||||
#define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
 | 
			
		||||
#define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
 | 
			
		||||
#define ZILOG_SLEEPING		0x01000000 /* have shut it down for sleep */
 | 
			
		||||
 | 
			
		||||
/* Software state per channel */
 | 
			
		||||
 | 
			
		||||
#ifdef __KERNEL__
 | 
			
		||||
/*
 | 
			
		||||
 * This is our internal structure for each serial port's state.
 | 
			
		||||
 * 
 | 
			
		||||
 * Many fields are paralleled by the structure used by the serial_struct
 | 
			
		||||
 * structure.
 | 
			
		||||
 *
 | 
			
		||||
 * For definitions of the flags field, see tty.h
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct mac_serial;
 | 
			
		||||
 | 
			
		||||
struct mac_zschannel {
 | 
			
		||||
	volatile unsigned char*	control;
 | 
			
		||||
	volatile unsigned char*	data;
 | 
			
		||||
	spinlock_t		lock;
 | 
			
		||||
	/* Used for debugging */
 | 
			
		||||
	struct mac_serial*	parent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mac_dma {
 | 
			
		||||
	volatile struct dbdma_regs	dma;
 | 
			
		||||
	volatile unsigned short		res_count;
 | 
			
		||||
	volatile unsigned short		command;
 | 
			
		||||
	volatile unsigned int		buf_addr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mac_serial {
 | 
			
		||||
	struct mac_serial *zs_next;	/* For IRQ servicing chain */
 | 
			
		||||
	struct mac_zschannel *zs_channel; /* Channel registers */
 | 
			
		||||
	struct mac_zschannel *zs_chan_a;	/* A side registers */
 | 
			
		||||
	unsigned char read_reg_zero;
 | 
			
		||||
	struct device_node* dev_node;
 | 
			
		||||
	spinlock_t lock;
 | 
			
		||||
 | 
			
		||||
	char soft_carrier;  /* Use soft carrier on this channel */
 | 
			
		||||
	char break_abort;   /* Is serial console in, so process brk/abrt */
 | 
			
		||||
	char kgdb_channel;  /* Kgdb is running on this channel */
 | 
			
		||||
	char is_cons;       /* Is this our console. */
 | 
			
		||||
	char is_internal_modem; /* is connected to an internal modem */
 | 
			
		||||
	char is_irda;		/* is connected to an IrDA codec */
 | 
			
		||||
	int port_type;		/* Port type for pmac_feature */
 | 
			
		||||
	unsigned char tx_active; /* character is being xmitted */
 | 
			
		||||
	unsigned char tx_stopped; /* output is suspended */
 | 
			
		||||
	unsigned char power_wait; /* waiting for power-up delay to expire */
 | 
			
		||||
 | 
			
		||||
	/* We need to know the current clock divisor
 | 
			
		||||
	 * to read the bps rate the chip has currently
 | 
			
		||||
	 * loaded.
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
 | 
			
		||||
	int zs_baud;
 | 
			
		||||
 | 
			
		||||
	/* Current write register values */
 | 
			
		||||
	unsigned char curregs[NUM_ZSREGS];
 | 
			
		||||
 | 
			
		||||
	/* Values we need to set next opportunity */
 | 
			
		||||
	unsigned char pendregs[NUM_ZSREGS];
 | 
			
		||||
 | 
			
		||||
	char change_needed;
 | 
			
		||||
 | 
			
		||||
	int			magic;
 | 
			
		||||
	int			baud_base;
 | 
			
		||||
	int			port;
 | 
			
		||||
	int			irq;
 | 
			
		||||
	int			flags; 		/* defined in tty.h */
 | 
			
		||||
	int			type; 		/* UART type */
 | 
			
		||||
	struct tty_struct 	*tty;
 | 
			
		||||
	int			read_status_mask;
 | 
			
		||||
	int			ignore_status_mask;
 | 
			
		||||
	int			timeout;
 | 
			
		||||
	int			xmit_fifo_size;
 | 
			
		||||
	int			custom_divisor;
 | 
			
		||||
	int			x_char;	/* xon/xoff character */
 | 
			
		||||
	int			close_delay;
 | 
			
		||||
	unsigned short		closing_wait;
 | 
			
		||||
	unsigned short		closing_wait2;
 | 
			
		||||
	unsigned long		event;
 | 
			
		||||
	unsigned long		last_active;
 | 
			
		||||
	int			line;
 | 
			
		||||
	int			count;	    /* # of fd on device */
 | 
			
		||||
	int			blocked_open; /* # of blocked opens */
 | 
			
		||||
	unsigned char 		*xmit_buf;
 | 
			
		||||
	int			xmit_head;
 | 
			
		||||
	int			xmit_tail;
 | 
			
		||||
	int			xmit_cnt;
 | 
			
		||||
	struct work_struct	tqueue;
 | 
			
		||||
	wait_queue_head_t	open_wait;
 | 
			
		||||
	wait_queue_head_t	close_wait;
 | 
			
		||||
 | 
			
		||||
	volatile struct dbdma_regs *tx_dma;
 | 
			
		||||
	int			tx_dma_irq;
 | 
			
		||||
	volatile struct dbdma_cmd *tx_cmds;
 | 
			
		||||
	volatile struct mac_dma *rx;
 | 
			
		||||
	int 			rx_dma_irq;
 | 
			
		||||
	volatile struct dbdma_cmd **rx_cmds;
 | 
			
		||||
	unsigned char		**rx_char_buf;
 | 
			
		||||
	unsigned char		**rx_flag_buf;
 | 
			
		||||
#define	RX_BUF_SIZE	256
 | 
			
		||||
	int			rx_nbuf;
 | 
			
		||||
	int			rx_done_bytes;
 | 
			
		||||
	int			rx_ubuf;
 | 
			
		||||
	int			rx_fbuf;
 | 
			
		||||
#define	RX_NO_FBUF	(-1)
 | 
			
		||||
	int			rx_cbuf;
 | 
			
		||||
	spinlock_t		rx_dma_lock;
 | 
			
		||||
	int			has_dma;
 | 
			
		||||
	int			dma_initted;
 | 
			
		||||
	void			*dma_priv;
 | 
			
		||||
	struct timer_list	poll_dma_timer;
 | 
			
		||||
#define RX_DMA_TIMER	(jiffies + 10*HZ/1000)
 | 
			
		||||
 | 
			
		||||
	struct timer_list	powerup_timer;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SERIAL_MAGIC 0x5301
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The size of the serial xmit buffer is 1 page, or 4096 bytes
 | 
			
		||||
 */
 | 
			
		||||
#define SERIAL_XMIT_SIZE 4096
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Events are used to schedule things to happen at timer-interrupt
 | 
			
		||||
 * time, instead of at rs interrupt time.
 | 
			
		||||
 */
 | 
			
		||||
#define RS_EVENT_WRITE_WAKEUP	0
 | 
			
		||||
 | 
			
		||||
#endif /* __KERNEL__ */
 | 
			
		||||
 | 
			
		||||
/* Conversion routines to/from brg time constants from/to bits
 | 
			
		||||
 * per second.
 | 
			
		||||
 */
 | 
			
		||||
#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
 | 
			
		||||
#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
 | 
			
		||||
 | 
			
		||||
/* The Zilog register set */
 | 
			
		||||
 | 
			
		||||
#define	FLAG	0x7e
 | 
			
		||||
 | 
			
		||||
/* Write Register 0 */
 | 
			
		||||
#define	R0	0		/* Register selects */
 | 
			
		||||
#define	R1	1
 | 
			
		||||
#define	R2	2
 | 
			
		||||
#define	R3	3
 | 
			
		||||
#define	R4	4
 | 
			
		||||
#define	R5	5
 | 
			
		||||
#define	R6	6
 | 
			
		||||
#define	R7	7
 | 
			
		||||
#define	R8	8
 | 
			
		||||
#define	R9	9
 | 
			
		||||
#define	R10	10
 | 
			
		||||
#define	R11	11
 | 
			
		||||
#define	R12	12
 | 
			
		||||
#define	R13	13
 | 
			
		||||
#define	R14	14
 | 
			
		||||
#define	R15	15
 | 
			
		||||
 | 
			
		||||
#define	NULLCODE	0	/* Null Code */
 | 
			
		||||
#define	POINT_HIGH	0x8	/* Select upper half of registers */
 | 
			
		||||
#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
 | 
			
		||||
#define	SEND_ABORT	0x18	/* HDLC Abort */
 | 
			
		||||
#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
 | 
			
		||||
#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
 | 
			
		||||
#define	ERR_RES		0x30	/* Error Reset */
 | 
			
		||||
#define	RES_H_IUS	0x38	/* Reset highest IUS */
 | 
			
		||||
 | 
			
		||||
#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
 | 
			
		||||
#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
 | 
			
		||||
#define	RES_EOM_L	0xC0	/* Reset EOM latch */
 | 
			
		||||
 | 
			
		||||
/* Write Register 1 */
 | 
			
		||||
 | 
			
		||||
#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
 | 
			
		||||
#define	TxINT_ENAB	0x2	/* Tx Int Enable */
 | 
			
		||||
#define	PAR_SPEC	0x4	/* Parity is special condition */
 | 
			
		||||
 | 
			
		||||
#define	RxINT_DISAB	0	/* Rx Int Disable */
 | 
			
		||||
#define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
 | 
			
		||||
#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
 | 
			
		||||
#define	INT_ERR_Rx	0x18	/* Int on error only */
 | 
			
		||||
 | 
			
		||||
#define	WT_RDY_RT	0x20	/* W/Req reflects recv if 1, xmit if 0 */
 | 
			
		||||
#define	WT_FN_RDYFN	0x40	/* W/Req pin is DMA request if 1, wait if 0 */
 | 
			
		||||
#define	WT_RDY_ENAB	0x80	/* Enable W/Req pin */
 | 
			
		||||
 | 
			
		||||
/* Write Register #2 (Interrupt Vector) */
 | 
			
		||||
 | 
			
		||||
/* Write Register 3 */
 | 
			
		||||
 | 
			
		||||
#define	RxENABLE	0x1	/* Rx Enable */
 | 
			
		||||
#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
 | 
			
		||||
#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
 | 
			
		||||
#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
 | 
			
		||||
#define	ENT_HM		0x10	/* Enter Hunt Mode */
 | 
			
		||||
#define	AUTO_ENAB	0x20	/* Auto Enables */
 | 
			
		||||
#define	Rx5		0x0	/* Rx 5 Bits/Character */
 | 
			
		||||
#define	Rx7		0x40	/* Rx 7 Bits/Character */
 | 
			
		||||
#define	Rx6		0x80	/* Rx 6 Bits/Character */
 | 
			
		||||
#define	Rx8		0xc0	/* Rx 8 Bits/Character */
 | 
			
		||||
#define RxNBITS_MASK	0xc0
 | 
			
		||||
 | 
			
		||||
/* Write Register 4 */
 | 
			
		||||
 | 
			
		||||
#define	PAR_ENA		0x1	/* Parity Enable */
 | 
			
		||||
#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
 | 
			
		||||
 | 
			
		||||
#define	SYNC_ENAB	0	/* Sync Modes Enable */
 | 
			
		||||
#define	SB1		0x4	/* 1 stop bit/char */
 | 
			
		||||
#define	SB15		0x8	/* 1.5 stop bits/char */
 | 
			
		||||
#define	SB2		0xc	/* 2 stop bits/char */
 | 
			
		||||
#define SB_MASK		0xc
 | 
			
		||||
 | 
			
		||||
#define	MONSYNC		0	/* 8 Bit Sync character */
 | 
			
		||||
#define	BISYNC		0x10	/* 16 bit sync character */
 | 
			
		||||
#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
 | 
			
		||||
#define	EXTSYNC		0x30	/* External Sync Mode */
 | 
			
		||||
 | 
			
		||||
#define	X1CLK		0x0	/* x1 clock mode */
 | 
			
		||||
#define	X16CLK		0x40	/* x16 clock mode */
 | 
			
		||||
#define	X32CLK		0x80	/* x32 clock mode */
 | 
			
		||||
#define	X64CLK		0xC0	/* x64 clock mode */
 | 
			
		||||
#define XCLK_MASK	0xC0
 | 
			
		||||
 | 
			
		||||
/* Write Register 5 */
 | 
			
		||||
 | 
			
		||||
#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
 | 
			
		||||
#define	RTS		0x2	/* RTS */
 | 
			
		||||
#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
 | 
			
		||||
#define	TxENAB		0x8	/* Tx Enable */
 | 
			
		||||
#define	SND_BRK		0x10	/* Send Break */
 | 
			
		||||
#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
 | 
			
		||||
#define	Tx7		0x20	/* Tx 7 bits/character */
 | 
			
		||||
#define	Tx6		0x40	/* Tx 6 bits/character */
 | 
			
		||||
#define	Tx8		0x60	/* Tx 8 bits/character */
 | 
			
		||||
#define TxNBITS_MASK	0x60
 | 
			
		||||
#define	DTR		0x80	/* DTR */
 | 
			
		||||
 | 
			
		||||
/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
 | 
			
		||||
 | 
			
		||||
/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
 | 
			
		||||
 | 
			
		||||
/* Write Register 7' (Some enhanced feature control) */
 | 
			
		||||
#define	ENEXREAD	0x40	/* Enable read of some write registers */
 | 
			
		||||
 | 
			
		||||
/* Write Register 8 (transmit buffer) */
 | 
			
		||||
 | 
			
		||||
/* Write Register 9 (Master interrupt control) */
 | 
			
		||||
#define	VIS	1	/* Vector Includes Status */
 | 
			
		||||
#define	NV	2	/* No Vector */
 | 
			
		||||
#define	DLC	4	/* Disable Lower Chain */
 | 
			
		||||
#define	MIE	8	/* Master Interrupt Enable */
 | 
			
		||||
#define	STATHI	0x10	/* Status high */
 | 
			
		||||
#define	NORESET	0	/* No reset on write to R9 */
 | 
			
		||||
#define	CHRB	0x40	/* Reset channel B */
 | 
			
		||||
#define	CHRA	0x80	/* Reset channel A */
 | 
			
		||||
#define	FHWRES	0xc0	/* Force hardware reset */
 | 
			
		||||
 | 
			
		||||
/* Write Register 10 (misc control bits) */
 | 
			
		||||
#define	BIT6	1	/* 6 bit/8bit sync */
 | 
			
		||||
#define	LOOPMODE 2	/* SDLC Loop mode */
 | 
			
		||||
#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
 | 
			
		||||
#define	MARKIDLE 8	/* Mark/flag on idle */
 | 
			
		||||
#define	GAOP	0x10	/* Go active on poll */
 | 
			
		||||
#define	NRZ	0	/* NRZ mode */
 | 
			
		||||
#define	NRZI	0x20	/* NRZI mode */
 | 
			
		||||
#define	FM1	0x40	/* FM1 (transition = 1) */
 | 
			
		||||
#define	FM0	0x60	/* FM0 (transition = 0) */
 | 
			
		||||
#define	CRCPS	0x80	/* CRC Preset I/O */
 | 
			
		||||
 | 
			
		||||
/* Write Register 11 (Clock Mode control) */
 | 
			
		||||
#define	TRxCXT	0	/* TRxC = Xtal output */
 | 
			
		||||
#define	TRxCTC	1	/* TRxC = Transmit clock */
 | 
			
		||||
#define	TRxCBR	2	/* TRxC = BR Generator Output */
 | 
			
		||||
#define	TRxCDP	3	/* TRxC = DPLL output */
 | 
			
		||||
#define	TRxCOI	4	/* TRxC O/I */
 | 
			
		||||
#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
 | 
			
		||||
#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
 | 
			
		||||
#define	TCBR	0x10	/* Transmit clock = BR Generator output */
 | 
			
		||||
#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
 | 
			
		||||
#define	RCRTxCP	0	/* Receive clock = RTxC pin */
 | 
			
		||||
#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
 | 
			
		||||
#define	RCBR	0x40	/* Receive clock = BR Generator output */
 | 
			
		||||
#define	RCDPLL	0x60	/* Receive clock = DPLL output */
 | 
			
		||||
#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
 | 
			
		||||
 | 
			
		||||
/* Write Register 12 (lower byte of baud rate generator time constant) */
 | 
			
		||||
 | 
			
		||||
/* Write Register 13 (upper byte of baud rate generator time constant) */
 | 
			
		||||
 | 
			
		||||
/* Write Register 14 (Misc control bits) */
 | 
			
		||||
#define	BRENABL	1	/* Baud rate generator enable */
 | 
			
		||||
#define	BRSRC	2	/* Baud rate generator source */
 | 
			
		||||
#define	DTRREQ	4	/* DTR/Request function */
 | 
			
		||||
#define	AUTOECHO 8	/* Auto Echo */
 | 
			
		||||
#define	LOOPBAK	0x10	/* Local loopback */
 | 
			
		||||
#define	SEARCH	0x20	/* Enter search mode */
 | 
			
		||||
#define	RMC	0x40	/* Reset missing clock */
 | 
			
		||||
#define	DISDPLL	0x60	/* Disable DPLL */
 | 
			
		||||
#define	SSBR	0x80	/* Set DPLL source = BR generator */
 | 
			
		||||
#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
 | 
			
		||||
#define	SFMM	0xc0	/* Set FM mode */
 | 
			
		||||
#define	SNRZI	0xe0	/* Set NRZI mode */
 | 
			
		||||
 | 
			
		||||
/* Write Register 15 (external/status interrupt control) */
 | 
			
		||||
#define	EN85C30	1	/* Enable some 85c30-enhanced registers */
 | 
			
		||||
#define	ZCIE	2	/* Zero count IE */
 | 
			
		||||
#define	ENSTFIFO 4	/* Enable status FIFO (SDLC) */
 | 
			
		||||
#define	DCDIE	8	/* DCD IE */
 | 
			
		||||
#define	SYNCIE	0x10	/* Sync/hunt IE */
 | 
			
		||||
#define	CTSIE	0x20	/* CTS IE */
 | 
			
		||||
#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
 | 
			
		||||
#define	BRKIE	0x80	/* Break/Abort IE */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Read Register 0 */
 | 
			
		||||
#define	Rx_CH_AV	0x1	/* Rx Character Available */
 | 
			
		||||
#define	ZCOUNT		0x2	/* Zero count */
 | 
			
		||||
#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
 | 
			
		||||
#define	DCD		0x8	/* DCD */
 | 
			
		||||
#define	SYNC_HUNT	0x10	/* Sync/hunt */
 | 
			
		||||
#define	CTS		0x20	/* CTS */
 | 
			
		||||
#define	TxEOM		0x40	/* Tx underrun */
 | 
			
		||||
#define	BRK_ABRT	0x80	/* Break/Abort */
 | 
			
		||||
 | 
			
		||||
/* Read Register 1 */
 | 
			
		||||
#define	ALL_SNT		0x1	/* All sent */
 | 
			
		||||
/* Residue Data for 8 Rx bits/char programmed */
 | 
			
		||||
#define	RES3		0x8	/* 0/3 */
 | 
			
		||||
#define	RES4		0x4	/* 0/4 */
 | 
			
		||||
#define	RES5		0xc	/* 0/5 */
 | 
			
		||||
#define	RES6		0x2	/* 0/6 */
 | 
			
		||||
#define	RES7		0xa	/* 0/7 */
 | 
			
		||||
#define	RES8		0x6	/* 0/8 */
 | 
			
		||||
#define	RES18		0xe	/* 1/8 */
 | 
			
		||||
#define	RES28		0x0	/* 2/8 */
 | 
			
		||||
/* Special Rx Condition Interrupts */
 | 
			
		||||
#define	PAR_ERR		0x10	/* Parity error */
 | 
			
		||||
#define	Rx_OVR		0x20	/* Rx Overrun Error */
 | 
			
		||||
#define	FRM_ERR		0x40	/* CRC/Framing Error */
 | 
			
		||||
#define	END_FR		0x80	/* End of Frame (SDLC) */
 | 
			
		||||
 | 
			
		||||
/* Read Register 2 (channel b only) - Interrupt vector */
 | 
			
		||||
#define	CHB_Tx_EMPTY	0x00
 | 
			
		||||
#define	CHB_EXT_STAT	0x02
 | 
			
		||||
#define	CHB_Rx_AVAIL	0x04
 | 
			
		||||
#define	CHB_SPECIAL	0x06
 | 
			
		||||
#define	CHA_Tx_EMPTY	0x08
 | 
			
		||||
#define	CHA_EXT_STAT	0x0a
 | 
			
		||||
#define	CHA_Rx_AVAIL	0x0c
 | 
			
		||||
#define	CHA_SPECIAL	0x0e
 | 
			
		||||
#define	STATUS_MASK	0x06
 | 
			
		||||
 | 
			
		||||
/* Read Register 3 (interrupt pending register) ch a only */
 | 
			
		||||
#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
 | 
			
		||||
#define	CHBTxIP	0x2		/* Channel B Tx IP */
 | 
			
		||||
#define	CHBRxIP	0x4		/* Channel B Rx IP */
 | 
			
		||||
#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
 | 
			
		||||
#define	CHATxIP	0x10		/* Channel A Tx IP */
 | 
			
		||||
#define	CHARxIP	0x20		/* Channel A Rx IP */
 | 
			
		||||
 | 
			
		||||
/* Read Register 8 (receive data register) */
 | 
			
		||||
 | 
			
		||||
/* Read Register 10  (misc status bits) */
 | 
			
		||||
#define	ONLOOP	2		/* On loop */
 | 
			
		||||
#define	LOOPSEND 0x10		/* Loop sending */
 | 
			
		||||
#define	CLK2MIS	0x40		/* Two clocks missing */
 | 
			
		||||
#define	CLK1MIS	0x80		/* One clock missing */
 | 
			
		||||
 | 
			
		||||
/* Read Register 12 (lower byte of baud rate generator constant) */
 | 
			
		||||
 | 
			
		||||
/* Read Register 13 (upper byte of baud rate generator constant) */
 | 
			
		||||
 | 
			
		||||
/* Read Register 15 (value of WR 15) */
 | 
			
		||||
 | 
			
		||||
/* Misc macros */
 | 
			
		||||
#define ZS_CLEARERR(channel)    (write_zsreg(channel, 0, ERR_RES))
 | 
			
		||||
#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
 | 
			
		||||
				     garbage = read_zsdata(channel); \
 | 
			
		||||
				     garbage = read_zsdata(channel); \
 | 
			
		||||
				     garbage = read_zsdata(channel); \
 | 
			
		||||
				} while(0)
 | 
			
		||||
 | 
			
		||||
#endif /* !(_MACSERIAL_H) */
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +63,10 @@
 | 
			
		|||
#include <asm/backlight.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PPC32
 | 
			
		||||
#include <asm/open_pic.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Some compile options */
 | 
			
		||||
#undef SUSPEND_USES_PMU
 | 
			
		||||
#define DEBUG_SLEEP
 | 
			
		||||
| 
						 | 
				
			
			@ -151,10 +155,10 @@ static spinlock_t pmu_lock;
 | 
			
		|||
static u8 pmu_intr_mask;
 | 
			
		||||
static int pmu_version;
 | 
			
		||||
static int drop_interrupts;
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
static int option_lid_wakeup = 1;
 | 
			
		||||
static int sleep_in_progress;
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif /* CONFIG_PM */
 | 
			
		||||
static unsigned long async_req_locks;
 | 
			
		||||
static unsigned int pmu_irq_stats[11];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +168,6 @@ static struct proc_dir_entry *proc_pmu_irqstats;
 | 
			
		|||
static struct proc_dir_entry *proc_pmu_options;
 | 
			
		||||
static int option_server_mode;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
int pmu_battery_count;
 | 
			
		||||
int pmu_cur_battery;
 | 
			
		||||
unsigned int pmu_power_flags;
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +175,6 @@ struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
 | 
			
		|||
static int query_batt_timer = BATTERY_POLLING_COUNT;
 | 
			
		||||
static struct adb_request batt_req;
 | 
			
		||||
static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
 | 
			
		||||
extern int disable_kernel_backlight;
 | 
			
		||||
| 
						 | 
				
			
			@ -206,11 +208,9 @@ static int proc_get_irqstats(char *page, char **start, off_t off,
 | 
			
		|||
static int pmu_set_backlight_level(int level, void* data);
 | 
			
		||||
static int pmu_set_backlight_enable(int on, int level, void* data);
 | 
			
		||||
#endif /* CONFIG_PMAC_BACKLIGHT */
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
static void pmu_pass_intr(unsigned char *data, int len);
 | 
			
		||||
static int proc_get_batt(char *page, char **start, off_t off,
 | 
			
		||||
			int count, int *eof, void *data);
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
static int proc_read_options(char *page, char **start, off_t off,
 | 
			
		||||
			int count, int *eof, void *data);
 | 
			
		||||
static int proc_write_options(struct file *file, const char __user *buffer,
 | 
			
		||||
| 
						 | 
				
			
			@ -403,8 +403,12 @@ static int __init via_pmu_start(void)
 | 
			
		|||
 | 
			
		||||
	bright_req_1.complete = 1;
 | 
			
		||||
	bright_req_2.complete = 1;
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
	batt_req.complete = 1;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PPC32
 | 
			
		||||
	if (pmu_kind == PMU_KEYLARGO_BASED)
 | 
			
		||||
		openpic_set_irq_priority(vias->intrs[0].line,
 | 
			
		||||
					 OPENPIC_PRIORITY_DEFAULT + 1);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
 | 
			
		||||
| 
						 | 
				
			
			@ -458,7 +462,7 @@ static int __init via_pmu_dev_init(void)
 | 
			
		|||
	register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
 | 
			
		||||
#endif /* CONFIG_PMAC_BACKLIGHT */
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PPC32
 | 
			
		||||
  	if (machine_is_compatible("AAPL,3400/2400") ||
 | 
			
		||||
  		machine_is_compatible("AAPL,3500")) {
 | 
			
		||||
		int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
 | 
			
		||||
| 
						 | 
				
			
			@ -486,20 +490,19 @@ static int __init via_pmu_dev_init(void)
 | 
			
		|||
				pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif /* CONFIG_PPC32 */
 | 
			
		||||
 | 
			
		||||
	/* Create /proc/pmu */
 | 
			
		||||
	proc_pmu_root = proc_mkdir("pmu", NULL);
 | 
			
		||||
	if (proc_pmu_root) {
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
		int i;
 | 
			
		||||
		long i;
 | 
			
		||||
 | 
			
		||||
		for (i=0; i<pmu_battery_count; i++) {
 | 
			
		||||
			char title[16];
 | 
			
		||||
			sprintf(title, "battery_%d", i);
 | 
			
		||||
			sprintf(title, "battery_%ld", i);
 | 
			
		||||
			proc_pmu_batt[i] = create_proc_read_entry(title, 0, proc_pmu_root,
 | 
			
		||||
						proc_get_batt, (void *)i);
 | 
			
		||||
		}
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
 | 
			
		||||
		proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,
 | 
			
		||||
					proc_get_info, NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -619,8 +622,6 @@ static void pmu_set_server_mode(int server_mode)
 | 
			
		|||
	pmu_wait_complete(&req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
 | 
			
		||||
/* This new version of the code for 2400/3400/3500 powerbooks
 | 
			
		||||
 * is inspired from the implementation in gkrellm-pmu
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -803,8 +804,6 @@ query_battery_state(void)
 | 
			
		|||
			2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
 | 
			
		||||
static int __pmac
 | 
			
		||||
proc_get_info(char *page, char **start, off_t off,
 | 
			
		||||
		int count, int *eof, void *data)
 | 
			
		||||
| 
						 | 
				
			
			@ -813,11 +812,9 @@ proc_get_info(char *page, char **start, off_t off,
 | 
			
		|||
 | 
			
		||||
	p += sprintf(p, "PMU driver version     : %d\n", PMU_DRIVER_VERSION);
 | 
			
		||||
	p += sprintf(p, "PMU firmware version   : %02x\n", pmu_version);
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
	p += sprintf(p, "AC Power               : %d\n",
 | 
			
		||||
		((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0));
 | 
			
		||||
	p += sprintf(p, "Battery count          : %d\n", pmu_battery_count);
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
 | 
			
		||||
	return p - page;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -849,12 +846,11 @@ proc_get_irqstats(char *page, char **start, off_t off,
 | 
			
		|||
	return p - page;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
static int __pmac
 | 
			
		||||
proc_get_batt(char *page, char **start, off_t off,
 | 
			
		||||
		int count, int *eof, void *data)
 | 
			
		||||
{
 | 
			
		||||
	int batnum = (int)data;
 | 
			
		||||
	long batnum = (long)data;
 | 
			
		||||
	char *p = page;
 | 
			
		||||
	
 | 
			
		||||
	p += sprintf(p, "\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -873,7 +869,6 @@ proc_get_batt(char *page, char **start, off_t off,
 | 
			
		|||
 | 
			
		||||
	return p - page;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
 | 
			
		||||
static int __pmac
 | 
			
		||||
proc_read_options(char *page, char **start, off_t off,
 | 
			
		||||
| 
						 | 
				
			
			@ -881,11 +876,11 @@ proc_read_options(char *page, char **start, off_t off,
 | 
			
		|||
{
 | 
			
		||||
	char *p = page;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
	if (pmu_kind == PMU_KEYLARGO_BASED &&
 | 
			
		||||
	    pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
 | 
			
		||||
		p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif
 | 
			
		||||
	if (pmu_kind == PMU_KEYLARGO_BASED)
 | 
			
		||||
		p += sprintf(p, "server_mode=%d\n", option_server_mode);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -922,12 +917,12 @@ proc_write_options(struct file *file, const char __user *buffer,
 | 
			
		|||
	*(val++) = 0;
 | 
			
		||||
	while(*val == ' ')
 | 
			
		||||
		val++;
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
	if (pmu_kind == PMU_KEYLARGO_BASED &&
 | 
			
		||||
	    pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
 | 
			
		||||
		if (!strcmp(label, "lid_wakeup"))
 | 
			
		||||
			option_lid_wakeup = ((*val) == '1');
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif
 | 
			
		||||
	if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) {
 | 
			
		||||
		int new_value;
 | 
			
		||||
		new_value = ((*val) == '1');
 | 
			
		||||
| 
						 | 
				
			
			@ -1422,7 +1417,6 @@ next:
 | 
			
		|||
	}
 | 
			
		||||
	/* Tick interrupt */
 | 
			
		||||
	else if ((1 << pirq) & PMU_INT_TICK) {
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
		/* Environement or tick interrupt, query batteries */
 | 
			
		||||
		if (pmu_battery_count) {
 | 
			
		||||
			if ((--query_batt_timer) == 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1437,7 +1431,6 @@ next:
 | 
			
		|||
		pmu_pass_intr(data, len);
 | 
			
		||||
	} else {
 | 
			
		||||
	       pmu_pass_intr(data, len);
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
	}
 | 
			
		||||
	goto next;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2052,7 +2045,7 @@ pmu_i2c_simple_write(int bus, int addr,  u8* data, int len)
 | 
			
		|||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
 | 
			
		||||
static LIST_HEAD(sleep_notifiers);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2705,6 +2698,8 @@ powerbook_sleep_3400(void)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIG_PM */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Support for /dev/pmu device
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -2884,11 +2879,11 @@ static int __pmac
 | 
			
		|||
pmu_ioctl(struct inode * inode, struct file *filp,
 | 
			
		||||
		     u_int cmd, u_long arg)
 | 
			
		||||
{
 | 
			
		||||
	struct pmu_private *pp = filp->private_data;
 | 
			
		||||
	__u32 __user *argp = (__u32 __user *)arg;
 | 
			
		||||
	int error;
 | 
			
		||||
	int error = -EINVAL;
 | 
			
		||||
 | 
			
		||||
	switch (cmd) {
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
	case PMU_IOC_SLEEP:
 | 
			
		||||
		if (!capable(CAP_SYS_ADMIN))
 | 
			
		||||
			return -EACCES;
 | 
			
		||||
| 
						 | 
				
			
			@ -2910,12 +2905,13 @@ pmu_ioctl(struct inode * inode, struct file *filp,
 | 
			
		|||
			error = -ENOSYS;
 | 
			
		||||
		}
 | 
			
		||||
		sleep_in_progress = 0;
 | 
			
		||||
		return error;
 | 
			
		||||
		break;
 | 
			
		||||
	case PMU_IOC_CAN_SLEEP:
 | 
			
		||||
		if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
 | 
			
		||||
			return put_user(0, argp);
 | 
			
		||||
		else
 | 
			
		||||
			return put_user(1, argp);
 | 
			
		||||
#endif /* CONFIG_PM */
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PMAC_BACKLIGHT
 | 
			
		||||
	/* Backlight should have its own device or go via
 | 
			
		||||
| 
						 | 
				
			
			@ -2936,11 +2932,13 @@ pmu_ioctl(struct inode * inode, struct file *filp,
 | 
			
		|||
		error = get_user(value, argp);
 | 
			
		||||
		if (!error)
 | 
			
		||||
			error = set_backlight_level(value);
 | 
			
		||||
		return error;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
#ifdef CONFIG_INPUT_ADBHID
 | 
			
		||||
	case PMU_IOC_GRAB_BACKLIGHT: {
 | 
			
		||||
		struct pmu_private *pp = filp->private_data;
 | 
			
		||||
		unsigned long flags;
 | 
			
		||||
 | 
			
		||||
		if (pp->backlight_locker)
 | 
			
		||||
			return 0;
 | 
			
		||||
		pp->backlight_locker = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -2956,7 +2954,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
 | 
			
		|||
	case PMU_IOC_HAS_ADB:
 | 
			
		||||
		return put_user(pmu_has_adb, argp);
 | 
			
		||||
	}
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
	return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct file_operations pmu_device_fops __pmacdata = {
 | 
			
		||||
| 
						 | 
				
			
			@ -2972,14 +2970,16 @@ static struct miscdevice pmu_device __pmacdata = {
 | 
			
		|||
	PMU_MINOR, "pmu", &pmu_device_fops
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void pmu_device_init(void)
 | 
			
		||||
static int pmu_device_init(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!via)
 | 
			
		||||
		return;
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (misc_register(&pmu_device) < 0)
 | 
			
		||||
		printk(KERN_ERR "via-pmu: cannot register misc device.\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
device_initcall(pmu_device_init);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_SLEEP
 | 
			
		||||
static inline void  __pmac
 | 
			
		||||
| 
						 | 
				
			
			@ -3147,12 +3147,12 @@ EXPORT_SYMBOL(pmu_i2c_combined_read);
 | 
			
		|||
EXPORT_SYMBOL(pmu_i2c_stdsub_write);
 | 
			
		||||
EXPORT_SYMBOL(pmu_i2c_simple_read);
 | 
			
		||||
EXPORT_SYMBOL(pmu_i2c_simple_write);
 | 
			
		||||
#ifdef CONFIG_PMAC_PBOOK
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
EXPORT_SYMBOL(pmu_register_sleep_notifier);
 | 
			
		||||
EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
 | 
			
		||||
EXPORT_SYMBOL(pmu_enable_irled);
 | 
			
		||||
EXPORT_SYMBOL(pmu_battery_count);
 | 
			
		||||
EXPORT_SYMBOL(pmu_batteries);
 | 
			
		||||
EXPORT_SYMBOL(pmu_power_flags);
 | 
			
		||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
			
		||||
#endif /* CONFIG_PM */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ menu "Video For Linux"
 | 
			
		|||
 | 
			
		||||
comment "Video Adapters"
 | 
			
		||||
 | 
			
		||||
config CONFIG_TUNER_MULTI_I2C
 | 
			
		||||
config TUNER_MULTI_I2C
 | 
			
		||||
	bool "Enable support for multiple I2C devices on Video Adapters (EXPERIMENTAL)"
 | 
			
		||||
	depends on VIDEO_DEV && EXPERIMENTAL
 | 
			
		||||
	---help---
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1274,6 +1274,7 @@ module_param_array(irq, int, NULL, 0);
 | 
			
		|||
module_param_array(io, int, NULL, 0);
 | 
			
		||||
MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
 | 
			
		||||
MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
 | 
			
		||||
int init_module(void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1320,7 +1320,7 @@ config FORCEDETH
 | 
			
		|||
 | 
			
		||||
config CS89x0
 | 
			
		||||
	tristate "CS89x0 support"
 | 
			
		||||
	depends on NET_PCI && (ISA || ARCH_IXDP2X01)
 | 
			
		||||
	depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105
 | 
			
		||||
	---help---
 | 
			
		||||
	  Support for CS89x0 chipset based Ethernet cards. If you have a
 | 
			
		||||
	  network (Ethernet) card of this type, say Y and read the
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1285,6 +1285,9 @@ static int b44_open(struct net_device *dev)
 | 
			
		|||
	b44_init_hw(bp);
 | 
			
		||||
	bp->flags |= B44_FLAG_INIT_COMPLETE;
 | 
			
		||||
 | 
			
		||||
	netif_carrier_off(dev);
 | 
			
		||||
	b44_check_phy(bp);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irq(&bp->lock);
 | 
			
		||||
 | 
			
		||||
	init_timer(&bp->timer);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -174,6 +174,13 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0};
 | 
			
		|||
#include <asm/irq.h>
 | 
			
		||||
static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
 | 
			
		||||
static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
 | 
			
		||||
#elif defined(CONFIG_ARCH_PNX0105)
 | 
			
		||||
#include <asm/irq.h>
 | 
			
		||||
#include <asm/arch/gpio.h>
 | 
			
		||||
#define CIRRUS_DEFAULT_BASE	IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000)	/* = Physical address 0x48200000 */
 | 
			
		||||
#define CIRRUS_DEFAULT_IRQ	VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
 | 
			
		||||
static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0};
 | 
			
		||||
static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
 | 
			
		||||
#else
 | 
			
		||||
static unsigned int netcard_portlist[] __initdata =
 | 
			
		||||
   { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
 | 
			
		||||
| 
						 | 
				
			
			@ -431,6 +438,30 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
 | 
			
		|||
#endif
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARCH_PNX0105
 | 
			
		||||
	initialize_ebi();
 | 
			
		||||
 | 
			
		||||
	/* Map GPIO registers for the pins connected to the CS8900a. */
 | 
			
		||||
	if (map_cirrus_gpio() < 0)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	reset_cirrus();
 | 
			
		||||
 | 
			
		||||
	/* Map event-router registers. */
 | 
			
		||||
	if (map_event_router() < 0)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	enable_cirrus_irq();
 | 
			
		||||
 | 
			
		||||
	unmap_cirrus_gpio();
 | 
			
		||||
	unmap_event_router();
 | 
			
		||||
 | 
			
		||||
	dev->base_addr = ioaddr;
 | 
			
		||||
 | 
			
		||||
	for (i = 0 ; i < 3 ; i++)
 | 
			
		||||
		readreg(dev, 0);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Grab the region so we can find another board if autoIRQ fails. */
 | 
			
		||||
	/* WTF is going on here? */
 | 
			
		||||
	if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -672,7 +703,7 @@ printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT));
 | 
			
		|||
	} else {
 | 
			
		||||
		i = lp->isa_config & INT_NO_MASK;
 | 
			
		||||
		if (lp->chip_type == CS8900) {
 | 
			
		||||
#ifdef CONFIG_ARCH_IXDP2X01
 | 
			
		||||
#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
 | 
			
		||||
		        i = cs8900_irq_map[0];
 | 
			
		||||
#else
 | 
			
		||||
			/* Translate the IRQ using the IRQ mapping table. */
 | 
			
		||||
| 
						 | 
				
			
			@ -1145,7 +1176,7 @@ net_open(struct net_device *dev)
 | 
			
		|||
	int i;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_SH_HICOSH4 /* uses irq#1, so this won't work */
 | 
			
		||||
#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX0105) /* uses irq#1, so this won't work */
 | 
			
		||||
	if (dev->irq < 2) {
 | 
			
		||||
		/* Allow interrupts to be generated by the chip */
 | 
			
		||||
/* Cirrus' release had this: */
 | 
			
		||||
| 
						 | 
				
			
			@ -1176,7 +1207,7 @@ net_open(struct net_device *dev)
 | 
			
		|||
	else
 | 
			
		||||
#endif
 | 
			
		||||
	{
 | 
			
		||||
#ifndef CONFIG_ARCH_IXDP2X01
 | 
			
		||||
#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105)
 | 
			
		||||
		if (((1 << dev->irq) & lp->irq_map) == 0) {
 | 
			
		||||
			printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
 | 
			
		||||
                               dev->name, dev->irq, lp->irq_map);
 | 
			
		||||
| 
						 | 
				
			
			@ -1261,6 +1292,9 @@ net_open(struct net_device *dev)
 | 
			
		|||
	case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
 | 
			
		||||
        default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
 | 
			
		||||
        }
 | 
			
		||||
#ifdef CONFIG_ARCH_PNX0105
 | 
			
		||||
	result = A_CNF_10B_T;
 | 
			
		||||
#endif
 | 
			
		||||
        if (!result) {
 | 
			
		||||
                printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
 | 
			
		||||
        release_irq:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue