From ed092cbc837297e6826734760d8aacc15ea0b1f0 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 6 Jan 2005 05:57:16 -0500 Subject: [PATCH] export print_sense_internal Currently, we have scsi_print_sense and scsi_print_req_sense, but the linux-iscsi driver receives async messages from a target that may contain SCSI sense data and these messages are not tied to any specific command. So that we can use the scsi-ml sense printing capabilities the attached patch exports exports print_sense_internal and renames it to __scsi_print_sense. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- include/scsi/scsi_dbg.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index 38fbb68c9b87..12e90934a7a8 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -8,6 +8,9 @@ extern void scsi_print_command(struct scsi_cmnd *); extern void __scsi_print_command(unsigned char *); extern void scsi_print_sense(const char *, struct scsi_cmnd *); extern void scsi_print_req_sense(const char *, struct scsi_request *); +extern void __scsi_print_sense(const char *name, + const unsigned char *sense_buffer, + int sense_len); extern void scsi_print_driverbyte(int); extern void scsi_print_hostbyte(int); extern void scsi_print_status(unsigned char); -- cgit v1.2.3 From 9521392a2fbb55db92f12741ae329efd121b0d81 Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Sun, 9 Jan 2005 22:56:57 -0600 Subject: [PATCH] cciss update to version 2.6.4 This patch removes support for 2 controllers that were recently cancelled and it adds support for the P600, a cciss based SAS controller due to ship in late March/early April '05. Neither of these controllers have made it to the field. Signed-off-by: Mike Miller Signed-off-by: James Bottomley --- Documentation/cciss.txt | 3 +-- drivers/block/cciss.c | 17 +++++++---------- include/linux/pci_ids.h | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt index 7d8f67e5c837..5bbc54667aa3 100644 --- a/Documentation/cciss.txt +++ b/Documentation/cciss.txt @@ -14,8 +14,7 @@ This driver is known to work with the following cards: * SA 6400 * SA 6400 U320 Expansion Module * SA 6i - * SA 6422 - * SA V100 + * SA P600 If nodes are not already created in the /dev/cciss directory diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 97bf2d4b9207..30ae21daa7ba 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -46,14 +46,14 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "HP CISS Driver (v 2.6.2)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,2) +#define DRIVER_NAME "HP CISS Driver (v 2.6.4)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,4) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.2"); +MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.4"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" - " SA6i V100"); + " SA6i P600"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -80,10 +80,8 @@ const struct pci_device_id cciss_pci_device_id[] = { 0x0E11, 0x409D, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x4091, 0, 0, 0}, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, - 0x0E11, 0x409E, 0, 0, 0}, - { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISS, - 0x103C, 0x3211, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA, + 0x103C, 0x3225, 0, 0, 0}, {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); @@ -104,8 +102,7 @@ static struct board_type products[] = { { 0x409C0E11, "Smart Array 6400", &SA5_access}, { 0x409D0E11, "Smart Array 6400 EM", &SA5_access}, { 0x40910E11, "Smart Array 6i", &SA5_access}, - { 0x409E0E11, "Smart Array 6422", &SA5_access}, - { 0x3211103C, "Smart Array V100", &SA5_access}, + { 0x3225103C, "Smart Array P600", &SA5_access}, }; /* How long to wait (in millesconds) for board to go into simple mode */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d607c59b3851..6c55342f5865 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -690,7 +690,7 @@ #define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c #define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 #define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 -#define PCI_DEVICE_ID_HP_CISS 0x3210 +#define PCI_DEVICE_ID_HP_CISSA 0x3220 #define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 -- cgit v1.2.3 From 4cc329ec856b828bb5dc306d9d0574619b8815a0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Jan 2005 12:58:17 -0500 Subject: [PATCH] mark arcdev_setup static It's only used in arcnet.c, and following the model of the other link layers it doesn't make sense to use it outside alloc_arcdev() either. --- drivers/net/arcnet/arcnet.c | 3 +-- include/linux/arcdevice.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 282a678007b3..9fd21724f61f 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -93,7 +93,6 @@ EXPORT_SYMBOL(arc_raw_proto); EXPORT_SYMBOL(arc_proto_null); EXPORT_SYMBOL(arcnet_unregister_proto); EXPORT_SYMBOL(arcnet_debug); -EXPORT_SYMBOL(arcdev_setup); EXPORT_SYMBOL(alloc_arcdev); EXPORT_SYMBOL(arcnet_interrupt); @@ -317,7 +316,7 @@ static int choose_mtu(void) /* Setup a struct device for ARCnet. */ -void arcdev_setup(struct net_device *dev) +static void arcdev_setup(struct net_device *dev) { dev->type = ARPHRD_ARCNET; dev->hard_header_len = sizeof(struct archdr); diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index bd4364daf948..7198f129e135 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -343,7 +343,6 @@ void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc, void arcnet_unregister_proto(struct ArcProto *proto); irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); -void arcdev_setup(struct net_device *dev); struct net_device *alloc_arcdev(char *name); void arcnet_rx(struct net_device *dev, int bufnum); -- cgit v1.2.3 From 0a71336b6a8858a525007c5b4e0d14ba57f9f315 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 11 Jan 2005 01:40:38 -0800 Subject: [PATCH] cputime: introduce cputime This patch introduces the concept of (virtual) cputime. Each architecture can define its method to measure cputime. The main idea is to define a cputime_t type and a set of operations on it (see asm-generic/cputime.h). Then use the type for utime, stime, cutime, cstime, it_virt_value, it_virt_incr, it_prof_value and it_prof_incr and use the cputime operations for each access to these variables. The default implementation is jiffies based and the effect of this patch for architectures which use the default implementation should be neglectible. There is a second type cputime64_t which is necessary for the kernel_stat cpu statistics. The default cputime_t is 32 bit and based on HZ, this will overflow after 49.7 days. This is not enough for kernel_stat (ihmo not enough for a processes too), so it is necessary to have a 64 bit type. The third thing that gets introduced by this patch is an additional field for the /proc/stat interface: cpu steal time. An architecture can account cpu steal time by calls to the account_stealtime function. The cpu which backs a virtual processor doesn't spent all of its time for the virtual cpu. To get meaningful cpu usage numbers this involuntary wait time needs to be accounted and exported to user space. From: Hugh Dickins The p->signal check in account_system_time is insufficient. If the timer interrupt hits near the end of exit_notify, after EXIT_ZOMBIE has been set, another cpu may release_task (NULLifying p->signal) in between account_system_time's check and check_rlimit's dereference. Nor should account_it_prof risk send_sig. But surely account_user_time is safe? Signed-off-by: Hugh Dickins Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/parisc/kernel/binfmt_elf32.c | 6 +- arch/ppc64/kernel/binfmt_elf32.c | 6 +- arch/s390/kernel/binfmt_elf32.c | 6 +- arch/sparc64/kernel/binfmt_elf32.c | 6 +- fs/binfmt_elf.c | 12 +-- fs/proc/array.c | 22 ++--- fs/proc/proc_misc.c | 60 +++++++------ include/asm-alpha/cputime.h | 6 ++ include/asm-arm/cputime.h | 6 ++ include/asm-arm26/cputime.h | 6 ++ include/asm-cris/cputime.h | 6 ++ include/asm-generic/cputime.h | 64 ++++++++++++++ include/asm-h8300/cputime.h | 6 ++ include/asm-i386/cputime.h | 6 ++ include/asm-ia64/cputime.h | 6 ++ include/asm-m32r/cputime.h | 6 ++ include/asm-m68k/cputime.h | 6 ++ include/asm-m68knommu/cputime.h | 6 ++ include/asm-mips/cputime.h | 6 ++ include/asm-parisc/cputime.h | 6 ++ include/asm-ppc/cputime.h | 6 ++ include/asm-ppc64/cputime.h | 6 ++ include/asm-s390/cputime.h | 6 ++ include/asm-sh/cputime.h | 6 ++ include/asm-sh64/cputime.h | 6 ++ include/asm-sparc/cputime.h | 6 ++ include/asm-sparc64/cputime.h | 6 ++ include/asm-um/cputime.h | 6 ++ include/asm-v850/cputime.h | 6 ++ include/asm-x86_64/cputime.h | 6 ++ include/linux/kernel_stat.h | 20 +++-- include/linux/sched.h | 12 +-- kernel/compat.c | 14 ++-- kernel/cpu.c | 4 +- kernel/exit.c | 18 ++-- kernel/fork.c | 14 ++-- kernel/itimer.c | 57 +++++++------ kernel/sched.c | 168 +++++++++++++++++++++++++++++++------ kernel/signal.c | 14 ++-- kernel/sys.c | 34 ++++---- kernel/timer.c | 65 ++------------ mm/oom_kill.c | 3 +- 42 files changed, 523 insertions(+), 214 deletions(-) create mode 100644 include/asm-alpha/cputime.h create mode 100644 include/asm-arm/cputime.h create mode 100644 include/asm-arm26/cputime.h create mode 100644 include/asm-cris/cputime.h create mode 100644 include/asm-generic/cputime.h create mode 100644 include/asm-h8300/cputime.h create mode 100644 include/asm-i386/cputime.h create mode 100644 include/asm-ia64/cputime.h create mode 100644 include/asm-m32r/cputime.h create mode 100644 include/asm-m68k/cputime.h create mode 100644 include/asm-m68knommu/cputime.h create mode 100644 include/asm-mips/cputime.h create mode 100644 include/asm-parisc/cputime.h create mode 100644 include/asm-ppc/cputime.h create mode 100644 include/asm-ppc64/cputime.h create mode 100644 include/asm-s390/cputime.h create mode 100644 include/asm-sh/cputime.h create mode 100644 include/asm-sh64/cputime.h create mode 100644 include/asm-sparc/cputime.h create mode 100644 include/asm-sparc64/cputime.h create mode 100644 include/asm-um/cputime.h create mode 100644 include/asm-v850/cputime.h create mode 100644 include/asm-x86_64/cputime.h (limited to 'include') diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c index 4486a745b0ef..6fd07e90aad7 100644 --- a/arch/parisc/kernel/binfmt_elf32.c +++ b/arch/parisc/kernel/binfmt_elf32.c @@ -92,10 +92,12 @@ struct elf_prpsinfo32 current->thread.map_base = DEFAULT_MAP_BASE32; \ current->thread.task_size = DEFAULT_TASK_SIZE32 \ -#define jiffies_to_timeval jiffies_to_compat_timeval +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval static __inline__ void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { + unsigned long jiffies = cputime_to_jiffies(cputime); value->tv_usec = (jiffies % HZ) * (1000000L / HZ); value->tv_sec = jiffies / HZ; } diff --git a/arch/ppc64/kernel/binfmt_elf32.c b/arch/ppc64/kernel/binfmt_elf32.c index 478e5fce6be1..fadc699a0497 100644 --- a/arch/ppc64/kernel/binfmt_elf32.c +++ b/arch/ppc64/kernel/binfmt_elf32.c @@ -60,10 +60,12 @@ struct elf_prpsinfo32 #include -#define jiffies_to_timeval jiffies_to_compat_timeval +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval static __inline__ void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { + unsigned long jiffies = cputime_to_jiffies(cputime); value->tv_usec = (jiffies % HZ) * (1000000L / HZ); value->tv_sec = jiffies / HZ; } diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index 1100c409b5bb..ed234bf06d1c 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -197,10 +197,12 @@ MODULE_AUTHOR("Gerhard Tonn "); #undef MODULE_DESCRIPTION #undef MODULE_AUTHOR -#define jiffies_to_timeval jiffies_to_compat_timeval +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval static __inline__ void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { + unsigned long jiffies = cputime_to_jiffies(cputime); value->tv_usec = (jiffies % HZ) * (1000000L / HZ); value->tv_sec = jiffies / HZ; } diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index c13eaf030758..a1a12d2aa353 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -132,10 +132,12 @@ struct elf_prpsinfo32 #include -#define jiffies_to_timeval jiffies_to_compat_timeval +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval static __inline__ void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { + unsigned long jiffies = cputime_to_jiffies(cputime); value->tv_usec = (jiffies % HZ) * (1000000L / HZ); value->tv_sec = jiffies / HZ; } diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 0ecc44fb0551..eaa2c7026e60 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1215,16 +1215,16 @@ static void fill_prstatus(struct elf_prstatus *prstatus, * this and each other thread to finish dying after the * core dump synchronization phase. */ - jiffies_to_timeval(p->utime + p->signal->utime, + cputime_to_timeval(cputime_add(p->utime, p->signal->utime), &prstatus->pr_utime); - jiffies_to_timeval(p->stime + p->signal->stime, + cputime_to_timeval(cputime_add(p->stime, p->signal->stime), &prstatus->pr_stime); } else { - jiffies_to_timeval(p->utime, &prstatus->pr_utime); - jiffies_to_timeval(p->stime, &prstatus->pr_stime); + cputime_to_timeval(p->utime, &prstatus->pr_utime); + cputime_to_timeval(p->stime, &prstatus->pr_stime); } - jiffies_to_timeval(p->signal->cutime, &prstatus->pr_cutime); - jiffies_to_timeval(p->signal->cstime, &prstatus->pr_cstime); + cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); + cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); } static void fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, diff --git a/fs/proc/array.c b/fs/proc/array.c index e4bd14aa005d..eb5c084ede4a 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -313,8 +313,9 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) int num_threads = 0; struct mm_struct *mm; unsigned long long start_time; - unsigned long cmin_flt = 0, cmaj_flt = 0, cutime = 0, cstime = 0; - unsigned long min_flt = 0, maj_flt = 0, utime = 0, stime = 0; + unsigned long cmin_flt = 0, cmaj_flt = 0; + unsigned long min_flt = 0, maj_flt = 0; + cputime_t cutime, cstime, utime, stime; unsigned long rsslim = 0; struct task_struct *t; char tcomm[sizeof(task->comm)]; @@ -332,6 +333,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) sigemptyset(&sigign); sigemptyset(&sigcatch); + cutime = cstime = utime = stime = cputime_zero; read_lock(&tasklist_lock); if (task->sighand) { spin_lock_irq(&task->sighand->siglock); @@ -344,8 +346,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) do { min_flt += t->min_flt; maj_flt += t->maj_flt; - utime += t->utime; - stime += t->stime; + utime = cputime_add(utime, t->utime); + stime = cputime_add(stime, t->stime); t = next_thread(t); } while (t != task); } @@ -367,8 +369,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) if (whole) { min_flt += task->signal->min_flt; maj_flt += task->signal->maj_flt; - utime += task->signal->utime; - stime += task->signal->stime; + utime = cputime_add(utime, task->signal->utime); + stime = cputime_add(stime, task->signal->stime); } } ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; @@ -411,10 +413,10 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) cmin_flt, maj_flt, cmaj_flt, - jiffies_to_clock_t(utime), - jiffies_to_clock_t(stime), - jiffies_to_clock_t(cutime), - jiffies_to_clock_t(cstime), + cputime_to_clock_t(utime), + cputime_to_clock_t(stime), + cputime_to_clock_t(cutime), + cputime_to_clock_t(cstime), priority, nice, num_threads, diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index c7322cfefe13..89d09007df5d 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -101,10 +101,10 @@ static int uptime_read_proc(char *page, char **start, off_t off, struct timespec uptime; struct timespec idle; int len; - u64 idle_jiffies = init_task.utime + init_task.stime; + cputime_t idletime = cputime_add(init_task.utime, init_task.stime); do_posix_clock_monotonic_gettime(&uptime); - jiffies_to_timespec(idle_jiffies, &idle); + cputime_to_timespec(idletime, &idle); len = sprintf(page,"%lu.%02lu %lu.%02lu\n", (unsigned long) uptime.tv_sec, (uptime.tv_nsec / (NSEC_PER_SEC / 100)), @@ -322,9 +322,11 @@ static int show_stat(struct seq_file *p, void *v) { int i; unsigned long jif; - u64 sum = 0, user = 0, nice = 0, system = 0, - idle = 0, iowait = 0, irq = 0, softirq = 0; + cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; + u64 sum = 0; + user = nice = system = idle = iowait = + irq = softirq = steal = cputime64_zero; jif = - wall_to_monotonic.tv_sec; if (wall_to_monotonic.tv_nsec) --jif; @@ -332,25 +334,27 @@ static int show_stat(struct seq_file *p, void *v) for_each_cpu(i) { int j; - user += kstat_cpu(i).cpustat.user; - nice += kstat_cpu(i).cpustat.nice; - system += kstat_cpu(i).cpustat.system; - idle += kstat_cpu(i).cpustat.idle; - iowait += kstat_cpu(i).cpustat.iowait; - irq += kstat_cpu(i).cpustat.irq; - softirq += kstat_cpu(i).cpustat.softirq; + user = cputime64_add(user, kstat_cpu(i).cpustat.user); + nice = cputime64_add(nice, kstat_cpu(i).cpustat.nice); + system = cputime64_add(system, kstat_cpu(i).cpustat.system); + idle = cputime64_add(idle, kstat_cpu(i).cpustat.idle); + iowait = cputime64_add(iowait, kstat_cpu(i).cpustat.iowait); + irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq); + softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); + steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); for (j = 0 ; j < NR_IRQS ; j++) sum += kstat_cpu(i).irqs[j]; } - seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu\n", - (unsigned long long)jiffies_64_to_clock_t(user), - (unsigned long long)jiffies_64_to_clock_t(nice), - (unsigned long long)jiffies_64_to_clock_t(system), - (unsigned long long)jiffies_64_to_clock_t(idle), - (unsigned long long)jiffies_64_to_clock_t(iowait), - (unsigned long long)jiffies_64_to_clock_t(irq), - (unsigned long long)jiffies_64_to_clock_t(softirq)); + seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu\n", + (unsigned long long)cputime64_to_clock_t(user), + (unsigned long long)cputime64_to_clock_t(nice), + (unsigned long long)cputime64_to_clock_t(system), + (unsigned long long)cputime64_to_clock_t(idle), + (unsigned long long)cputime64_to_clock_t(iowait), + (unsigned long long)cputime64_to_clock_t(irq), + (unsigned long long)cputime64_to_clock_t(softirq), + (unsigned long long)cputime64_to_clock_t(steal)); for_each_online_cpu(i) { /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ @@ -361,15 +365,17 @@ static int show_stat(struct seq_file *p, void *v) iowait = kstat_cpu(i).cpustat.iowait; irq = kstat_cpu(i).cpustat.irq; softirq = kstat_cpu(i).cpustat.softirq; - seq_printf(p, "cpu%d %llu %llu %llu %llu %llu %llu %llu\n", + steal = kstat_cpu(i).cpustat.steal; + seq_printf(p, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu\n", i, - (unsigned long long)jiffies_64_to_clock_t(user), - (unsigned long long)jiffies_64_to_clock_t(nice), - (unsigned long long)jiffies_64_to_clock_t(system), - (unsigned long long)jiffies_64_to_clock_t(idle), - (unsigned long long)jiffies_64_to_clock_t(iowait), - (unsigned long long)jiffies_64_to_clock_t(irq), - (unsigned long long)jiffies_64_to_clock_t(softirq)); + (unsigned long long)cputime64_to_clock_t(user), + (unsigned long long)cputime64_to_clock_t(nice), + (unsigned long long)cputime64_to_clock_t(system), + (unsigned long long)cputime64_to_clock_t(idle), + (unsigned long long)cputime64_to_clock_t(iowait), + (unsigned long long)cputime64_to_clock_t(irq), + (unsigned long long)cputime64_to_clock_t(softirq), + (unsigned long long)cputime64_to_clock_t(steal)); } seq_printf(p, "intr %llu", (unsigned long long)sum); diff --git a/include/asm-alpha/cputime.h b/include/asm-alpha/cputime.h new file mode 100644 index 000000000000..19577fd93230 --- /dev/null +++ b/include/asm-alpha/cputime.h @@ -0,0 +1,6 @@ +#ifndef __ALPHA_CPUTIME_H +#define __ALPHA_CPUTIME_H + +#include + +#endif /* __ALPHA_CPUTIME_H */ diff --git a/include/asm-arm/cputime.h b/include/asm-arm/cputime.h new file mode 100644 index 000000000000..3a8002a5fec7 --- /dev/null +++ b/include/asm-arm/cputime.h @@ -0,0 +1,6 @@ +#ifndef __ARM_CPUTIME_H +#define __ARM_CPUTIME_H + +#include + +#endif /* __ARM_CPUTIME_H */ diff --git a/include/asm-arm26/cputime.h b/include/asm-arm26/cputime.h new file mode 100644 index 000000000000..d2783a9e47b3 --- /dev/null +++ b/include/asm-arm26/cputime.h @@ -0,0 +1,6 @@ +#ifndef __ARM26_CPUTIME_H +#define __ARM26_CPUTIME_H + +#include + +#endif /* __ARM26_CPUTIME_H */ diff --git a/include/asm-cris/cputime.h b/include/asm-cris/cputime.h new file mode 100644 index 000000000000..4446a65656fa --- /dev/null +++ b/include/asm-cris/cputime.h @@ -0,0 +1,6 @@ +#ifndef __CRIS_CPUTIME_H +#define __CRIS_CPUTIME_H + +#include + +#endif /* __CRIS_CPUTIME_H */ diff --git a/include/asm-generic/cputime.h b/include/asm-generic/cputime.h new file mode 100644 index 000000000000..c9968a09f8ab --- /dev/null +++ b/include/asm-generic/cputime.h @@ -0,0 +1,64 @@ +#ifndef _ASM_GENERIC_CPUTIME_H +#define _ASM_GENERIC_CPUTIME_H + +#include +#include + +typedef unsigned long cputime_t; + +#define cputime_zero (0UL) +#define cputime_max ((~0UL >> 1) - 1) +#define cputime_add(__a, __b) ((__a) + (__b)) +#define cputime_sub(__a, __b) ((__a) - (__b)) +#define cputime_eq(__a, __b) ((__a) == (__b)) +#define cputime_gt(__a, __b) ((__a) > (__b)) +#define cputime_ge(__a, __b) ((__a) >= (__b)) +#define cputime_lt(__a, __b) ((__a) < (__b)) +#define cputime_le(__a, __b) ((__a) <= (__b)) +#define cputime_to_jiffies(__ct) (__ct) +#define jiffies_to_cputime(__hz) (__hz) + +typedef u64 cputime64_t; + +#define cputime64_zero (0ULL) +#define cputime64_add(__a, __b) ((__a) + (__b)) +#define cputime64_to_jiffies64(__ct) (__ct) +#define cputime_to_cputime64(__ct) ((u64) __ct) + + +/* + * Convert cputime to milliseconds and back. + */ +#define cputime_to_msecs(__ct) jiffies_to_msecs(__ct) +#define msecs_to_cputime(__msecs) msecs_to_jiffies(__msecs) + +/* + * Convert cputime to seconds and back. + */ +#define cputime_to_secs(__ct) (jiffies_to_msecs(__ct) / HZ) +#define secs_to_cputime(__secs) (msecs_to_jiffies(__secs * HZ)) + +/* + * Convert cputime to timespec and back. + */ +#define timespec_to_cputime(__val) timespec_to_jiffies(__val) +#define cputime_to_timespec(__ct,__val) jiffies_to_timespec(__ct,__val) + +/* + * Convert cputime to timeval and back. + */ +#define timeval_to_cputime(__val) timeval_to_jiffies(__val) +#define cputime_to_timeval(__ct,__val) jiffies_to_timeval(__ct,__val) + +/* + * Convert cputime to clock and back. + */ +#define cputime_to_clock_t(__ct) jiffies_to_clock_t(__ct) +#define clock_t_to_cputime(__x) clock_t_to_jiffies(__x) + +/* + * Convert cputime64 to clock. + */ +#define cputime64_to_clock_t(__ct) jiffies_64_to_clock_t(__ct) + +#endif diff --git a/include/asm-h8300/cputime.h b/include/asm-h8300/cputime.h new file mode 100644 index 000000000000..092e187c7b08 --- /dev/null +++ b/include/asm-h8300/cputime.h @@ -0,0 +1,6 @@ +#ifndef __H8300_CPUTIME_H +#define __H8300_CPUTIME_H + +#include + +#endif /* __H8300_CPUTIME_H */ diff --git a/include/asm-i386/cputime.h b/include/asm-i386/cputime.h new file mode 100644 index 000000000000..398ed7cd171d --- /dev/null +++ b/include/asm-i386/cputime.h @@ -0,0 +1,6 @@ +#ifndef __I386_CPUTIME_H +#define __I386_CPUTIME_H + +#include + +#endif /* __I386_CPUTIME_H */ diff --git a/include/asm-ia64/cputime.h b/include/asm-ia64/cputime.h new file mode 100644 index 000000000000..72400a78002a --- /dev/null +++ b/include/asm-ia64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __IA64_CPUTIME_H +#define __IA64_CPUTIME_H + +#include + +#endif /* __IA64_CPUTIME_H */ diff --git a/include/asm-m32r/cputime.h b/include/asm-m32r/cputime.h new file mode 100644 index 000000000000..0a47550df2b7 --- /dev/null +++ b/include/asm-m32r/cputime.h @@ -0,0 +1,6 @@ +#ifndef __M32R_CPUTIME_H +#define __M32R_CPUTIME_H + +#include + +#endif /* __M32R_CPUTIME_H */ diff --git a/include/asm-m68k/cputime.h b/include/asm-m68k/cputime.h new file mode 100644 index 000000000000..c79c5e892305 --- /dev/null +++ b/include/asm-m68k/cputime.h @@ -0,0 +1,6 @@ +#ifndef __M68K_CPUTIME_H +#define __M68K_CPUTIME_H + +#include + +#endif /* __M68K_CPUTIME_H */ diff --git a/include/asm-m68knommu/cputime.h b/include/asm-m68knommu/cputime.h new file mode 100644 index 000000000000..a0c4a660878d --- /dev/null +++ b/include/asm-m68knommu/cputime.h @@ -0,0 +1,6 @@ +#ifndef __M68KNOMMU_CPUTIME_H +#define __M68KNOMMU_CPUTIME_H + +#include + +#endif /* __M68KNOMMU_CPUTIME_H */ diff --git a/include/asm-mips/cputime.h b/include/asm-mips/cputime.h new file mode 100644 index 000000000000..c00eacbdd979 --- /dev/null +++ b/include/asm-mips/cputime.h @@ -0,0 +1,6 @@ +#ifndef __MIPS_CPUTIME_H +#define __MIPS_CPUTIME_H + +#include + +#endif /* __MIPS_CPUTIME_H */ diff --git a/include/asm-parisc/cputime.h b/include/asm-parisc/cputime.h new file mode 100644 index 000000000000..dcdf2fbd7e72 --- /dev/null +++ b/include/asm-parisc/cputime.h @@ -0,0 +1,6 @@ +#ifndef __PARISC_CPUTIME_H +#define __PARISC_CPUTIME_H + +#include + +#endif /* __PARISC_CPUTIME_H */ diff --git a/include/asm-ppc/cputime.h b/include/asm-ppc/cputime.h new file mode 100644 index 000000000000..8e9faf5ce720 --- /dev/null +++ b/include/asm-ppc/cputime.h @@ -0,0 +1,6 @@ +#ifndef __PPC_CPUTIME_H +#define __PPC_CPUTIME_H + +#include + +#endif /* __PPC_CPUTIME_H */ diff --git a/include/asm-ppc64/cputime.h b/include/asm-ppc64/cputime.h new file mode 100644 index 000000000000..8e9faf5ce720 --- /dev/null +++ b/include/asm-ppc64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __PPC_CPUTIME_H +#define __PPC_CPUTIME_H + +#include + +#endif /* __PPC_CPUTIME_H */ diff --git a/include/asm-s390/cputime.h b/include/asm-s390/cputime.h new file mode 100644 index 000000000000..ad989e5d369c --- /dev/null +++ b/include/asm-s390/cputime.h @@ -0,0 +1,6 @@ +#ifndef __S390_CPUTIME_H +#define __S390_CPUTIME_H + +#include + +#endif /* __S390_CPUTIME_H */ diff --git a/include/asm-sh/cputime.h b/include/asm-sh/cputime.h new file mode 100644 index 000000000000..6ca395d1393e --- /dev/null +++ b/include/asm-sh/cputime.h @@ -0,0 +1,6 @@ +#ifndef __SH_CPUTIME_H +#define __SH_CPUTIME_H + +#include + +#endif /* __SH_CPUTIME_H */ diff --git a/include/asm-sh64/cputime.h b/include/asm-sh64/cputime.h new file mode 100644 index 000000000000..0fd89da2aa86 --- /dev/null +++ b/include/asm-sh64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __SH64_CPUTIME_H +#define __SH64_CPUTIME_H + +#include + +#endif /* __SH64_CPUTIME_H */ diff --git a/include/asm-sparc/cputime.h b/include/asm-sparc/cputime.h new file mode 100644 index 000000000000..1a642b81e019 --- /dev/null +++ b/include/asm-sparc/cputime.h @@ -0,0 +1,6 @@ +#ifndef __SPARC_CPUTIME_H +#define __SPARC_CPUTIME_H + +#include + +#endif /* __SPARC_CPUTIME_H */ diff --git a/include/asm-sparc64/cputime.h b/include/asm-sparc64/cputime.h new file mode 100644 index 000000000000..dec2fc7a36f8 --- /dev/null +++ b/include/asm-sparc64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __SPARC64_CPUTIME_H +#define __SPARC64_CPUTIME_H + +#include + +#endif /* __SPARC64_CPUTIME_H */ diff --git a/include/asm-um/cputime.h b/include/asm-um/cputime.h new file mode 100644 index 000000000000..c84acbadfa2f --- /dev/null +++ b/include/asm-um/cputime.h @@ -0,0 +1,6 @@ +#ifndef __UM_CPUTIME_H +#define __UM_CPUTIME_H + +#include + +#endif /* __UM_CPUTIME_H */ diff --git a/include/asm-v850/cputime.h b/include/asm-v850/cputime.h new file mode 100644 index 000000000000..7c799c33b8a9 --- /dev/null +++ b/include/asm-v850/cputime.h @@ -0,0 +1,6 @@ +#ifndef __V850_CPUTIME_H +#define __V850_CPUTIME_H + +#include + +#endif /* __V850_CPUTIME_H */ diff --git a/include/asm-x86_64/cputime.h b/include/asm-x86_64/cputime.h new file mode 100644 index 000000000000..a07012dc5a3c --- /dev/null +++ b/include/asm-x86_64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __X86_64_CPUTIME_H +#define __X86_64_CPUTIME_H + +#include + +#endif /* __X86_64_CPUTIME_H */ diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 4594ccc4a7c1..dba27749b428 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -6,6 +6,7 @@ #include #include #include +#include /* * 'kernel_stat.h' contains the definitions needed for doing @@ -14,13 +15,14 @@ */ struct cpu_usage_stat { - u64 user; - u64 nice; - u64 system; - u64 softirq; - u64 irq; - u64 idle; - u64 iowait; + cputime64_t user; + cputime64_t nice; + cputime64_t system; + cputime64_t softirq; + cputime64_t irq; + cputime64_t idle; + cputime64_t iowait; + cputime64_t steal; }; struct kernel_stat { @@ -50,4 +52,8 @@ static inline int kstat_irqs(int irq) return sum; } +extern void account_user_time(struct task_struct *, cputime_t); +extern void account_system_time(struct task_struct *, int, cputime_t); +extern void account_steal_time(struct task_struct *, cputime_t); + #endif /* _LINUX_KERNEL_STAT_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 3c2c63f23a4a..dcc1814f97e8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -168,7 +169,7 @@ long io_schedule_timeout(long timeout); extern void cpu_init (void); extern void trap_init(void); extern void update_process_times(int user); -extern void scheduler_tick(int user_tick, int system); +extern void scheduler_tick(void); extern unsigned long cache_decay_ticks; /* Attach to any functions which should be ignored in wchan output. */ @@ -311,7 +312,7 @@ struct signal_struct { * Live threads maintain their own counters and add to these * in __exit_signal, except for the group leader. */ - unsigned long utime, stime, cutime, cstime; + cputime_t utime, stime, cutime, cstime; unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt; @@ -589,10 +590,11 @@ struct task_struct { int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ unsigned long rt_priority; - unsigned long it_real_value, it_prof_value, it_virt_value; - unsigned long it_real_incr, it_prof_incr, it_virt_incr; + unsigned long it_real_value, it_real_incr; + cputime_t it_virt_value, it_virt_incr; + cputime_t it_prof_value, it_prof_incr; struct timer_list real_timer; - unsigned long utime, stime; + cputime_t utime, stime; unsigned long nvcsw, nivcsw; /* context switch counts */ struct timespec start_time; /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ diff --git a/kernel/compat.c b/kernel/compat.c index 48ee147c1343..d1b1d4dd019a 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -163,15 +163,15 @@ asmlinkage long compat_sys_times(struct compat_tms __user *tbuf) struct compat_tms tmp; struct task_struct *tsk = current; struct task_struct *t; - unsigned long utime, stime, cutime, cstime; + cputime_t utime, stime, cutime, cstime; read_lock(&tasklist_lock); utime = tsk->signal->utime; stime = tsk->signal->stime; t = tsk; do { - utime += t->utime; - stime += t->stime; + utime = cputime_add(utime, t->utime); + stime = cputime_add(stime, t->stime); t = next_thread(t); } while (t != tsk); @@ -190,10 +190,10 @@ asmlinkage long compat_sys_times(struct compat_tms __user *tbuf) spin_unlock_irq(&tsk->sighand->siglock); read_unlock(&tasklist_lock); - tmp.tms_utime = compat_jiffies_to_clock_t(utime); - tmp.tms_stime = compat_jiffies_to_clock_t(stime); - tmp.tms_cutime = compat_jiffies_to_clock_t(cutime); - tmp.tms_cstime = compat_jiffies_to_clock_t(cstime); + tmp.tms_utime = compat_jiffies_to_clock_t(cputime_to_jiffies(utime)); + tmp.tms_stime = compat_jiffies_to_clock_t(cputime_to_jiffies(stime)); + tmp.tms_cutime = compat_jiffies_to_clock_t(cputime_to_jiffies(cutime)); + tmp.tms_cstime = compat_jiffies_to_clock_t(cputime_to_jiffies(cstime)); if (copy_to_user(tbuf, &tmp, sizeof(tmp))) return -EFAULT; } diff --git a/kernel/cpu.c b/kernel/cpu.c index b97f7f91ec6d..628f4ccda127 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -48,7 +48,9 @@ static inline void check_for_tasks(int cpu) write_lock_irq(&tasklist_lock); for_each_process(p) { - if (task_cpu(p) == cpu && (p->utime != 0 || p->stime != 0)) + if (task_cpu(p) == cpu && + (!cputime_eq(p->utime, cputime_zero) || + !cputime_eq(p->stime, cputime_zero))) printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\ (state = %ld, flags = %lx) \n", p->comm, p->pid, cpu, p->state, p->flags); diff --git a/kernel/exit.c b/kernel/exit.c index 02f0a95cb557..e0df301a4553 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -755,8 +755,8 @@ static void exit_notify(struct task_struct *tsk) * Clear these here so that update_process_times() won't try to deliver * itimer, profile or rlimit signals to this task while it is in late exit. */ - tsk->it_virt_value = 0; - tsk->it_prof_value = 0; + tsk->it_virt_value = cputime_zero; + tsk->it_prof_value = cputime_zero; write_unlock_irq(&tasklist_lock); @@ -1046,10 +1046,16 @@ static int wait_task_zombie(task_t *p, int noreap, * here reaping other children at the same time. */ spin_lock_irq(&p->parent->sighand->siglock); - p->parent->signal->cutime += - p->utime + p->signal->utime + p->signal->cutime; - p->parent->signal->cstime += - p->stime + p->signal->stime + p->signal->cstime; + p->parent->signal->cutime = + cputime_add(p->parent->signal->cutime, + cputime_add(p->utime, + cputime_add(p->signal->utime, + p->signal->cutime))); + p->parent->signal->cstime = + cputime_add(p->parent->signal->cstime, + cputime_add(p->stime, + cputime_add(p->signal->stime, + p->signal->cstime))); p->parent->signal->cmin_flt += p->min_flt + p->signal->min_flt + p->signal->cmin_flt; p->parent->signal->cmaj_flt += diff --git a/kernel/fork.c b/kernel/fork.c index 6d9412937d37..be1ff8ddbb9c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -749,7 +749,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts sig->leader = 0; /* session leadership doesn't inherit */ sig->tty_old_pgrp = 0; - sig->utime = sig->stime = sig->cutime = sig->cstime = 0; + sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero; sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0; sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0; @@ -871,15 +871,15 @@ static task_t *copy_process(unsigned long clone_flags, p->it_real_value = 0; p->it_real_incr = 0; - p->it_virt_value = 0; - p->it_virt_incr = 0; - p->it_prof_value = 0; - p->it_prof_incr = 0; + p->it_virt_value = cputime_zero; + p->it_virt_incr = cputime_zero; + p->it_prof_value = cputime_zero; + p->it_prof_incr = cputime_zero; init_timer(&p->real_timer); p->real_timer.data = (unsigned long) p; - p->utime = 0; - p->stime = 0; + p->utime = cputime_zero; + p->stime = cputime_zero; p->rchar = 0; /* I/O counter: bytes read */ p->wchar = 0; /* I/O counter: bytes written */ p->syscr = 0; /* I/O counter: read syscalls */ diff --git a/kernel/itimer.c b/kernel/itimer.c index 95fbf1c6becf..e1743c563206 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -16,11 +16,10 @@ int do_getitimer(int which, struct itimerval *value) { - register unsigned long val, interval; + register unsigned long val; switch (which) { case ITIMER_REAL: - interval = current->it_real_incr; val = 0; /* * FIXME! This needs to be atomic, in case the kernel timer happens! @@ -32,20 +31,20 @@ int do_getitimer(int which, struct itimerval *value) if ((long) val <= 0) val = 1; } + jiffies_to_timeval(val, &value->it_value); + jiffies_to_timeval(current->it_real_incr, &value->it_interval); break; case ITIMER_VIRTUAL: - val = current->it_virt_value; - interval = current->it_virt_incr; + cputime_to_timeval(current->it_virt_value, &value->it_value); + cputime_to_timeval(current->it_virt_incr, &value->it_interval); break; case ITIMER_PROF: - val = current->it_prof_value; - interval = current->it_prof_incr; + cputime_to_timeval(current->it_prof_value, &value->it_value); + cputime_to_timeval(current->it_prof_incr, &value->it_interval); break; default: return(-EINVAL); } - jiffies_to_timeval(val, &value->it_value); - jiffies_to_timeval(interval, &value->it_interval); return 0; } @@ -81,37 +80,43 @@ void it_real_fn(unsigned long __data) int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) { - register unsigned long i, j; + unsigned long expire; + cputime_t cputime; int k; - i = timeval_to_jiffies(&value->it_interval); - j = timeval_to_jiffies(&value->it_value); if (ovalue && (k = do_getitimer(which, ovalue)) < 0) return k; switch (which) { case ITIMER_REAL: del_timer_sync(¤t->real_timer); - current->it_real_value = j; - current->it_real_incr = i; - if (!j) + expire = timeval_to_jiffies(&value->it_value); + current->it_real_value = expire; + current->it_real_incr = + timeval_to_jiffies(&value->it_interval); + if (!expire) break; - if (j > (unsigned long) LONG_MAX) - j = LONG_MAX; - i = j + jiffies; - current->real_timer.expires = i; + if (expire > (unsigned long) LONG_MAX) + expire = LONG_MAX; + current->real_timer.expires = jiffies + expire; add_timer(¤t->real_timer); break; case ITIMER_VIRTUAL: - if (j) - j++; - current->it_virt_value = j; - current->it_virt_incr = i; + cputime = timeval_to_cputime(&value->it_value); + if (cputime_gt(cputime, cputime_zero)) + cputime = cputime_add(cputime, + jiffies_to_cputime(1)); + current->it_virt_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_virt_incr = cputime; break; case ITIMER_PROF: - if (j) - j++; - current->it_prof_value = j; - current->it_prof_incr = i; + cputime = timeval_to_cputime(&value->it_value); + if (cputime_gt(cputime, cputime_zero)) + cputime = cputime_add(cputime, + jiffies_to_cputime(1)); + current->it_prof_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_prof_incr = cputime; break; default: return -EINVAL; diff --git a/kernel/sched.c b/kernel/sched.c index 1c523337bc61..9e1fbc42bd01 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1182,7 +1182,7 @@ void fastcall sched_fork(task_t *p) */ current->time_slice = 1; preempt_disable(); - scheduler_tick(0, 0); + scheduler_tick(); local_irq_enable(); preempt_enable(); } else @@ -2250,6 +2250,148 @@ EXPORT_PER_CPU_SYMBOL(kstat); STARVATION_LIMIT * ((rq)->nr_running) + 1))) || \ ((rq)->curr->static_prio > (rq)->best_expired_prio)) +/* + * Do the virtual cpu time signal calculations. + * @p: the process that the cpu time gets accounted to + * @cputime: the cpu time spent in user space since the last update + */ +static inline void account_it_virt(struct task_struct * p, cputime_t cputime) +{ + cputime_t it_virt = p->it_virt_value; + + if (cputime_gt(it_virt, cputime_zero) && + cputime_gt(cputime, cputime_zero)) { + if (cputime_ge(cputime, it_virt)) { + it_virt = cputime_add(it_virt, p->it_virt_incr); + send_sig(SIGVTALRM, p, 1); + } + it_virt = cputime_sub(it_virt, cputime); + p->it_virt_value = it_virt; + } +} + +/* + * Do the virtual profiling signal calculations. + * @p: the process that the cpu time gets accounted to + * @cputime: the cpu time spent in user and kernel space since the last update + */ +static void account_it_prof(struct task_struct *p, cputime_t cputime) +{ + cputime_t it_prof = p->it_prof_value; + + if (cputime_gt(it_prof, cputime_zero) && + cputime_gt(cputime, cputime_zero)) { + if (cputime_ge(cputime, it_prof)) { + it_prof = cputime_add(it_prof, p->it_prof_incr); + send_sig(SIGPROF, p, 1); + } + it_prof = cputime_sub(it_prof, cputime); + p->it_prof_value = it_prof; + } +} + +/* + * Check if the process went over its cputime resource limit after + * some cpu time got added to utime/stime. + * @p: the process that the cpu time gets accounted to + * @cputime: the cpu time spent in user and kernel space since the last update + */ +static void check_rlimit(struct task_struct *p, cputime_t cputime) +{ + cputime_t total, tmp; + + total = cputime_add(p->utime, p->stime); + tmp = jiffies_to_cputime(p->signal->rlim[RLIMIT_CPU].rlim_cur); + if (unlikely(cputime_gt(total, tmp))) { + /* Send SIGXCPU every second. */ + tmp = cputime_sub(total, cputime); + if (cputime_to_secs(tmp) < cputime_to_secs(total)) + send_sig(SIGXCPU, p, 1); + /* and SIGKILL when we go over max.. */ + tmp = jiffies_to_cputime(p->signal->rlim[RLIMIT_CPU].rlim_max); + if (cputime_gt(total, tmp)) + send_sig(SIGKILL, p, 1); + } +} + +/* + * Account user cpu time to a process. + * @p: the process that the cpu time gets accounted to + * @hardirq_offset: the offset to subtract from hardirq_count() + * @cputime: the cpu time spent in user space since the last update + */ +void account_user_time(struct task_struct *p, cputime_t cputime) +{ + struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; + cputime64_t tmp; + + p->utime = cputime_add(p->utime, cputime); + + /* Check for signals (SIGVTALRM, SIGPROF, SIGXCPU & SIGKILL). */ + check_rlimit(p, cputime); + account_it_virt(p, cputime); + account_it_prof(p, cputime); + + /* Add user time to cpustat. */ + tmp = cputime_to_cputime64(cputime); + if (TASK_NICE(p) > 0) + cpustat->nice = cputime64_add(cpustat->nice, tmp); + else + cpustat->user = cputime64_add(cpustat->user, tmp); +} + +/* + * Account system cpu time to a process. + * @p: the process that the cpu time gets accounted to + * @hardirq_offset: the offset to subtract from hardirq_count() + * @cputime: the cpu time spent in kernel space since the last update + */ +void account_system_time(struct task_struct *p, int hardirq_offset, + cputime_t cputime) +{ + struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; + runqueue_t *rq = this_rq(); + cputime64_t tmp; + + p->stime = cputime_add(p->stime, cputime); + + /* Check for signals (SIGPROF, SIGXCPU & SIGKILL). */ + if (likely(p->signal && p->exit_state < EXIT_ZOMBIE)) { + check_rlimit(p, cputime); + account_it_prof(p, cputime); + } + + /* Add system time to cpustat. */ + tmp = cputime_to_cputime64(cputime); + if (hardirq_count() - hardirq_offset) + cpustat->irq = cputime64_add(cpustat->irq, tmp); + else if (softirq_count()) + cpustat->softirq = cputime64_add(cpustat->softirq, tmp); + else if (p != rq->idle) + cpustat->system = cputime64_add(cpustat->system, tmp); + else if (atomic_read(&rq->nr_iowait) > 0) + cpustat->iowait = cputime64_add(cpustat->iowait, tmp); + else + cpustat->idle = cputime64_add(cpustat->idle, tmp); +} + +/* + * Account for involuntary wait time. + * @p: the process from which the cpu time has been stolen + * @steal: the cpu time spent in involuntary wait + */ +void account_steal_time(struct task_struct *p, cputime_t steal) +{ + struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; + cputime64_t steal64 = cputime_to_cputime64(steal); + runqueue_t *rq = this_rq(); + + if (p == rq->idle) + cpustat->system = cputime64_add(cpustat->system, steal64); + else + cpustat->steal = cputime64_add(cpustat->steal, steal64); +} + /* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. @@ -2257,42 +2399,20 @@ EXPORT_PER_CPU_SYMBOL(kstat); * It also gets called by the fork code, when changing the parent's * timeslices. */ -void scheduler_tick(int user_ticks, int sys_ticks) +void scheduler_tick(void) { int cpu = smp_processor_id(); - struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; runqueue_t *rq = this_rq(); task_t *p = current; rq->timestamp_last_tick = sched_clock(); - if (rcu_pending(cpu)) - rcu_check_callbacks(cpu, user_ticks); - - /* note: this timer irq context must be accounted for as well */ - if (hardirq_count() - HARDIRQ_OFFSET) { - cpustat->irq += sys_ticks; - sys_ticks = 0; - } else if (softirq_count()) { - cpustat->softirq += sys_ticks; - sys_ticks = 0; - } - if (p == rq->idle) { - if (atomic_read(&rq->nr_iowait) > 0) - cpustat->iowait += sys_ticks; - else - cpustat->idle += sys_ticks; if (wake_priority_sleeper(rq)) goto out; rebalance_tick(cpu, rq, SCHED_IDLE); return; } - if (TASK_NICE(p) > 0) - cpustat->nice += user_ticks; - else - cpustat->user += user_ticks; - cpustat->system += sys_ticks; /* Task might have expired already, but not scheduled off yet */ if (p->array != rq->active) { diff --git a/kernel/signal.c b/kernel/signal.c index d800b3f97323..6d0a3bd948ab 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -375,8 +375,8 @@ void __exit_signal(struct task_struct *tsk) * We won't ever get here for the group leader, since it * will have been the last reference on the signal_struct. */ - sig->utime += tsk->utime; - sig->stime += tsk->stime; + sig->utime = cputime_add(sig->utime, tsk->utime); + sig->stime = cputime_add(sig->stime, tsk->stime); sig->min_flt += tsk->min_flt; sig->maj_flt += tsk->maj_flt; sig->nvcsw += tsk->nvcsw; @@ -1470,8 +1470,10 @@ void do_notify_parent(struct task_struct *tsk, int sig) info.si_uid = tsk->uid; /* FIXME: find out whether or not this is supposed to be c*time. */ - info.si_utime = tsk->utime + tsk->signal->utime; - info.si_stime = tsk->stime + tsk->signal->stime; + info.si_utime = cputime_to_jiffies(cputime_add(tsk->utime, + tsk->signal->utime)); + info.si_stime = cputime_to_jiffies(cputime_add(tsk->stime, + tsk->signal->stime)); info.si_status = tsk->exit_code & 0x7f; if (tsk->exit_code & 0x80) @@ -1527,8 +1529,8 @@ do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent, info.si_uid = tsk->uid; /* FIXME: find out whether or not this is supposed to be c*time. */ - info.si_utime = tsk->utime; - info.si_stime = tsk->stime; + info.si_utime = cputime_to_jiffies(tsk->utime); + info.si_stime = cputime_to_jiffies(tsk->stime); info.si_code = why; switch (why) { diff --git a/kernel/sys.c b/kernel/sys.c index 20080da0c3de..6e354fd380e7 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -893,15 +893,15 @@ asmlinkage long sys_times(struct tms __user * tbuf) struct tms tmp; struct task_struct *tsk = current; struct task_struct *t; - unsigned long utime, stime, cutime, cstime; + cputime_t utime, stime, cutime, cstime; read_lock(&tasklist_lock); utime = tsk->signal->utime; stime = tsk->signal->stime; t = tsk; do { - utime += t->utime; - stime += t->stime; + utime = cputime_add(utime, t->utime); + stime = cputime_add(stime, t->stime); t = next_thread(t); } while (t != tsk); @@ -920,10 +920,10 @@ asmlinkage long sys_times(struct tms __user * tbuf) spin_unlock_irq(&tsk->sighand->siglock); read_unlock(&tasklist_lock); - tmp.tms_utime = jiffies_to_clock_t(utime); - tmp.tms_stime = jiffies_to_clock_t(stime); - tmp.tms_cutime = jiffies_to_clock_t(cutime); - tmp.tms_cstime = jiffies_to_clock_t(cstime); + tmp.tms_utime = cputime_to_clock_t(utime); + tmp.tms_stime = cputime_to_clock_t(stime); + tmp.tms_cutime = cputime_to_clock_t(cutime); + tmp.tms_cstime = cputime_to_clock_t(cstime); if (copy_to_user(tbuf, &tmp, sizeof(struct tms))) return -EFAULT; } @@ -1528,7 +1528,7 @@ void k_getrusage(struct task_struct *p, int who, struct rusage *r) { struct task_struct *t; unsigned long flags; - unsigned long utime, stime; + cputime_t utime, stime; memset((char *) r, 0, sizeof *r); @@ -1545,12 +1545,12 @@ void k_getrusage(struct task_struct *p, int who, struct rusage *r) r->ru_minflt = p->signal->cmin_flt; r->ru_majflt = p->signal->cmaj_flt; spin_unlock_irqrestore(&p->sighand->siglock, flags); - jiffies_to_timeval(utime, &r->ru_utime); - jiffies_to_timeval(stime, &r->ru_stime); + cputime_to_timeval(utime, &r->ru_utime); + cputime_to_timeval(stime, &r->ru_stime); break; case RUSAGE_SELF: spin_lock_irqsave(&p->sighand->siglock, flags); - utime = stime = 0; + utime = stime = cputime_zero; goto sum_group; case RUSAGE_BOTH: spin_lock_irqsave(&p->sighand->siglock, flags); @@ -1561,16 +1561,16 @@ void k_getrusage(struct task_struct *p, int who, struct rusage *r) r->ru_minflt = p->signal->cmin_flt; r->ru_majflt = p->signal->cmaj_flt; sum_group: - utime += p->signal->utime; - stime += p->signal->stime; + utime = cputime_add(utime, p->signal->utime); + stime = cputime_add(stime, p->signal->stime); r->ru_nvcsw += p->signal->nvcsw; r->ru_nivcsw += p->signal->nivcsw; r->ru_minflt += p->signal->min_flt; r->ru_majflt += p->signal->maj_flt; t = p; do { - utime += t->utime; - stime += t->stime; + utime = cputime_add(utime, t->utime); + stime = cputime_add(stime, t->stime); r->ru_nvcsw += t->nvcsw; r->ru_nivcsw += t->nivcsw; r->ru_minflt += t->min_flt; @@ -1578,8 +1578,8 @@ void k_getrusage(struct task_struct *p, int who, struct rusage *r) t = next_thread(t); } while (t != p); spin_unlock_irqrestore(&p->sighand->siglock, flags); - jiffies_to_timeval(utime, &r->ru_utime); - jiffies_to_timeval(stime, &r->ru_stime); + cputime_to_timeval(utime, &r->ru_utime); + cputime_to_timeval(stime, &r->ru_stime); break; default: BUG(); diff --git a/kernel/timer.c b/kernel/timer.c index ec35a6e801a8..6bb47b0e4983 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -806,59 +806,6 @@ static void update_wall_time(unsigned long ticks) } while (ticks); } -static inline void do_process_times(struct task_struct *p, - unsigned long user, unsigned long system) -{ - unsigned long psecs; - - psecs = (p->utime += user); - psecs += (p->stime += system); - if (p->signal && !unlikely(p->exit_state) && - psecs / HZ >= p->signal->rlim[RLIMIT_CPU].rlim_cur) { - /* Send SIGXCPU every second.. */ - if (!(psecs % HZ)) - send_sig(SIGXCPU, p, 1); - /* and SIGKILL when we go over max.. */ - if (psecs / HZ >= p->signal->rlim[RLIMIT_CPU].rlim_max) - send_sig(SIGKILL, p, 1); - } -} - -static inline void do_it_virt(struct task_struct * p, unsigned long ticks) -{ - unsigned long it_virt = p->it_virt_value; - - if (it_virt) { - it_virt -= ticks; - if (!it_virt) { - it_virt = p->it_virt_incr; - send_sig(SIGVTALRM, p, 1); - } - p->it_virt_value = it_virt; - } -} - -static inline void do_it_prof(struct task_struct *p) -{ - unsigned long it_prof = p->it_prof_value; - - if (it_prof) { - if (--it_prof == 0) { - it_prof = p->it_prof_incr; - send_sig(SIGPROF, p, 1); - } - p->it_prof_value = it_prof; - } -} - -static void update_one_process(struct task_struct *p, unsigned long user, - unsigned long system, int cpu) -{ - do_process_times(p, user, system); - do_it_virt(p, user); - do_it_prof(p); -} - /* * Called from the timer interrupt handler to charge one tick to the current * process. user_tick is 1 if the tick is user time, 0 for system. @@ -866,11 +813,17 @@ static void update_one_process(struct task_struct *p, unsigned long user, void update_process_times(int user_tick) { struct task_struct *p = current; - int cpu = smp_processor_id(), system = user_tick ^ 1; + int cpu = smp_processor_id(); - update_one_process(p, user_tick, system, cpu); + /* Note: this timer irq context must be accounted for as well. */ + if (user_tick) + account_user_time(p, jiffies_to_cputime(1)); + else + account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1)); run_local_timers(); - scheduler_tick(user_tick, system); + if (rcu_pending(cpu)) + rcu_check_callbacks(cpu, user_tick); + scheduler_tick(); } /* diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 967958c7fae1..7f2951f4ddca 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -61,7 +61,8 @@ static unsigned long badness(struct task_struct *p, unsigned long uptime) * of seconds. There is no particular reason for this other than * that it turned out to work very well in practice. */ - cpu_time = (p->utime + p->stime) >> (SHIFT_HZ + 3); + cpu_time = (cputime_to_jiffies(p->utime) + cputime_to_jiffies(p->stime)) + >> (SHIFT_HZ + 3); if (uptime >= p->start_time.tv_sec) run_time = (uptime - p->start_time.tv_sec) >> 10; -- cgit v1.2.3 From a6ab0c16edd9bf13db04afc7cd88cb137fe770aa Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 11 Jan 2005 01:40:53 -0800 Subject: [PATCH] cputime: microsecond based cputime for s390 This patch adds the architecture magic to replace the jiffies based cputime with microsecond based cputime and it adds code to calculate involuntary wait time. With this patch the numbers reported by top and ps when running on LPAR or z/VM are finally not junk anymore. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/s390/Kconfig | 7 ++ arch/s390/kernel/binfmt_elf32.c | 5 +- arch/s390/kernel/entry.S | 135 +++++++++++++++++++++++++++++-- arch/s390/kernel/entry64.S | 128 ++++++++++++++++++++++++++++-- arch/s390/kernel/irq.c | 8 ++ arch/s390/kernel/time.c | 42 +++------- arch/s390/kernel/vtime.c | 111 ++++++++++++++++++++++---- include/asm-s390/cputime.h | 170 +++++++++++++++++++++++++++++++++++++++- include/asm-s390/hardirq.h | 1 + include/asm-s390/lowcore.h | 47 +++++++++-- include/asm-s390/system.h | 18 +++++ include/asm-s390/timer.h | 2 - include/linux/hardirq.h | 18 ++++- kernel/softirq.c | 1 + 14 files changed, 620 insertions(+), 73 deletions(-) (limited to 'include') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 85ecab32be89..8394c4e51073 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -367,6 +367,13 @@ config VIRT_TIMER This provides a kernel interface for virtual CPU timers. Default is disabled. +config VIRT_CPU_ACCOUNTING + bool "Base user process accounting on virtual cpu timer" + depends on VIRT_TIMER + help + Select this option to use CPU timer deltas to do user + process accounting. + config APPLDATA_BASE bool "Linux - VM Monitor Stream, base infrastructure" depends on PROC_FS && VIRT_TIMER=y diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index ed234bf06d1c..03ba5893f17b 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -202,9 +202,8 @@ MODULE_AUTHOR("Gerhard Tonn "); static __inline__ void cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { - unsigned long jiffies = cputime_to_jiffies(cputime); - value->tv_usec = (jiffies % HZ) * (1000000L / HZ); - value->tv_sec = jiffies / HZ; + value->tv_usec = cputime % 1000000; + value->tv_sec = cputime / 1000000; } #include "../../../fs/binfmt_elf.c" diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index f72f9ec9be55..c0e09b33febe 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -66,6 +66,27 @@ STACK_SIZE = 1 << STACK_SHIFT * R15 - kernel stack pointer */ + .macro STORE_TIMER lc_offset +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + stpt \lc_offset +#endif + .endm + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .macro UPDATE_VTIME lc_from,lc_to,lc_sum + lm %r10,%r11,\lc_from + sl %r10,\lc_to + sl %r11,\lc_to+4 + bc 3,BASED(0f) + sl %r10,BASED(.Lc_1) +0: al %r10,\lc_sum + al %r11,\lc_sum+4 + bc 12,BASED(1f) + al %r10,BASED(.Lc_1) +1: stm %r10,%r11,\lc_sum + .endm +#endif + .macro SAVE_ALL_BASE savearea stm %r12,%r15,\savearea l %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13 @@ -118,6 +139,7 @@ STACK_SIZE = 1 << STACK_SHIFT ni __LC_RETURN_PSW+1,0xfd # clear wait state bit .endif lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user + STORE_TIMER __LC_EXIT_TIMER lpsw __LC_RETURN_PSW # back to caller .endm @@ -159,9 +181,21 @@ __critical_start: .globl system_call system_call: + STORE_TIMER __LC_SYNC_ENTER_TIMER +sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 lh %r7,0x8a # get svc number from lowcore +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +sysc_vtime: + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(sysc_do_svc) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER +sysc_stime: + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER +sysc_update: + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +#endif sysc_do_svc: l %r9,__LC_THREAD_INFO # load pointer to thread_info struct sla %r7,2 # *4 and test for svc 0 @@ -391,10 +425,19 @@ pgm_check_handler: * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ + STORE_TIMER __LC_SYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception bnz BASED(pgm_per) # got per exception -> special case SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(pgm_no_vtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime: +#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct l %r3,__LC_PGM_ILC # load program interruption code la %r8,0x7f @@ -425,6 +468,14 @@ pgm_per: # pgm_per_std: SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(pgm_no_vtime2) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime2: +#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct l %r1,__TI_task(%r9) mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID @@ -442,6 +493,14 @@ pgm_per_std: # pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(pgm_no_vtime3) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime3: +#endif lh %r7,0x8a # get svc number from lowcore l %r9,__LC_THREAD_INFO # load pointer to thread_info struct l %r1,__TI_task(%r9) @@ -458,9 +517,18 @@ pgm_svcper: .globl io_int_handler io_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+16 SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(io_no_vtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +io_no_vtime: +#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ la %r2,SP_PTREGS(%r15) # address of register-save area @@ -549,9 +617,18 @@ io_sigpending: .globl ext_int_handler ext_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+16 SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(ext_no_vtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +ext_no_vtime: +#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # address of register-save area lh %r3,__LC_EXT_INT_CODE # get interruption code @@ -565,8 +642,17 @@ ext_int_handler: .globl mcck_int_handler mcck_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(mcck_no_vtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +mcck_no_vtime: +#endif l %r1,BASED(.Ls390_mcck) basr %r14,%r1 # call machine check handler mcck_return: @@ -661,17 +747,47 @@ cleanup_critical: br %r14 cleanup_system_call: - mvc __LC_RETURN_PSW(4),0(%r12) - clc 4(4,%r12),BASED(cleanup_table_system_call) - bne BASED(0f) + mvc __LC_RETURN_PSW(8),0(%r12) +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4) + bh BASED(0f) + mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER +0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) + bhe BASED(cleanup_vtime) +#endif + clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn) + bh BASED(0f) mvc __LC_SAVE_AREA(16),__LC_SAVE_AREA+16 0: st %r13,__LC_SAVE_AREA+20 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 st %r15,__LC_SAVE_AREA+28 lh %r7,0x8a +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +cleanup_vtime: + clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12) + bhe BASED(cleanup_stime) + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(cleanup_novtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER +cleanup_stime: + clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+16) + bh BASED(cleanup_update) + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER +cleanup_update: + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +cleanup_novtime: +#endif mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_system_call+4) la %r12,__LC_RETURN_PSW br %r14 +cleanup_system_call_insn: + .long sysc_saveall + 0x80000000 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .long system_call + 0x80000000 + .long sysc_vtime + 0x80000000 + .long sysc_stime + 0x80000000 + .long sysc_update + 0x80000000 +#endif cleanup_sysc_return: mvc __LC_RETURN_PSW(4),0(%r12) @@ -680,15 +796,23 @@ cleanup_sysc_return: br %r14 cleanup_sysc_leave: - clc 4(4,%r12),BASED(cleanup_sysc_leave_lpsw) + clc 4(4,%r12),BASED(cleanup_sysc_leave_insn) + be BASED(0f) +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER + clc 4(4,%r12),BASED(cleanup_sysc_leave_insn+4) be BASED(0f) +#endif mvc __LC_RETURN_PSW(8),SP_PSW(%r15) mvc __LC_SAVE_AREA+16(16),SP_R12(%r15) lm %r0,%r11,SP_R0(%r15) l %r15,SP_R15(%r15) 0: la %r12,__LC_RETURN_PSW br %r14 -cleanup_sysc_leave_lpsw: +cleanup_sysc_leave_insn: +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .long sysc_leave + 14 + 0x80000000 +#endif .long sysc_leave + 10 + 0x80000000 /* @@ -704,6 +828,7 @@ cleanup_sysc_leave_lpsw: .L0x028: .short 0x028 .L0x030: .short 0x030 .L0x038: .short 0x038 +.Lc_1: .long 1 /* * Symbol constants diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index adbe2a5f5f72..51527ab8c8f9 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -58,6 +58,21 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) #define BASED(name) name-system_call(%r13) + .macro STORE_TIMER lc_offset +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + stpt \lc_offset +#endif + .endm + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .macro UPDATE_VTIME lc_from,lc_to,lc_sum + lg %r10,\lc_from + slg %r10,\lc_to + alg %r10,\lc_sum + stg %r10,\lc_sum + .endm +#endif + /* * Register usage in interrupt handlers: * R9 - pointer to current task structure @@ -117,6 +132,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) ni __LC_RETURN_PSW+1,0xfd # clear wait state bit .endif lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user + STORE_TIMER __LC_EXIT_TIMER lpswe __LC_RETURN_PSW # back to caller .endm @@ -156,9 +172,21 @@ __critical_start: .globl system_call system_call: + STORE_TIMER __LC_SYNC_ENTER_TIMER +sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +sysc_vtime: + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz sysc_do_svc + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER +sysc_stime: + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER +sysc_update: + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +#endif sysc_do_svc: lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct slag %r7,%r7,2 # *4 and test for svc 0 @@ -441,10 +469,19 @@ pgm_check_handler: * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ + STORE_TIMER __LC_SYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception jnz pgm_per # got per exception -> special case SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz pgm_no_vtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime: +#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lgf %r3,__LC_PGM_ILC # load program interruption code lghi %r8,0x7f @@ -475,6 +512,14 @@ pgm_per: # pgm_per_std: SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz pgm_no_vtime2 + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime2: +#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r1,__TI_task(%r9) mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID @@ -492,6 +537,14 @@ pgm_per_std: # pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz pgm_no_vtime3 + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime3: +#endif llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r1,__TI_task(%r9) @@ -507,9 +560,18 @@ pgm_svcper: */ .globl io_int_handler io_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz io_no_vtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +io_no_vtime: +#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # address of register-save area brasl %r14,do_IRQ # call standard irq handler @@ -595,9 +657,18 @@ io_sigpending: */ .globl ext_int_handler ext_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz ext_no_vtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +ext_no_vtime: +#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # address of register-save area llgh %r3,__LC_EXT_INT_CODE # get interruption code @@ -609,8 +680,17 @@ ext_int_handler: */ .globl mcck_int_handler mcck_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA+64 SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz mcck_no_vtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +mcck_no_vtime: +#endif brasl %r14,s390_do_machine_check mcck_return: RESTORE_ALL 0 @@ -700,17 +780,47 @@ cleanup_critical: br %r14 cleanup_system_call: - mvc __LC_RETURN_PSW(8),0(%r12) - clc 8(8,%r12),BASED(cleanup_table_system_call) - jne 0f + mvc __LC_RETURN_PSW(16),0(%r12) +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8) + jh 0f + mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER +0: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16) + jhe cleanup_vtime +#endif + clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn) + jh 0f mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32 0: stg %r13,__LC_SAVE_AREA+40 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 stg %r15,__LC_SAVE_AREA+56 llgh %r7,__LC_SVC_INT_CODE +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +cleanup_vtime: + clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) + jhe cleanup_stime + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz cleanup_novtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER +cleanup_stime: + clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+32) + jh cleanup_update + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER +cleanup_update: + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +cleanup_novtime: +#endif mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8) la %r12,__LC_RETURN_PSW br %r14 +cleanup_system_call_insn: + .quad sysc_saveall +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .quad system_call + .quad sysc_vtime + .quad sysc_stime + .quad sysc_update +#endif cleanup_sysc_return: mvc __LC_RETURN_PSW(8),0(%r12) @@ -719,15 +829,23 @@ cleanup_sysc_return: br %r14 cleanup_sysc_leave: - clc 8(8,%r12),BASED(cleanup_sysc_leave_lpsw) + clc 8(8,%r12),BASED(cleanup_sysc_leave_insn) + je 0f +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER + clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8) je 0f +#endif mvc __LC_RETURN_PSW(16),SP_PSW(%r15) mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) lmg %r0,%r11,SP_R0(%r15) lg %r15,SP_R15(%r15) 0: la %r12,__LC_RETURN_PSW br %r14 -cleanup_sysc_leave_lpsw: +cleanup_sysc_leave_insn: +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .quad sysc_leave + 16 +#endif .quad sysc_leave + 12 /* diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 75275fe905b1..59bfceabaebe 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -71,6 +71,10 @@ asmlinkage void do_softirq(void) local_irq_save(flags); + account_system_vtime(current); + + local_bh_disable(); + if (local_softirq_pending()) { /* Get current stack pointer. */ asm volatile("la %0,0(15)" : "=a" (old)); @@ -93,6 +97,10 @@ asmlinkage void do_softirq(void) __do_softirq(); } + account_system_vtime(current); + + __local_bh_enable(); + local_irq_restore(flags); } diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 2fea300f4b47..995e2cd38e77 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -150,28 +150,6 @@ int do_settimeofday(struct timespec *tv) EXPORT_SYMBOL(do_settimeofday); -#ifndef CONFIG_ARCH_S390X - -static inline __u32 -__calculate_ticks(__u64 elapsed) -{ - register_pair rp; - - rp.pair = elapsed >> 1; - asm ("dr %0,%1" : "+d" (rp) : "d" (CLK_TICKS_PER_JIFFY >> 1)); - return rp.subreg.odd; -} - -#else /* CONFIG_ARCH_S390X */ - -static inline __u32 -__calculate_ticks(__u64 elapsed) -{ - return elapsed / CLK_TICKS_PER_JIFFY; -} - -#endif /* CONFIG_ARCH_S390X */ - #ifdef CONFIG_PROFILING #define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs) @@ -187,14 +165,14 @@ __calculate_ticks(__u64 elapsed) void account_ticks(struct pt_regs *regs) { __u64 tmp; - __u32 ticks; + __u32 ticks, xticks; /* Calculate how many ticks have passed. */ if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) return; tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer; if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */ - ticks = __calculate_ticks(tmp) + 1; + ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1; S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY * (__u64) ticks; } else if (tmp >= CLK_TICKS_PER_JIFFY) { @@ -216,11 +194,9 @@ void account_ticks(struct pt_regs *regs) */ write_seqlock(&xtime_lock); if (S390_lowcore.jiffy_timer > xtime_cc) { - __u32 xticks; - tmp = S390_lowcore.jiffy_timer - xtime_cc; if (tmp >= 2*CLK_TICKS_PER_JIFFY) { - xticks = __calculate_ticks(tmp); + xticks = __div(tmp, CLK_TICKS_PER_JIFFY); xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY; } else { xticks = 1; @@ -230,14 +206,18 @@ void account_ticks(struct pt_regs *regs) do_timer(regs); } write_sequnlock(&xtime_lock); - while (ticks--) - update_process_times(user_mode(regs)); #else - while (ticks--) { + for (xticks = ticks; xticks > 0; xticks--) do_timer(regs); +#endif + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + account_user_vtime(current); +#else + while (ticks--) update_process_times(user_mode(regs)); - } #endif + s390_do_profile(regs); } diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 02d2179e4082..63cdfec3ba99 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -25,7 +27,95 @@ static ext_int_info_t ext_int_info_timer; DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); -void start_cpu_timer(void) +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +/* + * Update process times based on virtual cpu times stored by entry.S + * to the lowcore fields user_timer, system_timer & steal_clock. + */ +void account_user_vtime(struct task_struct *tsk) +{ + cputime_t cputime; + __u64 timer, clock; + int rcu_user_flag; + + timer = S390_lowcore.last_update_timer; + clock = S390_lowcore.last_update_clock; + asm volatile (" STPT %0\n" /* Store current cpu timer value */ + " STCK %1" /* Store current tod clock value */ + : "=m" (S390_lowcore.last_update_timer), + "=m" (S390_lowcore.last_update_clock) ); + S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; + S390_lowcore.steal_clock += S390_lowcore.last_update_clock - clock; + + cputime = S390_lowcore.user_timer >> 12; + rcu_user_flag = cputime != 0; + S390_lowcore.user_timer -= cputime << 12; + S390_lowcore.steal_clock -= cputime << 12; + account_user_time(tsk, cputime); + + cputime = S390_lowcore.system_timer >> 12; + S390_lowcore.system_timer -= cputime << 12; + S390_lowcore.steal_clock -= cputime << 12; + account_system_time(tsk, HARDIRQ_OFFSET, cputime); + + cputime = S390_lowcore.steal_clock; + if ((__s64) cputime > 0) { + cputime >>= 12; + S390_lowcore.steal_clock -= cputime << 12; + account_steal_time(tsk, cputime); + } + + run_local_timers(); + if (rcu_pending(smp_processor_id())) + rcu_check_callbacks(smp_processor_id(), rcu_user_flag); + scheduler_tick(); +} + +/* + * Update process times based on virtual cpu times stored by entry.S + * to the lowcore fields user_timer, system_timer & steal_clock. + */ +void account_system_vtime(struct task_struct *tsk) +{ + cputime_t cputime; + __u64 timer; + + timer = S390_lowcore.last_update_timer; + asm volatile (" STPT %0" /* Store current cpu timer value */ + : "=m" (S390_lowcore.last_update_timer) ); + S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; + + cputime = S390_lowcore.system_timer >> 12; + S390_lowcore.system_timer -= cputime << 12; + S390_lowcore.steal_clock -= cputime << 12; + account_system_time(tsk, 0, cputime); +} + +static inline void set_vtimer(__u64 expires) +{ + __u64 timer; + + asm volatile (" STPT %0\n" /* Store current cpu timer value */ + " SPT %1" /* Set new value immediatly afterwards */ + : "=m" (timer) : "m" (expires) ); + S390_lowcore.system_timer += S390_lowcore.last_update_timer - timer; + S390_lowcore.last_update_timer = expires; + + /* store expire time for this CPU timer */ + per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; +} +#else +static inline void set_vtimer(__u64 expires) +{ + S390_lowcore.last_update_timer = expires; + asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer)); + + /* store expire time for this CPU timer */ + per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; +} +#endif + +static void start_cpu_timer(void) { struct vtimer_queue *vt_list; @@ -33,7 +123,7 @@ void start_cpu_timer(void) set_vtimer(vt_list->idle); } -void stop_cpu_timer(void) +static void stop_cpu_timer(void) { __u64 done; struct vtimer_queue *vt_list; @@ -71,19 +161,11 @@ void stop_cpu_timer(void) set_vtimer(VTIMER_MAX_SLICE); } -void set_vtimer(__u64 expires) -{ - asm volatile ("SPT %0" : : "m" (expires)); - - /* store expire time for this CPU timer */ - per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; -} - /* * Sorted add to a list. List is linear searched until first bigger * element is found. */ -void list_add_sorted(struct vtimer_list *timer, struct list_head *head) +static void list_add_sorted(struct vtimer_list *timer, struct list_head *head) { struct vtimer_list *event; @@ -429,11 +511,12 @@ void init_cpu_vtimer(void) { struct vtimer_queue *vt_list; unsigned long cr0; - __u64 timer; /* kick the virtual timer */ - timer = VTIMER_MAX_SLICE; - asm volatile ("SPT %0" : : "m" (timer)); + S390_lowcore.exit_timer = VTIMER_MAX_SLICE; + S390_lowcore.last_update_timer = VTIMER_MAX_SLICE; + asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer)); + asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock)); __ctl_store(cr0, 0, 0); cr0 |= 0x400; __ctl_load(cr0, 0, 0); diff --git a/include/asm-s390/cputime.h b/include/asm-s390/cputime.h index ad989e5d369c..216d861337e6 100644 --- a/include/asm-s390/cputime.h +++ b/include/asm-s390/cputime.h @@ -1,6 +1,168 @@ -#ifndef __S390_CPUTIME_H -#define __S390_CPUTIME_H +/* + * include/asm-s390/cputime.h + * + * (C) Copyright IBM Corp. 2004 + * + * Author: Martin Schwidefsky + */ -#include +#ifndef _S390_CPUTIME_H +#define _S390_CPUTIME_H -#endif /* __S390_CPUTIME_H */ +/* We want to use micro-second resolution. */ + +typedef unsigned long long cputime_t; +typedef unsigned long long cputime64_t; + +#ifndef __s390x__ + +static inline unsigned int +__div(unsigned long long n, unsigned int base) +{ + register_pair rp; + + rp.pair = n >> 1; + asm ("dr %0,%1" : "+d" (rp) : "d" (base >> 1)); + return rp.subreg.odd; +} + +#else /* __s390x__ */ + +static inline unsigned int +__div(unsigned long long n, unsigned int base) +{ + return n / base; +} + +#endif /* __s390x__ */ + +#define cputime_zero (0ULL) +#define cputime_max ((~0UL >> 1) - 1) +#define cputime_add(__a, __b) ((__a) + (__b)) +#define cputime_sub(__a, __b) ((__a) - (__b)) +#define cputime_eq(__a, __b) ((__a) == (__b)) +#define cputime_gt(__a, __b) ((__a) > (__b)) +#define cputime_ge(__a, __b) ((__a) >= (__b)) +#define cputime_lt(__a, __b) ((__a) < (__b)) +#define cputime_le(__a, __b) ((__a) <= (__b)) +#define cputime_to_jiffies(__ct) (__div((__ct), 1000000 / HZ)) +#define jiffies_to_cputime(__hz) ((cputime_t)(__hz) * (1000000 / HZ)) + +#define cputime64_zero (0ULL) +#define cputime64_add(__a, __b) ((__a) + (__b)) +#define cputime_to_cputime64(__ct) (__ct) + +static inline u64 +cputime64_to_jiffies64(cputime64_t cputime) +{ + do_div(cputime, 1000000 / HZ); + return cputime; +} + +/* + * Convert cputime to milliseconds and back. + */ +static inline unsigned int +cputime_to_msecs(const cputime_t cputime) +{ + return __div(cputime, 1000); +} + +static inline cputime_t +msecs_to_cputime(const unsigned int m) +{ + return (cputime_t) m * 1000; +} + +/* + * Convert cputime to milliseconds and back. + */ +static inline unsigned int +cputime_to_secs(const cputime_t cputime) +{ + return __div(cputime, 1000000); +} + +static inline cputime_t +secs_to_cputime(const unsigned int s) +{ + return (cputime_t) s * 1000000; +} + +/* + * Convert cputime to timespec and back. + */ +static inline cputime_t +timespec_to_cputime(const struct timespec *value) +{ + return value->tv_nsec / 1000 + (u64) value->tv_sec * 1000000; +} + +static inline void +cputime_to_timespec(const cputime_t cputime, struct timespec *value) +{ +#ifndef __s390x__ + register_pair rp; + + rp.pair = cputime >> 1; + asm ("dr %0,%1" : "+d" (rp) : "d" (1000000 >> 1)); + value->tv_nsec = rp.subreg.even * 1000; + value->tv_sec = rp.subreg.odd; +#else + value->tv_nsec = (cputime % 1000000) * 1000; + value->tv_sec = cputime / 1000000; +#endif +} + +/* + * Convert cputime to timeval and back. + * Since cputime and timeval have the same resolution (microseconds) + * this is easy. + */ +static inline cputime_t +timeval_to_cputime(const struct timeval *value) +{ + return value->tv_usec + (u64) value->tv_sec * 1000000; +} + +static inline void +cputime_to_timeval(const cputime_t cputime, struct timeval *value) +{ +#ifndef __s390x__ + register_pair rp; + + rp.pair = cputime >> 1; + asm ("dr %0,%1" : "+d" (rp) : "d" (1000000 >> 1)); + value->tv_usec = rp.subreg.even; + value->tv_sec = rp.subreg.odd; +#else + value->tv_usec = cputime % 1000000; + value->tv_sec = cputime / 1000000; +#endif +} + +/* + * Convert cputime to clock and back. + */ +static inline clock_t +cputime_to_clock_t(cputime_t cputime) +{ + return __div(cputime, 1000000 / USER_HZ); +} + +static inline cputime_t +clock_t_to_cputime(unsigned long x) +{ + return (cputime_t) x * (1000000 / USER_HZ); +} + +/* + * Convert cputime64 to clock. + */ +static inline clock_t +cputime64_to_clock_t(cputime64_t cputime) +{ + return __div(cputime, 1000000 / USER_HZ); +} + +#endif /* _S390_CPUTIME_H */ diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h index 1580b7b2b05e..53e59b4760c5 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h @@ -16,6 +16,7 @@ #include #include #include +#include #include /* irq_cpustat_t is unused currently, but could be converted diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index 0aa1c0f1e705..df5172fc589d 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h @@ -56,13 +56,18 @@ #define __LC_RETURN_PSW 0x200 -#define __LC_IRB 0x210 - -#define __LC_DIAG44_OPCODE 0x250 - #define __LC_SAVE_AREA 0xC00 #ifndef __s390x__ +#define __LC_IRB 0x208 +#define __LC_SYNC_ENTER_TIMER 0x248 +#define __LC_ASYNC_ENTER_TIMER 0x250 +#define __LC_EXIT_TIMER 0x258 +#define __LC_LAST_UPDATE_TIMER 0x260 +#define __LC_USER_TIMER 0x268 +#define __LC_SYSTEM_TIMER 0x270 +#define __LC_LAST_UPDATE_CLOCK 0x278 +#define __LC_STEAL_CLOCK 0x280 #define __LC_KERNEL_STACK 0xC40 #define __LC_THREAD_INFO 0xC44 #define __LC_ASYNC_STACK 0xC48 @@ -76,6 +81,16 @@ #define __LC_CURRENT 0xC90 #define __LC_INT_CLOCK 0xC98 #else /* __s390x__ */ +#define __LC_IRB 0x210 +#define __LC_SYNC_ENTER_TIMER 0x250 +#define __LC_ASYNC_ENTER_TIMER 0x258 +#define __LC_EXIT_TIMER 0x260 +#define __LC_LAST_UPDATE_TIMER 0x268 +#define __LC_USER_TIMER 0x270 +#define __LC_SYSTEM_TIMER 0x278 +#define __LC_LAST_UPDATE_CLOCK 0x280 +#define __LC_STEAL_CLOCK 0x288 +#define __LC_DIAG44_OPCODE 0x290 #define __LC_KERNEL_STACK 0xD40 #define __LC_THREAD_INFO 0xD48 #define __LC_ASYNC_STACK 0xD50 @@ -87,7 +102,7 @@ #define __LC_IPLDEV 0xDB8 #define __LC_JIFFY_TIMER 0xDC0 #define __LC_CURRENT 0xDD8 -#define __LC_INT_CLOCK 0xDe8 +#define __LC_INT_CLOCK 0xDE8 #endif /* __s390x__ */ #define __LC_PANIC_MAGIC 0xE00 @@ -169,7 +184,15 @@ struct _lowcore psw_t return_psw; /* 0x200 */ __u8 irb[64]; /* 0x208 */ - __u8 pad8[0xc00-0x248]; /* 0x248 */ + __u64 sync_enter_timer; /* 0x248 */ + __u64 async_enter_timer; /* 0x250 */ + __u64 exit_timer; /* 0x258 */ + __u64 last_update_timer; /* 0x260 */ + __u64 user_timer; /* 0x268 */ + __u64 system_timer; /* 0x270 */ + __u64 last_update_clock; /* 0x278 */ + __u64 steal_clock; /* 0x280 */ + __u8 pad8[0xc00-0x288]; /* 0x288 */ /* System info area */ __u32 save_area[16]; /* 0xc00 */ @@ -250,8 +273,16 @@ struct _lowcore psw_t io_new_psw; /* 0x1f0 */ psw_t return_psw; /* 0x200 */ __u8 irb[64]; /* 0x210 */ - __u32 diag44_opcode; /* 0x250 */ - __u8 pad8[0xc00-0x254]; /* 0x254 */ + __u64 sync_enter_timer; /* 0x250 */ + __u64 async_enter_timer; /* 0x258 */ + __u64 exit_timer; /* 0x260 */ + __u64 last_update_timer; /* 0x268 */ + __u64 user_timer; /* 0x270 */ + __u64 system_timer; /* 0x278 */ + __u64 last_update_clock; /* 0x280 */ + __u64 steal_clock; /* 0x288 */ + __u32 diag44_opcode; /* 0x290 */ + __u8 pad8[0xc00-0x294]; /* 0x294 */ /* System info area */ __u64 save_area[16]; /* 0xc00 */ __u8 pad9[0xd40-0xc80]; /* 0xc80 */ diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index d9f3498136e1..e8596077e057 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -105,11 +105,29 @@ static inline void restore_access_regs(unsigned int *acrs) #define prepare_arch_switch(rq, next) do { } while(0) #define task_running(rq, p) ((rq)->curr == (p)) + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +extern void account_user_vtime(struct task_struct *); +extern void account_system_vtime(struct task_struct *); + +#define finish_arch_switch(rq, prev) do { \ + set_fs(current->thread.mm_segment); \ + spin_unlock(&(rq)->lock); \ + account_system_vtime(prev); \ + local_irq_enable(); \ +} while (0) + +#else + +#define account_system_vtime(prev) + #define finish_arch_switch(rq, prev) do { \ set_fs(current->thread.mm_segment); \ spin_unlock_irq(&(rq)->lock); \ } while (0) +#endif + #define nop() __asm__ __volatile__ ("nop") #define xchg(ptr,x) \ diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h index 454d1ea85c54..ea0788967c51 100644 --- a/include/asm-s390/timer.h +++ b/include/asm-s390/timer.h @@ -37,8 +37,6 @@ struct vtimer_queue { __u64 idle; /* temp var for idle */ }; -void set_vtimer(__u64 expires); - extern void init_virt_timer(struct vtimer_list *timer); extern void add_virt_timer(void *new); extern void add_virt_timer_periodic(void *new); diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index ba0fcb34c8cd..ebc712e91066 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * We put the hardirq and softirq counter into the preemption @@ -84,7 +85,22 @@ extern void synchronize_irq(unsigned int irq); #define nmi_enter() irq_enter() #define nmi_exit() sub_preempt_count(HARDIRQ_OFFSET) -#define irq_enter() add_preempt_count(HARDIRQ_OFFSET) +#ifndef CONFIG_VIRT_CPU_ACCOUNTING +static inline void account_user_vtime(struct task_struct *tsk) +{ +} + +static inline void account_system_vtime(struct task_struct *tsk) +{ +} +#endif + +#define irq_enter() \ + do { \ + account_system_vtime(current); \ + add_preempt_count(HARDIRQ_OFFSET); \ + } while (0) + extern void irq_exit(void); #endif /* LINUX_HARDIRQ_H */ diff --git a/kernel/softirq.c b/kernel/softirq.c index 9e2d204da364..582a1e8091bc 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -163,6 +163,7 @@ EXPORT_SYMBOL(local_bh_enable); */ void irq_exit(void) { + account_system_vtime(current); sub_preempt_count(IRQ_EXIT_OFFSET); if (!in_interrupt() && local_softirq_pending()) invoke_softirq(); -- cgit v1.2.3 From a1996f881869fc68b2ff8d164190cb258831aca5 Mon Sep 17 00:00:00 2001 From: Zwane Mwaikambo Date: Tue, 11 Jan 2005 01:42:00 -0800 Subject: [PATCH] ppc64: Move hotplug cpu functions to smp_ops This should allow for easier adding of hotplug cpu support for other PPC64 subarchs. The patch is untested but does compile with and without hotplug cpu on pSeries and G5 configs. What can get slightly confusing is the fact that both ppc_md and smp_ops have cpu_die members. Signed-off-by: Zwane Mwaikambo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/pSeries_smp.c | 9 +++++++-- arch/ppc64/kernel/smp.c | 16 ++++++++++++++++ include/asm-ppc64/machdep.h | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index d03c47164001..12da1cdf854e 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c @@ -87,7 +87,7 @@ static int query_cpu_stopped(unsigned int pcpu) #ifdef CONFIG_HOTPLUG_CPU -int __cpu_disable(void) +int pSeries_cpu_disable(void) { /* FIXME: go put this in a header somewhere */ extern void xics_migrate_irqs_away(void); @@ -103,7 +103,7 @@ int __cpu_disable(void) return 0; } -void __cpu_die(unsigned int cpu) +void pSeries_cpu_die(unsigned int cpu) { int tries; int cpu_status; @@ -352,6 +352,11 @@ void __init smp_init_pSeries(void) else smp_ops = &pSeries_xics_smp_ops; +#ifdef CONFIG_HOTPLUG_CPU + smp_ops->cpu_disable = pSeries_cpu_disable; + smp_ops->cpu_die = pSeries_cpu_die; +#endif + /* Start secondary threads on SMT systems; primary threads * are already in the running state. */ diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index db78b2f03884..808bb3d906c6 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -551,3 +551,19 @@ void __init smp_cpus_done(unsigned int max_cpus) */ cpu_present_map = cpu_possible_map; } + +#ifdef CONFIG_HOTPLUG_CPU +int __cpu_disable(void) +{ + if (smp_ops->cpu_disable) + return smp_ops->cpu_disable(); + + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ + if (smp_ops->cpu_die) + smp_ops->cpu_die(cpu); +} +#endif diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h index ae1c4fd4a7cf..a21a944d326f 100644 --- a/include/asm-ppc64/machdep.h +++ b/include/asm-ppc64/machdep.h @@ -31,6 +31,8 @@ struct smp_ops_t { void (*late_setup_cpu)(int nr); void (*take_timebase)(void); void (*give_timebase)(void); + int (*cpu_disable)(void); + void (*cpu_die)(unsigned int nr); }; #endif -- cgit v1.2.3 From 9aaf64a0f7cfd94cac1d0be99d2943e1302c0608 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 11 Jan 2005 01:43:28 -0800 Subject: [PATCH] ppc64: make xmon print BUG() warnings I've had to explain to a number of people that a 0x700 exception is often a BUG(). Make this crystal clear by printing the BUG information in the xmon exception printout. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/traps.c | 4 ++-- arch/ppc64/xmon/xmon.c | 24 ++++++++++++++++++++++++ include/asm-ppc64/bug.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c index c37af43a7a62..418aff49933e 100644 --- a/arch/ppc64/kernel/traps.c +++ b/arch/ppc64/kernel/traps.c @@ -344,7 +344,7 @@ extern struct bug_entry __start___bug_table[], __stop___bug_table[]; #define module_find_bug(x) NULL #endif -static struct bug_entry *find_bug(unsigned long bugaddr) +struct bug_entry *find_bug(unsigned long bugaddr) { struct bug_entry *bug; @@ -354,7 +354,7 @@ static struct bug_entry *find_bug(unsigned long bugaddr) return module_find_bug(bugaddr); } -int +static int check_bug_trap(struct pt_regs *regs) { struct bug_entry *bug; diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c index c53046d52e6c..2be270592fb3 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/ppc64/xmon/xmon.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "nonstdio.h" #include "privinst.h" @@ -1319,6 +1320,26 @@ static void backtrace(struct pt_regs *excp) scannl(); } +static void print_bug_trap(struct pt_regs *regs) +{ + struct bug_entry *bug; + unsigned long addr; + + if (regs->msr & MSR_PR) + return; /* not in kernel */ + addr = regs->nip; /* address of trap instruction */ + if (addr < PAGE_OFFSET) + return; + bug = find_bug(regs->nip); + if (bug == NULL) + return; + if (bug->line & BUG_WARNING_TRAP) + return; + + printf("kernel BUG in %s at %s:%d!\n", + bug->function, bug->file, (unsigned int)bug->line); +} + void excprint(struct pt_regs *fp) { unsigned long trap; @@ -1350,6 +1371,9 @@ void excprint(struct pt_regs *fp) printf(" pid = %ld, comm = %s\n", current->pid, current->comm); } + + if (trap == 0x700) + print_bug_trap(fp); } void prregs(struct pt_regs *fp) diff --git a/include/asm-ppc64/bug.h b/include/asm-ppc64/bug.h index 790bc56091d6..db31dd22233c 100644 --- a/include/asm-ppc64/bug.h +++ b/include/asm-ppc64/bug.h @@ -18,6 +18,8 @@ struct bug_entry { const char *function; }; +struct bug_entry *find_bug(unsigned long bugaddr); + /* * If this bit is set in the line number it means that the trap * is for WARN_ON rather than BUG or BUG_ON. -- cgit v1.2.3 From 0ca63a2ac3a68acd98b2af1bf1972a61bfcfa63f Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 11 Jan 2005 01:43:55 -0800 Subject: [PATCH] ppc64: PCI cleanup - remove pci_fix_bus_sysdata. We required it for the old pci dma subsystem, but now it is useless. - remove PCI_GET_PHB_PTR and use pci_bus_to_host instead - remove pci_find_hose_for_OF_device - remove some unused fields in struct pci_controller - remove pci_device_loc stale prototype - remove an old mask of pci bus number that was left around from the pre PCI domains days Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/maple_pci.c | 3 --- arch/ppc64/kernel/pSeries_pci.c | 1 - arch/ppc64/kernel/pci.c | 33 ++++++++------------------------- arch/ppc64/kernel/pci.h | 4 ---- arch/ppc64/kernel/pci_dn.c | 33 --------------------------------- arch/ppc64/kernel/pmac_pci.c | 2 -- include/asm-ppc64/pci-bridge.h | 23 +++-------------------- 7 files changed, 11 insertions(+), 88 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c index f8cd5b495d6b..53993999b265 100644 --- a/arch/ppc64/kernel/maple_pci.c +++ b/arch/ppc64/kernel/maple_pci.c @@ -382,9 +382,6 @@ void __init maple_pcibios_fixup(void) /* Do the mapping of the IO space */ phbs_remap_io(); - /* Fixup the pci_bus sysdata pointers */ - pci_fix_bus_sysdata(); - DBG(" <- maple_pcibios_fixup\n"); } diff --git a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c index 2b9a00951f20..8953e94889ba 100644 --- a/arch/ppc64/kernel/pSeries_pci.c +++ b/arch/ppc64/kernel/pSeries_pci.c @@ -552,7 +552,6 @@ void __init pSeries_final_fixup(void) phbs_remap_io(); pSeries_request_regions(); - pci_fix_bus_sysdata(); pci_addr_cache_build(); } diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 25822272542e..a7bf62655601 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -91,7 +91,7 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region struct resource *res) { unsigned long offset = 0; - struct pci_controller *hose = PCI_GET_PHB_PTR(dev); + struct pci_controller *hose = pci_bus_to_host(dev->bus); if (!hose) return; @@ -127,7 +127,7 @@ void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align) { struct pci_dev *dev = data; - struct pci_controller *hose = PCI_GET_PHB_PTR(dev); + struct pci_controller *hose = pci_bus_to_host(dev->bus); unsigned long start = res->start; unsigned long alignto; @@ -292,7 +292,7 @@ int pci_domain_nr(struct pci_bus *bus) #ifdef CONFIG_PPC_ISERIES return 0; #else - struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + struct pci_controller *hose = pci_bus_to_host(bus); return hose->global_number; #endif @@ -304,7 +304,7 @@ EXPORT_SYMBOL(pci_domain_nr); int pci_name_bus(char *name, struct pci_bus *bus) { #ifndef CONFIG_PPC_ISERIES - struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + struct pci_controller *hose = pci_bus_to_host(bus); if (hose->buid) sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number); @@ -336,7 +336,7 @@ static __inline__ int __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state) { - struct pci_controller *hose = PCI_GET_PHB_PTR(dev); + struct pci_controller *hose = pci_bus_to_host(dev->bus); unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long io_offset = 0; int i, res_bit; @@ -643,7 +643,7 @@ void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose) static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys, unsigned long *start_virt, unsigned long *size) { - struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + struct pci_controller *hose = pci_bus_to_host(bus); struct pci_bus_region region; struct resource *res; @@ -728,23 +728,6 @@ void phbs_remap_io(void) remap_bus_range(hose->bus); } - -/* - * This function finds the PHB that matching device_node in the - * OpenFirmware by scanning all the pci_controllers. - */ -struct pci_controller* pci_find_hose_for_OF_device(struct device_node *node) -{ - while (node) { - struct pci_controller *hose, *tmp; - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) - if (hose->arch_data == node) - return hose; - node=node->parent; - } - return NULL; -} - /* * ppc64 can have multifunction devices that do not respond to function 0. * In this case we must scan all functions. @@ -778,7 +761,7 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus) { /* Update device resources. */ - struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + struct pci_controller *hose = pci_bus_to_host(bus); int i; for (i = 0; i < PCI_NUM_RESOURCES; i++) { @@ -814,7 +797,7 @@ EXPORT_SYMBOL(pcibios_fixup_device_resources); void __devinit pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + struct pci_controller *hose = pci_bus_to_host(bus); struct pci_dev *dev = bus->self; struct resource *res; int i; diff --git a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h index 2ed6b674bbca..28517c14015b 100644 --- a/arch/ppc64/kernel/pci.h +++ b/arch/ppc64/kernel/pci.h @@ -17,7 +17,6 @@ extern unsigned long isa_io_base; extern void pci_setup_pci_controller(struct pci_controller *hose); extern void pci_setup_phb_io(struct pci_controller *hose, int primary); -extern struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node); extern void pci_setup_phb_io_dynamic(struct pci_controller *hose); @@ -36,11 +35,8 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre, void pci_devs_phb_init(void); void pci_devs_phb_init_dynamic(struct pci_controller *phb); -void pci_fix_bus_sysdata(void); struct device_node *fetch_dev_dn(struct pci_dev *dev); -#define PCI_GET_PHB_PTR(dev) (((struct device_node *)(dev)->sysdata)->phb) - /* PCI address cache management routines */ void pci_addr_cache_insert_device(struct pci_dev *dev); void pci_addr_cache_remove_device(struct pci_dev *dev); diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c index 962394708ece..280b744fe64e 100644 --- a/arch/ppc64/kernel/pci_dn.c +++ b/arch/ppc64/kernel/pci_dn.c @@ -21,19 +21,12 @@ */ #include #include -#include #include #include -#include #include -#include -#include #include -#include #include -#include -#include #include "pci.h" @@ -178,29 +171,3 @@ void __init pci_devs_phb_init(void) list_for_each_entry_safe(phb, tmp, &hose_list, list_node) pci_devs_phb_init_dynamic(phb); } - - -static void __init pci_fixup_bus_sysdata_list(struct list_head *bus_list) -{ - struct pci_bus *bus; - - list_for_each_entry(bus, bus_list, node) { - if (bus->self) - bus->sysdata = bus->self->sysdata; - pci_fixup_bus_sysdata_list(&bus->children); - } -} - -/* - * Fixup the bus->sysdata ptrs to point to the bus' device_node. - * This is done late in pcibios_init(). We do this mostly for - * sanity, but pci_dma.c uses these at DMA time so they must be - * correct. - * To do this we recurse down the bus hierarchy. Note that PHB's - * have bus->self == NULL, but fortunately bus->sysdata is already - * correct in this case. - */ -void __init pci_fix_bus_sysdata(void) -{ - pci_fixup_bus_sysdata_list(&pci_root_buses); -} diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c index 32634216ad78..00a831df6d9f 100644 --- a/arch/ppc64/kernel/pmac_pci.c +++ b/arch/ppc64/kernel/pmac_pci.c @@ -664,8 +664,6 @@ void __init pmac_pcibios_fixup(void) for_each_pci_dev(dev) pci_read_irq_line(dev); - - pci_fix_bus_sysdata(); } static void __init pmac_fixup_phb_resources(void) diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 51cfa8b72812..c4f9023ea5ed 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -11,18 +11,10 @@ * 2 of the License, or (at your option) any later version. */ -struct device_node; -struct pci_controller; - -/* Get the PCI host controller for an OF device */ -extern struct pci_controller* -pci_find_hose_for_OF_device(struct device_node* node); - /* * Structure of a PCI controller (host bridge) */ struct pci_controller { - char what[8]; /* Eye catcher */ struct pci_bus *bus; char is_dynamic; void *arch_data; @@ -49,7 +41,6 @@ struct pci_controller { */ struct resource io_resource; struct resource mem_resources[3]; - int mem_resource_count; int global_number; int local_number; unsigned long buid; @@ -57,14 +48,6 @@ struct pci_controller { unsigned long dma_window_size; }; -/* - * pci_device_loc returns the bus number and device/function number - * for a device on a PCI bus, given its device_node struct. - * It returns 0 if OK, -1 on error. - */ -extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, - unsigned char *devfn_ptr); - struct device_node *fetch_dev_dn(struct pci_dev *dev); /* Get a device_node from a pci_dev. This code must be fast except in the case @@ -72,8 +55,9 @@ struct device_node *fetch_dev_dn(struct pci_dev *dev); */ static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev) { - struct device_node *dn = (struct device_node *)(dev->sysdata); - if (dn->devfn == dev->devfn && dn->busno == (dev->bus->number&0xff)) + struct device_node *dn = dev->sysdata; + + if (dn->devfn == dev->devfn && dn->busno == dev->bus->number) return dn; /* fast path. sysdata is good */ else return fetch_dev_dn(dev); @@ -102,6 +86,5 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus) return busdn->phb; } - #endif #endif /* __KERNEL__ */ -- cgit v1.2.3 From f52cf14bfd2b0e6cff9aba14dbafb96547fbeb7c Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 11 Jan 2005 01:44:09 -0800 Subject: [PATCH] ppc64: Remove flush_instruction_cache Remove flush_instruction_cache, we cant touch HID bits on LPAR machines. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/misc.S | 20 -------------------- arch/ppc64/kernel/ppc_ksyms.c | 1 - include/asm-ppc64/system.h | 1 - 3 files changed, 22 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index a795ae320b37..1502b814a558 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -167,27 +167,7 @@ _GLOBAL(call_with_mmu_off) xori r0,r0,MSR_IR|MSR_DR mtspr SPRN_SRR1,r0 rfid - -/* - * Flush instruction cache. - */ -_GLOBAL(flush_instruction_cache) -/* - * This is called by kgdb code - * and should probably go away - * to be replaced by invalidating - * the cache lines that are actually - * modified - */ - /* use invalidate-all bit in HID0 - * - is this consistent across all 64-bit cpus? -- paulus */ - mfspr r3,HID0 - ori r3,r3,HID0_ICFI - mtspr HID0,r3 - sync - isync - blr .section ".toc","aw" PPC64_CACHES: diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c index 7efdaabf5b7b..38c0398d823c 100644 --- a/arch/ppc64/kernel/ppc_ksyms.c +++ b/arch/ppc64/kernel/ppc_ksyms.c @@ -114,7 +114,6 @@ EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(flush_instruction_cache); EXPORT_SYMBOL(giveup_fpu); #ifdef CONFIG_ALTIVEC EXPORT_SYMBOL(giveup_altivec); diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index dc3153fa414e..6785e69e8b9e 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -108,7 +108,6 @@ extern void show_regs(struct pt_regs * regs); extern void low_hash_fault(struct pt_regs *regs, unsigned long address); extern int die(const char *str, struct pt_regs *regs, long err); -extern void flush_instruction_cache(void); extern int _get_PVR(void); extern void giveup_fpu(struct task_struct *); extern void disable_kernel_fp(void); -- cgit v1.2.3 From d00da3f86a633fa1a767a406e52aa3201717f33a Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 11 Jan 2005 01:44:23 -0800 Subject: [PATCH] ppc64: interrupt code cleanup - Move some function prototypes into header files. - Remove late_setup_cpu, put the set indicator and vpa init into xics probe instead - rtas-proc was doing weird stuff with the 9005 indicator. Get rid of it. - Dont open code the set_indicator call in the hotplug code Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/pSeries_smp.c | 46 ++++++++++++----------------------------- arch/ppc64/kernel/rtas-proc.c | 12 ----------- arch/ppc64/kernel/smp.c | 12 ----------- arch/ppc64/kernel/xics.c | 10 +++------ include/asm-ppc64/machdep.h | 1 - include/asm-ppc64/rtas.h | 2 ++ include/asm-ppc64/xics.h | 4 ++++ 7 files changed, 22 insertions(+), 65 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index 12da1cdf854e..da4b63fbb7ae 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c @@ -19,9 +19,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -40,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -89,9 +86,6 @@ static int query_cpu_stopped(unsigned int pcpu) int pSeries_cpu_disable(void) { - /* FIXME: go put this in a header somewhere */ - extern void xics_migrate_irqs_away(void); - systemcfg->processorCount--; /*fix boot_cpuid here*/ @@ -250,8 +244,6 @@ static void smp_xics_message_pass(int target, int msg) } } -extern void xics_request_IPIs(void); - static int __init smp_xics_probe(void) { xics_request_IPIs(); @@ -263,6 +255,18 @@ static void __devinit smp_xics_setup_cpu(int cpu) { if (cpu != boot_cpuid) xics_setup_cpu(); + + if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) + vpa_init(cpu); + +#ifdef CONFIG_IRQ_ALL_CPUS + /* + * Put the calling processor into the GIQ. This is really only + * necessary from a secondary thread as the OF start-cpu interface + * performs this function for us on primary threads. + */ + rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, default_distrib_server, 1); +#endif } static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED; @@ -290,26 +294,7 @@ static void __devinit pSeries_take_timebase(void) spin_unlock(&timebase_lock); } -static void __devinit pSeries_late_setup_cpu(int cpu) -{ - extern unsigned int default_distrib_server; - - if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { - vpa_init(cpu); - } - -#ifdef CONFIG_IRQ_ALL_CPUS - /* Put the calling processor into the GIQ. This is really only - * necessary from a secondary thread as the OF start-cpu interface - * performs this function for us on primary threads. - */ - /* TODO: 9005 is #defined in rtas-proc.c -- move to a header */ - rtas_set_indicator(9005, default_distrib_server, 1); -#endif -} - - -void __devinit smp_pSeries_kick_cpu(int nr) +static void __devinit smp_pSeries_kick_cpu(int nr) { BUG_ON(nr < 0 || nr >= NR_CPUS); @@ -329,7 +314,6 @@ static struct smp_ops_t pSeries_mpic_smp_ops = { .probe = smp_mpic_probe, .kick_cpu = smp_pSeries_kick_cpu, .setup_cpu = smp_mpic_setup_cpu, - .late_setup_cpu = pSeries_late_setup_cpu, }; static struct smp_ops_t pSeries_xics_smp_ops = { @@ -337,7 +321,6 @@ static struct smp_ops_t pSeries_xics_smp_ops = { .probe = smp_xics_probe, .kick_cpu = smp_pSeries_kick_cpu, .setup_cpu = smp_xics_setup_cpu, - .late_setup_cpu = pSeries_late_setup_cpu, }; /* This is called very early */ @@ -372,9 +355,6 @@ void __init smp_init_pSeries(void) } } - if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) - vpa_init(boot_cpuid); - /* Non-lpar has additional take/give timebase */ if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) { smp_ops->give_timebase = pSeries_give_timebase; diff --git a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c index ed07210b9917..28b1f1521f21 100644 --- a/arch/ppc64/kernel/rtas-proc.c +++ b/arch/ppc64/kernel/rtas-proc.c @@ -52,7 +52,6 @@ #define IBM_VOLTAGE 0x232a /* 9002 */ #define IBM_DRCONNECTOR 0x232b /* 9003 */ #define IBM_POWERSUPPLY 0x232c /* 9004 */ -#define IBM_INTQUEUE 0x232d /* 9005 */ /* Status return values */ #define SENSOR_CRITICAL_HIGH 13 @@ -107,7 +106,6 @@ #define DR_ACTION 0x2329 /* 9001 */ #define DR_INDICATOR 0x232a /* 9002 */ /* 9003 - 9004: Vendor specific */ -#define GLOBAL_INTERRUPT_QUEUE 0x232d /* 9005 */ /* 9006 - 9999: Vendor specific */ /* other */ @@ -553,7 +551,6 @@ static void ppc_rtas_process_sensor(struct seq_file *m, "No current flow" }; const char * ibm_drconnector[] = { "Empty", "Present", "Unusable", "Exchange" }; - const char * ibm_intqueue[] = { "Disabled", "Enabled" }; int have_strings = 0; int num_states = 0; @@ -665,15 +662,6 @@ static void ppc_rtas_process_sensor(struct seq_file *m, case IBM_POWERSUPPLY: seq_printf(m, "Powersupply:\t"); break; - case IBM_INTQUEUE: - seq_printf(m, "Interrupt queue:\t"); - num_states = sizeof(ibm_intqueue) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - ibm_intqueue[state]); - have_strings = 1; - } - break; default: seq_printf(m, "Unknown sensor (type %d), ignoring it\n", s->token); diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 808bb3d906c6..f5b4a8f29581 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -38,12 +36,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -58,7 +54,6 @@ #endif int smp_threads_ready; -unsigned long cache_decay_ticks; cpumask_t cpu_possible_map = CPU_MASK_NONE; cpumask_t cpu_online_map = CPU_MASK_NONE; @@ -77,10 +72,6 @@ void smp_call_function_interrupt(void); int smt_enabled_at_boot = 1; -/* Low level assembly function used to backup CPU 0 state */ -extern void __save_cpu_setup(void); - - #ifdef CONFIG_PPC_MULTIPLATFORM void smp_mpic_message_pass(int target, int msg) { @@ -507,9 +498,6 @@ int __devinit start_secondary(void *unused) if (smp_ops->take_timebase) smp_ops->take_timebase(); - if (smp_ops->late_setup_cpu) - smp_ops->late_setup_cpu(cpu); - spin_lock(&call_lock); cpu_set(cpu, cpu_online_map); spin_unlock(&call_lock); diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c index b9fdcc60d6e8..dd88142ebf39 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/ppc64/kernel/xics.c @@ -643,20 +643,16 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) /* Interrupts are disabled. */ void xics_migrate_irqs_away(void) { - int set_indicator = rtas_token("set-indicator"); - const unsigned int giqs = 9005UL; /* Global Interrupt Queue Server */ - int status = 0; + int status; unsigned int irq, virq, cpu = smp_processor_id(); - BUG_ON(set_indicator == RTAS_UNKNOWN_SERVICE); - /* Reject any interrupt that was queued to us... */ ops->cppr_info(cpu, 0); iosync(); /* Refuse any new interrupts... */ - rtas_call(set_indicator, 3, 1, &status, giqs, - hard_smp_processor_id(), 0); + status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, + hard_smp_processor_id(), 0); WARN_ON(status != 0); /* Allow IPIs again... */ diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h index a21a944d326f..476d2185ffd1 100644 --- a/include/asm-ppc64/machdep.h +++ b/include/asm-ppc64/machdep.h @@ -28,7 +28,6 @@ struct smp_ops_t { int (*probe)(void); void (*kick_cpu)(int nr); void (*setup_cpu)(int nr); - void (*late_setup_cpu)(int nr); void (*take_timebase)(void); void (*give_timebase)(void); int (*cpu_disable)(void); diff --git a/include/asm-ppc64/rtas.h b/include/asm-ppc64/rtas.h index a405a871919e..dc2879cc4981 100644 --- a/include/asm-ppc64/rtas.h +++ b/include/asm-ppc64/rtas.h @@ -241,4 +241,6 @@ extern void rtas_stop_self(void); /* RMO buffer reserved for user-space RTAS use */ extern unsigned long rtas_rmo_buf; +#define GLOBAL_INTERRUPT_QUEUE 9005 + #endif /* _PPC64_RTAS_H */ diff --git a/include/asm-ppc64/xics.h b/include/asm-ppc64/xics.h index 560f4fd99e21..6b9aedc6eadb 100644 --- a/include/asm-ppc64/xics.h +++ b/include/asm-ppc64/xics.h @@ -18,6 +18,8 @@ void xics_init_IRQ(void); int xics_get_irq(struct pt_regs *); void xics_setup_cpu(void); void xics_cause_IPI(int cpu); +void xics_request_IPIs(void); +void xics_migrate_irqs_away(void); /* first argument is ignored for now*/ void pSeriesLP_cppr_info(int n_cpu, u8 value); @@ -28,4 +30,6 @@ struct xics_ipi_struct { extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; +extern unsigned int default_distrib_server; + #endif /* _PPC64_KERNEL_XICS_H */ -- cgit v1.2.3 From 3d311cb2e0c88fa555aff6ce67635028241b7440 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 11 Jan 2005 01:44:36 -0800 Subject: [PATCH] ppc64: Fix rtas_set_indicator(9005) It turns out we were passing in the wrong thing to the rtas_set_indicator call. Luckily we got away with it because it looks like firmware does not check arguments and just inserts or removes the current cpu from the global server group. Fix it. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/pSeries_smp.c | 3 ++- arch/ppc64/kernel/xics.c | 9 +++++++-- include/asm-ppc64/xics.h | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index da4b63fbb7ae..f8f2007b8885 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c @@ -265,7 +265,8 @@ static void __devinit smp_xics_setup_cpu(int cpu) * necessary from a secondary thread as the OF start-cpu interface * performs this function for us on primary threads. */ - rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, default_distrib_server, 1); + rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, + (1UL << interrupt_server_size) - 1 - default_distrib_server, 1); #endif } diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c index dd88142ebf39..eca025abe098 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/ppc64/kernel/xics.c @@ -91,6 +91,7 @@ static int xics_irq_8259_cascade_real = 0; static unsigned int default_server = 0xFF; /* also referenced in smp.c... */ unsigned int default_distrib_server = 0; +unsigned int interrupt_server_size = 8; /* * XICS only has a single IPI, so encode the messages per CPU @@ -511,6 +512,10 @@ nextnode: default_server = ireg[0]; default_distrib_server = ireg[i-1]; /* take last element */ } + ireg = (uint *)get_property(np, + "ibm,interrupt-server#-size", NULL); + if (ireg) + interrupt_server_size = *ireg; break; } } @@ -650,9 +655,9 @@ void xics_migrate_irqs_away(void) ops->cppr_info(cpu, 0); iosync(); - /* Refuse any new interrupts... */ + /* remove ourselves from the global interrupt queue */ status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, - hard_smp_processor_id(), 0); + (1UL << interrupt_server_size) - 1 - default_distrib_server, 0); WARN_ON(status != 0); /* Allow IPIs again... */ diff --git a/include/asm-ppc64/xics.h b/include/asm-ppc64/xics.h index 6b9aedc6eadb..0027da4364ac 100644 --- a/include/asm-ppc64/xics.h +++ b/include/asm-ppc64/xics.h @@ -31,5 +31,6 @@ struct xics_ipi_struct { extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; extern unsigned int default_distrib_server; +extern unsigned int interrupt_server_size; #endif /* _PPC64_KERNEL_XICS_H */ -- cgit v1.2.3 From a46596def4cc4beb3f850dee0f2643fa3cc88ce0 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:47:21 -0800 Subject: [PATCH] x86_64: Fix sparse warnings Fix sparse warnings warning: cast removes address space of expression for uses of put_user() on x86_64 caused by doing __m(addr) in __put_user_asm() with addr a __user pointer. Signed-off-by: Roland Dreier Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-x86_64/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h index 406102dbf298..926e614e60d6 100644 --- a/include/asm-x86_64/uaccess.h +++ b/include/asm-x86_64/uaccess.h @@ -172,7 +172,7 @@ do { \ /* FIXME: this hack is definitely wrong -AK */ struct __large_struct { unsigned long buf[100]; }; -#define __m(x) (*(struct __large_struct *)(x)) +#define __m(x) (*(struct __large_struct __user *)(x)) /* * Tell gcc we read from memory instead of writing: this is because -- cgit v1.2.3 From 6d925f6d2b0c955ee1185f9923b5aa2f02a3d7fd Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:47:35 -0800 Subject: [PATCH] x86_64: Fix some gcc 4 warnings in arch/x86_64 Fix some gcc 4 warnings in arch/x86_64 There are tons more outside though. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/head64.c | 13 +++++++------ arch/x86_64/kernel/setup.c | 8 ++++---- arch/x86_64/kernel/signal.c | 2 +- include/asm-x86_64/msr.h | 3 ++- include/asm-x86_64/unistd.h | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c index 5254e90a8113..6cad46c98a23 100644 --- a/arch/x86_64/kernel/head64.c +++ b/arch/x86_64/kernel/head64.c @@ -61,16 +61,17 @@ static void __init copy_bootdata(char *real_mode_data) static void __init setup_boot_cpu_data(void) { - int dummy, eax; + unsigned int dummy, eax; /* get vendor info */ - cpuid(0, &boot_cpu_data.cpuid_level, - (int *)&boot_cpu_data.x86_vendor_id[0], - (int *)&boot_cpu_data.x86_vendor_id[8], - (int *)&boot_cpu_data.x86_vendor_id[4]); + cpuid(0, (unsigned int *)&boot_cpu_data.cpuid_level, + (unsigned int *)&boot_cpu_data.x86_vendor_id[0], + (unsigned int *)&boot_cpu_data.x86_vendor_id[8], + (unsigned int *)&boot_cpu_data.x86_vendor_id[4]); /* get cpu type */ - cpuid(1, &eax, &dummy, &dummy, (int *) &boot_cpu_data.x86_capability); + cpuid(1, &eax, &dummy, &dummy, + (unsigned int *) &boot_cpu_data.x86_capability); boot_cpu_data.x86 = (eax >> 8) & 0xf; boot_cpu_data.x86_model = (eax >> 4) & 0xf; boot_cpu_data.x86_mask = eax & 0xf; diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 1bf8d4e95e92..7a7be426f5af 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -849,10 +849,10 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) memset(&c->x86_capability, 0, sizeof c->x86_capability); /* Get vendor name */ - cpuid(0x00000000, &c->cpuid_level, - (int *)&c->x86_vendor_id[0], - (int *)&c->x86_vendor_id[8], - (int *)&c->x86_vendor_id[4]); + cpuid(0x00000000, (unsigned int *)&c->cpuid_level, + (unsigned int *)&c->x86_vendor_id[0], + (unsigned int *)&c->x86_vendor_id[8], + (unsigned int *)&c->x86_vendor_id[4]); get_cpu_vendor(c); diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index e9aa2ca0b55d..df01c50b7177 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -139,7 +139,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe __user *frame; sigset_t set; - long eax; + unsigned long eax; frame = (struct rt_sigframe __user *)(regs->rsp - 8); if (verify_area(VERIFY_READ, frame, sizeof(*frame))) { diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h index ed94245a5d4f..850695678419 100644 --- a/include/asm-x86_64/msr.h +++ b/include/asm-x86_64/msr.h @@ -67,7 +67,8 @@ : "=a" (low), "=d" (high) \ : "c" (counter)) -extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx) +extern inline void cpuid(int op, unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) { __asm__("cpuid" : "=a" (*eax), diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index 506ec8d12e75..f1a510a9b195 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -724,7 +724,7 @@ static inline long dup(unsigned int fd) } /* implemented in asm in arch/x86_64/kernel/entry.S */ -extern long execve(char *, char **, char **); +extern int execve(const char *, char * const *, char * const *); static inline long open(const char * filename, int flags, int mode) { -- cgit v1.2.3 From e77da0004873c55d33962075b2625e728f1568eb Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:47:47 -0800 Subject: [PATCH] i386: Port missing cpuid bits from x86-64 to i386 Port missing cpuid bits from x86-64 to i386 Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/common.c | 4 +++- arch/i386/kernel/cpu/proc.c | 10 ++++++++-- include/asm-i386/cpufeature.h | 6 +++++- 3 files changed, 16 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index aef962cac862..35f37a3d3954 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -274,8 +274,10 @@ void __init generic_identify(struct cpuinfo_x86 * c) /* AMD-defined flags: level 0x80000001 */ xlvl = cpuid_eax(0x80000000); if ( (xlvl & 0xffff0000) == 0x80000000 ) { - if ( xlvl >= 0x80000001 ) + if ( xlvl >= 0x80000001 ) { c->x86_capability[1] = cpuid_edx(0x80000001); + c->x86_capability[6] = cpuid_ecx(0x80000001); + } if ( xlvl >= 0x80000004 ) get_model_name(c); /* Default name */ } diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c index 4ba834c44ea5..8c179a948131 100644 --- a/arch/i386/kernel/cpu/proc.c +++ b/arch/i386/kernel/cpu/proc.c @@ -28,7 +28,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) "pni", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL, - NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow", + NULL, "fxsr_opt", NULL, NULL, NULL, "lm", "3dnowext", "3dnow", /* Transmeta-defined */ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL, @@ -45,7 +45,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) /* Intel-defined (#2) */ "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "est", - "tm2", NULL, "cid", NULL, NULL, NULL, "xtpr", NULL, + "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -54,6 +54,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* AMD-defined (#2) */ + "lahf_lm", "cmp_legacy", NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; struct cpuinfo_x86 *c = v; int i, n = c - cpu_data; diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h index fdbd65ca669e..e147cabd3bfe 100644 --- a/include/asm-i386/cpufeature.h +++ b/include/asm-i386/cpufeature.h @@ -9,7 +9,7 @@ #include -#define NCAPINTS 6 /* Currently we have 6 32-bit words worth of info */ +#define NCAPINTS 7 /* N 32-bit words worth of info */ /* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */ #define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */ @@ -77,6 +77,7 @@ #define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */ #define X86_FEATURE_TM2 (4*32+ 8) /* Thermal Monitor 2 */ #define X86_FEATURE_CID (4*32+10) /* Context ID */ +#define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B */ #define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ @@ -85,6 +86,9 @@ #define X86_FEATURE_XCRYPT (5*32+ 6) /* on-CPU crypto (xcrypt insn) */ #define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */ +/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */ +#define X86_FEATURE_LAHF_LM (5*32+ 0) /* LAHF/SAHF in long mode */ +#define X86_FEATURE_CMP_LEGACY (5*32+ 1) /* If yes HyperThreading not valid */ #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) #define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability) -- cgit v1.2.3 From b9662b21dd274ff9c9d1ddbc85b90f7cebf38d03 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:48:01 -0800 Subject: [PATCH] i386: AMD dual core support for i386 AMD dual core support for i386 Run HT initialization on AMD dual core CPUs on i386. They fake being HT CPUs. This patch makes the HT detection run on AMD CPUs too. I moved the HT detection code into a common file from intel.c for that. It would be actually better to run HT detection always on all CPUs but this would need a second callback afterwards to AMD code, which I avoided for now. It adds a cpuinfo->x86_num_cores field. This sets up the phys_proc_id[] array. This overloads this array with HT, but when smp_num_siblings is 1 It is currently only used for /proc/cpuinfo printing. The reason we want to behave this like SMT is that there are some license managers in user space that license according to number of physical CPUs, and when they handle HT they should handle CMP with this hack too. Another reason we need this is that the powernow k8 driver needs this information to properly manage dual core CPUs. When there are ever dual core HT CPUs this will need small changes in smpboot.c. I didn't do this for now to keep the patch simple. Then we set smp_num_siblings to 1 on these systems again to prevent the scheduler from setting up HT scheduling (which is not a very good match for dual core). This is a port of the CMP support code from x86-64 (minus the NUMA bits) Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/amd.c | 17 +++++++++++++++ arch/i386/kernel/cpu/common.c | 48 +++++++++++++++++++++++++++++++++++++++++++ arch/i386/kernel/cpu/intel.c | 43 +------------------------------------- include/asm-i386/processor.h | 3 +++ 4 files changed, 69 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c index 091b98ae93b6..ae94585d0445 100644 --- a/arch/i386/kernel/cpu/amd.c +++ b/arch/i386/kernel/cpu/amd.c @@ -188,6 +188,23 @@ static void __init init_amd(struct cpuinfo_x86 *c) } display_cacheinfo(c); + detect_ht(c); + +#ifdef CONFIG_X86_HT + /* AMD dual core looks like HT but isn't really. Hide it from the + scheduler. This works around problems with the domain scheduler. + Also probably gives slightly better scheduling and disables + SMT nice which is harmful on dual core. + TBD tune the domain scheduler for dual core. */ + if (cpu_has(c, X86_FEATURE_CMP_LEGACY)) + smp_num_siblings = 1; +#endif + + if (cpuid_eax(0x80000000) >= 0x80000008) { + c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1; + if (c->x86_num_cores & (c->x86_num_cores - 1)) + c->x86_num_cores = 1; + } } static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size) diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 35f37a3d3954..5761150d84e0 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -10,6 +10,11 @@ #include #include #include +#ifdef CONFIG_X86_LOCAL_APIC +#include +#include +#include +#endif #include "cpu.h" @@ -323,6 +328,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c) c->x86_model = c->x86_mask = 0; /* So far unknown... */ c->x86_vendor_id[0] = '\0'; /* Unset */ c->x86_model_id[0] = '\0'; /* Unset */ + c->x86_num_cores = 1; memset(&c->x86_capability, 0, sizeof c->x86_capability); if (!have_cpuid_p()) { @@ -431,6 +437,48 @@ void __init dodgy_tsc(void) cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data); } +void __init detect_ht(struct cpuinfo_x86 *c) +{ + u32 eax, ebx, ecx, edx; + int index_lsb, index_msb, tmp; + int cpu = smp_processor_id(); + + if (!cpu_has(c, X86_FEATURE_HT)) + return; + + cpuid(1, &eax, &ebx, &ecx, &edx); + smp_num_siblings = (ebx & 0xff0000) >> 16; + + if (smp_num_siblings == 1) { + printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); + } else if (smp_num_siblings > 1 ) { + index_lsb = 0; + index_msb = 31; + + if (smp_num_siblings > NR_CPUS) { + printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings); + smp_num_siblings = 1; + return; + } + tmp = smp_num_siblings; + while ((tmp & 1) == 0) { + tmp >>=1 ; + index_lsb++; + } + tmp = smp_num_siblings; + while ((tmp & 0x80000000 ) == 0) { + tmp <<=1 ; + index_msb--; + } + if (index_lsb != index_msb ) + index_msb++; + phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb); + + printk(KERN_INFO "CPU: Physical Processor ID: %d\n", + phys_proc_id[cpu]); + } +} + void __init print_cpu_info(struct cpuinfo_x86 *c) { char *vendor = NULL; diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c index eb145ed88d6a..ec3858cf4c5a 100644 --- a/arch/i386/kernel/cpu/intel.c +++ b/arch/i386/kernel/cpu/intel.c @@ -140,48 +140,7 @@ static void __init init_intel(struct cpuinfo_x86 *c) strcpy(c->x86_model_id, p); #ifdef CONFIG_X86_HT - if (cpu_has(c, X86_FEATURE_HT)) { - extern int phys_proc_id[NR_CPUS]; - - u32 eax, ebx, ecx, edx; - int index_lsb, index_msb, tmp; - int cpu = smp_processor_id(); - - cpuid(1, &eax, &ebx, &ecx, &edx); - smp_num_siblings = (ebx & 0xff0000) >> 16; - - if (smp_num_siblings == 1) { - printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); - } else if (smp_num_siblings > 1 ) { - index_lsb = 0; - index_msb = 31; - - if (smp_num_siblings > NR_CPUS) { - printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings); - smp_num_siblings = 1; - goto too_many_siblings; - } - tmp = smp_num_siblings; - while ((tmp & 1) == 0) { - tmp >>=1 ; - index_lsb++; - } - tmp = smp_num_siblings; - while ((tmp & 0x80000000 ) == 0) { - tmp <<=1 ; - index_msb--; - } - if (index_lsb != index_msb ) - index_msb++; - phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb); - - printk(KERN_INFO "CPU: Physical Processor ID: %d\n", - phys_proc_id[cpu]); - } - - } -too_many_siblings: - + detect_ht(c); #endif /* Work around errata */ diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 0d4e4acc3b12..b97d274521b2 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -65,6 +65,7 @@ struct cpuinfo_x86 { int f00f_bug; int coma_bug; unsigned long loops_per_jiffy; + unsigned char x86_num_cores; } __attribute__((__aligned__(SMP_CACHE_BYTES))); #define X86_VENDOR_INTEL 0 @@ -96,12 +97,14 @@ extern struct cpuinfo_x86 cpu_data[]; #define current_cpu_data boot_cpu_data #endif +extern int phys_proc_id[NR_CPUS]; extern char ignore_fpu_irq; extern void identify_cpu(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *); extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); extern void dodgy_tsc(void); +extern void detect_ht(struct cpuinfo_x86 *c); /* * EFLAGS bits -- cgit v1.2.3 From 42382d56082e4a545f0d0851f9b57d4ba30faab0 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:48:14 -0800 Subject: [PATCH] i386: Count both multi cores and SMP siblings in /proc/cpuinfo siblings. Count both multi cores and SMP siblings in /proc/cpuinfo siblings. This avoids breaking user space licensing managers who license by CPU on dual core systems. Port of the equivalent code on x86-64. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/common.c | 2 ++ arch/i386/kernel/cpu/intel.c | 2 -- arch/i386/kernel/cpu/proc.c | 7 ++----- include/asm-i386/processor.h | 5 +++++ 4 files changed, 9 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 5761150d84e0..b619be984d5a 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -437,6 +437,7 @@ void __init dodgy_tsc(void) cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data); } +#ifdef CONFIG_X86_HT void __init detect_ht(struct cpuinfo_x86 *c) { u32 eax, ebx, ecx, edx; @@ -478,6 +479,7 @@ void __init detect_ht(struct cpuinfo_x86 *c) phys_proc_id[cpu]); } } +#endif void __init print_cpu_info(struct cpuinfo_x86 *c) { diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c index ec3858cf4c5a..b8d847b850dc 100644 --- a/arch/i386/kernel/cpu/intel.c +++ b/arch/i386/kernel/cpu/intel.c @@ -139,9 +139,7 @@ static void __init init_intel(struct cpuinfo_x86 *c) if ( p ) strcpy(c->x86_model_id, p); -#ifdef CONFIG_X86_HT detect_ht(c); -#endif /* Work around errata */ Intel_errata_workarounds(c); diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c index 8c179a948131..c8d83fdc237a 100644 --- a/arch/i386/kernel/cpu/proc.c +++ b/arch/i386/kernel/cpu/proc.c @@ -94,11 +94,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (c->x86_cache_size >= 0) seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); #ifdef CONFIG_X86_HT - if (smp_num_siblings > 1) { - extern int phys_proc_id[NR_CPUS]; - seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]); - seq_printf(m, "siblings\t: %d\n", smp_num_siblings); - } + seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]); + seq_printf(m, "siblings\t: %d\n", c->x86_num_cores * smp_num_siblings); #endif /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index b97d274521b2..70a48f509d24 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -104,7 +104,12 @@ extern void identify_cpu(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *); extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); extern void dodgy_tsc(void); + +#ifdef CONFIG_X86_HT extern void detect_ht(struct cpuinfo_x86 *c); +#else +static inline void detect_ht(struct cpuinfo_x86 *c) {} +#endif /* * EFLAGS bits -- cgit v1.2.3 From 82a7151979b57d1ca84792ddf19efccc247c9558 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:48:40 -0800 Subject: [PATCH] x86_64: Move memset_io out of line to avoid warnings. Move memset_io out of line to avoid warnings. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/lib/io.c | 8 ++++++++ include/asm-x86_64/io.h | 6 ++---- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/x86_64/lib/io.c b/arch/x86_64/lib/io.c index df68a2623736..87b4a4e18039 100644 --- a/arch/x86_64/lib/io.c +++ b/arch/x86_64/lib/io.c @@ -13,3 +13,11 @@ void __memcpy_fromio(void *dst,unsigned long src,unsigned len) __inline_memcpy(dst,(const void *) src,len); } EXPORT_SYMBOL(__memcpy_fromio); + +void memset_io(volatile void __iomem *a, int b, size_t c) +{ + /* XXX: memset can mangle the IO patterns quite a bit. + perhaps it would be better to use a dumb one */ + memset((void *)a,b,c); +} +EXPORT_SYMBOL(memset_io); diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h index ce379aee7355..734db492e889 100644 --- a/include/asm-x86_64/io.h +++ b/include/asm-x86_64/io.h @@ -260,10 +260,8 @@ static inline void memcpy_toio(volatile void __iomem *to, const void *from, unsi { __memcpy_toio((unsigned long)to,from,len); } -static inline void memset_io(volatile void __iomem *a, int b, size_t c) -{ - memset((__force void *)a,b,c); -} + +void memset_io(volatile void __iomem *a, int b, size_t c); /* * ISA space is 'always mapped' on a typical x86 system, no need to -- cgit v1.2.3 From 54465502760ca40444639dcb8114860dda8a5453 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:48:53 -0800 Subject: [PATCH] x86_64: Fix ioremap attribute restoration on i386 and x86-64 We need to save the access flags to properly restore the direct mapping on unmap. For that we use some upper bits in vm_flags Also add a comment for that to the header file. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/mm/ioremap.c | 6 +++--- arch/x86_64/mm/ioremap.c | 10 +++++----- include/linux/vmalloc.h | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index 1aa488b7f999..58ff04eeb9db 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -157,7 +157,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l /* * Ok, go for it.. */ - area = get_vm_area(size, VM_IOREMAP); + area = get_vm_area(size, VM_IOREMAP | (flags << 20)); if (!area) return NULL; area->phys_addr = phys_addr; @@ -235,9 +235,9 @@ void iounmap(volatile void __iomem *addr) if (!p) { printk("__iounmap: bad address %p\n", addr); return; - } + } - if (p->flags && p->phys_addr < virt_to_phys(high_memory) - 1) { + if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) { change_page_attr(virt_to_page(__va(p->phys_addr)), p->size >> PAGE_SHIFT, PAGE_KERNEL); diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c index 1a166779eeba..12363e69b0c3 100644 --- a/arch/x86_64/mm/ioremap.c +++ b/arch/x86_64/mm/ioremap.c @@ -175,11 +175,11 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l if (phys_addr >= 0xA0000 && last_addr < 0x100000) return (__force void __iomem *)phys_to_virt(phys_addr); +#ifndef CONFIG_DISCONTIGMEM /* * Don't allow anybody to remap normal RAM that we're using.. */ - if (phys_addr < virt_to_phys(high_memory)) { -#ifndef CONFIG_DISCONTIGMEM + if (last_addr < virt_to_phys(high_memory)) { char *t_addr, *t_end; struct page *page; @@ -189,8 +189,8 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) if(!PageReserved(page)) return NULL; -#endif } +#endif /* * Mappings have to be page-aligned @@ -202,7 +202,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l /* * Ok, go for it.. */ - area = get_vm_area(size, VM_IOREMAP | (flags << 24)); + area = get_vm_area(size, VM_IOREMAP | (flags << 20)); if (!area) return NULL; area->phys_addr = phys_addr; @@ -263,7 +263,7 @@ void iounmap(volatile void __iomem *addr) } *pprev = p->next; unmap_vm_area(p); - if ((p->flags >> 24) && + if ((p->flags >> 20) && p->phys_addr + p->size - 1 < virt_to_phys(high_memory)) { change_page_attr(virt_to_page(__va(p->phys_addr)), p->size >> PAGE_SHIFT, diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 8c68717810c3..9af7ad38c08d 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -8,6 +8,7 @@ #define VM_IOREMAP 0x00000001 /* ioremap() and friends */ #define VM_ALLOC 0x00000002 /* vmalloc() */ #define VM_MAP 0x00000004 /* vmap()ed pages */ +/* bits [20..32] reserved for arch specific ioremap internals */ struct vm_struct { void *addr; -- cgit v1.2.3 From 46e801e5ad461e6c17cb83bd72d1d84c0cb25626 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:49:46 -0800 Subject: [PATCH] x86_64: Add new key syscalls. Add new key syscalls. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/ia32/ia32entry.S | 4 ++++ include/asm-x86_64/ia32_unistd.h | 6 +++++- include/asm-x86_64/unistd.h | 10 ++++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 4210fa0e6918..270f8ca873ae 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -587,6 +587,10 @@ ia32_sys_call_table: .quad compat_sys_mq_getsetattr .quad quiet_ni_syscall /* reserved for kexec */ .quad sys32_waitid + .quad quiet_ni_syscall /* sys_altroot */ + .quad sys_add_key + .quad sys_request_key + .quad sys_keyctl /* don't forget to change IA32_NR_syscalls */ ia32_syscall_end: .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 diff --git a/include/asm-x86_64/ia32_unistd.h b/include/asm-x86_64/ia32_unistd.h index 26e56c27fe18..f3b7111cf33d 100644 --- a/include/asm-x86_64/ia32_unistd.h +++ b/include/asm-x86_64/ia32_unistd.h @@ -290,7 +290,11 @@ #define __NR_ia32_mq_getsetattr (__NR_ia32_mq_open+5) #define __NR_ia32_kexec 283 #define __NR_ia32_waitid 284 +/* #define __NR_sys_setaltroot 285 */ +#define __NR_ia32_add_key 286 +#define __NR_ia32_request_key 287 +#define __NR_ia32_keyctl 288 -#define IA32_NR_syscalls 285 /* must be > than biggest syscall! */ +#define IA32_NR_syscalls 290 /* must be > than biggest syscall! */ #endif /* _ASM_X86_64_IA32_UNISTD_H_ */ diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index f1a510a9b195..d9182e600b69 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -556,8 +556,14 @@ __SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr) __SYSCALL(__NR_kexec_load, sys_ni_syscall) #define __NR_waitid 247 __SYSCALL(__NR_waitid, sys_waitid) - -#define __NR_syscall_max __NR_waitid +#define __NR_add_key 248 +__SYSCALL(__NR_add_key, sys_add_key) +#define __NR_request_key 249 +__SYSCALL(__NR_request_key, sys_request_key) +#define __NR_keyctl 250 +__SYSCALL(__NR_keyctl, sys_keyctl) + +#define __NR_syscall_max __NR_keyctl #ifndef __NO_STUBS /* user-visible error numbers are in the range -1 - -4095 */ -- cgit v1.2.3 From 9156123ff70b756a4d2385a4bd546e71cf7a9be8 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:50:51 -0800 Subject: [PATCH] x86_64: Cleanups preparing for memory hotplug From: Matt Tolentino Some cleanup work in early page table init preparing for memory hotplug. Hacked up by AK Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/setup.c | 2 +- arch/x86_64/mm/init.c | 48 +++++++++++++++++++++++++--------------------- include/asm-x86_64/proto.h | 2 +- 3 files changed, 28 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 6b0b38c71608..7a8711a03294 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -493,7 +493,7 @@ void __init setup_arch(char **cmdline_p) check_efer(); - init_memory_mapping(); + init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT)); #ifdef CONFIG_ACPI_BOOT /* diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index c2ac2b4b7842..e4c8d2dc190c 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -252,51 +252,55 @@ static void __init phys_pud_init(pud_t *pud, unsigned long address, unsigned lon __flush_tlb(); } +static void __init find_early_table_space(unsigned long end) +{ + unsigned long puds, pmds, tables; + + puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; + pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; + tables = round_up(puds * sizeof(pud_t), PAGE_SIZE) + + round_up(pmds * sizeof(pmd_t), PAGE_SIZE); + + table_start = find_e820_area(0x8000, __pa_symbol(&_text), tables); + if (table_start == -1UL) + panic("Cannot find space for the kernel page tables"); + + table_start >>= PAGE_SHIFT; + table_end = table_start; +} + /* Setup the direct mapping of the physical memory at PAGE_OFFSET. This runs before bootmem is initialized and gets pages directly from the physical memory. To access them they are temporarily mapped. */ -void __init init_memory_mapping(void) +void __init init_memory_mapping(unsigned long start, unsigned long end) { - unsigned long adr; - unsigned long end; unsigned long next; - unsigned long puds, pmds, tables; Dprintk("init_memory_mapping\n"); - end = end_pfn_map << PAGE_SHIFT; - /* * Find space for the kernel direct mapping tables. * Later we should allocate these tables in the local node of the memory * mapped. Unfortunately this is done currently before the nodes are * discovered. */ + find_early_table_space(end); - puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; - pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; - tables = round_up(puds*8, PAGE_SIZE) + round_up(pmds * 8, PAGE_SIZE); - - table_start = find_e820_area(0x8000, __pa_symbol(&_text), tables); - if (table_start == -1UL) - panic("Cannot find space for the kernel page tables"); + start = (unsigned long)__va(start); + end = (unsigned long)__va(end); - table_start >>= PAGE_SHIFT; - table_end = table_start; - - end += __PAGE_OFFSET; /* turn virtual */ - - for (adr = PAGE_OFFSET; adr < end; adr = next) { + for (; start < end; start = next) { int map; unsigned long pud_phys; pud_t *pud = alloc_low_page(&map, &pud_phys); - next = adr + PGDIR_SIZE; + next = start + PGDIR_SIZE; if (next > end) next = end; - phys_pud_init(pud, adr-PAGE_OFFSET, next-PAGE_OFFSET); - set_pgd(init_level4_pgt + pgd_index(adr), mk_kernel_pgd(pud_phys)); + phys_pud_init(pud, __pa(start), __pa(next)); + set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys)); unmap_low_page(map); } + asm volatile("movq %%cr4,%0" : "=r" (mmu_cr4_features)); __flush_tlb_all(); early_printk("kernel direct mapping tables upto %lx @ %lx-%lx\n", end, diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index e942ca5957e4..3bee3482389a 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -15,7 +15,7 @@ extern void pda_init(int); extern void early_idt_handler(void); extern void mcheck_init(struct cpuinfo_x86 *c); -extern void init_memory_mapping(void); +extern void init_memory_mapping(unsigned long start, unsigned long end); extern void system_call(void); extern int kernel_syscall(void); -- cgit v1.2.3 From 1d563ebcaf796f4bcf2903336899dcd7c48db429 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:51:05 -0800 Subject: [PATCH] x86_64: Remove unused prototypes. Pointed out by Matthew Wilcox. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-x86_64/hw_irq.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 767e11abd5c5..2b5cb2865d21 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -87,8 +87,6 @@ extern u8 irq_vector[NR_IRQ_VECTORS]; * Interrupt entry/exit code at both C and assembly level */ -extern void mask_irq(unsigned int irq); -extern void unmask_irq(unsigned int irq); extern void disable_8259A_irq(unsigned int irq); extern void enable_8259A_irq(unsigned int irq); extern int i8259A_irq_pending(unsigned int irq); -- cgit v1.2.3 From 1821c54f2a37b7ef2b53dc6cbd3c5da450e182ac Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 11 Jan 2005 01:52:11 -0800 Subject: [PATCH] UML: add some pudding This adds pud_t support to UML. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/mem.c | 3 ++- arch/um/kernel/process_kern.c | 12 +++++++++++- arch/um/kernel/skas/tlb.c | 7 +++++-- arch/um/kernel/tlb.c | 16 ++++++++++++---- arch/um/kernel/trap_kern.c | 7 +++++-- arch/um/kernel/tt/tlb.c | 12 +++++++++--- include/asm-um/pgalloc.h | 14 ++++++++------ include/asm-um/pgtable.h | 35 +++++++++++++++++++++-------------- 8 files changed, 73 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 4279161c8849..77d063d5407f 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -135,7 +135,8 @@ pte_t *kmap_pte; pgprot_t kmap_prot; #define kmap_get_fixmap_pte(vaddr) \ - pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) + pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\ + (vaddr)), (vaddr)) void __init kmap_init(void) { diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 2af5a343cf1c..62e6c8ef2e67 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -235,18 +235,28 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte_out) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; if(task->mm == NULL) return(ERR_PTR(-EINVAL)); pgd = pgd_offset(task->mm, addr); - pmd = pmd_offset(pgd, addr); + if(!pgd_present(*pgd)) + return(ERR_PTR(-EINVAL)); + + pud = pud_offset(pgd, addr); + if(!pud_present(*pud)) + return(ERR_PTR(-EINVAL)); + + pmd = pmd_offset(pud, addr); if(!pmd_present(*pmd)) return(ERR_PTR(-EINVAL)); + pte = pte_offset_kernel(pmd, addr); if(!pte_present(*pte)) return(ERR_PTR(-EINVAL)); + if(pte_out != NULL) *pte_out = *pte; return((void *) (pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK)); diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c index 02e3e06bb033..3b0d8da430c1 100644 --- a/arch/um/kernel/skas/tlb.c +++ b/arch/um/kernel/skas/tlb.c @@ -18,6 +18,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr, int force) { pgd_t *npgd; + pmd_t *npud; pmd_t *npmd; pte_t *npte; unsigned long addr; @@ -27,7 +28,8 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, fd = mm->context.skas.mm_fd; for(addr = start_addr; addr < end_addr;){ npgd = pgd_offset(mm, addr); - npmd = pmd_offset(npgd, addr); + npud = pud_offset(npgd, addr); + npmd = pmd_offset(npud, addr); if(pmd_present(*npmd)){ npte = pte_offset_kernel(npmd, addr); r = pte_read(*npte); @@ -79,7 +81,8 @@ void flush_tlb_kernel_range_skas(unsigned long start, unsigned long end) mm = &init_mm; for(addr = start; addr < end;){ pgd = pgd_offset(mm, addr); - pmd = pmd_offset(pgd, addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); if(pmd_present(*pmd)){ pte = pte_offset_kernel(pmd, addr); if(!pte_present(*pte) || pte_newpage(*pte)){ diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index c42053140e2b..26f5d12d81f3 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -59,9 +59,14 @@ pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) return(pgd_offset(mm, address)); } -pmd_t *pmd_offset_proc(pgd_t *pgd, unsigned long address) +pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address) { - return(pmd_offset(pgd, address)); + return(pud_offset(pgd, address)); +} + +pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address) +{ + return(pmd_offset(pud, address)); } pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address) @@ -71,8 +76,11 @@ pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address) pte_t *addr_pte(struct task_struct *task, unsigned long addr) { - return(pte_offset_kernel(pmd_offset(pgd_offset(task->mm, addr), addr), - addr)); + pgd_t *pgd = pgd_offset(task->mm, addr); + pud_t *pud = pud_offset(pgd, addr); + pmd_t *pmd = pmd_offset(pud, addr); + + return(pte_offset_map(pmd, addr)); } /* diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index cba33ef6da5d..9385a1aefaba 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -13,6 +13,7 @@ #include "linux/ptrace.h" #include "asm/semaphore.h" #include "asm/pgtable.h" +#include "asm/pgalloc.h" #include "asm/tlbflush.h" #include "asm/a.out.h" #include "asm/current.h" @@ -32,6 +33,7 @@ int handle_page_fault(unsigned long address, unsigned long ip, struct mm_struct *mm = current->mm; struct vm_area_struct *vma; pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; unsigned long page; @@ -54,8 +56,9 @@ int handle_page_fault(unsigned long address, unsigned long ip, if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; page = address & PAGE_MASK; - pgd = pgd_offset(mm, page); - pmd = pmd_offset(pgd, page); + pgd = pgd_offset(mm); + pud = pud_offset(pgd, page); + pmd = pmd_offset(pud, page); do { survive: switch (handle_mm_fault(mm, vma, address, is_write)){ diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c index d8ad334cfac9..ce057e3c1fb4 100644 --- a/arch/um/kernel/tt/tlb.c +++ b/arch/um/kernel/tt/tlb.c @@ -19,6 +19,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr, int force) { pgd_t *npgd; + pud_t *npud; pmd_t *npmd; pte_t *npte; unsigned long addr; @@ -42,7 +43,8 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, continue; } npgd = pgd_offset(mm, addr); - npmd = pmd_offset(npgd, addr); + npud = pud_offset(npgd, addr); + npmd = pmd_offset(npud, addr); if(pmd_present(*npmd)){ npte = pte_offset_kernel(npmd, addr); r = pte_read(*npte); @@ -90,6 +92,7 @@ static void flush_kernel_vm_range(unsigned long start, unsigned long end, { struct mm_struct *mm; pgd_t *pgd; + pud_t *pmd; pmd_t *pmd; pte_t *pte; unsigned long addr; @@ -98,7 +101,8 @@ static void flush_kernel_vm_range(unsigned long start, unsigned long end, mm = &init_mm; for(addr = start; addr < end;){ pgd = pgd_offset(mm, addr); - pmd = pmd_offset(pgd, addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); if(pmd_present(*pmd)){ pte = pte_offset_kernel(pmd, addr); if(!pte_present(*pte) || pte_newpage(*pte)){ @@ -155,6 +159,7 @@ void mprotect_kernel_vm(int w) { struct mm_struct *mm; pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; unsigned long addr; @@ -162,7 +167,8 @@ void mprotect_kernel_vm(int w) mm = &init_mm; for(addr = start_vm; addr < end_vm;){ pgd = pgd_offset(mm, addr); - pmd = pmd_offset(pgd, addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); if(pmd_present(*pmd)){ pte = pte_offset_kernel(pmd, addr); if(pte_present(*pte)) protect_vm_page(addr, w, 0); diff --git a/include/asm-um/pgalloc.h b/include/asm-um/pgalloc.h index 73973aeaf482..d22a15573d83 100644 --- a/include/asm-um/pgalloc.h +++ b/include/asm-um/pgalloc.h @@ -13,12 +13,14 @@ #define pmd_populate_kernel(mm, pmd, pte) \ set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte))) -static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, - struct page *pte) -{ - set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte))); -} +#define pmd_populate(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + \ + ((unsigned long long)page_to_pfn(pte) << \ + (unsigned long long) PAGE_SHIFT))) +/* + * Allocate and free page tables. + */ extern pgd_t *pgd_alloc(struct mm_struct *); extern void pgd_free(pgd_t *pgd); @@ -45,7 +47,7 @@ static inline void pte_free(struct page *pte) #define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) #define pmd_free(x) do { } while (0) #define __pmd_free_tlb(tlb,x) do { } while (0) -#define pgd_populate(mm, pmd, pte) BUG() +#define pud_populate(mm, pmd, pte) BUG() #define check_pgt_cache() do { } while (0) diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h index a747f7dd4ff4..e16ea2a3ecd7 100644 --- a/include/asm-um/pgtable.h +++ b/include/asm-um/pgtable.h @@ -7,8 +7,6 @@ #ifndef __UM_PGTABLE_H #define __UM_PGTABLE_H -#include - #include "linux/sched.h" #include "asm/processor.h" #include "asm/page.h" @@ -23,7 +21,6 @@ extern unsigned long *empty_zero_page; #define pgtable_cache_init() do ; while (0) /* PMD_SHIFT determines the size of the area a second-level page table can map */ -#define PMD_SHIFT 22 #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~(PMD_SIZE-1)) @@ -39,7 +36,6 @@ extern unsigned long *empty_zero_page; #define PTRS_PER_PTE 1024 #define PTRS_PER_PMD 1 #define PTRS_PER_PGD 1024 -#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) #define FIRST_USER_PGD_NR 0 #define pte_ERROR(e) \ @@ -176,6 +172,15 @@ extern pte_t * __bad_pagetable(void); #define pmd_newpage(x) (pmd_val(x) & _PAGE_NEWPAGE) #define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE) +#define pud_newpage(x) (pud_val(x) & _PAGE_NEWPAGE) +#define pud_mkuptodate(x) (pud_val(x) &= ~_PAGE_NEWPAGE) + +static inline pud_t *__pud_alloc(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr) +{ + BUG(); +} + /* * The "pgd_xxx()" functions here are trivial for a folded two-level * setup: the pgd is never bad, and a pmd always exists (as it's folded @@ -374,15 +379,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * this macro returns the index of the entry in the pgd page which would * control the given virtual address */ -#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) + +#define pgd_index_k(addr) pgd_index(addr) /* * pgd_offset() returns a (pgd_t *) * pgd_index() is used get the offset into the pgd page's array of pgd_t's; */ -#define pgd_offset(mm, address) \ -((mm)->pgd + ((address) >> PGDIR_SHIFT)) - +#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) /* * a shortcut which implies the use of the kernel's pgd, instead @@ -390,15 +395,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) */ #define pgd_offset_k(address) pgd_offset(&init_mm, address) +/* + * the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD] + * + * this macro returns the index of the entry in the pmd page which would + * control the given virtual address + */ #define pmd_index(address) \ (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) -/* Find an entry in the second-level page table.. */ -static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) -{ - return (pmd_t *) dir; -} - /* * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] * @@ -430,6 +435,8 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) #include +#include + #endif #endif -- cgit v1.2.3 From 7d35ecabf698b47a613a2fbc9035d859d331767c Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 11 Jan 2005 01:52:52 -0800 Subject: [PATCH] UML: Three-level page table support This is the three-level page table support from the x86_64 patch. It can be enabled on x86, although it's not particularly needed at this point. However, it can be used to implement very large physical memory (with almost all of it in highmem) on UML. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig | 2 + arch/um/Kconfig_i386 | 8 ++ arch/um/Makefile | 2 +- arch/um/defconfig | 1 + arch/um/kernel/mem.c | 5 +- arch/um/kernel/physmem.c | 7 +- arch/um/kernel/skas/tlb.c | 149 ++++++++++++++++++++-------- arch/um/kernel/trap_kern.c | 5 +- arch/um/kernel/tt/tlb.c | 156 +++++++++++++++++++++-------- include/asm-um/page.h | 106 +++++++++++++++++--- include/asm-um/pgalloc.h | 12 +-- include/asm-um/pgtable-2level.h | 83 ++++++++++++++++ include/asm-um/pgtable-3level.h | 172 ++++++++++++++++++++++++++++++++ include/asm-um/pgtable.h | 209 ++++++++++++++------------------------- include/asm-um/vm-flags-i386.h | 14 +++ include/asm-um/vm-flags-x86_64.h | 27 +++++ 16 files changed, 714 insertions(+), 244 deletions(-) create mode 100644 arch/um/Kconfig_i386 create mode 100644 include/asm-um/pgtable-2level.h create mode 100644 include/asm-um/pgtable-3level.h create mode 100644 include/asm-um/vm-flags-i386.h create mode 100644 include/asm-um/vm-flags-x86_64.h (limited to 'include') diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 06ba2aca73a5..633e8a54fde2 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -68,6 +68,8 @@ config MODE_SKAS to CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this option will shrink the UML binary slightly. +source "arch/um/Kconfig_arch" + config NET bool "Networking support" help diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386 new file mode 100644 index 000000000000..e2a5f6692cd6 --- /dev/null +++ b/arch/um/Kconfig_i386 @@ -0,0 +1,8 @@ +config 3_LEVEL_PGTABLES + bool "Three-level pagetables" + default n + help + Three-level pagetables will let UML have more than 4G of physical + memory. All the memory that can't be mapped directly will be treated + as high memory. + diff --git a/arch/um/Makefile b/arch/um/Makefile index b8371a95849a..288a375b9c3b 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -17,7 +17,7 @@ core-y += $(ARCH_DIR)/kernel/ \ # Have to precede the include because the included Makefiles reference them. SYMLINK_HEADERS = archparam.h system.h sigcontext.h processor.h ptrace.h \ - arch-signal.h module.h + arch-signal.h module.h vm-flags.h SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ diff --git a/arch/um/defconfig b/arch/um/defconfig index 708878e397a9..515581109029 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -17,6 +17,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y # CONFIG_MODE_TT=y CONFIG_MODE_SKAS=y +# CONFIG_3_LEVEL_PGTABLES is not set CONFIG_NET=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 77d063d5407f..e8a2c9c5716b 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -25,7 +25,7 @@ extern char __binary_start; /* Changed during early boot */ unsigned long *empty_zero_page = NULL; unsigned long *empty_bad_page = NULL; -pgd_t swapper_pg_dir[1024]; +pgd_t swapper_pg_dir[PTRS_PER_PGD]; unsigned long highmem; int kmalloc_ok = 0; @@ -242,6 +242,7 @@ struct page *arch_validate(struct page *page, int mask, int order) } addr += PAGE_SIZE; } + if(i == (1 << order)) return(page); page = alloc_pages(mask, order); goto again; @@ -336,7 +337,7 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) { struct page *pte; - pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); + pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); return pte; } diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 3253bc0e3a5c..2853028657b3 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -309,7 +309,7 @@ struct page *__virt_to_page(const unsigned long virt) return(&mem_map[__pa(virt) >> PAGE_SHIFT]); } -unsigned long page_to_phys(struct page *page) +phys_t page_to_phys(struct page *page) { return((page - mem_map) << PAGE_SHIFT); } @@ -318,8 +318,9 @@ pte_t mk_pte(struct page *page, pgprot_t pgprot) { pte_t pte; - pte_val(pte) = page_to_phys(page) + pgprot_val(pgprot); - if(pte_present(pte)) pte_mknewprot(pte_mknewpage(pte)); + pte_set_val(pte, page_to_phys(page), pgprot); + if(pte_present(pte)) + pte_mknewprot(pte_mknewpage(pte)); return(pte); } diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c index 3b0d8da430c1..956fb0102a1e 100644 --- a/arch/um/kernel/skas/tlb.c +++ b/arch/um/kernel/skas/tlb.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. * Licensed under the GPL */ @@ -18,54 +19,86 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr, int force) { pgd_t *npgd; - pmd_t *npud; + pud_t *npud; pmd_t *npmd; pte_t *npte; - unsigned long addr; + unsigned long addr, end; int r, w, x, err, fd; if(mm == NULL) return; fd = mm->context.skas.mm_fd; for(addr = start_addr; addr < end_addr;){ npgd = pgd_offset(mm, addr); - npud = pud_offset(npgd, addr); - npmd = pmd_offset(npud, addr); - if(pmd_present(*npmd)){ - npte = pte_offset_kernel(npmd, addr); - r = pte_read(*npte); - w = pte_write(*npte); - x = pte_exec(*npte); - if(!pte_dirty(*npte)) w = 0; - if(!pte_young(*npte)){ - r = 0; - w = 0; - } - if(force || pte_newpage(*npte)){ - err = unmap(fd, (void *) addr, PAGE_SIZE); + if(!pgd_present(*npgd)){ + if(force || pgd_newpage(*npgd)){ + end = addr + PGDIR_SIZE; + if(end > end_addr) + end = end_addr; + err = unmap(fd, (void *) addr, end - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); - if(pte_present(*npte)) - map(fd, addr, - pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x); + pgd_mkuptodate(*npgd); } - else if(pte_newprot(*npte)){ - protect(fd, addr, PAGE_SIZE, r, w, x, 1); + addr += PGDIR_SIZE; + continue; + } + + npud = pud_offset(npgd, addr); + if(!pud_present(*npud)){ + if(force || pud_newpage(*npud)){ + end = addr + PUD_SIZE; + if(end > end_addr) + end = end_addr; + err = unmap(fd, (void *) addr, end - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + pud_mkuptodate(*npud); } - *npte = pte_mkuptodate(*npte); - addr += PAGE_SIZE; + addr += PUD_SIZE; + continue; } - else { + + npmd = pmd_offset(npud, addr); + if(!pmd_present(*npmd)){ if(force || pmd_newpage(*npmd)){ - err = unmap(fd, (void *) addr, PMD_SIZE); + end = addr + PMD_SIZE; + if(end > end_addr) + end = end_addr; + err = unmap(fd, (void *) addr, end - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); pmd_mkuptodate(*npmd); } addr += PMD_SIZE; + continue; + } + + npte = pte_offset_kernel(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); + if(!pte_dirty(*npte)) + w = 0; + if(!pte_young(*npte)){ + r = 0; + w = 0; } + if(force || pte_newpage(*npte)){ + err = unmap(fd, (void *) addr, PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", -err); + if(pte_present(*npte)) + map(fd, addr, pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x); + } + else if(pte_newprot(*npte)) + protect(fd, addr, PAGE_SIZE, r, w, x, 1); + + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; } } @@ -73,9 +106,10 @@ void flush_tlb_kernel_range_skas(unsigned long start, unsigned long end) { struct mm_struct *mm; pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; - unsigned long addr; + unsigned long addr, last; int updated = 0, err; mm = &init_mm; @@ -83,36 +117,71 @@ void flush_tlb_kernel_range_skas(unsigned long start, unsigned long end) pgd = pgd_offset(mm, addr); pud = pud_offset(pgd, addr); pmd = pmd_offset(pud, addr); - if(pmd_present(*pmd)){ - pte = pte_offset_kernel(pmd, addr); - if(!pte_present(*pte) || pte_newpage(*pte)){ + if(!pgd_present(*pgd)){ + if(pgd_newpage(*pgd)){ updated = 1; + last = addr + PGDIR_SIZE; + if(last > end) + last = end; err = os_unmap_memory((void *) addr, - PAGE_SIZE); + last - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); - if(pte_present(*pte)) - map_memory(addr, - pte_val(*pte) & PAGE_MASK, - PAGE_SIZE, 1, 1, 1); } - else if(pte_newprot(*pte)){ + addr += PGDIR_SIZE; + continue; + } + + pud = pud_offset(pgd, addr); + if(!pud_present(*pud)){ + if(pud_newpage(*pud)){ updated = 1; - protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + last = addr + PUD_SIZE; + if(last > end) + last = end; + err = os_unmap_memory((void *) addr, + last - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); } - addr += PAGE_SIZE; + addr += PUD_SIZE; + continue; } - else { + + pmd = pmd_offset(pud, addr); + if(!pmd_present(*pmd)){ if(pmd_newpage(*pmd)){ updated = 1; - err = os_unmap_memory((void *) addr, PMD_SIZE); + last = addr + PMD_SIZE; + if(last > end) + last = end; + err = os_unmap_memory((void *) addr, + last - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); } addr += PMD_SIZE; + continue; + } + + pte = pte_offset_kernel(pmd, addr); + if(!pte_present(*pte) || pte_newpage(*pte)){ + updated = 1; + err = os_unmap_memory((void *) addr, PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", -err); + if(pte_present(*pte)) + map_memory(addr, pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, 1, 1, 1); } + else if(pte_newprot(*pte)){ + updated = 1; + protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + } + addr += PAGE_SIZE; } } diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 9385a1aefaba..80d07fe6b979 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -56,7 +56,7 @@ int handle_page_fault(unsigned long address, unsigned long ip, if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; page = address & PAGE_MASK; - pgd = pgd_offset(mm); + pgd = pgd_offset(mm, page); pud = pud_offset(pgd, page); pmd = pmd_offset(pud, page); do { @@ -77,6 +77,9 @@ int handle_page_fault(unsigned long address, unsigned long ip, default: BUG(); } + pgd = pgd_offset(mm, page); + pud = pud_offset(pgd, page); + pmd = pmd_offset(pud, page); pte = pte_offset_kernel(pmd, page); } while(!pte_present(*pte)); err = 0; diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c index ce057e3c1fb4..3bc35eea1da4 100644 --- a/arch/um/kernel/tt/tlb.c +++ b/arch/um/kernel/tt/tlb.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. * Licensed under the GPL */ @@ -22,7 +23,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, pud_t *npud; pmd_t *npmd; pte_t *npte; - unsigned long addr; + unsigned long addr, end; int r, w, x, err; if((current->thread.mode.tt.extern_pid != -1) && @@ -42,46 +43,81 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, addr = STACK_TOP - ABOVE_KMEM; continue; } + npgd = pgd_offset(mm, addr); + if(!pgd_present(*npgd)){ + if(force || pgd_newpage(*npgd)){ + end = addr + PGDIR_SIZE; + if(end > end_addr) + end = end_addr; + err = os_unmap_memory((void *) addr, + end - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + pgd_mkuptodate(*npgd); + } + addr += PGDIR_SIZE; + continue; + } + npud = pud_offset(npgd, addr); - npmd = pmd_offset(npud, addr); - if(pmd_present(*npmd)){ - npte = pte_offset_kernel(npmd, addr); - r = pte_read(*npte); - w = pte_write(*npte); - x = pte_exec(*npte); - if(!pte_dirty(*npte)) w = 0; - if(!pte_young(*npte)){ - r = 0; - w = 0; - } - if(force || pte_newpage(*npte)){ + if(!pud_present(*npud)){ + if(force || pud_newpage(*npud)){ + end = addr + PUD_SIZE; + if(end > end_addr) + end = end_addr; err = os_unmap_memory((void *) addr, - PAGE_SIZE); + end - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); - if(pte_present(*npte)) - map_memory(addr, - pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x); - } - else if(pte_newprot(*npte)){ - protect_memory(addr, PAGE_SIZE, r, w, x, 1); + pud_mkuptodate(*npud); } - *npte = pte_mkuptodate(*npte); - addr += PAGE_SIZE; + addr += PUD_SIZE; + continue; } - else { + + npmd = pmd_offset(npud, addr); + if(!pmd_present(*npmd)){ if(force || pmd_newpage(*npmd)){ - err = os_unmap_memory((void *) addr, PMD_SIZE); + end = addr + PMD_SIZE; + if(end > end_addr) + end = end_addr; + err = os_unmap_memory((void *) addr, + end - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); pmd_mkuptodate(*npmd); } addr += PMD_SIZE; + continue; } + + npte = pte_offset_kernel(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); + if(!pte_dirty(*npte)) + w = 0; + if(!pte_young(*npte)){ + r = 0; + w = 0; + } + if(force || pte_newpage(*npte)){ + err = os_unmap_memory((void *) addr, PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", -err); + if(pte_present(*npte)) + map_memory(addr, pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x); + } + else if(pte_newprot(*npte)) + protect_memory(addr, PAGE_SIZE, r, w, x, 1); + + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; } } @@ -92,47 +128,83 @@ static void flush_kernel_vm_range(unsigned long start, unsigned long end, { struct mm_struct *mm; pgd_t *pgd; - pud_t *pmd; + pud_t *pud; pmd_t *pmd; pte_t *pte; - unsigned long addr; + unsigned long addr, last; int updated = 0, err; mm = &init_mm; for(addr = start; addr < end;){ pgd = pgd_offset(mm, addr); - pud = pud_offset(pgd, addr); - pmd = pmd_offset(pud, addr); - if(pmd_present(*pmd)){ - pte = pte_offset_kernel(pmd, addr); - if(!pte_present(*pte) || pte_newpage(*pte)){ + if(!pgd_present(*pgd)){ + if(pgd_newpage(*pgd)){ updated = 1; + last = addr + PGDIR_SIZE; + if(last > end) + last = end; err = os_unmap_memory((void *) addr, - PAGE_SIZE); + last - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); - if(pte_present(*pte)) - map_memory(addr, - pte_val(*pte) & PAGE_MASK, - PAGE_SIZE, 1, 1, 1); } - else if(pte_newprot(*pte)){ + addr += PGDIR_SIZE; + continue; + } + + pud = pud_offset(pgd, addr); + if(!pud_present(*pud)){ + if(pud_newpage(*pud)){ updated = 1; - protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + last = addr + PUD_SIZE; + if(last > end) + last = end; + err = os_unmap_memory((void *) addr, + last - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); } - addr += PAGE_SIZE; + addr += PUD_SIZE; + continue; } - else { + + pmd = pmd_offset(pud, addr); + if(!pmd_present(*pmd)){ if(pmd_newpage(*pmd)){ updated = 1; - err = os_unmap_memory((void *) addr, PMD_SIZE); + last = addr + PMD_SIZE; + if(last > end) + last = end; + err = os_unmap_memory((void *) addr, + last - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); } addr += PMD_SIZE; + continue; + } + + pte = pte_offset_kernel(pmd, addr); + if(!pte_present(*pte) || pte_newpage(*pte)){ + updated = 1; + err = os_unmap_memory((void *) addr, + PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + if(pte_present(*pte)) + map_memory(addr, + pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, 1, 1, 1); + } + else if(pte_newprot(*pte)){ + updated = 1; + protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); } + addr += PAGE_SIZE; } if(updated && update_seq) atomic_inc(&vmchange_seq); } diff --git a/include/asm-um/page.h b/include/asm-um/page.h index f69b0f1c270e..3620a08dc9f3 100644 --- a/include/asm-um/page.h +++ b/include/asm-um/page.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright 2003 PathScale, Inc. * Licensed under the GPL */ @@ -8,18 +9,82 @@ struct page; -#include "asm/arch/page.h" +#include +#include -#undef __pa -#undef __va -#undef pfn_to_page -#undef page_to_pfn -#undef virt_to_page -#undef pfn_valid -#undef virt_addr_valid -#undef VALID_PAGE -#undef PAGE_OFFSET -#undef KERNELBASE +/* PAGE_SHIFT determines the page size */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +/* + * These are used to make use of C type-checking.. + */ + +#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) +#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +#if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64_BIT) + +typedef struct { unsigned long pte_low, pte_high; } pte_t; +typedef struct { unsigned long long pmd; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +#define pte_val(x) ((x).pte_low | ((unsigned long long) (x).pte_high << 32)) + +#define pte_get_bits(pte, bits) ((pte).pte_low & (bits)) +#define pte_set_bits(pte, bits) ((pte).pte_low |= (bits)) +#define pte_clear_bits(pte, bits) ((pte).pte_low &= ~(bits)) +#define pte_copy(to, from) ({ (to).pte_high = (from).pte_high; \ + smp_wmb(); \ + (to).pte_low = (from).pte_low; }) +#define pte_is_zero(pte) (!((pte).pte_low & ~_PAGE_NEWPAGE) && !(pte).pte_high) +#define pte_set_val(pte, phys, prot) \ + ({ (pte).pte_high = (phys) >> 32; \ + (pte).pte_low = (phys) | pgprot_val(prot); }) + +typedef unsigned long long pfn_t; +typedef unsigned long long phys_t; + +#else + +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pgd; } pgd_t; + +#ifdef CONFIG_3_LEVEL_PGTABLES +typedef struct { unsigned long pmd; } pmd_t; +#define pmd_val(x) ((x).pmd) +#define __pmd(x) ((pmd_t) { (x) } ) +#endif + +#define pte_val(x) ((x).pte) + + +#define pte_get_bits(p, bits) ((p).pte & (bits)) +#define pte_set_bits(p, bits) ((p).pte |= (bits)) +#define pte_clear_bits(p, bits) ((p).pte &= ~(bits)) +#define pte_copy(to, from) ((to).pte = (from).pte) +#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEWPAGE)) +#define pte_set_val(p, phys, prot) (p).pte = (phys | pgprot_val(prot)) + +typedef unsigned long pfn_t; +typedef unsigned long phys_t; + +#endif + +typedef struct { unsigned long pgprot; } pgprot_t; + +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) extern unsigned long uml_physmem; @@ -30,7 +95,6 @@ extern unsigned long uml_physmem; extern unsigned long to_phys(void *virt); extern void *to_virt(unsigned long phys); - #define __pa(virt) to_phys((void *) virt) #define __va(phys) to_virt((unsigned long) phys) @@ -42,7 +106,21 @@ extern void *to_virt(unsigned long phys); #define pfn_valid(pfn) ((pfn) < max_mapnr) #define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v))) - + +/* Pure 2^n version of get_order */ +static __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + extern struct page *arch_validate(struct page *page, int mask, int order); #define HAVE_ARCH_VALIDATE diff --git a/include/asm-um/pgalloc.h b/include/asm-um/pgalloc.h index d22a15573d83..8fcb2fc0a892 100644 --- a/include/asm-um/pgalloc.h +++ b/include/asm-um/pgalloc.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. * Derived from include/asm-i386/pgalloc.h and include/asm-i386/pgtable.h * Licensed under the GPL */ @@ -7,11 +8,12 @@ #ifndef __UM_PGALLOC_H #define __UM_PGALLOC_H +#include "linux/config.h" #include "linux/mm.h" #include "asm/fixmap.h" #define pmd_populate_kernel(mm, pmd, pte) \ - set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte))) + set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte))) #define pmd_populate(mm, pmd, pte) \ set_pmd(pmd, __pmd(_PAGE_TABLE + \ @@ -39,15 +41,13 @@ static inline void pte_free(struct page *pte) #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) +#ifdef CONFIG_3_LEVEL_PGTABLES /* - * allocating and freeing a pmd is trivial: the 1-entry pmd is - * inside the pgd, so has no extra memory associated with it. + * In the 3-level case we free the pmds as part of the pgd. */ - -#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) #define pmd_free(x) do { } while (0) #define __pmd_free_tlb(tlb,x) do { } while (0) -#define pud_populate(mm, pmd, pte) BUG() +#endif #define check_pgt_cache() do { } while (0) diff --git a/include/asm-um/pgtable-2level.h b/include/asm-um/pgtable-2level.h new file mode 100644 index 000000000000..f6263d11f205 --- /dev/null +++ b/include/asm-um/pgtable-2level.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. + * Derived from include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGTABLE_2LEVEL_H +#define __UM_PGTABLE_2LEVEL_H + +#include + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ + +#define PGDIR_SHIFT 22 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * entries per page directory level: the i386 is two-level, so + * we don't really have any PMD directory physically. + */ +#define PTRS_PER_PTE 1024 +#define PTRS_PER_PMD 1 +#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) +#define PTRS_PER_PGD 1024 +#define FIRST_USER_PGD_NR 0 + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%08lx).\n", __FILE__, __LINE__, &(e), \ + pte_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), \ + pgd_val(e)) + +static inline int pgd_newpage(pgd_t pgd) { return 0; } +static inline void pgd_mkuptodate(pgd_t pgd) { } + +#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) + +static inline pte_t pte_mknewprot(pte_t pte) +{ + pte_val(pte) |= _PAGE_NEWPROT; + return(pte); +} + +static inline pte_t pte_mknewpage(pte_t pte) +{ + pte_val(pte) |= _PAGE_NEWPAGE; + return(pte); +} + +static inline void set_pte(pte_t *pteptr, pte_t pteval) +{ + /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so + * fix_range knows to unmap it. _PAGE_NEWPROT is specific to + * mapped pages. + */ + *pteptr = pte_mknewpage(pteval); + if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr); +} + +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval)) + +#define pte_page(x) pfn_to_page(pte_pfn(x)) +#define pte_none(x) !(pte_val(x) & ~_PAGE_NEWPAGE) +#define pte_pfn(x) phys_to_pfn(pte_val(x)) +#define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot)) +#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot)) + +#define pmd_page_kernel(pmd) \ + ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + +/* + * Bits 0 through 3 are taken + */ +#define PTE_FILE_MAX_BITS 28 + +#define pte_to_pgoff(pte) (pte_val(pte) >> 4) + +#define pgoff_to_pte(off) ((pte_t) { ((off) << 4) + _PAGE_FILE }) + +#endif diff --git a/include/asm-um/pgtable-3level.h b/include/asm-um/pgtable-3level.h new file mode 100644 index 000000000000..acebb593cfd6 --- /dev/null +++ b/include/asm-um/pgtable-3level.h @@ -0,0 +1,172 @@ +/* + * Copyright 2003 PathScale Inc + * Derived from include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGTABLE_3LEVEL_H +#define __UM_PGTABLE_3LEVEL_H + +#include + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ + +#define PGDIR_SHIFT 30 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* PMD_SHIFT determines the size of the area a second-level page table can + * map + */ + +#define PMD_SHIFT 21 +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* + * entries per page directory level + */ + +#define PTRS_PER_PTE 512 +#define PTRS_PER_PMD 512 +#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) +#define PTRS_PER_PGD 512 +#define FIRST_USER_PGD_NR 0 + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pte_val(e)) +#define pmd_ERROR(e) \ + printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pmd_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pgd_val(e)) + +#define pud_none(x) (!(pud_val(x) & ~_PAGE_NEWPAGE)) +#define pud_bad(x) ((pud_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) +#define pud_present(x) (pud_val(x) & _PAGE_PRESENT) +#define pud_populate(mm, pud, pmd) \ + set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd))) + +#define set_pud(pudptr, pudval) set_64bit((phys_t *) (pudptr), pud_val(pudval)) +static inline int pgd_newpage(pgd_t pgd) +{ + return(pgd_val(pgd) & _PAGE_NEWPAGE); +} + +static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; } + + +#define pte_present(x) pte_get_bits(x, (_PAGE_PRESENT | _PAGE_PROTNONE)) + +static inline pte_t pte_mknewprot(pte_t pte) +{ + pte_set_bits(pte, _PAGE_NEWPROT); + return(pte); +} + +static inline pte_t pte_mknewpage(pte_t pte) +{ + pte_set_bits(pte, _PAGE_NEWPAGE); + return(pte); +} + +static inline void set_pte(pte_t *pteptr, pte_t pteval) +{ + pte_copy(*pteptr, pteval); + + /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so + * fix_range knows to unmap it. _PAGE_NEWPROT is specific to + * mapped pages. + */ + + *pteptr = pte_mknewpage(*pteptr); + if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr); +} + +#define set_pmd(pmdptr, pmdval) set_64bit((phys_t *) (pmdptr), pmd_val(pmdval)) + +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL); + + if(pmd) + memset(pmd, 0, PAGE_SIZE); + + return pmd; +} + +static inline void pmd_free(pmd_t *pmd){ + free_page((unsigned long) pmd); +} + +#define __pmd_free_tlb(tlb,x) do { } while (0) + +static inline void pud_clear (pud_t * pud) { } + +#define pud_page(pud) \ + ((struct page *) __va(pud_val(pud) & PAGE_MASK)) + +/* Find an entry in the second-level page table.. */ +#define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \ + pmd_index(address)) + +#define pte_page(x) pfn_to_page(pte_pfn(x)) + +static inline int pte_none(pte_t pte) +{ + return pte_is_zero(pte); +} + +static inline unsigned long pte_pfn(pte_t pte) +{ + return phys_to_pfn(pte_val(pte)); +} + +static inline pte_t pfn_pte(pfn_t page_nr, pgprot_t pgprot) +{ + pte_t pte; + phys_t phys = pfn_to_phys(page_nr); + + pte_set_val(pte, phys, pgprot); + return pte; +} + +static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot) +{ + return __pmd((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); +} + +/* + * Bits 0 through 3 are taken in the low part of the pte, + * put the 32 bits of offset into the high part. + */ +#define PTE_FILE_MAX_BITS 32 + +#ifdef CONFIG_64_BIT + +#define pte_to_pgoff(p) ((p).pte >> 32) + +#define pgoff_to_pte(off) ((pte_t) { ((off) < 32) | _PAGE_FILE }) + +#else + +#define pte_to_pgoff(pte) ((pte).pte_high) + +#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) }) + +#endif + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h index e16ea2a3ecd7..7f980a262334 100644 --- a/include/asm-um/pgtable.h +++ b/include/asm-um/pgtable.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. * Derived from include/asm-i386/pgtable.h * Licensed under the GPL */ @@ -12,6 +13,24 @@ #include "asm/page.h" #include "asm/fixmap.h" +#define _PAGE_PRESENT 0x001 +#define _PAGE_NEWPAGE 0x002 +#define _PAGE_NEWPROT 0x004 +#define _PAGE_FILE 0x008 /* set:pagecache unset:swap */ +#define _PAGE_PROTNONE 0x010 /* If not present */ +#define _PAGE_RW 0x020 +#define _PAGE_USER 0x040 +#define _PAGE_ACCESSED 0x080 +#define _PAGE_DIRTY 0x100 + +#ifdef CONFIG_3_LEVEL_PGTABLES +#include "asm/pgtable-3level.h" +#else +#include "asm/pgtable-2level.h" +#endif + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt, pte_t *pte_out); @@ -20,33 +39,6 @@ extern unsigned long *empty_zero_page; #define pgtable_cache_init() do ; while (0) -/* PMD_SHIFT determines the size of the area a second-level page table can map */ -#define PMD_SIZE (1UL << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1)) - -/* PGDIR_SHIFT determines what a third-level page table entry can map */ -#define PGDIR_SHIFT 22 -#define PGDIR_SIZE (1UL << PGDIR_SHIFT) -#define PGDIR_MASK (~(PGDIR_SIZE-1)) - -/* - * entries per page directory level: the i386 is two-level, so - * we don't really have any PMD directory physically. - */ -#define PTRS_PER_PTE 1024 -#define PTRS_PER_PMD 1 -#define PTRS_PER_PGD 1024 -#define FIRST_USER_PGD_NR 0 - -#define pte_ERROR(e) \ - printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) -#define pmd_ERROR(e) \ - printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e)) -#define pgd_ERROR(e) \ - printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) - -extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; - /* * pgd entries used up by user/kernel: */ @@ -66,7 +58,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern unsigned long end_iomem; #define VMALLOC_OFFSET (__va_space) -#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #ifdef CONFIG_HIGHMEM # define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) @@ -74,18 +66,8 @@ extern unsigned long end_iomem; # define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) #endif -#define _PAGE_PRESENT 0x001 -#define _PAGE_NEWPAGE 0x002 -#define _PAGE_NEWPROT 0x004 -#define _PAGE_FILE 0x008 /* set:pagecache unset:swap */ -#define _PAGE_PROTNONE 0x010 /* If not present */ -#define _PAGE_RW 0x020 -#define _PAGE_USER 0x040 -#define _PAGE_ACCESSED 0x080 -#define _PAGE_DIRTY 0x100 - -#define REGION_MASK 0xf0000000 -#define REGION_SHIFT 28 +#define REGION_SHIFT (sizeof(pte_t) * 8 - 4) +#define REGION_MASK (((unsigned long) 0xf) << REGION_SHIFT) #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) @@ -153,16 +135,13 @@ extern pte_t * __bad_pagetable(void); /* sizeof(void*)==1<>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) -#define pte_none(x) !(pte_val(x) & ~_PAGE_NEWPAGE) -#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) - -#define pte_clear(xp) do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0) +#define pte_clear(xp) pte_set_val(*(xp), (phys_t) 0, __pgprot(_PAGE_NEWPAGE)) #define pmd_none(x) (!(pmd_val(x) & ~_PAGE_NEWPAGE)) #define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) @@ -181,67 +160,13 @@ static inline pud_t *__pud_alloc(struct mm_struct *mm, pgd_t *pgd, BUG(); } -/* - * The "pgd_xxx()" functions here are trivial for a folded two-level - * setup: the pgd is never bad, and a pmd always exists (as it's folded - * into the pgd entry) - */ -static inline int pgd_none(pgd_t pgd) { return 0; } -static inline int pgd_bad(pgd_t pgd) { return 0; } -static inline int pgd_present(pgd_t pgd) { return 1; } -static inline void pgd_clear(pgd_t * pgdp) { } - - #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) -#define pte_page(pte) phys_to_page(pte_val(pte)) #define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK) -#define pte_pfn(x) phys_to_pfn(pte_val(x)) -#define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot)) - -extern struct page *phys_to_page(const unsigned long phys); -extern struct page *__virt_to_page(const unsigned long virt); -#define virt_to_page(addr) __virt_to_page((const unsigned long) addr) - -/* - * Bits 0 through 3 are taken - */ -#define PTE_FILE_MAX_BITS 28 - -#define pte_to_pgoff(pte) ((pte).pte_low >> 4) - -#define pgoff_to_pte(off) \ - ((pte_t) { ((off) << 4) + _PAGE_FILE }) - -static inline pte_t pte_mknewprot(pte_t pte) -{ - pte_val(pte) |= _PAGE_NEWPROT; - return(pte); -} - -static inline pte_t pte_mknewpage(pte_t pte) -{ - pte_val(pte) |= _PAGE_NEWPAGE; - return(pte); -} - -static inline void set_pte(pte_t *pteptr, pte_t pteval) -{ - /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so - * fix_range knows to unmap it. _PAGE_NEWPROT is specific to - * mapped pages. - */ - *pteptr = pte_mknewpage(pteval); - if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr); -} - -/* - * (pmds are folded into pgds so this doesn't get actually called, - * but the define is needed for a generic inline function.) - */ -#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) -#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval) +#define pte_address(x) (__va(pte_val(x) & PAGE_MASK)) +#define mk_phys(a, r) ((a) + (((unsigned long) r) << REGION_SHIFT)) +#define phys_addr(p) ((p) & ~REGION_MASK) /* * The following only work if pte_present() is true. @@ -249,25 +174,25 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval) */ static inline int pte_user(pte_t pte) { - return((pte_val(pte) & _PAGE_USER) && - !(pte_val(pte) & _PAGE_PROTNONE)); + return((pte_get_bits(pte, _PAGE_USER)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); } static inline int pte_read(pte_t pte) { - return((pte_val(pte) & _PAGE_USER) && - !(pte_val(pte) & _PAGE_PROTNONE)); + return((pte_get_bits(pte, _PAGE_USER)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); } static inline int pte_exec(pte_t pte){ - return((pte_val(pte) & _PAGE_USER) && - !(pte_val(pte) & _PAGE_PROTNONE)); + return((pte_get_bits(pte, _PAGE_USER)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); } static inline int pte_write(pte_t pte) { - return((pte_val(pte) & _PAGE_RW) && - !(pte_val(pte) & _PAGE_PROTNONE)); + return((pte_get_bits(pte, _PAGE_RW)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); } /* @@ -275,85 +200,98 @@ static inline int pte_write(pte_t pte) */ static inline int pte_file(pte_t pte) { - return (pte).pte_low & _PAGE_FILE; + return pte_get_bits(pte, _PAGE_FILE); +} + +static inline int pte_dirty(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_DIRTY); +} + +static inline int pte_young(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_ACCESSED); +} + +static inline int pte_newpage(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_NEWPAGE); } -static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } -static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; } static inline int pte_newprot(pte_t pte) { - return(pte_present(pte) && (pte_val(pte) & _PAGE_NEWPROT)); + return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT))); } static inline pte_t pte_rdprotect(pte_t pte) { - pte_val(pte) &= ~_PAGE_USER; + pte_clear_bits(pte, _PAGE_USER); return(pte_mknewprot(pte)); } static inline pte_t pte_exprotect(pte_t pte) { - pte_val(pte) &= ~_PAGE_USER; + pte_clear_bits(pte, _PAGE_USER); return(pte_mknewprot(pte)); } static inline pte_t pte_mkclean(pte_t pte) { - pte_val(pte) &= ~_PAGE_DIRTY; + pte_clear_bits(pte, _PAGE_DIRTY); return(pte); } static inline pte_t pte_mkold(pte_t pte) { - pte_val(pte) &= ~_PAGE_ACCESSED; + pte_clear_bits(pte, _PAGE_ACCESSED); return(pte); } static inline pte_t pte_wrprotect(pte_t pte) { - pte_val(pte) &= ~_PAGE_RW; + pte_clear_bits(pte, _PAGE_RW); return(pte_mknewprot(pte)); } static inline pte_t pte_mkread(pte_t pte) { - pte_val(pte) |= _PAGE_USER; + pte_set_bits(pte, _PAGE_RW); return(pte_mknewprot(pte)); } static inline pte_t pte_mkexec(pte_t pte) { - pte_val(pte) |= _PAGE_USER; + pte_set_bits(pte, _PAGE_USER); return(pte_mknewprot(pte)); } static inline pte_t pte_mkdirty(pte_t pte) { - pte_val(pte) |= _PAGE_DIRTY; + pte_set_bits(pte, _PAGE_DIRTY); return(pte); } static inline pte_t pte_mkyoung(pte_t pte) { - pte_val(pte) |= _PAGE_ACCESSED; + pte_set_bits(pte, _PAGE_ACCESSED); return(pte); } static inline pte_t pte_mkwrite(pte_t pte) { - pte_val(pte) |= _PAGE_RW; + pte_set_bits(pte, _PAGE_RW); return(pte_mknewprot(pte)); } static inline pte_t pte_mkuptodate(pte_t pte) { - pte_val(pte) &= ~_PAGE_NEWPAGE; - if(pte_present(pte)) pte_val(pte) &= ~_PAGE_NEWPROT; + pte_clear_bits(pte, _PAGE_NEWPAGE); + if(pte_present(pte)) + pte_clear_bits(pte, _PAGE_NEWPROT); return(pte); } -extern unsigned long page_to_phys(struct page *page); +extern phys_t page_to_phys(struct page *page); /* * Conversion functions: convert a page and protection to a page entry, @@ -362,11 +300,9 @@ extern unsigned long page_to_phys(struct page *page); extern pte_t mk_pte(struct page *page, pgprot_t pgprot); -#define pte_set_val(p, phys, prot) pte_val(p) = (phys | pgprot_val(prot)) - static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { - pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); + pte_set_val(pte, (pte_val(pte) & _PAGE_CHG_MASK), newprot); if(pte_present(pte)) pte = pte_mknewpage(pte_mknewprot(pte)); return pte; } @@ -401,8 +337,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * this macro returns the index of the entry in the pmd page which would * control the given virtual address */ -#define pmd_index(address) \ - (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) +#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) /* * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] @@ -435,11 +370,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #include -#include +#include #endif - #endif + +extern struct page *phys_to_page(const unsigned long phys); +extern struct page *__virt_to_page(const unsigned long virt); +#define virt_to_page(addr) __virt_to_page((const unsigned long) addr) + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/include/asm-um/vm-flags-i386.h b/include/asm-um/vm-flags-i386.h new file mode 100644 index 000000000000..e0d24c568dbc --- /dev/null +++ b/include/asm-um/vm-flags-i386.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#ifndef __VM_FLAGS_I386_H +#define __VM_FLAGS_I386_H + +#define VM_DATA_DEFAULT_FLAGS \ + (VM_READ | VM_WRITE | \ + ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#endif diff --git a/include/asm-um/vm-flags-x86_64.h b/include/asm-um/vm-flags-x86_64.h new file mode 100644 index 000000000000..e04e92d64858 --- /dev/null +++ b/include/asm-um/vm-flags-x86_64.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Copyright 2003 PathScale, Inc. + * Licensed under the GPL + */ + +#ifndef __VM_FLAGS_X86_64_H +#define __VM_FLAGS_X86_64_H + +#define __VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define __VM_STACK_FLAGS (VM_GROWSDOWN | VM_READ | VM_WRITE | \ + VM_EXEC | VM_MAYREAD | VM_MAYWRITE | \ + VM_MAYEXEC) + +extern unsigned long vm_stack_flags, vm_stack_flags32; +extern unsigned long vm_data_default_flags, vm_data_default_flags32; +extern unsigned long vm_force_exec32; + +#define VM_DATA_DEFAULT_FLAGS \ + (test_thread_flag(TIF_IA32) ? vm_data_default_flags32 : \ + vm_data_default_flags) + +#define VM_STACK_DEFAULT_FLAGS \ + (test_thread_flag(TIF_IA32) ? vm_stack_flags32 : vm_stack_flags) + +#endif -- cgit v1.2.3 From df69f7acb11b7bd78fd5ec8bcb216e0d70728e03 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 11 Jan 2005 01:53:06 -0800 Subject: [PATCH] UML: x86-64 core support This adds the new files from the x86_64 port which just drop in and don't require any work anywhere else. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Makefile | 6 +- arch/um/Makefile-i386 | 2 + arch/um/Makefile-x86_64 | 35 ++++ arch/um/include/sysdep-x86_64/checksum.h | 151 ++++++++++++++++ arch/um/include/sysdep-x86_64/sigcontext.h | 49 +++++ arch/um/kernel/tt/Makefile | 5 +- arch/um/sys-x86_64/Makefile | 39 ++++ arch/um/sys-x86_64/bugs.c | 122 +++++++++++++ arch/um/sys-x86_64/fault.c | 23 +++ arch/um/sys-x86_64/mem.c | 25 +++ arch/um/sys-x86_64/sigcontext.c | 39 ++++ arch/um/sys-x86_64/signal.c | 276 +++++++++++++++++++++++++++++ arch/um/sys-x86_64/sysrq.c | 49 +++++ arch/um/sys-x86_64/util/Makefile | 10 ++ arch/um/sys-x86_64/util/mk_sc.c | 58 ++++++ arch/um/sys-x86_64/util/mk_thread_kern.c | 21 +++ arch/um/sys-x86_64/util/mk_thread_user.c | 30 ++++ include/asm-um/apic.h | 4 + include/asm-um/module-x86_64.h | 30 ++++ include/asm-um/pda.h | 31 ++++ include/asm-um/prctl.h | 6 + include/asm-um/processor-x86_64.h | 33 ++++ include/asm-um/sigcontext-x86_64.h | 22 +++ include/asm-um/system-x86_64.h | 23 +++ include/asm-um/vm-flags-x86_64.h | 6 + 25 files changed, 1092 insertions(+), 3 deletions(-) create mode 100644 arch/um/include/sysdep-x86_64/checksum.h create mode 100644 arch/um/include/sysdep-x86_64/sigcontext.h create mode 100644 arch/um/sys-x86_64/Makefile create mode 100644 arch/um/sys-x86_64/bugs.c create mode 100644 arch/um/sys-x86_64/fault.c create mode 100644 arch/um/sys-x86_64/mem.c create mode 100644 arch/um/sys-x86_64/sigcontext.c create mode 100644 arch/um/sys-x86_64/signal.c create mode 100644 arch/um/sys-x86_64/sysrq.c create mode 100644 arch/um/sys-x86_64/util/Makefile create mode 100644 arch/um/sys-x86_64/util/mk_sc.c create mode 100644 arch/um/sys-x86_64/util/mk_thread_kern.c create mode 100644 arch/um/sys-x86_64/util/mk_thread_user.c create mode 100644 include/asm-um/apic.h create mode 100644 include/asm-um/module-x86_64.h create mode 100644 include/asm-um/pda.h create mode 100644 include/asm-um/prctl.h create mode 100644 include/asm-um/processor-x86_64.h create mode 100644 include/asm-um/sigcontext-x86_64.h create mode 100644 include/asm-um/system-x86_64.h (limited to 'include') diff --git a/arch/um/Makefile b/arch/um/Makefile index 288a375b9c3b..62e78418b1ea 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -12,8 +12,7 @@ SHELL := /bin/bash filechk_gen_header = $< core-y += $(ARCH_DIR)/kernel/ \ - $(ARCH_DIR)/drivers/ \ - $(ARCH_DIR)/sys-$(SUBARCH)/ + $(ARCH_DIR)/drivers/ # Have to precede the include because the included Makefiles reference them. SYMLINK_HEADERS = archparam.h system.h sigcontext.h processor.h ptrace.h \ @@ -38,6 +37,9 @@ SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH) include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS) +core-y += $(SUBARCH_CORE) +libs-y += $(SUBARCH_LIBS) + # -Derrno=kernel_errno - This turns all kernel references to errno into # kernel_errno to separate them from the libc errno. This allows -fno-common # in CFLAGS. Otherwise, it would cause ld to complain about the two different diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index 7c7d008478b6..43991d9e3437 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -1,3 +1,5 @@ +SUBARCH_CORE := arch/um/sys-i386/ + ifeq ($(CONFIG_HOST_2G_2G), y) TOP_ADDR := 0x80000000 else diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index 705df73454c8..9638cac93165 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 @@ -1 +1,36 @@ +# Copyright 2003 - 2004 Pathscale, Inc +# Released under the GPL + +SUBARCH_LIBS := arch/um/sys-x86_64/ +START := 0x60000000 + +CFLAGS += -U__$(SUBARCH)__ -fno-builtin ARCH_USER_CFLAGS := -D__x86_64__ + +ELF_ARCH := i386:x86-64 +ELF_FORMAT := elf64-x86-64 + +SYS_UTIL_DIR := $(ARCH_DIR)/sys-x86_64/util +SYS_DIR := $(ARCH_DIR)/include/sysdep-x86_64 + +SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h + +prepare: $(SYS_HEADERS) + +$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc + $(call filechk,gen_header) + +$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread + $(call filechk,gen_header) + +$(SYS_UTIL_DIR)/mk_sc: scripts_basic FORCE + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@ + +$(SYS_UTIL_DIR)/mk_thread: scripts_basic $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@ + +CLEAN_FILES += $(SYS_HEADERS) + +LIBC_DIR := /usr/lib64 + +export LIBC_DIR diff --git a/arch/um/include/sysdep-x86_64/checksum.h b/arch/um/include/sysdep-x86_64/checksum.h new file mode 100644 index 000000000000..d57aa7f3130e --- /dev/null +++ b/arch/um/include/sysdep-x86_64/checksum.h @@ -0,0 +1,151 @@ +/* + * Licensed under the GPL + */ + +#ifndef __UM_SYSDEP_CHECKSUM_H +#define __UM_SYSDEP_CHECKSUM_H + +#include "linux/string.h" +#include "linux/in6.h" +#include "asm/uaccess.h" + +extern unsigned int csum_partial_copy_from(const char *src, char *dst, int len, + int sum, int *err_ptr); +extern unsigned csum_partial(const unsigned char *buff, unsigned len, + unsigned sum); + +/* + * Note: when you get a NULL pointer exception here this means someone + * passed in an incorrect kernel address to one of these functions. + * + * If you use these functions directly please don't forget the + * verify_area(). + */ + +static __inline__ +unsigned int csum_partial_copy_nocheck(const char *src, char *dst, + int len, int sum) +{ + memcpy(dst, src, len); + return(csum_partial(dst, len, sum)); +} + +static __inline__ +unsigned int csum_partial_copy_from_user(const char *src, char *dst, + int len, int sum, int *err_ptr) +{ + return csum_partial_copy_from(src, dst, len, sum, err_ptr); +} + +/** + * csum_fold - Fold and invert a 32bit checksum. + * sum: 32bit unfolded sum + * + * Fold a 32bit running checksum to 16bit and invert it. This is usually + * the last step before putting a checksum into a packet. + * Make sure not to mix with 64bit checksums. + */ +static inline unsigned int csum_fold(unsigned int sum) +{ + __asm__( + " addl %1,%0\n" + " adcl $0xffff,%0" + : "=r" (sum) + : "r" (sum << 16), "0" (sum & 0xffff0000) + ); + return (~sum) >> 16; +} + +/** + * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum. + * @saddr: source address + * @daddr: destination address + * @len: length of packet + * @proto: ip protocol of packet + * @sum: initial sum to be added in (32bit unfolded) + * + * Returns the pseudo header checksum the input data. Result is + * 32bit unfolded. + */ +static inline unsigned long +csum_tcpudp_nofold(unsigned saddr, unsigned daddr, unsigned short len, + unsigned short proto, unsigned int sum) +{ + asm(" addl %1, %0\n" + " adcl %2, %0\n" + " adcl %3, %0\n" + " adcl $0, %0\n" + : "=r" (sum) + : "g" (daddr), "g" (saddr), "g" ((ntohs(len)<<16)+proto*256), "0" (sum)); + return sum; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); +} + +/** + * ip_fast_csum - Compute the IPv4 header checksum efficiently. + * iph: ipv4 header + * ihl: length of header / 4 + */ +static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) +{ + unsigned int sum; + + asm( " movl (%1), %0\n" + " subl $4, %2\n" + " jbe 2f\n" + " addl 4(%1), %0\n" + " adcl 8(%1), %0\n" + " adcl 12(%1), %0\n" + "1: adcl 16(%1), %0\n" + " lea 4(%1), %1\n" + " decl %2\n" + " jne 1b\n" + " adcl $0, %0\n" + " movl %0, %2\n" + " shrl $16, %0\n" + " addw %w2, %w0\n" + " adcl $0, %0\n" + " notl %0\n" + "2:" + /* Since the input registers which are loaded with iph and ipl + are modified, we must also specify them as outputs, or gcc + will assume they contain their original values. */ + : "=r" (sum), "=r" (iph), "=r" (ihl) + : "1" (iph), "2" (ihl) + : "memory"); + return(sum); +} + +static inline unsigned add32_with_carry(unsigned a, unsigned b) +{ + asm("addl %2,%0\n\t" + "adcl $0,%0" + : "=r" (a) + : "0" (a), "r" (b)); + return a; +} + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/sysdep-x86_64/sigcontext.h b/arch/um/include/sysdep-x86_64/sigcontext.h new file mode 100644 index 000000000000..6a0c346b6404 --- /dev/null +++ b/arch/um/include/sysdep-x86_64/sigcontext.h @@ -0,0 +1,49 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __SYSDEP_X86_64_SIGCONTEXT_H +#define __SYSDEP_X86_64_SIGCONTEXT_H + +#include "sc.h" + +#define IP_RESTART_SYSCALL(ip) ((ip) -= 2) + +#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc)) +#define SC_SET_SYSCALL_RETURN(sc, result) SC_RAX(sc) = (result) + +#define SC_FAULT_ADDR(sc) SC_CR2(sc) +#define SC_FAULT_TYPE(sc) SC_ERR(sc) + +#define FAULT_WRITE(err) ((err) & 2) + +#define SC_FAULT_WRITE(sc) FAULT_WRITE(SC_FAULT_TYPE(sc)) + +#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc) + +/* ptrace expects that, at the start of a system call, %eax contains + * -ENOSYS, so this makes it so. + */ + +#define SC_START_SYSCALL(sc) do SC_RAX(sc) = -ENOSYS; while(0) + +#define SEGV_IS_FIXABLE(trap) ((trap) == 14) +#define SC_SEGV_IS_FIXABLE(sc) SEGV_IS_FIXABLE(SC_TRAP_TYPE(sc)) + +extern unsigned long *sc_sigmask(void *sc_ptr); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ + diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 17f4594dc231..7c9eec5fded5 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -24,6 +24,9 @@ $(USER_OBJS) : %.o: %.c $(obj)/unmap.o: $(src)/unmap.c $(CC) $(UNMAP_CFLAGS) -c -o $@ $< +LIBC_DIR ?= /usr/lib + $(obj)/unmap_fin.o : $(obj)/unmap.o - ld -r -o $(obj)/unmap_tmp.o $< -lc -L/usr/lib + ld -r -o $(obj)/unmap_tmp.o $< -lc -L$(LIBC_DIR) objcopy $(obj)/unmap_tmp.o $@ -G switcheroo + diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile new file mode 100644 index 000000000000..0859685f511a --- /dev/null +++ b/arch/um/sys-x86_64/Makefile @@ -0,0 +1,39 @@ +# +# Copyright 2003 PathScale, Inc. +# +# Licensed under the GPL +# + +lib-y = bitops.o bugs.o csum-partial.o fault.o mem.o memcpy.o \ + ptrace.o semaphore.o sigcontext.o signal.o syscalls.o \ + sysrq.o thunk.o + +USER_OBJS := sigcontext.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + +SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \ + semaphore.c thunk.S +SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f) + +clean-files := $(SYMLINKS) + +bitops.c-dir = lib +csum-copy.S-dir = lib +csum-partial.c-dir = lib +csum-wrappers.c-dir = lib +memcpy.S-dir = lib +semaphore.c-dir = kernel +thunk.S-dir = lib + +define make_link + -rm -f $1 + ln -sf $(TOPDIR)/arch/x86_64/$($(notdir $1)-dir)/$(notdir $1) $1 +endef + +$(SYMLINKS): + $(call make_link,$@) + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +CFLAGS_csum-partial.o := -Dcsum_partial=arch_csum_partial diff --git a/arch/um/sys-x86_64/bugs.c b/arch/um/sys-x86_64/bugs.c new file mode 100644 index 000000000000..fdce7ea98ca7 --- /dev/null +++ b/arch/um/sys-x86_64/bugs.c @@ -0,0 +1,122 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/errno.h" +#include "asm/system.h" +#include "asm/pda.h" +#include "sysdep/ptrace.h" +#include "os.h" + +void arch_init_thread(void) +{ +} + +void arch_check_bugs(void) +{ +} + +int arch_handle_signal(int sig, union uml_pt_regs *regs) +{ + return(0); +} + +#define MAXTOKEN 64 + +/* Set during early boot */ +int host_has_cmov = 1; +int host_has_xmm = 0; + +static char token(int fd, char *buf, int len, char stop) +{ + int n; + char *ptr, *end, c; + + ptr = buf; + end = &buf[len]; + do { + n = os_read_file(fd, ptr, sizeof(*ptr)); + c = *ptr++; + if(n != sizeof(*ptr)){ + if(n == 0) return(0); + printk("Reading /proc/cpuinfo failed, err = %d\n", -n); + if(n < 0) + return(n); + else + return(-EIO); + } + } while((c != '\n') && (c != stop) && (ptr < end)); + + if(ptr == end){ + printk("Failed to find '%c' in /proc/cpuinfo\n", stop); + return(-1); + } + *(ptr - 1) = '\0'; + return(c); +} + +static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) +{ + int n; + char c; + + scratch[len - 1] = '\0'; + while(1){ + c = token(fd, scratch, len - 1, ':'); + if(c <= 0) + return(0); + else if(c != ':'){ + printk("Failed to find ':' in /proc/cpuinfo\n"); + return(0); + } + + if(!strncmp(scratch, key, strlen(key))) + return(1); + + do { + n = os_read_file(fd, &c, sizeof(c)); + if(n != sizeof(c)){ + printk("Failed to find newline in " + "/proc/cpuinfo, err = %d\n", -n); + return(0); + } + } while(c != '\n'); + } + return(0); +} + +int cpu_feature(char *what, char *buf, int len) +{ + int fd, ret = 0; + + fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); + return(0); + } + + if(!find_cpuinfo_line(fd, what, buf, len)){ + printk("Couldn't find '%s' line in /proc/cpuinfo\n", what); + goto out_close; + } + + token(fd, buf, len, '\n'); + ret = 1; + + out_close: + os_close_file(fd); + return(ret); +} + +/* Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/fault.c b/arch/um/sys-x86_64/fault.c new file mode 100644 index 000000000000..cee1513c5c31 --- /dev/null +++ b/arch/um/sys-x86_64/fault.c @@ -0,0 +1,23 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include "user.h" + +int arch_fixup(unsigned long address, void *sc_ptr) +{ + /* XXX search_exception_tables() */ + return(0); +} + +/* Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/mem.c b/arch/um/sys-x86_64/mem.c new file mode 100644 index 000000000000..3f59a0a4f156 --- /dev/null +++ b/arch/um/sys-x86_64/mem.c @@ -0,0 +1,25 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include "linux/mm.h" +#include "asm/page.h" +#include "asm/mman.h" + +unsigned long vm_stack_flags = __VM_STACK_FLAGS; +unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; +unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; +unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; +unsigned long vm_force_exec32 = PROT_EXEC; + +/* Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/sigcontext.c b/arch/um/sys-x86_64/sigcontext.c new file mode 100644 index 000000000000..c88e64def6f2 --- /dev/null +++ b/arch/um/sys-x86_64/sigcontext.c @@ -0,0 +1,39 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include +#include +#include +#include "user.h" + +void sc_to_sc(void *to_ptr, void *from_ptr) +{ + struct sigcontext *to = to_ptr, *from = from_ptr; + int size = sizeof(*to); /* + sizeof(struct _fpstate); */ + + memcpy(to, from, size); + if(from->fpstate != NULL) + to->fpstate = (struct _fpstate *) (to + 1); + + to->fpstate = NULL; +} + +unsigned long *sc_sigmask(void *sc_ptr) +{ + struct sigcontext *sc = sc_ptr; + + return(&sc->oldmask); +} + +/* Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c new file mode 100644 index 000000000000..4864c0605972 --- /dev/null +++ b/arch/um/sys-x86_64/signal.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2003 PathScale, Inc. + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/errno.h" +#include "linux/personality.h" +#include "linux/ptrace.h" +#include "asm/current.h" +#include "asm/uaccess.h" +#include "asm/sigcontext.h" +#include "asm/ptrace.h" +#include "asm/arch/ucontext.h" +#include "choose-mode.h" +#include "sysdep/ptrace.h" +#include "frame_kern.h" + +#ifdef CONFIG_MODE_SKAS + +#include "skas.h" + +static int copy_sc_from_user_skas(struct pt_regs *regs, + struct sigcontext *from) +{ + int err = 0; + +#define GETREG(regs, regno, sc, regname) \ + __get_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \ + &(sc)->regname) + + err |= GETREG(regs, R8, from, r8); + err |= GETREG(regs, R9, from, r9); + err |= GETREG(regs, R10, from, r10); + err |= GETREG(regs, R11, from, r11); + err |= GETREG(regs, R12, from, r12); + err |= GETREG(regs, R13, from, r13); + err |= GETREG(regs, R14, from, r14); + err |= GETREG(regs, R15, from, r15); + err |= GETREG(regs, RDI, from, rdi); + err |= GETREG(regs, RSI, from, rsi); + err |= GETREG(regs, RBP, from, rbp); + err |= GETREG(regs, RBX, from, rbx); + err |= GETREG(regs, RDX, from, rdx); + err |= GETREG(regs, RAX, from, rax); + err |= GETREG(regs, RCX, from, rcx); + err |= GETREG(regs, RSP, from, rsp); + err |= GETREG(regs, RIP, from, rip); + err |= GETREG(regs, EFLAGS, from, eflags); + err |= GETREG(regs, CS, from, cs); + +#undef GETREG + + return(err); +} + +int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, + struct pt_regs *regs, unsigned long mask) +{ + unsigned long eflags; + int err = 0; + + err |= __put_user(0, &to->gs); + err |= __put_user(0, &to->fs); + +#define PUTREG(regs, regno, sc, regname) \ + __put_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \ + &(sc)->regname) + + err |= PUTREG(regs, RDI, to, rdi); + err |= PUTREG(regs, RSI, to, rsi); + err |= PUTREG(regs, RBP, to, rbp); + err |= PUTREG(regs, RSP, to, rsp); + err |= PUTREG(regs, RBX, to, rbx); + err |= PUTREG(regs, RDX, to, rdx); + err |= PUTREG(regs, RCX, to, rcx); + err |= PUTREG(regs, RAX, to, rax); + err |= PUTREG(regs, R8, to, r8); + err |= PUTREG(regs, R9, to, r9); + err |= PUTREG(regs, R10, to, r10); + err |= PUTREG(regs, R11, to, r11); + err |= PUTREG(regs, R12, to, r12); + err |= PUTREG(regs, R13, to, r13); + err |= PUTREG(regs, R14, to, r14); + err |= PUTREG(regs, R15, to, r15); + err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */ + err |= __put_user(current->thread.err, &to->err); + err |= __put_user(current->thread.trap_no, &to->trapno); + err |= PUTREG(regs, RIP, to, rip); + err |= PUTREG(regs, EFLAGS, to, eflags); +#undef PUTREG + + err |= __put_user(mask, &to->oldmask); + err |= __put_user(current->thread.cr2, &to->cr2); + + return(err); +} + +#endif + +#ifdef CONFIG_MODE_TT +int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, + int fpsize) +{ + struct _fpstate *to_fp, *from_fp; + unsigned long sigs; + int err; + + to_fp = to->fpstate; + from_fp = from->fpstate; + sigs = to->oldmask; + err = copy_from_user(to, from, sizeof(*to)); + to->oldmask = sigs; + return(err); +} + +int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, + struct sigcontext *from, int fpsize) +{ + struct _fpstate *to_fp, *from_fp; + int err; + + to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); + from_fp = from->fpstate; + err = copy_to_user(to, from, sizeof(*to)); + return(err); +} + +#endif + +static int copy_sc_from_user(struct pt_regs *to, void *from) +{ + int ret; + + ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, + sizeof(struct _fpstate)), + copy_sc_from_user_skas(to, from)); + return(ret); +} + +static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, + struct pt_regs *from, unsigned long mask) +{ + return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), + sizeof(*fp)), + copy_sc_to_user_skas(to, fp, from, mask))); +} + +struct rt_sigframe +{ + char *pretcode; + struct ucontext uc; + struct siginfo info; +}; + +#define round_down(m, n) (((m) / (n)) * (n)) + +int setup_signal_stack_si(unsigned long stack_top, int sig, + struct k_sigaction *ka, struct pt_regs * regs, + siginfo_t *info, sigset_t *set) +{ + struct rt_sigframe __user *frame; + struct _fpstate __user *fp = NULL; + int err = 0; + struct task_struct *me = current; + + frame = (struct rt_sigframe __user *) + round_down(stack_top - sizeof(struct rt_sigframe), 16) - 8; + frame -= 128; + + if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) + goto out; + +#if 0 /* XXX */ + if (save_i387(fp) < 0) + err |= -1; +#endif + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto out; + + if (ka->sa.sa_flags & SA_SIGINFO) { + err |= copy_siginfo_to_user(&frame->info, info); + if (err) + goto out; + } + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); + err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); + if (sizeof(*set) == 16) { + __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); + __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); + } + else + err |= __copy_to_user(&frame->uc.uc_sigmask, set, + sizeof(*set)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + /* x86-64 should always use SA_RESTORER. */ + if (ka->sa.sa_flags & SA_RESTORER) + err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); + else + /* could use a vstub here */ + goto out; + + if (err) + goto out; + + /* Set up registers for signal handler */ + { + struct exec_domain *ed = current_thread_info()->exec_domain; + if (unlikely(ed && ed->signal_invmap && sig < 32)) + sig = ed->signal_invmap[sig]; + } + + PT_REGS_RDI(regs) = sig; + /* In case the signal handler was declared without prototypes */ + PT_REGS_RAX(regs) = 0; + + /* This also works for non SA_SIGINFO handlers because they expect the + next argument after the signal number on the stack. */ + PT_REGS_RSI(regs) = (unsigned long) &frame->info; + PT_REGS_RDX(regs) = (unsigned long) &frame->uc; + PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; + + PT_REGS_RSP(regs) = (unsigned long) frame; + out: + return(err); +} + +long sys_rt_sigreturn(struct pt_regs *regs) +{ + unsigned long __user sp = PT_REGS_SP(¤t->thread.regs); + struct rt_sigframe __user *frame = + (struct rt_sigframe __user *)(sp - 8); + struct ucontext __user *uc = &frame->uc; + sigset_t set; + + if(copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) + goto segfault; + + sigdelsetmask(&set, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) + goto segfault; + + /* Avoid ERESTART handling */ + PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; + return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); + + segfault: + force_sig(SIGSEGV, current); + return 0; +} +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c new file mode 100644 index 000000000000..c33f85f9e8bb --- /dev/null +++ b/arch/um/sys-x86_64/sysrq.c @@ -0,0 +1,49 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include "linux/kernel.h" +#include "linux/version.h" +#include "linux/module.h" +#include "asm/current.h" +#include "asm/ptrace.h" +#include "sysrq.h" + +void __show_regs(struct pt_regs * regs) +{ + printk("\n"); + print_modules(); + printk("Pid: %d, comm: %.20s %s %s\n", + current->pid, current->comm, print_tainted(), UTS_RELEASE); + printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff, + PT_REGS_RIP(regs)); + printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs), + PT_REGS_EFLAGS(regs)); + printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", + PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs)); + printk("RDX: %016lx RSI: %016lx RDI: %016lx\n", + PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs)); + printk("RBP: %016lx R08: %016lx R09: %016lx\n", + PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs)); + printk("R10: %016lx R11: %016lx R12: %016lx\n", + PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs)); + printk("R13: %016lx R14: %016lx R15: %016lx\n", + PT_REGS_R13(regs), PT_REGS_R14(regs), PT_REGS_R15(regs)); +} + +void show_regs(struct pt_regs *regs) +{ + __show_regs(regs); + show_trace((unsigned long *) ®s); +} + +/* Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/util/Makefile b/arch/um/sys-x86_64/util/Makefile new file mode 100644 index 000000000000..002607980864 --- /dev/null +++ b/arch/um/sys-x86_64/util/Makefile @@ -0,0 +1,10 @@ +# Copyright 2003 - 2004 Pathscale, Inc +# Released under the GPL + +hostprogs-y := mk_sc mk_thread +always := $(hostprogs-y) + +mk_thread-objs := mk_thread_kern.o mk_thread_user.o + +HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS) +HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS) diff --git a/arch/um/sys-x86_64/util/mk_sc.c b/arch/um/sys-x86_64/util/mk_sc.c new file mode 100644 index 000000000000..c236e213918d --- /dev/null +++ b/arch/um/sys-x86_64/util/mk_sc.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2003 - 2004 PathScale, Inc + * Released under the GPL + */ + +#include +#include +#include + +#define SC_OFFSET(name, field) \ + printf("#define " name \ + "(sc) *((unsigned long *) &(((char *) (sc))[%ld]))\n",\ + offsetof(struct sigcontext, field)) + +#define SC_FP_OFFSET(name, field) \ + printf("#define " name \ + "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%ld]))\n",\ + offsetof(struct _fpstate, field)) + +#define SC_FP_OFFSET_PTR(name, field, type) \ + printf("#define " name \ + "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\ + offsetof(struct _fpstate, field)) + +int main(int argc, char **argv) +{ + SC_OFFSET("SC_RBX", rbx); + SC_OFFSET("SC_RCX", rcx); + SC_OFFSET("SC_RDX", rdx); + SC_OFFSET("SC_RSI", rsi); + SC_OFFSET("SC_RDI", rdi); + SC_OFFSET("SC_RBP", rbp); + SC_OFFSET("SC_RAX", rax); + SC_OFFSET("SC_R8", r8); + SC_OFFSET("SC_R9", r9); + SC_OFFSET("SC_R10", r10); + SC_OFFSET("SC_R11", r11); + SC_OFFSET("SC_R12", r12); + SC_OFFSET("SC_R13", r13); + SC_OFFSET("SC_R14", r14); + SC_OFFSET("SC_R15", r15); + SC_OFFSET("SC_IP", rip); + SC_OFFSET("SC_SP", rsp); + SC_OFFSET("SC_CR2", cr2); + SC_OFFSET("SC_ERR", err); + SC_OFFSET("SC_TRAPNO", trapno); + SC_OFFSET("SC_CS", cs); + SC_OFFSET("SC_FS", fs); + SC_OFFSET("SC_GS", gs); + SC_OFFSET("SC_EFLAGS", eflags); + SC_OFFSET("SC_SIGMASK", oldmask); +#if 0 + SC_OFFSET("SC_ORIG_RAX", orig_rax); + SC_OFFSET("SC_DS", ds); + SC_OFFSET("SC_ES", es); + SC_OFFSET("SC_SS", ss); +#endif + return(0); +} diff --git a/arch/um/sys-x86_64/util/mk_thread_kern.c b/arch/um/sys-x86_64/util/mk_thread_kern.c new file mode 100644 index 000000000000..a281673f02b2 --- /dev/null +++ b/arch/um/sys-x86_64/util/mk_thread_kern.c @@ -0,0 +1,21 @@ +#include "linux/config.h" +#include "linux/stddef.h" +#include "linux/sched.h" + +extern void print_head(void); +extern void print_constant_ptr(char *name, int value); +extern void print_constant(char *name, char *type, int value); +extern void print_tail(void); + +#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field) + +int main(int argc, char **argv) +{ + print_head(); +#ifdef CONFIG_MODE_TT + print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid)); +#endif + print_tail(); + return(0); +} + diff --git a/arch/um/sys-x86_64/util/mk_thread_user.c b/arch/um/sys-x86_64/util/mk_thread_user.c new file mode 100644 index 000000000000..7989725568b8 --- /dev/null +++ b/arch/um/sys-x86_64/util/mk_thread_user.c @@ -0,0 +1,30 @@ +#include + +void print_head(void) +{ + printf("/*\n"); + printf(" * Generated by mk_thread\n"); + printf(" */\n"); + printf("\n"); + printf("#ifndef __UM_THREAD_H\n"); + printf("#define __UM_THREAD_H\n"); + printf("\n"); +} + +void print_constant_ptr(char *name, int value) +{ + printf("#define %s(task) ((unsigned long *) " + "&(((char *) (task))[%d]))\n", name, value); +} + +void print_constant(char *name, char *type, int value) +{ + printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type, + value); +} + +void print_tail(void) +{ + printf("\n"); + printf("#endif\n"); +} diff --git a/include/asm-um/apic.h b/include/asm-um/apic.h new file mode 100644 index 000000000000..876dee84ab11 --- /dev/null +++ b/include/asm-um/apic.h @@ -0,0 +1,4 @@ +#ifndef __UM_APIC_H +#define __UM_APIC_H + +#endif diff --git a/include/asm-um/module-x86_64.h b/include/asm-um/module-x86_64.h new file mode 100644 index 000000000000..35b5491d3e96 --- /dev/null +++ b/include/asm-um/module-x86_64.h @@ -0,0 +1,30 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __UM_MODULE_X86_64_H +#define __UM_MODULE_X86_64_H + +/* UML is simple */ +struct mod_arch_specific +{ +}; + +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Ehdr Elf64_Ehdr + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/pda.h b/include/asm-um/pda.h new file mode 100644 index 000000000000..0d8bf33ffd42 --- /dev/null +++ b/include/asm-um/pda.h @@ -0,0 +1,31 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __UM_PDA_X86_64_H +#define __UM_PDA_X86_64_H + +/* XXX */ +struct foo { + unsigned int __softirq_pending; + unsigned int __nmi_count; +}; + +extern struct foo me; + +#define read_pda(me) (&me) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/prctl.h b/include/asm-um/prctl.h new file mode 100644 index 000000000000..64b6d099bdd5 --- /dev/null +++ b/include/asm-um/prctl.h @@ -0,0 +1,6 @@ +#ifndef __UM_PRCTL_H +#define __UM_PRCTL_H + +#include "asm/arch/prctl.h" + +#endif diff --git a/include/asm-um/processor-x86_64.h b/include/asm-um/processor-x86_64.h new file mode 100644 index 000000000000..0b8d4e2d8efc --- /dev/null +++ b/include/asm-um/processor-x86_64.h @@ -0,0 +1,33 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __UM_PROCESSOR_X86_64_H +#define __UM_PROCESSOR_X86_64_H + +#include "asm/arch/user.h" + +struct arch_thread { +}; + +#define INIT_ARCH_THREAD { } + +#define current_text_addr() \ + ({ void *pc; __asm__("movq $1f,%0\n1:":"=g" (pc)); pc; }) + +#include "asm/processor-generic.h" + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/sigcontext-x86_64.h b/include/asm-um/sigcontext-x86_64.h new file mode 100644 index 000000000000..b600e0b01e48 --- /dev/null +++ b/include/asm-um/sigcontext-x86_64.h @@ -0,0 +1,22 @@ +/* Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __UM_SIGCONTEXT_X86_64_H +#define __UM_SIGCONTEXT_X86_64_H + +#include "asm/sigcontext-generic.h" + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/system-x86_64.h b/include/asm-um/system-x86_64.h new file mode 100644 index 000000000000..e1b61b580734 --- /dev/null +++ b/include/asm-um/system-x86_64.h @@ -0,0 +1,23 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __UM_SYSTEM_X86_64_H +#define __UM_SYSTEM_X86_64_H + +#include "asm/system-generic.h" + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/vm-flags-x86_64.h b/include/asm-um/vm-flags-x86_64.h index e04e92d64858..3213edfa7888 100644 --- a/include/asm-um/vm-flags-x86_64.h +++ b/include/asm-um/vm-flags-x86_64.h @@ -17,11 +17,17 @@ extern unsigned long vm_stack_flags, vm_stack_flags32; extern unsigned long vm_data_default_flags, vm_data_default_flags32; extern unsigned long vm_force_exec32; +#ifdef TIF_IA32 #define VM_DATA_DEFAULT_FLAGS \ (test_thread_flag(TIF_IA32) ? vm_data_default_flags32 : \ vm_data_default_flags) #define VM_STACK_DEFAULT_FLAGS \ (test_thread_flag(TIF_IA32) ? vm_stack_flags32 : vm_stack_flags) +#endif + +#define VM_DATA_DEFAULT_FLAGS vm_data_default_flags + +#define VM_STACK_DEFAULT_FLAGS vm_stack_flags #endif -- cgit v1.2.3 From 104d88dfb8ab4ea3ff022873281abaca28e6bc04 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 11 Jan 2005 03:13:00 -0800 Subject: [PATCH] UML: x86_64 ptrace support This adds the x86_64 ptrace support. It also cleans up the existing code somewhat, eliminating a couple of simple header files, and generalizing the mk_ptregs buils to accomodate multiple architectures. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/sysdep-i386/ptrace.h | 45 ++++- arch/um/include/sysdep-x86_64/ptrace.h | 260 ++++++++++++++++++++++++++++ arch/um/include/sysdep-x86_64/ptrace_user.h | 69 ++++++++ arch/um/kernel/ptrace.c | 1 + arch/um/kernel/skas/Makefile | 2 - arch/um/kernel/skas/include/ptrace-skas.h | 57 ------ arch/um/kernel/skas/util/Makefile | 2 + arch/um/kernel/skas/util/mk_ptregs-i386.c | 51 ++++++ arch/um/kernel/skas/util/mk_ptregs-x86_64.c | 68 ++++++++ arch/um/kernel/skas/util/mk_ptregs.c | 51 ------ arch/um/kernel/tt/include/ptrace-tt.h | 26 --- arch/um/sys-i386/ldt.c | 2 + arch/um/sys-x86_64/Makefile | 6 +- arch/um/sys-x86_64/ptrace.c | 138 +++++++++++++++ arch/um/sys-x86_64/ptrace_user.c | 64 +++++++ include/asm-um/ptrace-generic.h | 1 - include/asm-um/ptrace-x86_64.h | 75 ++++++++ 17 files changed, 776 insertions(+), 142 deletions(-) create mode 100644 arch/um/include/sysdep-x86_64/ptrace.h create mode 100644 arch/um/include/sysdep-x86_64/ptrace_user.h delete mode 100644 arch/um/kernel/skas/include/ptrace-skas.h create mode 100644 arch/um/kernel/skas/util/mk_ptregs-i386.c create mode 100644 arch/um/kernel/skas/util/mk_ptregs-x86_64.c delete mode 100644 arch/um/kernel/skas/util/mk_ptregs.c delete mode 100644 arch/um/kernel/tt/include/ptrace-tt.h create mode 100644 arch/um/sys-x86_64/ptrace.c create mode 100644 arch/um/sys-x86_64/ptrace_user.c create mode 100644 include/asm-um/ptrace-x86_64.h (limited to 'include') diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h index fc8e4f314ca6..dc126e5e25ac 100644 --- a/arch/um/include/sysdep-i386/ptrace.h +++ b/arch/um/include/sysdep-i386/ptrace.h @@ -9,11 +9,52 @@ #include "uml-config.h" #ifdef UML_CONFIG_MODE_TT -#include "ptrace-tt.h" +#include "sysdep/sc.h" #endif #ifdef UML_CONFIG_MODE_SKAS -#include "ptrace-skas.h" + +/* syscall emulation path in ptrace */ + +#ifndef PTRACE_SYSEMU +#define PTRACE_SYSEMU 31 +#endif + +void set_using_sysemu(int value); +int get_using_sysemu(void); +extern int sysemu_supported; + +#include "skas_ptregs.h" + +#define HOST_FRAME_SIZE 17 + +#define REGS_IP(r) ((r)[HOST_IP]) +#define REGS_SP(r) ((r)[HOST_SP]) +#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) +#define REGS_EAX(r) ((r)[HOST_EAX]) +#define REGS_EBX(r) ((r)[HOST_EBX]) +#define REGS_ECX(r) ((r)[HOST_ECX]) +#define REGS_EDX(r) ((r)[HOST_EDX]) +#define REGS_ESI(r) ((r)[HOST_ESI]) +#define REGS_EDI(r) ((r)[HOST_EDI]) +#define REGS_EBP(r) ((r)[HOST_EBP]) +#define REGS_CS(r) ((r)[HOST_CS]) +#define REGS_SS(r) ((r)[HOST_SS]) +#define REGS_DS(r) ((r)[HOST_DS]) +#define REGS_ES(r) ((r)[HOST_ES]) +#define REGS_FS(r) ((r)[HOST_FS]) +#define REGS_GS(r) ((r)[HOST_GS]) + +#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res) + +#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) + +#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type) + +#define REGS_FAULT_ADDR(r) ((r)->fault_addr) + +#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type) + #endif #ifndef PTRACE_SYSEMU_SINGLESTEP #define PTRACE_SYSEMU_SINGLESTEP 32 diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h new file mode 100644 index 000000000000..64b1cc16752d --- /dev/null +++ b/arch/um/include/sysdep-x86_64/ptrace.h @@ -0,0 +1,260 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __SYSDEP_X86_64_PTRACE_H +#define __SYSDEP_X86_64_PTRACE_H + +#include "uml-config.h" + +#ifdef UML_CONFIG_MODE_TT +#include "sysdep/sc.h" +#endif + +#ifdef UML_CONFIG_MODE_SKAS +#include "skas_ptregs.h" + +#define REGS_IP(r) ((r)[HOST_IP]) +#define REGS_SP(r) ((r)[HOST_SP]) + +#define REGS_RBX(r) ((r)[HOST_RBX]) +#define REGS_RCX(r) ((r)[HOST_RCX]) +#define REGS_RDX(r) ((r)[HOST_RDX]) +#define REGS_RSI(r) ((r)[HOST_RSI]) +#define REGS_RDI(r) ((r)[HOST_RDI]) +#define REGS_RBP(r) ((r)[HOST_RBP]) +#define REGS_RAX(r) ((r)[HOST_RAX]) +#define REGS_R8(r) ((r)[HOST_R8]) +#define REGS_R9(r) ((r)[HOST_R9]) +#define REGS_R10(r) ((r)[HOST_R10]) +#define REGS_R11(r) ((r)[HOST_R11]) +#define REGS_R12(r) ((r)[HOST_R12]) +#define REGS_R13(r) ((r)[HOST_R13]) +#define REGS_R14(r) ((r)[HOST_R14]) +#define REGS_R15(r) ((r)[HOST_R15]) +#define REGS_CS(r) ((r)[HOST_CS]) +#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) +#define REGS_SS(r) ((r)[HOST_SS]) + +#define HOST_FS_BASE 21 +#define HOST_GS_BASE 22 +#define HOST_DS 23 +#define HOST_ES 24 +#define HOST_FS 25 +#define HOST_GS 26 + +#define REGS_FS_BASE(r) ((r)[HOST_FS_BASE]) +#define REGS_GS_BASE(r) ((r)[HOST_GS_BASE]) +#define REGS_DS(r) ((r)[HOST_DS]) +#define REGS_ES(r) ((r)[HOST_ES]) +#define REGS_FS(r) ((r)[HOST_FS]) +#define REGS_GS(r) ((r)[HOST_GS]) + +#define REGS_ORIG_RAX(r) ((r)[HOST_ORIG_RAX]) + +#define REGS_SET_SYSCALL_RETURN(r, res) REGS_RAX(r) = (res) + +#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) + +#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type) + +#define REGS_FAULT_ADDR(r) ((r)->fault_addr) + +#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type) + +#define REGS_TRAP(r) ((r)->trap_type) + +#define REGS_ERR(r) ((r)->fault_type) + +#endif + +#include "choose-mode.h" + +/* XXX */ +union uml_pt_regs { +#ifdef UML_CONFIG_MODE_TT + struct tt_regs { + long syscall; + unsigned long orig_rax; + void *sc; + } tt; +#endif +#ifdef UML_CONFIG_MODE_SKAS + struct skas_regs { + /* XXX */ + unsigned long regs[27]; + unsigned long fp[65]; + unsigned long fault_addr; + unsigned long fault_type; + unsigned long trap_type; + long syscall; + int is_user; + } skas; +#endif +}; + +#define EMPTY_UML_PT_REGS { } + +/* XXX */ +extern int mode_tt; + +#define UPT_RBX(r) CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs)) +#define UPT_RCX(r) CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs)) +#define UPT_RDX(r) CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs)) +#define UPT_RSI(r) CHOOSE_MODE(SC_RSI(UPT_SC(r)), REGS_RSI((r)->skas.regs)) +#define UPT_RDI(r) CHOOSE_MODE(SC_RDI(UPT_SC(r)), REGS_RDI((r)->skas.regs)) +#define UPT_RBP(r) CHOOSE_MODE(SC_RBP(UPT_SC(r)), REGS_RBP((r)->skas.regs)) +#define UPT_RAX(r) CHOOSE_MODE(SC_RAX(UPT_SC(r)), REGS_RAX((r)->skas.regs)) +#define UPT_R8(r) CHOOSE_MODE(SC_R8(UPT_SC(r)), REGS_R8((r)->skas.regs)) +#define UPT_R9(r) CHOOSE_MODE(SC_R9(UPT_SC(r)), REGS_R9((r)->skas.regs)) +#define UPT_R10(r) CHOOSE_MODE(SC_R10(UPT_SC(r)), REGS_R10((r)->skas.regs)) +#define UPT_R11(r) CHOOSE_MODE(SC_R11(UPT_SC(r)), REGS_R11((r)->skas.regs)) +#define UPT_R12(r) CHOOSE_MODE(SC_R12(UPT_SC(r)), REGS_R12((r)->skas.regs)) +#define UPT_R13(r) CHOOSE_MODE(SC_R13(UPT_SC(r)), REGS_R13((r)->skas.regs)) +#define UPT_R14(r) CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs)) +#define UPT_R15(r) CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs)) +#define UPT_CS(r) CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs)) +#define UPT_FS(r) CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs)) +#define UPT_GS(r) CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs)) +#define UPT_DS(r) CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs)) +#define UPT_ES(r) CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs)) +#define UPT_CS(r) CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs)) +#define UPT_ORIG_RAX(r) \ + CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs)) + +#define UPT_IP(r) CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs)) +#define UPT_SP(r) CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs)) + +#define UPT_EFLAGS(r) \ + CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs)) +#define UPT_SC(r) ((r)->tt.sc) +#define UPT_SYSCALL_NR(r) CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall) + +extern int user_context(unsigned long sp); + +#define UPT_IS_USER(r) \ + CHOOSE_MODE(user_context(UPT_SP(r)), (r)->skas.is_user) + +#define UPT_SYSCALL_ARG1(r) UPT_RDI(r) +#define UPT_SYSCALL_ARG2(r) UPT_RSI(r) +#define UPT_SYSCALL_ARG3(r) UPT_RDX(r) +#define UPT_SYSCALL_ARG4(r) UPT_R10(r) +#define UPT_SYSCALL_ARG5(r) UPT_R8(r) +#define UPT_SYSCALL_ARG6(r) UPT_R9(r) + +struct syscall_args { + unsigned long args[6]; +}; + +#define SYSCALL_ARGS(r) ((struct syscall_args) \ + { .args = { UPT_SYSCALL_ARG1(r), \ + UPT_SYSCALL_ARG2(r), \ + UPT_SYSCALL_ARG3(r), \ + UPT_SYSCALL_ARG4(r), \ + UPT_SYSCALL_ARG5(r), \ + UPT_SYSCALL_ARG6(r) } } ) + +#define UPT_REG(regs, reg) \ + ({ unsigned long val; \ + switch(reg){ \ + case R8: val = UPT_R8(regs); break; \ + case R9: val = UPT_R9(regs); break; \ + case R10: val = UPT_R10(regs); break; \ + case R11: val = UPT_R11(regs); break; \ + case R12: val = UPT_R12(regs); break; \ + case R13: val = UPT_R13(regs); break; \ + case R14: val = UPT_R14(regs); break; \ + case R15: val = UPT_R15(regs); break; \ + case RIP: val = UPT_IP(regs); break; \ + case RSP: val = UPT_SP(regs); break; \ + case RAX: val = UPT_RAX(regs); break; \ + case RBX: val = UPT_RBX(regs); break; \ + case RCX: val = UPT_RCX(regs); break; \ + case RDX: val = UPT_RDX(regs); break; \ + case RSI: val = UPT_RSI(regs); break; \ + case RDI: val = UPT_RDI(regs); break; \ + case RBP: val = UPT_RBP(regs); break; \ + case ORIG_RAX: val = UPT_ORIG_RAX(regs); break; \ + case CS: val = UPT_CS(regs); break; \ + case DS: val = UPT_DS(regs); break; \ + case ES: val = UPT_ES(regs); break; \ + case FS: val = UPT_FS(regs); break; \ + case GS: val = UPT_GS(regs); break; \ + case EFLAGS: val = UPT_EFLAGS(regs); break; \ + default : \ + panic("Bad register in UPT_REG : %d\n", reg); \ + val = -1; \ + } \ + val; \ + }) + + +#define UPT_SET(regs, reg, val) \ + ({ unsigned long val; \ + switch(reg){ \ + case R8: UPT_R8(regs) = val; break; \ + case R9: UPT_R9(regs) = val; break; \ + case R10: UPT_R10(regs) = val; break; \ + case R11: UPT_R11(regs) = val; break; \ + case R12: UPT_R12(regs) = val; break; \ + case R13: UPT_R13(regs) = val; break; \ + case R14: UPT_R14(regs) = val; break; \ + case R15: UPT_R15(regs) = val; break; \ + case RIP: UPT_IP(regs) = val; break; \ + case RSP: UPT_SP(regs) = val; break; \ + case RAX: UPT_RAX(regs) = val; break; \ + case RBX: UPT_RBX(regs) = val; break; \ + case RCX: UPT_RCX(regs) = val; break; \ + case RDX: UPT_RDX(regs) = val; break; \ + case RSI: UPT_RSI(regs) = val; break; \ + case RDI: UPT_RDI(regs) = val; break; \ + case RBP: UPT_RBP(regs) = val; break; \ + case ORIG_RAX: UPT_ORIG_RAX(regs) = val; break; \ + case CS: UPT_CS(regs) = val; break; \ + case DS: UPT_DS(regs) = val; break; \ + case ES: UPT_ES(regs) = val; break; \ + case FS: UPT_FS(regs) = val; break; \ + case GS: UPT_GS(regs) = val; break; \ + case EFLAGS: UPT_EFLAGS(regs) = val; break; \ + default : \ + panic("Bad register in UPT_SET : %d\n", reg); \ + break; \ + } \ + val; \ + }) + +#define UPT_SET_SYSCALL_RETURN(r, res) \ + CHOOSE_MODE(SC_SET_SYSCALL_RETURN(UPT_SC(r), (res)), \ + REGS_SET_SYSCALL_RETURN((r)->skas.regs, (res))) + +#define UPT_RESTART_SYSCALL(r) \ + CHOOSE_MODE(SC_RESTART_SYSCALL(UPT_SC(r)), \ + REGS_RESTART_SYSCALL((r)->skas.regs)) + +#define UPT_SEGV_IS_FIXABLE(r) \ + CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \ + REGS_SEGV_IS_FIXABLE(&r->skas)) + +#define UPT_FAULT_ADDR(r) \ + CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas)) + +#define UPT_FAULT_WRITE(r) \ + CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas)) + +#define UPT_TRAP(r) CHOOSE_MODE(SC_TRAP_TYPE(UPT_SC(r)), REGS_TRAP(&r->skas)) +#define UPT_ERR(r) CHOOSE_MODE(SC_FAULT_TYPE(UPT_SC(r)), REGS_ERR(&r->skas)) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h new file mode 100644 index 000000000000..a7bb52bbe624 --- /dev/null +++ b/arch/um/include/sysdep-x86_64/ptrace_user.h @@ -0,0 +1,69 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __SYSDEP_X86_64_PTRACE_USER_H__ +#define __SYSDEP_X86_64_PTRACE_USER_H__ + +#define __FRAME_OFFSETS +#include +#undef __FRAME_OFFSETS + +#define PT_INDEX(off) ((off) / sizeof(unsigned long)) + +#define PT_SYSCALL_NR(regs) ((regs)[PT_INDEX(ORIG_RAX)]) +#define PT_SYSCALL_NR_OFFSET (ORIG_RAX) + +#define PT_SYSCALL_ARG1(regs) (((unsigned long *) (regs))[PT_INDEX(RDI)]) +#define PT_SYSCALL_ARG1_OFFSET (RDI) + +#define PT_SYSCALL_ARG2(regs) (((unsigned long *) (regs))[PT_INDEX(RSI)]) +#define PT_SYSCALL_ARG2_OFFSET (RSI) + +#define PT_SYSCALL_ARG3(regs) (((unsigned long *) (regs))[PT_INDEX(RDX)]) +#define PT_SYSCALL_ARG3_OFFSET (RDX) + +#define PT_SYSCALL_ARG4(regs) (((unsigned long *) (regs))[PT_INDEX(RCX)]) +#define PT_SYSCALL_ARG4_OFFSET (RCX) + +#define PT_SYSCALL_ARG5(regs) (((unsigned long *) (regs))[PT_INDEX(R8)]) +#define PT_SYSCALL_ARG5_OFFSET (R8) + +#define PT_SYSCALL_ARG6(regs) (((unsigned long *) (regs))[PT_INDEX(R9)]) +#define PT_SYSCALL_ARG6_OFFSET (R9) + +#define PT_SYSCALL_RET_OFFSET (RAX) + +#define PT_IP_OFFSET (RIP) +#define PT_IP(regs) ((regs)[PT_INDEX(RIP)]) + +#define PT_SP_OFFSET (RSP) +#define PT_SP(regs) ((regs)[PT_INDEX(RSP)]) + +#define PT_ORIG_RAX_OFFSET (ORIG_RAX) +#define PT_ORIG_RAX(regs) ((regs)[PT_INDEX(ORIG_RAX)]) + +#define MAX_REG_OFFSET (FRAME_SIZE) +#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long)) + +/* x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though + * it's defined in the kernel's include/linux/ptrace.h + */ +#ifndef PTRACE_SETOPTIONS +#define PTRACE_SETOPTIONS 0x4200 +#endif + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index daf1cb54d023..be56a8f103d7 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -16,6 +16,7 @@ #include "asm/uaccess.h" #include "kern_util.h" #include "ptrace_user.h" +#include "skas_ptrace.h" /* * Called by kernel/ptrace.c when detaching.. diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index d7b61cba9448..c340c9cbf19b 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -6,8 +6,6 @@ obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \ -subdir-y := util - USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) diff --git a/arch/um/kernel/skas/include/ptrace-skas.h b/arch/um/kernel/skas/include/ptrace-skas.h deleted file mode 100644 index f5c5268cc492..000000000000 --- a/arch/um/kernel/skas/include/ptrace-skas.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __PTRACE_SKAS_H -#define __PTRACE_SKAS_H - -#include "uml-config.h" - -#ifdef UML_CONFIG_MODE_SKAS - -#include "skas_ptregs.h" - -#define HOST_FRAME_SIZE 17 - -#define REGS_IP(r) ((r)[HOST_IP]) -#define REGS_SP(r) ((r)[HOST_SP]) -#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) -#define REGS_EAX(r) ((r)[HOST_EAX]) -#define REGS_EBX(r) ((r)[HOST_EBX]) -#define REGS_ECX(r) ((r)[HOST_ECX]) -#define REGS_EDX(r) ((r)[HOST_EDX]) -#define REGS_ESI(r) ((r)[HOST_ESI]) -#define REGS_EDI(r) ((r)[HOST_EDI]) -#define REGS_EBP(r) ((r)[HOST_EBP]) -#define REGS_CS(r) ((r)[HOST_CS]) -#define REGS_SS(r) ((r)[HOST_SS]) -#define REGS_DS(r) ((r)[HOST_DS]) -#define REGS_ES(r) ((r)[HOST_ES]) -#define REGS_FS(r) ((r)[HOST_FS]) -#define REGS_GS(r) ((r)[HOST_GS]) - -#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res) - -#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) - -#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type) - -#define REGS_FAULT_ADDR(r) ((r)->fault_addr) - -#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type) - -#endif - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile index a26e0c34a762..17f5909d60f7 100644 --- a/arch/um/kernel/skas/util/Makefile +++ b/arch/um/kernel/skas/util/Makefile @@ -1,2 +1,4 @@ hostprogs-y := mk_ptregs always := $(hostprogs-y) + +mk_ptregs-objs := mk_ptregs-$(SUBARCH).o diff --git a/arch/um/kernel/skas/util/mk_ptregs-i386.c b/arch/um/kernel/skas/util/mk_ptregs-i386.c new file mode 100644 index 000000000000..0788dd05bcac --- /dev/null +++ b/arch/um/kernel/skas/util/mk_ptregs-i386.c @@ -0,0 +1,51 @@ +#include +#include +#include + +#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val)) + +int main(int argc, char **argv) +{ + printf("/* Automatically generated by " + "arch/um/kernel/skas/util/mk_ptregs */\n"); + printf("\n"); + printf("#ifndef __SKAS_PT_REGS_\n"); + printf("#define __SKAS_PT_REGS_\n"); + printf("\n"); + printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE); + printf("#define HOST_FP_SIZE %d\n", + sizeof(struct user_i387_struct) / sizeof(unsigned long)); + printf("#define HOST_XFP_SIZE %d\n", + sizeof(struct user_fxsr_struct) / sizeof(unsigned long)); + + PRINT_REG("IP", EIP); + PRINT_REG("SP", UESP); + PRINT_REG("EFLAGS", EFL); + PRINT_REG("EAX", EAX); + PRINT_REG("EBX", EBX); + PRINT_REG("ECX", ECX); + PRINT_REG("EDX", EDX); + PRINT_REG("ESI", ESI); + PRINT_REG("EDI", EDI); + PRINT_REG("EBP", EBP); + PRINT_REG("CS", CS); + PRINT_REG("SS", SS); + PRINT_REG("DS", DS); + PRINT_REG("FS", FS); + PRINT_REG("ES", ES); + PRINT_REG("GS", GS); + printf("\n"); + printf("#endif\n"); + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c new file mode 100644 index 000000000000..67aee92a70ef --- /dev/null +++ b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c @@ -0,0 +1,68 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include +#define __FRAME_OFFSETS +#include + +#define PRINT_REG(name, val) \ + printf("#define HOST_%s (%d / sizeof(unsigned long))\n", (name), (val)) + +int main(int argc, char **argv) +{ + printf("/* Automatically generated by " + "arch/um/kernel/skas/util/mk_ptregs */\n"); + printf("\n"); + printf("#ifndef __SKAS_PT_REGS_\n"); + printf("#define __SKAS_PT_REGS_\n"); + printf("#define HOST_FRAME_SIZE (%d / sizeof(unsigned long))\n", + FRAME_SIZE); + PRINT_REG("RBX", RBX); + PRINT_REG("RCX", RCX); + PRINT_REG("RDI", RDI); + PRINT_REG("RSI", RSI); + PRINT_REG("RDX", RDX); + PRINT_REG("RBP", RBP); + PRINT_REG("RAX", RAX); + PRINT_REG("R8", R8); + PRINT_REG("R9", R9); + PRINT_REG("R10", R10); + PRINT_REG("R11", R11); + PRINT_REG("R12", R12); + PRINT_REG("R13", R13); + PRINT_REG("R14", R14); + PRINT_REG("R15", R15); + PRINT_REG("ORIG_RAX", ORIG_RAX); + PRINT_REG("CS", CS); + PRINT_REG("SS", SS); + PRINT_REG("EFLAGS", EFLAGS); +#if 0 + PRINT_REG("FS", FS); + PRINT_REG("GS", GS); + PRINT_REG("DS", DS); + PRINT_REG("ES", ES); +#endif + + PRINT_REG("IP", RIP); + PRINT_REG("SP", RSP); + printf("#define HOST_FP_SIZE 0\n"); + printf("#define HOST_XFP_SIZE 0\n"); + printf("\n"); + printf("\n"); + printf("#endif\n"); + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/util/mk_ptregs.c b/arch/um/kernel/skas/util/mk_ptregs.c deleted file mode 100644 index 116f74d2c334..000000000000 --- a/arch/um/kernel/skas/util/mk_ptregs.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include - -#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val)) - -int main(int argc, char **argv) -{ - printf("/* Automatically generated by " - "arch/um/kernel/skas/util/mk_ptregs */\n"); - printf("\n"); - printf("#ifndef __SKAS_PT_REGS_\n"); - printf("#define __SKAS_PT_REGS_\n"); - printf("\n"); - printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE); - printf("#define HOST_FP_SIZE %d\n", - sizeof(struct user_i387_struct) / sizeof(unsigned long)); - printf("#define HOST_XFP_SIZE %d\n", - sizeof(struct user_fxsr_struct) / sizeof(unsigned long)); - - PRINT_REG("IP", EIP); - PRINT_REG("SP", UESP); - PRINT_REG("EFLAGS", EFL); - PRINT_REG("EAX", EAX); - PRINT_REG("EBX", EBX); - PRINT_REG("ECX", ECX); - PRINT_REG("EDX", EDX); - PRINT_REG("ESI", ESI); - PRINT_REG("EDI", EDI); - PRINT_REG("EBP", EBP); - PRINT_REG("CS", CS); - PRINT_REG("SS", SS); - PRINT_REG("DS", DS); - PRINT_REG("FS", FS); - PRINT_REG("ES", ES); - PRINT_REG("GS", GS); - printf("\n"); - printf("#endif\n"); - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/include/ptrace-tt.h b/arch/um/kernel/tt/include/ptrace-tt.h deleted file mode 100644 index 3084c1db8678..000000000000 --- a/arch/um/kernel/tt/include/ptrace-tt.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __PTRACE_TT_H -#define __PTRACE_TT_H - -#include "uml-config.h" - -#ifdef UML_CONFIG_MODE_TT -#include "sysdep/sc.h" -#endif - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index ba77ccaa8361..98d7691980b2 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -25,6 +25,8 @@ int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) #ifdef CONFIG_MODE_SKAS extern int userspace_pid; +#include "skas_ptrace.h" + int sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) { struct ptrace_ldt ldt; diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 0859685f511a..81e165903570 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -5,10 +5,10 @@ # lib-y = bitops.o bugs.o csum-partial.o fault.o mem.o memcpy.o \ - ptrace.o semaphore.o sigcontext.o signal.o syscalls.o \ - sysrq.o thunk.o + ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \ + syscalls.o sysrq.o thunk.o -USER_OBJS := sigcontext.o +USER_OBJS := ptrace_user.o sigcontext.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \ diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c new file mode 100644 index 000000000000..8c146b2a1e00 --- /dev/null +++ b/arch/um/sys-x86_64/ptrace.c @@ -0,0 +1,138 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#define __FRAME_OFFSETS +#include "asm/ptrace.h" +#include "linux/sched.h" +#include "linux/errno.h" +#include "asm/elf.h" + +/* XXX x86_64 */ +unsigned long not_ss; +unsigned long not_ds; +unsigned long not_es; + +#define SC_SS(r) (not_ss) +#define SC_DS(r) (not_ds) +#define SC_ES(r) (not_es) + +/* determines which flags the user has access to. */ +/* 1 = access 0 = no access */ +#define FLAG_MASK 0x44dd5UL + +int putreg(struct task_struct *child, int regno, unsigned long value) +{ + unsigned long tmp; + +#ifdef TIF_IA32 + /* Some code in the 64bit emulation may not be 64bit clean. + Don't take any chances. */ + if (test_tsk_thread_flag(child, TIF_IA32)) + value &= 0xffffffff; +#endif + switch (regno){ + case FS: + case GS: + case DS: + case ES: + case SS: + case CS: + if (value && (value & 3) != 3) + return -EIO; + value &= 0xffff; + break; + + case FS_BASE: + case GS_BASE: + if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) + return -EIO; + break; + + case EFLAGS: + value &= FLAG_MASK; + tmp = PT_REGS_EFLAGS(&child->thread.regs) & ~FLAG_MASK; + value |= tmp; + break; + } + + PT_REGS_SET(&child->thread.regs, regno, value); + return 0; +} + +unsigned long getreg(struct task_struct *child, int regno) +{ + unsigned long retval = ~0UL; + switch (regno) { + case FS: + case GS: + case DS: + case ES: + case SS: + case CS: + retval = 0xffff; + /* fall through */ + default: + retval &= PT_REG(&child->thread.regs, regno); +#ifdef TIF_IA32 + if (test_tsk_thread_flag(child, TIF_IA32)) + retval &= 0xffffffff; +#endif + } + return retval; +} + +void arch_switch(void) +{ +/* XXX + printk("arch_switch\n"); +*/ +} + +int is_syscall(unsigned long addr) +{ + panic("is_syscall"); +} + +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) +{ + panic("dump_fpu"); + return(1); +} + +int get_fpregs(unsigned long buf, struct task_struct *child) +{ + panic("get_fpregs"); + return(0); +} + +int set_fpregs(unsigned long buf, struct task_struct *child) +{ + panic("set_fpregs"); + return(0); +} + +int get_fpxregs(unsigned long buf, struct task_struct *tsk) +{ + panic("get_fpxregs"); + return(0); +} + +int set_fpxregs(unsigned long buf, struct task_struct *tsk) +{ + panic("set_fxpregs"); + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/ptrace_user.c b/arch/um/sys-x86_64/ptrace_user.c new file mode 100644 index 000000000000..e1f8bacc5f1a --- /dev/null +++ b/arch/um/sys-x86_64/ptrace_user.c @@ -0,0 +1,64 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include +#include +#define __FRAME_OFFSETS +#include +#include +#include "user.h" +#include "kern_constants.h" + +int ptrace_getregs(long pid, unsigned long *regs_out) +{ + if(ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) + return(-errno); + return(0); +} + +int ptrace_setregs(long pid, unsigned long *regs) +{ + if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) + return(-errno); + return(0); +} + +void ptrace_pokeuser(unsigned long addr, unsigned long data) +{ + panic("ptrace_pokeuser"); +} + +#define DS 184 +#define ES 192 +#define __USER_DS 0x2b + +void arch_enter_kernel(void *task, int pid) +{ +} + +void arch_leave_kernel(void *task, int pid) +{ +#ifdef UM_USER_CS + if(ptrace(PTRACE_POKEUSER, pid, CS, UM_USER_CS) < 0) + tracer_panic("POKEUSER CS failed"); +#endif + + if(ptrace(PTRACE_POKEUSER, pid, DS, __USER_DS) < 0) + tracer_panic("POKEUSER DS failed"); + if(ptrace(PTRACE_POKEUSER, pid, ES, __USER_DS) < 0) + tracer_panic("POKEUSER ES failed"); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h index a1bb25f8e85b..0e187165cf02 100644 --- a/include/asm-um/ptrace-generic.h +++ b/include/asm-um/ptrace-generic.h @@ -21,7 +21,6 @@ #undef instruction_pointer #include "sysdep/ptrace.h" -#include "skas_ptrace.h" struct pt_regs { union uml_pt_regs regs; diff --git a/include/asm-um/ptrace-x86_64.h b/include/asm-um/ptrace-x86_64.h new file mode 100644 index 000000000000..c34be39b78b2 --- /dev/null +++ b/include/asm-um/ptrace-x86_64.h @@ -0,0 +1,75 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __UM_PTRACE_X86_64_H +#define __UM_PTRACE_X86_64_H + +#include "linux/compiler.h" + +#define signal_fault signal_fault_x86_64 +#define __FRAME_OFFSETS /* Needed to get the R* macros */ +#include "asm/ptrace-generic.h" +#undef signal_fault + +void signal_fault(struct pt_regs_subarch *regs, void *frame, char *where); + +#define FS_BASE (21 * sizeof(unsigned long)) +#define GS_BASE (22 * sizeof(unsigned long)) +#define DS (23 * sizeof(unsigned long)) +#define ES (24 * sizeof(unsigned long)) +#define FS (25 * sizeof(unsigned long)) +#define GS (26 * sizeof(unsigned long)) + +#define PT_REGS_RBX(r) UPT_RBX(&(r)->regs) +#define PT_REGS_RCX(r) UPT_RCX(&(r)->regs) +#define PT_REGS_RDX(r) UPT_RDX(&(r)->regs) +#define PT_REGS_RSI(r) UPT_RSI(&(r)->regs) +#define PT_REGS_RDI(r) UPT_RDI(&(r)->regs) +#define PT_REGS_RBP(r) UPT_RBP(&(r)->regs) +#define PT_REGS_RAX(r) UPT_RAX(&(r)->regs) +#define PT_REGS_R8(r) UPT_R8(&(r)->regs) +#define PT_REGS_R9(r) UPT_R9(&(r)->regs) +#define PT_REGS_R10(r) UPT_R10(&(r)->regs) +#define PT_REGS_R11(r) UPT_R11(&(r)->regs) +#define PT_REGS_R12(r) UPT_R12(&(r)->regs) +#define PT_REGS_R13(r) UPT_R13(&(r)->regs) +#define PT_REGS_R14(r) UPT_R14(&(r)->regs) +#define PT_REGS_R15(r) UPT_R15(&(r)->regs) + +#define PT_REGS_FS(r) UPT_FS(&(r)->regs) +#define PT_REGS_GS(r) UPT_GS(&(r)->regs) +#define PT_REGS_DS(r) UPT_DS(&(r)->regs) +#define PT_REGS_ES(r) UPT_ES(&(r)->regs) +#define PT_REGS_SS(r) UPT_SS(&(r)->regs) +#define PT_REGS_CS(r) UPT_CS(&(r)->regs) + +#define PT_REGS_ORIG_RAX(r) UPT_ORIG_RAX(&(r)->regs) +#define PT_REGS_RIP(r) UPT_IP(&(r)->regs) +#define PT_REGS_RSP(r) UPT_SP(&(r)->regs) + +#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs) + +/* XXX */ +#define user_mode(r) UPT_IS_USER(&(r)->regs) +#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_RAX(r) +#define PT_REGS_SYSCALL_RET(r) PT_REGS_RAX(r) + +#define PT_FIX_EXEC_STACK(sp) do ; while(0) + +#define profile_pc(regs) PT_REGS_IP(regs) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ -- cgit v1.2.3 From e08d84a7687bab59c762cca3a9008a4f1e18b591 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 11 Jan 2005 03:13:41 -0800 Subject: [PATCH] UML: Separate out the time code Move the i386 __delay to sys-i386 and add an implementation for x86_64. Also get rid of the definition of um_udelay_t. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/time_kern.c | 19 ++----------------- arch/um/sys-i386/Makefile | 2 +- arch/um/sys-i386/delay.c | 14 ++++++++++++++ arch/um/sys-x86_64/Makefile | 2 +- arch/um/sys-x86_64/delay.c | 26 ++++++++++++++++++++++++++ include/asm-um/archparam-i386.h | 4 ---- include/asm-um/archparam-ppc.h | 4 ---- 7 files changed, 44 insertions(+), 27 deletions(-) create mode 100644 arch/um/sys-i386/delay.c create mode 100644 arch/um/sys-x86_64/delay.c (limited to 'include') diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 498344110eee..3b538f6cc3ae 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -136,22 +136,7 @@ long um_stime(int * tptr) return 0; } -/* XXX Needs to be moved under sys-i386 */ -void __delay(um_udelay_t time) -{ - /* Stolen from the i386 __loop_delay */ - int d0; - __asm__ __volatile__( - "\tjmp 1f\n" - ".align 16\n" - "1:\tjmp 2f\n" - ".align 16\n" - "2:\tdecl %0\n\tjns 2b" - :"=&a" (d0) - :"0" (time)); -} - -void __udelay(um_udelay_t usecs) +void __udelay(unsigned long usecs) { int i, n; @@ -159,7 +144,7 @@ void __udelay(um_udelay_t usecs) for(i=0;i Date: Tue, 11 Jan 2005 03:13:55 -0800 Subject: [PATCH] UML: x86-64 headers Add a bunch of headers to include/asm-um to support x86_64. Also move some arch-specific things from generic files to x86-specific ones. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-um/archparam-i386.h | 7 +++++ include/asm-um/archparam-x86_64.h | 62 +++++++++++++++++++++++++++++++++++++++ include/asm-um/calling.h | 9 ++++++ include/asm-um/dwarf2.h | 11 +++++++ include/asm-um/elf.h | 5 ++++ include/asm-um/fixmap.h | 7 ----- 6 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 include/asm-um/archparam-x86_64.h create mode 100644 include/asm-um/calling.h create mode 100644 include/asm-um/dwarf2.h (limited to 'include') diff --git a/include/asm-um/archparam-i386.h b/include/asm-um/archparam-i386.h index 61de0d440cdc..5b5df118d9a5 100644 --- a/include/asm-um/archparam-i386.h +++ b/include/asm-um/archparam-i386.h @@ -65,6 +65,13 @@ extern unsigned long __kernel_vsyscall; #define VSYSCALL_BASE vsyscall_ehdr #define VSYSCALL_END vsyscall_end +/* + * This is the range that is readable by user mode, and things + * acting like user mode such as get_user_pages. + */ +#define FIXADDR_USER_START VSYSCALL_BASE +#define FIXADDR_USER_END VSYSCALL_END + /* * Architecture-neutral AT_ values in 0-17, leave some room * for more of them, start the x86-specific ones at 32. diff --git a/include/asm-um/archparam-x86_64.h b/include/asm-um/archparam-x86_64.h new file mode 100644 index 000000000000..96321c4892f1 --- /dev/null +++ b/include/asm-um/archparam-x86_64.h @@ -0,0 +1,62 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#ifndef __UM_ARCHPARAM_X86_64_H +#define __UM_ARCHPARAM_X86_64_H + +#include + +#define ELF_PLATFORM "x86_64" + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + +typedef unsigned long elf_greg_t; +typedef struct { } elf_fpregset_t; + +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_X86_64 + +#define ELF_PLAT_INIT(regs, load_addr) do { \ + PT_REGS_RBX(regs) = 0; \ + PT_REGS_RCX(regs) = 0; \ + PT_REGS_RDX(regs) = 0; \ + PT_REGS_RSI(regs) = 0; \ + PT_REGS_RDI(regs) = 0; \ + PT_REGS_RBP(regs) = 0; \ + PT_REGS_RAX(regs) = 0; \ + PT_REGS_R8(regs) = 0; \ + PT_REGS_R9(regs) = 0; \ + PT_REGS_R10(regs) = 0; \ + PT_REGS_R11(regs) = 0; \ + PT_REGS_R12(regs) = 0; \ + PT_REGS_R13(regs) = 0; \ + PT_REGS_R14(regs) = 0; \ + PT_REGS_R15(regs) = 0; \ +} while (0) + +#ifdef TIF_IA32 /* XXX */ + clear_thread_flag(TIF_IA32); +#endif + +/* No user-accessible fixmap addresses, i.e. vsyscall */ +#define FIXADDR_USER_START 0 +#define FIXADDR_USER_END 0 + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/calling.h b/include/asm-um/calling.h new file mode 100644 index 000000000000..0b2384cc99fd --- /dev/null +++ b/include/asm-um/calling.h @@ -0,0 +1,9 @@ +# Copyright 2003 - 2004 Pathscale, Inc +# Released under the GPL + +#ifndef __UM_CALLING_H /* XXX x86_64 */ +#define __UM_CALLING_H + +#include "asm/arch/calling.h" + +#endif diff --git a/include/asm-um/dwarf2.h b/include/asm-um/dwarf2.h new file mode 100644 index 000000000000..d1a02e762931 --- /dev/null +++ b/include/asm-um/dwarf2.h @@ -0,0 +1,11 @@ +/* Copyright 2003 - 2004 Pathscale, Inc + * Released under the GPL + */ + +/* Needed on x86_64 by thunk.S */ +#ifndef __UM_DWARF2_H +#define __UM_DWARF2_H + +#include "asm/arch/dwarf2.h" + +#endif diff --git a/include/asm-um/elf.h b/include/asm-um/elf.h index b689a770a83f..b3a7258f9971 100644 --- a/include/asm-um/elf.h +++ b/include/asm-um/elf.h @@ -1,6 +1,7 @@ #ifndef __UM_ELF_H #define __UM_ELF_H +#include "linux/config.h" #include "asm/archparam.h" extern long elf_aux_hwcap; @@ -12,7 +13,11 @@ extern long elf_aux_hwcap; #define elf_check_arch(x) (1) +#ifdef CONFIG_64_BIT +#define ELF_CLASS ELFCLASS64 +#else #define ELF_CLASS ELFCLASS32 +#endif #define USE_ELF_CORE_DUMP diff --git a/include/asm-um/fixmap.h b/include/asm-um/fixmap.h index 0fb5779088b0..900f3fbb9fab 100644 --- a/include/asm-um/fixmap.h +++ b/include/asm-um/fixmap.h @@ -64,13 +64,6 @@ extern unsigned long get_kmem_end(void); #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) #define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) -/* - * This is the range that is readable by user mode, and things - * acting like user mode such as get_user_pages. - */ -#define FIXADDR_USER_START VSYSCALL_BASE -#define FIXADDR_USER_END VSYSCALL_END - extern void __this_fixmap_does_not_exist(void); /* -- cgit v1.2.3 From 986edf120fbe724b49b7127328641ab57d0e2d05 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 11 Jan 2005 03:14:48 -0800 Subject: [PATCH] UML: code tidying Some small cleanups that resulted from the x86_64 merge: Some unneeded includes were removed Some overlong lines were shortened current_thread_info was replaced by a generic version. Some warnings were fixed Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/process.h | 2 +- arch/um/kernel/mem.c | 2 ++ arch/um/kernel/mem_user.c | 4 +--- arch/um/kernel/process.c | 7 ++----- arch/um/kernel/skas/process.c | 3 ++- arch/um/kernel/skas/trap_user.c | 1 - arch/um/kernel/tt/ptproxy/sysdep.c | 1 - arch/um/kernel/tt/ptproxy/wait.c | 1 - arch/um/kernel/tt/trap_user.c | 1 - arch/um/kernel/um_arch.c | 5 +++++ arch/um/os-Linux/Makefile | 2 ++ arch/um/os-Linux/elf_aux.c | 1 - arch/um/os-Linux/user_syms.c | 8 +++++--- include/asm-um/processor-i386.h | 3 ++- include/asm-um/thread_info.h | 2 +- 15 files changed, 23 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/arch/um/include/process.h b/arch/um/include/process.h index 07af218574fd..5af9157ff54f 100644 --- a/arch/um/include/process.h +++ b/arch/um/include/process.h @@ -6,7 +6,7 @@ #ifndef __PROCESS_H__ #define __PROCESS_H__ -#include +#include extern void sig_handler(int sig, struct sigcontext sc); extern void alarm_handler(int sig, struct sigcontext sc); diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index e8a2c9c5716b..f95e90ae9c88 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -173,6 +173,7 @@ static void init_highmem(void) static void __init fixaddr_user_init( void) { +#if FIXADDR_USER_START != 0 long size = FIXADDR_USER_END - FIXADDR_USER_START; pgd_t *pgd; pmd_t *pmd; @@ -192,6 +193,7 @@ static void __init fixaddr_user_init( void) pte = pte_offset_kernel(pmd, vaddr); pte_set_val( (*pte), paddr, PAGE_READONLY); } +#endif } void paging_init(void) diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c index 33f71e764951..4a663fd434bb 100644 --- a/arch/um/kernel/mem_user.c +++ b/arch/um/kernel/mem_user.c @@ -48,8 +48,6 @@ #include "tempfile.h" #include "kern_constants.h" -extern struct mem_region physmem_region; - #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" static int create_tmp_file(unsigned long len) @@ -135,7 +133,7 @@ static int create_anon_file(unsigned long len) addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if(addr == MAP_FAILED){ - os_print_error((int) addr, "mapping physmem file"); + perror("mapping physmem file"); exit(1); } munmap(addr, len); diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 0fca3f073c86..1e638b813199 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -13,14 +13,10 @@ #include #include #include -#include #include #include -#include -#include #include #include -#include #include "user_util.h" #include "kern_util.h" #include "user.h" @@ -28,6 +24,7 @@ #include "signal_kern.h" #include "signal_user.h" #include "sysdep/ptrace.h" +#include "sysdep/ptrace_user.h" #include "sysdep/sigcontext.h" #include "irq_user.h" #include "ptrace_user.h" @@ -331,7 +328,7 @@ void __init check_ptrace(void) CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); - if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP + 0x80))) + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80)) panic("check_ptrace : expected SIGTRAP + 0x80, " "got status = %d", status); diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 4b368908e5a4..2fc18a123dae 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -73,7 +73,8 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu "errno = %d\n", errno); CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); - if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP + 0x80))) + if((err < 0) || !WIFSTOPPED(status) || + (WSTOPSIG(status) != SIGTRAP + 0x80)) panic("handle_trap - failed to wait at end of syscall, " "errno = %d, status = %d\n", errno, status); } diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index 96593709a6e1..09248772de60 100644 --- a/arch/um/kernel/skas/trap_user.c +++ b/arch/um/kernel/skas/trap_user.c @@ -5,7 +5,6 @@ #include #include -#include #include "sysdep/ptrace.h" #include "signal_user.h" #include "user_util.h" diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c index c42855aeda60..4545ea4f27e1 100644 --- a/arch/um/kernel/tt/ptproxy/sysdep.c +++ b/arch/um/kernel/tt/ptproxy/sysdep.c @@ -12,7 +12,6 @@ terms and conditions. #include #include #include -#include #include #include "ptrace_user.h" #include "user_util.h" diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c index 86ef67653e72..fcb7ea50fc7e 100644 --- a/arch/um/kernel/tt/ptproxy/wait.c +++ b/arch/um/kernel/tt/ptproxy/wait.c @@ -10,7 +10,6 @@ terms and conditions. #include #include #include -#include #include "ptproxy.h" #include "sysdep.h" diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c index 00bacacfcc35..67fdef69d54e 100644 --- a/arch/um/kernel/tt/trap_user.c +++ b/arch/um/kernel/tt/trap_user.c @@ -6,7 +6,6 @@ #include #include #include -#include #include "sysdep/ptrace.h" #include "signal_user.h" #include "user_util.h" diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 1ce25f89f8ac..8096843e4d4c 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -17,6 +17,7 @@ #include "linux/sysrq.h" #include "linux/seq_file.h" #include "linux/delay.h" +#include "linux/module.h" #include "asm/page.h" #include "asm/pgtable.h" #include "asm/ptrace.h" @@ -156,6 +157,8 @@ static int __init uml_version_setup(char *line, int *add) { printf("%s\n", system_utsname.release); exit(0); + + return 0; } __uml_setup("--version", uml_version_setup, @@ -256,6 +259,8 @@ static int __init Usage(char *line, int *add) p++; } exit(0); + + return 0; } __uml_setup("--help", Usage, diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 9d88f68977df..f8378124be13 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -11,3 +11,5 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 36575ff8bfac..9aee0b62ebca 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c @@ -26,7 +26,6 @@ unsigned long vsyscall_end; unsigned long __kernel_vsyscall; - __init void scan_elf_aux( char **envp) { long page_size = 0; diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 383ac7b52beb..75d7af9ae1d2 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c @@ -26,9 +26,6 @@ EXPORT_SYMBOL(printf); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(vsyscall_ehdr); -EXPORT_SYMBOL(vsyscall_end); - /* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. * However, the modules will use the CRC defined *here*, no matter if it is * good; so the versions of these symbols will always match @@ -37,6 +34,11 @@ EXPORT_SYMBOL(vsyscall_end); int sym(void); \ EXPORT_SYMBOL(sym); +#ifdef SUBARCH_i386 +EXPORT_SYMBOL(vsyscall_ehdr); +EXPORT_SYMBOL(vsyscall_end); +#endif + EXPORT_SYMBOL_PROTO(__errno_location); EXPORT_SYMBOL_PROTO(access); diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h index b276481cc6cb..cb44bb56836f 100644 --- a/include/asm-um/processor-i386.h +++ b/include/asm-um/processor-i386.h @@ -24,7 +24,8 @@ struct arch_thread { * instruction pointer ("program counter"). Stolen * from asm-i386/processor.h */ -#define current_text_addr() ({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; }) +#define current_text_addr() \ + ({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; }) #include "asm/processor-generic.h" diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index 6550ed4355c2..7797873890c2 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h @@ -47,7 +47,7 @@ static inline struct thread_info *current_thread_info(void) struct thread_info *ti; unsigned long mask = PAGE_SIZE * (1 << CONFIG_KERNEL_STACK_ORDER) - 1; - __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~mask)); + ti = (struct thread_info *) (((unsigned long) &ti) & ~mask); return ti; } -- cgit v1.2.3 From 757c4d2fc71af260c8112ce7ae7816e4ac6fad40 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 11 Jan 2005 03:15:14 -0800 Subject: [PATCH] UML: 2.6.10 ptrace updates Add some of the 2.6.10 ptrace updates. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/ptrace.c | 28 ++++++++++++++++++++++++++-- include/asm-um/ptrace-generic.h | 5 +++++ 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index be56a8f103d7..23c11c426ab2 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -307,6 +307,25 @@ long sys_ptrace(long request, long pid, long addr, long data) return ret; } +void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs, + int error_code) +{ + struct siginfo info; + + memset(&info, 0, sizeof(info)); + info.si_signo = SIGTRAP; + info.si_code = TRAP_BRKPT; + + /* User-mode eip? */ + info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL; + + /* Send us the fakey SIGTRAP */ + force_sig_info(SIGTRAP, &info, tsk); +} + +/* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and + * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check + */ void syscall_trace(union uml_pt_regs *regs, int entryexit) { int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; @@ -321,14 +340,19 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit) audit_syscall_exit(current, regs->eax); } - if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_singlestep) + /* Fake a debug trap */ + if (is_singlestep) + send_sigtrap(current, regs, 0); + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; + if (!(current->ptrace & PT_PTRACED)) return; /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ - tracesysgood = (current->ptrace & PT_TRACESYSGOOD) && !is_singlestep; + tracesysgood = (current->ptrace & PT_TRACESYSGOOD); ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); if (entryexit) /* force do_signal() --> is_syscall() */ diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h index 0e187165cf02..46599ac44037 100644 --- a/include/asm-um/ptrace-generic.h +++ b/include/asm-um/ptrace-generic.h @@ -12,11 +12,13 @@ #define pt_regs pt_regs_subarch #define show_regs show_regs_subarch +#define send_sigtrap send_sigtrap_subarch #include "asm/arch/ptrace.h" #undef pt_regs #undef show_regs +#undef send_sigtrap #undef user_mode #undef instruction_pointer @@ -55,6 +57,9 @@ extern int set_fpxregs(unsigned long buf, struct task_struct *tsk); extern void show_regs(struct pt_regs *regs); +extern void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs, + int error_code); + #endif #endif -- cgit v1.2.3 From 7ab79f6551b8fc72895def06dc17b80bf91d5dd4 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 11 Jan 2005 03:16:34 -0800 Subject: [PATCH] UML: sparse annotations Lots of sparse annotations from Chris Wright. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/mconsole_kern.c | 2 +- arch/um/drivers/ubd_kern.c | 10 +++++----- arch/um/include/um_uaccess.h | 14 +++++++------- arch/um/include/uml_uaccess.h | 2 +- arch/um/kernel/checksum.c | 12 ++++++------ arch/um/kernel/exec_kern.c | 10 ++++++---- arch/um/kernel/exitcode.c | 2 +- arch/um/kernel/irq.c | 4 ++-- arch/um/kernel/mem.c | 4 ++-- arch/um/kernel/process_kern.c | 8 ++++---- arch/um/kernel/ptrace.c | 15 ++++++++------- arch/um/kernel/signal_kern.c | 2 +- arch/um/kernel/skas/uaccess.c | 22 +++++++++++----------- arch/um/kernel/syscall_kern.c | 7 +++---- arch/um/kernel/time_kern.c | 6 +++--- arch/um/kernel/tt/uaccess.c | 12 ++++++------ arch/um/sys-i386/ldt.c | 12 +++++++----- arch/um/sys-i386/ptrace.c | 24 +++++++++++++----------- arch/um/sys-i386/sigcontext.c | 3 +-- arch/um/sys-i386/signal.c | 2 +- arch/um/sys-i386/syscalls.c | 16 +++++++++------- arch/um/sys-x86_64/signal.c | 2 +- include/asm-um/uaccess.h | 4 ++-- 23 files changed, 101 insertions(+), 94 deletions(-) (limited to 'include') diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index cb8c1ee24fc7..ecbabd351c6d 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -499,7 +499,7 @@ int mconsole_init(void) __initcall(mconsole_init); -static int write_proc_mconsole(struct file *file, const char *buffer, +static int write_proc_mconsole(struct file *file, const char __user *buffer, unsigned long count, void *data) { char *buf; diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index f05c2b7514f2..17d85730086b 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -172,7 +172,7 @@ static struct proc_dir_entry *proc_ide = NULL; static void make_proc_ide(void) { - proc_ide_root = proc_mkdir("ide", 0); + proc_ide_root = proc_mkdir("ide", NULL); proc_ide = proc_mkdir("ide0", proc_ide_root); } @@ -1087,7 +1087,7 @@ static void do_ubd_request(request_queue_t *q) static int ubd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { - struct hd_geometry *loc = (struct hd_geometry *) arg; + struct hd_geometry __user *loc = (struct hd_geometry __user *) arg; struct ubd *dev = inode->i_bdev->bd_disk->private_data; struct hd_driveid ubd_id = { .cyls = 0, @@ -1108,19 +1108,19 @@ static int ubd_ioctl(struct inode * inode, struct file * file, case HDIO_GET_IDENTITY: ubd_id.cyls = dev->size / (128 * 32 * 512); - if(copy_to_user((char *) arg, (char *) &ubd_id, + if(copy_to_user((char __user *) arg, (char *) &ubd_id, sizeof(ubd_id))) return(-EFAULT); return(0); case CDROMVOLREAD: - if(copy_from_user(&volume, (char *) arg, sizeof(volume))) + if(copy_from_user(&volume, (char __user *) arg, sizeof(volume))) return(-EFAULT); volume.channel0 = 255; volume.channel1 = 255; volume.channel2 = 255; volume.channel3 = 255; - if(copy_to_user((char *) arg, &volume, sizeof(volume))) + if(copy_to_user((char __user *) arg, &volume, sizeof(volume))) return(-EFAULT); return(0); } diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h index c72024219f23..4eb302cbf865 100644 --- a/arch/um/include/um_uaccess.h +++ b/arch/um/include/um_uaccess.h @@ -20,19 +20,19 @@ #define access_ok(type, addr, size) \ CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size) -static inline int verify_area(int type, const void * addr, unsigned long size) +static inline int verify_area(int type, const void __user *addr, unsigned long size) { - return(CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr, + return (CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr, size)); } -static inline int copy_from_user(void *to, const void *from, int n) +static inline int copy_from_user(void *to, const void __user *from, int n) { return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to, from, n)); } -static inline int copy_to_user(void *to, const void *from, int n) +static inline int copy_to_user(void __user *to, const void *from, int n) { return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to, from, n)); @@ -57,7 +57,7 @@ static inline int copy_to_user(void *to, const void *from, int n) * and returns @count. */ -static inline int strncpy_from_user(char *dst, const char *src, int count) +static inline int strncpy_from_user(char *dst, const char __user *src, int count) { return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas, dst, src, count)); @@ -89,7 +89,7 @@ static inline int __clear_user(void *mem, int len) * Returns number of bytes that could not be cleared. * On success, this will be zero. */ -static inline int clear_user(void *mem, int len) +static inline int clear_user(void __user *mem, int len) { return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len)); } @@ -105,7 +105,7 @@ static inline int clear_user(void *mem, int len) * On exception, returns 0. * If the string is too long, returns a value greater than @n. */ -static inline int strnlen_user(const void *str, long len) +static inline int strnlen_user(const void __user *str, long len) { return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len)); } diff --git a/arch/um/include/uml_uaccess.h b/arch/um/include/uml_uaccess.h index 785ccd51bbf5..f77eb6428453 100644 --- a/arch/um/include/uml_uaccess.h +++ b/arch/um/include/uml_uaccess.h @@ -7,7 +7,7 @@ #define __UML_UACCESS_H__ extern int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher); + void **fault_addr, void **fault_catcher); extern unsigned long __do_user_copy(void *to, const void *from, int n, void **fault_addr, void **fault_catcher, void (*op)(void *to, const void *from, diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c index fa50a9b81ca2..669783580fe5 100644 --- a/arch/um/kernel/checksum.c +++ b/arch/um/kernel/checksum.c @@ -2,16 +2,16 @@ #include "linux/errno.h" #include "linux/module.h" -extern unsigned int arch_csum_partial(const char *buff, int len, int sum); +unsigned int arch_csum_partial(const char *buff, int len, int sum); -extern unsigned int csum_partial(char *buff, int len, int sum) +unsigned int csum_partial(char *buff, int len, int sum) { - return(arch_csum_partial(buff, len, sum)); + return arch_csum_partial(buff, len, sum); } EXPORT_SYMBOL(csum_partial); -unsigned int csum_partial_copy_to(const char *src, char *dst, int len, +unsigned int csum_partial_copy_to(const char *src, char __user *dst, int len, int sum, int *err_ptr) { if(copy_to_user(dst, src, len)){ @@ -22,7 +22,7 @@ unsigned int csum_partial_copy_to(const char *src, char *dst, int len, return(arch_csum_partial(src, len, sum)); } -unsigned int csum_partial_copy_from(const char *src, char *dst, int len, +unsigned int csum_partial_copy_from(const char __user *src, char *dst, int len, int sum, int *err_ptr) { if(copy_from_user(dst, src, len)){ @@ -30,7 +30,7 @@ unsigned int csum_partial_copy_from(const char *src, char *dst, int len, return(-1); } - return(arch_csum_partial(dst, len, sum)); + return arch_csum_partial(dst, len, sum); } /* diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index 4336240c179a..49ddabe69be7 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -34,7 +34,8 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) extern void log_exec(char **argv, void *tty); -static long execve1(char *file, char **argv, char **env) +static long execve1(char *file, char __user * __user *argv, + char *__user __user *env) { long error; @@ -51,7 +52,7 @@ static long execve1(char *file, char **argv, char **env) return(error); } -long um_execve(char *file, char **argv, char **env) +long um_execve(char *file, char __user *__user *argv, char __user *__user *env) { long err; @@ -61,13 +62,14 @@ long um_execve(char *file, char **argv, char **env) return(err); } -long sys_execve(char *file, char **argv, char **env) +long sys_execve(char *file, char __user *__user *argv, + char __user *__user *env) { long error; char *filename; lock_kernel(); - filename = getname((char *) file); + filename = getname((char __user *) file); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; error = execve1(filename, argv, env); diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index 14a748e2e25a..0ea87f24b36f 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -27,7 +27,7 @@ static int read_proc_exitcode(char *page, char **start, off_t off, return(len); } -static int write_proc_exitcode(struct file *file, const char *buffer, +static int write_proc_exitcode(struct file *file, const char __user *buffer, unsigned long count, void *data) { char *end, buf[sizeof("nnnnn\0")]; diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 6d53b5987d62..ab7417b78c87 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -152,13 +152,13 @@ void __init init_IRQ(void) int i; irq_desc[TIMER_IRQ].status = IRQ_DISABLED; - irq_desc[TIMER_IRQ].action = 0; + irq_desc[TIMER_IRQ].action = NULL; irq_desc[TIMER_IRQ].depth = 1; irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type; enable_irq(TIMER_IRQ); for(i=1;ithread.fault_addr = (void *) addr; - if(__do_copy_to_user((void *) addr, &zero, + if(__do_copy_to_user((void __user *) addr, &zero, sizeof(zero), ¤t->thread.fault_addr, ¤t->thread.fault_catcher)){ diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 62e6c8ef2e67..8d003f351eb3 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -368,22 +368,22 @@ void *get_init_task(void) return(&init_thread_union.thread_info.task); } -int copy_to_user_proc(void *to, void *from, int size) +int copy_to_user_proc(void __user *to, void *from, int size) { return(copy_to_user(to, from, size)); } -int copy_from_user_proc(void *to, void *from, int size) +int copy_from_user_proc(void *to, void __user *from, int size) { return(copy_from_user(to, from, size)); } -int clear_user_proc(void *buf, int size) +int clear_user_proc(void __user *buf, int size) { return(clear_user(buf, size)); } -int strlen_user_proc(char *str) +int strlen_user_proc(char __user *str) { return(strlen_user(str)); } diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 23c11c426ab2..0d8e76969600 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -81,7 +81,7 @@ long sys_ptrace(long request, long pid, long addr, long data) copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) break; - ret = put_user(tmp,(unsigned long *) data); + ret = put_user(tmp, (unsigned long __user *) data); break; } @@ -103,7 +103,7 @@ long sys_ptrace(long request, long pid, long addr, long data) addr = addr >> 2; tmp = child->thread.arch.debugregs[addr]; } - ret = put_user(tmp, (unsigned long *) data); + ret = put_user(tmp, (unsigned long __user *) data); break; } @@ -201,7 +201,8 @@ long sys_ptrace(long request, long pid, long addr, long data) break; } for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) { - __put_user(getreg(child, i), (unsigned long *) data); + __put_user(getreg(child, i), + (unsigned long __user *) data); data += sizeof(long); } ret = 0; @@ -217,7 +218,7 @@ long sys_ptrace(long request, long pid, long addr, long data) break; } for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) { - __get_user(tmp, (unsigned long *) data); + __get_user(tmp, (unsigned long __user *) data); putreg(child, i, tmp); data += sizeof(long); } @@ -251,14 +252,14 @@ long sys_ptrace(long request, long pid, long addr, long data) fault = ((struct ptrace_faultinfo) { .is_write = child->thread.err, .addr = child->thread.cr2 }); - ret = copy_to_user((unsigned long *) data, &fault, + ret = copy_to_user((unsigned long __user *) data, &fault, sizeof(fault)); if(ret) break; break; } case PTRACE_SIGPENDING: - ret = copy_to_user((unsigned long *) data, + ret = copy_to_user((unsigned long __user *) data, &child->pending.signal, sizeof(child->pending.signal)); break; @@ -266,7 +267,7 @@ long sys_ptrace(long request, long pid, long addr, long data) case PTRACE_LDT: { struct ptrace_ldt ldt; - if(copy_from_user(&ldt, (unsigned long *) data, + if(copy_from_user(&ldt, (unsigned long __user *) data, sizeof(ldt))){ ret = -EIO; break; diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 44c05e5690b8..7807a3e8c426 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -196,7 +196,7 @@ long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) } } -long sys_sigaltstack(const stack_t *uss, stack_t *uoss) +long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) { return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); } diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 6d559db8f865..c8e5fe49583a 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -132,10 +132,10 @@ static int copy_chunk_from_user(unsigned long from, int len, void *arg) return(0); } -int copy_from_user_skas(void *to, const void *from, int n) +int copy_from_user_skas(void *to, const void __user *from, int n) { if(segment_eq(get_fs(), KERNEL_DS)){ - memcpy(to, from, n); + memcpy(to, (__force void*)from, n); return(0); } @@ -153,10 +153,10 @@ static int copy_chunk_to_user(unsigned long to, int len, void *arg) return(0); } -int copy_to_user_skas(void *to, const void *from, int n) +int copy_to_user_skas(void __user *to, const void *from, int n) { if(segment_eq(get_fs(), KERNEL_DS)){ - memcpy(to, from, n); + memcpy((__force void*)to, from, n); return(0); } @@ -179,13 +179,13 @@ static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) return(0); } -int strncpy_from_user_skas(char *dst, const char *src, int count) +int strncpy_from_user_skas(char *dst, const char __user *src, int count) { int n; char *ptr = dst; if(segment_eq(get_fs(), KERNEL_DS)){ - strncpy(dst, src, count); + strncpy(dst, (__force void*)src, count); return(strnlen(dst, count)); } @@ -205,15 +205,15 @@ static int clear_chunk(unsigned long addr, int len, void *unused) return(0); } -int __clear_user_skas(void *mem, int len) +int __clear_user_skas(void __user *mem, int len) { return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL)); } -int clear_user_skas(void *mem, int len) +int clear_user_skas(void __user *mem, int len) { if(segment_eq(get_fs(), KERNEL_DS)){ - memset(mem, 0, len); + memset((__force void*)mem, 0, len); return(0); } @@ -233,12 +233,12 @@ static int strnlen_chunk(unsigned long str, int len, void *arg) return(0); } -int strnlen_user_skas(const void *str, int len) +int strnlen_user_skas(const void __user *str, int len) { int count = 0, n; if(segment_eq(get_fs(), KERNEL_DS)) - return(strnlen(str, len) + 1); + return(strnlen((__force char*)str, len) + 1); n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count); if(n == 0) diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index b620e7c17aa2..a294e5071fe8 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -27,10 +27,9 @@ /* Unlocked, I don't care if this is a bit off */ int nsyscalls = 0; -long um_mount(char * dev_name, char * dir_name, char * type, - unsigned long new_flags, void * data) +long um_mount(char __user * dev_name, char __user * dir_name, + char __user * type, unsigned long new_flags, void __user * data) { - if(type == NULL) type = ""; return(sys_mount(dev_name, dir_name, type, new_flags, data)); } @@ -96,7 +95,7 @@ long old_mmap(unsigned long addr, unsigned long len, * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ -long sys_pipe(unsigned long * fildes) +long sys_pipe(unsigned long __user * fildes) { int fd[2]; long error; diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 3b538f6cc3ae..df21b0529ae6 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -111,19 +111,19 @@ irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) return(IRQ_HANDLED); } -long um_time(int * tloc) +long um_time(int __user *tloc) { struct timeval now; do_gettimeofday(&now); if (tloc) { - if (put_user(now.tv_sec,tloc)) + if (put_user(now.tv_sec, tloc)) now.tv_sec = -EFAULT; } return now.tv_sec; } -long um_stime(int * tptr) +long um_stime(int __user *tptr) { int value; struct timespec new; diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c index 0409718935f7..a72aa632972f 100644 --- a/arch/um/kernel/tt/uaccess.c +++ b/arch/um/kernel/tt/uaccess.c @@ -6,7 +6,7 @@ #include "linux/sched.h" #include "asm/uaccess.h" -int copy_from_user_tt(void *to, const void *from, int n) +int copy_from_user_tt(void *to, const void __user *from, int n) { if(!access_ok_tt(VERIFY_READ, from, n)) return(n); @@ -15,7 +15,7 @@ int copy_from_user_tt(void *to, const void *from, int n) ¤t->thread.fault_catcher)); } -int copy_to_user_tt(void *to, const void *from, int n) +int copy_to_user_tt(void __user *to, const void *from, int n) { if(!access_ok_tt(VERIFY_WRITE, to, n)) return(n); @@ -24,7 +24,7 @@ int copy_to_user_tt(void *to, const void *from, int n) ¤t->thread.fault_catcher)); } -int strncpy_from_user_tt(char *dst, const char *src, int count) +int strncpy_from_user_tt(char *dst, const char __user *src, int count) { int n; @@ -38,14 +38,14 @@ int strncpy_from_user_tt(char *dst, const char *src, int count) return(n); } -int __clear_user_tt(void *mem, int len) +int __clear_user_tt(void __user *mem, int len) { return(__do_clear_user(mem, len, ¤t->thread.fault_addr, ¤t->thread.fault_catcher)); } -int clear_user_tt(void *mem, int len) +int clear_user_tt(void __user *mem, int len) { if(!access_ok_tt(VERIFY_WRITE, mem, len)) return(len); @@ -54,7 +54,7 @@ int clear_user_tt(void *mem, int len) ¤t->thread.fault_catcher)); } -int strnlen_user_tt(const void *str, int len) +int strnlen_user_tt(const void __user *str, int len) { return(__do_strnlen_user(str, len, ¤t->thread.fault_addr, diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index 98d7691980b2..e97b98806af7 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -15,10 +15,12 @@ extern int modify_ldt(int func, void *ptr, unsigned long bytecount); /* XXX this needs copy_to_user and copy_from_user */ -int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) +int sys_modify_ldt_tt(int func, void __user *ptr, unsigned long bytecount) { - if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT); - return(modify_ldt(func, ptr, bytecount)); + if (verify_area(VERIFY_READ, ptr, bytecount)) + return -EFAULT; + + return modify_ldt(func, ptr, bytecount); } #endif @@ -27,7 +29,7 @@ extern int userspace_pid; #include "skas_ptrace.h" -int sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) +int sys_modify_ldt_skas(int func, void __user *ptr, unsigned long bytecount) { struct ptrace_ldt ldt; void *buf; @@ -76,7 +78,7 @@ int sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) } #endif -int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) +int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) { return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, ptr, bytecount)); diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index 42322d888503..c6a1bba337ea 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -3,6 +3,8 @@ * Licensed under the GPL */ +#include +#include #include "linux/sched.h" #include "asm/elf.h" #include "asm/ptrace.h" @@ -22,7 +24,7 @@ int is_syscall(unsigned long addr) unsigned short instr; int n; - n = copy_from_user(&instr, (void *) addr, sizeof(instr)); + n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); if(n){ printk("is_syscall : failed to read instruction from 0x%lx\n", addr); @@ -175,12 +177,12 @@ static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave */ #ifdef CONFIG_MODE_TT -static inline int convert_fxsr_to_user_tt(struct _fpstate *buf, +static inline int convert_fxsr_to_user_tt(struct _fpstate __user *buf, struct pt_regs *regs) { struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); unsigned long env[7]; - struct _fpreg *to; + struct _fpreg __user *to; struct _fpxreg *from; int i; @@ -205,7 +207,7 @@ static inline int convert_fxsr_to_user_tt(struct _fpstate *buf, } #endif -static inline int convert_fxsr_to_user(struct _fpstate *buf, +static inline int convert_fxsr_to_user(struct _fpstate __user *buf, struct pt_regs *regs) { return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0)); @@ -213,12 +215,12 @@ static inline int convert_fxsr_to_user(struct _fpstate *buf, #ifdef CONFIG_MODE_TT static inline int convert_fxsr_from_user_tt(struct pt_regs *regs, - struct _fpstate *buf) + struct _fpstate __user *buf) { struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); unsigned long env[7]; struct _fpxreg *to; - struct _fpreg *from; + struct _fpreg __user *from; int i; if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) @@ -244,7 +246,7 @@ static inline int convert_fxsr_from_user_tt(struct pt_regs *regs, #endif static inline int convert_fxsr_from_user(struct pt_regs *regs, - struct _fpstate *buf) + struct _fpstate __user *buf) { return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0)); } @@ -253,7 +255,7 @@ int get_fpregs(unsigned long buf, struct task_struct *child) { int err; - err = convert_fxsr_to_user((struct _fpstate *) buf, + err = convert_fxsr_to_user((struct _fpstate __user *) buf, &child->thread.regs); if(err) return(-EFAULT); else return(0); @@ -264,7 +266,7 @@ int set_fpregs(unsigned long buf, struct task_struct *child) int err; err = convert_fxsr_from_user(&child->thread.regs, - (struct _fpstate *) buf); + (struct _fpstate __user *) buf); if(err) return(-EFAULT); else return(0); } @@ -276,7 +278,7 @@ int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk) struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); int err; - err = __copy_to_user((void *) buf, fxsave, + err = __copy_to_user((void __user *) buf, fxsave, sizeof(struct user_fxsr_struct)); if(err) return -EFAULT; else return 0; @@ -295,7 +297,7 @@ int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk) struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); int err; - err = __copy_from_user(fxsave, (void *) buf, + err = __copy_from_user(fxsave, (void __user *) buf, sizeof(struct user_fxsr_struct) ); if(err) return -EFAULT; else return 0; diff --git a/arch/um/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c index a30140331cf7..467d489c31cd 100644 --- a/arch/um/sys-i386/sigcontext.c +++ b/arch/um/sys-i386/sigcontext.c @@ -22,8 +22,7 @@ void sc_to_sc(void *to_ptr, void *from_ptr) unsigned long *sc_sigmask(void *sc_ptr) { struct sigcontext *sc = sc_ptr; - - return(&sc->oldmask); + return &sc->oldmask; } int sc_get_fpregs(unsigned long buf, void *sc_ptr) diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 6794671be7a3..0cb4c86b5c2b 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c @@ -146,7 +146,7 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, } #endif -static int copy_sc_from_user(struct pt_regs *to, void *from) +static int copy_sc_from_user(struct pt_regs *to, void __user *from) { int ret; diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c index 14f1434374ee..dd58b5511e9b 100644 --- a/arch/um/sys-i386/syscalls.c +++ b/arch/um/sys-i386/syscalls.c @@ -30,7 +30,7 @@ extern int old_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long offset); -long old_mmap_i386(struct mmap_arg_struct *arg) +long old_mmap_i386(struct mmap_arg_struct __user *arg) { struct mmap_arg_struct a; int err = -EFAULT; @@ -45,11 +45,13 @@ long old_mmap_i386(struct mmap_arg_struct *arg) struct sel_arg_struct { unsigned long n; - fd_set *inp, *outp, *exp; - struct timeval *tvp; + fd_set __user *inp; + fd_set __user *outp; + fd_set __user *exp; + struct timeval __user *tvp; }; -long old_select(struct sel_arg_struct *arg) +long old_select(struct sel_arg_struct __user *arg) { struct sel_arg_struct a; @@ -62,8 +64,8 @@ long old_select(struct sel_arg_struct *arg) /* The i386 version skips reading from %esi, the fourth argument. So we must do * this, too. */ -long sys_clone(unsigned long clone_flags, unsigned long newsp, int *parent_tid, - int unused, int *child_tid) +long sys_clone(unsigned long clone_flags, unsigned long newsp, + int __user *parent_tid, int unused, int __user *child_tid) { long ret; @@ -86,7 +88,7 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp, int *parent_tid, * This is really horribly ugly. */ long sys_ipc (uint call, int first, int second, - int third, void *ptr, long fifth) + int third, void *__user ptr, long fifth) { int version, ret; diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index 4864c0605972..a5682f1d020d 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c @@ -128,7 +128,7 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, #endif -static int copy_sc_from_user(struct pt_regs *to, void *from) +static int copy_sc_from_user(struct pt_regs *to, void __user *from) { int ret; diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h index d42d5f8dcdfd..801710d00a40 100644 --- a/include/asm-um/uaccess.h +++ b/include/asm-um/uaccess.h @@ -55,7 +55,7 @@ #define get_user(x, ptr) \ ({ \ - const __typeof__((*(ptr))) *private_ptr = (ptr); \ + const __typeof__((*(ptr))) __user *private_ptr = (ptr); \ (access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \ __get_user(x, private_ptr) : ((x) = 0, -EFAULT)); \ }) @@ -75,7 +75,7 @@ #define put_user(x, ptr) \ ({ \ - __typeof__(*(ptr)) *private_ptr = (ptr); \ + __typeof__(*(ptr)) __user *private_ptr = (ptr); \ (access_ok(VERIFY_WRITE, private_ptr, sizeof(*private_ptr)) ? \ __put_user(x, private_ptr) : -EFAULT); \ }) -- cgit v1.2.3 From bf36f91f08100b758a4f12811da05b9c1ce09c90 Mon Sep 17 00:00:00 2001 From: Prasanna Meda Date: Tue, 11 Jan 2005 03:18:08 -0800 Subject: [PATCH] easily tweakable comm length This change still keeps the comm length at 16, but allows easier patching for local modifications, and also introduces a macro to use instead of magic 16, where sizeof(comm) is not preferable to use. Not able to use killall, pidof etc. effectively, when long process names are used for scripts. Just changing the command length from 16 to 32 breaks a.out coredump logic. Deamonise and get_task_comm helped in other places in 2.6.10. Signed-off-by: Prasanna Meda Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/sparc64/kernel/binfmt_aout32.c | 2 +- fs/binfmt_aout.c | 2 +- include/linux/sched.h | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index 64d547853b48..c54d806e13d2 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -95,7 +95,7 @@ static int aout32_core_dump(long signr, struct pt_regs *regs, struct file *file) set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; - strncpy(dump.u_comm, current->comm, sizeof(current->comm)); + strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); dump.signal = signr; dump_thread(regs, &dump); diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index acdd53848566..8075fdff2364 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -112,7 +112,7 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; - strncpy(dump.u_comm, current->comm, sizeof(current->comm)); + strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); #ifndef __sparc__ dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump))); #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index dcc1814f97e8..96f69aaa0534 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -121,6 +121,9 @@ extern unsigned long nr_iowait(void); #define set_current_state(state_value) \ set_mb(current->state, (state_value)) +/* Task command name length */ +#define TASK_COMM_LEN 16 + /* * Scheduling policies */ @@ -612,7 +615,7 @@ struct task_struct { struct key *thread_keyring; /* keyring private to this thread */ #endif unsigned short used_math; - char comm[16]; + char comm[TASK_COMM_LEN]; /* file system info */ int link_count, total_link_count; /* ipc stuff */ -- cgit v1.2.3 From f1395ea3c1fbf67824ff83e5d4fd7aefb5346e90 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:19:00 -0800 Subject: [PATCH] pcmcia: new ds - cs interface Add a new registration function to register the PCMCIA 16-bit subsystem (ds a.k.a. pcmcia) with the PCMICA core (cs a.k.a. pcmcia_core). As send_event is only called with skt->sem held, we can use that to safeguard skt->callback(), too. Note that the class_device_register() call by pccardd() is done _before_ skt->sem() is held, and the pcmcia_socket_register() doesn't hold skt->sem() as well, so there is no chance for a deadlock. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/cs.c | 55 ++++++++++++++++++++++++++++++++++++++++++-- drivers/pcmcia/cs_internal.h | 8 +++++++ drivers/pcmcia/ds.c | 51 ++++++++++++---------------------------- include/pcmcia/ss.h | 2 ++ 4 files changed, 78 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 4e4c964f7e01..7a522f0eed88 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -349,8 +349,6 @@ static void free_regions(memory_handle_t *list) } } -static int send_event(struct pcmcia_socket *s, event_t event, int priority); - static void shutdown_socket(struct pcmcia_socket *s) { client_t **c; @@ -402,6 +400,26 @@ static void shutdown_socket(struct pcmcia_socket *s) ======================================================================*/ + +static int pcmcia_send_event(struct pcmcia_socket *s, event_t event, int priority) +{ + int ret; + + if (!s->callback) + return 0; + if (!try_module_get(s->callback->owner)) + return 0; + + ret = s->callback->event(s, event, priority); + + module_put(s->callback->owner); + + return ret; +} + + +/* NOTE: send_event needs to be called with skt->sem held. */ + static int send_event(struct pcmcia_socket *s, event_t event, int priority) { client_t *client = s->clients; @@ -411,6 +429,11 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) ret = 0; if (s->state & SOCKET_CARDBUS) return 0; + + ret = pcmcia_send_event(s, event, priority); + if (ret) + return (ret); + for (; client; client = client->next) { if (client->state & (CLIENT_UNBOUND|CLIENT_STALE)) continue; @@ -1363,6 +1386,34 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) return CS_OUT_OF_RESOURCE; } /* register_client */ +/* register pcmcia_callback */ +int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) +{ + int ret = 0; + + /* s->skt_sem also protects s->callback */ + down(&s->skt_sem); + + if (c) { + /* registration */ + if (s->callback) { + ret = -EBUSY; + goto err; + } + + s->callback = c; + + if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) + pcmcia_send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); + } else + s->callback = NULL; + err: + up(&s->skt_sem); + + return ret; +} +EXPORT_SYMBOL(pccard_register_pcmcia); + /*====================================================================*/ int pcmcia_release_configuration(client_handle_t handle) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index fbce6b67988b..dcb1c651724f 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -173,6 +173,14 @@ int pccard_reset_card(struct pcmcia_socket *skt); int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status); int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int function, conf_reg_t *reg); + +struct pcmcia_callback{ + struct module *owner; + int (*event) (struct pcmcia_socket *s, event_t event, int priority); +}; + +int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); + #define cs_socket_name(skt) ((skt)->dev.class_id) #ifdef DEBUG diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 639c5acf22f1..536dccc5bff1 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -112,7 +112,7 @@ typedef struct user_info_t { /* Socket state information */ struct pcmcia_bus_socket { atomic_t refcount; - client_handle_t handle; + struct pcmcia_callback callback; int state; user_info_t *user; int req_pending, req_result; @@ -484,14 +484,12 @@ static void handle_removal(void *data) ======================================================================*/ -static int ds_event(event_t event, int priority, - event_callback_args_t *args) +static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) { - struct pcmcia_bus_socket *s; + struct pcmcia_bus_socket *s = skt->pcmcia; ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", - event, priority, args->client_handle); - s = args->client_data; + event, priority, s); switch (event) { @@ -1082,8 +1080,6 @@ static struct file_operations ds_fops = { static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) { struct pcmcia_socket *socket = class_dev->class_data; - client_reg_t client_reg; - bind_req_t bind; struct pcmcia_bus_socket *s; int ret; @@ -1107,35 +1103,18 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) s->parent = socket; /* Set up hotline to Card Services */ - client_reg.dev_info = bind.dev_info = &dev_info; - - bind.Socket = socket; - bind.Function = BIND_FN_ALL; - ret = pcmcia_bind_device(&bind); - if (ret != CS_SUCCESS) { - cs_error(NULL, BindDevice, ret); - kfree(s); - return -EINVAL; - } + s->callback.owner = THIS_MODULE; + s->callback.event = &ds_event; + socket->pcmcia = s; - client_reg.Attributes = INFO_MASTER_CLIENT; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ds_event; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = s; - ret = pcmcia_register_client(&s->handle, &client_reg); - if (ret != CS_SUCCESS) { - cs_error(NULL, RegisterClient, ret); - kfree(s); - return -EINVAL; + ret = pccard_register_pcmcia(socket, &s->callback); + if (ret) { + printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket); + pcmcia_put_bus_socket(s); + socket->pcmcia = NULL; + return (ret); } - socket->pcmcia = s; - return 0; } @@ -1147,9 +1126,9 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev) if (!socket || !socket->pcmcia) return; - flush_scheduled_work(); + pccard_register_pcmcia(socket, NULL); - pcmcia_deregister_client(socket->pcmcia->handle); + flush_scheduled_work(); socket->pcmcia->state |= DS_SOCKET_DEAD; pcmcia_put_bus_socket(socket->pcmcia); diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 1958cda29889..c8c53fc0ef07 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -159,6 +159,7 @@ typedef struct window_t { struct config_t; struct region_t; +struct pcmcia_callback; struct pcmcia_socket { struct module *owner; @@ -215,6 +216,7 @@ struct pcmcia_socket { /* pcmcia (16-bit) */ struct pcmcia_bus_socket *pcmcia; + struct pcmcia_callback *callback; /* cardbus (32-bit) */ #ifdef CONFIG_CARDBUS -- cgit v1.2.3 From 32363bfb234d9514f6f278eb84e53401de7734f8 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:19:27 -0800 Subject: [PATCH] pcmcia: unify bind_mtd and pcmcia_bind_mtd Unify the pcmcia_bind_mtd and bind_mtd functions. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 73 +++++++++++++---------------------------------------- include/pcmcia/cs.h | 7 ----- 2 files changed, 18 insertions(+), 62 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index fee02e131d85..f8fc17b0d92b 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -171,46 +171,6 @@ static int pcmcia_bind_device(bind_req_t *req) return CS_SUCCESS; } /* bind_device */ - -/*====================================================================== - - Bind_mtd() associates a device driver with a particular memory - region. It is normally called by Driver Services after it has - identified a memory device type. An instance of the corresponding - driver will then be able to register to control this region. - -======================================================================*/ - -static int pcmcia_bind_mtd(mtd_bind_t *req) -{ - struct pcmcia_socket *s; - memory_handle_t region; - - s = req->Socket; - if (!s) - return CS_BAD_SOCKET; - - if (req->Attributes & REGION_TYPE_AM) - region = s->a_region; - else - region = s->c_region; - - while (region) { - if (region->info.CardOffset == req->CardOffset) - break; - region = region->info.next; - } - if (!region || (region->mtd != NULL)) - return CS_BAD_OFFSET; - strlcpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN); - - ds_dbg(1, "%s: bind_mtd: attr 0x%x, offset 0x%x, dev %s\n", - cs_socket_name(s), req->Attributes, req->CardOffset, - (char *)req->dev_info); - return CS_SUCCESS; -} /* bind_mtd */ - - /* String tables for error messages */ typedef struct lookup_t { @@ -545,22 +505,25 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info) { - mtd_bind_t bind_req; - int ret; + struct pcmcia_socket *s = bus_sock->parent; + memory_handle_t region; - bind_req.dev_info = &mtd_info->dev_info; - bind_req.Attributes = mtd_info->Attributes; - bind_req.Socket = bus_sock->parent; - bind_req.CardOffset = mtd_info->CardOffset; - ret = pcmcia_bind_mtd(&bind_req); - if (ret != CS_SUCCESS) { - cs_error(NULL, BindMTD, ret); - printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d" - " offset 0x%x\n", - (char *)bind_req.dev_info, bus_sock->parent->sock, bind_req.CardOffset); - return -ENODEV; - } - return 0; + if (mtd_info->Attributes & REGION_TYPE_AM) + region = s->a_region; + else + region = s->c_region; + + while (region) { + if (region->info.CardOffset == mtd_info->CardOffset) + break; + region = region->info.next; + } + if (!region || (region->mtd != NULL)) + return -ENODEV; + + strlcpy(region->dev_info, mtd_info->dev_info, DEV_NAME_LEN); + + return 0; } /* bind_mtd */ /*====================================================================== diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h index 48eddee1e554..6c518d10d8d5 100644 --- a/include/pcmcia/cs.h +++ b/include/pcmcia/cs.h @@ -325,13 +325,6 @@ typedef struct bind_req_t { /* Flag to bind to all functions */ #define BIND_FN_ALL 0xff -typedef struct mtd_bind_t { - struct pcmcia_socket *Socket; - u_int Attributes; - u_int CardOffset; - dev_info_t *dev_info; -} mtd_bind_t; - /* Events */ #define CS_EVENT_PRI_LOW 0 #define CS_EVENT_PRI_HIGH 1 -- cgit v1.2.3 From 26432027dec4d2c887a742a619331e6b82de34f3 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:19:40 -0800 Subject: [PATCH] pcmcia: unfiy bind_device and pcmcia_bind_device Unify bind_device and pcmcia_bind_device. Also, change bind_device so that it conforms to CodingStyle. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 161 ++++++++++++++++++++++------------------------------ include/pcmcia/cs.h | 9 +-- 2 files changed, 69 insertions(+), 101 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index f8fc17b0d92b..a9d572ec8bc0 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -128,49 +128,12 @@ struct pcmcia_bus_socket { /*====================================================================*/ -/* Device driver ID passed to Card Services */ -static dev_info_t dev_info = "Driver Services"; - static int major_dev = -1; /*====================================================================*/ /* code which was in cs.c before */ -/*====================================================================== - - Bind_device() associates a device driver with a particular socket. - It is normally called by Driver Services after it has identified - a newly inserted card. An instance of that driver will then be - eligible to register as a client of this socket. - -======================================================================*/ - -static int pcmcia_bind_device(bind_req_t *req) -{ - client_t *client; - struct pcmcia_socket *s; - - s = req->Socket; - if (!s) - return CS_BAD_SOCKET; - - client = (client_t *) kmalloc(sizeof(client_t), GFP_KERNEL); - if (!client) - return CS_OUT_OF_RESOURCE; - memset(client, '\0', sizeof(client_t)); - client->client_magic = CLIENT_MAGIC; - strlcpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN); - client->Socket = s; - client->Function = req->Function; - client->state = CLIENT_UNBOUND; - client->next = s->clients; - s->clients = client; - ds_dbg(1, "%s: bind_device(): client 0x%p, dev %s\n", - cs_socket_name(client->Socket), client, client->dev_info); - return CS_SUCCESS; -} /* bind_device */ - /* String tables for error messages */ typedef struct lookup_t { @@ -528,79 +491,89 @@ static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info) /*====================================================================== + bind_request() and bind_device() are merged by now. Individual + descriptions: + bind_request() connects a socket to a particular client driver. It looks up the specified device ID in the list of registered drivers, binds it to the socket, and tries to create an instance of the device. unbind_request() deletes a driver instance. + Bind_device() associates a device driver with a particular socket. + It is normally called by Driver Services after it has identified + a newly inserted card. An instance of that driver will then be + eligible to register as a client of this socket. + ======================================================================*/ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { - struct pcmcia_driver *driver; - socket_bind_t *b; - bind_req_t bind_req; - int ret; + struct pcmcia_driver *driver; + socket_bind_t *b; + client_t *client; - if (!s) - return -EINVAL; + if (!s) + return -EINVAL; - ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock, - (char *)bind_info->dev_info); - driver = get_pcmcia_driver(&bind_info->dev_info); - if (!driver) - return -EINVAL; + ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock, + (char *)bind_info->dev_info); + driver = get_pcmcia_driver(&bind_info->dev_info); + if (!driver) + return -EINVAL; - for (b = s->bind; b; b = b->next) - if ((driver == b->driver) && - (bind_info->function == b->function)) - break; - if (b != NULL) { - bind_info->instance = b->instance; - return -EBUSY; - } + for (b = s->bind; b; b = b->next) + if ((driver == b->driver) && + (bind_info->function == b->function)) + break; + if (b != NULL) { + bind_info->instance = b->instance; + return -EBUSY; + } - if (!try_module_get(driver->owner)) - return -EINVAL; - - bind_req.Socket = s->parent; - bind_req.Function = bind_info->function; - bind_req.dev_info = (dev_info_t *) driver->drv.name; - ret = pcmcia_bind_device(&bind_req); - if (ret != CS_SUCCESS) { - cs_error(NULL, BindDevice, ret); - printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n", - (char *)dev_info, s->parent->sock); - module_put(driver->owner); - return -ENODEV; - } + if (!try_module_get(driver->owner)) + return -EINVAL; - /* Add binding to list for this socket */ - driver->use_count++; - b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL); - if (!b) - { - driver->use_count--; - module_put(driver->owner); - return -ENOMEM; - } - b->driver = driver; - b->function = bind_info->function; - b->instance = NULL; - b->next = s->bind; - s->bind = b; - - if (driver->attach) { - b->instance = driver->attach(); - if (b->instance == NULL) { - printk(KERN_NOTICE "ds: unable to create instance " - "of '%s'!\n", (char *)bind_info->dev_info); - module_put(driver->owner); - return -ENODEV; + client = (client_t *) kmalloc(sizeof(client_t), GFP_KERNEL); + if (!client) { + module_put(driver->owner); + return -ENOMEM; + } + memset(client, 0, sizeof(client_t)); + + client->client_magic = CLIENT_MAGIC; + client->Socket = s->parent; + client->Function = bind_info->function; + client->state = CLIENT_UNBOUND; + client->next = s->parent->clients; + strlcpy(client->dev_info, driver->drv.name, DEV_NAME_LEN); + s->parent->clients = client; + + /* Add binding to list for this socket */ + b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL); + if (!b) + { + module_put(driver->owner); + return -ENOMEM; + } + b->driver = driver; + b->function = bind_info->function; + b->instance = NULL; + b->next = s->bind; + s->bind = b; + + driver->use_count++; + if (driver->attach) { + b->instance = driver->attach(); + if (b->instance == NULL) { + printk(KERN_NOTICE "ds: unable to create instance " + "of '%s'!\n", (char *)bind_info->dev_info); + module_put(driver->owner); + /* FIXME: client isn't freed here */ + return -ENODEV; + } } - } - return 0; + return 0; } /* bind_request */ /*====================================================================*/ diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h index 6c518d10d8d5..4a82490a1e45 100644 --- a/include/pcmcia/cs.h +++ b/include/pcmcia/cs.h @@ -315,13 +315,6 @@ typedef struct error_info_t { int retcode; } error_info_t; -/* Special stuff for binding drivers to sockets */ -typedef struct bind_req_t { - struct pcmcia_socket *Socket; - u_char Function; - dev_info_t *dev_info; -} bind_req_t; - /* Flag to bind to all functions */ #define BIND_FN_ALL 0xff @@ -413,6 +406,8 @@ enum service { GetFirstWindow, GetNextWindow, GetMemPage }; +struct pcmcia_socket; + int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg); int pcmcia_deregister_client(client_handle_t handle); int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config); -- cgit v1.2.3 From 632a82e01b23d22667117e035a2b81455e7f9335 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:19:53 -0800 Subject: [PATCH] pcmcia: device model integration can only be submitted under GPL As discussed previously, my integration of ds.c with the driver model can and will only be available under the GPL, as it's too much derived of other buses' implementation of integration with the driver model. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 48 +++++++++++++++--------------------------------- include/pcmcia/ds.h | 26 ++++++-------------------- 2 files changed, 21 insertions(+), 53 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a9d572ec8bc0..b2f42d04503d 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1,35 +1,17 @@ -/*====================================================================== - - PC Card Driver Services - - ds.c 1.112 2001/10/13 00:08:28 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ +/* + * ds.c -- 16-bit PCMCIA core support + * + * 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. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * (C) 1999 David A. Hinds + * (C) 2003 - 2004 Dominik Brodowski + */ #include #include @@ -72,7 +54,7 @@ MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("PCMCIA Driver Services"); -MODULE_LICENSE("Dual MPL/GPL"); +MODULE_LICENSE("GPL"); #ifdef DEBUG int ds_pc_debug; diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index 8a22fecf1cbd..ec0c0b9c1a06 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -1,30 +1,16 @@ /* - * ds.h 1.56 2000/06/12 21:55:40 + * ds.h -- 16-bit PCMCIA core support * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. + * (C) 1999 David A. Hinds + * (C) 2003 - 2004 Dominik Brodowski */ #ifndef _LINUX_DS_H -- cgit v1.2.3 From eac81ddc89a8a15f7ac4a0e44d8225c4a8e88a5f Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:20:06 -0800 Subject: [PATCH] pcmcia: add pcmcia_device(s) Add pcmcia_device(s). Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/pcmcia/ds.h | 22 ++++++++++++++++ 2 files changed, 95 insertions(+) (limited to 'include') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index b2f42d04503d..a37746187881 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -101,7 +101,15 @@ struct pcmcia_bus_socket { wait_queue_head_t queue, request; socket_bind_t *bind; struct pcmcia_socket *parent; + + /* the PCMCIA devices connected to this socket (normally one, more + * for multifunction devices: */ + struct list_head devices_list; + u8 device_count; /* the number of devices, used + * only internally and subject + * to incorrectness and change */ }; +static spinlock_t pcmcia_dev_list_lock; #define DS_SOCKET_PRESENT 0x01 #define DS_SOCKET_BUSY 0x02 @@ -328,6 +336,16 @@ static int proc_read_drivers(char *buf, char **start, off_t pos, } #endif +/* pcmcia_device handling */ + +static void pcmcia_release_dev(struct device *dev) +{ + struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + p_dev->socket->pcmcia->device_count = 0; + kfree(p_dev); +} + + /*====================================================================== These manage a ring buffer of events pending for one user process @@ -491,8 +509,10 @@ static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info) static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { struct pcmcia_driver *driver; + struct pcmcia_device *p_dev; socket_bind_t *b; client_t *client; + unsigned long flags; if (!s) return -EINVAL; @@ -543,6 +563,38 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) b->next = s->bind; s->bind = b; + /* Currently, the userspace pcmcia cardmgr detects pcmcia devices. + * Here this information is translated into a kernel + * struct pcmcia_device. + */ + + p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); + if (!p_dev) { + /* FIXME: client isn't freed here */ + goto no_p_dev; + } + memset(p_dev, 0, sizeof(struct pcmcia_device)); + + p_dev->socket = s->parent; + p_dev->device_no = (s->device_count++); + p_dev->func = bind_info->function; + + p_dev->dev.bus = &pcmcia_bus_type; + p_dev->dev.parent = s->parent->dev.dev; + p_dev->dev.release = pcmcia_release_dev; + sprintf (p_dev->dev.bus_id, "pcmcia%d.%d", p_dev->socket->sock, p_dev->device_no); + p_dev->dev.driver = &driver->drv; + if (device_register(&p_dev->dev)) { + /* FIXME: client isn't freed here */ + kfree(p_dev); + goto no_p_dev; + } + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + list_add_tail(&p_dev->socket_device_list, &s->devices_list); + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + + no_p_dev: + driver->use_count++; if (driver->attach) { b->instance = driver->attach(); @@ -632,6 +684,8 @@ static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { socket_bind_t **b, *c; + struct pcmcia_device *p_dev; + unsigned long flags; ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock, (char *)bind_info->dev_info); @@ -652,6 +706,22 @@ static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) module_put(c->driver->owner); *b = c->next; kfree(c); + + restart: + /* unregister the pcmcia_device */ + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { + if (p_dev->func == bind_info->function) { + list_del(&p_dev->socket_device_list); + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + + device_unregister(&p_dev->dev); + + /* multiple devices may be registered to this "function" */ + goto restart; + } + } + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); return 0; } /* unbind_request */ @@ -1034,6 +1104,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) init_waitqueue_head(&s->queue); init_waitqueue_head(&s->request); + INIT_LIST_HEAD(&s->devices_list); /* initialize data */ s->parent = socket; @@ -1090,6 +1161,8 @@ static int __init init_pcmcia_bus(void) { int i; + spin_lock_init(&pcmcia_dev_list_lock); + bus_register(&pcmcia_bus_type); class_interface_register(&pcmcia_bus_interface); diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index ec0c0b9c1a06..35437bc8303b 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -127,6 +127,8 @@ typedef struct dev_link_t { ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT))) +struct pcmcia_socket; + extern struct bus_type pcmcia_bus_type; struct pcmcia_driver { @@ -141,6 +143,26 @@ struct pcmcia_driver { int pcmcia_register_driver(struct pcmcia_driver *driver); void pcmcia_unregister_driver(struct pcmcia_driver *driver); +struct pcmcia_device { + /* the socket and the device_no [for multifunction devices] + uniquely define a pcmcia_device */ + struct pcmcia_socket *socket; + + u8 device_no; + + /* the hardware "function" device; certain subdevices can + * share one hardware "function" device. */ + u8 func; + + struct list_head socket_device_list; + + struct device dev; +}; + +#define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev) +#define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv) + + /* error reporting */ void cs_error(client_handle_t handle, int func, int ret); -- cgit v1.2.3 From daca1b3686b00cfad0281d016d5517610345c85f Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:20:20 -0800 Subject: [PATCH] pcmcia: remove socket_bind_t, use pcmcia_devices instead Remove struct socket_bind_t by moving "dev_link_t *instance" to struct pcmcia_device, and transforming all users of socket_bind_t to use struct pcmcia_device instead. Also, CodingStyle updates for get_device_info and unbind_request. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 310 +++++++++++++++++++++++++++------------------------- include/pcmcia/ds.h | 4 + 2 files changed, 168 insertions(+), 146 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a37746187881..1fe37b8ad12b 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -71,13 +71,6 @@ module_param_named(pc_debug, ds_pc_debug, int, 0644); /*====================================================================*/ -typedef struct socket_bind_t { - struct pcmcia_driver *driver; - u_char function; - dev_link_t *instance; - struct socket_bind_t *next; -} socket_bind_t; - /* Device user information */ #define MAX_EVENTS 32 #define USER_MAGIC 0x7ea4 @@ -99,7 +92,6 @@ struct pcmcia_bus_socket { user_info_t *user; int req_pending, req_result; wait_queue_head_t queue, request; - socket_bind_t *bind; struct pcmcia_socket *parent; /* the PCMCIA devices connected to this socket (normally one, more @@ -338,6 +330,20 @@ static int proc_read_drivers(char *buf, char **start, off_t pos, /* pcmcia_device handling */ +static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev) +{ + struct device *tmp_dev; + tmp_dev = get_device(&p_dev->dev); + if (!tmp_dev) + return NULL; + return to_pcmcia_dev(tmp_dev); +} + +static void pcmcia_put_dev(struct pcmcia_device *p_dev) +{ + put_device(&p_dev->dev); +} + static void pcmcia_release_dev(struct device *dev) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); @@ -508,37 +514,29 @@ static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info) static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { - struct pcmcia_driver *driver; - struct pcmcia_device *p_dev; - socket_bind_t *b; + struct pcmcia_driver *p_drv; + struct pcmcia_device *p_dev, *tmp_dev; client_t *client; unsigned long flags; + int ret = 0; if (!s) return -EINVAL; ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock, (char *)bind_info->dev_info); - driver = get_pcmcia_driver(&bind_info->dev_info); - if (!driver) - return -EINVAL; - for (b = s->bind; b; b = b->next) - if ((driver == b->driver) && - (bind_info->function == b->function)) - break; - if (b != NULL) { - bind_info->instance = b->instance; - return -EBUSY; - } + p_drv = get_pcmcia_driver(&bind_info->dev_info); + if (!p_drv) + return -EINVAL; - if (!try_module_get(driver->owner)) + if (!try_module_get(p_drv->owner)) return -EINVAL; client = (client_t *) kmalloc(sizeof(client_t), GFP_KERNEL); if (!client) { - module_put(driver->owner); - return -ENOMEM; + ret = -ENOMEM; + goto err_put; } memset(client, 0, sizeof(client_t)); @@ -547,21 +545,7 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) client->Function = bind_info->function; client->state = CLIENT_UNBOUND; client->next = s->parent->clients; - strlcpy(client->dev_info, driver->drv.name, DEV_NAME_LEN); - s->parent->clients = client; - - /* Add binding to list for this socket */ - b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL); - if (!b) - { - module_put(driver->owner); - return -ENOMEM; - } - b->driver = driver; - b->function = bind_info->function; - b->instance = NULL; - b->next = s->bind; - s->bind = b; + strlcpy(client->dev_info, p_drv->drv.name, DEV_NAME_LEN); /* Currently, the userspace pcmcia cardmgr detects pcmcia devices. * Here this information is translated into a kernel @@ -570,8 +554,8 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); if (!p_dev) { - /* FIXME: client isn't freed here */ - goto no_p_dev; + ret = -ENOMEM; + goto err_free_client; } memset(p_dev, 0, sizeof(struct pcmcia_device)); @@ -583,31 +567,53 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) p_dev->dev.parent = s->parent->dev.dev; p_dev->dev.release = pcmcia_release_dev; sprintf (p_dev->dev.bus_id, "pcmcia%d.%d", p_dev->socket->sock, p_dev->device_no); - p_dev->dev.driver = &driver->drv; - if (device_register(&p_dev->dev)) { - /* FIXME: client isn't freed here */ + p_dev->dev.driver = &p_drv->drv; + + ret = device_register(&p_dev->dev); + if (ret) { kfree(p_dev); - goto no_p_dev; + goto err_free_client; } + + /* Add to the list in pcmcia_bus_socket, but only if no device + * with the same func _and_ driver exists */ spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) { + if ((tmp_dev->func == bind_info->function) && + (tmp_dev->dev.driver == p_dev->dev.driver)){ + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + bind_info->instance = tmp_dev->instance; + ret = -EBUSY; + goto err_unregister; + } + } list_add_tail(&p_dev->socket_device_list, &s->devices_list); spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - no_p_dev: + /* finally here the parent client is registered */ + s->parent->clients = client; - driver->use_count++; - if (driver->attach) { - b->instance = driver->attach(); - if (b->instance == NULL) { + p_drv->use_count++; + if (p_drv->attach) { + p_dev->instance = p_drv->attach(); + if (!p_dev->instance) { printk(KERN_NOTICE "ds: unable to create instance " "of '%s'!\n", (char *)bind_info->dev_info); - module_put(driver->owner); /* FIXME: client isn't freed here */ - return -ENODEV; + ret = -ENODEV; + goto err_unregister; } } - + return 0; + + err_unregister: + device_unregister(&p_dev->dev); + err_free_client: + kfree(client); + err_put: + module_put(p_drv->owner); + return (ret); } /* bind_request */ /*====================================================================*/ @@ -616,113 +622,125 @@ extern struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s); static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first) { - socket_bind_t *b; - dev_node_t *node; + dev_node_t *node; + struct pcmcia_device *p_dev; + unsigned long flags; + int ret = 0; #ifdef CONFIG_CARDBUS - /* - * Some unbelievably ugly code to associate the PCI cardbus - * device and its driver with the PCMCIA "bind" information. - */ - { - struct pci_bus *bus; - - bus = pcmcia_lookup_bus(s->parent); - if (bus) { - struct list_head *list; - struct pci_dev *dev = NULL; - - list = bus->devices.next; - while (list != &bus->devices) { - struct pci_dev *pdev = pci_dev_b(list); - list = list->next; - - if (first) { - dev = pdev; - break; - } + /* + * Some unbelievably ugly code to associate the PCI cardbus + * device and its driver with the PCMCIA "bind" information. + */ + { + struct pci_bus *bus; - /* Try to handle "next" here some way? */ - } - if (dev && dev->driver) { - strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN); - bind_info->major = 0; - bind_info->minor = 0; - bind_info->next = NULL; - return 0; + bus = pcmcia_lookup_bus(s->parent); + if (bus) { + struct list_head *list; + struct pci_dev *dev = NULL; + + list = bus->devices.next; + while (list != &bus->devices) { + struct pci_dev *pdev = pci_dev_b(list); + list = list->next; + + if (first) { + dev = pdev; + break; + } + + /* Try to handle "next" here some way? */ + } + if (dev && dev->driver) { + strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN); + bind_info->major = 0; + bind_info->minor = 0; + bind_info->next = NULL; + return 0; + } } } - } #endif - for (b = s->bind; b; b = b->next) - if ((strcmp((char *)b->driver->drv.name, - (char *)bind_info->dev_info) == 0) && - (b->function == bind_info->function)) - break; - if (b == NULL) return -ENODEV; - if ((b->instance == NULL) || - (b->instance->state & DEV_CONFIG_PENDING)) - return -EAGAIN; - if (first) - node = b->instance->dev; - else - for (node = b->instance->dev; node; node = node->next) - if (node == bind_info->next) break; - if (node == NULL) return -ENODEV; - - strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN); - bind_info->major = node->major; - bind_info->minor = node->minor; - bind_info->next = node->next; - - return 0; + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { + if (p_dev->func == bind_info->function) { + p_dev = pcmcia_get_dev(p_dev); + if (!p_dev) + continue; + goto found; + } + } + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + return -ENODEV; + + found: + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + + if ((!p_dev->instance) || + (p_dev->instance->state & DEV_CONFIG_PENDING)) { + ret = -EAGAIN; + goto err_put; + } + + if (first) + node = p_dev->instance->dev; + else + for (node = p_dev->instance->dev; node; node = node->next) + if (node == bind_info->next) + break; + if (!node) { + ret = -ENODEV; + goto err_put; + } + + strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN); + bind_info->major = node->major; + bind_info->minor = node->minor; + bind_info->next = node->next; + + err_put: + pcmcia_put_dev(p_dev); + return (ret); } /* get_device_info */ /*====================================================================*/ static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { - socket_bind_t **b, *c; - struct pcmcia_device *p_dev; - unsigned long flags; - - ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock, - (char *)bind_info->dev_info); - for (b = &s->bind; *b; b = &(*b)->next) - if ((strcmp((char *)(*b)->driver->drv.name, - (char *)bind_info->dev_info) == 0) && - ((*b)->function == bind_info->function)) - break; - if (*b == NULL) - return -ENODEV; - - c = *b; - c->driver->use_count--; - if (c->driver->detach) { - if (c->instance) - c->driver->detach(c->instance); - } - module_put(c->driver->owner); - *b = c->next; - kfree(c); + struct pcmcia_device *p_dev; + struct pcmcia_driver *p_drv; + unsigned long flags; + + ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock, + (char *)bind_info->dev_info); restart: - /* unregister the pcmcia_device */ - spin_lock_irqsave(&pcmcia_dev_list_lock, flags); - list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { - if (p_dev->func == bind_info->function) { - list_del(&p_dev->socket_device_list); - spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - - device_unregister(&p_dev->dev); - - /* multiple devices may be registered to this "function" */ - goto restart; - } - } - spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - return 0; + /* unregister the pcmcia_device */ + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { + if (p_dev->func == bind_info->function) { + list_del(&p_dev->socket_device_list); + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + + /* detach the "instance" */ + p_drv = to_pcmcia_drv(p_dev->dev.driver); + if (p_drv) { + p_drv->use_count--; + if ((p_drv->detach) && (p_dev->instance)) + p_drv->detach(p_dev->instance); + module_put(p_drv->owner); + } + + device_unregister(&p_dev->dev); + + /* multiple devices may be registered to this "function" */ + goto restart; + } + } + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + return 0; } /* unbind_request */ /*====================================================================== diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index 35437bc8303b..9a25e32eca9b 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -156,6 +156,10 @@ struct pcmcia_device { struct list_head socket_device_list; + /* deprecated, a cleaned up version will be moved into this + struct soon */ + dev_link_t *instance; + struct device dev; }; -- cgit v1.2.3 From ef3571cc1e8902902430ccf85b45510a97fc5ba8 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:20:33 -0800 Subject: [PATCH] pcmcia: remove internal module use count, use module_refcount instead Remove the internal driver use_count in ds.c, as the reference counting is done in the module core anyways, and that reference count is available for cardmgr's usage by a call to module_refcount. And if !CONFIG_MODULE_UNLOAD, rmmod is useless anyways, so avoid that call by cardmgr at all. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 13 ++++++++----- include/pcmcia/ds.h | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 1fe37b8ad12b..24dd95e238a9 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -285,7 +285,6 @@ int pcmcia_register_driver(struct pcmcia_driver *driver) if (!driver) return -EINVAL; - driver->use_count = 0; driver->drv.bus = &pcmcia_bus_type; return driver_register(&driver->drv); @@ -307,10 +306,16 @@ static struct proc_dir_entry *proc_pccard = NULL; static int proc_read_drivers_callback(struct device_driver *driver, void *d) { char **p = d; - struct pcmcia_driver *p_dev = container_of(driver, + struct pcmcia_driver *p_drv = container_of(driver, struct pcmcia_driver, drv); - *p += sprintf(*p, "%-24.24s 1 %d\n", driver->name, p_dev->use_count); + *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name, +#ifdef CONFIG_MODULE_UNLOAD + (p_drv->owner) ? module_refcount(p_drv->owner) : 1 +#else + 1 +#endif + ); d = (void *) p; return 0; @@ -593,7 +598,6 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) /* finally here the parent client is registered */ s->parent->clients = client; - p_drv->use_count++; if (p_drv->attach) { p_dev->instance = p_drv->attach(); if (!p_dev->instance) { @@ -727,7 +731,6 @@ static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) /* detach the "instance" */ p_drv = to_pcmcia_drv(p_dev->dev.driver); if (p_drv) { - p_drv->use_count--; if ((p_drv->detach) && (p_dev->instance)) p_drv->detach(p_dev->instance); module_put(p_drv->owner); diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index 9a25e32eca9b..3f1e4ccbb31f 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -132,7 +132,6 @@ struct pcmcia_socket; extern struct bus_type pcmcia_bus_type; struct pcmcia_driver { - int use_count; dev_link_t *(*attach)(void); void (*detach)(dev_link_t *); struct module *owner; -- cgit v1.2.3 From 249b2be4f41cd018f89238a5e03dbb16b4bff496 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:21:13 -0800 Subject: [PATCH] pcmcia: device model integration can only be submitted under GPL, part 2 As discussed previously, my integration of ds.c and cs.c with the driver model can and will only be available under the GPL, as it's too much derived of other buses' implementation of integration with the driver model. cs_internal.h did only contain the MPL header before - I contacted Dave Hinds because of this, and as far as he can tell, it was just an oversight that this was not marked as dual-licensed as the other files are. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/bulkmem.c | 45 ++++++++++++------------------------------ drivers/pcmcia/cardbus.c | 45 ++++++++++++------------------------------ drivers/pcmcia/cistpl.c | 45 ++++++++++++------------------------------ drivers/pcmcia/cs.c | 47 +++++++++++++------------------------------- drivers/pcmcia/cs_internal.h | 18 +++++++---------- drivers/pcmcia/rsrc_mgr.c | 45 ++++++++++++------------------------------ include/pcmcia/bulkmem.h | 28 +++++--------------------- include/pcmcia/ciscode.h | 25 +++++------------------ include/pcmcia/cisreg.h | 25 +++++------------------ include/pcmcia/cistpl.h | 25 +++++------------------ include/pcmcia/cs.h | 25 +++++------------------ include/pcmcia/cs_types.h | 25 +++++------------------ include/pcmcia/mem_op.h | 25 +++++------------------ include/pcmcia/ss.h | 25 +++++------------------ 14 files changed, 113 insertions(+), 335 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c index 855c1f76c5dd..1be40034acd4 100644 --- a/drivers/pcmcia/bulkmem.c +++ b/drivers/pcmcia/bulkmem.c @@ -1,35 +1,16 @@ -/*====================================================================== - - PCMCIA Bulk Memory Services - - bulkmem.c 1.38 2000/09/25 19:29:51 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ +/* + * bulkmem.c -- 16-bit PCMCIA Bulk Memory Services + * + * 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. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * (C) 1999 David A. Hinds + */ #include #include diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 1b86c6d3a572..3ccb5247ec50 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -1,35 +1,16 @@ -/*====================================================================== - - Cardbus device configuration - - cardbus.c 1.87 2002/10/24 06:11:41 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ +/* + * cardbus.c -- 16-bit PCMCIA core support + * + * 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. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * (C) 1999 David A. Hinds + */ /* * Cardbus handling has been re-written to be more of a PCI bridge thing, diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 8cf0623397f7..9dbc73df87ee 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1,35 +1,16 @@ -/*====================================================================== - - PCMCIA Card Information Structure parser - - cistpl.c 1.99 2002/10/24 06:11:48 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ +/* + * cistpl.c -- 16-bit PCMCIA Card Information Structure parser + * + * 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. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * (C) 1999 David A. Hinds + */ #include #include diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index c8de9491938c..192ffc4540cf 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -1,35 +1,16 @@ -/*====================================================================== - - Kernel Card Services -- core services - - cs.c 1.271 2000/10/02 20:27:49 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ +/* + * cs.c -- Kernel Card Services - core services + * + * 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. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * (C) 1999 David A. Hinds + */ #include #include @@ -92,7 +73,7 @@ static const char *options = "options: " OPTIONS; MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("Linux Kernel Card Services\noptions:" OPTIONS); -MODULE_LICENSE("Dual MPL/GPL"); +MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index dcb1c651724f..67f85f56fe9d 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -1,19 +1,15 @@ /* - * cs_internal.h 1.57 2002/10/24 06:11:43 + * cs_internal.h * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * (C) 1999 David A. Hinds */ #ifndef _LINUX_CS_INTERNAL_H diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 4e0ca166dade..481758277a4d 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -1,35 +1,16 @@ -/*====================================================================== - - Resource management routines - - rsrc_mgr.c 1.79 2000/08/30 20:23:58 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ +/* + * rsrc_mgr.c -- Resource management routines + * + * 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. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * (C) 1999 David A. Hinds + */ #include #include diff --git a/include/pcmcia/bulkmem.h b/include/pcmcia/bulkmem.h index f6954220f419..b53b78d497ba 100644 --- a/include/pcmcia/bulkmem.h +++ b/include/pcmcia/bulkmem.h @@ -1,33 +1,15 @@ /* - * Definitions for bulk memory services + * bulkmem.h -- Definitions for bulk memory services * - * bulkmem.h 1.12 2000/06/12 21:55:41 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * bulkmem.h 1.3 1995/05/27 04:49:49 + * (C) 1999 David A. Hinds */ #ifndef _LINUX_BULKMEM_H diff --git a/include/pcmcia/ciscode.h b/include/pcmcia/ciscode.h index 0d84b163d055..2000b43ece91 100644 --- a/include/pcmcia/ciscode.h +++ b/include/pcmcia/ciscode.h @@ -1,30 +1,15 @@ /* - * ciscode.h 1.56 2002/10/25 06:37:30 + * ciscode.h -- Definitions for bulk memory services * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. + * (C) 1999 David A. Hinds */ #ifndef _LINUX_CISCODE_H diff --git a/include/pcmcia/cisreg.h b/include/pcmcia/cisreg.h index 803d2c369a4b..ddaad465502e 100644 --- a/include/pcmcia/cisreg.h +++ b/include/pcmcia/cisreg.h @@ -1,30 +1,15 @@ /* - * cisreg.h 1.17 2000/06/12 21:55:41 + * cisreg.h * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. + * (C) 1999 David A. Hinds */ #ifndef _LINUX_CISREG_H diff --git a/include/pcmcia/cistpl.h b/include/pcmcia/cistpl.h index 499f748c0028..c6a069554fd7 100644 --- a/include/pcmcia/cistpl.h +++ b/include/pcmcia/cistpl.h @@ -1,30 +1,15 @@ /* - * cistpl.h 1.34 2000/06/19 23:18:12 + * cistpl.h * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. + * (C) 1999 David A. Hinds */ #ifndef _LINUX_CISTPL_H diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h index 4a82490a1e45..8bd6081c5f8f 100644 --- a/include/pcmcia/cs.h +++ b/include/pcmcia/cs.h @@ -1,30 +1,15 @@ /* - * cs.h 1.71 2000/08/29 00:54:20 + * cs.h * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. + * (C) 1999 David A. Hinds */ #ifndef _LINUX_CS_H diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h index 3a4aec08549e..b57c921998f0 100644 --- a/include/pcmcia/cs_types.h +++ b/include/pcmcia/cs_types.h @@ -1,30 +1,15 @@ /* - * cs_types.h 1.18 2000/06/12 21:55:40 + * cs_types.h * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. + * (C) 1999 David A. Hinds */ #ifndef _LINUX_CS_TYPES_H diff --git a/include/pcmcia/mem_op.h b/include/pcmcia/mem_op.h index 261dd5bbbdf2..8d19b9401a5b 100644 --- a/include/pcmcia/mem_op.h +++ b/include/pcmcia/mem_op.h @@ -1,30 +1,15 @@ /* - * mem_op.h 1.13 2000/06/12 21:55:40 + * mem_op.h * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. + * (C) 1999 David A. Hinds */ #ifndef _LINUX_MEM_OP_H diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index c8c53fc0ef07..cc679ac74891 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -1,30 +1,15 @@ /* - * ss.h 1.28 2000/06/12 21:55:40 + * ss.h * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. + * 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. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. + * (C) 1999 David A. Hinds */ #ifndef _LINUX_SS_H -- cgit v1.2.3 From b504f217c32be942c0634c415e668d11726ef7e4 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:21:40 -0800 Subject: [PATCH] pcmcia: add pcmcia_(put,get)_socket Add pcmcia_{put,get}_socket Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/cs.c | 23 +++++++++++++++++++++++ include/pcmcia/cs.h | 3 +++ 2 files changed, 26 insertions(+) (limited to 'include') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 192ffc4540cf..c7827c26db94 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -172,6 +172,29 @@ int pcmcia_socket_dev_resume(struct device *dev) EXPORT_SYMBOL(pcmcia_socket_dev_resume); +struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt) +{ + struct class_device *cl_dev = class_device_get(&skt->dev); + if (!cl_dev) + return NULL; + skt = class_get_devdata(cl_dev); + if (!try_module_get(skt->owner)) { + class_device_put(&skt->dev); + return NULL; + } + return (skt); +} +EXPORT_SYMBOL(pcmcia_get_socket); + + +void pcmcia_put_socket(struct pcmcia_socket *skt) +{ + module_put(skt->owner); + class_device_put(&skt->dev); +} +EXPORT_SYMBOL(pcmcia_put_socket); + + static void pcmcia_release_socket(struct class_device *class_dev) { struct pcmcia_socket *socket = class_get_devdata(class_dev); diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h index 8bd6081c5f8f..bcc0abee07eb 100644 --- a/include/pcmcia/cs.h +++ b/include/pcmcia/cs.h @@ -426,6 +426,9 @@ int pcmcia_modify_window(window_handle_t win, modwin_t *req); int pcmcia_set_event_mask(client_handle_t handle, eventmask_t *mask); #endif +struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt); +void pcmcia_put_socket(struct pcmcia_socket *skt); + #endif /* __KERNEL__ */ #endif /* _LINUX_CS_H */ -- cgit v1.2.3 From 00bfce19fba26c176381ddde535e5d85efdeea19 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:22:20 -0800 Subject: [PATCH] pcmcia: add a pointer to client in struct pcmcia_device Add a pointer to the "client" structure to struct pcmcia_device. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 1 + include/pcmcia/ds.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'include') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 77adb5f06185..107a48ba4ac8 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -704,6 +704,7 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) p_dev->socket = s->parent; p_dev->device_no = (s->device_count++); p_dev->func = bind_info->function; + p_dev->client = client; p_dev->dev.bus = &pcmcia_bus_type; p_dev->dev.parent = s->parent->dev.dev; diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index 3f1e4ccbb31f..ba49e8bc7abd 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -128,6 +128,7 @@ typedef struct dev_link_t { struct pcmcia_socket; +struct client_t; extern struct bus_type pcmcia_bus_type; @@ -158,6 +159,7 @@ struct pcmcia_device { /* deprecated, a cleaned up version will be moved into this struct soon */ dev_link_t *instance; + struct client_t *client; struct device dev; }; -- cgit v1.2.3 From d56666b522432b244f38f52f89a3ccf275c4e41d Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:24:11 -0800 Subject: [PATCH] pcmcia: move struct client_t inside struct pcmcia_device Move the struct client_t inside struct pcmcia_device. This means it gets proper reference counting as well. The clients list inside struct pcmcia_socket can be removed now. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/bulkmem.c | 1 + drivers/pcmcia/cs.c | 4 +- drivers/pcmcia/cs_internal.h | 14 +------ drivers/pcmcia/ds.c | 88 +++++++++++++++----------------------------- include/pcmcia/ds.h | 15 +++++++- include/pcmcia/ss.h | 1 - 6 files changed, 46 insertions(+), 77 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c index 1be40034acd4..8997b5c04a9e 100644 --- a/drivers/pcmcia/bulkmem.c +++ b/drivers/pcmcia/bulkmem.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "cs_internal.h" #ifdef DEBUG diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index b93ec422c78a..e875cb399ffb 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "cs_internal.h" #ifdef CONFIG_PCI @@ -199,8 +200,6 @@ static void pcmcia_release_socket(struct class_device *class_dev) { struct pcmcia_socket *socket = class_get_devdata(class_dev); - BUG_ON(socket->clients); - complete(&socket->socket_released); } @@ -369,7 +368,6 @@ static void shutdown_socket(struct pcmcia_socket *s) kfree(s->config); s->config = NULL; } - BUG_ON(s->clients); free_regions(&s->a_region); free_regions(&s->c_region); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 67f85f56fe9d..6d441e178f63 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -18,19 +18,7 @@ #include #define CLIENT_MAGIC 0x51E6 -typedef struct client_t { - u_short client_magic; - struct pcmcia_socket *Socket; - u_char Function; - dev_info_t dev_info; - u_int Attributes; - u_int state; - event_t EventMask, PendingEvents; - int (*event_handler)(event_t event, int priority, - event_callback_args_t *); - event_callback_args_t event_callback_args; - struct client_t *next; -} client_t; +typedef struct client_t client_t; /* Flags in client state */ #define CLIENT_CONFIG_LOCKED 0x0001 diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 059f02471b62..f6609d8f4639 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -356,6 +356,7 @@ static void pcmcia_put_dev(struct pcmcia_device *p_dev) static void pcmcia_release_dev(struct device *dev) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + ds_dbg(1, "releasing dev %p\n", p_dev); pcmcia_put_bus_socket(p_dev->socket->pcmcia); kfree(p_dev); } @@ -430,11 +431,11 @@ static int send_event_callback(struct device *dev, void * _data) if (p_dev->socket != data->skt) return 0; - if (p_dev->client->state & (CLIENT_UNBOUND|CLIENT_STALE)) + if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE)) return 0; - if (p_dev->client->EventMask & data->event) - return EVENT(p_dev->client, data->event, data->priority); + if (p_dev->client.EventMask & data->event) + return EVENT(&p_dev->client, data->event, data->priority); return 0; } @@ -559,10 +560,10 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { struct pcmcia_driver *p_drv; struct pcmcia_device *p_dev, *tmp_dev; - client_t *client; unsigned long flags; int ret = 0; + s = pcmcia_get_bus_socket(s); if (!s) return -EINVAL; @@ -570,25 +571,10 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) (char *)bind_info->dev_info); p_drv = get_pcmcia_driver(&bind_info->dev_info); - if (!p_drv) - return -EINVAL; - - if (!try_module_get(p_drv->owner)) - return -EINVAL; - - client = (client_t *) kmalloc(sizeof(client_t), GFP_KERNEL); - if (!client) { - ret = -ENOMEM; + if ((!p_drv) || (!try_module_get(p_drv->owner))) { + ret = -EINVAL; goto err_put; } - memset(client, 0, sizeof(client_t)); - - client->client_magic = CLIENT_MAGIC; - client->Socket = s->parent; - client->Function = bind_info->function; - client->state = CLIENT_UNBOUND; - client->next = s->parent->clients; - strlcpy(client->dev_info, p_drv->drv.name, DEV_NAME_LEN); /* Currently, the userspace pcmcia cardmgr detects pcmcia devices. * Here this information is translated into a kernel @@ -598,21 +584,13 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); if (!p_dev) { ret = -ENOMEM; - goto err_free_client; + goto err_put_module; } memset(p_dev, 0, sizeof(struct pcmcia_device)); - s = pcmcia_get_bus_socket(s); - if (!s) { - ret = -ENODEV; - kfree(p_dev); - goto err_free_client; - } - p_dev->socket = s->parent; p_dev->device_no = (s->device_count++); p_dev->func = bind_info->function; - p_dev->client = client; p_dev->dev.bus = &pcmcia_bus_type; p_dev->dev.parent = s->parent->dev.dev; @@ -620,11 +598,17 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) sprintf (p_dev->dev.bus_id, "pcmcia%d.%d", p_dev->socket->sock, p_dev->device_no); p_dev->dev.driver = &p_drv->drv; + /* compat */ + p_dev->client.client_magic = CLIENT_MAGIC; + p_dev->client.Socket = s->parent; + p_dev->client.Function = bind_info->function; + p_dev->client.state = CLIENT_UNBOUND; + strlcpy(p_dev->client.dev_info, p_drv->drv.name, DEV_NAME_LEN); + ret = device_register(&p_dev->dev); if (ret) { kfree(p_dev); - pcmcia_put_bus_socket(s); - goto err_free_client; + goto err_put_module; } /* Add to the list in pcmcia_bus_socket, but only if no device @@ -642,15 +626,11 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) list_add_tail(&p_dev->socket_device_list, &s->devices_list); spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - /* finally here the parent client is registered */ - s->parent->clients = client; - if (p_drv->attach) { p_dev->instance = p_drv->attach(); - if (!p_dev->instance) { + if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) { printk(KERN_NOTICE "ds: unable to create instance " "of '%s'!\n", (char *)bind_info->dev_info); - /* FIXME: client isn't freed here */ ret = -ENODEV; goto err_unregister; } @@ -660,11 +640,14 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) err_unregister: device_unregister(&p_dev->dev); - err_free_client: - kfree(client); - err_put: module_put(p_drv->owner); return (ret); + + err_put_module: + module_put(p_drv->owner); + err_put: + pcmcia_put_bus_socket(s); + return (ret); } /* bind_request */ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) @@ -690,11 +673,11 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) continue; spin_lock_irqsave(&pcmcia_dev_list_lock, flags); list_for_each_entry(p_dev, &skt->devices_list, socket_device_list) { - if ((p_dev->client->state & CLIENT_UNBOUND) && - (!strcmp(p_dev->client->dev_info, (char *)req->dev_info))) { + if ((p_dev->client.state & CLIENT_UNBOUND) && + (!strcmp(p_dev->client.dev_info, (char *)req->dev_info))) { p_dev = pcmcia_get_dev(p_dev); if (p_dev) - client = p_dev->client; + client = &p_dev->client; spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); goto found; } @@ -753,7 +736,6 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) } up(&s->skt_sem); - pcmcia_put_dev(p_dev); /* FIXME: put in deregister_client. */ return CS_SUCCESS; out_no_resource: @@ -877,7 +859,7 @@ static int unbind_request(struct pcmcia_bus_socket *s) } p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); list_del(&p_dev->socket_device_list); - p_dev->client->state |= CLIENT_STALE; + p_dev->client.state |= CLIENT_STALE; spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); /* detach the "instance" */ @@ -896,10 +878,9 @@ static int unbind_request(struct pcmcia_bus_socket *s) int pcmcia_deregister_client(client_handle_t handle) { - client_t **client; struct pcmcia_socket *s; - u_long flags; int i; + struct pcmcia_device *p_dev = handle_to_pdev(handle); if (CHECK_HANDLE(handle)) return CS_BAD_HANDLE; @@ -914,18 +895,9 @@ int pcmcia_deregister_client(client_handle_t handle) goto warn_out; if (handle->state & CLIENT_STALE) { - spin_lock_irqsave(&s->lock, flags); - client = &s->clients; - while ((*client) && ((*client) != handle)) - client = &(*client)->next; - if (*client == NULL) { - spin_unlock_irqrestore(&s->lock, flags); - return CS_BAD_HANDLE; - } - *client = handle->next; handle->client_magic = 0; - kfree(handle); - spin_unlock_irqrestore(&s->lock, flags); + handle->state &= ~CLIENT_STALE; + pcmcia_put_dev(p_dev); } else { handle->state = CLIENT_UNBOUND; handle->event_handler = NULL; diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index ba49e8bc7abd..c8223b32742e 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -128,7 +128,6 @@ typedef struct dev_link_t { struct pcmcia_socket; -struct client_t; extern struct bus_type pcmcia_bus_type; @@ -159,7 +158,18 @@ struct pcmcia_device { /* deprecated, a cleaned up version will be moved into this struct soon */ dev_link_t *instance; - struct client_t *client; + struct client_t { + u_short client_magic; + struct pcmcia_socket *Socket; + u_char Function; + dev_info_t dev_info; + u_int Attributes; + u_int state; + event_t EventMask, PendingEvents; + int (*event_handler) (event_t event, int priority, + event_callback_args_t *); + event_callback_args_t event_callback_args; + } client; struct device dev; }; @@ -167,6 +177,7 @@ struct pcmcia_device { #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev) #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv) +#define handle_to_pdev(handle) container_of(handle, struct pcmcia_device, client); /* error reporting */ void cs_error(client_handle_t handle, int func, int ret); diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index cc679ac74891..fc8080f2b691 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -153,7 +153,6 @@ struct pcmcia_socket { u_int state; u_short functions; u_short lock_count; - client_handle_t clients; pccard_mem_map cis_mem; void __iomem *cis_virt; struct config_t *config; -- cgit v1.2.3 From 301d0dc6bc4b1d148f23da8ac006247a6f7bb719 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:24:39 -0800 Subject: [PATCH] pcmcia: SET_NETDEV for network devices This patch updates pcmcia network drivers so that their class devices are linked to the correct physical device. Based on an patch by Adam Belay, but adapted to a different pcmcia driver model implementation. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/pcmcia/3c574_cs.c | 1 + drivers/net/pcmcia/3c589_cs.c | 1 + drivers/net/pcmcia/axnet_cs.c | 1 + drivers/net/pcmcia/com20020_cs.c | 1 + drivers/net/pcmcia/fmvj18x_cs.c | 1 + drivers/net/pcmcia/ibmtr_cs.c | 1 + drivers/net/pcmcia/nmclan_cs.c | 1 + drivers/net/pcmcia/pcnet_cs.c | 1 + drivers/net/pcmcia/smc91c92_cs.c | 1 + drivers/net/pcmcia/xirc2ps_cs.c | 1 + include/pcmcia/ds.h | 1 + 11 files changed, 11 insertions(+) (limited to 'include') diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 1154fbbc0dc4..f29d4f88e874 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -519,6 +519,7 @@ static void tc574_config(dev_link_t *link) link->state &= ~DEV_CONFIG_PENDING; link->dev = &lp->node; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 2dd8f774dc5a..108d67066d4c 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -391,6 +391,7 @@ static void tc589_config(dev_link_t *link) link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if (register_netdev(dev) != 0) { printk(KERN_ERR "3c589_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 91be6752dd39..a01842d09324 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -458,6 +458,7 @@ static void axnet_config(dev_link_t *link) info->phy_id = (i < 32) ? i : -1; link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 1cf038aa604a..c39124e79b76 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -394,6 +394,7 @@ static void com20020_config(dev_link_t *link) link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); i = com20020_found(dev, 0); /* calls register_netdev */ diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index d5b1bb63936b..e077d1510a3a 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -591,6 +591,7 @@ static void fmvj18x_config(dev_link_t *link) lp->cardtype = cardtype; link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 886398f1d15c..ca1efb928c41 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -366,6 +366,7 @@ static void ibmtr_config(dev_link_t *link) link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); i = ibmtr_probe_card(dev); if (i != 0) { diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 8e616d4dccd8..7410230d69c8 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -775,6 +775,7 @@ static void nmclan_config(dev_link_t *link) link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); i = register_netdev(dev); if (i != 0) { diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index b9ca8347f9e6..0aa0ec3f3113 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -722,6 +722,7 @@ static void pcnet_config(dev_link_t *link) link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = ei_poll; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 8a381612fef7..99ce9a2bbfcd 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1024,6 +1024,7 @@ static void smc91c92_config(dev_link_t *link) link->dev = &smc->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if (register_netdev(dev) != 0) { printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 0f5a664841b7..cbf072b06d2b 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1121,6 +1121,7 @@ xirc2ps_config(dev_link_t * link) link->dev = &local->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if ((err=register_netdev(dev))) { printk(KNOT_XIRC "register_netdev() failed\n"); diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index c8223b32742e..eeb118ceced1 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -178,6 +178,7 @@ struct pcmcia_device { #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv) #define handle_to_pdev(handle) container_of(handle, struct pcmcia_device, client); +#define handle_to_dev(handle) ((container_of(handle, struct pcmcia_device, client))->dev) /* error reporting */ void cs_error(client_handle_t handle, int func, int ret); -- cgit v1.2.3 From ff274f25ca7dc5decce21db4411d2aa5655fe8e4 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:26:22 -0800 Subject: [PATCH] pcmcia: remove obsolete code Remove the code marked as obsolete -- nobody complained. Signed-off-by: Dominik Broodwski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/Kconfig | 12 --------- drivers/pcmcia/bulkmem.c | 46 -------------------------------- drivers/pcmcia/cs.c | 60 ------------------------------------------ drivers/pcmcia/pcmcia_compat.c | 20 -------------- include/pcmcia/cs.h | 7 ----- 5 files changed, 145 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 37b643d24825..22f3c9a0841e 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -39,18 +39,6 @@ config PCMCIA_DEBUG In all the above examples, N is the debugging verbosity level. -config PCMCIA_OBSOLETE - bool "Enable obsolete PCCARD code" - depends on PCCARD != n - help - Say Y here to enable some code found in the PCCARD subsystem - which has no in-kernel usage, but might be needed for certain - external PCMCIA drivers. If you do need to say Y here so that - one such driver compiles and/or works correctly, please report - this to linux-pcmcia lists.infradead.org - - If unsure, say N - config PCMCIA tristate "16-bit PCMCIA support" depends on PCCARD diff --git a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c index 8997b5c04a9e..1ce023699a96 100644 --- a/drivers/pcmcia/bulkmem.c +++ b/drivers/pcmcia/bulkmem.c @@ -152,49 +152,3 @@ int pccard_get_next_region(struct pcmcia_socket *s, region_info_t *rgn) return pccard_match_region(rgn->next, rgn); } /* get_next_region */ - -#ifdef CONFIG_PCMCIA_OBSOLETE - -static int match_region(client_handle_t handle, memory_handle_t list, - region_info_t *match) -{ - while (list != NULL) { - if (!(handle->Attributes & INFO_MTD_CLIENT) || - (strcmp(handle->dev_info, list->dev_info) == 0)) { - *match = list->info; - return CS_SUCCESS; - } - list = list->info.next; - } - return CS_NO_MORE_ITEMS; -} /* match_region */ - -int pcmcia_get_first_region(client_handle_t handle, region_info_t *rgn) -{ - struct pcmcia_socket *s = SOCKET(handle); - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - - if ((handle->Attributes & INFO_MASTER_CLIENT) && - (!(s->state & SOCKET_REGION_INFO))) { - setup_regions(s, handle->Function, 0, &s->c_region); - setup_regions(s, handle->Function, 1, &s->a_region); - s->state |= SOCKET_REGION_INFO; - } - - if (rgn->Attributes & REGION_TYPE_AM) - return match_region(handle, s->a_region, rgn); - else - return match_region(handle, s->c_region, rgn); -} /* get_first_region */ -EXPORT_SYMBOL(pcmcia_get_first_region); - -int pcmcia_get_next_region(client_handle_t handle, region_info_t *rgn) -{ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - return match_region(handle, rgn->next, rgn); -} /* get_next_region */ -EXPORT_SYMBOL(pcmcia_get_next_region); - -#endif diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index e875cb399ffb..298bd4689897 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -1147,37 +1147,6 @@ int pcmcia_modify_configuration(client_handle_t handle, return CS_SUCCESS; } /* modify_configuration */ -#ifdef CONFIG_PCMCIA_OBSOLETE - -/*====================================================================== - - Modify the attributes of a window returned by RequestWindow. - -======================================================================*/ - -int pcmcia_modify_window(window_handle_t win, modwin_t *req) -{ - if ((win == NULL) || (win->magic != WINDOW_MAGIC)) - return CS_BAD_HANDLE; - - win->ctl.flags &= ~(MAP_ATTRIB|MAP_ACTIVE); - if (req->Attributes & WIN_MEMORY_TYPE) - win->ctl.flags |= MAP_ATTRIB; - if (req->Attributes & WIN_ENABLE) - win->ctl.flags |= MAP_ACTIVE; - if (req->Attributes & WIN_DATA_WIDTH_16) - win->ctl.flags |= MAP_16BIT; - if (req->Attributes & WIN_USE_WAIT) - win->ctl.flags |= MAP_USE_WAIT; - win->ctl.speed = req->AccessSpeed; - win->sock->ops->set_mem_map(win->sock, &win->ctl); - - return CS_SUCCESS; -} /* modify_window */ -EXPORT_SYMBOL(pcmcia_modify_window); - -#endif /* CONFIG_PCMCIA_OBSOLETE */ - /* register pcmcia_callback */ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) { @@ -1863,35 +1832,6 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) return ret; } /* insert_card */ -/*====================================================================== - - Maybe this should send a CS_EVENT_CARD_INSERTION event if we - haven't sent one to this client yet? - -======================================================================*/ - -#ifdef CONFIG_PCMCIA_OBSOLETE -int pcmcia_set_event_mask(client_handle_t handle, eventmask_t *mask) -{ - u_int events, bit; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - if (handle->Attributes & CONF_EVENT_MASK_VALID) - return CS_BAD_SOCKET; - handle->EventMask = mask->EventMask; - events = handle->PendingEvents & handle->EventMask; - handle->PendingEvents -= events; - while (events != 0) { - bit = ((events ^ (events-1)) + 1) >> 1; - EVENT(handle, bit, CS_EVENT_PRI_LOW); - events -= bit; - } - return CS_SUCCESS; -} /* set_event_mask */ -EXPORT_SYMBOL(pcmcia_set_event_mask); - -#endif /* CONFIG_PCMCIA_OBSOLETE */ - /*====================================================================== OS-specific module glue goes here diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c index 673d34576d3b..68b80084f83f 100644 --- a/drivers/pcmcia/pcmcia_compat.c +++ b/drivers/pcmcia/pcmcia_compat.c @@ -123,23 +123,3 @@ int pcmcia_access_configuration_register(client_handle_t handle, } EXPORT_SYMBOL(pcmcia_access_configuration_register); -#ifdef CONFIG_PCMCIA_OBSOLETE - -int pcmcia_get_first_window(window_handle_t *win, win_req_t *req) -{ - if ((win == NULL) || ((*win)->magic != WINDOW_MAGIC)) - return CS_BAD_HANDLE; - - return pcmcia_get_window(((client_handle_t)*win)->Socket, win, 0, req); -} -EXPORT_SYMBOL(pcmcia_get_first_window); - -int pcmcia_get_next_window(window_handle_t *win, win_req_t *req) -{ - if ((win == NULL) || ((*win)->magic != WINDOW_MAGIC)) - return CS_BAD_HANDLE; - return pcmcia_get_window((*win)->sock, win, (*win)->index+1, req); -} -EXPORT_SYMBOL(pcmcia_get_next_window); - -#endif diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h index bcc0abee07eb..dfc7ede3c0fb 100644 --- a/include/pcmcia/cs.h +++ b/include/pcmcia/cs.h @@ -419,13 +419,6 @@ int pcmcia_eject_card(struct pcmcia_socket *skt); int pcmcia_insert_card(struct pcmcia_socket *skt); int pcmcia_report_error(client_handle_t handle, error_info_t *err); -#ifdef CONFIG_PCMCIA_OBSOLETE -int pcmcia_get_first_client(client_handle_t *handle, client_req_t *req); -int pcmcia_get_next_client(client_handle_t *handle, client_req_t *req); -int pcmcia_modify_window(window_handle_t win, modwin_t *req); -int pcmcia_set_event_mask(client_handle_t handle, eventmask_t *mask); -#endif - struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt); void pcmcia_put_socket(struct pcmcia_socket *skt); -- cgit v1.2.3 From bbdedd8fb89e19647576019a5f34d9108dd184c1 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:26:35 -0800 Subject: [PATCH] pcmcia: remove pending_events PendingEvents is unused, so remove it Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 2 -- include/pcmcia/ds.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 78857f9f0cac..ee08e945e1fb 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -741,8 +741,6 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) { if (client->EventMask & CS_EVENT_CARD_INSERTION) EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); - else - client->PendingEvents |= CS_EVENT_CARD_INSERTION; } up(&s->skt_sem); diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index eeb118ceced1..c579df808e5b 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -165,7 +165,7 @@ struct pcmcia_device { dev_info_t dev_info; u_int Attributes; u_int state; - event_t EventMask, PendingEvents; + event_t EventMask; int (*event_handler) (event_t event, int priority, event_callback_args_t *); event_callback_args_t event_callback_args; -- cgit v1.2.3 From b1b3650d7652a786bfe85f53c09378d06ad2a13f Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:26:51 -0800 Subject: [PATCH] pcmcia: remove client_attributes Remove the "Attributes" entry of struct client_t -- _all_ in-kernel drivers did set it to INFO_IO_CLIENT | INFO_CARD_SHARE anyway, and the pcmcia core didn't care at all what this value was set to. Also, remove the setting of the respective request field in all in-kernel drivers -- the request structure is kept the same, though, to keep external drivers compiling. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/bluetooth/bluecard_cs.c | 1 - drivers/bluetooth/bt3c_cs.c | 1 - drivers/bluetooth/btuart_cs.c | 1 - drivers/bluetooth/dtl1_cs.c | 1 - drivers/char/pcmcia/synclink_cs.c | 1 - drivers/ide/legacy/ide-cs.c | 1 - drivers/isdn/hardware/avm/avm_cs.c | 1 - drivers/isdn/hisax/avma1_cs.c | 1 - drivers/isdn/hisax/elsa_cs.c | 1 - drivers/isdn/hisax/sedlbauer_cs.c | 1 - drivers/isdn/hisax/teles_cs.c | 1 - drivers/mtd/maps/pcmciamtd.c | 1 - drivers/net/pcmcia/3c574_cs.c | 1 - drivers/net/pcmcia/3c589_cs.c | 1 - drivers/net/pcmcia/axnet_cs.c | 1 - drivers/net/pcmcia/com20020_cs.c | 1 - drivers/net/pcmcia/fmvj18x_cs.c | 1 - drivers/net/pcmcia/ibmtr_cs.c | 1 - drivers/net/pcmcia/nmclan_cs.c | 1 - drivers/net/pcmcia/pcnet_cs.c | 1 - drivers/net/pcmcia/smc91c92_cs.c | 1 - drivers/net/pcmcia/xirc2ps_cs.c | 1 - drivers/net/wireless/airo_cs.c | 1 - drivers/net/wireless/atmel_cs.c | 1 - drivers/net/wireless/netwave_cs.c | 1 - drivers/net/wireless/orinoco_cs.c | 1 - drivers/net/wireless/ray_cs.c | 1 - drivers/net/wireless/wavelan_cs.c | 1 - drivers/net/wireless/wl3501_cs.c | 1 - drivers/parport/parport_cs.c | 1 - drivers/pcmcia/ds.c | 1 - drivers/scsi/pcmcia/aha152x_stub.c | 1 - drivers/scsi/pcmcia/fdomain_stub.c | 1 - drivers/scsi/pcmcia/nsp_cs.c | 1 - drivers/scsi/pcmcia/qlogic_stub.c | 1 - drivers/scsi/pcmcia/sym53c500_cs.c | 1 - drivers/serial/serial_cs.c | 1 - drivers/telephony/ixj_pcmcia.c | 1 - include/pcmcia/cs.h | 4 ++-- include/pcmcia/ds.h | 1 - sound/pcmcia/pdaudiocf/pdaudiocf.c | 1 - sound/pcmcia/vx/vx_entry.c | 1 - 42 files changed, 2 insertions(+), 43 deletions(-) (limited to 'include') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 9a75536afb8d..325ab5d76786 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -904,7 +904,6 @@ static dev_link_t *bluecard_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 227e3e5a9d36..84977a0605e5 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -709,7 +709,6 @@ static dev_link_t *bt3c_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 4ba1dfa62911..38dbac8db507 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -628,7 +628,6 @@ static dev_link_t *btuart_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 2ea43e748695..9fcc8e4d2159 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -607,7 +607,6 @@ static dev_link_t *dtl1_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index d732bdcbfc45..c6accb1ab6ac 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -608,7 +608,6 @@ static dev_link_t *mgslpc_attach(void) dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 0e0047ef5760..b114113b0acb 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -144,7 +144,6 @@ static dev_link_t *ide_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index d1d615fc9e12..fbbfb9cfbc4e 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -178,7 +178,6 @@ static dev_link_t *avmcs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index b30a1e330f77..784df60d1a1f 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -193,7 +193,6 @@ static dev_link_t *avma1cs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 14f0f0fe246d..92349814990f 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -227,7 +227,6 @@ static dev_link_t *elsa_cs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 3802923e8b27..ab4f78a33def 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -240,7 +240,6 @@ static dev_link_t *sedlbauer_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 0f789f3b8df5..c17c25fd4713 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -208,7 +208,6 @@ static dev_link_t *teles_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 9c17b52fe5a7..e37b4c1976e5 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -800,7 +800,6 @@ static dev_link_t *pcmciamtd_attach(void) /* Register with Card Services */ client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index f29d4f88e874..3e05fd774128 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -322,7 +322,6 @@ static dev_link_t *tc574_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 108d67066d4c..00c82eafb21b 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -236,7 +236,6 @@ static dev_link_t *tc589_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index a01842d09324..c61fba0ea898 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -191,7 +191,6 @@ static dev_link_t *axnet_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index c39124e79b76..211fdac0a6eb 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -211,7 +211,6 @@ static dev_link_t *com20020_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index e077d1510a3a..850f1d94c5d6 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -299,7 +299,6 @@ static dev_link_t *fmvj18x_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index ca1efb928c41..c3ca9fb65912 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -204,7 +204,6 @@ static dev_link_t *ibmtr_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 7410230d69c8..35e66f0f9e42 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -512,7 +512,6 @@ static dev_link_t *nmclan_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 0aa0ec3f3113..ddaf72136c2d 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -286,7 +286,6 @@ static dev_link_t *pcnet_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 99ce9a2bbfcd..78f84e1f9fc8 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -374,7 +374,6 @@ static dev_link_t *smc91c92_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index cbf072b06d2b..aadbb787982c 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -627,7 +627,6 @@ xirc2ps_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index cee7eab30b22..16a973141091 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -225,7 +225,6 @@ static dev_link_t *airo_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 5ceec62a57af..3fe780d128d9 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -237,7 +237,6 @@ static dev_link_t *atmel_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index d19e7981863d..e2685634c2d5 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -503,7 +503,6 @@ static dev_link_t *netwave_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index ba2f3b50a65d..2c8618098602 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -197,7 +197,6 @@ orinoco_cs_attach(void) dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index c7c5c22c7ae2..e220781b03ae 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -398,7 +398,6 @@ static dev_link_t *ray_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 1509c5dadd50..a2b95854f4fc 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -4689,7 +4689,6 @@ wavelan_attach(void) /* Register with Card Services */ client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 5d4f4c32efb9..b0186c8398be 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -2015,7 +2015,6 @@ static dev_link_t *wl3501_attach(void) link->next = wl3501_dev_list; wl3501_dev_list = link; client_reg.dev_info = &wl3501_dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index f828b97ce9e7..d497877ef11c 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -143,7 +143,6 @@ static dev_link_t *parport_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index ee08e945e1fb..8ab0615c786b 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -709,7 +709,6 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) *handle = client; client->state &= ~CLIENT_UNBOUND; client->Socket = s; - client->Attributes = req->Attributes; client->EventMask = req->EventMask; client->event_handler = req->event_handler; client->event_callback_args = req->event_callback_args; diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index b82c0df05b9f..97d69da43825 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -145,7 +145,6 @@ static dev_link_t *aha152x_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.event_handler = &aha152x_event; client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 67d98b20650f..343b67578706 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -131,7 +131,6 @@ static dev_link_t *fdomain_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.event_handler = &fdomain_event; client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index b6d615a6b447..8aae1ae9fa9b 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1672,7 +1672,6 @@ static dev_link_t *nsp_cs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 23ac561c849b..4b66969ace4a 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -212,7 +212,6 @@ static dev_link_t *qlogic_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.event_handler = &qlogic_event; client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 84d06345614e..be3d3369cae6 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -995,7 +995,6 @@ SYM53C500_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.event_handler = &SYM53C500_event; client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 6b592a0d2fac..59dd5560fa1f 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -237,7 +237,6 @@ static dev_link_t *serial_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index 789c17c65b03..e1ef0d7ee8d1 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -69,7 +69,6 @@ static dev_link_t *ixj_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h index dfc7ede3c0fb..311682a7fef0 100644 --- a/include/pcmcia/cs.h +++ b/include/pcmcia/cs.h @@ -124,7 +124,7 @@ typedef struct client_req_t { /* For RegisterClient */ typedef struct client_reg_t { dev_info_t *dev_info; - u_int Attributes; + u_int Attributes; /* UNUSED */ u_int EventMask; int (*event_handler)(event_t event, int priority, event_callback_args_t *); @@ -279,7 +279,7 @@ typedef struct win_req_t { #define WIN_BAR_MASK 0xe000 #define WIN_BAR_SHIFT 13 -/* Attributes for RegisterClient */ +/* Attributes for RegisterClient -- UNUSED -- */ #define INFO_MASTER_CLIENT 0x01 #define INFO_IO_CLIENT 0x02 #define INFO_MTD_CLIENT 0x04 diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index c579df808e5b..e46ae96e867b 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -163,7 +163,6 @@ struct pcmcia_device { struct pcmcia_socket *Socket; u_char Function; dev_info_t dev_info; - u_int Attributes; u_int state; event_t EventMask; int (*event_handler) (event_t event, int priority, diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 1276b3652601..299bbf228358 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -183,7 +183,6 @@ static dev_link_t *snd_pdacf_attach(void) /* Register with Card Services */ client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL #ifdef CONFIG_PM diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c index ad2917e4e69f..8f59818fef8a 100644 --- a/sound/pcmcia/vx/vx_entry.c +++ b/sound/pcmcia/vx/vx_entry.c @@ -175,7 +175,6 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw) /* Register with Card Services */ memset(&client_reg, 0, sizeof(client_reg)); client_reg.dev_info = hw->dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL #ifdef CONFIG_PM -- cgit v1.2.3 From cfe963fa06f43cb8d97a230c9a3ecd632766d992 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:27:18 -0800 Subject: [PATCH] pcmcia: remove dev_info from client Remove the dev_info - contained name from struct client_t Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/cs.c | 3 ++- drivers/pcmcia/ds.c | 27 ++++++++++++++++++--------- include/pcmcia/ds.h | 1 - 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 30b2980f0176..4f8cf5cdd904 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -1530,6 +1530,7 @@ int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) struct pcmcia_socket *s; config_t *c; int ret = CS_IN_USE, irq = 0; + struct pcmcia_device *p_dev = handle_to_pdev(handle); if (CHECK_HANDLE(handle)) return CS_BAD_HANDLE; @@ -1579,7 +1580,7 @@ int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || (s->functions > 1) || (irq == s->pci_irq)) ? SA_SHIRQ : 0, - handle->dev_info, req->Instance)) + p_dev->dev.bus_id, req->Instance)) return CS_IN_USE; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 8ab0615c786b..db18d56c825f 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -221,8 +221,10 @@ int pcmcia_report_error(client_handle_t handle, error_info_t *err) if (CHECK_HANDLE(handle)) printk(KERN_NOTICE); - else - printk(KERN_NOTICE "%s: ", handle->dev_info); + else { + struct pcmcia_device *p_dev = handle_to_pdev(handle); + printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id); + } for (i = 0; i < ARRAY_SIZE(service_table); i++) if (service_table[i].key == err->func) @@ -608,7 +610,6 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) p_dev->client.Socket = s->parent; p_dev->client.Function = bind_info->function; p_dev->client.state = CLIENT_UNBOUND; - strlcpy(p_dev->client.dev_info, p_drv->drv.name, DEV_NAME_LEN); ret = device_register(&p_dev->dev); if (ret) { @@ -683,14 +684,22 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) continue; spin_lock_irqsave(&pcmcia_dev_list_lock, flags); list_for_each_entry(p_dev, &skt->devices_list, socket_device_list) { - if ((p_dev->client.state & CLIENT_UNBOUND) && - (!strcmp(p_dev->client.dev_info, (char *)req->dev_info))) { - p_dev = pcmcia_get_dev(p_dev); - if (p_dev) - client = &p_dev->client; + struct pcmcia_driver *p_drv; + p_dev = pcmcia_get_dev(p_dev); + if (!p_dev) + continue; + if ((!p_dev->client.state & CLIENT_UNBOUND) || + (!p_dev->dev.driver)) { + pcmcia_put_dev(p_dev); + continue; + } + p_drv = to_pcmcia_drv(p_dev->dev.driver); + if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) { + client = &p_dev->client; spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); goto found; } + pcmcia_put_dev(p_dev); } spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); pcmcia_put_bus_socket(skt); @@ -733,7 +742,7 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) } ds_dbg(1, "register_client(): client 0x%p, dev %s\n", - client, client->dev_info); + client, p_dev->dev.bus_id); if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE) EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW); diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index e46ae96e867b..1a7a03d8623a 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -162,7 +162,6 @@ struct pcmcia_device { u_short client_magic; struct pcmcia_socket *Socket; u_char Function; - dev_info_t dev_info; u_int state; event_t EventMask; int (*event_handler) (event_t event, int priority, -- cgit v1.2.3 From dd9b77563baf01b205b2016dc1caf473b9222831 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:27:45 -0800 Subject: [PATCH] pcmcia: per-socket resource database Make the io and mem db per-socket, as different sockets may have different requirements or may not even need the resource db at all (SS_CAP_STATIC_MAP). Updated to make rsrc_mem_probe per-socket and to remove unnecessary and even broken check for empty list as per Russell King's suggestions. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/cs.c | 6 ++- drivers/pcmcia/cs_internal.h | 2 +- drivers/pcmcia/rsrc_mgr.c | 99 +++++++++++++++++++++----------------------- include/pcmcia/ss.h | 10 +++++ 4 files changed, 63 insertions(+), 54 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 4f8cf5cdd904..9c21a58f835e 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -250,6 +250,10 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) socket->cis_mem.flags = 0; socket->cis_mem.speed = cis_speed; + /* init resource database */ + socket->mem_db.next = &socket->mem_db; + socket->io_db.next = &socket->io_db; + INIT_LIST_HEAD(&socket->cis_cache); spin_lock_init(&socket->lock); @@ -305,6 +309,7 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) up_write(&pcmcia_socket_list_rwsem); /* wait for sysfs to drop all references */ + release_resource_db(socket); wait_for_completion(&socket->socket_released); } /* pcmcia_unregister_socket */ EXPORT_SYMBOL(pcmcia_unregister_socket); @@ -1879,7 +1884,6 @@ static int __init init_pcmcia_cs(void) static void __exit exit_pcmcia_cs(void) { printk(KERN_INFO "unloading Kernel Card Services\n"); - release_resource_db(); class_interface_unregister(&pccard_sysfs_interface); class_unregister(&pcmcia_socket_class); } diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index e53886be55fe..f64ca5663f3c 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -143,7 +143,7 @@ struct resource *find_mem_region(u_long base, u_long num, u_long align, int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); -void release_resource_db(void); +void release_resource_db(struct pcmcia_socket *s); /* In socket_sysfs.c */ extern struct class_interface pccard_sysfs_interface; diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index a487cafb1903..d2aa1aabe219 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -53,23 +53,10 @@ INT_MODULE_PARM(mem_limit, 0x10000); ======================================================================*/ -typedef struct resource_map_t { - u_long base, num; - struct resource_map_t *next; -} resource_map_t; - -/* Memory resource database */ -static resource_map_t mem_db = { - .next = &mem_db, -}; - -/* IO port resource database */ -static resource_map_t io_db = { - .next = &io_db, -}; +typedef struct resource_map_t resource_map_t; static DECLARE_MUTEX(rsrc_sem); -static unsigned int rsrc_mem_probe; + #define MEM_PROBE_LOW (1 << 0) #define MEM_PROBE_HIGH (1 << 1) @@ -208,7 +195,7 @@ static int sub_interval(resource_map_t *map, u_long base, u_long num) ======================================================================*/ #ifdef CONFIG_PCMCIA_PROBE -static void do_io_probe(ioaddr_t base, ioaddr_t num) +static void do_io_probe(struct pcmcia_socket *s, ioaddr_t base, ioaddr_t num) { struct resource *res; ioaddr_t i, j, bad, any; @@ -253,7 +240,7 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num) bad = any = i; } else { if (bad) { - sub_interval(&io_db, bad, i-bad); + sub_interval(&s->io_db, bad, i-bad); printk(" %#04x-%#04x", bad, i-1); bad = 0; } @@ -264,7 +251,7 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num) printk(" nothing: probe failed.\n"); return; } else { - sub_interval(&io_db, bad, i-bad); + sub_interval(&s->io_db, bad, i-bad); printk(" %#04x-%#04x", bad, i-1); } } @@ -409,7 +396,7 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) if (i != j) { if (!bad) printk(" excluding"); printk(" %#05lx-%#05lx", i, j-1); - sub_interval(&mem_db, i, j-i); + sub_interval(&s->mem_db, i, j-i); bad += j-i; } } @@ -422,12 +409,12 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) static u_long inv_probe(resource_map_t *m, struct pcmcia_socket *s) { u_long ok; - if (m == &mem_db) + if (m == &s->mem_db) return 0; ok = inv_probe(m->next, s); if (ok) { if (m->base >= 0x100000) - sub_interval(&mem_db, m->base, m->num); + sub_interval(&s->mem_db, m->base, m->num); return ok; } if (m->base < 0x100000) @@ -443,14 +430,14 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) /* We do up to four passes through the list */ if (probe_mask & MEM_PROBE_HIGH) { - if (inv_probe(mem_db.next, s) > 0) + if (inv_probe(s->mem_db.next, s) > 0) return; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); } if ((probe_mask & MEM_PROBE_LOW) == 0) return; - for (m = mem_db.next; m != &mem_db; m = mm.next) { + for (m = s->mem_db.next; m != &s->mem_db; m = mm.next) { mm = *m; /* Only probe < 1 MB */ if (mm.base >= 0x100000) continue; @@ -463,7 +450,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) b = order[i] << 12; if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) { if (ok >= mem_limit) - sub_interval(&mem_db, b, 0x10000); + sub_interval(&s->mem_db, b, 0x10000); else ok += do_mem_probe(b, 0x10000, s); } @@ -477,7 +464,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { resource_map_t *m, mm; - for (m = mem_db.next; m != &mem_db; m = mm.next) { + for (m = s->mem_db.next; m != &s->mem_db; m = mm.next) { mm = *m; if (do_mem_probe(mm.base, mm.num, s)) break; @@ -501,8 +488,8 @@ void pcmcia_validate_mem(struct pcmcia_socket *s) if (s->features & SS_CAP_PAGE_REGS) probe_mask = MEM_PROBE_HIGH; - if (probe_mask & ~rsrc_mem_probe) { - rsrc_mem_probe |= probe_mask; + if (probe_mask & ~s->rsrc_mem_probe) { + s->rsrc_mem_probe |= probe_mask; down(&s->skt_sem); @@ -591,7 +578,7 @@ int adjust_io_region(struct resource *res, unsigned long r_start, int ret = -ENOMEM; down(&rsrc_sem); - for (m = io_db.next; m != &io_db; m = m->next) { + for (m = s->io_db.next; m != &s->io_db; m = m->next) { unsigned long start = m->base; unsigned long end = m->base + m->num - 1; @@ -632,7 +619,7 @@ struct resource *find_io_region(unsigned long base, int num, data.mask = align - 1; data.offset = base & data.mask; - data.map = &io_db; + data.map = &s->io_db; down(&rsrc_sem); #ifdef CONFIG_PCI @@ -664,7 +651,7 @@ struct resource *find_mem_region(u_long base, u_long num, u_long align, data.mask = align - 1; data.offset = base & data.mask; - data.map = &mem_db; + data.map = &s->mem_db; for (i = 0; i < 2; i++) { if (low) { @@ -830,7 +817,7 @@ void undo_irq(u_int Attributes, int irq) ======================================================================*/ -static int adjust_memory(adjust_t *adj) +static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) { u_long base, num; int ret; @@ -845,10 +832,10 @@ static int adjust_memory(adjust_t *adj) down(&rsrc_sem); switch (adj->Action) { case ADD_MANAGED_RESOURCE: - ret = add_interval(&mem_db, base, num); + ret = add_interval(&s->mem_db, base, num); break; case REMOVE_MANAGED_RESOURCE: - ret = sub_interval(&mem_db, base, num); + ret = sub_interval(&s->mem_db, base, num); if (ret == CS_SUCCESS) { struct pcmcia_socket *socket; down_read(&pcmcia_socket_list_rwsem); @@ -867,7 +854,7 @@ static int adjust_memory(adjust_t *adj) /*====================================================================*/ -static int adjust_io(adjust_t *adj) +static int adjust_io(struct pcmcia_socket *s, adjust_t *adj) { int base, num, ret = CS_SUCCESS; @@ -881,17 +868,17 @@ static int adjust_io(adjust_t *adj) down(&rsrc_sem); switch (adj->Action) { case ADD_MANAGED_RESOURCE: - if (add_interval(&io_db, base, num) != 0) { + if (add_interval(&s->io_db, base, num) != 0) { ret = CS_IN_USE; break; } #ifdef CONFIG_PCMCIA_PROBE if (probe_io) - do_io_probe(base, num); + do_io_probe(s, base, num); #endif break; case REMOVE_MANAGED_RESOURCE: - sub_interval(&io_db, base, num); + sub_interval(&s->io_db, base, num); break; default: ret = CS_UNSUPPORTED_FUNCTION; @@ -956,32 +943,40 @@ static int adjust_irq(adjust_t *adj) int pcmcia_adjust_resource_info(adjust_t *adj) { - switch (adj->Resource) { - case RES_MEMORY_RANGE: - return adjust_memory(adj); - break; - case RES_IO_RANGE: - return adjust_io(adj); - break; - case RES_IRQ: - return adjust_irq(adj); - break; - } - return CS_UNSUPPORTED_FUNCTION; + struct pcmcia_socket *s; + int ret = CS_UNSUPPORTED_FUNCTION; + + if (adj->Resource == RES_IRQ) + return adjust_irq(adj); + + down_read(&pcmcia_socket_list_rwsem); + list_for_each_entry(s, &pcmcia_socket_list, socket_list) { + switch (adj->Resource) { + case RES_MEMORY_RANGE: + ret = adjust_memory(s, adj); + break; + case RES_IO_RANGE: + ret = adjust_io(s, adj); + break; + } + } + up_read(&pcmcia_socket_list_rwsem); + + return (ret); } EXPORT_SYMBOL(pcmcia_adjust_resource_info); /*====================================================================*/ -void release_resource_db(void) +void release_resource_db(struct pcmcia_socket *s) { resource_map_t *p, *q; - for (p = mem_db.next; p != &mem_db; p = q) { + for (p = s->mem_db.next; p != &s->mem_db; p = q) { q = p->next; kfree(p); } - for (p = io_db.next; p != &io_db; p = q) { + for (p = s->io_db.next; p != &s->io_db; p = q) { q = p->next; kfree(p); } diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index fc8080f2b691..fe5bdada22f7 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -146,6 +146,12 @@ struct config_t; struct region_t; struct pcmcia_callback; +/* for io_db and mem_db */ +struct resource_map_t { + u_long base, num; + struct resource_map_t *next; +}; + struct pcmcia_socket { struct module *owner; spinlock_t lock; @@ -170,6 +176,10 @@ struct pcmcia_socket { struct list_head socket_list; struct completion socket_released; + struct resource_map_t mem_db; + struct resource_map_t io_db; + unsigned int rsrc_mem_probe; + /* deprecated */ unsigned int sock; /* socket number */ -- cgit v1.2.3 From 23d2f5dbc2b457b2f7f486f343ee8feece9eba8a Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:27:58 -0800 Subject: [PATCH] pcmcia: validate_mem only for non-statically mapped sockets validate_mem() does only make sense for !SS_CAP_STATIC_MAP sockets. Therefore, re-direct validate_mem() calls only for those. The newly added redirection layer will allow for a "library" module named "rsrc_nonstatic" which contains the resource database handling code, and it will only need to be loaded for the drivers which need it. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/cs.c | 6 +++++- drivers/pcmcia/cs_internal.h | 2 ++ drivers/pcmcia/rsrc_mgr.c | 17 ++++++++++++++++- include/pcmcia/ss.h | 5 +++++ 4 files changed, 28 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 9c21a58f835e..590b2a561890 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -250,7 +250,11 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) socket->cis_mem.flags = 0; socket->cis_mem.speed = cis_speed; - /* init resource database */ + /* init resource handling */ + if (socket->features & SS_CAP_STATIC_MAP) + socket->resource_ops = &pccard_static_ops; + else + socket->resource_ops = &pccard_nonstatic_ops; socket->mem_db.next = &socket->mem_db; socket->io_db.next = &socket->io_db; diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index f64ca5663f3c..764e71bcecab 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -144,6 +144,8 @@ int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); void release_resource_db(struct pcmcia_socket *s); +extern struct pccard_resource_ops pccard_static_ops; +extern struct pccard_resource_ops pccard_nonstatic_ops; /* In socket_sysfs.c */ extern struct class_interface pccard_sysfs_interface; diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index d2aa1aabe219..1bc69b669477 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -473,11 +473,12 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) #endif /* CONFIG_PCMCIA_PROBE */ + /* * Locking note: this is the only place where we take * both rsrc_sem and skt_sem. */ -void pcmcia_validate_mem(struct pcmcia_socket *s) +static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) { if (probe_mem) { unsigned int probe_mask; @@ -503,6 +504,11 @@ void pcmcia_validate_mem(struct pcmcia_socket *s) } } +void pcmcia_validate_mem(struct pcmcia_socket *s) +{ + if (s->resource_ops->validate_mem) + s->resource_ops->validate_mem(s); +} EXPORT_SYMBOL(pcmcia_validate_mem); struct pcmcia_align_data { @@ -981,3 +987,12 @@ void release_resource_db(struct pcmcia_socket *s) kfree(p); } } + + +struct pccard_resource_ops pccard_static_ops = { + .validate_mem = NULL, +}; + +struct pccard_resource_ops pccard_nonstatic_ops = { + .validate_mem = pcmcia_nonstatic_validate_mem, +}; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index fe5bdada22f7..d872a714fa28 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -115,6 +115,10 @@ struct pccard_operations { int (*set_mem_map)(struct pcmcia_socket *sock, struct pccard_mem_map *mem); }; +struct pccard_resource_ops { + void (*validate_mem) (struct pcmcia_socket *s); +}; + /* * Calls to set up low-level "Socket Services" drivers */ @@ -194,6 +198,7 @@ struct pcmcia_socket { /* socket operations */ struct pccard_operations * ops; + struct pccard_resource_ops * resource_ops; /* Zoom video behaviour is so chip specific its not worth adding this to _ops */ -- cgit v1.2.3 From aa4cb19247959d6c3ee9f0274f1d299155791aae Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:28:10 -0800 Subject: [PATCH] pcmcia: adjust_io_region only for non-statically mapped sockets Calls to adjust_io_region only happen if !SS_CAP_STATIC_MAP. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/rsrc_mgr.c | 14 ++++++++++++-- include/pcmcia/ss.h | 6 +++++- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 1bc69b669477..a97c971ad805 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -577,8 +577,8 @@ pcmcia_align(void *align_data, struct resource *res, * Adjust an existing IO region allocation, but making sure that we don't * encroach outside the resources which the user supplied. */ -int adjust_io_region(struct resource *res, unsigned long r_start, - unsigned long r_end, struct pcmcia_socket *s) +static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_start, + unsigned long r_end, struct pcmcia_socket *s) { resource_map_t *m; int ret = -ENOMEM; @@ -599,6 +599,14 @@ int adjust_io_region(struct resource *res, unsigned long r_start, return ret; } +int adjust_io_region(struct resource *res, unsigned long r_start, + unsigned long r_end, struct pcmcia_socket *s) +{ + if (s->resource_ops->adjust_io_region) + return s->resource_ops->adjust_io_region(res, r_start, r_end, s); + return -ENOMEM; +} + /*====================================================================== These find ranges of I/O ports or memory addresses that are not @@ -991,8 +999,10 @@ void release_resource_db(struct pcmcia_socket *s) struct pccard_resource_ops pccard_static_ops = { .validate_mem = NULL, + .adjust_io_region = NULL, }; struct pccard_resource_ops pccard_nonstatic_ops = { .validate_mem = pcmcia_nonstatic_validate_mem, + .adjust_io_region = nonstatic_adjust_io_region, }; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index d872a714fa28..63eba592e00c 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -116,7 +116,11 @@ struct pccard_operations { }; struct pccard_resource_ops { - void (*validate_mem) (struct pcmcia_socket *s); + void (*validate_mem) (struct pcmcia_socket *s); + int (*adjust_io_region) (struct resource *res, + unsigned long r_start, + unsigned long r_end, + struct pcmcia_socket *s); }; /* -- cgit v1.2.3 From 1b71fababfefb7b4477826789eaaad961e423b06 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:28:24 -0800 Subject: [PATCH] pcmcia: find_io_region only for non-statically mapped sockets Calls to find_io_region only happen if !SS_CAP_STATIC_MAP. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/rsrc_mgr.c | 43 +++++++++++++++++++++++++++---------------- include/pcmcia/ss.h | 3 +++ 2 files changed, 30 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index a97c971ad805..de488824dbe6 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -504,13 +504,6 @@ static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) } } -void pcmcia_validate_mem(struct pcmcia_socket *s) -{ - if (s->resource_ops->validate_mem) - s->resource_ops->validate_mem(s); -} -EXPORT_SYMBOL(pcmcia_validate_mem); - struct pcmcia_align_data { unsigned long mask; unsigned long offset; @@ -599,14 +592,6 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star return ret; } -int adjust_io_region(struct resource *res, unsigned long r_start, - unsigned long r_end, struct pcmcia_socket *s) -{ - if (s->resource_ops->adjust_io_region) - return s->resource_ops->adjust_io_region(res, r_start, r_end, s); - return -ENOMEM; -} - /*====================================================================== These find ranges of I/O ports or memory addresses that are not @@ -620,7 +605,7 @@ int adjust_io_region(struct resource *res, unsigned long r_start, ======================================================================*/ -struct resource *find_io_region(unsigned long base, int num, +struct resource *nonstatic_find_io_region(unsigned long base, int num, unsigned long align, struct pcmcia_socket *s) { struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id); @@ -997,12 +982,38 @@ void release_resource_db(struct pcmcia_socket *s) } +void pcmcia_validate_mem(struct pcmcia_socket *s) +{ + if (s->resource_ops->validate_mem) + s->resource_ops->validate_mem(s); +} +EXPORT_SYMBOL(pcmcia_validate_mem); + +int adjust_io_region(struct resource *res, unsigned long r_start, + unsigned long r_end, struct pcmcia_socket *s) +{ + if (s->resource_ops->adjust_io_region) + return s->resource_ops->adjust_io_region(res, r_start, r_end, s); + return -ENOMEM; +} + +struct resource *find_io_region(unsigned long base, int num, + unsigned long align, struct pcmcia_socket *s) +{ + if (s->resource_ops->find_io) + return s->resource_ops->find_io(base, num, align, s); + return NULL; +} + + struct pccard_resource_ops pccard_static_ops = { .validate_mem = NULL, .adjust_io_region = NULL, + .find_io = NULL, }; struct pccard_resource_ops pccard_nonstatic_ops = { .validate_mem = pcmcia_nonstatic_validate_mem, .adjust_io_region = nonstatic_adjust_io_region, + .find_io = nonstatic_find_io_region, }; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 63eba592e00c..02fd88e83e32 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -121,6 +121,9 @@ struct pccard_resource_ops { unsigned long r_start, unsigned long r_end, struct pcmcia_socket *s); + struct resource* (*find_io) (unsigned long base, int num, + unsigned long align, + struct pcmcia_socket *s); }; /* -- cgit v1.2.3 From 1b55e603e08a16ed866a91433fc1b44eb9a1e16d Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:28:37 -0800 Subject: [PATCH] pcmcia: find_mem_region only for non-statically mapped sockets Calls to adjust_mem_region only happen if !SS_CAP_STATIC_MAP. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/rsrc_mgr.c | 12 +++++++++++- include/pcmcia/ss.h | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index de488824dbe6..ea52d03e9f4b 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -638,7 +638,7 @@ struct resource *nonstatic_find_io_region(unsigned long base, int num, return res; } -struct resource *find_mem_region(u_long base, u_long num, u_long align, +struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align, int low, struct pcmcia_socket *s) { struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id); @@ -1005,15 +1005,25 @@ struct resource *find_io_region(unsigned long base, int num, return NULL; } +struct resource *find_mem_region(u_long base, u_long num, u_long align, + int low, struct pcmcia_socket *s) +{ + if (s->resource_ops->find_mem) + return s->resource_ops->find_mem(base, num, align, low, s); + return NULL; +} + struct pccard_resource_ops pccard_static_ops = { .validate_mem = NULL, .adjust_io_region = NULL, .find_io = NULL, + .find_mem = NULL, }; struct pccard_resource_ops pccard_nonstatic_ops = { .validate_mem = pcmcia_nonstatic_validate_mem, .adjust_io_region = nonstatic_adjust_io_region, .find_io = nonstatic_find_io_region, + .find_mem = nonstatic_find_mem_region, }; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 02fd88e83e32..bd22d0c69975 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -124,6 +124,9 @@ struct pccard_resource_ops { struct resource* (*find_io) (unsigned long base, int num, unsigned long align, struct pcmcia_socket *s); + struct resource* (*find_mem) (unsigned long base, unsigned long num, + unsigned long align, int low, + struct pcmcia_socket *s); }; /* -- cgit v1.2.3 From 83b52fe651c487d60a3e7e55770bbde73a16a10c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:28:50 -0800 Subject: [PATCH] pcmcia: adjust_ and release_resources only for non-statically mapped sockets re-direct calls to adjust_resource_info for MEM and IO. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/rsrc_mgr.c | 34 +++++++++++++++++++++++++--------- include/pcmcia/ss.h | 3 +++ 2 files changed, 28 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index ea52d03e9f4b..ff67766d0a07 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -940,6 +940,17 @@ static int adjust_irq(adjust_t *adj) /*====================================================================*/ +static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj) +{ + switch (adj->Resource) { + case RES_MEMORY_RANGE: + return adjust_memory(s, adj); + case RES_IO_RANGE: + return adjust_io(s, adj); + } + return CS_UNSUPPORTED_FUNCTION; +} + int pcmcia_adjust_resource_info(adjust_t *adj) { struct pcmcia_socket *s; @@ -950,14 +961,8 @@ int pcmcia_adjust_resource_info(adjust_t *adj) down_read(&pcmcia_socket_list_rwsem); list_for_each_entry(s, &pcmcia_socket_list, socket_list) { - switch (adj->Resource) { - case RES_MEMORY_RANGE: - ret = adjust_memory(s, adj); - break; - case RES_IO_RANGE: - ret = adjust_io(s, adj); - break; - } + if (s->resource_ops->adjust_resource) + ret = s->resource_ops->adjust_resource(s, adj); } up_read(&pcmcia_socket_list_rwsem); @@ -967,7 +972,7 @@ EXPORT_SYMBOL(pcmcia_adjust_resource_info); /*====================================================================*/ -void release_resource_db(struct pcmcia_socket *s) +static void nonstatic_release_resource_db(struct pcmcia_socket *s) { resource_map_t *p, *q; @@ -982,6 +987,7 @@ void release_resource_db(struct pcmcia_socket *s) } + void pcmcia_validate_mem(struct pcmcia_socket *s) { if (s->resource_ops->validate_mem) @@ -1013,12 +1019,20 @@ struct resource *find_mem_region(u_long base, u_long num, u_long align, return NULL; } +void release_resource_db(struct pcmcia_socket *s) +{ + if (s->resource_ops->exit) + s->resource_ops->exit(s); +} + struct pccard_resource_ops pccard_static_ops = { .validate_mem = NULL, .adjust_io_region = NULL, .find_io = NULL, .find_mem = NULL, + .adjust_resource = NULL, + .exit = NULL, }; struct pccard_resource_ops pccard_nonstatic_ops = { @@ -1026,4 +1040,6 @@ struct pccard_resource_ops pccard_nonstatic_ops = { .adjust_io_region = nonstatic_adjust_io_region, .find_io = nonstatic_find_io_region, .find_mem = nonstatic_find_mem_region, + .adjust_resource = nonstatic_adjust_resource_info, + .exit = nonstatic_release_resource_db, }; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index bd22d0c69975..3b4b3cfea12d 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -127,6 +127,9 @@ struct pccard_resource_ops { struct resource* (*find_mem) (unsigned long base, unsigned long num, unsigned long align, int low, struct pcmcia_socket *s); + int (*adjust_resource) (struct pcmcia_socket *s, + adjust_t *adj); + void (*exit) (struct pcmcia_socket *s); }; /* -- cgit v1.2.3 From 6238b318f00f14924f07e1d5aa18d067d80f9fbd Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:29:18 -0800 Subject: [PATCH] pcmcia: make rsrc_nonstatic an independend module Make rsrc_nonstatic an independent module. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/Kconfig | 9 +++++++++ drivers/pcmcia/Makefile | 4 +++- drivers/pcmcia/cistpl.c | 2 ++ drivers/pcmcia/cs.c | 8 ++------ drivers/pcmcia/cs_internal.h | 2 -- drivers/pcmcia/hd64465_ss.c | 1 + drivers/pcmcia/i82092.c | 1 + drivers/pcmcia/i82365.c | 1 + drivers/pcmcia/m32r_cfc.c | 1 + drivers/pcmcia/m32r_pcc.c | 1 + drivers/pcmcia/pd6729.c | 1 + drivers/pcmcia/rsrc_mgr.c | 1 + drivers/pcmcia/rsrc_nonstatic.c | 4 ++++ drivers/pcmcia/soc_common.c | 1 + drivers/pcmcia/tcic.c | 3 ++- drivers/pcmcia/yenta_socket.c | 1 + include/pcmcia/ss.h | 4 ++++ 17 files changed, 35 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 22f3c9a0841e..ca14e721502d 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -80,6 +80,7 @@ config YENTA depends on PCCARD && PCI #fixme: remove dependendcy on CARDBUS depends on CARDBUS + select PCCARD_NONSTATIC ---help--- This option enables support for CardBus host bridges. Virtually all modern PCMCIA bridges are CardBus compatible. A "bridge" is @@ -94,6 +95,7 @@ config YENTA config PD6729 tristate "Cirrus PD6729 compatible bridge support" depends on PCMCIA && PCI + select PCCARD_NONSTATIC help This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge device, found in some older laptops and PCMCIA card readers. @@ -101,6 +103,7 @@ config PD6729 config I82092 tristate "i82092 compatible bridge support" depends on PCMCIA && PCI + select PCCARD_NONSTATIC help This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device, found in some older laptops and more commonly in evaluation boards for the @@ -109,6 +112,7 @@ config I82092 config I82365 tristate "i82365 compatible bridge support" depends on PCMCIA && ISA + select PCCARD_NONSTATIC help Say Y here to include support for ISA-bus PCMCIA host bridges that are register compatible with the Intel i82365. These are found on @@ -119,6 +123,7 @@ config I82365 config TCIC tristate "Databook TCIC host bridge support" depends on PCMCIA + select PCCARD_NONSTATIC help Say Y here to include support for the Databook TCIC family of PCMCIA host bridges. These are only found on a handful of old systems. @@ -178,4 +183,8 @@ config M32R_CFC_NUM help Set the number of M32R CF slots. +config PCCARD_NONSTATIC + tristate + depends on PCCARD + endmenu diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 1d26c873b6f6..3d5eb4984a7f 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -6,13 +6,15 @@ ifeq ($(CONFIG_PCMCIA_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif -pcmcia_core-y += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o rsrc_nonstatic.o +pcmcia_core-y += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o obj-$(CONFIG_PCCARD) += pcmcia_core.o pcmcia-y += ds.o pcmcia_compat.o obj-$(CONFIG_PCMCIA) += pcmcia.o +obj-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o + # socket drivers diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 99b90c2334f7..e29a6ddf2fd7 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -78,6 +78,7 @@ void release_cis_mem(struct pcmcia_socket *s) s->cis_virt = NULL; } } +EXPORT_SYMBOL(release_cis_mem); /* * Map the card memory at "card_offset" into virtual space. @@ -320,6 +321,7 @@ void destroy_cis_cache(struct pcmcia_socket *s) s->fake_cis = NULL; } } +EXPORT_SYMBOL(destroy_cis_cache); /*====================================================================== diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 590b2a561890..ecf3afff5dce 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -212,7 +212,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) { int ret; - if (!socket || !socket->ops || !socket->dev.dev) + if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops) return -EINVAL; cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops); @@ -250,11 +250,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) socket->cis_mem.flags = 0; socket->cis_mem.speed = cis_speed; - /* init resource handling */ - if (socket->features & SS_CAP_STATIC_MAP) - socket->resource_ops = &pccard_static_ops; - else - socket->resource_ops = &pccard_nonstatic_ops; + socket->mem_db.next = &socket->mem_db; socket->io_db.next = &socket->io_db; diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 764e71bcecab..f64ca5663f3c 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -144,8 +144,6 @@ int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); void release_resource_db(struct pcmcia_socket *s); -extern struct pccard_resource_ops pccard_static_ops; -extern struct pccard_resource_ops pccard_nonstatic_ops; /* In socket_sysfs.c */ extern struct class_interface pccard_sysfs_interface; diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index 875c9cfaea3f..36d85f04e276 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -922,6 +922,7 @@ static int __init init_hs(void) hs_set_voltages(&hs_sockets[i], 0, 0); hs_sockets[i].socket.features |= SS_CAP_PCCARD | SS_CAP_STATIC_MAP; /* mappings are fixed in host memory */ + hs_sockets[i].socket.resource_ops = &pccard_static_ops; hs_sockets[i].socket.irq_mask = 0xffde;/*0xffff*/ /* IRQs mapped in s/w so can do any, really */ hs_sockets[i].socket.map_size = HD64465_PCC_WINDOW; /* 16MB fixed window size */ diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index eb255238aef8..aa8ed192d21a 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -162,6 +162,7 @@ static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_de for (i = 0; idev; sockets[i].socket.ops = &i82092aa_operations; + sockets[i].socket.resource_ops = &pccard_nonstatic_ops; ret = pcmcia_register_socket(&sockets[i].socket); if (ret) { goto err_out_free_sockets; diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 56ced25d993c..0d9bb1505c2e 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1400,6 +1400,7 @@ static int __init init_i82365(void) for (i = 0; i < sockets; i++) { socket[i].socket.dev.dev = &i82365_device.dev; socket[i].socket.ops = &pcic_operations; + socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.owner = THIS_MODULE; socket[i].number = i; ret = pcmcia_register_socket(&socket[i].socket); diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 836058dfa2c0..023013d3e263 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -831,6 +831,7 @@ static int __init init_m32r_pcc(void) for (i = 0 ; i < pcc_sockets ; i++) { socket[i].socket.dev.dev = &pcc_device.dev; socket[i].socket.ops = &pcc_operations; + socket[i].socket.resource_ops = &pccard_static_ops; socket[i].socket.owner = THIS_MODULE; socket[i].number = i; ret = pcmcia_register_socket(&socket[i].socket); diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index aae7a16a1815..8c881ae73287 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -768,6 +768,7 @@ static int __init init_m32r_pcc(void) for (i = 0 ; i < pcc_sockets ; i++) { socket[i].socket.dev.dev = &pcc_device.dev; socket[i].socket.ops = &pcc_operations; + socket[i].socket.resource_ops = &pccard_static_ops; socket[i].socket.owner = THIS_MODULE; socket[i].number = i; ret = pcmcia_register_socket(&socket[i].socket); diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index ded56ce22d17..1347f94260c7 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -759,6 +759,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, socket[i].number = i; socket[i].socket.ops = &pd6729_operations; + socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.dev.dev = &dev->dev; socket[i].socket.driver_data = &socket[i]; } diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 7483249d09fe..b3f1fe0b02ca 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -290,3 +290,4 @@ struct pccard_resource_ops pccard_static_ops = { .adjust_resource = NULL, .exit = NULL, }; +EXPORT_SYMBOL(pccard_static_ops); diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 088bbb1d2949..025dca06b8d4 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -34,6 +34,9 @@ #include #include "cs_internal.h" +MODULE_AUTHOR("David A. Hinds, Dominik Brodowski"); +MODULE_LICENSE("GPL"); + /* Parameters that can be set with 'insmod' */ #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) @@ -769,3 +772,4 @@ struct pccard_resource_ops pccard_nonstatic_ops = { .adjust_resource = nonstatic_adjust_resource_info, .exit = nonstatic_release_resource_db, }; +EXPORT_SYMBOL(pccard_nonstatic_ops); diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index a45fee3f4355..20dd66b245bc 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -758,6 +758,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops goto out_err_6; skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; + skt->socket.resource_ops = &pccard_static_ops; skt->socket.irq_mask = 0; skt->socket.map_size = PAGE_SIZE; skt->socket.pci_irq = skt->irq; diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index a651309eb84f..e20438a7408f 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -531,8 +531,9 @@ static int __init init_tcic(void) for (i = 0; i < sockets; i++) { socket_table[i].socket.ops = &tcic_operations; + socket_table[i].socket.resource_ops = &pccard_nonstatic_ops; socket_table[i].socket.dev.dev = &tcic_device.dev; - ret = pcmcia_register_socket(&socket_table[i].socket); + ret = pcmcia_register_socket(&socket_table[i].socket); if (ret && i) pcmcia_unregister_socket(&socket_table[0].socket); } diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 8b76f7d6a37e..91b7b133989a 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -917,6 +917,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i /* prepare pcmcia_socket */ socket->socket.ops = ¥ta_socket_operations; + socket->socket.resource_ops = &pccard_nonstatic_ops; socket->socket.dev.dev = &dev->dev; socket->socket.driver_data = socket; socket->socket.owner = THIS_MODULE; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 3b4b3cfea12d..281689320506 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -131,6 +131,10 @@ struct pccard_resource_ops { adjust_t *adj); void (*exit) (struct pcmcia_socket *s); }; +/* SS_CAP_STATIC_MAP */ +extern struct pccard_resource_ops pccard_static_ops; +/* !SS_CAP_STATIC_MAP */ +extern struct pccard_resource_ops pccard_nonstatic_ops; /* * Calls to set up low-level "Socket Services" drivers -- cgit v1.2.3 From 6ca65becb8ced63d016e438792f84b99e5499c51 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 11 Jan 2005 03:29:31 -0800 Subject: [PATCH] pcmcia: allocate resource database per-socket Move the resource databases and the "mem_probe" flag into a struct specific to rsrc_nonstatic, as it is not needed for the SS_CAP_STATIC_MAP case. Saves a few bytes, and makes code clearer (in my opinion) Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/cs.c | 10 +++-- drivers/pcmcia/rsrc_nonstatic.c | 81 +++++++++++++++++++++++++++++++---------- include/pcmcia/ss.h | 11 +----- 3 files changed, 69 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index ecf3afff5dce..edfc17a30687 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -217,6 +217,12 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops); + if (socket->resource_ops->init) { + ret = socket->resource_ops->init(socket); + if (ret) + return (ret); + } + /* try to obtain a socket number [yes, it gets ugly if we * register more than 2^sizeof(unsigned int) pcmcia * sockets... but the socket number is deprecated @@ -250,10 +256,6 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) socket->cis_mem.flags = 0; socket->cis_mem.speed = cis_speed; - - socket->mem_db.next = &socket->mem_db; - socket->io_db.next = &socket->io_db; - INIT_LIST_HEAD(&socket->cis_cache); spin_lock_init(&socket->lock); diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 025dca06b8d4..72eeac72609f 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -47,8 +47,20 @@ INT_MODULE_PARM(probe_io, 1); /* IO port probe? */ INT_MODULE_PARM(mem_limit, 0x10000); #endif +/* for io_db and mem_db */ +struct resource_map_t { + u_long base, num; + struct resource_map_t *next; +}; + typedef struct resource_map_t resource_map_t; +struct socket_data { + struct resource_map_t mem_db; + struct resource_map_t io_db; + unsigned int rsrc_mem_probe; +}; + static DECLARE_MUTEX(rsrc_sem); #define MEM_PROBE_LOW (1 << 0) #define MEM_PROBE_HIGH (1 << 1) @@ -179,6 +191,7 @@ static int sub_interval(resource_map_t *map, u_long base, u_long num) static void do_io_probe(struct pcmcia_socket *s, ioaddr_t base, ioaddr_t num) { struct resource *res; + struct socket_data *s_data = s->resource_data; ioaddr_t i, j, bad, any; u_char *b, hole, most; @@ -221,7 +234,7 @@ static void do_io_probe(struct pcmcia_socket *s, ioaddr_t base, ioaddr_t num) bad = any = i; } else { if (bad) { - sub_interval(&s->io_db, bad, i-bad); + sub_interval(&s_data->io_db, bad, i-bad); printk(" %#04x-%#04x", bad, i-1); bad = 0; } @@ -232,7 +245,7 @@ static void do_io_probe(struct pcmcia_socket *s, ioaddr_t base, ioaddr_t num) printk(" nothing: probe failed.\n"); return; } else { - sub_interval(&s->io_db, bad, i-bad); + sub_interval(&s_data->io_db, bad, i-bad); printk(" %#04x-%#04x", bad, i-1); } } @@ -351,6 +364,7 @@ checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size) static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) { + struct socket_data *s_data = s->resource_data; u_long i, j, bad, fail, step; printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:", @@ -377,7 +391,7 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) if (i != j) { if (!bad) printk(" excluding"); printk(" %#05lx-%#05lx", i, j-1); - sub_interval(&s->mem_db, i, j-i); + sub_interval(&s_data->mem_db, i, j-i); bad += j-i; } } @@ -389,13 +403,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) static u_long inv_probe(resource_map_t *m, struct pcmcia_socket *s) { + struct socket_data *s_data = s->resource_data; u_long ok; - if (m == &s->mem_db) + if (m == &s_data->mem_db) return 0; ok = inv_probe(m->next, s); if (ok) { if (m->base >= 0x100000) - sub_interval(&s->mem_db, m->base, m->num); + sub_interval(&s_data->mem_db, m->base, m->num); return ok; } if (m->base < 0x100000) @@ -408,17 +423,18 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) resource_map_t *m, mm; static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; u_long b, i, ok = 0; + struct socket_data *s_data = s->resource_data; /* We do up to four passes through the list */ if (probe_mask & MEM_PROBE_HIGH) { - if (inv_probe(s->mem_db.next, s) > 0) + if (inv_probe(s_data->mem_db.next, s) > 0) return; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); } if ((probe_mask & MEM_PROBE_LOW) == 0) return; - for (m = s->mem_db.next; m != &s->mem_db; m = mm.next) { + for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { mm = *m; /* Only probe < 1 MB */ if (mm.base >= 0x100000) continue; @@ -431,7 +447,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) b = order[i] << 12; if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) { if (ok >= mem_limit) - sub_interval(&s->mem_db, b, 0x10000); + sub_interval(&s_data->mem_db, b, 0x10000); else ok += do_mem_probe(b, 0x10000, s); } @@ -444,8 +460,9 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { resource_map_t *m, mm; + struct socket_data *s_data = s->resource_data; - for (m = s->mem_db.next; m != &s->mem_db; m = mm.next) { + for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { mm = *m; if (do_mem_probe(mm.base, mm.num, s)) break; @@ -461,6 +478,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) */ static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) { + struct socket_data *s_data = s->resource_data; if (probe_mem) { unsigned int probe_mask; @@ -470,8 +488,8 @@ static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) if (s->features & SS_CAP_PAGE_REGS) probe_mask = MEM_PROBE_HIGH; - if (probe_mask & ~s->rsrc_mem_probe) { - s->rsrc_mem_probe |= probe_mask; + if (probe_mask & ~s_data->rsrc_mem_probe) { + s_data->rsrc_mem_probe |= probe_mask; down(&s->skt_sem); @@ -555,10 +573,11 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star unsigned long r_end, struct pcmcia_socket *s) { resource_map_t *m; + struct socket_data *s_data = s->resource_data; int ret = -ENOMEM; down(&rsrc_sem); - for (m = s->io_db.next; m != &s->io_db; m = m->next) { + for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) { unsigned long start = m->base; unsigned long end = m->base + m->num - 1; @@ -590,6 +609,7 @@ struct resource *nonstatic_find_io_region(unsigned long base, int num, unsigned long align, struct pcmcia_socket *s) { struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id); + struct socket_data *s_data = s->resource_data; struct pcmcia_align_data data; unsigned long min = base; int ret; @@ -599,7 +619,7 @@ struct resource *nonstatic_find_io_region(unsigned long base, int num, data.mask = align - 1; data.offset = base & data.mask; - data.map = &s->io_db; + data.map = &s_data->io_db; down(&rsrc_sem); #ifdef CONFIG_PCI @@ -623,6 +643,7 @@ struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long alig int low, struct pcmcia_socket *s) { struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id); + struct socket_data *s_data = s->resource_data; struct pcmcia_align_data data; unsigned long min, max; int ret, i; @@ -631,7 +652,7 @@ struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long alig data.mask = align - 1; data.offset = base & data.mask; - data.map = &s->mem_db; + data.map = &s_data->mem_db; for (i = 0; i < 2; i++) { if (low) { @@ -669,6 +690,7 @@ struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long alig static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) { u_long base, num; + struct socket_data *data = s->resource_data; int ret; base = adj->resource.memory.Base; @@ -681,10 +703,10 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) down(&rsrc_sem); switch (adj->Action) { case ADD_MANAGED_RESOURCE: - ret = add_interval(&s->mem_db, base, num); + ret = add_interval(&data->mem_db, base, num); break; case REMOVE_MANAGED_RESOURCE: - ret = sub_interval(&s->mem_db, base, num); + ret = sub_interval(&data->mem_db, base, num); if (ret == CS_SUCCESS) { struct pcmcia_socket *socket; down_read(&pcmcia_socket_list_rwsem); @@ -704,6 +726,7 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) static int adjust_io(struct pcmcia_socket *s, adjust_t *adj) { + struct socket_data *data = s->resource_data; int base, num, ret = CS_SUCCESS; base = adj->resource.io.BasePort; @@ -716,7 +739,7 @@ static int adjust_io(struct pcmcia_socket *s, adjust_t *adj) down(&rsrc_sem); switch (adj->Action) { case ADD_MANAGED_RESOURCE: - if (add_interval(&s->io_db, base, num) != 0) { + if (add_interval(&data->io_db, base, num) != 0) { ret = CS_IN_USE; break; } @@ -726,7 +749,7 @@ static int adjust_io(struct pcmcia_socket *s, adjust_t *adj) #endif break; case REMOVE_MANAGED_RESOURCE: - sub_interval(&s->io_db, base, num); + sub_interval(&data->io_db, base, num); break; default: ret = CS_UNSUPPORTED_FUNCTION; @@ -749,15 +772,32 @@ static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj return CS_UNSUPPORTED_FUNCTION; } +static int nonstatic_init(struct pcmcia_socket *s) +{ + struct socket_data *data; + + data = kmalloc(sizeof(struct socket_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->mem_db.next = &data->mem_db; + data->io_db.next = &data->io_db; + + s->resource_data = (void *) data; + + return 0; +} + static void nonstatic_release_resource_db(struct pcmcia_socket *s) { + struct socket_data *data = s->resource_data; resource_map_t *p, *q; - for (p = s->mem_db.next; p != &s->mem_db; p = q) { + for (p = data->mem_db.next; p != &data->mem_db; p = q) { q = p->next; kfree(p); } - for (p = s->io_db.next; p != &s->io_db; p = q) { + for (p = data->io_db.next; p != &data->io_db; p = q) { q = p->next; kfree(p); } @@ -770,6 +810,7 @@ struct pccard_resource_ops pccard_nonstatic_ops = { .find_io = nonstatic_find_io_region, .find_mem = nonstatic_find_mem_region, .adjust_resource = nonstatic_adjust_resource_info, + .init = nonstatic_init, .exit = nonstatic_release_resource_db, }; EXPORT_SYMBOL(pccard_nonstatic_ops); diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 281689320506..70cbca2638c5 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -129,6 +129,7 @@ struct pccard_resource_ops { struct pcmcia_socket *s); int (*adjust_resource) (struct pcmcia_socket *s, adjust_t *adj); + int (*init) (struct pcmcia_socket *s); void (*exit) (struct pcmcia_socket *s); }; /* SS_CAP_STATIC_MAP */ @@ -167,11 +168,6 @@ struct config_t; struct region_t; struct pcmcia_callback; -/* for io_db and mem_db */ -struct resource_map_t { - u_long base, num; - struct resource_map_t *next; -}; struct pcmcia_socket { struct module *owner; @@ -197,10 +193,6 @@ struct pcmcia_socket { struct list_head socket_list; struct completion socket_released; - struct resource_map_t mem_db; - struct resource_map_t io_db; - unsigned int rsrc_mem_probe; - /* deprecated */ unsigned int sock; /* socket number */ @@ -216,6 +208,7 @@ struct pcmcia_socket { /* socket operations */ struct pccard_operations * ops; struct pccard_resource_ops * resource_ops; + void * resource_data; /* Zoom video behaviour is so chip specific its not worth adding this to _ops */ -- cgit v1.2.3 From 66d272434a1b009b94bab07bae98dec39e0a9706 Mon Sep 17 00:00:00 2001 From: Hisashi Hifumi Date: Tue, 11 Jan 2005 03:30:37 -0800 Subject: [PATCH] BUG on error handlings in Ext3 under I/O failure condition I found bugs on error handlings in the functions arround the ext3 file system, which cause inadequate completions of synchronous write I/O operations when disk I/O failures occur. Both 2.4 and 2.6 have this problem. I carried out following experiment: 1. Mount a ext3 file system on a SCSI disk with ordered mode. 2. Open a file on the file system with O_SYNC|O_RDWR|O_TRUNC|O_CREAT flag. 3. Write 512 bytes data to the file by calling write() every 5 seconds, and examine return values from the syscall. from write(). 4. Disconnect the SCSI cable, and examine messages from the kernel. After the SCSI cable is disconnected, write() must fail. But the result was different: write() succeeded for a while even though messages of the kernel notified SCSI I/O error. By applying following modifications, the above problem was solved. Signed-off-by: Hisashi Hifumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/buffer.c | 8 +++++--- fs/fs-writeback.c | 15 ++++++++++----- fs/jbd/commit.c | 3 +++ include/linux/fs.h | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/fs/buffer.c b/fs/buffer.c index 7a31850892cb..341ba4c58a18 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -311,10 +311,10 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) { struct inode * inode = dentry->d_inode; struct super_block * sb; - int ret; + int ret, err; /* sync the inode to buffers */ - write_inode_now(inode, 0); + ret = write_inode_now(inode, 0); /* sync the superblock to buffers */ sb = inode->i_sb; @@ -324,7 +324,9 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) unlock_super(sb); /* .. finally sync the buffers to disk */ - ret = sync_blockdev(sb->s_bdev); + err = sync_blockdev(sb->s_bdev); + if (!ret) + ret = err; return ret; } diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 26f234a0da93..6d0e70efd399 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -558,22 +558,24 @@ void sync_inodes(int wait) * dirty. This is primarily needed by knfsd. */ -void write_inode_now(struct inode *inode, int sync) +int write_inode_now(struct inode *inode, int sync) { + int ret; struct writeback_control wbc = { .nr_to_write = LONG_MAX, .sync_mode = WB_SYNC_ALL, }; if (inode->i_mapping->backing_dev_info->memory_backed) - return; + return 0; might_sleep(); spin_lock(&inode_lock); - __writeback_single_inode(inode, &wbc); + ret = __writeback_single_inode(inode, &wbc); spin_unlock(&inode_lock); if (sync) wait_on_inode(inode); + return ret; } EXPORT_SYMBOL(write_inode_now); @@ -642,8 +644,11 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int need_write_inode_now = 1; spin_unlock(&inode_lock); - if (need_write_inode_now) - write_inode_now(inode, 1); + if (need_write_inode_now) { + err2 = write_inode_now(inode, 1); + if (!err) + err = err2; + } else wait_on_inode(inode); diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index c5c9983e3a60..aa5f22435d0c 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -337,6 +337,9 @@ write_out_data: } spin_unlock(&journal->j_list_lock); + if (err) + __journal_abort_hard(journal); + journal_write_revoke_records(journal, commit_transaction); jbd_debug(3, "JBD: commit phase 2\n"); diff --git a/include/linux/fs.h b/include/linux/fs.h index aa7abb112dbc..4d26f55c1299 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1344,7 +1344,7 @@ static inline void invalidate_remote_inode(struct inode *inode) invalidate_inode_pages(inode->i_mapping); } extern int invalidate_inode_pages2(struct address_space *mapping); -extern void write_inode_now(struct inode *, int); +extern int write_inode_now(struct inode *, int); extern int filemap_fdatawrite(struct address_space *); extern int filemap_flush(struct address_space *); extern int filemap_fdatawait(struct address_space *); -- cgit v1.2.3 From 8f13ed2fa0cc179e1462f8d7c81dd4a62b7e0c88 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 15:35:48 -0800 Subject: [PATCH] x86_64: Fix ACPI SRAT NUMA parsing Fix fallout from the recent nodemask_t changes. The node ids assigned in the SRAT parser were off by one. I added a new first_unset_node() function to nodemask.h to allocate IDs sanely. Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/x86_64/mm/srat.c | 17 ++++++++++------- include/linux/nodemask.h | 9 +++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 1db7483a0564..aaf329373367 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -20,17 +20,20 @@ static struct acpi_table_slit *acpi_slit; -static DECLARE_BITMAP(nodes_parsed, MAX_NUMNODES) __initdata; +static nodemask_t nodes_parsed __initdata; +static nodemask_t nodes_found __initdata; static struct node nodes[MAX_NUMNODES] __initdata; static __u8 pxm2node[256] __initdata = { [0 ... 255] = 0xff }; static __init int setup_node(int pxm) { - if (pxm2node[pxm] == 0xff) { - if (num_online_nodes() >= MAX_NUMNODES) + unsigned node = pxm2node[pxm]; + if (node == 0xff) { + if (nodes_weight(nodes_found) >= MAX_NUMNODES) return -1; - pxm2node[pxm] = num_online_nodes(); - node_set_online(num_online_nodes()); + node = first_unset_node(nodes_found); + node_set(node, nodes_found); + pxm2node[pxm] = node; } return pxm2node[pxm]; } @@ -140,7 +143,7 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) return; } nd = &nodes[node]; - if (!test_and_set_bit(node, &nodes_parsed)) { + if (!node_test_and_set(node, nodes_parsed)) { nd->start = start; nd->end = end; } else { @@ -171,7 +174,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) return -1; } for (i = 0; i < MAX_NUMNODES; i++) { - if (!test_bit(i, &nodes_parsed)) + if (!node_isset(i, nodes_parsed)) continue; cutoff_node(i, start, end); if (nodes[i].start == nodes[i].end) diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 4de843d94147..16475a23efa7 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -38,6 +38,8 @@ * * int first_node(mask) Number lowest set bit, or MAX_NUMNODES * int next_node(node, mask) Next node past 'node', or MAX_NUMNODES + * int first_unset_node(mask) First node not set in mask, or + * MAX_NUMNODES. * * nodemask_t nodemask_of_node(node) Return nodemask with bit 'node' set * NODE_MASK_ALL Initializer - all bits set @@ -235,6 +237,13 @@ static inline int __next_node(int n, const nodemask_t *srcp, int nbits) m; \ }) +#define first_unset_node(mask) __first_unset_node(&(mask)) +static inline int __first_unset_node(const nodemask_t *maskp) +{ + return min_t(int,MAX_NUMNODES, + find_first_zero_bit(maskp->bits, MAX_NUMNODES)); +} + #define NODE_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(MAX_NUMNODES) #if MAX_NUMNODES <= BITS_PER_LONG -- cgit v1.2.3 From c0e289599d4ad6b448b7a3fb52a086dc294da88f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 15:36:17 -0800 Subject: [PATCH] [3/4] x86_64: Fix NUMA hash setup Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/x86_64/mm/k8topology.c | 2 +- arch/x86_64/mm/numa.c | 8 +++----- arch/x86_64/mm/srat.c | 2 +- include/asm-x86_64/numa.h | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c index 0622ad3016f2..55a2e67e32a6 100644 --- a/arch/x86_64/mm/k8topology.c +++ b/arch/x86_64/mm/k8topology.c @@ -148,7 +148,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) if (!found) return -1; - memnode_shift = compute_hash_shift(nodes); + memnode_shift = compute_hash_shift(nodes, numnodes); if (memnode_shift < 0) { printk(KERN_ERR "No NUMA node hash function found. Contact maintainer\n"); return -1; diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index b1a7db4f4d6d..72b16f3d5e87 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -34,9 +34,7 @@ cpumask_t node_to_cpumask[MAX_NUMNODES]; int numa_off __initdata; -unsigned long nodes_present; - -int __init compute_hash_shift(struct node *nodes) +int __init compute_hash_shift(struct node *nodes, int numnodes) { int i; int shift = 24; @@ -45,7 +43,7 @@ int __init compute_hash_shift(struct node *nodes) /* When in doubt use brute force. */ while (shift < 48) { memset(memnodemap,0xff,sizeof(*memnodemap) * NODEMAPSIZE); - for_each_online_node(i) { + for (i = 0; i < numnodes; i++) { if (nodes[i].start == nodes[i].end) continue; for (addr = nodes[i].start; @@ -197,7 +195,7 @@ static int numa_emulation(unsigned long start_pfn, unsigned long end_pfn) (nodes[i].end - nodes[i].start) >> 20); node_set_online(i); } - memnode_shift = compute_hash_shift(nodes); + memnode_shift = compute_hash_shift(nodes, numa_fake); if (memnode_shift < 0) { memnode_shift = 0; printk(KERN_ERR "No NUMA hash function found. Emulation disabled.\n"); diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index aaf329373367..3bd04832f041 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -166,7 +166,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) int i; if (acpi_numa <= 0) return -1; - memnode_shift = compute_hash_shift(nodes); + memnode_shift = compute_hash_shift(nodes, nodes_weight(nodes_parsed)); if (memnode_shift < 0) { printk(KERN_ERR "SRAT: No NUMA node hash function found. Contact maintainer\n"); diff --git a/include/asm-x86_64/numa.h b/include/asm-x86_64/numa.h index 21843b35ef18..3574f604542b 100644 --- a/include/asm-x86_64/numa.h +++ b/include/asm-x86_64/numa.h @@ -8,7 +8,7 @@ struct node { u64 start,end; }; -extern int compute_hash_shift(struct node *nodes); +extern int compute_hash_shift(struct node *nodes, int numnodes); #define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) -- cgit v1.2.3 From d2bca7baf9666c0ba382f39b8b1ca9a04b88798a Mon Sep 17 00:00:00 2001 From: Ivan Kokshaysky Date: Tue, 11 Jan 2005 16:48:35 -0800 Subject: [PATCH] Alpha: typos in io_trivial.h This apparently explains some weird IO failures reported in last two months. Only non-bwx (including generic) kernels were affected. Acked-by: Richard Henderson Signed-off-by: Linus Torvalds --- include/asm-alpha/io_trivial.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-alpha/io_trivial.h b/include/asm-alpha/io_trivial.h index cfe1f86c33db..b10d1aa4cdd1 100644 --- a/include/asm-alpha/io_trivial.h +++ b/include/asm-alpha/io_trivial.h @@ -26,7 +26,7 @@ IO_CONCAT(__IO_PREFIX,iowrite8)(u8 b, void __iomem *a) __EXTERN_INLINE void IO_CONCAT(__IO_PREFIX,iowrite16)(u16 b, void __iomem *a) { - __kernel_stb(b, *(volatile u16 __force *)a); + __kernel_stw(b, *(volatile u16 __force *)a); } #endif @@ -66,7 +66,7 @@ IO_CONCAT(__IO_PREFIX,writeb)(u8 b, volatile void __iomem *a) __EXTERN_INLINE void IO_CONCAT(__IO_PREFIX,writew)(u16 b, volatile void __iomem *a) { - __kernel_stb(b, *(volatile u16 __force *)a); + __kernel_stw(b, *(volatile u16 __force *)a); } #elif IO_CONCAT(__IO_PREFIX,trivial_rw_bw) == 2 __EXTERN_INLINE u8 -- cgit v1.2.3 From 8de4d36f31299effc7c2c4ba05262de4e3d69b4d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Jan 2005 16:50:53 -0800 Subject: [PATCH] PPC64 had _raw_read_trylock already Ingo presumably didn't notice that ppc64 already had a functional _raw_read_trylock when he added the #define to use the generic version. This just removes the #define so we use the ppc64-specific version again. Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds --- include/asm-ppc64/spinlock.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/asm-ppc64/spinlock.h b/include/asm-ppc64/spinlock.h index 58e5dc61d9d8..e194599dbe50 100644 --- a/include/asm-ppc64/spinlock.h +++ b/include/asm-ppc64/spinlock.h @@ -222,8 +222,6 @@ static void __inline__ _raw_read_unlock(rwlock_t *rw) : "cr0", "memory"); } -#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) - /* * This returns the old value in the lock, * so we got the write lock if the return value is 0. -- cgit v1.2.3 From 8d3f522381071d2847aea15f0ef5ac66c9a3c93a Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 11 Jan 2005 17:02:21 -0800 Subject: [PATCH] ppc: fix removed MMCR0_PMXE define In ChangeSet 1.2370, 2005/01/11 17:41:32-08:00, tglx@linutronix.de wrote: > > [PATCH] ppc: remove duplicate define > > The MMCR0_PMXE is already defined in reg.h... Er, no it's not. But perhaps it should be... --- include/asm-ppc/reg.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h index 73eab4528eb9..48c0706466ca 100644 --- a/include/asm-ppc/reg.h +++ b/include/asm-ppc/reg.h @@ -329,6 +329,7 @@ #define MMCR0_PMC2_CYCLES 0x1 #define MMCR0_PMC2_ITLB 0x7 #define MMCR0_PMC2_LOADMISSTIME 0x5 +#define MMCR0_PMXE (1 << 26) /* Short-hand versions for a number of the above SPRNs */ #define CTR SPRN_CTR /* Counter Register */ -- cgit v1.2.3 From 65c333c9425f7914ec3cf8fa5e18b1f08abb812a Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 11 Jan 2005 22:06:41 -0600 Subject: SCSI: add starget_for_each_device From: James.Smart@Emulex.Com This patch deprecates the use of device_for_each_child() with stargets. The reasoning behind this is due to issues regarding: Semaphores that device_for_each_child() takes Implicit assumptions that each child is an sdev device. The patch adds a new helper function, starget_for_each_device(), and replaces all previous uses of device_for_each_child(). Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 22 ++++++++++++++++++++++ drivers/scsi/scsi_lib.c | 18 ++++++++---------- drivers/scsi/scsi_transport_fc.c | 16 +++++++--------- include/scsi/scsi_device.h | 2 ++ 4 files changed, 39 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 82c7b0ab4047..63e5224eee0a 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1082,6 +1082,28 @@ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, } EXPORT_SYMBOL(__scsi_iterate_devices); +/** + * starget_for_each_device - helper to walk all devices of a target + * @starget: target whose devices we want to iterate over. + * + * This traverses over each devices of @shost. The devices have + * a reference that must be released by scsi_host_put when breaking + * out of the loop. + */ +void starget_for_each_device(struct scsi_target *starget, void * data, + void (*fn)(struct scsi_device *, void *)) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct scsi_device *sdev; + + shost_for_each_device(sdev, shost) { + if ((sdev->channel == starget->channel) && + (sdev->id == starget->id)) + fn(sdev, data); + } +} +EXPORT_SYMBOL(starget_for_each_device); + /** * scsi_device_lookup - find a device given the host (UNLOCKED) * @shost: SCSI host pointer diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 73660628b520..38f165070c94 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1782,31 +1782,29 @@ scsi_device_resume(struct scsi_device *sdev) } EXPORT_SYMBOL(scsi_device_resume); -static int -device_quiesce_fn(struct device *dev, void *data) +static void +device_quiesce_fn(struct scsi_device *sdev, void *data) { - scsi_device_quiesce(to_scsi_device(dev)); - return 0; + scsi_device_quiesce(sdev); } void scsi_target_quiesce(struct scsi_target *starget) { - device_for_each_child(&starget->dev, NULL, device_quiesce_fn); + starget_for_each_device(starget, NULL, device_quiesce_fn); } EXPORT_SYMBOL(scsi_target_quiesce); -static int -device_resume_fn(struct device *dev, void *data) +static void +device_resume_fn(struct scsi_device *sdev, void *data) { - scsi_device_resume(to_scsi_device(dev)); - return 0; + scsi_device_resume(sdev); } void scsi_target_resume(struct scsi_target *starget) { - device_for_each_child(&starget->dev, NULL, device_resume_fn); + starget_for_each_device(starget, NULL, device_resume_fn); } EXPORT_SYMBOL(scsi_target_resume); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 926cec15e5f2..2fddf2c24b67 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -808,10 +808,9 @@ EXPORT_SYMBOL(fc_release_transport); * @dev: scsi device * @data: unused **/ -static int fc_device_block(struct device *dev, void *data) +static void fc_device_block(struct scsi_device *sdev, void *data) { - scsi_internal_device_block(to_scsi_device(dev)); - return 0; + scsi_internal_device_block(sdev); } /** @@ -819,10 +818,9 @@ static int fc_device_block(struct device *dev, void *data) * @dev: scsi device * @data: unused **/ -static int fc_device_unblock(struct device *dev, void *data) +static void fc_device_unblock(struct scsi_device *sdev, void *data) { - scsi_internal_device_unblock(to_scsi_device(dev)); - return 0; + scsi_internal_device_unblock(sdev); } /** @@ -842,7 +840,7 @@ static void fc_timeout_blocked_tgt(void *data) * unblock this device, then IO errors will probably * result if the host still isn't ready. */ - device_for_each_child(&starget->dev, NULL, fc_device_unblock); + starget_for_each_device(starget, NULL, fc_device_unblock); } /** @@ -870,7 +868,7 @@ fc_target_block(struct scsi_target *starget) if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) return -EINVAL; - device_for_each_child(&starget->dev, NULL, fc_device_block); + starget_for_each_device(starget, NULL, fc_device_block); /* The scsi lld blocks this target for the timeout period only. */ schedule_delayed_work(work, timeout * HZ); @@ -901,7 +899,7 @@ fc_target_unblock(struct scsi_target *starget) if (cancel_delayed_work(&fc_starget_dev_loss_work(starget))) flush_scheduled_work(); - device_for_each_child(&starget->dev, NULL, fc_device_unblock); + starget_for_each_device(starget, NULL, fc_device_unblock); } EXPORT_SYMBOL(fc_target_unblock); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 6afc72fba7dc..8678132e3947 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -172,6 +172,8 @@ extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *, uint, uint, uint); extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *, uint, uint, uint); +extern void starget_for_each_device(struct scsi_target *, void *, + void (*fn)(struct scsi_device *, void *)); /* only exposed to implement shost_for_each_device */ extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, -- cgit v1.2.3 From e47da19362bec6bc9d7e17a599cc9eb6fd144eed Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 11 Jan 2005 22:09:46 -0600 Subject: FC Transport updates - additional fc host attributes From: James.Smart@Emulex.Com This patch adds 5 more FC transport host attributes in support of HBAAPI. Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 20 ++++++++++++++++++++ include/scsi/scsi_transport_fc.h | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'include') diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 2fddf2c24b67..1aca210eabd1 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -270,6 +270,16 @@ static int fc_setup_host_transport_attrs(struct Scsi_Host *shost) sizeof(fc_host_symbolic_name(shost))); fc_host_supported_speeds(shost) = FC_PORTSPEED_UNKNOWN; fc_host_maxframe_size(shost) = -1; + memset(fc_host_hardware_version(shost), 0, + sizeof(fc_host_hardware_version(shost))); + memset(fc_host_firmware_version(shost), 0, + sizeof(fc_host_firmware_version(shost))); + memset(fc_host_serial_number(shost), 0, + sizeof(fc_host_serial_number(shost))); + memset(fc_host_opt_rom_version(shost), 0, + sizeof(fc_host_opt_rom_version(shost))); + memset(fc_host_driver_version(shost), 0, + sizeof(fc_host_driver_version(shost))); fc_host_port_id(shost) = -1; fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; @@ -536,6 +546,11 @@ fc_private_host_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long); fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long); fc_private_host_rd_attr(symbolic_name, "%s\n", (FC_SYMBOLIC_NAME_SIZE +1)); fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20); +fc_private_host_rd_attr(hardware_version, "%s\n", (FC_VERSION_STRING_SIZE +1)); +fc_private_host_rd_attr(firmware_version, "%s\n", (FC_VERSION_STRING_SIZE +1)); +fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1)); +fc_private_host_rd_attr(opt_rom_version, "%s\n", (FC_VERSION_STRING_SIZE +1)); +fc_private_host_rd_attr(driver_version, "%s\n", (FC_VERSION_STRING_SIZE +1)); /* Dynamic Host Attributes */ @@ -772,6 +787,11 @@ fc_attach_transport(struct fc_function_template *ft) SETUP_HOST_ATTRIBUTE_RD(symbolic_name); SETUP_HOST_ATTRIBUTE_RD(supported_speeds); SETUP_HOST_ATTRIBUTE_RD(maxframe_size); + SETUP_HOST_ATTRIBUTE_RD(hardware_version); + SETUP_HOST_ATTRIBUTE_RD(firmware_version); + SETUP_HOST_ATTRIBUTE_RD(serial_number); + SETUP_HOST_ATTRIBUTE_RD(opt_rom_version); + SETUP_HOST_ATTRIBUTE_RD(driver_version); SETUP_HOST_ATTRIBUTE_RD(port_id); SETUP_HOST_ATTRIBUTE_RD(port_type); diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 3b7128327791..1d4adfd6d3e9 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -185,6 +185,8 @@ struct fc_host_statistics { #define FC_FC4_LIST_SIZE 32 #define FC_SYMBOLIC_NAME_SIZE 256 +#define FC_VERSION_STRING_SIZE 64 +#define FC_SERIAL_NUMBER_SIZE 80 struct fc_host_attrs { /* Fixed Attributes */ @@ -195,6 +197,11 @@ struct fc_host_attrs { char symbolic_name[FC_SYMBOLIC_NAME_SIZE]; u32 supported_speeds; u32 maxframe_size; + char hardware_version[FC_VERSION_STRING_SIZE]; + char firmware_version[FC_VERSION_STRING_SIZE]; + char serial_number[FC_SERIAL_NUMBER_SIZE]; + char opt_rom_version[FC_VERSION_STRING_SIZE]; + char driver_version[FC_VERSION_STRING_SIZE]; /* Dynamic Attributes */ u32 port_id; @@ -226,6 +233,16 @@ struct fc_host_attrs { (((struct fc_host_attrs *)(x)->shost_data)->supported_speeds) #define fc_host_maxframe_size(x) \ (((struct fc_host_attrs *)(x)->shost_data)->maxframe_size) +#define fc_host_hardware_version(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->hardware_version) +#define fc_host_firmware_version(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->firmware_version) +#define fc_host_serial_number(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->serial_number) +#define fc_host_opt_rom_version(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->opt_rom_version) +#define fc_host_driver_version(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->driver_version) #define fc_host_port_id(x) \ (((struct fc_host_attrs *)(x)->shost_data)->port_id) #define fc_host_port_type(x) \ @@ -285,6 +302,11 @@ struct fc_function_template { unsigned long show_host_symbolic_name:1; unsigned long show_host_supported_speeds:1; unsigned long show_host_maxframe_size:1; + unsigned long show_host_hardware_version:1; + unsigned long show_host_firmware_version:1; + unsigned long show_host_serial_number:1; + unsigned long show_host_opt_rom_version:1; + unsigned long show_host_driver_version:1; /* host dynamic attributes */ unsigned long show_host_port_id:1; unsigned long show_host_port_type:1; -- cgit v1.2.3