aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/DMA-mapping.txt8
-rw-r--r--Documentation/accounting/delay-accounting.txt110
-rw-r--r--Documentation/accounting/getdelays.c396
-rw-r--r--Documentation/accounting/taskstats.txt181
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--Documentation/memory-barriers.txt5
-rw-r--r--Documentation/ramdisk.txt12
-rw-r--r--MAINTAINERS16
-rw-r--r--arch/i386/kernel/crash.c2
-rw-r--r--arch/i386/kernel/setup.c5
-rw-r--r--arch/i386/kernel/traps.c40
-rw-r--r--arch/i386/lib/usercopy.c2
-rw-r--r--arch/um/Makefile-x86_641
-rw-r--r--arch/um/include/longjmp.h4
-rw-r--r--arch/um/include/os.h68
-rw-r--r--arch/um/kernel/vmlinux.lds.S2
-rw-r--r--arch/um/os-Linux/process.c8
-rw-r--r--arch/um/os-Linux/skas/process.c16
-rw-r--r--arch/um/os-Linux/uaccess.c3
-rw-r--r--block/ioctl.c4
-rw-r--r--drivers/block/Kconfig10
-rw-r--r--drivers/block/cpqarray.c2
-rw-r--r--drivers/block/rd.c2
-rw-r--r--drivers/char/nsc_gpio.c6
-rw-r--r--drivers/char/pc8736x_gpio.c15
-rw-r--r--drivers/char/scx200_gpio.c72
-rw-r--r--drivers/char/tpm/tpm.c1
-rw-r--r--drivers/char/tpm/tpm_tis.c77
-rw-r--r--drivers/infiniband/core/cm.c21
-rw-r--r--drivers/infiniband/core/cma.c22
-rw-r--r--drivers/infiniband/core/fmr_pool.c8
-rw-r--r--drivers/infiniband/core/sa_query.c10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_av.c5
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c13
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c3
-rw-r--r--drivers/leds/leds-net48xx.c7
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-isl1208.c591
-rw-r--r--drivers/video/Kconfig20
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/mbx/Makefile4
-rw-r--r--drivers/video/mbx/mbxdebugfs.c188
-rw-r--r--drivers/video/mbx/mbxfb.c683
-rw-r--r--drivers/video/mbx/reg_bits.h418
-rw-r--r--drivers/video/mbx/regs.h195
-rw-r--r--fs/char_dev.c22
-rw-r--r--fs/namei.c8
-rw-r--r--fs/proc/array.c6
-rw-r--r--fs/proc/base.c3
-rw-r--r--fs/reiserfs/procfs.c25
-rw-r--r--include/asm-alpha/barrier.h3
-rw-r--r--include/asm-arm/system.h1
-rw-r--r--include/asm-arm26/system.h1
-rw-r--r--include/asm-cris/system.h1
-rw-r--r--include/asm-frv/system.h1
-rw-r--r--include/asm-generic/Kbuild.asm5
-rw-r--r--include/asm-h8300/system.h1
-rw-r--r--include/asm-i386/system.h2
-rw-r--r--include/asm-ia64/system.h3
-rw-r--r--include/asm-m32r/system.h1
-rw-r--r--include/asm-m68k/system.h1
-rw-r--r--include/asm-m68knommu/system.h1
-rw-r--r--include/asm-mips/system.h3
-rw-r--r--include/asm-parisc/system.h2
-rw-r--r--include/asm-powerpc/system.h1
-rw-r--r--include/asm-ppc/system.h1
-rw-r--r--include/asm-s390/system.h1
-rw-r--r--include/asm-sh/system.h1
-rw-r--r--include/asm-sh64/system.h1
-rw-r--r--include/asm-sparc/system.h1
-rw-r--r--include/asm-sparc64/system.h2
-rw-r--r--include/asm-v850/system.h1
-rw-r--r--include/asm-x86_64/system.h1
-rw-r--r--include/asm-xtensa/system.h1
-rw-r--r--include/linux/delayacct.h119
-rw-r--r--include/linux/i2c-id.h1
-rw-r--r--include/linux/if_vlan.h5
-rw-r--r--include/linux/kthread.h1
-rw-r--r--include/linux/list.h11
-rw-r--r--include/linux/module.h10
-rw-r--r--include/linux/namei.h2
-rw-r--r--include/linux/nsc_gpio.h2
-rw-r--r--include/linux/sched.h56
-rw-r--r--include/linux/taskstats.h137
-rw-r--r--include/linux/taskstats_kern.h89
-rw-r--r--include/linux/time.h12
-rw-r--r--include/linux/vmalloc.h1
-rw-r--r--include/net/genetlink.h20
-rw-r--r--include/rdma/ib_addr.h10
-rw-r--r--include/rdma/ib_fmr_pool.h2
-rw-r--r--include/video/mbxfb.h28
-rw-r--r--init/Kconfig24
-rw-r--r--init/main.c4
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/acct.c4
-rw-r--r--kernel/delayacct.c178
-rw-r--r--kernel/exit.c10
-rw-r--r--kernel/fork.c6
-rw-r--r--kernel/kallsyms.c4
-rw-r--r--kernel/kthread.c24
-rw-r--r--kernel/module.c11
-rw-r--r--kernel/rtmutex-tester.c1
-rw-r--r--kernel/sched.c84
-rw-r--r--kernel/softirq.c2
-rw-r--r--kernel/taskstats.c568
-rw-r--r--kernel/timer.c20
-rw-r--r--lib/Kconfig.debug10
-rw-r--r--lib/idr.c16
-rw-r--r--mm/memory.c6
-rw-r--r--mm/nommu.c2
-rw-r--r--mm/vmalloc.c7
-rw-r--r--net/core/skbuff.c91
-rw-r--r--net/ipv4/ip_input.c3
-rw-r--r--net/sched/sch_htb.c4
-rw-r--r--security/selinux/hooks.c14
117 files changed, 4600 insertions, 374 deletions
diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
index 7c717699032..63392c9132b 100644
--- a/Documentation/DMA-mapping.txt
+++ b/Documentation/DMA-mapping.txt
@@ -698,12 +698,12 @@ these interfaces. Remember that, as defined, consistent mappings are
always going to be SAC addressable.
The first thing your driver needs to do is query the PCI platform
-layer with your devices DAC addressing capabilities:
+layer if it is capable of handling your devices DAC addressing
+capabilities:
- int pci_dac_set_dma_mask(struct pci_dev *pdev, u64 mask);
+ int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask);
-This routine behaves identically to pci_set_dma_mask. You may not
-use the following interfaces if this routine fails.
+You may not use the following interfaces if this routine fails.
Next, DMA addresses using this API are kept track of using the
dma64_addr_t type. It is guaranteed to be big enough to hold any
diff --git a/Documentation/accounting/delay-accounting.txt b/Documentation/accounting/delay-accounting.txt
new file mode 100644
index 00000000000..be215e58423
--- /dev/null
+++ b/Documentation/accounting/delay-accounting.txt
@@ -0,0 +1,110 @@
+Delay accounting
+----------------
+
+Tasks encounter delays in execution when they wait
+for some kernel resource to become available e.g. a
+runnable task may wait for a free CPU to run on.
+
+The per-task delay accounting functionality measures
+the delays experienced by a task while
+
+a) waiting for a CPU (while being runnable)
+b) completion of synchronous block I/O initiated by the task
+c) swapping in pages
+
+and makes these statistics available to userspace through
+the taskstats interface.
+
+Such delays provide feedback for setting a task's cpu priority,
+io priority and rss limit values appropriately. Long delays for
+important tasks could be a trigger for raising its corresponding priority.
+
+The functionality, through its use of the taskstats interface, also provides
+delay statistics aggregated for all tasks (or threads) belonging to a
+thread group (corresponding to a traditional Unix process). This is a commonly
+needed aggregation that is more efficiently done by the kernel.
+
+Userspace utilities, particularly resource management applications, can also
+aggregate delay statistics into arbitrary groups. To enable this, delay
+statistics of a task are available both during its lifetime as well as on its
+exit, ensuring continuous and complete monitoring can be done.
+
+
+Interface
+---------
+
+Delay accounting uses the taskstats interface which is described
+in detail in a separate document in this directory. Taskstats returns a
+generic data structure to userspace corresponding to per-pid and per-tgid
+statistics. The delay accounting functionality populates specific fields of
+this structure. See
+ include/linux/taskstats.h
+for a description of the fields pertaining to delay accounting.
+It will generally be in the form of counters returning the cumulative
+delay seen for cpu, sync block I/O, swapin etc.
+
+Taking the difference of two successive readings of a given
+counter (say cpu_delay_total) for a task will give the delay
+experienced by the task waiting for the corresponding resource
+in that interval.
+
+When a task exits, records containing the per-task statistics
+are sent to userspace without requiring a command. If it is the last exiting
+task of a thread group, the per-tgid statistics are also sent. More details
+are given in the taskstats interface description.
+
+The getdelays.c userspace utility in this directory allows simple commands to
+be run and the corresponding delay statistics to be displayed. It also serves
+as an example of using the taskstats interface.
+
+Usage
+-----
+
+Compile the kernel with
+ CONFIG_TASK_DELAY_ACCT=y
+ CONFIG_TASKSTATS=y
+
+Enable the accounting at boot time by adding
+the following to the kernel boot options
+ delayacct
+
+and after the system has booted up, use a utility
+similar to getdelays.c to access the delays
+seen by a given task or a task group (tgid).
+The utility also allows a given command to be
+executed and the corresponding delays to be
+seen.
+
+General format of the getdelays command
+
+getdelays [-t tgid] [-p pid] [-c cmd...]
+
+
+Get delays, since system boot, for pid 10
+# ./getdelays -p 10
+(output similar to next case)
+
+Get sum of delays, since system boot, for all pids with tgid 5
+# ./getdelays -t 5
+
+
+CPU count real total virtual total delay total
+ 7876 92005750 100000000 24001500
+IO count delay total
+ 0 0
+MEM count delay total
+ 0 0
+
+Get delays seen in executing a given simple command
+# ./getdelays -c ls /
+
+bin data1 data3 data5 dev home media opt root srv sys usr
+boot data2 data4 data6 etc lib mnt proc sbin subdomain tmp var
+
+
+CPU count real total virtual total delay total
+ 6 4000250 4000000 0
+IO count delay total
+ 0 0
+MEM count delay total
+ 0 0
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
new file mode 100644
index 00000000000..795ca3911cc
--- /dev/null
+++ b/Documentation/accounting/getdelays.c
@@ -0,0 +1,396 @@
+/* getdelays.c
+ *
+ * Utility to get per-pid and per-tgid delay accounting statistics
+ * Also illustrates usage of the taskstats interface
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2005
+ * Copyright (C) Balbir Singh, IBM Corp. 2006
+ * Copyright (c) Jay Lan, SGI. 2006
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <poll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <linux/genetlink.h>
+#include <linux/taskstats.h>
+
+/*
+ * Generic macros for dealing with netlink sockets. Might be duplicated
+ * elsewhere. It is recommended that commercial grade applications use
+ * libnl or libnetlink and use the interfaces provided by the library
+ */
+#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
+#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
+#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
+#define NLA_PAYLOAD(len) (len - NLA_HDRLEN)
+
+#define err(code, fmt, arg...) do { printf(fmt, ##arg); exit(code); } while (0)
+int done = 0;
+int rcvbufsz=0;
+
+ char name[100];
+int dbg=0, print_delays=0;
+__u64 stime, utime;
+#define PRINTF(fmt, arg...) { \
+ if (dbg) { \
+ printf(fmt, ##arg); \
+ } \
+ }
+
+/* Maximum size of response requested or message sent */
+#define MAX_MSG_SIZE 256
+/* Maximum number of cpus expected to be specified in a cpumask */
+#define MAX_CPUS 32
+/* Maximum length of pathname to log file */
+#define MAX_FILENAME 256
+
+struct msgtemplate {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[MAX_MSG_SIZE];
+};
+
+char cpumask[100+6*MAX_CPUS];
+
+/*
+ * Create a raw netlink socket and bind
+ */
+static int create_nl_socket(int protocol)
+{
+ int fd;
+ struct sockaddr_nl local;
+
+ fd = socket(AF_NETLINK, SOCK_RAW, protocol);
+ if (fd < 0)
+ return -1;
+
+ if (rcvbufsz)
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
+ &rcvbufsz, sizeof(rcvbufsz)) < 0) {
+ printf("Unable to set socket rcv buf size to %d\n",
+ rcvbufsz);
+ return -1;
+ }
+
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+
+ if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0)
+ goto error;
+
+ return fd;
+error:
+ close(fd);
+ return -1;
+}
+
+
+int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
+ __u8 genl_cmd, __u16 nla_type,
+ void *nla_data, int nla_len)
+{
+ struct nlattr *na;
+ struct sockaddr_nl nladdr;
+ int r, buflen;
+ char *buf;
+
+ struct msgtemplate msg;
+
+ msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ msg.n.nlmsg_type = nlmsg_type;
+ msg.n.nlmsg_flags = NLM_F_REQUEST;
+ msg.n.nlmsg_seq = 0;
+ msg.n.nlmsg_pid = nlmsg_pid;
+ msg.g.cmd = genl_cmd;
+ msg.g.version = 0x1;
+ na = (struct nlattr *) GENLMSG_DATA(&msg);
+ na->nla_type = nla_type;
+ na->nla_len = nla_len + 1 + NLA_HDRLEN;
+ memcpy(NLA_DATA(na), nla_data, nla_len);
+ msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+ buf = (char *) &msg;
+ buflen = msg.n.nlmsg_len ;
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr,
+ sizeof(nladdr))) < buflen) {
+ if (r > 0) {
+ buf += r;
+ buflen -= r;
+ } else if (errno != EAGAIN)
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * Probe the controller in genetlink to find the family id
+ * for the TASKSTATS family
+ */
+int get_family_id(int sd)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[256];
+ } ans;
+
+ int id, rc;
+ struct nlattr *na;
+ int rep_len;
+
+ strcpy(name, TASKSTATS_GENL_NAME);
+ rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
+ CTRL_ATTR_FAMILY_NAME, (void *)name,
+ strlen(TASKSTATS_GENL_NAME)+1);
+
+ rep_len = recv(sd, &ans, sizeof(ans), 0);
+ if (ans.n.nlmsg_type == NLMSG_ERROR ||
+ (rep_len < 0) || !NLMSG_OK((&ans.n), rep_len))
+ return 0;
+
+ na = (struct nlattr *) GENLMSG_DATA(&ans);
+ na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
+ if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(__u16 *) NLA_DATA(na);
+ }
+ return id;
+}
+
+void print_delayacct(struct taskstats *t)
+{
+ printf("\n\nCPU %15s%15s%15s%15s\n"
+ " %15llu%15llu%15llu%15llu\n"
+ "IO %15s%15s\n"
+ " %15llu%15llu\n"
+ "MEM %15s%15s\n"
+ " %15llu%15llu\n\n",
+ "count", "real total", "virtual total", "delay total",
+ t->cpu_count, t->cpu_run_real_total, t->cpu_run_virtual_total,
+ t->cpu_delay_total,
+ "count", "delay total",
+ t->blkio_count, t->blkio_delay_total,
+ "count", "delay total", t->swapin_count, t->swapin_delay_total);
+}
+
+int main(int argc, char *argv[])
+{
+ int c, rc, rep_len, aggr_len, len2, cmd_type;
+ __u16 id;
+ __u32 mypid;
+
+ struct nlattr *na;
+ int nl_sd = -1;
+ int len = 0;
+ pid_t tid = 0;
+ pid_t rtid = 0;
+
+ int fd = 0;
+ int count = 0;
+ int write_file = 0;
+ int maskset = 0;
+ char logfile[128];
+ int loop = 0;
+
+ struct msgtemplate msg;
+
+ while (1) {
+ c = getopt(argc, argv, "dw:r:m:t:p:v:l");
+ if (c < 0)
+ break;
+
+ switch (c) {
+ case 'd':
+ printf("print delayacct stats ON\n");
+ print_delays = 1;
+ break;
+ case 'w':
+ strncpy(logfile, optarg, MAX_FILENAME);
+ printf("write to file %s\n", logfile);
+ write_file = 1;
+ break;
+ case 'r':
+ rcvbufsz = atoi(optarg);
+ printf("receive buf size %d\n", rcvbufsz);
+ if (rcvbufsz < 0)
+ err(1, "Invalid rcv buf size\n");
+ break;
+ case 'm':
+ strncpy(cpumask, optarg, sizeof(cpumask));
+ maskset = 1;
+ printf("cpumask %s maskset %d\n", cpumask, maskset);
+ break;
+ case 't':
+ tid = atoi(optarg);
+ if (!tid)
+ err(1, "Invalid tgid\n");
+ cmd_type = TASKSTATS_CMD_ATTR_TGID;
+ print_delays = 1;
+ break;
+ case 'p':
+ tid = atoi(optarg);
+ if (!tid)
+ err(1, "Invalid pid\n");
+ cmd_type = TASKSTATS_CMD_ATTR_PID;
+ print_delays = 1;
+ break;
+ case 'v':
+ printf("debug on\n");
+ dbg = 1;
+ break;
+ case 'l':
+ printf("listen forever\n");
+ loop = 1;
+ break;
+ default:
+ printf("Unknown option %d\n", c);
+ exit(-1);
+ }
+ }
+
+ if (write_file) {
+ fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd == -1) {
+ perror("Cannot open output file\n");
+ exit(1);
+ }
+ }
+
+ if ((nl_sd = create_nl_socket(NETLINK_GENERIC)) < 0)
+ err(1, "error creating Netlink socket\n");
+
+
+ mypid = getpid();
+ id = get_family_id(nl_sd);
+ if (!id) {
+ printf("Error getting family id, errno %d", errno);
+ goto err;
+ }
+ PRINTF("family id %d\n", id);
+
+ if (maskset) {
+ rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
+ TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
+ &cpumask, sizeof(cpumask));
+ PRINTF("Sent register cpumask, retval %d\n", rc);
+ if (rc < 0) {
+ printf("error sending register cpumask\n");
+ goto err;
+ }
+ }
+
+ if (tid) {
+ rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
+ cmd_type, &tid, sizeof(__u32));
+ PRINTF("Sent pid/tgid, retval %d\n", rc);
+ if (rc < 0) {
+ printf("error sending tid/tgid cmd\n");
+ goto done;
+ }
+ }
+
+ do {
+ int i;
+
+ rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
+ PRINTF("received %d bytes\n", rep_len);
+
+ if (rep_len < 0) {
+ printf("nonfatal reply error: errno %d\n", errno);
+ continue;
+ }
+ if (msg.n.nlmsg_type == NLMSG_ERROR ||
+ !NLMSG_OK((&msg.n), rep_len)) {
+ printf("fatal reply error, errno %d\n", errno);
+ goto done;
+ }
+
+ PRINTF("nlmsghdr size=%d, nlmsg_len=%d, rep_len=%d\n",
+ sizeof(struct nlmsghdr), msg.n.nlmsg_len, rep_len);
+
+
+ rep_len = GENLMSG_PAYLOAD(&msg.n);
+
+ na = (struct nlattr *) GENLMSG_DATA(&msg);
+ len = 0;
+ i = 0;
+ while (len < rep_len) {
+ len += NLA_ALIGN(na->nla_len);
+ switch (na->nla_type) {
+ case TASKSTATS_TYPE_AGGR_TGID:
+ /* Fall through */
+ case TASKSTATS_TYPE_AGGR_PID:
+ aggr_len = NLA_PAYLOAD(na->nla_len);
+ len2 = 0;
+ /* For nested attributes, na follows */
+ na = (struct nlattr *) NLA_DATA(na);
+ done = 0;
+ while (len2 < aggr_len) {
+ switch (na->nla_type) {
+ case TASKSTATS_TYPE_PID:
+ rtid = *(int *) NLA_DATA(na);
+ if (print_delays)
+ printf("PID\t%d\n", rtid);
+ break;
+ case TASKSTATS_TYPE_TGID:
+ rtid = *(int *) NLA_DATA(na);
+ if (print_delays)
+ printf("TGID\t%d\n", rtid);
+ break;
+ case TASKSTATS_TYPE_STATS:
+ count++;
+ if (print_delays)
+ print_delayacct((struct taskstats *) NLA_DATA(na));
+ if (fd) {
+ if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
+ err(1,"write error\n");
+ }
+ }
+ if (!loop)
+ goto done;
+ break;
+ default:
+ printf("Unknown nested nla_type %d\n", na->nla_type);
+ break;
+ }
+ len2 += NLA_ALIGN(na->nla_len);
+ na = (struct nlattr *) ((char *) na + len2);
+ }
+ break;
+
+ default:
+ printf("Unknown nla_type %d\n", na->nla_type);
+ break;
+ }
+ na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
+ }
+ } while (loop);
+done:
+ if (maskset) {
+ rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
+ TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
+ &cpumask, sizeof(cpumask));
+ printf("Sent deregister mask, retval %d\n", rc);
+ if (rc < 0)
+ err(rc, "error sending deregister cpumask\n");
+ }
+err:
+ close(nl_sd);
+ if (fd)
+ close(fd);
+ return 0;
+}
diff --git a/Documentation/accounting/taskstats.txt b/Documentation/accounting/taskstats.txt
new file mode 100644
index 00000000000..92ebf29e904
--- /dev/null
+++ b/Documentation/accounting/taskstats.txt
@@ -0,0 +1,181 @@
+Per-task statistics interface
+-----------------------------
+
+
+Taskstats is a netlink-based interface for sending per-task and
+per-process statistics from the kernel to userspace.
+
+Taskstats was designed for the following benefits:
+
+- efficiently provide statistics during lifetime of a task and on its exit
+- unified interface for multiple accounting subsystems
+- extensibility for use by future accounting patches
+
+Terminology
+-----------
+
+"pid", "tid" and "task" are used interchangeably and refer to the standard
+Linux task defined by struct task_struct. per-pid stats are the same as
+per-task stats.
+
+"tgid", "process" and "thread group" are used interchangeably and refer to the
+tasks that share an mm_struct i.e. the traditional Unix process. Despite the
+use of tgid, there is no special treatment for the task that is thread group
+leader - a process is deemed alive as long as it has any task belonging to it.
+
+Usage
+-----
+
+To get statistics during a task's lifetime, userspace opens a unicast netlink
+socket (NETLINK_GENERIC family) and sends commands specifying a pid or a tgid.
+The response contains statistics for a task (if pid is specified) or the sum of
+statistics for all tasks of the process (if tgid is specified).
+
+To obtain statistics for tasks which are exiting, the userspace listener
+sends a register command and specifies a cpumask. Whenever a task exits on
+one of the cpus in the cpumask, its per-pid statistics are sent to the
+registered listener. Using cpumasks allows the data received by one listener
+to be limited and assists in flow control over the netlink interface and is
+explained in more detail below.
+
+If the exiting task is the last thread exiting its thread group,
+an additional record containing the per-tgid stats is also sent to userspace.
+The latter contains the sum of per-pid stats for all threads in the thread
+group, both past and present.
+
+getdelays.c is a simple utility demonstrating usage of the taskstats interface
+for reporting delay accounting statistics. Users can register cpumasks,
+send commands and process responses, listen for per-tid/tgid exit data,
+write the data received to a file and do basic flow control by increasing
+receive buffer sizes.
+
+Interface
+---------
+
+The user-kernel interface is encapsulated in include/linux/taskstats.h
+
+To avoid this documentation becoming obsolete as the interface evolves, only
+an outline of the current version is given. taskstats.h always overrides the
+description here.
+
+struct taskstats is the common accounting structure for both per-pid and
+per-tgid data. It is versioned and can be extended by each accounting subsystem
+that is added to the kernel. The fields and their semantics are defined in the
+taskstats.h file.
+
+The data exchanged between user and kernel space is a netlink message belonging
+to the NETLINK_GENERIC family and using the netlink attributes interface.
+The messages are in the format
+
+ +----------+- - -+-------------+-------------------+
+ | nlmsghdr | Pad | genlmsghdr | taskstats payload |
+ +----------+- - -+-------------+-------------------+
+
+
+The taskstats payload is one of the following three kinds:
+
+1. Commands: Sent from user to kernel. Commands to get data on
+a pid/tgid consist of one attribute, of type TASKSTATS_CMD_ATTR_PID/TGID,
+containing a u32 pid or tgid in the attribute payload. The pid/tgid denotes
+the task/process for which userspace wants statistics.
+
+Commands to register/deregister interest in exit data from a set of cpus
+consist of one attribute, of type
+TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK and contain a cpumask in the
+attribute payload. The cpumask is specified as an ascii string of
+comma-separated cpu ranges e.g. to listen to exit data from cpus 1,2,3,5,7,8
+the cpumask would be "1-3,5,7-8". If userspace forgets to deregister interest
+in cpus before closing the listening socket, the kernel cleans up its interest
+set over time. However, for the sake of efficiency, an explicit deregistration
+is advisable.
+
+2. Response for a command: sent from the kernel in response to a userspace
+command. The payload is a series of three attributes of type:
+
+a) TASKSTATS_TYPE_AGGR_PID/TGID : attribute containing no payload but indicates
+a pid/tgid will be followed by some stats.
+
+b) TASKSTATS_TYPE_PID/TGID: attribute whose payload is the pid/tgid whose stats
+is being returned.
+
+c) TASKSTATS_TYPE_STATS: attribute with a struct taskstsats as payload. The
+same structure is used for both per-pid and per-tgid stats.
+
+3. New message sent by kernel whenever a task exits. The payload consists of a
+ series of attributes of the following type:
+
+a) TASKSTATS_TYPE_AGGR_PID: indicates next two attributes will be pid+stats
+b) TASKSTATS_TYPE_PID: contains exiting task's pid
+c) TASKSTATS_TYPE_STATS: contains the exiting task's per-pid stats
+d) TASKSTATS_TYPE_AGGR_TGID: indicates next two attributes will be tgid+stats
+e) TASKSTATS_TYPE_TGID: contains tgid of process to which task belongs
+f) TASKSTATS_TYPE_STATS: contains the per-tgid stats for exiting task's process
+
+
+per-tgid stats
+--------------
+
+Taskstats provides per-process stats, in addition to per-task stats, since
+resource management is often done at a process granularity and aggregating task
+stats in userspace alone is inefficient and potentially inaccurate (due to lack
+of atomicity).
+
+However, maintaining per-process, in addition to per-task stats, within the
+kernel has space and time overheads. To address this, the taskstats code
+accumalates each exiting task's statistics into a process-wide data structure.
+When the last task of a process exits, the process level data accumalated also
+gets sent to userspace (along with the per-task data).
+
+When a user queries to get per-tgid data, the sum of all other live threads in
+the group is added up and added to the accumalated total for previously exited
+threads of the same thread group.
+
+Extending taskstats
+-------------------
+
+There are two ways to extend the taskstats interface to export more
+per-task/process stats as patches to collect them get added to the kernel
+in future:
+
+1. Adding more fields to the end of the existing struct taskstats. Backward
+ compatibility is ensured by the version number within the
+ structure. Userspace will use only the fields of the struct that correspond
+ to the version its using.
+
+2. Defining separate statistic structs and using the netlink attributes
+ interface to return them. Since userspace processes each netlink attribute
+ independently, it can always ignore attributes whose type it does not
+ understand (because it is using an older version of the interface).
+
+
+Choosing between 1. and 2. is a matter of trading off flexibility and
+overhead. If only a few fields need to be added, then 1. is the preferable
+path since the kernel and userspace don't need to incur the overhead of
+processing new netlink attributes. But if the new fields expand the existing
+struct too much, requiring disparate userspace accounting utilities to
+unnecessarily receive large structures whose fields are of no interest, then
+extending the attributes structure would be worthwhile.
+
+Flow control for taskstats
+--------------------------
+
+When the rate of task exits becomes large, a listener may not be able to keep
+up with the kernel's rate of sending per-tid/tgid exit data leading to data
+loss. This possibility gets compounded when the taskstats structure gets
+extended and the number of cpus grows large.
+
+To avoid losing statistics, userspace should do one or more of the following:
+
+- increase the receive buffer sizes for the netlink sockets opened by
+listeners to receive exit data.
+
+- create more listeners and reduce the number of cpus being listened to by
+each listener. In the extreme case, there could be one listener for each cpu.
+Users may also consider setting the cpu affinity of the listener to the subset
+of cpus to which it listens, especially if they are listening to just one cpu.
+
+Despite these measures, if the userspace receives ENOBUFS error messages
+indicated overflow of receive buffers, it should take measures to handle the
+loss of data.
+
+----
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 149f62ba14a..e11f7728ec6 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -448,6 +448,8 @@ running once the system is up.
Format: <area>[,<node>]
See also Documentation/networking/decnet.txt.
+ delayacct [KNL] Enable per-task delay accounting
+
dhash_entries= [KNL]
Set number of hash buckets for dentry cache.
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index 28d1bc3edb1..46b9b389df3 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -1015,10 +1015,9 @@ CPU from reordering them.
There are some more advanced barrier functions:
(*) set_mb(var, value)
- (*) set_wmb(var, value)
- These assign the value to the variable and then insert at least a write
- barrier after it, depending on the function. They aren't guaranteed to
+ This assigns the value to the variable and then inserts at least a write
+ barrier after it, depending on the function. It isn't guaranteed to
insert anything more than a compiler barrier in a UP compilation.
diff --git a/Documentation/ramdisk.txt b/Documentation/ramdisk.txt
index 7c25584e082..52f75b7d51c 100644
--- a/Documentation/ramdisk.txt
+++ b/Documentation/ramdisk.txt
@@ -6,7 +6,7 @@ Contents:
1) Overview
2) Kernel Command Line Parameters
3) Using "rdev -r"
- 4) An Example of Creating a Compressed RAM Disk
+ 4) An Example of Creating a Compressed RAM Disk
1) Overview
@@ -34,7 +34,7 @@ make it clearer. The original "ramdisk=<ram_size>" has been kept around for
compatibility reasons, but it may be removed in the future.
The new RAM disk also has the ability to load compressed RAM disk images,
-allowing one to squeeze more programs onto an average installation or
+allowing one to squeeze more programs onto an average installation or
rescue floppy disk.
@@ -51,7 +51,7 @@ default is 4096 (4 MB) (8192 (8 MB) on S390).
===================
This parameter tells the RAM disk driver how many bytes to use per block. The
-default is 512.
+default is 1024 (BLOCK_SIZE).
3) Using "rdev -r"
@@ -70,7 +70,7 @@ These numbers are no magical secrets, as seen below:
./arch/i386/kernel/setup.c:#define RAMDISK_PROMPT_FLAG 0x8000
./arch/i386/kernel/setup.c:#define RAMDISK_LOAD_FLAG 0x4000
-Consider a typical two floppy disk setup, where you will have the
+Consider a typical two floppy disk setup, where you will have the
kernel on disk one, and have already put a RAM disk image onto disk #2.
Hence you want to set bits 0 to 13 as 0, meaning that your RAM disk
@@ -97,12 +97,12 @@ Since the default start = 0 and the default prompt = 1, you could use:
append = "load_ramdisk=1"
-4) An Example of Creating a Compressed RAM Disk
+4) An Example of Creating a Compressed RAM Disk
----------------------------------------------
To create a RAM disk image, you will need a spare block device to
construct it on. This can be the RAM disk device itself, or an
-unused disk partition (such as an unmounted swap partition). For this
+unused disk partition (such as an unmounted swap partition). For this
example, we will use the RAM disk device, "/dev/ram0".
Note: This technique should not be done on a machine with less than 8 MB
diff --git a/MAINTAINERS b/MAINTAINERS
index a3462c3414c..e99028ca2f7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -771,6 +771,7 @@ M: aliakc@web.de
P: Jamie Lenehan
M: lenehan@twibble.org
W: http://twibble.org/dist/dc395x/
+L: dc395x@twibble.org
L: http://lists.twibble.org/mailman/listinfo/dc395x/
S: Maintained
@@ -1501,6 +1502,7 @@ P: Yi Zhu
M: yi.zhu@intel.com
P: James Ketrenos
M: jketreno@linux.intel.com
+L: ipw2100-devel@lists.sourceforge.net
L: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
W: http://ipw2100.sourceforge.net
S: Supported
@@ -1510,6 +1512,7 @@ P: Yi Zhu
M: yi.zhu@intel.com
P: James Ketrenos
M: jketreno@linux.intel.com
+L: ipw2100-devel@lists.sourceforge.net
L: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
W: http://ipw2200.sourceforge.net
S: Supported
@@ -2226,6 +2229,7 @@ S: Maintained
PCMCIA SUBSYSTEM
P: Linux PCMCIA Team
+L: linux-pcmcia@lists.infradead.org
L: http://lists.infradead.org/mailman/listinfo/linux-pcmcia
T: git kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
S: Maintained
@@ -2236,6 +2240,12 @@ M: tsbogend@alpha.franken.de
L: netdev@vger.kernel.org
S: Maintained
+PER-TASK DELAY ACCOUNTING
+P: Shailabh Nagar
+M: nagar@watson.ibm.com
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
PERSONALITY HANDLING
P: Christoph Hellwig
M: hch@infradead.org
@@ -2763,6 +2773,12 @@ P: Deepak Saxena
M: dsaxena@plexity.net
S: Maintained
+TASKSTATS STATISTICS INTERFACE
+P: Shailabh Nagar
+M: nagar@watson.ibm.com
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
TI PARALLEL LINK CABLE DRIVER
P: Romain Lievin
M: roms@lpg.ticalc.org
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index 48f0f62f781..5b96f038367 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -90,7 +90,7 @@ static void crash_save_self(struct pt_regs *regs)
crash_save_this_cpu(regs, cpu);
}
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
static atomic_t waiting_for_crash_ipi;
static int crash_nmi_callback(struct pt_regs *regs, int cpu)
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 7864395c144..f1682206d30 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -1327,7 +1327,10 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat
res->start = e820.map[i].addr;
res->end = res->start + e820.map[i].size - 1;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
- request_resource(&iomem_resource, res);
+ if (request_resource(&iomem_resource, res)) {
+ kfree(res);
+ continue;
+ }
if (e820.map[i].type == E820_RAM) {
/*
* We don't know which RAM region contains kernel data,
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 5cfd4f42eeb..313ac1f7dc5 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -324,35 +324,35 @@ void show_registers(struct pt_regs *regs)
static void handle_BUG(struct pt_regs *regs)
{
+ unsigned long eip = regs->eip;
unsigned short ud2;
- unsigned short line;
- char *file;
- char c;
- unsigned long eip;
-
- eip = regs->eip;
if (eip < PAGE_OFFSET)
- goto no_bug;
+ return;
if (__get_user(ud2, (unsigned short __user *)eip))
- goto no_bug;
+ return;
if (ud2 != 0x0b0f)
- goto no_bug;
- if (__get_user(line, (unsigned short __user *)(eip + 2)))
- goto bug;
- if (__get_user(file, (char * __user *)(eip + 4)) ||
- (unsigned long)file < PAGE_OFFSET || __get_user(c, file))
- file = "<bad filename>";
+ return;
printk(KERN_EMERG "------------[ cut here ]------------\n");
- printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line);
-no_bug:
- return;
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+ do {
+ unsigned short line;
+ char *file;
+ char c;
- /* Here we know it was a BUG but file-n-line is unavailable */
-bug:
- printk(KERN_EMERG "Kernel BUG\n");
+ if (__get_user(line, (unsigned short __user *)(eip + 2)))
+ break;
+ if (__get_user(file, (char * __user *)(eip + 4)) ||
+ (unsigned long)file < PAGE_OFFSET || __get_user(c, file))
+ file = "<bad filename>";
+
+ printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line);
+ return;
+ } while (0);
+#endif
+ printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\n");
}
/* This is gone through when something in the kernel
diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
index 4b75212ab6d..efc7e7d5f4d 100644
--- a/arch/i386/lib/usercopy.c
+++ b/arch/i386/lib/usercopy.c
@@ -843,7 +843,6 @@ unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *fr
unsigned long
copy_to_user(void __user *to, const void *from, unsigned long n)
{
- might_sleep();
BUG_ON((long) n < 0);
if (access_ok(VERIFY_WRITE, to, n))
n = __copy_to_user(to, from, n);
@@ -870,7 +869,6 @@ EXPORT_SYMBOL(copy_to_user);
unsigned long
copy_from_user(void *to, const void __user *from, unsigned long n)
{
- might_sleep();
BUG_ON((long) n < 0);
if (access_ok(VERIFY_READ, from, n))
n = __copy_from_user(to, from, n);
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index dffd1184c95..9558a7cf34d 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -11,6 +11,7 @@ USER_CFLAGS += -fno-builtin -m64
CHECKFLAGS += -m64
AFLAGS += -m64
LDFLAGS += -m elf_x86_64
+CPPFLAGS += -m64
ELF_ARCH := i386:x86-64
ELF_FORMAT := elf64-x86-64
diff --git a/arch/um/include/longjmp.h b/arch/um/include/longjmp.h
index 8e7053013f7..1b5c0131a12 100644
--- a/arch/um/include/longjmp.h
+++ b/arch/um/include/longjmp.h
@@ -8,8 +8,8 @@
longjmp(*buf, val); \
} while(0)
-#define UML_SETJMP(buf, enable) ({ \
- int n; \
+#define UML_SETJMP(buf) ({ \
+ int n, enable; \
enable = get_signals(); \
n = setjmp(*buf); \
if(n != 0) \
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index b6c52496e15..5316e8a4a4f 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -15,9 +15,9 @@
#include "irq_user.h"
#include "sysdep/tls.h"
-#define OS_TYPE_FILE 1
-#define OS_TYPE_DIR 2
-#define OS_TYPE_SYMLINK 3
+#define OS_TYPE_FILE 1
+#define OS_TYPE_DIR 2
+#define OS_TYPE_SYMLINK 3
#define OS_TYPE_CHARDEV 4
#define OS_TYPE_BLOCKDEV 5
#define OS_TYPE_FIFO 6
@@ -61,68 +61,68 @@ struct openflags {
};
#define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \
- .t = 0, .a = 0, .e = 0, .cl = 0 })
+ .t = 0, .a = 0, .e = 0, .cl = 0 })
static inline struct openflags of_read(struct openflags flags)
{
- flags.r = 1;
- return(flags);
+ flags.r = 1;
+ return flags;
}
static inline struct openflags of_write(struct openflags flags)
{
- flags.w = 1;
- return(flags);
+ flags.w = 1;
+ return flags;
}
static inline struct openflags of_rdwr(struct openflags flags)
{
- return(of_read(of_write(flags)));
+ return of_read(of_write(flags));
}
static inline struct openflags of_set_rw(struct openflags flags, int r, int w)
{
flags.r = r;
flags.w = w;
- return(flags);
+ return flags;
}
static inline struct openflags of_sync(struct openflags flags)
-{
- flags.s = 1;
- return(flags);
+{
+ flags.s = 1;
+ return flags;
}
static inline struct openflags of_create(struct openflags flags)
-{
- flags.c = 1;
- return(flags);
+{
+ flags.c = 1;
+ return flags;
}
-
+
static inline struct openflags of_trunc(struct openflags flags)
-{
- flags.t = 1;
- return(flags);
+{
+ flags.t = 1;
+ return flags;
}
-
+
static inline struct openflags of_append(struct openflags flags)
-{
- flags.a = 1;
- return(flags);
+{
+ flags.a = 1;
+ return flags;
}
-
+
static inline struct openflags of_excl(struct openflags flags)
-{
- flags.e = 1;
- return(flags);
+{
+ flags.e = 1;
+ return flags;
}
static inline struct openflags of_cloexec(struct openflags flags)
-{
- flags.cl = 1;
- return(flags);
+{
+ flags.cl = 1;
+ return flags;
}
-
+
/* file.c */
extern int os_stat_file(const char *file_name, struct uml_stat *buf);
extern int os_stat_fd(const int fd, struct uml_stat *buf);
@@ -204,7 +204,7 @@ extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
extern int os_map_memory(void *virt, int fd, unsigned long long off,
unsigned long len, int r, int w, int x);
-extern int os_protect_memory(void *addr, unsigned long len,
+extern int os_protect_memory(void *addr, unsigned long len,
int r, int w, int x);
extern int os_unmap_memory(void *addr, int len);
extern int os_drop_memory(void *addr, int length);
diff --git a/arch/um/kernel/vmlinux.lds.S b/arch/um/kernel/vmlinux.lds.S
index 72acdce205e..f8aeb448aab 100644
--- a/arch/um/kernel/vmlinux.lds.S
+++ b/arch/um/kernel/vmlinux.lds.S
@@ -1,5 +1,3 @@
-/* in case the preprocessor is a 32bit one */
-#undef i386
#ifdef CONFIG_LD_SCRIPT_STATIC
#include "uml.lds.S"
#else
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index b1cda818f5b..b98d3ca2cd1 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -273,12 +273,12 @@ void init_new_thread_signals(void)
int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
{
jmp_buf buf;
- int n, enable;
+ int n;
*jmp_ptr = &buf;
- n = UML_SETJMP(&buf, enable);
+ n = UML_SETJMP(&buf);
if(n != 0)
- return(n);
+ return n;
(*fn)(arg);
- return(0);
+ return 0;
}
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index bf35572d9cf..7baf90fda58 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -435,7 +435,6 @@ void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
{
unsigned long flags;
jmp_buf switch_buf, fork_buf;
- int enable;
*switch_buf_ptr = &switch_buf;
*fork_buf_ptr = &fork_buf;
@@ -450,7 +449,7 @@ void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
*/
flags = get_signals();
block_signals();
- if(UML_SETJMP(&fork_buf, enable) == 0)
+ if(UML_SETJMP(&fork_buf) == 0)
new_thread_proc(stack, handler);
remove_sigstack();
@@ -467,21 +466,19 @@ void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
void thread_wait(void *sw, void *fb)
{
jmp_buf buf, **switch_buf = sw, *fork_buf;
- int enable;
*switch_buf = &buf;
fork_buf = fb;
- if(UML_SETJMP(&buf, enable) == 0)
+ if(UML_SETJMP(&buf) == 0)
siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK);
}
void switch_threads(void *me, void *next)
{
jmp_buf my_buf, **me_ptr = me, *next_buf = next;
- int enable;
*me_ptr = &my_buf;
- if(UML_SETJMP(&my_buf, enable) == 0)
+ if(UML_SETJMP(&my_buf) == 0)
UML_LONGJMP(next_buf, 1);
}
@@ -495,14 +492,14 @@ static jmp_buf *cb_back;
int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
{
jmp_buf **switch_buf = switch_buf_ptr;
- int n, enable;
+ int n;
set_handler(SIGWINCH, (__sighandler_t) sig_handler,
SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
SIGVTALRM, -1);
*fork_buf_ptr = &initial_jmpbuf;
- n = UML_SETJMP(&initial_jmpbuf, enable);
+ n = UML_SETJMP(&initial_jmpbuf);
switch(n){
case INIT_JMP_NEW_THREAD:
new_thread_proc((void *) stack, new_thread_handler);
@@ -529,14 +526,13 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
void initial_thread_cb_skas(void (*proc)(void *), void *arg)
{
jmp_buf here;
- int enable;
cb_proc = proc;
cb_arg = arg;
cb_back = &here;
block_signals();
- if(UML_SETJMP(&here, enable) == 0)
+ if(UML_SETJMP(&here) == 0)
UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK);
unblock_signals();
diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c
index e523719330b..865f6a6a259 100644
--- a/arch/um/os-Linux/uaccess.c
+++ b/arch/um/os-Linux/uaccess.c
@@ -14,11 +14,10 @@ unsigned long __do_user_copy(void *to, const void *from, int n,
int n), int *faulted_out)
{
unsigned long *faddrp = (unsigned long *) fault_addr, ret;
- int enable;
jmp_buf jbuf;
*fault_catcher = &jbuf;
- if(UML_SETJMP(&jbuf, enable) == 0){
+ if(UML_SETJMP(&jbuf) == 0){
(*op)(to, from, n);
ret = 0;
*faulted_out = 0;
diff --git a/block/ioctl.c b/block/ioctl.c
index 9cfa2e1ecb2..309760b7e37 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -72,7 +72,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
bdevp = bdget_disk(disk, part);
if (!bdevp)
return -ENOMEM;
- mutex_lock(&bdevp->bd_mutex);
+ mutex_lock_nested(&bdevp->bd_mutex, BD_MUTEX_PARTITION);
if (bdevp->bd_openers) {
mutex_unlock(&bdevp->bd_mutex);
bdput(bdevp);
@@ -82,7 +82,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
fsync_bdev(bdevp);
invalidate_bdev(bdevp, 0);
- mutex_lock(&bdev->bd_mutex);
+ mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_WHOLE);
delete_partition(disk, part);
mutex_unlock(&bdev->bd_mutex);
mutex_unlock(&bdevp->bd_mutex);
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 93d94749310..b5382cedf0c 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -400,6 +400,16 @@ config BLK_DEV_RAM_SIZE
what are you doing. If you are using IBM S/390, then set this to
8192.
+config BLK_DEV_RAM_BLOCKSIZE
+ int "Default RAM disk block size (bytes)"
+ depends on BLK_DEV_RAM
+ default "1024"
+ help
+ The default value is 1024 kilobytes. PAGE_SIZE is a much more
+ efficient choice however. The default is kept to ensure initrd
+ setups function - apparently needed by the rd_load_image routine
+ that supposes the filesystem in the image uses a 1024 blocksize.
+
config BLK_DEV_INITRD
bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
depends on BROKEN || !FRV
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 757f42dd8e8..78082edc14b 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -1739,8 +1739,6 @@ static void getgeometry(int ctlr)
(log_index < id_ctlr_buf->nr_drvs)
&& (log_unit < NWD);
log_unit++) {
- struct gendisk *disk = ida_gendisk[ctlr][log_unit];
-
size = sizeof(sense_log_drv_stat_t);
/*
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 3cf246abb5e..a3f64bfe6b5 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -84,7 +84,7 @@ int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */
* behaviour. The default is still BLOCK_SIZE (needed by rd_load_image that
* supposes the filesystem in the image uses a BLOCK_SIZE blocksize).
*/
-static int rd_blocksize = BLOCK_SIZE; /* blocksize of the RAM disks */
+static int rd_blocksize = CONFIG_BLK_DEV_RAM_BLOCKSIZE;
/*
* Copyright (C) 2000 Linus Torvalds.
diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c
index 5b91e4e2564..7719bd75810 100644
--- a/drivers/char/nsc_gpio.c
+++ b/drivers/char/nsc_gpio.c
@@ -68,13 +68,11 @@ ssize_t nsc_gpio_write(struct file *file, const char __user *data,
amp->gpio_config(m, ~1, 0);
break;
case 'T':
- dev_dbg(dev, "GPIO%d output is push pull\n",
- m);
+ dev_dbg(dev, "GPIO%d output is push pull\n", m);
amp->gpio_config(m, ~2, 2);
break;
case 't':
- dev_dbg(dev, "GPIO%d output is open drain\n",
- m);
+ dev_dbg(dev, "GPIO%d output is open drain\n", m);
amp->gpio_config(m, ~2, 0);
break;
case 'P':
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c
index 11bd78c8062..645eb81cb5a 100644
--- a/drivers/char/pc8736x_gpio.c
+++ b/drivers/char/pc8736x_gpio.c
@@ -212,22 +212,21 @@ static void pc8736x_gpio_change(unsigned index)
pc8736x_gpio_set(index, !pc8736x_gpio_current(index));
}
-static struct nsc_gpio_ops pc8736x_access = {
+static struct nsc_gpio_ops pc8736x_gpio_ops = {
.owner = THIS_MODULE,
.gpio_config = pc8736x_gpio_configure,
.gpio_dump = nsc_gpio_dump,
.gpio_get = pc8736x_gpio_get,
.gpio_set = pc8736x_gpio_set,
- .gpio_set_high = pc8736x_gpio_set_high,
- .gpio_set_low = pc8736x_gpio_set_low,
.gpio_change = pc8736x_gpio_change,
.gpio_current = pc8736x_gpio_current
};
+EXPORT_SYMBOL(pc8736x_gpio_ops);
static int pc8736x_gpio_open(struct inode *inode, struct file *file)
{
unsigned m = iminor(inode);
- file->private_data = &pc8736x_access;
+ file->private_data = &pc8736x_gpio_ops;
dev_dbg(&pdev->dev, "open %d\n", m);
@@ -236,7 +235,7 @@ static int pc8736x_gpio_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
-static const struct file_operations pc8736x_gpio_fops = {
+static const struct file_operations pc8736x_gpio_fileops = {
.owner = THIS_MODULE,
.open = pc8736x_gpio_open,
.write = nsc_gpio_write,
@@ -278,7 +277,7 @@ static int __init pc8736x_gpio_init(void)
dev_err(&pdev->dev, "no device found\n");
goto undo_platform_dev_add;
}
- pc8736x_access.dev = &pdev->dev;
+ pc8736x_gpio_ops.dev = &pdev->dev;
/* Verify that chip and it's GPIO unit are both enabled.
My BIOS does this, so I take minimum action here
@@ -328,7 +327,7 @@ static int __init pc8736x_gpio_init(void)
pc8736x_init_shadow();
/* ignore minor errs, and succeed */
- cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fops);
+ cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fileops);
cdev_add(&pc8736x_gpio_cdev, devid, PC8736X_GPIO_CT);
return 0;
@@ -355,7 +354,5 @@ static void __exit pc8736x_gpio_cleanup(void)
platform_device_put(pdev);
}
-EXPORT_SYMBOL(pc8736x_access);
-
module_init(pc8736x_gpio_init);
module_exit(pc8736x_gpio_cleanup);
diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c
index 425c58719db..b956c7babd1 100644
--- a/drivers/char/scx200_gpio.c
+++ b/drivers/char/scx200_gpio.c
@@ -5,7 +5,6 @@
Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
@@ -22,37 +21,37 @@
#include <linux/scx200_gpio.h>
#include <linux/nsc_gpio.h>
-#define NAME "scx200_gpio"
-#define DEVNAME NAME
+#define DRVNAME "scx200_gpio"
static struct platform_device *pdev;
MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
+MODULE_DESCRIPTION("NatSemi/AMD SCx200 GPIO Pin Driver");
MODULE_LICENSE("GPL");
static int major = 0; /* default to dynamic major */
module_param(major, int, 0);
MODULE_PARM_DESC(major, "Major device number");
-struct nsc_gpio_ops scx200_access = {
+#define MAX_PINS 32 /* 64 later, when known ok */
+
+struct nsc_gpio_ops scx200_gpio_ops = {
.owner = THIS_MODULE,
.gpio_config = scx200_gpio_configure,
.gpio_dump = nsc_gpio_dump,
.gpio_get = scx200_gpio_get,
.gpio_set = scx200_gpio_set,
- .gpio_set_high = scx200_gpio_set_high,
- .gpio_set_low = scx200_gpio_set_low,
.gpio_change = scx200_gpio_change,
.gpio_current = scx200_gpio_current
};
+EXPORT_SYMBOL(scx200_gpio_ops);
static int scx200_gpio_open(struct inode *inode, struct file *file)
{
unsigned m = iminor(inode);
- file->private_data = &scx200_access;
+ file->private_data = &scx200_gpio_ops;
- if (m > 63)
+ if (m >= MAX_PINS)
return -EINVAL;
return nonseekable_open(inode, file);
}
@@ -62,8 +61,7 @@ static int scx200_gpio_release(struct inode *inode, struct file *file)
return 0;
}
-
-static const struct file_operations scx200_gpio_fops = {
+static const struct file_operations scx200_gpio_fileops = {
.owner = THIS_MODULE,
.write = nsc_gpio_write,
.read = nsc_gpio_read,
@@ -71,21 +69,20 @@ static const struct file_operations scx200_gpio_fops = {
.release = scx200_gpio_release,
};
-struct cdev *scx200_devices;
-static int num_pins = 32;
+struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */
static int __init scx200_gpio_init(void)
{
- int rc, i;
- dev_t dev = MKDEV(major, 0);
+ int rc;
+ dev_t devid;
if (!scx200_gpio_present()) {
- printk(KERN_ERR NAME ": no SCx200 gpio present\n");
+ printk(KERN_ERR DRVNAME ": no SCx200 gpio present\n");
return -ENODEV;
}
/* support dev_dbg() with pdev->dev */
- pdev = platform_device_alloc(DEVNAME, 0);
+ pdev = platform_device_alloc(DRVNAME, 0);
if (!pdev)
return -ENOMEM;
@@ -94,37 +91,25 @@ static int __init scx200_gpio_init(void)
goto undo_malloc;
/* nsc_gpio uses dev_dbg(), so needs this */
- scx200_access.dev = &pdev->dev;
-
- if (major)
- rc = register_chrdev_region(dev, num_pins, "scx200_gpio");
- else {
- rc = alloc_chrdev_region(&dev, 0, num_pins, "scx200_gpio");
- major = MAJOR(dev);
+ scx200_gpio_ops.dev = &pdev->dev;
+
+ if (major) {
+ devid = MKDEV(major, 0);
+ rc = register_chrdev_region(devid, MAX_PINS, "scx200_gpio");
+ } else {
+ rc = alloc_chrdev_region(&devid, 0, MAX_PINS, "scx200_gpio");
+ major = MAJOR(devid);
}
if (rc < 0) {
dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc);
goto undo_platform_device_add;
}
- scx200_devices = kzalloc(num_pins * sizeof(struct cdev), GFP_KERNEL);
- if (!scx200_devices) {
- rc = -ENOMEM;
- goto undo_chrdev_region;
- }
- for (i = 0; i < num_pins; i++) {
- struct cdev *cdev = &scx200_devices[i];
- cdev_init(cdev, &scx200_gpio_fops);
- cdev->owner = THIS_MODULE;
- rc = cdev_add(cdev, MKDEV(major, i), 1);
- /* tolerate 'minor' errors */
- if (rc)
- dev_err(&pdev->dev, "Error %d on minor %d", rc, i);
- }
+
+ cdev_init(&scx200_gpio_cdev, &scx200_gpio_fileops);
+ cdev_add(&scx200_gpio_cdev, devid, MAX_PINS);
return 0; /* succeed */
-undo_chrdev_region:
- unregister_chrdev_region(dev, num_pins);
undo_platform_device_add:
platform_device_del(pdev);
undo_malloc:
@@ -135,10 +120,11 @@ undo_malloc:
static void __exit scx200_gpio_cleanup(void)
{
- kfree(scx200_devices);
- unregister_chrdev_region(MKDEV(major, 0), num_pins);
+ cdev_del(&scx200_gpio_cdev);
+ /* cdev_put(&scx200_gpio_cdev); */
+
+ unregister_chrdev_region(MKDEV(major, 0), MAX_PINS);
platform_device_unregister(pdev);
- /* kfree(pdev); */
}
module_init(scx200_gpio_init);
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 6889e7db3af..a082a2e3425 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1141,6 +1141,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
put_device(dev);
clear_bit(chip->dev_num, dev_mask);
kfree(chip);
+ kfree(devname);
return NULL;
}
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 3232b193259..ee7ac6f43c6 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -424,6 +424,7 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
iowrite32(interrupt,
chip->vendor.iobase +
TPM_INT_STATUS(chip->vendor.locality));
+ ioread32(chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
return IRQ_HANDLED;
}
@@ -431,23 +432,19 @@ static int interrupts = 1;
module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
-static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
- const struct pnp_device_id *pnp_id)
+static int tpm_tis_init(struct device *dev, resource_size_t start,
+ resource_size_t len)
{
u32 vendor, intfcaps, intmask;
int rc, i;
- unsigned long start, len;
struct tpm_chip *chip;
- start = pnp_mem_start(pnp_dev, 0);
- len = pnp_mem_len(pnp_dev, 0);
-
if (!start)
start = TIS_MEM_BASE;
if (!len)
len = TIS_MEM_LEN;
- if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis)))
+ if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
return -ENODEV;
chip->vendor.iobase = ioremap(start, len);
@@ -464,7 +461,7 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
- dev_info(&pnp_dev->dev,
+ dev_info(dev,
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
@@ -472,26 +469,26 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
intfcaps =
ioread32(chip->vendor.iobase +
TPM_INTF_CAPS(chip->vendor.locality));
- dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n",
+ dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
intfcaps);
if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
- dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n");
+ dev_dbg(dev, "\tBurst Count Static\n");
if (intfcaps & TPM_INTF_CMD_READY_INT)
- dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n");
+ dev_dbg(dev, "\tCommand Ready Int Support\n");
if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n");
+ dev_dbg(dev, "\tInterrupt Edge Falling\n");
if (intfcaps & TPM_INTF_INT_EDGE_RISING)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n");
+ dev_dbg(dev, "\tInterrupt Edge Rising\n");
if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n");
+ dev_dbg(dev, "\tInterrupt Level Low\n");
if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n");
+ dev_dbg(dev, "\tInterrupt Level High\n");
if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
- dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n");
+ dev_dbg(dev, "\tLocality Change Int Support\n");
if (intfcaps & TPM_INTF_STS_VALID_INT)
- dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n");
+ dev_dbg(dev, "\tSts Valid Int Support\n");
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
- dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n");
+ dev_dbg(dev, "\tData Avail Int Support\n");
if (request_locality(chip, 0) != 0) {
rc = -ENODEV;
@@ -594,6 +591,16 @@ out_err:
return rc;
}
+static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
+ const struct pnp_device_id *pnp_id)
+{
+ resource_size_t start, len;
+ start = pnp_mem_start(pnp_dev, 0);
+ len = pnp_mem_len(pnp_dev, 0);
+
+ return tpm_tis_init(&pnp_dev->dev, start, len);
+}
+
static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
{
return tpm_pm_suspend(&dev->dev, msg);
@@ -628,8 +635,36 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
+static struct device_driver tis_drv = {
+ .name = "tpm_tis",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ .suspend = tpm_pm_suspend,
+ .resume = tpm_pm_resume,
+};
+
+static struct platform_device *pdev;
+
+static int force;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
static int __init init_tis(void)
{
+ int rc;
+
+ if (force) {
+ rc = driver_register(&tis_drv);
+ if (rc < 0)
+ return rc;
+ if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
+ return PTR_ERR(pdev);
+ if((rc=tpm_tis_init(&pdev->dev, 0, 0)) != 0) {
+ platform_device_unregister(pdev);
+ driver_unregister(&tis_drv);
+ }
+ return rc;
+ }
+
return pnp_register_driver(&tis_pnp_driver);
}
@@ -654,7 +689,11 @@ static void __exit cleanup_tis(void)
tpm_remove_hardware(chip->dev);
}
spin_unlock(&tis_lock);
- pnp_unregister_driver(&tis_pnp_driver);
+ if (force) {
+ platform_device_unregister(pdev);
+ driver_unregister(&tis_drv);
+ } else
+ pnp_unregister_driver(&tis_pnp_driver);
}
module_init(init_tis);
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 3f6705f3083..f85c97f7500 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -701,7 +701,7 @@ static void cm_reset_to_idle(struct cm_id_private *cm_id_priv)
}
}
-void ib_destroy_cm_id(struct ib_cm_id *cm_id)
+static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
{
struct cm_id_private *cm_id_priv;
struct cm_work *work;
@@ -735,12 +735,22 @@ retest:
sizeof cm_id_priv->av.port->cm_dev->ca_guid,
NULL, 0);
break;
+ case IB_CM_REQ_RCVD:
+ if (err == -ENOMEM) {
+ /* Do not reject to allow future retries. */
+ cm_reset_to_idle(cm_id_priv);
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ } else {
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
+ NULL, 0, NULL, 0);
+ }
+ break;
case IB_CM_MRA_REQ_RCVD:
case IB_CM_REP_SENT:
case IB_CM_MRA_REP_RCVD:
ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
/* Fall through */
- case IB_CM_REQ_RCVD:
case IB_CM_MRA_REQ_SENT:
case IB_CM_REP_RCVD:
case IB_CM_MRA_REP_SENT:
@@ -775,6 +785,11 @@ retest:
kfree(cm_id_priv->private_data);
kfree(cm_id_priv);
}
+
+void ib_destroy_cm_id(struct ib_cm_id *cm_id)
+{
+ cm_destroy_id(cm_id, 0);
+}
EXPORT_SYMBOL(ib_destroy_cm_id);
int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
@@ -1163,7 +1178,7 @@ static void cm_process_work(struct cm_id_private *cm_id_priv,
}
cm_deref_id(cm_id_priv);
if (ret)
- ib_destroy_cm_id(&cm_id_priv->id);
+ cm_destroy_id(&cm_id_priv->id, ret);
}
static void cm_format_mra(struct cm_mra_msg *mra_msg,
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 863f64befc7..d6f99d5720f 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -262,14 +262,14 @@ static void cma_detach_from_dev(struct rdma_id_private *id_priv)
static int cma_acquire_ib_dev(struct rdma_id_private *id_priv)
{
struct cma_device *cma_dev;
- union ib_gid *gid;
+ union ib_gid gid;
int ret = -ENODEV;
- gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
+ ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid),
mutex_lock(&lock);
list_for_each_entry(cma_dev, &dev_list, list) {
- ret = ib_find_cached_gid(cma_dev->device, gid,
+ ret = ib_find_cached_gid(cma_dev->device, &gid,
&id_priv->id.port_num, NULL);
if (!ret) {
cma_attach_to_dev(id_priv, cma_dev);
@@ -812,6 +812,7 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
cma_modify_qp_err(&id_priv->id);
status = ib_event->param.rej_rcvd.reason;
event = RDMA_CM_EVENT_REJECTED;
+ private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
break;
default:
printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d",
@@ -1134,8 +1135,8 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
struct ib_sa_path_rec path_rec;
memset(&path_rec, 0, sizeof path_rec);
- path_rec.sgid = *ib_addr_get_sgid(addr);
- path_rec.dgid = *ib_addr_get_dgid(addr);
+ ib_addr_get_sgid(addr, &path_rec.sgid);
+ ib_addr_get_dgid(addr, &path_rec.dgid);
path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
path_rec.numb_path = 1;
@@ -1263,7 +1264,7 @@ static int cma_bind_loopback(struct rdma_id_private *id_priv)
{
struct cma_device *cma_dev;
struct ib_port_attr port_attr;
- union ib_gid *gid;
+ union ib_gid gid;
u16 pkey;
int ret;
u8 p;
@@ -1284,8 +1285,7 @@ static int cma_bind_loopback(struct rdma_id_private *id_priv)
}
port_found:
- gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
- ret = ib_get_cached_gid(cma_dev->device, p, 0, gid);
+ ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid);
if (ret)
goto out;
@@ -1293,6 +1293,7 @@ port_found:
if (ret)
goto out;
+ ib_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
id_priv->id.port_num = p;
cma_attach_to_dev(id_priv, cma_dev);
@@ -1339,6 +1340,7 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
{
struct cma_work *work;
struct sockaddr_in *src_in, *dst_in;
+ union ib_gid gid;
int ret;
work = kzalloc(sizeof *work, GFP_KERNEL);
@@ -1351,8 +1353,8 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
goto err;
}
- ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr,
- ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr));
+ ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
+ ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) {
src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr;
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index 615fe9cc6c5..86a3b2d401d 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -426,7 +426,7 @@ EXPORT_SYMBOL(ib_flush_fmr_pool);
struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
u64 *page_list,
int list_len,
- u64 *io_virtual_address)
+ u64 io_virtual_address)
{
struct ib_fmr_pool *pool = pool_handle;
struct ib_pool_fmr *fmr;
@@ -440,7 +440,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
fmr = ib_fmr_cache_lookup(pool,
page_list,
list_len,
- *io_virtual_address);
+ io_virtual_address);
if (fmr) {
/* found in cache */
++fmr->ref_count;
@@ -464,7 +464,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
spin_unlock_irqrestore(&pool->pool_lock, flags);
result = ib_map_phys_fmr(fmr->fmr, page_list, list_len,
- *io_virtual_address);
+ io_virtual_address);
if (result) {
spin_lock_irqsave(&pool->pool_lock, flags);
@@ -481,7 +481,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
fmr->ref_count = 1;
if (pool->cache_bucket) {
- fmr->io_virtual_address = *io_virtual_address;
+ fmr->io_virtual_address = io_virtual_address;
fmr->page_list_len = list_len;
memcpy(fmr->page_list, page_list, list_len * sizeof(*page_list));
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index e911c99ff84..aeda484ffd8 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -488,13 +488,13 @@ static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent)
spin_unlock_irqrestore(&tid_lock, flags);
}
-static int send_mad(struct ib_sa_query *query, int timeout_ms)
+static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
{
unsigned long flags;
int ret, id;
retry:
- if (!idr_pre_get(&query_idr, GFP_ATOMIC))
+ if (!idr_pre_get(&query_idr, gfp_mask))
return -ENOMEM;
spin_lock_irqsave(&idr_lock, flags);
ret = idr_get_new(&query_idr, query, &id);
@@ -630,7 +630,7 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
*sa_query = &query->sa_query;
- ret = send_mad(&query->sa_query, timeout_ms);
+ ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
if (ret < 0)
goto err2;
@@ -752,7 +752,7 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method,
*sa_query = &query->sa_query;
- ret = send_mad(&query->sa_query, timeout_ms);
+ ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
if (ret < 0)
goto err2;
@@ -844,7 +844,7 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
*sa_query = &query->sa_query;
- ret = send_mad(&query->sa_query, timeout_ms);
+ ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
if (ret < 0)
goto err2;
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index b12aa03be25..e215041b2db 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -303,9 +303,10 @@ int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr)
memset(attr, 0, sizeof *attr);
attr->dlid = be16_to_cpu(ah->av->dlid);
attr->sl = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
- attr->static_rate = ah->av->msg_sr & 0x7;
- attr->src_path_bits = ah->av->g_slid & 0x7F;
attr->port_num = be32_to_cpu(ah->av->port_pd) >> 24;
+ attr->static_rate = mthca_rate_to_ib(dev, ah->av->msg_sr & 0x7,
+ attr->port_num);
+ attr->src_path_bits = ah->av->g_slid & 0x7F;
attr->ah_flags = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0;
if (attr->ah_flags) {
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 490fc783bb0..cd8b6721ac9 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -222,9 +222,8 @@ static void *get_send_wqe(struct mthca_qp *qp, int n)
(PAGE_SIZE - 1));
}
-static void mthca_wq_init(struct mthca_wq *wq)
+static void mthca_wq_reset(struct mthca_wq *wq)
{
- /* mthca_alloc_qp_common() initializes the locks */
wq->next_ind = 0;
wq->last_comp = wq->max - 1;
wq->head = 0;
@@ -845,10 +844,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
- mthca_wq_init(&qp->sq);
+ mthca_wq_reset(&qp->sq);
qp->sq.last = get_send_wqe(qp, qp->sq.max - 1);
- mthca_wq_init(&qp->rq);
+ mthca_wq_reset(&qp->rq);
qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1);
if (mthca_is_memfree(dev)) {
@@ -1112,9 +1111,9 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
qp->atomic_rd_en = 0;
qp->resp_depth = 0;
qp->sq_policy = send_policy;
- mthca_wq_init(&qp->sq);
- mthca_wq_init(&qp->rq);
- /* these are initialized separately so lockdep can tell them apart */
+ mthca_wq_reset(&qp->sq);
+ mthca_wq_reset(&qp->rq);
+
spin_lock_init(&qp->sq.lock);
spin_lock_init(&qp->rq.lock);
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index ff117bbf81b..72febf1f8ff 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -594,7 +594,7 @@ int iser_reg_page_vec(struct iser_conn *ib_conn,
mem = ib_fmr_pool_map_phys(ib_conn->fmr_pool,
page_list,
page_vec->length,
- &io_addr);
+ io_addr);
if (IS_ERR(mem)) {
status = (int)PTR_ERR(mem);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 4e22afef720..8f472e7113b 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -615,9 +615,10 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
(sg_dma_address(&scat[i]) & dev->fmr_page_mask) + j;
req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool,
- dma_pages, page_cnt, &io_addr);
+ dma_pages, page_cnt, io_addr);
if (IS_ERR(req->fmr)) {
ret = PTR_ERR(req->fmr);
+ req->fmr = NULL;
goto out;
}
diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c
index 35ee52f9b79..713c4a8aa77 100644
--- a/drivers/leds/leds-net48xx.c
+++ b/drivers/leds/leds-net48xx.c
@@ -18,6 +18,7 @@
#include <asm/io.h>
#include <linux/scx200_gpio.h>
+#define DRVNAME "net48xx-led"
#define NET48XX_ERROR_LED_GPIO 20
static struct platform_device *pdev;
@@ -66,13 +67,13 @@ static int net48xx_led_remove(struct platform_device *pdev)
}
static struct platform_driver net48xx_led_driver = {
- .driver.owner = THIS_MODULE,
.probe = net48xx_led_probe,
.remove = net48xx_led_remove,
.suspend = net48xx_led_suspend,
.resume = net48xx_led_resume,
.driver = {
- .name = "net48xx-led",
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
},
};
@@ -89,7 +90,7 @@ static int __init net48xx_led_init(void)
if (ret < 0)
goto out;
- pdev = platform_device_register_simple("net48xx-led", -1, NULL, 0);
+ pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
platform_driver_unregister(&net48xx_led_driver);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index f5b9f187a93..7ff1d88094b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -121,6 +121,16 @@ config RTC_DRV_DS1553
This driver can also be built as a module. If so, the module
will be called rtc-ds1553.
+config RTC_DRV_ISL1208
+ tristate "Intersil 1208"
+ depends on RTC_CLASS && I2C
+ help
+ If you say yes here you get support for the
+ Intersil 1208 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-isl1208.
+
config RTC_DRV_DS1672
tristate "Dallas/Maxim DS1672"
depends on RTC_CLASS && I2C
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 54220714ff4..bbcfb09d81d 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
+obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
new file mode 100644
index 00000000000..f324d0a635d
--- /dev/null
+++ b/drivers/rtc/rtc-isl1208.c
@@ -0,0 +1,591 @@
+/*
+ * Intersil ISL1208 rtc class driver
+ *
+ * Copyright 2005,2006 Hebert Valerio Riedel <hvr@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+
+#define DRV_NAME "isl1208"
+#define DRV_VERSION "0.2"
+
+/* Register map */
+/* rtc section */
+#define ISL1208_REG_SC 0x00
+#define ISL1208_REG_MN 0x01
+#define ISL1208_REG_HR 0x02
+#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */
+#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
+#define ISL1208_REG_DT 0x03
+#define ISL1208_REG_MO 0x04
+#define ISL1208_REG_YR 0x05
+#define ISL1208_REG_DW 0x06
+#define ISL1208_RTC_SECTION_LEN 7
+
+/* control/status section */
+#define ISL1208_REG_SR 0x07
+#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */
+#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */
+#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */
+#define ISL1208_REG_SR_ALM (1<<2) /* alarm */
+#define ISL1208_REG_SR_BAT (1<<1) /* battery */
+#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */
+#define ISL1208_REG_INT 0x08
+#define ISL1208_REG_09 0x09 /* reserved */
+#define ISL1208_REG_ATR 0x0a
+#define ISL1208_REG_DTR 0x0b
+
+/* alarm section */
+#define ISL1208_REG_SCA 0x0c
+#define ISL1208_REG_MNA 0x0d
+#define ISL1208_REG_HRA 0x0e
+#define ISL1208_REG_DTA 0x0f
+#define ISL1208_REG_MOA 0x10
+#define ISL1208_REG_DWA 0x11
+#define ISL1208_ALARM_SECTION_LEN 6
+
+/* user section */
+#define ISL1208_REG_USR1 0x12
+#define ISL1208_REG_USR2 0x13
+#define ISL1208_USR_SECTION_LEN 2
+
+/* i2c configuration */
+#define ISL1208_I2C_ADDR 0xde
+
+static unsigned short normal_i2c[] = {
+ ISL1208_I2C_ADDR>>1, I2C_CLIENT_END
+};
+I2C_CLIENT_INSMOD; /* defines addr_data */
+
+static int isl1208_attach_adapter(struct i2c_adapter *adapter);
+static int isl1208_detach_client(struct i2c_client *client);
+
+static struct i2c_driver isl1208_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ },
+ .id = I2C_DRIVERID_ISL1208,
+ .attach_adapter = &isl1208_attach_adapter,
+ .detach_client = &isl1208_detach_client,
+};
+
+/* block read */
+static int
+isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
+ unsigned len)
+{
+ u8 reg_addr[1] = { reg };
+ struct i2c_msg msgs[2] = {
+ { client->addr, client->flags, sizeof(reg_addr), reg_addr },
+ { client->addr, client->flags | I2C_M_RD, len, buf }
+ };
+ int ret;
+
+ BUG_ON(len == 0);
+ BUG_ON(reg > ISL1208_REG_USR2);
+ BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
+
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret > 0)
+ ret = 0;
+ return ret;
+}
+
+/* block write */
+static int
+isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[],
+ unsigned len)
+{
+ u8 i2c_buf[ISL1208_REG_USR2 + 2];
+ struct i2c_msg msgs[1] = {
+ { client->addr, client->flags, len + 1, i2c_buf }
+ };
+ int ret;
+
+ BUG_ON(len == 0);
+ BUG_ON(reg > ISL1208_REG_USR2);
+ BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
+
+ i2c_buf[0] = reg;
+ memcpy(&i2c_buf[1], &buf[0], len);
+
+ ret = i2c_transfer(client->adapter, msgs, 1);
+ if (ret > 0)
+ ret = 0;
+ return ret;
+}
+
+/* simple check to see wether we have a isl1208 */
+static int isl1208_i2c_validate_client(struct i2c_client *client)
+{
+ u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
+ u8 zero_mask[ISL1208_RTC_SECTION_LEN] = {
+ 0x80, 0x80, 0x40, 0xc0, 0xe0, 0x00, 0xf8
+ };
+ int i;
+ int ret;
+
+ ret = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) {
+ if (regs[i] & zero_mask[i]) /* check if bits are cleared */
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int isl1208_i2c_get_sr(struct i2c_client *client)
+{
+ return i2c_smbus_read_byte_data(client, ISL1208_REG_SR) == -1 ? -EIO:0;
+}
+
+static int isl1208_i2c_get_atr(struct i2c_client *client)
+{
+ int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR);
+
+ if (atr < 0)
+ return -EIO;
+
+ /* The 6bit value in the ATR register controls the load
+ * capacitance C_load * in steps of 0.25pF
+ *
+ * bit (1<<5) of the ATR register is inverted
+ *
+ * C_load(ATR=0x20) = 4.50pF
+ * C_load(ATR=0x00) = 12.50pF
+ * C_load(ATR=0x1f) = 20.25pF
+ *
+ */
+
+ atr &= 0x3f; /* mask out lsb */
+ atr ^= 1<<5; /* invert 6th bit */
+ atr += 2*9; /* add offset of 4.5pF; unit[atr] = 0.25pF */
+
+ return atr;
+}
+
+static int isl1208_i2c_get_dtr(struct i2c_client *client)
+{
+ int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR);
+
+ if (dtr < 0)
+ return -EIO;
+
+ /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */
+ dtr = ((dtr & 0x3) * 20) * (dtr & (1<<2) ? -1 : 1);
+
+ return dtr;
+}
+
+static int isl1208_i2c_get_usr(struct i2c_client *client)
+{
+ u8 buf[ISL1208_USR_SECTION_LEN] = { 0, };
+ int ret;
+
+ ret = isl1208_i2c_read_regs (client, ISL1208_REG_USR1, buf,
+ ISL1208_USR_SECTION_LEN);
+ if (ret < 0)
+ return ret;
+
+ return (buf[1] << 8) | buf[0];
+}
+
+static int isl1208_i2c_set_usr(struct i2c_client *client, u16 usr)
+{
+ u8 buf[ISL1208_USR_SECTION_LEN];
+
+ buf[0] = usr & 0xff;
+ buf[1] = (usr >> 8) & 0xff;
+
+ return isl1208_i2c_set_regs (client, ISL1208_REG_USR1, buf,
+ ISL1208_USR_SECTION_LEN);
+}
+
+static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct i2c_client *const client = to_i2c_client(dev);
+ int sr, dtr, atr, usr;
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return sr;
+ }
+
+ seq_printf(seq, "status_reg\t:%s%s%s%s%s%s (0x%.2x)\n",
+ (sr & ISL1208_REG_SR_RTCF) ? " RTCF" : "",
+ (sr & ISL1208_REG_SR_BAT) ? " BAT" : "",
+ (sr & ISL1208_REG_SR_ALM) ? " ALM" : "",
+ (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "",
+ (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "",
+ (sr & ISL1208_REG_SR_ARST) ? " ARST" : "",
+ sr);
+
+ seq_printf(seq, "batt_status\t: %s\n",
+ (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay");
+
+ dtr = isl1208_i2c_get_dtr(client);
+ if (dtr >= 0 -1)
+ seq_printf(seq, "digital_trim\t: %d ppm\n", dtr);
+
+ atr = isl1208_i2c_get_atr(client);
+ if (atr >= 0)
+ seq_printf(seq, "analog_trim\t: %d.%.2d pF\n",
+ atr>>2, (atr&0x3)*25);
+
+ usr = isl1208_i2c_get_usr(client);
+ if (usr >= 0)
+ seq_printf(seq, "user_data\t: 0x%.4x\n", usr);
+
+ return 0;
+}
+
+
+static int isl1208_i2c_read_time(struct i2c_client *client,
+ struct rtc_time *tm)
+{
+ int sr;
+ u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return -EIO;
+ }
+
+ sr = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading RTC section failed\n",
+ __func__);
+ return sr;
+ }
+
+ tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]);
+ tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]);
+ { /* HR field has a more complex interpretation */
+ const u8 _hr = regs[ISL1208_REG_HR];
+ if (_hr & ISL1208_REG_HR_MIL) /* 24h format */
+ tm->tm_hour = BCD2BIN(_hr & 0x3f);
+ else { // 12h format
+ tm->tm_hour = BCD2BIN(_hr & 0x1f);
+ if (_hr & ISL1208_REG_HR_PM) /* PM flag set */
+ tm->tm_hour += 12;
+ }
+ }
+
+ tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]);
+ tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */
+ tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100;
+ tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]);
+
+ return 0;
+}
+
+static int isl1208_i2c_read_alarm(struct i2c_client *client,
+ struct rtc_wkalrm *alarm)
+{
+ struct rtc_time *const tm = &alarm->time;
+ u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
+ int sr;
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return sr;
+ }
+
+ sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs,
+ ISL1208_ALARM_SECTION_LEN);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading alarm section failed\n",
+ __func__);
+ return sr;
+ }
+
+ /* MSB of each alarm register is an enable bit */
+ tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA-ISL1208_REG_SCA] & 0x7f);
+ tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA-ISL1208_REG_SCA] & 0x7f);
+ tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA-ISL1208_REG_SCA] & 0x3f);
+ tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA-ISL1208_REG_SCA] & 0x3f);
+ tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MOA-ISL1208_REG_SCA] & 0x1f)-1;
+ tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA-ISL1208_REG_SCA] & 0x03);
+
+ return 0;
+}
+
+static int isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return isl1208_i2c_read_time(to_i2c_client(dev), tm);
+}
+
+static int isl1208_i2c_set_time(struct i2c_client *client,
+ struct rtc_time const *tm)
+{
+ int sr;
+ u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
+
+ regs[ISL1208_REG_SC] = BIN2BCD(tm->tm_sec);
+ regs[ISL1208_REG_MN] = BIN2BCD(tm->tm_min);
+ regs[ISL1208_REG_HR] = BIN2BCD(tm->tm_hour) | ISL1208_REG_HR_MIL;
+
+ regs[ISL1208_REG_DT] = BIN2BCD(tm->tm_mday);
+ regs[ISL1208_REG_MO] = BIN2BCD(tm->tm_mon + 1);
+ regs[ISL1208_REG_YR] = BIN2BCD(tm->tm_year - 100);
+
+ regs[ISL1208_REG_DW] = BIN2BCD(tm->tm_wday & 7);
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return sr;
+ }
+
+ /* set WRTC */
+ sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
+ sr | ISL1208_REG_SR_WRTC);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: writing SR failed\n", __func__);
+ return sr;
+ }
+
+ /* write RTC registers */
+ sr = isl1208_i2c_set_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: writing RTC section failed\n",
+ __func__);
+ return sr;
+ }
+
+ /* clear WRTC again */
+ sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
+ sr & ~ISL1208_REG_SR_WRTC);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: writing SR failed\n", __func__);
+ return sr;
+ }
+
+ return 0;
+}
+
+
+static int isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return isl1208_i2c_set_time(to_i2c_client(dev), tm);
+}
+
+static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm);
+}
+
+static struct rtc_class_ops isl1208_rtc_ops = {
+ .proc = isl1208_rtc_proc,
+ .read_time = isl1208_rtc_read_time,
+ .set_time = isl1208_rtc_set_time,
+ .read_alarm = isl1208_rtc_read_alarm,
+ //.set_alarm = isl1208_rtc_set_alarm,
+};
+
+/* sysfs interface */
+
+static ssize_t isl1208_sysfs_show_atrim(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int atr;
+
+ atr = isl1208_i2c_get_atr(to_i2c_client(dev));
+ if (atr < 0)
+ return atr;
+
+ return sprintf(buf, "%d.%.2d pF\n", atr>>2, (atr&0x3)*25);
+}
+static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL);
+
+static ssize_t isl1208_sysfs_show_dtrim(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int dtr;
+
+ dtr = isl1208_i2c_get_dtr(to_i2c_client(dev));
+ if (dtr < 0)
+ return dtr;
+
+ return sprintf(buf, "%d ppm\n", dtr);
+}
+static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL);
+
+static ssize_t isl1208_sysfs_show_usr(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int usr;
+
+ usr = isl1208_i2c_get_usr(to_i2c_client(dev));
+ if (usr < 0)
+ return usr;
+
+ return sprintf(buf, "0x%.4x\n", usr);
+}
+
+static ssize_t isl1208_sysfs_store_usr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int usr = -1;
+
+ if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) {
+ if (sscanf(buf, "%x", &usr) != 1)
+ return -EINVAL;
+ } else {
+ if (sscanf(buf, "%d", &usr) != 1)
+ return -EINVAL;
+ }
+
+ if (usr < 0 || usr > 0xffff)
+ return -EINVAL;
+
+ return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count;
+}
+static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
+ isl1208_sysfs_store_usr);
+
+static int
+isl1208_probe(struct i2c_adapter *adapter, int addr, int kind)
+{
+ int rc = 0;
+ struct i2c_client *new_client = NULL;
+ struct rtc_device *rtc = NULL;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+ rc = -ENODEV;
+ goto failout;
+ }
+
+ new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (new_client == NULL) {
+ rc = -ENOMEM;
+ goto failout;
+ }
+
+ new_client->addr = addr;
+ new_client->adapter = adapter;
+ new_client->driver = &isl1208_driver;
+ new_client->flags = 0;
+ strcpy(new_client->name, DRV_NAME);
+
+ if (kind < 0) {
+ rc = isl1208_i2c_validate_client(new_client);
+ if (rc < 0)
+ goto failout;
+ }
+
+ rc = i2c_attach_client(new_client);
+ if (rc < 0)
+ goto failout;
+
+ dev_info(&new_client->dev,
+ "chip found, driver version " DRV_VERSION "\n");
+
+ rtc = rtc_device_register(isl1208_driver.driver.name,
+ &new_client->dev,
+ &isl1208_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc)) {
+ rc = PTR_ERR(rtc);
+ goto failout_detach;
+ }
+
+ i2c_set_clientdata(new_client, rtc);
+
+ rc = isl1208_i2c_get_sr(new_client);
+ if (rc < 0) {
+ dev_err(&new_client->dev, "reading status failed\n");
+ goto failout_unregister;
+ }
+
+ if (rc & ISL1208_REG_SR_RTCF)
+ dev_warn(&new_client->dev, "rtc power failure detected, "
+ "please set clock.\n");
+
+ rc = device_create_file(&new_client->dev, &dev_attr_atrim);
+ if (rc < 0)
+ goto failout_unregister;
+ rc = device_create_file(&new_client->dev, &dev_attr_dtrim);
+ if (rc < 0)
+ goto failout_atrim;
+ rc = device_create_file(&new_client->dev, &dev_attr_usr);
+ if (rc < 0)
+ goto failout_dtrim;
+
+ return 0;
+
+ failout_dtrim:
+ device_remove_file(&new_client->dev, &dev_attr_dtrim);
+ failout_atrim:
+ device_remove_file(&new_client->dev, &dev_attr_atrim);
+ failout_unregister:
+ rtc_device_unregister(rtc);
+ failout_detach:
+ i2c_detach_client(new_client);
+ failout:
+ kfree(new_client);
+ return rc;
+}
+
+static int
+isl1208_attach_adapter (struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, isl1208_probe);
+}
+
+static int
+isl1208_detach_client(struct i2c_client *client)
+{
+ int rc;
+ struct rtc_device *const rtc = i2c_get_clientdata(client);
+
+ if (rtc)
+ rtc_device_unregister(rtc); /* do we need to kfree? */
+
+ rc = i2c_detach_client(client);
+ if (rc)
+ return rc;
+
+ kfree(client);
+
+ return 0;
+}
+
+/* module management */
+
+static int __init isl1208_init(void)
+{
+ return i2c_add_driver(&isl1208_driver);
+}
+
+static void __exit isl1208_exit(void)
+{
+ i2c_del_driver(&isl1208_driver);
+}
+
+MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
+MODULE_DESCRIPTION("Intersil ISL1208 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(isl1208_init);
+module_exit(isl1208_exit);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3badb48d662..6533b0f3923 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1518,6 +1518,26 @@ config FB_PXA_PARAMETERS
<file:Documentation/fb/pxafb.txt> describes the available parameters.
+config FB_MBX
+ tristate "2700G LCD framebuffer support"
+ depends on FB && ARCH_PXA
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Framebuffer driver for the Intel 2700G (Marathon) Graphics
+ Accelerator
+
+config FB_MBX_DEBUG
+ bool "Enable debugging info via debugfs"
+ depends on FB_MBX && DEBUG_FS
+ default n
+ ---help---
+ Enable this if you want debugging information using the debug
+ filesystem (debugfs)
+
+ If unsure, say N.
+
config FB_W100
tristate "W100 frame buffer support"
depends on FB && PXA_SHARPSL
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 6283d015f8f..95563c9c6b9 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_FB_SIS) += sis/
obj-$(CONFIG_FB_KYRO) += kyro/
obj-$(CONFIG_FB_SAVAGE) += savage/
obj-$(CONFIG_FB_GEODE) += geode/
+obj-$(CONFIG_FB_MBX) += mbx/
obj-$(CONFIG_FB_I810) += vgastate.o
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o vgastate.o
obj-$(CONFIG_FB_VIRGE) += virgefb.o
diff --git a/drivers/video/mbx/Makefile b/drivers/video/mbx/Makefile
new file mode 100644
index 00000000000..16c1165cf9c
--- /dev/null
+++ b/drivers/video/mbx/Makefile
@@ -0,0 +1,4 @@
+# Makefile for the 2700G controller driver.
+
+obj-$(CONFIG_FB_MBX) += mbxfb.o
+obj-$(CONFIG_FB_MBX_DEBUG) += mbxfbdebugfs.o
diff --git a/drivers/video/mbx/mbxdebugfs.c b/drivers/video/mbx/mbxdebugfs.c
new file mode 100644
index 00000000000..84aab3ad024
--- /dev/null
+++ b/drivers/video/mbx/mbxdebugfs.c
@@ -0,0 +1,188 @@
+#include <linux/debugfs.h>
+
+#define BIG_BUFFER_SIZE (1024)
+
+static char big_buffer[BIG_BUFFER_SIZE];
+
+struct mbxfb_debugfs_data {
+ struct dentry *dir;
+ struct dentry *sysconf;
+ struct dentry *clock;
+ struct dentry *display;
+ struct dentry *gsctl;
+};
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->u.generic_ip;
+ return 0;
+}
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return count;
+}
+
+static ssize_t sysconf_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "SYSCFG = %08lx\n", SYSCFG);
+ s += sprintf(s, "PFBASE = %08lx\n", PFBASE);
+ s += sprintf(s, "PFCEIL = %08lx\n", PFCEIL);
+ s += sprintf(s, "POLLFLAG = %08lx\n", POLLFLAG);
+ s += sprintf(s, "SYSRST = %08lx\n", SYSRST);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+
+static ssize_t gsctl_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "GSCTRL = %08lx\n", GSCTRL);
+ s += sprintf(s, "VSCTRL = %08lx\n", VSCTRL);
+ s += sprintf(s, "GBBASE = %08lx\n", GBBASE);
+ s += sprintf(s, "VBBASE = %08lx\n", VBBASE);
+ s += sprintf(s, "GDRCTRL = %08lx\n", GDRCTRL);
+ s += sprintf(s, "VCMSK = %08lx\n", VCMSK);
+ s += sprintf(s, "GSCADR = %08lx\n", GSCADR);
+ s += sprintf(s, "VSCADR = %08lx\n", VSCADR);
+ s += sprintf(s, "VUBASE = %08lx\n", VUBASE);
+ s += sprintf(s, "VVBASE = %08lx\n", VVBASE);
+ s += sprintf(s, "GSADR = %08lx\n", GSADR);
+ s += sprintf(s, "VSADR = %08lx\n", VSADR);
+ s += sprintf(s, "HCCTRL = %08lx\n", HCCTRL);
+ s += sprintf(s, "HCSIZE = %08lx\n", HCSIZE);
+ s += sprintf(s, "HCPOS = %08lx\n", HCPOS);
+ s += sprintf(s, "HCBADR = %08lx\n", HCBADR);
+ s += sprintf(s, "HCCKMSK = %08lx\n", HCCKMSK);
+ s += sprintf(s, "GPLUT = %08lx\n", GPLUT);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static ssize_t display_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "DSCTRL = %08lx\n", DSCTRL);
+ s += sprintf(s, "DHT01 = %08lx\n", DHT01);
+ s += sprintf(s, "DHT02 = %08lx\n", DHT02);
+ s += sprintf(s, "DHT03 = %08lx\n", DHT03);
+ s += sprintf(s, "DVT01 = %08lx\n", DVT01);
+ s += sprintf(s, "DVT02 = %08lx\n", DVT02);
+ s += sprintf(s, "DVT03 = %08lx\n", DVT03);
+ s += sprintf(s, "DBCOL = %08lx\n", DBCOL);
+ s += sprintf(s, "BGCOLOR = %08lx\n", BGCOLOR);
+ s += sprintf(s, "DINTRS = %08lx\n", DINTRS);
+ s += sprintf(s, "DINTRE = %08lx\n", DINTRE);
+ s += sprintf(s, "DINTRCNT = %08lx\n", DINTRCNT);
+ s += sprintf(s, "DSIG = %08lx\n", DSIG);
+ s += sprintf(s, "DMCTRL = %08lx\n", DMCTRL);
+ s += sprintf(s, "CLIPCTRL = %08lx\n", CLIPCTRL);
+ s += sprintf(s, "SPOCTRL = %08lx\n", SPOCTRL);
+ s += sprintf(s, "SVCTRL = %08lx\n", SVCTRL);
+ s += sprintf(s, "DLSTS = %08lx\n", DLSTS);
+ s += sprintf(s, "DLLCTRL = %08lx\n", DLLCTRL);
+ s += sprintf(s, "DVLNUM = %08lx\n", DVLNUM);
+ s += sprintf(s, "DUCTRL = %08lx\n", DUCTRL);
+ s += sprintf(s, "DVECTRL = %08lx\n", DVECTRL);
+ s += sprintf(s, "DHDET = %08lx\n", DHDET);
+ s += sprintf(s, "DVDET = %08lx\n", DVDET);
+ s += sprintf(s, "DODMSK = %08lx\n", DODMSK);
+ s += sprintf(s, "CSC01 = %08lx\n", CSC01);
+ s += sprintf(s, "CSC02 = %08lx\n", CSC02);
+ s += sprintf(s, "CSC03 = %08lx\n", CSC03);
+ s += sprintf(s, "CSC04 = %08lx\n", CSC04);
+ s += sprintf(s, "CSC05 = %08lx\n", CSC05);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static ssize_t clock_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "SYSCLKSRC = %08lx\n", SYSCLKSRC);
+ s += sprintf(s, "PIXCLKSRC = %08lx\n", PIXCLKSRC);
+ s += sprintf(s, "CLKSLEEP = %08lx\n", CLKSLEEP);
+ s += sprintf(s, "COREPLL = %08lx\n", COREPLL);
+ s += sprintf(s, "DISPPLL = %08lx\n", DISPPLL);
+ s += sprintf(s, "PLLSTAT = %08lx\n", PLLSTAT);
+ s += sprintf(s, "VOVRCLK = %08lx\n", VOVRCLK);
+ s += sprintf(s, "PIXCLK = %08lx\n", PIXCLK);
+ s += sprintf(s, "MEMCLK = %08lx\n", MEMCLK);
+ s += sprintf(s, "M24CLK = %08lx\n", M24CLK);
+ s += sprintf(s, "MBXCLK = %08lx\n", MBXCLK);
+ s += sprintf(s, "SDCLK = %08lx\n", SDCLK);
+ s += sprintf(s, "PIXCLKDIV = %08lx\n", PIXCLKDIV);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static struct file_operations sysconf_fops = {
+ .read = sysconf_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations clock_fops = {
+ .read = clock_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations display_fops = {
+ .read = display_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations gsctl_fops = {
+ .read = gsctl_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+
+static void __devinit mbxfb_debugfs_init(struct fb_info *fbi)
+{
+ struct mbxfb_info *mfbi = fbi->par;
+ struct mbxfb_debugfs_data *dbg;
+
+ dbg = kzalloc(sizeof(struct mbxfb_debugfs_data), GFP_KERNEL);
+ mfbi->debugfs_data = dbg;
+
+ dbg->dir = debugfs_create_dir("mbxfb", NULL);
+ dbg->sysconf = debugfs_create_file("sysconf", 0444, dbg->dir,
+ fbi, &sysconf_fops);
+ dbg->clock = debugfs_create_file("clock", 0444, dbg->dir,
+ fbi, &clock_fops);
+ dbg->display = debugfs_create_file("display", 0444, dbg->dir,
+ fbi, &display_fops);
+ dbg->gsctl = debugfs_create_file("gsctl", 0444, dbg->dir,
+ fbi, &gsctl_fops);
+}
+
+static void __devexit mbxfb_debugfs_remove(struct fb_info *fbi)
+{
+ struct mbxfb_info *mfbi = fbi->par;
+ struct mbxfb_debugfs_data *dbg = mfbi->debugfs_data;
+
+ debugfs_remove(dbg->gsctl);
+ debugfs_remove(dbg->display);
+ debugfs_remove(dbg->clock);
+ debugfs_remove(dbg->sysconf);
+ debugfs_remove(dbg->dir);
+}
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
new file mode 100644
index 00000000000..6849ab75d40
--- /dev/null
+++ b/drivers/video/mbx/mbxfb.c
@@ -0,0 +1,683 @@
+/*
+ * linux/drivers/video/mbx/mbxfb.c
+ *
+ * Copyright (C) 2006 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on pxafb.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <video/mbxfb.h>
+
+#include "regs.h"
+#include "reg_bits.h"
+
+static unsigned long virt_base_2700;
+
+#define MIN_XRES 16
+#define MIN_YRES 16
+#define MAX_XRES 2048
+#define MAX_YRES 2048
+
+#define MAX_PALETTES 16
+
+/* FIXME: take care of different chip revisions with different sizes
+ of ODFB */
+#define MEMORY_OFFSET 0x60000
+
+struct mbxfb_info {
+ struct device *dev;
+
+ struct resource *fb_res;
+ struct resource *fb_req;
+
+ struct resource *reg_res;
+ struct resource *reg_req;
+
+ void __iomem *fb_virt_addr;
+ unsigned long fb_phys_addr;
+
+ void __iomem *reg_virt_addr;
+ unsigned long reg_phys_addr;
+
+ int (*platform_probe) (struct fb_info * fb);
+ int (*platform_remove) (struct fb_info * fb);
+
+ u32 pseudo_palette[MAX_PALETTES];
+#ifdef CONFIG_FB_MBX_DEBUG
+ void *debugfs_data;
+#endif
+
+};
+
+static struct fb_var_screeninfo mbxfb_default __devinitdata = {
+ .xres = 640,
+ .yres = 480,
+ .xres_virtual = 640,
+ .yres_virtual = 480,
+ .bits_per_pixel = 16,
+ .red = {11, 5, 0},
+ .green = {5, 6, 0},
+ .blue = {0, 5, 0},
+ .activate = FB_ACTIVATE_TEST,
+ .height = -1,
+ .width = -1,
+ .pixclock = 40000,
+ .left_margin = 48,
+ .right_margin = 16,
+ .upper_margin = 33,
+ .lower_margin = 10,
+ .hsync_len = 96,
+ .vsync_len = 2,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct fb_fix_screeninfo mbxfb_fix __devinitdata = {
+ .id = "MBX",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+struct pixclock_div {
+ u8 m;
+ u8 n;
+ u8 p;
+};
+
+static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
+ struct pixclock_div *div)
+{
+ u8 m, n, p;
+ unsigned int err = 0;
+ unsigned int min_err = ~0x0;
+ unsigned int clk;
+ unsigned int best_clk = 0;
+ unsigned int ref_clk = 13000; /* FIXME: take from platform data */
+ unsigned int pixclock;
+
+ /* convert pixclock to KHz */
+ pixclock = PICOS2KHZ(pixclock_ps);
+
+ for (m = 1; m < 64; m++) {
+ for (n = 1; n < 8; n++) {
+ for (p = 0; p < 8; p++) {
+ clk = (ref_clk * m) / (n * (1 << p));
+ err = (clk > pixclock) ? (clk - pixclock) :
+ (pixclock - clk);
+ if (err < min_err) {
+ min_err = err;
+ best_clk = clk;
+ div->m = m;
+ div->n = n;
+ div->p = p;
+ }
+ }
+ }
+ }
+ return KHZ2PICOS(best_clk);
+}
+
+static int mbxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int trans, struct fb_info *info)
+{
+ u32 val, ret = 1;
+
+ if (regno < MAX_PALETTES) {
+ u32 *pal = info->pseudo_palette;
+
+ val = (red & 0xf800) | ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ pal[regno] = val;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int mbxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct pixclock_div div;
+
+ var->pixclock = mbxfb_get_pixclock(var->pixclock, &div);
+
+ if (var->xres < MIN_XRES)
+ var->xres = MIN_XRES;
+ if (var->yres < MIN_YRES)
+ var->yres = MIN_YRES;
+ if (var->xres > MAX_XRES)
+ return -EINVAL;
+ if (var->yres > MAX_YRES)
+ return -EINVAL;
+ var->xres_virtual = max(var->xres_virtual, var->xres);
+ var->yres_virtual = max(var->yres_virtual, var->yres);
+
+ switch (var->bits_per_pixel) {
+ /* 8 bits-per-pixel is not supported yet */
+ case 8:
+ return -EINVAL;
+ case 16:
+ var->green.length = (var->green.length == 5) ? 5 : 6;
+ var->red.length = 5;
+ var->blue.length = 5;
+ var->transp.length = 6 - var->green.length;
+ var->blue.offset = 0;
+ var->green.offset = 5;
+ var->red.offset = 5 + var->green.length;
+ var->transp.offset = (5 + var->red.offset) & 15;
+ break;
+ case 24: /* RGB 888 */
+ case 32: /* RGBA 8888 */
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.length = var->bits_per_pixel - 24;
+ var->transp.offset = (var->transp.length) ? 24 : 0;
+ break;
+ }
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+
+ return 0;
+}
+
+static int mbxfb_set_par(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct pixclock_div div;
+ ushort hbps, ht, hfps, has;
+ ushort vbps, vt, vfps, vas;
+ u32 gsctrl = readl(GSCTRL);
+ u32 gsadr = readl(GSADR);
+
+ info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+ /* setup color mode */
+ gsctrl &= ~(FMsk(GSCTRL_GPIXFMT));
+ /* FIXME: add *WORKING* support for 8-bits per color */
+ if (info->var.bits_per_pixel == 8) {
+ return -EINVAL;
+ } else {
+ fb_dealloc_cmap(&info->cmap);
+ gsctrl &= ~GSCTRL_LUT_EN;
+
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ if (info->var.green.length == 5)
+ gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
+ else
+ gsctrl |= GSCTRL_GPIXFMT_RGB565;
+ break;
+ case 24:
+ gsctrl |= GSCTRL_GPIXFMT_RGB888;
+ break;
+ case 32:
+ gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
+ break;
+ }
+ }
+
+ /* setup resolution */
+ gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
+ gsctrl |= Gsctrl_Width(info->var.xres - 1) |
+ Gsctrl_Height(info->var.yres - 1);
+ writel(gsctrl, GSCTRL);
+ udelay(1000);
+
+ gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
+ gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
+ (8 * 16) - 1);
+ writel(gsadr, GSADR);
+ udelay(1000);
+
+ /* setup timings */
+ var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
+
+ writel((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
+ Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
+
+ hbps = var->hsync_len;
+ has = hbps + var->left_margin;
+ hfps = has + var->xres;
+ ht = hfps + var->right_margin;
+
+ vbps = var->vsync_len;
+ vas = vbps + var->upper_margin;
+ vfps = vas + var->yres;
+ vt = vfps + var->lower_margin;
+
+ writel((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
+ writel((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
+ writel((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
+ writel((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
+
+ writel((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
+ writel((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
+ writel((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
+ writel((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
+ writel((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
+
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+
+ return 0;
+}
+
+static int mbxfb_blank(int blank, struct fb_info *info)
+{
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ writel((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
+ udelay(1000);
+ writel((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
+ udelay(1000);
+ writel((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
+ udelay(1000);
+ break;
+ case FB_BLANK_UNBLANK:
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ udelay(1000);
+ writel((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
+ udelay(1000);
+ break;
+ }
+ return 0;
+}
+
+static struct fb_ops mbxfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = mbxfb_check_var,
+ .fb_set_par = mbxfb_set_par,
+ .fb_setcolreg = mbxfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = mbxfb_blank,
+};
+
+/*
+ Enable external SDRAM controller. Assume that all clocks are active
+ by now.
+*/
+static void __devinit setup_memc(struct fb_info *fbi)
+{
+ struct mbxfb_info *mfbi = fbi->par;
+ unsigned long tmp;
+ int i;
+
+ /* FIXME: use platfrom specific parameters */
+ /* setup SDRAM controller */
+ writel((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
+ LMCFG_LMA_TS),
+ LMCFG);
+ udelay(1000);
+
+ writel(LMPWR_MC_PWR_ACT, LMPWR);
+ udelay(1000);
+
+ /* setup SDRAM timings */
+ writel((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
+ Lmtim_Trc(9) | Lmtim_Tdpl(2)),
+ LMTIM);
+ udelay(1000);
+ /* setup SDRAM refresh rate */
+ writel(0xc2b, LMREFRESH);
+ udelay(1000);
+ /* setup SDRAM type parameters */
+ writel((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
+ LMTYPE_COLSZ_8),
+ LMTYPE);
+ udelay(1000);
+ /* enable memory controller */
+ writel(LMPWR_MC_PWR_ACT, LMPWR);
+ udelay(1000);
+
+ /* perform dummy reads */
+ for ( i = 0; i < 16; i++ ) {
+ tmp = readl(fbi->screen_base);
+ }
+}
+
+static void enable_clocks(struct fb_info *fbi)
+{
+ /* enable clocks */
+ writel(SYSCLKSRC_PLL_2, SYSCLKSRC);
+ udelay(1000);
+ writel(PIXCLKSRC_PLL_1, PIXCLKSRC);
+ udelay(1000);
+ writel(0x00000000, CLKSLEEP);
+ udelay(1000);
+ writel((Core_Pll_M(0x17) | Core_Pll_N(0x3) | Core_Pll_P(0x0) |
+ CORE_PLL_EN),
+ COREPLL);
+ udelay(1000);
+ writel((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
+ DISP_PLL_EN),
+ DISPPLL);
+
+ writel(0x00000000, VOVRCLK);
+ udelay(1000);
+ writel(PIXCLK_EN, PIXCLK);
+ udelay(1000);
+ writel(MEMCLK_EN, MEMCLK);
+ udelay(1000);
+ writel(0x00000006, M24CLK);
+ udelay(1000);
+ writel(0x00000006, MBXCLK);
+ udelay(1000);
+ writel(SDCLK_EN, SDCLK);
+ udelay(1000);
+ writel(0x00000001, PIXCLKDIV);
+ udelay(1000);
+}
+
+static void __devinit setup_graphics(struct fb_info *fbi)
+{
+ unsigned long gsctrl;
+
+ gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres - 1) |
+ Gsctrl_Height(fbi->var.yres - 1);
+ switch (fbi->var.bits_per_pixel) {
+ case 16:
+ if (fbi->var.green.length == 5)
+ gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
+ else
+ gsctrl |= GSCTRL_GPIXFMT_RGB565;
+ break;
+ case 24:
+ gsctrl |= GSCTRL_GPIXFMT_RGB888;
+ break;
+ case 32:
+ gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
+ break;
+ }
+
+ writel(gsctrl, GSCTRL);
+ udelay(1000);
+ writel(0x00000000, GBBASE);
+ udelay(1000);
+ writel(0x00ffffff, GDRCTRL);
+ udelay(1000);
+ writel((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
+ udelay(1000);
+ writel(0x00000000, GPLUT);
+ udelay(1000);
+}
+
+static void __devinit setup_display(struct fb_info *fbi)
+{
+ unsigned long dsctrl = 0;
+
+ dsctrl = DSCTRL_BLNK_POL;
+ if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ dsctrl |= DSCTRL_HS_POL;
+ if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ dsctrl |= DSCTRL_VS_POL;
+ writel(dsctrl, DSCTRL);
+ udelay(1000);
+ writel(0xd0303010, DMCTRL);
+ udelay(1000);
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+}
+
+static void __devinit enable_controller(struct fb_info *fbi)
+{
+ writel(SYSRST_RST, SYSRST);
+ udelay(1000);
+
+
+ enable_clocks(fbi);
+ setup_memc(fbi);
+ setup_graphics(fbi);
+ setup_display(fbi);
+}
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ /* make frame buffer memory enter self-refresh mode */
+ writel(LMPWR_MC_PWR_SRM, LMPWR);
+ while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM)
+ ; /* empty statement */
+
+ /* reset the device, since it's initial state is 'mostly sleeping' */
+ writel(SYSRST_RST, SYSRST);
+ return 0;
+}
+
+static int mbxfb_resume(struct platform_device *dev)
+{
+ struct fb_info *fbi = platform_get_drvdata(dev);
+
+ enable_clocks(fbi);
+/* setup_graphics(fbi); */
+/* setup_display(fbi); */
+
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ return 0;
+}
+#else
+#define mbxfb_suspend NULL
+#define mbxfb_resume NULL
+#endif
+
+/* debugfs entries */
+#ifndef CONFIG_FB_MBX_DEBUG
+#define mbxfb_debugfs_init(x) do {} while(0)
+#define mbxfb_debugfs_remove(x) do {} while(0)
+#endif
+
+#define res_size(_r) (((_r)->end - (_r)->start) + 1)
+
+static int __devinit mbxfb_probe(struct platform_device *dev)
+{
+ int ret;
+ struct fb_info *fbi;
+ struct mbxfb_info *mfbi;
+ struct mbxfb_platform_data *pdata;
+
+ dev_dbg(dev, "mbxfb_probe\n");
+
+ fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
+ if (fbi == NULL) {
+ dev_err(&dev->dev, "framebuffer_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ mfbi = fbi->par;
+ fbi->pseudo_palette = mfbi->pseudo_palette;
+ pdata = dev->dev.platform_data;
+ if (pdata->probe)
+ mfbi->platform_probe = pdata->probe;
+ if (pdata->remove)
+ mfbi->platform_remove = pdata->remove;
+
+ mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+
+ if (!mfbi->fb_res || !mfbi->reg_res) {
+ dev_err(&dev->dev, "no resources found\n");
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ mfbi->fb_req = request_mem_region(mfbi->fb_res->start,
+ res_size(mfbi->fb_res), dev->name);
+ if (mfbi->fb_req == NULL) {
+ dev_err(&dev->dev, "failed to claim framebuffer memory\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+ mfbi->fb_phys_addr = mfbi->fb_res->start;
+
+ mfbi->reg_req = request_mem_region(mfbi->reg_res->start,
+ res_size(mfbi->reg_res), dev->name);
+ if (mfbi->reg_req == NULL) {
+ dev_err(&dev->dev, "failed to claim Marathon registers\n");
+ ret = -EINVAL;
+ goto err2;
+ }
+ mfbi->reg_phys_addr = mfbi->reg_res->start;
+
+ mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr,
+ res_size(mfbi->reg_req));
+ if (!mfbi->reg_virt_addr) {
+ dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
+ ret = -EINVAL;
+ goto err3;
+ }
+ virt_base_2700 = (unsigned long)mfbi->reg_virt_addr;
+
+ mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
+ res_size(mfbi->fb_req));
+ if (!mfbi->reg_virt_addr) {
+ dev_err(&dev->dev, "failed to ioremap frame buffer\n");
+ ret = -EINVAL;
+ goto err4;
+ }
+
+ /* FIXME: get from platform */
+ fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
+ fbi->screen_size = 8 * 1024 * 1024; /* 8 Megs */
+ fbi->fbops = &mbxfb_ops;
+
+ fbi->var = mbxfb_default;
+ fbi->fix = mbxfb_fix;
+ fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
+ fbi->fix.smem_len = 8 * 1024 * 1024;
+ fbi->fix.line_length = 640 * 2;
+
+ ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+ if (ret < 0) {
+ dev_err(&dev->dev, "fb_alloc_cmap failed\n");
+ ret = -EINVAL;
+ goto err5;
+ }
+
+ platform_set_drvdata(dev, fbi);
+
+ printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node);
+
+ if (mfbi->platform_probe)
+ mfbi->platform_probe(fbi);
+
+ enable_controller(fbi);
+
+ mbxfb_debugfs_init(fbi);
+
+ ret = register_framebuffer(fbi);
+ if (ret < 0) {
+ dev_err(&dev->dev, "register_framebuffer failed\n");
+ ret = -EINVAL;
+ goto err6;
+ }
+
+ return 0;
+
+err6:
+ fb_dealloc_cmap(&fbi->cmap);
+err5:
+ iounmap(mfbi->fb_virt_addr);
+err4:
+ iounmap(mfbi->reg_virt_addr);
+err3:
+ release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
+err2:
+ release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res));
+err1:
+ framebuffer_release(fbi);
+
+ return ret;
+}
+
+static int __devexit mbxfb_remove(struct platform_device *dev)
+{
+ struct fb_info *fbi = platform_get_drvdata(dev);
+
+ writel(SYSRST_RST, SYSRST);
+ udelay(1000);
+
+ mbxfb_debugfs_remove(fbi);
+
+ if (fbi) {
+ struct mbxfb_info *mfbi = fbi->par;
+
+ unregister_framebuffer(fbi);
+ if (mfbi) {
+ if (mfbi->platform_remove)
+ mfbi->platform_remove(fbi);
+
+ if (mfbi->fb_virt_addr)
+ iounmap(mfbi->fb_virt_addr);
+ if (mfbi->reg_virt_addr)
+ iounmap(mfbi->reg_virt_addr);
+ if (mfbi->reg_req)
+ release_mem_region(mfbi->reg_req->start,
+ res_size(mfbi->reg_req));
+ if (mfbi->fb_req)
+ release_mem_region(mfbi->fb_req->start,
+ res_size(mfbi->fb_req));
+ }
+ framebuffer_release(fbi);
+ }
+
+ return 0;
+}
+
+static struct platform_driver mbxfb_driver = {
+ .probe = mbxfb_probe,
+ .remove = mbxfb_remove,
+ .suspend = mbxfb_suspend,
+ .resume = mbxfb_resume,
+ .driver = {
+ .name = "mbx-fb",
+ },
+};
+
+int __devinit mbxfb_init(void)
+{
+ return platform_driver_register(&mbxfb_driver);
+}
+
+static void __devexit mbxfb_exit(void)
+{
+ platform_driver_unregister(&mbxfb_driver);
+}
+
+module_init(mbxfb_init);
+module_exit(mbxfb_exit);
+
+MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
+MODULE_AUTHOR("Mike Rapoport, Compulab");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mbx/reg_bits.h b/drivers/video/mbx/reg_bits.h
new file mode 100644
index 00000000000..c226a8e4531
--- /dev/null
+++ b/drivers/video/mbx/reg_bits.h
@@ -0,0 +1,418 @@
+#ifndef __REG_BITS_2700G_
+#define __REG_BITS_2700G_
+
+/* use defines from asm-arm/arch-pxa/bitfields.h for bit fields access */
+#define UData(Data) ((unsigned long) (Data))
+#define Fld(Size, Shft) (((Size) << 16) + (Shft))
+#define FSize(Field) ((Field) >> 16)
+#define FShft(Field) ((Field) & 0x0000FFFF)
+#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field))
+#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1)
+#define F1stBit(Field) (UData (1) << FShft (Field))
+
+#define SYSRST_RST (1 << 0)
+
+/* SYSCLKSRC - SYSCLK Source Control Register */
+#define SYSCLKSRC_SEL Fld(2,0)
+#define SYSCLKSRC_REF ((0x0) << FShft(SYSCLKSRC_SEL))
+#define SYSCLKSRC_PLL_1 ((0x1) << FShft(SYSCLKSRC_SEL))
+#define SYSCLKSRC_PLL_2 ((0x2) << FShft(SYSCLKSRC_SEL))
+
+/* PIXCLKSRC - PIXCLK Source Control Register */
+#define PIXCLKSRC_SEL Fld(2,0)
+#define PIXCLKSRC_REF ((0x0) << FShft(PIXCLKSRC_SEL))
+#define PIXCLKSRC_PLL_1 ((0x1) << FShft(PIXCLKSRC_SEL))
+#define PIXCLKSRC_PLL_2 ((0x2) << FShft(PIXCLKSRC_SEL))
+
+/* Clock Disable Register */
+#define CLKSLEEP_SLP (1 << 0)
+
+/* Core PLL Control Register */
+#define CORE_PLL_M Fld(6,7)
+#define Core_Pll_M(x) ((x) << FShft(CORE_PLL_M))
+#define CORE_PLL_N Fld(3,4)
+#define Core_Pll_N(x) ((x) << FShft(CORE_PLL_N))
+#define CORE_PLL_P Fld(3,1)
+#define Core_Pll_P(x) ((x) << FShft(CORE_PLL_P))
+#define CORE_PLL_EN (1 << 0)
+
+/* Display PLL Control Register */
+#define DISP_PLL_M Fld(6,7)
+#define Disp_Pll_M(x) ((x) << FShft(DISP_PLL_M))
+#define DISP_PLL_N Fld(3,4)
+#define Disp_Pll_N(x) ((x) << FShft(DISP_PLL_N))
+#define DISP_PLL_P Fld(3,1)
+#define Disp_Pll_P(x) ((x) << FShft(DISP_PLL_P))
+#define DISP_PLL_EN (1 << 0)
+
+/* PLL status register */
+#define PLLSTAT_CORE_PLL_LOST_L (1 << 3)
+#define PLLSTAT_CORE_PLL_LSTS (1 << 2)
+#define PLLSTAT_DISP_PLL_LOST_L (1 << 1)
+#define PLLSTAT_DISP_PLL_LSTS (1 << 0)
+
+/* Video and scale clock control register */
+#define VOVRCLK_EN (1 << 0)
+
+/* Pixel clock control register */
+#define PIXCLK_EN (1 << 0)
+
+/* Memory clock control register */
+#define MEMCLK_EN (1 << 0)
+
+/* MBX clock control register */
+#define MBXCLK_DIV Fld(2,2)
+#define MBXCLK_DIV_1 ((0x0) << FShft(MBXCLK_DIV))
+#define MBXCLK_DIV_2 ((0x1) << FShft(MBXCLK_DIV))
+#define MBXCLK_DIV_3 ((0x2) << FShft(MBXCLK_DIV))
+#define MBXCLK_DIV_4 ((0x3) << FShft(MBXCLK_DIV))
+#define MBXCLK_EN Fld(2,0)
+#define MBXCLK_EN_NONE ((0x0) << FShft(MBXCLK_EN))
+#define MBXCLK_EN_2D ((0x1) << FShft(MBXCLK_EN))
+#define MBXCLK_EN_BOTH ((0x2) << FShft(MBXCLK_EN))
+
+/* M24 clock control register */
+#define M24CLK_DIV Fld(2,1)
+#define M24CLK_DIV_1 ((0x0) << FShft(M24CLK_DIV))
+#define M24CLK_DIV_2 ((0x1) << FShft(M24CLK_DIV))
+#define M24CLK_DIV_3 ((0x2) << FShft(M24CLK_DIV))
+#define M24CLK_DIV_4 ((0x3) << FShft(M24CLK_DIV))
+#define M24CLK_EN (1 << 0)
+
+/* SDRAM clock control register */
+#define SDCLK_EN (1 << 0)
+
+/* PixClk Divisor Register */
+#define PIXCLKDIV_PD Fld(9,0)
+#define Pixclkdiv_Pd(x) ((x) << FShft(PIXCLKDIV_PD))
+
+/* LCD Config control register */
+#define LCDCFG_IN_FMT Fld(3,28)
+#define Lcdcfg_In_Fmt(x) ((x) << FShft(LCDCFG_IN_FMT))
+#define LCDCFG_LCD1DEN_POL (1 << 27)
+#define LCDCFG_LCD1FCLK_POL (1 << 26)
+#define LCDCFG_LCD1LCLK_POL (1 << 25)
+#define LCDCFG_LCD1D_POL (1 << 24)
+#define LCDCFG_LCD2DEN_POL (1 << 23)
+#define LCDCFG_LCD2FCLK_POL (1 << 22)
+#define LCDCFG_LCD2LCLK_POL (1 << 21)
+#define LCDCFG_LCD2D_POL (1 << 20)
+#define LCDCFG_LCD1_TS (1 << 19)
+#define LCDCFG_LCD1D_DS (1 << 18)
+#define LCDCFG_LCD1C_DS (1 << 17)
+#define LCDCFG_LCD1_IS_IN (1 << 16)
+#define LCDCFG_LCD2_TS (1 << 3)
+#define LCDCFG_LCD2D_DS (1 << 2)
+#define LCDCFG_LCD2C_DS (1 << 1)
+#define LCDCFG_LCD2_IS_IN (1 << 0)
+
+/* On-Die Frame Buffer Power Control Register */
+#define ODFBPWR_SLOW (1 << 2)
+#define ODFBPWR_MODE Fld(2,0)
+#define ODFBPWR_MODE_ACT ((0x0) << FShft(ODFBPWR_MODE))
+#define ODFBPWR_MODE_ACT_LP ((0x1) << FShft(ODFBPWR_MODE))
+#define ODFBPWR_MODE_SLEEP ((0x2) << FShft(ODFBPWR_MODE))
+#define ODFBPWR_MODE_SHUTD ((0x3) << FShft(ODFBPWR_MODE))
+
+/* On-Die Frame Buffer Power State Status Register */
+#define ODFBSTAT_ACT (1 << 2)
+#define ODFBSTAT_SLP (1 << 1)
+#define ODFBSTAT_SDN (1 << 0)
+
+/* LMRST - Local Memory (SDRAM) Reset */
+#define LMRST_MC_RST (1 << 0)
+
+/* LMCFG - Local Memory (SDRAM) Configuration Register */
+#define LMCFG_LMC_DS (1 << 5)
+#define LMCFG_LMD_DS (1 << 4)
+#define LMCFG_LMA_DS (1 << 3)
+#define LMCFG_LMC_TS (1 << 2)
+#define LMCFG_LMD_TS (1 << 1)
+#define LMCFG_LMA_TS (1 << 0)
+
+/* LMPWR - Local Memory (SDRAM) Power Control Register */
+#define LMPWR_MC_PWR_CNT Fld(2,0)
+#define LMPWR_MC_PWR_ACT ((0x0) << FShft(LMPWR_MC_PWR_CNT)) /* Active */
+#define LMPWR_MC_PWR_SRM ((0x1) << FShft(LMPWR_MC_PWR_CNT)) /* Self-refresh */
+#define LMPWR_MC_PWR_DPD ((0x3) << FShft(LMPWR_MC_PWR_CNT)) /* deep power down */
+
+/* LMPWRSTAT - Local Memory (SDRAM) Power Status Register */
+#define LMPWRSTAT_MC_PWR_CNT Fld(2,0)
+#define LMPWRSTAT_MC_PWR_ACT ((0x0) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* Active */
+#define LMPWRSTAT_MC_PWR_SRM ((0x1) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* Self-refresh */
+#define LMPWRSTAT_MC_PWR_DPD ((0x3) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* deep power down */
+
+/* LMTYPE - Local Memory (SDRAM) Type Register */
+#define LMTYPE_CASLAT Fld(3,10)
+#define LMTYPE_CASLAT_1 ((0x1) << FShft(LMTYPE_CASLAT))
+#define LMTYPE_CASLAT_2 ((0x2) << FShft(LMTYPE_CASLAT))
+#define LMTYPE_CASLAT_3 ((0x3) << FShft(LMTYPE_CASLAT))
+#define LMTYPE_BKSZ Fld(2,8)
+#define LMTYPE_BKSZ_1 ((0x1) << FShft(LMTYPE_BKSZ))
+#define LMTYPE_BKSZ_2 ((0x2) << FShft(LMTYPE_BKSZ))
+#define LMTYPE_ROWSZ Fld(4,4)
+#define LMTYPE_ROWSZ_11 ((0xb) << FShft(LMTYPE_ROWSZ))
+#define LMTYPE_ROWSZ_12 ((0xc) << FShft(LMTYPE_ROWSZ))
+#define LMTYPE_ROWSZ_13 ((0xd) << FShft(LMTYPE_ROWSZ))
+#define LMTYPE_COLSZ Fld(4,0)
+#define LMTYPE_COLSZ_7 ((0x7) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_8 ((0x8) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_9 ((0x9) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_10 ((0xa) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_11 ((0xb) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_12 ((0xc) << FShft(LMTYPE_COLSZ))
+
+/* LMTIM - Local Memory (SDRAM) Timing Register */
+#define LMTIM_TRAS Fld(4,16)
+#define Lmtim_Tras(x) ((x) << FShft(LMTIM_TRAS))
+#define LMTIM_TRP Fld(4,12)
+#define Lmtim_Trp(x) ((x) << FShft(LMTIM_TRP))
+#define LMTIM_TRCD Fld(4,8)
+#define Lmtim_Trcd(x) ((x) << FShft(LMTIM_TRCD))
+#define LMTIM_TRC Fld(4,4)
+#define Lmtim_Trc(x) ((x) << FShft(LMTIM_TRC))
+#define LMTIM_TDPL Fld(4,0)
+#define Lmtim_Tdpl(x) ((x) << FShft(LMTIM_TDPL))
+
+/* LMREFRESH - Local Memory (SDRAM) tREF Control Register */
+#define LMREFRESH_TREF Fld(2,0)
+#define Lmrefresh_Tref(x) ((x) << FShft(LMREFRESH_TREF))
+
+/* GSCTRL - Graphics surface control register */
+#define GSCTRL_LUT_EN (1 << 31)
+#define GSCTRL_GPIXFMT Fld(4,27)
+#define GSCTRL_GPIXFMT_INDEXED ((0x0) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_ARGB4444 ((0x4) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_ARGB1555 ((0x5) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_RGB888 ((0x6) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_RGB565 ((0x7) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_ARGB8888 ((0x8) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GAMMA_EN (1 << 26)
+
+#define GSCTRL_GSWIDTH Fld(11,11)
+#define Gsctrl_Width(Pixel) /* Display Width [1..2048 pix.] */ \
+ (((Pixel) - 1) << FShft(GSCTRL_GSWIDTH))
+
+#define GSCTRL_GSHEIGHT Fld(11,0)
+#define Gsctrl_Height(Pixel) /* Display Height [1..2048 pix.] */ \
+ (((Pixel) - 1) << FShft(GSCTRL_GSHEIGHT))
+
+/* GBBASE fileds */
+#define GBBASE_GLALPHA Fld(8,24)
+#define Gbbase_Glalpha(x) ((x) << FShft(GBBASE_GLALPHA))
+
+#define GBBASE_COLKEY Fld(24,0)
+#define Gbbase_Colkey(x) ((x) << FShft(GBBASE_COLKEY))
+
+/* GDRCTRL fields */
+#define GDRCTRL_PIXDBL (1 << 31)
+#define GDRCTRL_PIXHLV (1 << 30)
+#define GDRCTRL_LNDBL (1 << 29)
+#define GDRCTRL_LNHLV (1 << 28)
+#define GDRCTRL_COLKEYM Fld(24,0)
+#define Gdrctrl_Colkeym(x) ((x) << FShft(GDRCTRL_COLKEYM))
+
+/* GSCADR graphics stream control address register fields */
+#define GSCADR_STR_EN (1 << 31)
+#define GSCADR_COLKEY_EN (1 << 30)
+#define GSCADR_COLKEYSCR (1 << 29)
+#define GSCADR_BLEND_M Fld(2,27)
+#define GSCADR_BLEND_NONE ((0x0) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_INV ((0x1) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_GLOB ((0x2) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_PIX ((0x3) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_POS Fld(2,24)
+#define GSCADR_BLEND_GFX ((0x0) << FShft(GSCADR_BLEND_POS))
+#define GSCADR_BLEND_VID ((0x1) << FShft(GSCADR_BLEND_POS))
+#define GSCADR_BLEND_CUR ((0x2) << FShft(GSCADR_BLEND_POS))
+#define GSCADR_GBASE_ADR Fld(23,0)
+#define Gscadr_Gbase_Adr(x) ((x) << FShft(GSCADR_GBASE_ADR))
+
+/* GSADR graphics stride address register fields */
+#define GSADR_SRCSTRIDE Fld(10,22)
+#define Gsadr_Srcstride(x) ((x) << FShft(GSADR_SRCSTRIDE))
+#define GSADR_XSTART Fld(11,11)
+#define Gsadr_Xstart(x) ((x) << FShft(GSADR_XSTART))
+#define GSADR_YSTART Fld(11,0)
+#define Gsadr_Ystart(y) ((y) << FShft(GSADR_YSTART))
+
+/* GPLUT graphics palette register fields */
+#define GPLUT_LUTADR Fld(8,24)
+#define Gplut_Lutadr(x) ((x) << FShft(GPLUT_LUTADR))
+#define GPLUT_LUTDATA Fld(24,0)
+#define Gplut_Lutdata(x) ((x) << FShft(GPLUT_LUTDATA))
+
+/* HCCTRL - Hardware Cursor Register fields */
+#define HCCTRL_CUR_EN (1 << 31)
+#define HCCTRL_COLKEY_EN (1 << 29)
+#define HCCTRL_COLKEYSRC (1 << 28)
+#define HCCTRL_BLEND_M Fld(2,26)
+#define HCCTRL_BLEND_NONE ((0x0) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_BLEND_INV ((0x1) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_BLEND_GLOB ((0x2) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_BLEND_PIX ((0x3) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_CPIXFMT Fld(3,23)
+#define HCCTRL_CPIXFMT_RGB332 ((0x3) << FShft(HCCTRL_CPIXFMT))
+#define HCCTRL_CPIXFMT_ARGB4444 ((0x4) << FShft(HCCTRL_CPIXFMT))
+#define HCCTRL_CPIXFMT_ARGB1555 ((0x5) << FShft(HCCTRL_CPIXFMT))
+#define HCCTRL_CBASE_ADR Fld(23,0)
+#define Hcctrl_Cbase_Adr(x) ((x) << FShft(HCCTRL_CBASE_ADR))
+
+/* HCSIZE Hardware Cursor Size Register fields */
+#define HCSIZE_BLEND_POS Fld(2,29)
+#define HCSIZE_BLEND_GFX ((0x0) << FShft(HCSIZE_BLEND_POS))
+#define HCSIZE_BLEND_VID ((0x1) << FShft(HCSIZE_BLEND_POS))
+#define HCSIZE_BLEND_CUR ((0x2) << FShft(HCSIZE_BLEND_POS))
+#define HCSIZE_CWIDTH Fld(3,16)
+#define Hcsize_Cwidth(x) ((x) << FShft(HCSIZE_CWIDTH))
+#define HCSIZE_CHEIGHT Fld(3,0)
+#define Hcsize_Cheight(x) ((x) << FShft(HCSIZE_CHEIGHT))
+
+/* HCPOS Hardware Cursor Position Register fields */
+#define HCPOS_SWITCHSRC (1 << 30)
+#define HCPOS_CURBLINK Fld(6,24)
+#define Hcpos_Curblink(x) ((x) << FShft(HCPOS_CURBLINK))
+#define HCPOS_XSTART Fld(12,12)
+#define Hcpos_Xstart(x) ((x) << FShft(HCPOS_XSTART))
+#define HCPOS_YSTART Fld(12,0)
+#define Hcpos_Ystart(y) ((y) << FShft(HCPOS_YSTART))
+
+/* HCBADR Hardware Cursor Blend Address Register */
+#define HCBADR_GLALPHA Fld(8,24)
+#define Hcbadr_Glalpha(x) ((x) << FShft(HCBADR_GLALPHA))
+#define HCBADR_COLKEY Fld(24,0)
+#define Hcbadr_Colkey(x) ((x) << FShft(HCBADR_COLKEY))
+
+/* HCCKMSK - Hardware Cursor Color Key Mask Register */
+#define HCCKMSK_COLKEY_M Fld(24,0)
+#define Hcckmsk_Colkey_M(x) ((x) << FShft(HCCKMSK_COLKEY_M))
+
+/* DSCTRL - Display sync control register */
+#define DSCTRL_SYNCGEN_EN (1 << 31)
+#define DSCTRL_DPL_RST (1 << 29)
+#define DSCTRL_PWRDN_M (1 << 28)
+#define DSCTRL_UPDSYNCCNT (1 << 26)
+#define DSCTRL_UPDINTCNT (1 << 25)
+#define DSCTRL_UPDCNT (1 << 24)
+#define DSCTRL_UPDWAIT Fld(4,16)
+#define Dsctrl_Updwait(x) ((x) << FShft(DSCTRL_UPDWAIT))
+#define DSCTRL_CLKPOL (1 << 11)
+#define DSCTRL_CSYNC_EN (1 << 10)
+#define DSCTRL_VS_SLAVE (1 << 7)
+#define DSCTRL_HS_SLAVE (1 << 6)
+#define DSCTRL_BLNK_POL (1 << 5)
+#define DSCTRL_BLNK_DIS (1 << 4)
+#define DSCTRL_VS_POL (1 << 3)
+#define DSCTRL_VS_DIS (1 << 2)
+#define DSCTRL_HS_POL (1 << 1)
+#define DSCTRL_HS_DIS (1 << 0)
+
+/* DHT01 - Display horizontal timing register 01 */
+#define DHT01_HBPS Fld(12,16)
+#define Dht01_Hbps(x) ((x) << FShft(DHT01_HBPS))
+#define DHT01_HT Fld(12,0)
+#define Dht01_Ht(x) ((x) << FShft(DHT01_HT))
+
+/* DHT02 - Display horizontal timing register 02 */
+#define DHT02_HAS Fld(12,16)
+#define Dht02_Has(x) ((x) << FShft(DHT02_HAS))
+#define DHT02_HLBS Fld(12,0)
+#define Dht02_Hlbs(x) ((x) << FShft(DHT02_HLBS))
+
+/* DHT03 - Display horizontal timing register 03 */
+#define DHT03_HFPS Fld(12,16)
+#define Dht03_Hfps(x) ((x) << FShft(DHT03_HFPS))
+#define DHT03_HRBS Fld(12,0)
+#define Dht03_Hrbs(x) ((x) << FShft(DHT03_HRBS))
+
+/* DVT01 - Display vertical timing register 01 */
+#define DVT01_VBPS Fld(12,16)
+#define Dvt01_Vbps(x) ((x) << FShft(DVT01_VBPS))
+#define DVT01_VT Fld(12,0)
+#define Dvt01_Vt(x) ((x) << FShft(DVT01_VT))
+
+/* DVT02 - Display vertical timing register 02 */
+#define DVT02_VAS Fld(12,16)
+#define Dvt02_Vas(x) ((x) << FShft(DVT02_VAS))
+#define DVT02_VTBS Fld(12,0)
+#define Dvt02_Vtbs(x) ((x) << FShft(DVT02_VTBS))
+
+/* DVT03 - Display vertical timing register 03 */
+#define DVT03_VFPS Fld(12,16)
+#define Dvt03_Vfps(x) ((x) << FShft(DVT03_VFPS))
+#define DVT03_VBBS Fld(12,0)
+#define Dvt03_Vbbs(x) ((x) << FShft(DVT03_VBBS))
+
+/* DVECTRL - display vertical event control register */
+#define DVECTRL_VEVENT Fld(12,16)
+#define Dvectrl_Vevent(x) ((x) << FShft(DVECTRL_VEVENT))
+#define DVECTRL_VFETCH Fld(12,0)
+#define Dvectrl_Vfetch(x) ((x) << FShft(DVECTRL_VFETCH))
+
+/* DHDET - display horizontal DE timing register */
+#define DHDET_HDES Fld(12,16)
+#define Dhdet_Hdes(x) ((x) << FShft(DHDET_HDES))
+#define DHDET_HDEF Fld(12,0)
+#define Dhdet_Hdef(x) ((x) << FShft(DHDET_HDEF))
+
+/* DVDET - display vertical DE timing register */
+#define DVDET_VDES Fld(12,16)
+#define Dvdet_Vdes(x) ((x) << FShft(DVDET_VDES))
+#define DVDET_VDEF Fld(12,0)
+#define Dvdet_Vdef(x) ((x) << FShft(DVDET_VDEF))
+
+/* DODMSK - display output data mask register */
+#define DODMSK_MASK_LVL (1 << 31)
+#define DODMSK_BLNK_LVL (1 << 30)
+#define DODMSK_MASK_B Fld(8,16)
+#define Dodmsk_Mask_B(x) ((x) << FShft(DODMSK_MASK_B))
+#define DODMSK_MASK_G Fld(8,8)
+#define Dodmsk_Mask_G(x) ((x) << FShft(DODMSK_MASK_G))
+#define DODMSK_MASK_R Fld(8,0)
+#define Dodmsk_Mask_R(x) ((x) << FShft(DODMSK_MASK_R))
+
+/* DBCOL - display border color control register */
+#define DBCOL_BORDCOL Fld(24,0)
+#define Dbcol_Bordcol(x) ((x) << FShft(DBCOL_BORDCOL))
+
+/* DVLNUM - display vertical line number register */
+#define DVLNUM_VLINE Fld(12,0)
+#define Dvlnum_Vline(x) ((x) << FShft(DVLNUM_VLINE))
+
+/* DMCTRL - Display Memory Control Register */
+#define DMCTRL_MEM_REF Fld(2,30)
+#define DMCTRL_MEM_REF_ACT ((0x0) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_MEM_REF_HB ((0x1) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_MEM_REF_VB ((0x2) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_MEM_REF_BOTH ((0x3) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_UV_THRHLD Fld(6,24)
+#define Dmctrl_Uv_Thrhld(x) ((x) << FShft(DMCTRL_UV_THRHLD))
+#define DMCTRL_V_THRHLD Fld(7,16)
+#define Dmctrl_V_Thrhld(x) ((x) << FShft(DMCTRL_V_THRHLD))
+#define DMCTRL_D_THRHLD Fld(7,8)
+#define Dmctrl_D_Thrhld(x) ((x) << FShft(DMCTRL_D_THRHLD))
+#define DMCTRL_BURSTLEN Fld(6,0)
+#define Dmctrl_Burstlen(x) ((x) << FShft(DMCTRL_BURSTLEN))
+
+
+/* DLSTS - display load status register */
+#define DLSTS_RLD_ADONE (1 << 23)
+/* #define DLSTS_RLD_ADOUT Fld(23,0) */
+
+/* DLLCTRL - display list load control register */
+#define DLLCTRL_RLD_ADRLN Fld(8,24)
+#define Dllctrl_Rld_Adrln(x) ((x) << FShft(DLLCTRL_RLD_ADRLN))
+
+/* SPOCTRL - Scale Pitch/Order Control Register */
+#define SPOCTRL_H_SC_BP (1 << 31)
+#define SPOCTRL_V_SC_BP (1 << 30)
+#define SPOCTRL_HV_SC_OR (1 << 29)
+#define SPOCTRL_VS_UR_C (1 << 27)
+#define SPOCTRL_VORDER Fld(2,16)
+#define SPOCTRL_VORDER_1TAP ((0x0) << FShft(SPOCTRL_VORDER))
+#define SPOCTRL_VORDER_2TAP ((0x1) << FShft(SPOCTRL_VORDER))
+#define SPOCTRL_VORDER_4TAP ((0x3) << FShft(SPOCTRL_VORDER))
+#define SPOCTRL_VPITCH Fld(16,0)
+#define Spoctrl_Vpitch(x) ((x) << FShft(SPOCTRL_VPITCH))
+
+#endif /* __REG_BITS_2700G_ */
diff --git a/drivers/video/mbx/regs.h b/drivers/video/mbx/regs.h
new file mode 100644
index 00000000000..ad20be07666
--- /dev/null
+++ b/drivers/video/mbx/regs.h
@@ -0,0 +1,195 @@
+#ifndef __REGS_2700G_
+#define __REGS_2700G_
+
+/* extern unsigned long virt_base_2700; */
+/* #define __REG_2700G(x) (*(volatile unsigned long*)((x)+virt_base_2700)) */
+#define __REG_2700G(x) ((x)+virt_base_2700)
+
+/* System Configuration Registers (0x0000_0000 0x0000_0010) */
+#define SYSCFG __REG_2700G(0x00000000)
+#define PFBASE __REG_2700G(0x00000004)
+#define PFCEIL __REG_2700G(0x00000008)
+#define POLLFLAG __REG_2700G(0x0000000c)
+#define SYSRST __REG_2700G(0x00000010)
+
+/* Interrupt Control Registers (0x0000_0014 0x0000_002F) */
+#define NINTPW __REG_2700G(0x00000014)
+#define MINTENABLE __REG_2700G(0x00000018)
+#define MINTSTAT __REG_2700G(0x0000001c)
+#define SINTENABLE __REG_2700G(0x00000020)
+#define SINTSTAT __REG_2700G(0x00000024)
+#define SINTCLR __REG_2700G(0x00000028)
+
+/* Clock Control Registers (0x0000_002C 0x0000_005F) */
+#define SYSCLKSRC __REG_2700G(0x0000002c)
+#define PIXCLKSRC __REG_2700G(0x00000030)
+#define CLKSLEEP __REG_2700G(0x00000034)
+#define COREPLL __REG_2700G(0x00000038)
+#define DISPPLL __REG_2700G(0x0000003c)
+#define PLLSTAT __REG_2700G(0x00000040)
+#define VOVRCLK __REG_2700G(0x00000044)
+#define PIXCLK __REG_2700G(0x00000048)
+#define MEMCLK __REG_2700G(0x0000004c)
+#define M24CLK __REG_2700G(0x00000054)
+#define MBXCLK __REG_2700G(0x00000054)
+#define SDCLK __REG_2700G(0x00000058)
+#define PIXCLKDIV __REG_2700G(0x0000005c)
+
+/* LCD Port Control Register (0x0000_0060 0x0000_006F) */
+#define LCD_CONFIG __REG_2700G(0x00000060)
+
+/* On-Die Frame Buffer Registers (0x0000_0064 0x0000_006B) */
+#define ODFBPWR __REG_2700G(0x00000064)
+#define ODFBSTAT __REG_2700G(0x00000068)
+
+/* GPIO Registers (0x0000_006C 0x0000_007F) */
+#define GPIOCGF __REG_2700G(0x0000006c)
+#define GPIOHI __REG_2700G(0x00000070)
+#define GPIOLO __REG_2700G(0x00000074)
+#define GPIOSTAT __REG_2700G(0x00000078)
+
+/* Pulse Width Modulator (PWM) Registers (0x0000_0200 0x0000_02FF) */
+#define PWMRST __REG_2700G(0x00000200)
+#define PWMCFG __REG_2700G(0x00000204)
+#define PWM0DIV __REG_2700G(0x00000210)
+#define PWM0DUTY __REG_2700G(0x00000214)
+#define PWM0PER __REG_2700G(0x00000218)
+#define PWM1DIV __REG_2700G(0x00000220)
+#define PWM1DUTY __REG_2700G(0x00000224)
+#define PWM1PER __REG_2700G(0x00000228)
+
+/* Identification (ID) Registers (0x0000_0300 0x0000_0FFF) */
+#define ID __REG_2700G(0x00000FF0)
+
+/* Local Memory (SDRAM) Interface Registers (0x0000_1000 0x0000_1FFF) */
+#define LMRST __REG_2700G(0x00001000)
+#define LMCFG __REG_2700G(0x00001004)
+#define LMPWR __REG_2700G(0x00001008)
+#define LMPWRSTAT __REG_2700G(0x0000100c)
+#define LMCEMR __REG_2700G(0x00001010)
+#define LMTYPE __REG_2700G(0x00001014)
+#define LMTIM __REG_2700G(0x00001018)
+#define LMREFRESH __REG_2700G(0x0000101c)
+#define LMPROTMIN __REG_2700G(0x00001020)
+#define LMPROTMAX __REG_2700G(0x00001024)
+#define LMPROTCFG __REG_2700G(0x00001028)
+#define LMPROTERR __REG_2700G(0x0000102c)
+
+/* Plane Controller Registers (0x0000_2000 0x0000_2FFF) */
+#define GSCTRL __REG_2700G(0x00002000)
+#define VSCTRL __REG_2700G(0x00002004)
+#define GBBASE __REG_2700G(0x00002020)
+#define VBBASE __REG_2700G(0x00002024)
+#define GDRCTRL __REG_2700G(0x00002040)
+#define VCMSK __REG_2700G(0x00002044)
+#define GSCADR __REG_2700G(0x00002060)
+#define VSCADR __REG_2700G(0x00002064)
+#define VUBASE __REG_2700G(0x00002084)
+#define VVBASE __REG_2700G(0x000020a4)
+#define GSADR __REG_2700G(0x000020c0)
+#define VSADR __REG_2700G(0x000020c4)
+#define HCCTRL __REG_2700G(0x00002100)
+#define HCSIZE __REG_2700G(0x00002110)
+#define HCPOS __REG_2700G(0x00002120)
+#define HCBADR __REG_2700G(0x00002130)
+#define HCCKMSK __REG_2700G(0x00002140)
+#define GPLUT __REG_2700G(0x00002150)
+#define DSCTRL __REG_2700G(0x00002154)
+#define DHT01 __REG_2700G(0x00002158)
+#define DHT02 __REG_2700G(0x0000215c)
+#define DHT03 __REG_2700G(0x00002160)
+#define DVT01 __REG_2700G(0x00002164)
+#define DVT02 __REG_2700G(0x00002168)
+#define DVT03 __REG_2700G(0x0000216c)
+#define DBCOL __REG_2700G(0x00002170)
+#define BGCOLOR __REG_2700G(0x00002174)
+#define DINTRS __REG_2700G(0x00002178)
+#define DINTRE __REG_2700G(0x0000217c)
+#define DINTRCNT __REG_2700G(0x00002180)
+#define DSIG __REG_2700G(0x00002184)
+#define DMCTRL __REG_2700G(0x00002188)
+#define CLIPCTRL __REG_2700G(0x0000218c)
+#define SPOCTRL __REG_2700G(0x00002190)
+#define SVCTRL __REG_2700G(0x00002194)
+
+/* 0x0000_2198 */
+/* 0x0000_21A8 VSCOEFF[0:4] Video Scalar Vertical Coefficient [0:4] 4.14.5 */
+#define VSCOEFF0 __REG_2700G(0x00002198)
+#define VSCOEFF1 __REG_2700G(0x0000219c)
+#define VSCOEFF2 __REG_2700G(0x000021a0)
+#define VSCOEFF3 __REG_2700G(0x000021a4)
+#define VSCOEFF4 __REG_2700G(0x000021a8)
+
+#define SHCTRL __REG_2700G(0x000021b0)
+
+/* 0x0000_21B4 */
+/* 0x0000_21D4 HSCOEFF[0:8] Video Scalar Horizontal Coefficient [0:8] 4.14.7 */
+#define HSCOEFF0 __REG_2700G(0x000021b4)
+#define HSCOEFF1 __REG_2700G(0x000021b8)
+#define HSCOEFF2 __REG_2700G(0x000021bc)
+#define HSCOEFF3 __REG_2700G(0x000021b0)
+#define HSCOEFF4 __REG_2700G(0x000021c4)
+#define HSCOEFF5 __REG_2700G(0x000021c8)
+#define HSCOEFF6 __REG_2700G(0x000021cc)
+#define HSCOEFF7 __REG_2700G(0x000021d0)
+#define HSCOEFF8 __REG_2700G(0x000021d4)
+
+#define SSSIZE __REG_2700G(0x000021D8)
+
+/* 0x0000_2200 */
+/* 0x0000_2240 VIDGAM[0:16] Video Gamma LUT Index [0:16] 4.15.2 */
+#define VIDGAM0 __REG_2700G(0x00002200)
+#define VIDGAM1 __REG_2700G(0x00002204)
+#define VIDGAM2 __REG_2700G(0x00002208)
+#define VIDGAM3 __REG_2700G(0x0000220c)
+#define VIDGAM4 __REG_2700G(0x00002210)
+#define VIDGAM5 __REG_2700G(0x00002214)
+#define VIDGAM6 __REG_2700G(0x00002218)
+#define VIDGAM7 __REG_2700G(0x0000221c)
+#define VIDGAM8 __REG_2700G(0x00002220)
+#define VIDGAM9 __REG_2700G(0x00002224)
+#define VIDGAM10 __REG_2700G(0x00002228)
+#define VIDGAM11 __REG_2700G(0x0000222c)
+#define VIDGAM12 __REG_2700G(0x00002230)
+#define VIDGAM13 __REG_2700G(0x00002234)
+#define VIDGAM14 __REG_2700G(0x00002238)
+#define VIDGAM15 __REG_2700G(0x0000223c)
+#define VIDGAM16 __REG_2700G(0x00002240)
+
+/* 0x0000_2250 */
+/* 0x0000_2290 GFXGAM[0:16] Graphics Gamma LUT Index [0:16] 4.15.3 */
+#define GFXGAM0 __REG_2700G(0x00002250)
+#define GFXGAM1 __REG_2700G(0x00002254)
+#define GFXGAM2 __REG_2700G(0x00002258)
+#define GFXGAM3 __REG_2700G(0x0000225c)
+#define GFXGAM4 __REG_2700G(0x00002260)
+#define GFXGAM5 __REG_2700G(0x00002264)
+#define GFXGAM6 __REG_2700G(0x00002268)
+#define GFXGAM7 __REG_2700G(0x0000226c)
+#define GFXGAM8 __REG_2700G(0x00002270)
+#define GFXGAM9 __REG_2700G(0x00002274)
+#define GFXGAM10 __REG_2700G(0x00002278)
+#define GFXGAM11 __REG_2700G(0x0000227c)
+#define GFXGAM12 __REG_2700G(0x00002280)
+#define GFXGAM13 __REG_2700G(0x00002284)
+#define GFXGAM14 __REG_2700G(0x00002288)
+#define GFXGAM15 __REG_2700G(0x0000228c)
+#define GFXGAM16 __REG_2700G(0x00002290)
+
+#define DLSTS __REG_2700G(0x00002300)
+#define DLLCTRL __REG_2700G(0x00002304)
+#define DVLNUM __REG_2700G(0x00002308)
+#define DUCTRL __REG_2700G(0x0000230c)
+#define DVECTRL __REG_2700G(0x00002310)
+#define DHDET __REG_2700G(0x00002314)
+#define DVDET __REG_2700G(0x00002318)
+#define DODMSK __REG_2700G(0x0000231c)
+#define CSC01 __REG_2700G(0x00002330)
+#define CSC02 __REG_2700G(0x00002334)
+#define CSC03 __REG_2700G(0x00002338)
+#define CSC04 __REG_2700G(0x0000233c)
+#define CSC05 __REG_2700G(0x00002340)
+
+#define FB_MEMORY_START __REG_2700G(0x00060000)
+
+#endif /* __REGS_2700G_ */
diff --git a/fs/char_dev.c b/fs/char_dev.c
index a4cbc6706ef..3483d3cf808 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -182,6 +182,28 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
return 0;
}
+/**
+ * register_chrdev() - Register a major number for character devices.
+ * @major: major device number or 0 for dynamic allocation
+ * @name: name of this range of devices
+ * @fops: file operations associated with this devices
+ *
+ * If @major == 0 this functions will dynamically allocate a major and return
+ * its number.
+ *
+ * If @major > 0 this function will attempt to reserve a device with the given
+ * major number and will return zero on success.
+ *
+ * Returns a -ve errno on failure.
+ *
+ * The name of this device has nothing to do with the name of the device in
+ * /dev. It only helps to keep track of the different owners of devices. If
+ * your module name has only one type of devices it's ok to use e.g. the name
+ * of the module here.
+ *
+ * This function registers a range of 256 minor numbers. The first minor number
+ * is 0.
+ */
int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
{
diff --git a/fs/namei.c b/fs/namei.c
index c9750d755af..e01070d7bf5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1712,8 +1712,14 @@ do_link:
if (error)
goto exit_dput;
error = __do_follow_link(&path, nd);
- if (error)
+ if (error) {
+ /* Does someone understand code flow here? Or it is only
+ * me so stupid? Anathema to whoever designed this non-sense
+ * with "intent.open".
+ */
+ release_open_intent(nd);
return error;
+ }
nd->flags &= ~LOOKUP_PARENT;
if (nd->last_type == LAST_BIND)
goto ok;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 7495d3e2077..0b615d62a15 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -74,6 +74,7 @@
#include <linux/times.h>
#include <linux/cpuset.h>
#include <linux/rcupdate.h>
+#include <linux/delayacct.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -411,7 +412,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n",
task->pid,
tcomm,
state,
@@ -455,7 +456,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
task->exit_signal,
task_cpu(task),
task->rt_priority,
- task->policy);
+ task->policy,
+ (unsigned long long)delayacct_blkio_ticks(task));
if(mm)
mmput(mm);
return res;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 0cb8f20d000..474eae34506 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1338,8 +1338,8 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
} else {
inode->i_uid = 0;
inode->i_gid = 0;
- inode->i_mode = 0;
}
+ inode->i_mode &= ~(S_ISUID | S_ISGID);
security_task_to_inode(task, inode);
put_task_struct(task);
return 1;
@@ -1390,6 +1390,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
inode->i_uid = 0;
inode->i_gid = 0;
}
+ inode->i_mode &= ~(S_ISUID | S_ISGID);
security_task_to_inode(task, inode);
put_task_struct(task);
return 1;
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index 5d8a8cfebc7..c533ec1bcae 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -492,9 +492,17 @@ static void add_file(struct super_block *sb, char *name,
int reiserfs_proc_info_init(struct super_block *sb)
{
+ char b[BDEVNAME_SIZE];
+ char *s;
+
+ /* Some block devices use /'s */
+ strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE);
+ s = strchr(b, '/');
+ if (s)
+ *s = '!';
+
spin_lock_init(&__PINFO(sb).lock);
- REISERFS_SB(sb)->procdir =
- proc_mkdir(reiserfs_bdevname(sb), proc_info_root);
+ REISERFS_SB(sb)->procdir = proc_mkdir(b, proc_info_root);
if (REISERFS_SB(sb)->procdir) {
REISERFS_SB(sb)->procdir->owner = THIS_MODULE;
REISERFS_SB(sb)->procdir->data = sb;
@@ -508,13 +516,22 @@ int reiserfs_proc_info_init(struct super_block *sb)
return 0;
}
reiserfs_warning(sb, "reiserfs: cannot create /proc/%s/%s",
- proc_info_root_name, reiserfs_bdevname(sb));
+ proc_info_root_name, b);
return 1;
}
int reiserfs_proc_info_done(struct super_block *sb)
{
struct proc_dir_entry *de = REISERFS_SB(sb)->procdir;
+ char b[BDEVNAME_SIZE];
+ char *s;
+
+ /* Some block devices use /'s */
+ strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE);
+ s = strchr(b, '/');
+ if (s)
+ *s = '!';
+
if (de) {
remove_proc_entry("journal", de);
remove_proc_entry("oidmap", de);
@@ -528,7 +545,7 @@ int reiserfs_proc_info_done(struct super_block *sb)
__PINFO(sb).exiting = 1;
spin_unlock(&__PINFO(sb).lock);
if (proc_info_root) {
- remove_proc_entry(reiserfs_bdevname(sb), proc_info_root);
+ remove_proc_entry(b, proc_info_root);
REISERFS_SB(sb)->procdir = NULL;
}
return 0;
diff --git a/include/asm-alpha/barrier.h b/include/asm-alpha/barrier.h
index 681ff581afa..384dc08d6f5 100644
--- a/include/asm-alpha/barrier.h
+++ b/include/asm-alpha/barrier.h
@@ -30,7 +30,4 @@ __asm__ __volatile__("mb": : :"memory")
#define set_mb(var, value) \
do { var = value; mb(); } while (0)
-#define set_wmb(var, value) \
-do { var = value; wmb(); } while (0)
-
#endif /* __BARRIER_H */
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index 6001febfe63..0947cbf9b69 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -176,7 +176,6 @@ extern unsigned int user_debug;
#define wmb() mb()
#define read_barrier_depends() do { } while(0)
#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
/*
diff --git a/include/asm-arm26/system.h b/include/asm-arm26/system.h
index d1f69d70619..00ae32aa1db 100644
--- a/include/asm-arm26/system.h
+++ b/include/asm-arm26/system.h
@@ -90,7 +90,6 @@ extern unsigned int user_debug;
#define read_barrier_depends() do { } while(0)
#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
/*
* We assume knowledge of how
diff --git a/include/asm-cris/system.h b/include/asm-cris/system.h
index b1c593b6dbf..b869f6161aa 100644
--- a/include/asm-cris/system.h
+++ b/include/asm-cris/system.h
@@ -17,7 +17,6 @@ extern struct task_struct *resume(struct task_struct *prev, struct task_struct *
#define wmb() mb()
#define read_barrier_depends() do { } while(0)
#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#ifdef CONFIG_SMP
#define smp_mb() mb()
diff --git a/include/asm-frv/system.h b/include/asm-frv/system.h
index 351863dfd06..1166899317d 100644
--- a/include/asm-frv/system.h
+++ b/include/asm-frv/system.h
@@ -179,7 +179,6 @@ do { \
#define rmb() asm volatile ("membar" : : :"memory")
#define wmb() asm volatile ("membar" : : :"memory")
#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define smp_mb() mb()
#define smp_rmb() rmb()
diff --git a/include/asm-generic/Kbuild.asm b/include/asm-generic/Kbuild.asm
index d8d0bcecd23..6b16dda1811 100644
--- a/include/asm-generic/Kbuild.asm
+++ b/include/asm-generic/Kbuild.asm
@@ -1,11 +1,8 @@
unifdef-y += a.out.h auxvec.h byteorder.h errno.h fcntl.h ioctl.h \
- ioctls.h ipcbuf.h irq.h mman.h msgbuf.h param.h poll.h \
+ ioctls.h ipcbuf.h mman.h msgbuf.h param.h poll.h \
posix_types.h ptrace.h resource.h sembuf.h shmbuf.h shmparam.h \
sigcontext.h siginfo.h signal.h socket.h sockios.h stat.h \
statfs.h termbits.h termios.h timex.h types.h unistd.h user.h
-# These really shouldn't be exported
-unifdef-y += atomic.h io.h
-
# These probably shouldn't be exported
unifdef-y += elf.h page.h
diff --git a/include/asm-h8300/system.h b/include/asm-h8300/system.h
index 134e0929fce..5084a9d4292 100644
--- a/include/asm-h8300/system.h
+++ b/include/asm-h8300/system.h
@@ -84,7 +84,6 @@ asmlinkage void resume(void);
#define wmb() asm volatile ("" : : :"memory")
#define set_rmb(var, value) do { xchg(&var, value); } while (0)
#define set_mb(var, value) set_rmb(var, value)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#ifdef CONFIG_SMP
#define smp_mb() mb()
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index 2db168ef949..49928eb33f8 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -453,8 +453,6 @@ static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long l
#define set_mb(var, value) do { var = value; barrier(); } while (0)
#endif
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
-
#include <linux/irqflags.h>
/*
diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h
index 65db43ce4de..fc9677bc87e 100644
--- a/include/asm-ia64/system.h
+++ b/include/asm-ia64/system.h
@@ -98,12 +98,11 @@ extern struct ia64_boot_param {
#endif
/*
- * XXX check on these---I suspect what Linus really wants here is
+ * XXX check on this ---I suspect what Linus really wants here is
* acquire vs release semantics but we can't discuss this stuff with
* Linus just yet. Grrr...
*/
#define set_mb(var, value) do { (var) = (value); mb(); } while (0)
-#define set_wmb(var, value) do { (var) = (value); mb(); } while (0)
#define safe_halt() ia64_pal_halt_light() /* PAL_HALT_LIGHT */
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index 311cebf44ef..9e618afec6e 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -336,7 +336,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
#endif
#define set_mb(var, value) do { xchg(&var, value); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define arch_align_stack(x) (x)
diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h
index d6dd8052cd6..131a0cb0f49 100644
--- a/include/asm-m68k/system.h
+++ b/include/asm-m68k/system.h
@@ -80,7 +80,6 @@ static inline int irqs_disabled(void)
#define wmb() barrier()
#define read_barrier_depends() do { } while(0)
#define set_mb(var, value) do { xchg(&var, value); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define smp_mb() barrier()
#define smp_rmb() barrier()
diff --git a/include/asm-m68knommu/system.h b/include/asm-m68knommu/system.h
index 2bbe2db00a2..2a814498672 100644
--- a/include/asm-m68knommu/system.h
+++ b/include/asm-m68knommu/system.h
@@ -106,7 +106,6 @@ asmlinkage void resume(void);
#define wmb() asm volatile ("" : : :"memory")
#define set_rmb(var, value) do { xchg(&var, value); } while (0)
#define set_mb(var, value) set_rmb(var, value)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#ifdef CONFIG_SMP
#define smp_mb() mb()
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 13c98dde82d..dcb4701d572 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -143,9 +143,6 @@
#define set_mb(var, value) \
do { var = value; mb(); } while (0)
-#define set_wmb(var, value) \
-do { var = value; wmb(); } while (0)
-
/*
* switch_to(n) should switch tasks to task nr n, first
* checking that n isn't the current task, in which case it does nothing.
diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h
index 5fe2d2329ab..74f037a39e6 100644
--- a/include/asm-parisc/system.h
+++ b/include/asm-parisc/system.h
@@ -143,8 +143,6 @@ static inline void set_eiem(unsigned long val)
#define read_barrier_depends() do { } while(0)
#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
-
#ifndef CONFIG_PA20
/* Because kmalloc only guarantees 8-byte alignment for kmalloc'd data,
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index c6569516ba3..7307aa77567 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -39,7 +39,6 @@
#define read_barrier_depends() do { } while(0)
#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#ifdef __KERNEL__
#ifdef CONFIG_SMP
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index fb49c0c49ea..738943584c0 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -33,7 +33,6 @@
#define read_barrier_depends() do { } while(0)
#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#ifdef CONFIG_SMP
#define smp_mb() mb()
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index 9ab186ffde2..36a3a85d611 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -299,7 +299,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#ifdef __s390x__
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index ce2e60664a8..ad35ad4958f 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -101,7 +101,6 @@ extern void __xchg_called_with_bad_pointer(void);
#endif
#define set_mb(var, value) do { xchg(&var, value); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
/* Interrupt Control */
static __inline__ void local_irq_enable(void)
diff --git a/include/asm-sh64/system.h b/include/asm-sh64/system.h
index 7606f6e1f01..87ef6f1ad5a 100644
--- a/include/asm-sh64/system.h
+++ b/include/asm-sh64/system.h
@@ -66,7 +66,6 @@ extern void __xchg_called_with_bad_pointer(void);
#define set_rmb(var, value) do { xchg(&var, value); } while (0)
#define set_mb(var, value) set_rmb(var, value)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
/* Interrupt Control */
#ifndef HARD_CLI
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index cb7dda1e5e9..100c3eaf3c1 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -199,7 +199,6 @@ static inline unsigned long getipl(void)
#define wmb() mb()
#define read_barrier_depends() do { } while(0)
#define set_mb(__var, __value) do { __var = __value; mb(); } while(0)
-#define set_wmb(__var, __value) set_mb(__var, __value)
#define smp_mb() __asm__ __volatile__("":::"memory")
#define smp_rmb() __asm__ __volatile__("":::"memory")
#define smp_wmb() __asm__ __volatile__("":::"memory")
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 4ca68600c67..a8b7432c9a7 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -123,8 +123,6 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
#define read_barrier_depends() do { } while(0)
#define set_mb(__var, __value) \
do { __var = __value; membar_storeload_storestore(); } while(0)
-#define set_wmb(__var, __value) \
- do { __var = __value; wmb(); } while(0)
#ifdef CONFIG_SMP
#define smp_mb() mb()
diff --git a/include/asm-v850/system.h b/include/asm-v850/system.h
index 7091af4b786..da39916f10b 100644
--- a/include/asm-v850/system.h
+++ b/include/asm-v850/system.h
@@ -68,7 +68,6 @@ static inline int irqs_disabled (void)
#define read_barrier_depends() ((void)0)
#define set_rmb(var, value) do { xchg (&var, value); } while (0)
#define set_mb(var, value) set_rmb (var, value)
-#define set_wmb(var, value) do { var = value; wmb (); } while (0)
#define smp_mb() mb ()
#define smp_rmb() rmb ()
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index f67f2873a92..6bf170bceae 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -240,7 +240,6 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
#endif
#define read_barrier_depends() do {} while(0)
#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define warn_if_not_ulong(x) do { unsigned long foo; (void) (&(x) == &foo); } while (0)
diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h
index f986170bd2a..932bda92a21 100644
--- a/include/asm-xtensa/system.h
+++ b/include/asm-xtensa/system.h
@@ -99,7 +99,6 @@ static inline void disable_coprocessor(int i)
#endif
#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#if !defined (__ASSEMBLY__)
diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h
new file mode 100644
index 00000000000..7e8b6011b8f
--- /dev/null
+++ b/include/linux/delayacct.h
@@ -0,0 +1,119 @@
+/* delayacct.h - per-task delay accounting
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_DELAYACCT_H
+#define _LINUX_DELAYACCT_H
+
+#include <linux/sched.h>
+#include <linux/taskstats_kern.h>
+
+/*
+ * Per-task flags relevant to delay accounting
+ * maintained privately to avoid exhausting similar flags in sched.h:PF_*
+ * Used to set current->delays->flags
+ */
+#define DELAYACCT_PF_SWAPIN 0x00000001 /* I am doing a swapin */
+
+#ifdef CONFIG_TASK_DELAY_ACCT
+
+extern int delayacct_on; /* Delay accounting turned on/off */
+extern kmem_cache_t *delayacct_cache;
+extern void delayacct_init(void);
+extern void __delayacct_tsk_init(struct task_struct *);
+extern void __delayacct_tsk_exit(struct task_struct *);
+extern void __delayacct_blkio_start(void);
+extern void __delayacct_blkio_end(void);
+extern int __delayacct_add_tsk(struct taskstats *, struct task_struct *);
+extern __u64 __delayacct_blkio_ticks(struct task_struct *);
+
+static inline void delayacct_set_flag(int flag)
+{
+ if (current->delays)
+ current->delays->flags |= flag;
+}
+
+static inline void delayacct_clear_flag(int flag)
+{
+ if (current->delays)
+ current->delays->flags &= ~flag;
+}
+
+static inline void delayacct_tsk_init(struct task_struct *tsk)
+{
+ /* reinitialize in case parent's non-null pointer was dup'ed*/
+ tsk->delays = NULL;
+ if (unlikely(delayacct_on))
+ __delayacct_tsk_init(tsk);
+}
+
+static inline void delayacct_tsk_exit(struct task_struct *tsk)
+{
+ if (tsk->delays)
+ __delayacct_tsk_exit(tsk);
+}
+
+static inline void delayacct_blkio_start(void)
+{
+ if (current->delays)
+ __delayacct_blkio_start();
+}
+
+static inline void delayacct_blkio_end(void)
+{
+ if (current->delays)
+ __delayacct_blkio_end();
+}
+
+static inline int delayacct_add_tsk(struct taskstats *d,
+ struct task_struct *tsk)
+{
+ if (likely(!delayacct_on))
+ return -EINVAL;
+ if (!tsk->delays)
+ return 0;
+ return __delayacct_add_tsk(d, tsk);
+}
+
+static inline __u64 delayacct_blkio_ticks(struct task_struct *tsk)
+{
+ if (tsk->delays)
+ return __delayacct_blkio_ticks(tsk);
+ return 0;
+}
+
+#else
+static inline void delayacct_set_flag(int flag)
+{}
+static inline void delayacct_clear_flag(int flag)
+{}
+static inline void delayacct_init(void)
+{}
+static inline void delayacct_tsk_init(struct task_struct *tsk)
+{}
+static inline void delayacct_tsk_exit(struct task_struct *tsk)
+{}
+static inline void delayacct_blkio_start(void)
+{}
+static inline void delayacct_blkio_end(void)
+{}
+static inline int delayacct_add_tsk(struct taskstats *d,
+ struct task_struct *tsk)
+{ return 0; }
+static inline __u64 delayacct_blkio_ticks(struct task_struct *tsk)
+{ return 0; }
+#endif /* CONFIG_TASK_DELAY_ACCT */
+
+#endif
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 21338bb3441..9418519a55d 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -115,6 +115,7 @@
#define I2C_DRIVERID_BT866 85 /* Conexant bt866 video encoder */
#define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */
#define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */
+#define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index eef0876d830..383627ad328 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -23,8 +23,8 @@ struct vlan_collection;
struct vlan_dev_info;
struct hlist_node;
-#include <linux/proc_fs.h> /* for proc_dir_entry */
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#define VLAN_HLEN 4 /* The additional bytes (on top of the Ethernet header)
* that VLAN requires.
@@ -185,7 +185,8 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb,
* This allows the VLAN to have a different MAC than the underlying
* device, and still route correctly.
*/
- if (!memcmp(eth_hdr(skb)->h_dest, skb->dev->dev_addr, ETH_ALEN))
+ if (!compare_ether_addr(eth_hdr(skb)->h_dest,
+ skb->dev->dev_addr))
skb->pkt_type = PACKET_HOST;
break;
};
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 7cce5dfa092..1c65e7a9f18 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -28,7 +28,6 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
void kthread_bind(struct task_struct *k, unsigned int cpu);
int kthread_stop(struct task_struct *k);
-int kthread_stop_sem(struct task_struct *k, struct semaphore *s);
int kthread_should_stop(void);
#endif /* _LINUX_KTHREAD_H */
diff --git a/include/linux/list.h b/include/linux/list.h
index 6b74adf5297..65a5b5ceda4 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -265,6 +265,17 @@ static inline void list_move_tail(struct list_head *list,
}
/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
diff --git a/include/linux/module.h b/include/linux/module.h
index d06c74fb8c2..0dfb794c52d 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -362,10 +362,8 @@ int is_module_address(unsigned long addr);
/* Returns module and fills in value, defined and namebuf, or NULL if
symnum out of range. */
-struct module *module_get_kallsym(unsigned int symnum,
- unsigned long *value,
- char *type,
- char namebuf[128]);
+struct module *module_get_kallsym(unsigned int symnum, unsigned long *value,
+ char *type, char *name, size_t namelen);
/* Look for this name: can be of form module:name. */
unsigned long module_kallsyms_lookup_name(const char *name);
@@ -535,8 +533,8 @@ static inline const char *module_address_lookup(unsigned long addr,
static inline struct module *module_get_kallsym(unsigned int symnum,
unsigned long *value,
- char *type,
- char namebuf[128])
+ char *type, char *name,
+ size_t namelen)
{
return NULL;
}
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 58cb3d3d44b..45511a5918d 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -11,7 +11,7 @@ struct open_intent {
struct file *file;
};
-enum { MAX_NESTED_LINKS = 5 };
+enum { MAX_NESTED_LINKS = 8 };
struct nameidata {
struct dentry *dentry;
diff --git a/include/linux/nsc_gpio.h b/include/linux/nsc_gpio.h
index 135742cfada..7da0cf3702e 100644
--- a/include/linux/nsc_gpio.h
+++ b/include/linux/nsc_gpio.h
@@ -25,8 +25,6 @@ struct nsc_gpio_ops {
void (*gpio_dump) (struct nsc_gpio_ops *amp, unsigned iminor);
int (*gpio_get) (unsigned iminor);
void (*gpio_set) (unsigned iminor, int state);
- void (*gpio_set_high)(unsigned iminor);
- void (*gpio_set_low) (unsigned iminor);
void (*gpio_change) (unsigned iminor);
int (*gpio_current) (unsigned iminor);
struct device* dev; /* for dev_dbg() support, set in init */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 1c876e27ff9..6afa72e080c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -463,6 +463,10 @@ struct signal_struct {
#ifdef CONFIG_BSD_PROCESS_ACCT
struct pacct_struct pacct; /* per-process accounting information */
#endif
+#ifdef CONFIG_TASKSTATS
+ spinlock_t stats_lock;
+ struct taskstats *stats;
+#endif
};
/* Context switch must be unlocked if interrupts are to be enabled */
@@ -537,7 +541,7 @@ extern struct user_struct root_user;
struct backing_dev_info;
struct reclaim_state;
-#ifdef CONFIG_SCHEDSTATS
+#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
struct sched_info {
/* cumulative counters */
unsigned long cpu_time, /* time spent on the cpu */
@@ -548,9 +552,53 @@ struct sched_info {
unsigned long last_arrival, /* when we last ran on a cpu */
last_queued; /* when we were last queued to run */
};
+#endif /* defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) */
+#ifdef CONFIG_SCHEDSTATS
extern struct file_operations proc_schedstat_operations;
+#endif /* CONFIG_SCHEDSTATS */
+
+#ifdef CONFIG_TASK_DELAY_ACCT
+struct task_delay_info {
+ spinlock_t lock;
+ unsigned int flags; /* Private per-task flags */
+
+ /* For each stat XXX, add following, aligned appropriately
+ *
+ * struct timespec XXX_start, XXX_end;
+ * u64 XXX_delay;
+ * u32 XXX_count;
+ *
+ * Atomicity of updates to XXX_delay, XXX_count protected by
+ * single lock above (split into XXX_lock if contention is an issue).
+ */
+
+ /*
+ * XXX_count is incremented on every XXX operation, the delay
+ * associated with the operation is added to XXX_delay.
+ * XXX_delay contains the accumulated delay time in nanoseconds.
+ */
+ struct timespec blkio_start, blkio_end; /* Shared by blkio, swapin */
+ u64 blkio_delay; /* wait for sync block io completion */
+ u64 swapin_delay; /* wait for swapin block io completion */
+ u32 blkio_count; /* total count of the number of sync block */
+ /* io operations performed */
+ u32 swapin_count; /* total count of the number of swapin block */
+ /* io operations performed */
+};
+#endif /* CONFIG_TASK_DELAY_ACCT */
+
+static inline int sched_info_on(void)
+{
+#ifdef CONFIG_SCHEDSTATS
+ return 1;
+#elif defined(CONFIG_TASK_DELAY_ACCT)
+ extern int delayacct_on;
+ return delayacct_on;
+#else
+ return 0;
#endif
+}
enum idle_type
{
@@ -747,7 +795,7 @@ struct task_struct {
cpumask_t cpus_allowed;
unsigned int time_slice, first_time_slice;
-#ifdef CONFIG_SCHEDSTATS
+#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
struct sched_info sched_info;
#endif
@@ -945,6 +993,10 @@ struct task_struct {
* cache last used pipe for splice
*/
struct pipe_inode_info *splice_pipe;
+#ifdef CONFIG_TASK_DELAY_ACCT
+ spinlock_t delays_lock;
+ struct task_delay_info *delays;
+#endif
};
static inline pid_t process_group(struct task_struct *tsk)
diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h
new file mode 100644
index 00000000000..f1cb6cddd19
--- /dev/null
+++ b/include/linux/taskstats.h
@@ -0,0 +1,137 @@
+/* taskstats.h - exporting per-task statistics
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2006
+ * (C) Balbir Singh, IBM Corp. 2006
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _LINUX_TASKSTATS_H
+#define _LINUX_TASKSTATS_H
+
+/* Format for per-task data returned to userland when
+ * - a task exits
+ * - listener requests stats for a task
+ *
+ * The struct is versioned. Newer versions should only add fields to
+ * the bottom of the struct to maintain backward compatibility.
+ *
+ *
+ * To add new fields
+ * a) bump up TASKSTATS_VERSION
+ * b) add comment indicating new version number at end of struct
+ * c) add new fields after version comment; maintain 64-bit alignment
+ */
+
+#define TASKSTATS_VERSION 1
+
+struct taskstats {
+
+ /* Version 1 */
+ __u16 version;
+ __u16 padding[3]; /* Userspace should not interpret the padding
+ * field which can be replaced by useful
+ * fields if struct taskstats is extended.
+ */
+
+ /* Delay accounting fields start
+ *
+ * All values, until comment "Delay accounting fields end" are
+ * available only if delay accounting is enabled, even though the last
+ * few fields are not delays
+ *
+ * xxx_count is the number of delay values recorded
+ * xxx_delay_total is the corresponding cumulative delay in nanoseconds
+ *
+ * xxx_delay_total wraps around to zero on overflow
+ * xxx_count incremented regardless of overflow
+ */
+
+ /* Delay waiting for cpu, while runnable
+ * count, delay_total NOT updated atomically
+ */
+ __u64 cpu_count;
+ __u64 cpu_delay_total;
+
+ /* Following four fields atomically updated using task->delays->lock */
+
+ /* Delay waiting for synchronous block I/O to complete
+ * does not account for delays in I/O submission
+ */
+ __u64 blkio_count;
+ __u64 blkio_delay_total;
+
+ /* Delay waiting for page fault I/O (swap in only) */
+ __u64 swapin_count;
+ __u64 swapin_delay_total;
+
+ /* cpu "wall-clock" running time
+ * On some architectures, value will adjust for cpu time stolen
+ * from the kernel in involuntary waits due to virtualization.
+ * Value is cumulative, in nanoseconds, without a corresponding count
+ * and wraps around to zero silently on overflow
+ */
+ __u64 cpu_run_real_total;
+
+ /* cpu "virtual" running time
+ * Uses time intervals seen by the kernel i.e. no adjustment
+ * for kernel's involuntary waits due to virtualization.
+ * Value is cumulative, in nanoseconds, without a corresponding count
+ * and wraps around to zero silently on overflow
+ */
+ __u64 cpu_run_virtual_total;
+ /* Delay accounting fields end */
+ /* version 1 ends here */
+};
+
+
+/*
+ * Commands sent from userspace
+ * Not versioned. New commands should only be inserted at the enum's end
+ * prior to __TASKSTATS_CMD_MAX
+ */
+
+enum {
+ TASKSTATS_CMD_UNSPEC = 0, /* Reserved */
+ TASKSTATS_CMD_GET, /* user->kernel request/get-response */
+ TASKSTATS_CMD_NEW, /* kernel->user event */
+ __TASKSTATS_CMD_MAX,
+};
+
+#define TASKSTATS_CMD_MAX (__TASKSTATS_CMD_MAX - 1)
+
+enum {
+ TASKSTATS_TYPE_UNSPEC = 0, /* Reserved */
+ TASKSTATS_TYPE_PID, /* Process id */
+ TASKSTATS_TYPE_TGID, /* Thread group id */
+ TASKSTATS_TYPE_STATS, /* taskstats structure */
+ TASKSTATS_TYPE_AGGR_PID, /* contains pid + stats */
+ TASKSTATS_TYPE_AGGR_TGID, /* contains tgid + stats */
+ __TASKSTATS_TYPE_MAX,
+};
+
+#define TASKSTATS_TYPE_MAX (__TASKSTATS_TYPE_MAX - 1)
+
+enum {
+ TASKSTATS_CMD_ATTR_UNSPEC = 0,
+ TASKSTATS_CMD_ATTR_PID,
+ TASKSTATS_CMD_ATTR_TGID,
+ TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
+ TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
+ __TASKSTATS_CMD_ATTR_MAX,
+};
+
+#define TASKSTATS_CMD_ATTR_MAX (__TASKSTATS_CMD_ATTR_MAX - 1)
+
+/* NETLINK_GENERIC related info */
+
+#define TASKSTATS_GENL_NAME "TASKSTATS"
+#define TASKSTATS_GENL_VERSION 0x1
+
+#endif /* _LINUX_TASKSTATS_H */
diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h
new file mode 100644
index 00000000000..16894b7edcc
--- /dev/null
+++ b/include/linux/taskstats_kern.h
@@ -0,0 +1,89 @@
+/* taskstats_kern.h - kernel header for per-task statistics interface
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2006
+ * (C) Balbir Singh, IBM Corp. 2006
+ */
+
+#ifndef _LINUX_TASKSTATS_KERN_H
+#define _LINUX_TASKSTATS_KERN_H
+
+#include <linux/taskstats.h>
+#include <linux/sched.h>
+#include <net/genetlink.h>
+
+#ifdef CONFIG_TASKSTATS
+extern kmem_cache_t *taskstats_cache;
+extern struct mutex taskstats_exit_mutex;
+
+static inline void taskstats_exit_free(struct taskstats *tidstats)
+{
+ if (tidstats)
+ kmem_cache_free(taskstats_cache, tidstats);
+}
+
+static inline void taskstats_tgid_init(struct signal_struct *sig)
+{
+ spin_lock_init(&sig->stats_lock);
+ sig->stats = NULL;
+}
+
+static inline void taskstats_tgid_alloc(struct signal_struct *sig)
+{
+ struct taskstats *stats;
+ unsigned long flags;
+
+ stats = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL);
+ if (!stats)
+ return;
+
+ spin_lock_irqsave(&sig->stats_lock, flags);
+ if (!sig->stats) {
+ sig->stats = stats;
+ stats = NULL;
+ }
+ spin_unlock_irqrestore(&sig->stats_lock, flags);
+
+ if (stats)
+ kmem_cache_free(taskstats_cache, stats);
+}
+
+static inline void taskstats_tgid_free(struct signal_struct *sig)
+{
+ struct taskstats *stats = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sig->stats_lock, flags);
+ if (sig->stats) {
+ stats = sig->stats;
+ sig->stats = NULL;
+ }
+ spin_unlock_irqrestore(&sig->stats_lock, flags);
+ if (stats)
+ kmem_cache_free(taskstats_cache, stats);
+}
+
+extern void taskstats_exit_alloc(struct taskstats **, unsigned int *);
+extern void taskstats_exit_send(struct task_struct *, struct taskstats *, int, unsigned int);
+extern void taskstats_init_early(void);
+extern void taskstats_tgid_alloc(struct signal_struct *);
+#else
+static inline void taskstats_exit_alloc(struct taskstats **ptidstats, unsigned int *mycpu)
+{}
+static inline void taskstats_exit_free(struct taskstats *ptidstats)
+{}
+static inline void taskstats_exit_send(struct task_struct *tsk,
+ struct taskstats *tidstats,
+ int group_dead, unsigned int cpu)
+{}
+static inline void taskstats_tgid_init(struct signal_struct *sig)
+{}
+static inline void taskstats_tgid_alloc(struct signal_struct *sig)
+{}
+static inline void taskstats_tgid_free(struct signal_struct *sig)
+{}
+static inline void taskstats_init_early(void)
+{}
+#endif /* CONFIG_TASKSTATS */
+
+#endif
+
diff --git a/include/linux/time.h b/include/linux/time.h
index c05f8bb9a32..a5b739967b7 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -71,6 +71,18 @@ extern unsigned long mktime(const unsigned int year, const unsigned int mon,
extern void set_normalized_timespec(struct timespec *ts, time_t sec, long nsec);
/*
+ * sub = lhs - rhs, in normalized form
+ */
+static inline struct timespec timespec_sub(struct timespec lhs,
+ struct timespec rhs)
+{
+ struct timespec ts_delta;
+ set_normalized_timespec(&ts_delta, lhs.tv_sec - rhs.tv_sec,
+ lhs.tv_nsec - rhs.tv_nsec);
+ return ts_delta;
+}
+
+/*
* Returns true if the timespec is norm, false if denorm:
*/
#define timespec_valid(ts) \
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index f6024ab4eff..71b6363caaa 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -11,6 +11,7 @@ struct vm_area_struct;
#define VM_ALLOC 0x00000002 /* vmalloc() */
#define VM_MAP 0x00000004 /* vmap()ed pages */
#define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */
+#define VM_VPAGES 0x00000010 /* buffer for pages was vmalloc'ed */
/* bits [20..32] reserved for arch specific ioremap internals */
/*
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 805de50df00..8c228726426 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -150,4 +150,24 @@ static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
return nlmsg_unicast(genl_sock, skb, pid);
}
+/**
+ * gennlmsg_data - head of message payload
+ * @gnlh: genetlink messsage header
+ */
+static inline void *genlmsg_data(const struct genlmsghdr *gnlh)
+{
+ return ((unsigned char *) gnlh + GENL_HDRLEN);
+}
+
+/**
+ * genlmsg_len - length of message payload
+ * @gnlh: genetlink message header
+ */
+static inline int genlmsg_len(const struct genlmsghdr *gnlh)
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh -
+ NLMSG_HDRLEN);
+ return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
+}
+
#endif /* __NET_GENERIC_NETLINK_H */
diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
index fcb5ba87dcc..0ff67398928 100644
--- a/include/rdma/ib_addr.h
+++ b/include/rdma/ib_addr.h
@@ -89,9 +89,10 @@ static inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey)
dev_addr->broadcast[9] = (unsigned char) pkey;
}
-static inline union ib_gid *ib_addr_get_sgid(struct rdma_dev_addr *dev_addr)
+static inline void ib_addr_get_sgid(struct rdma_dev_addr *dev_addr,
+ union ib_gid *gid)
{
- return (union ib_gid *) (dev_addr->src_dev_addr + 4);
+ memcpy(gid, dev_addr->src_dev_addr + 4, sizeof *gid);
}
static inline void ib_addr_set_sgid(struct rdma_dev_addr *dev_addr,
@@ -100,9 +101,10 @@ static inline void ib_addr_set_sgid(struct rdma_dev_addr *dev_addr,
memcpy(dev_addr->src_dev_addr + 4, gid, sizeof *gid);
}
-static inline union ib_gid *ib_addr_get_dgid(struct rdma_dev_addr *dev_addr)
+static inline void ib_addr_get_dgid(struct rdma_dev_addr *dev_addr,
+ union ib_gid *gid)
{
- return (union ib_gid *) (dev_addr->dst_dev_addr + 4);
+ memcpy(gid, dev_addr->dst_dev_addr + 4, sizeof *gid);
}
static inline void ib_addr_set_dgid(struct rdma_dev_addr *dev_addr,
diff --git a/include/rdma/ib_fmr_pool.h b/include/rdma/ib_fmr_pool.h
index 4ace54cd0cc..00dadbf94e1 100644
--- a/include/rdma/ib_fmr_pool.h
+++ b/include/rdma/ib_fmr_pool.h
@@ -88,7 +88,7 @@ int ib_flush_fmr_pool(struct ib_fmr_pool *pool);
struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
u64 *page_list,
int list_len,
- u64 *io_virtual_address);
+ u64 io_virtual_address);
int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr);
diff --git a/include/video/mbxfb.h b/include/video/mbxfb.h
new file mode 100644
index 00000000000..3bde0f5cd55
--- /dev/null
+++ b/include/video/mbxfb.h
@@ -0,0 +1,28 @@
+#ifndef __MBX_FB_H
+#define __MBX_FB_H
+
+struct mbxfb_val {
+ unsigned int defval;
+ unsigned int min;
+ unsigned int max;
+};
+
+struct fb_info;
+
+struct mbxfb_platform_data {
+ /* Screen info */
+ struct mbxfb_val xres;
+ struct mbxfb_val yres;
+ struct mbxfb_val bpp;
+
+ /* Memory info */
+ unsigned long memsize; /* if 0 use ODFB? */
+ unsigned long timings1;
+ unsigned long timings2;
+ unsigned long timings3;
+
+ int (*probe)(struct fb_info *fb);
+ int (*remove)(struct fb_info *fb);
+};
+
+#endif /* __MBX_FB_H */
diff --git a/init/Kconfig b/init/Kconfig
index a5b073a103e..a099fc6526d 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -158,6 +158,30 @@ config BSD_PROCESS_ACCT_V3
for processing it. A preliminary version of these tools is available
at <http://www.physik3.uni-rostock.de/tim/kernel/utils/acct/>.
+config TASKSTATS
+ bool "Export task/process statistics through netlink (EXPERIMENTAL)"
+ depends on NET
+ default n
+ help
+ Export selected statistics for tasks/processes through the
+ generic netlink interface. Unlike BSD process accounting, the
+ statistics are available during the lifetime of tasks/processes as
+ responses to commands. Like BSD accounting, they are sent to user
+ space on task exit.
+
+ Say N if unsure.
+
+config TASK_DELAY_ACCT
+ bool "Enable per-task delay accounting (EXPERIMENTAL)"
+ depends on TASKSTATS
+ help
+ Collect information on time spent by a task waiting for system
+ resources like cpu, synchronous block I/O completion and swapping
+ in pages. Such statistics can help in setting a task's priorities
+ relative to other tasks for cpu, io, rss limits etc.
+
+ Say N if unsure.
+
config SYSCTL
bool "Sysctl support" if EMBEDDED
default y
diff --git a/init/main.c b/init/main.c
index 628b8e9e841..8651a720a09 100644
--- a/init/main.c
+++ b/init/main.c
@@ -41,6 +41,8 @@
#include <linux/cpu.h>
#include <linux/cpuset.h>
#include <linux/efi.h>
+#include <linux/taskstats_kern.h>
+#include <linux/delayacct.h>
#include <linux/unistd.h>
#include <linux/rmap.h>
#include <linux/mempolicy.h>
@@ -574,6 +576,8 @@ asmlinkage void __init start_kernel(void)
proc_root_init();
#endif
cpuset_init();
+ taskstats_init_early();
+ delayacct_init();
check_bugs();
diff --git a/kernel/Makefile b/kernel/Makefile
index 47dbcd570cd..d62ec66c1af 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -48,6 +48,8 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_SECCOMP) += seccomp.o
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
obj-$(CONFIG_RELAY) += relay.o
+obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
+obj-$(CONFIG_TASKSTATS) += taskstats.o
ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/acct.c b/kernel/acct.c
index f18e0b8df3e..2a7c933651c 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -488,7 +488,7 @@ static void do_acct_process(struct file *file)
old_encode_dev(tty_devnum(current->signal->tty)) : 0;
read_unlock(&tasklist_lock);
- spin_lock(&current->sighand->siglock);
+ spin_lock_irq(&current->sighand->siglock);
ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
ac.ac_flag = pacct->ac_flag;
@@ -496,7 +496,7 @@ static void do_acct_process(struct file *file)
ac.ac_minflt = encode_comp_t(pacct->ac_minflt);
ac.ac_majflt = encode_comp_t(pacct->ac_majflt);
ac.ac_exitcode = pacct->ac_exitcode;
- spin_unlock(&current->sighand->siglock);
+ spin_unlock_irq(&current->sighand->siglock);
ac.ac_io = encode_comp_t(0 /* current->io_usage */); /* %% */
ac.ac_rw = encode_comp_t(ac.ac_io / 1024);
ac.ac_swaps = encode_comp_t(0);
diff --git a/kernel/delayacct.c b/kernel/delayacct.c
new file mode 100644
index 00000000000..f05392d6426
--- /dev/null
+++ b/kernel/delayacct.c
@@ -0,0 +1,178 @@
+/* delayacct.c - per-task delay accounting
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/sysctl.h>
+#include <linux/delayacct.h>
+
+int delayacct_on __read_mostly; /* Delay accounting turned on/off */
+kmem_cache_t *delayacct_cache;
+
+static int __init delayacct_setup_enable(char *str)
+{
+ delayacct_on = 1;
+ return 1;
+}
+__setup("delayacct", delayacct_setup_enable);
+
+void delayacct_init(void)
+{
+ delayacct_cache = kmem_cache_create("delayacct_cache",
+ sizeof(struct task_delay_info),
+ 0,
+ SLAB_PANIC,
+ NULL, NULL);
+ delayacct_tsk_init(&init_task);
+}
+
+void __delayacct_tsk_init(struct task_struct *tsk)
+{
+ spin_lock_init(&tsk->delays_lock);
+ /* No need to acquire tsk->delays_lock for allocation here unless
+ __delayacct_tsk_init called after tsk is attached to tasklist
+ */
+ tsk->delays = kmem_cache_zalloc(delayacct_cache, SLAB_KERNEL);
+ if (tsk->delays)
+ spin_lock_init(&tsk->delays->lock);
+}
+
+void __delayacct_tsk_exit(struct task_struct *tsk)
+{
+ struct task_delay_info *delays = tsk->delays;
+ spin_lock(&tsk->delays_lock);
+ tsk->delays = NULL;
+ spin_unlock(&tsk->delays_lock);
+ kmem_cache_free(delayacct_cache, delays);
+}
+
+/*
+ * Start accounting for a delay statistic using
+ * its starting timestamp (@start)
+ */
+
+static inline void delayacct_start(struct timespec *start)
+{
+ do_posix_clock_monotonic_gettime(start);
+}
+
+/*
+ * Finish delay accounting for a statistic using
+ * its timestamps (@start, @end), accumalator (@total) and @count
+ */
+
+static void delayacct_end(struct timespec *start, struct timespec *end,
+ u64 *total, u32 *count)
+{
+ struct timespec ts;
+ s64 ns;
+
+ do_posix_clock_monotonic_gettime(end);
+ ts = timespec_sub(*end, *start);
+ ns = timespec_to_ns(&ts);
+ if (ns < 0)
+ return;
+
+ spin_lock(&current->delays->lock);
+ *total += ns;
+ (*count)++;
+ spin_unlock(&current->delays->lock);
+}
+
+void __delayacct_blkio_start(void)
+{
+ delayacct_start(&current->delays->blkio_start);
+}
+
+void __delayacct_blkio_end(void)
+{
+ if (current->delays->flags & DELAYACCT_PF_SWAPIN)
+ /* Swapin block I/O */
+ delayacct_end(&current->delays->blkio_start,
+ &current->delays->blkio_end,
+ &current->delays->swapin_delay,
+ &current->delays->swapin_count);
+ else /* Other block I/O */
+ delayacct_end(&current->delays->blkio_start,
+ &current->delays->blkio_end,
+ &current->delays->blkio_delay,
+ &current->delays->blkio_count);
+}
+
+int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
+{
+ s64 tmp;
+ struct timespec ts;
+ unsigned long t1,t2,t3;
+
+ spin_lock(&tsk->delays_lock);
+
+ /* Though tsk->delays accessed later, early exit avoids
+ * unnecessary returning of other data
+ */
+ if (!tsk->delays)
+ goto done;
+
+ tmp = (s64)d->cpu_run_real_total;
+ cputime_to_timespec(tsk->utime + tsk->stime, &ts);
+ tmp += timespec_to_ns(&ts);
+ d->cpu_run_real_total = (tmp < (s64)d->cpu_run_real_total) ? 0 : tmp;
+
+ /*
+ * No locking available for sched_info (and too expensive to add one)
+ * Mitigate by taking snapshot of values
+ */
+ t1 = tsk->sched_info.pcnt;
+ t2 = tsk->sched_info.run_delay;
+ t3 = tsk->sched_info.cpu_time;
+
+ d->cpu_count += t1;
+
+ jiffies_to_timespec(t2, &ts);
+ tmp = (s64)d->cpu_delay_total + timespec_to_ns(&ts);
+ d->cpu_delay_total = (tmp < (s64)d->cpu_delay_total) ? 0 : tmp;
+
+ tmp = (s64)d->cpu_run_virtual_total + (s64)jiffies_to_usecs(t3) * 1000;
+ d->cpu_run_virtual_total =
+ (tmp < (s64)d->cpu_run_virtual_total) ? 0 : tmp;
+
+ /* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */
+
+ spin_lock(&tsk->delays->lock);
+ tmp = d->blkio_delay_total + tsk->delays->blkio_delay;
+ d->blkio_delay_total = (tmp < d->blkio_delay_total) ? 0 : tmp;
+ tmp = d->swapin_delay_total + tsk->delays->swapin_delay;
+ d->swapin_delay_total = (tmp < d->swapin_delay_total) ? 0 : tmp;
+ d->blkio_count += tsk->delays->blkio_count;
+ d->swapin_count += tsk->delays->swapin_count;
+ spin_unlock(&tsk->delays->lock);
+
+done:
+ spin_unlock(&tsk->delays_lock);
+ return 0;
+}
+
+__u64 __delayacct_blkio_ticks(struct task_struct *tsk)
+{
+ __u64 ret;
+
+ spin_lock(&tsk->delays->lock);
+ ret = nsec_to_clock_t(tsk->delays->blkio_delay +
+ tsk->delays->swapin_delay);
+ spin_unlock(&tsk->delays->lock);
+ return ret;
+}
+
diff --git a/kernel/exit.c b/kernel/exit.c
index 6664c084783..dba194a8d41 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -25,6 +25,8 @@
#include <linux/mount.h>
#include <linux/proc_fs.h>
#include <linux/mempolicy.h>
+#include <linux/taskstats_kern.h>
+#include <linux/delayacct.h>
#include <linux/cpuset.h>
#include <linux/syscalls.h>
#include <linux/signal.h>
@@ -843,7 +845,9 @@ static void exit_notify(struct task_struct *tsk)
fastcall NORET_TYPE void do_exit(long code)
{
struct task_struct *tsk = current;
+ struct taskstats *tidstats;
int group_dead;
+ unsigned int mycpu;
profile_task_exit(tsk);
@@ -881,6 +885,8 @@ fastcall NORET_TYPE void do_exit(long code)
current->comm, current->pid,
preempt_count());
+ taskstats_exit_alloc(&tidstats, &mycpu);
+
acct_update_integrals(tsk);
if (tsk->mm) {
update_hiwater_rss(tsk->mm);
@@ -900,6 +906,10 @@ fastcall NORET_TYPE void do_exit(long code)
#endif
if (unlikely(tsk->audit_context))
audit_free(tsk);
+ taskstats_exit_send(tsk, tidstats, group_dead, mycpu);
+ taskstats_exit_free(tidstats);
+ delayacct_tsk_exit(tsk);
+
exit_mm(tsk);
if (group_dead)
diff --git a/kernel/fork.c b/kernel/fork.c
index 926e5a68ea9..1b0f7b1e088 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -43,6 +43,8 @@
#include <linux/rmap.h>
#include <linux/acct.h>
#include <linux/cn_proc.h>
+#include <linux/delayacct.h>
+#include <linux/taskstats_kern.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -818,6 +820,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
if (clone_flags & CLONE_THREAD) {
atomic_inc(&current->signal->count);
atomic_inc(&current->signal->live);
+ taskstats_tgid_alloc(current->signal);
return 0;
}
sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL);
@@ -862,6 +865,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
INIT_LIST_HEAD(&sig->cpu_timers[0]);
INIT_LIST_HEAD(&sig->cpu_timers[1]);
INIT_LIST_HEAD(&sig->cpu_timers[2]);
+ taskstats_tgid_init(sig);
task_lock(current->group_leader);
memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim);
@@ -883,6 +887,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
void __cleanup_signal(struct signal_struct *sig)
{
exit_thread_group_keys(sig);
+ taskstats_tgid_free(sig);
kmem_cache_free(signal_cachep, sig);
}
@@ -1000,6 +1005,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
goto bad_fork_cleanup_put_domain;
p->did_exec = 0;
+ delayacct_tsk_init(p); /* Must remain after dup_task_struct() */
copy_flags(clone_flags, p);
p->pid = pid;
retval = -EFAULT;
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 39277dd6bf9..ab16a5a4cfe 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -275,8 +275,8 @@ static void upcase_if_global(struct kallsym_iter *iter)
static int get_ksymbol_mod(struct kallsym_iter *iter)
{
iter->owner = module_get_kallsym(iter->pos - kallsyms_num_syms,
- &iter->value,
- &iter->type, iter->name);
+ &iter->value, &iter->type,
+ iter->name, sizeof(iter->name));
if (iter->owner == NULL)
return 0;
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 24be714b04c..4f9c60ef95e 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -216,23 +216,6 @@ EXPORT_SYMBOL(kthread_bind);
*/
int kthread_stop(struct task_struct *k)
{
- return kthread_stop_sem(k, NULL);
-}
-EXPORT_SYMBOL(kthread_stop);
-
-/**
- * kthread_stop_sem - stop a thread created by kthread_create().
- * @k: thread created by kthread_create().
- * @s: semaphore that @k waits on while idle.
- *
- * Does essentially the same thing as kthread_stop() above, but wakes
- * @k by calling up(@s).
- *
- * Returns the result of threadfn(), or %-EINTR if wake_up_process()
- * was never called.
- */
-int kthread_stop_sem(struct task_struct *k, struct semaphore *s)
-{
int ret;
mutex_lock(&kthread_stop_lock);
@@ -246,10 +229,7 @@ int kthread_stop_sem(struct task_struct *k, struct semaphore *s)
/* Now set kthread_should_stop() to true, and wake it up. */
kthread_stop_info.k = k;
- if (s)
- up(s);
- else
- wake_up_process(k);
+ wake_up_process(k);
put_task_struct(k);
/* Once it dies, reset stop ptr, gather result and we're done. */
@@ -260,7 +240,7 @@ int kthread_stop_sem(struct task_struct *k, struct semaphore *s)
return ret;
}
-EXPORT_SYMBOL(kthread_stop_sem);
+EXPORT_SYMBOL(kthread_stop);
static __init int helper_init(void)
{
diff --git a/kernel/module.c b/kernel/module.c
index 35e1b1f859d..2a19cd47c04 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2019,10 +2019,8 @@ const char *module_address_lookup(unsigned long addr,
return NULL;
}
-struct module *module_get_kallsym(unsigned int symnum,
- unsigned long *value,
- char *type,
- char namebuf[128])
+struct module *module_get_kallsym(unsigned int symnum, unsigned long *value,
+ char *type, char *name, size_t namelen)
{
struct module *mod;
@@ -2031,9 +2029,8 @@ struct module *module_get_kallsym(unsigned int symnum,
if (symnum < mod->num_symtab) {
*value = mod->symtab[symnum].st_value;
*type = mod->symtab[symnum].st_info;
- strncpy(namebuf,
- mod->strtab + mod->symtab[symnum].st_name,
- 127);
+ strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
+ namelen);
mutex_unlock(&module_mutex);
return mod;
}
diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c
index 494dac872a1..948bd8f643e 100644
--- a/kernel/rtmutex-tester.c
+++ b/kernel/rtmutex-tester.c
@@ -275,6 +275,7 @@ static int test_func(void *data)
/* Wait for the next command to be executed */
schedule();
+ try_to_freeze();
if (signal_pending(current))
flush_signals(current);
diff --git a/kernel/sched.c b/kernel/sched.c
index d714611f169..b44b9a43b0f 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -51,6 +51,7 @@
#include <linux/times.h>
#include <linux/acct.h>
#include <linux/kprobes.h>
+#include <linux/delayacct.h>
#include <asm/tlb.h>
#include <asm/unistd.h>
@@ -501,9 +502,36 @@ struct file_operations proc_schedstat_operations = {
.release = single_release,
};
+/*
+ * Expects runqueue lock to be held for atomicity of update
+ */
+static inline void
+rq_sched_info_arrive(struct rq *rq, unsigned long delta_jiffies)
+{
+ if (rq) {
+ rq->rq_sched_info.run_delay += delta_jiffies;
+ rq->rq_sched_info.pcnt++;
+ }
+}
+
+/*
+ * Expects runqueue lock to be held for atomicity of update
+ */
+static inline void
+rq_sched_info_depart(struct rq *rq, unsigned long delta_jiffies)
+{
+ if (rq)
+ rq->rq_sched_info.cpu_time += delta_jiffies;
+}
# define schedstat_inc(rq, field) do { (rq)->field++; } while (0)
# define schedstat_add(rq, field, amt) do { (rq)->field += (amt); } while (0)
#else /* !CONFIG_SCHEDSTATS */
+static inline void
+rq_sched_info_arrive(struct rq *rq, unsigned long delta_jiffies)
+{}
+static inline void
+rq_sched_info_depart(struct rq *rq, unsigned long delta_jiffies)
+{}
# define schedstat_inc(rq, field) do { } while (0)
# define schedstat_add(rq, field, amt) do { } while (0)
#endif
@@ -523,7 +551,7 @@ static inline struct rq *this_rq_lock(void)
return rq;
}
-#ifdef CONFIG_SCHEDSTATS
+#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
/*
* Called when a process is dequeued from the active array and given
* the cpu. We should note that with the exception of interactive
@@ -551,21 +579,16 @@ static inline void sched_info_dequeued(struct task_struct *t)
*/
static void sched_info_arrive(struct task_struct *t)
{
- unsigned long now = jiffies, diff = 0;
- struct rq *rq = task_rq(t);
+ unsigned long now = jiffies, delta_jiffies = 0;
if (t->sched_info.last_queued)
- diff = now - t->sched_info.last_queued;
+ delta_jiffies = now - t->sched_info.last_queued;
sched_info_dequeued(t);
- t->sched_info.run_delay += diff;
+ t->sched_info.run_delay += delta_jiffies;
t->sched_info.last_arrival = now;
t->sched_info.pcnt++;
- if (!rq)
- return;
-
- rq->rq_sched_info.run_delay += diff;
- rq->rq_sched_info.pcnt++;
+ rq_sched_info_arrive(task_rq(t), delta_jiffies);
}
/*
@@ -585,8 +608,9 @@ static void sched_info_arrive(struct task_struct *t)
*/
static inline void sched_info_queued(struct task_struct *t)
{
- if (!t->sched_info.last_queued)
- t->sched_info.last_queued = jiffies;
+ if (unlikely(sched_info_on()))
+ if (!t->sched_info.last_queued)
+ t->sched_info.last_queued = jiffies;
}
/*
@@ -595,13 +619,10 @@ static inline void sched_info_queued(struct task_struct *t)
*/
static inline void sched_info_depart(struct task_struct *t)
{
- struct rq *rq = task_rq(t);
- unsigned long diff = jiffies - t->sched_info.last_arrival;
-
- t->sched_info.cpu_time += diff;
+ unsigned long delta_jiffies = jiffies - t->sched_info.last_arrival;
- if (rq)
- rq->rq_sched_info.cpu_time += diff;
+ t->sched_info.cpu_time += delta_jiffies;
+ rq_sched_info_depart(task_rq(t), delta_jiffies);
}
/*
@@ -610,7 +631,7 @@ static inline void sched_info_depart(struct task_struct *t)
* the idle task.) We are only called when prev != next.
*/
static inline void
-sched_info_switch(struct task_struct *prev, struct task_struct *next)
+__sched_info_switch(struct task_struct *prev, struct task_struct *next)
{
struct rq *rq = task_rq(prev);
@@ -625,10 +646,16 @@ sched_info_switch(struct task_struct *prev, struct task_struct *next)
if (next != rq->idle)
sched_info_arrive(next);
}
+static inline void
+sched_info_switch(struct task_struct *prev, struct task_struct *next)
+{
+ if (unlikely(sched_info_on()))
+ __sched_info_switch(prev, next);
+}
#else
#define sched_info_queued(t) do { } while (0)
#define sched_info_switch(t, next) do { } while (0)
-#endif /* CONFIG_SCHEDSTATS */
+#endif /* CONFIG_SCHEDSTATS || CONFIG_TASK_DELAY_ACCT */
/*
* Adding/removing a task to/from a priority array:
@@ -1530,8 +1557,9 @@ void fastcall sched_fork(struct task_struct *p, int clone_flags)
INIT_LIST_HEAD(&p->run_list);
p->array = NULL;
-#ifdef CONFIG_SCHEDSTATS
- memset(&p->sched_info, 0, sizeof(p->sched_info));
+#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
+ if (unlikely(sched_info_on()))
+ memset(&p->sched_info, 0, sizeof(p->sched_info));
#endif
#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
p->oncpu = 0;
@@ -1788,7 +1816,15 @@ context_switch(struct rq *rq, struct task_struct *prev,
WARN_ON(rq->prev_mm);
rq->prev_mm = oldmm;
}
+ /*
+ * Since the runqueue lock will be released by the next
+ * task (which is an invalid locking op but in the case
+ * of the scheduler it's an obvious special-case), so we
+ * do an early lockdep release here:
+ */
+#ifndef __ARCH_WANT_UNLOCKED_CTXSW
spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
+#endif
/* Here we just switch the register state and the stack. */
switch_to(prev, next, prev);
@@ -4526,9 +4562,11 @@ void __sched io_schedule(void)
{
struct rq *rq = &__raw_get_cpu_var(runqueues);
+ delayacct_blkio_start();
atomic_inc(&rq->nr_iowait);
schedule();
atomic_dec(&rq->nr_iowait);
+ delayacct_blkio_end();
}
EXPORT_SYMBOL(io_schedule);
@@ -4537,9 +4575,11 @@ long __sched io_schedule_timeout(long timeout)
struct rq *rq = &__raw_get_cpu_var(runqueues);
long ret;
+ delayacct_blkio_start();
atomic_inc(&rq->nr_iowait);
ret = schedule_timeout(timeout);
atomic_dec(&rq->nr_iowait);
+ delayacct_blkio_end();
return ret;
}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index fd12f2556f0..0f08a84ae30 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -311,8 +311,6 @@ void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
softirq_vec[nr].action = action;
}
-EXPORT_UNUSED_SYMBOL(open_softirq); /* June 2006 */
-
/* Tasklets */
struct tasklet_head
{
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
new file mode 100644
index 00000000000..f45179ce028
--- /dev/null
+++ b/kernel/taskstats.c
@@ -0,0 +1,568 @@
+/*
+ * taskstats.c - Export per-task statistics to userland
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2006
+ * (C) Balbir Singh, IBM Corp. 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/taskstats_kern.h>
+#include <linux/delayacct.h>
+#include <linux/cpumask.h>
+#include <linux/percpu.h>
+#include <net/genetlink.h>
+#include <asm/atomic.h>
+
+/*
+ * Maximum length of a cpumask that can be specified in
+ * the TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK attribute
+ */
+#define TASKSTATS_CPUMASK_MAXLEN (100+6*NR_CPUS)
+
+static DEFINE_PER_CPU(__u32, taskstats_seqnum) = { 0 };
+static int family_registered;
+kmem_cache_t *taskstats_cache;
+
+static struct genl_family family = {
+ .id = GENL_ID_GENERATE,
+ .name = TASKSTATS_GENL_NAME,
+ .version = TASKSTATS_GENL_VERSION,
+ .maxattr = TASKSTATS_CMD_ATTR_MAX,
+};
+
+static struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1]
+__read_mostly = {
+ [TASKSTATS_CMD_ATTR_PID] = { .type = NLA_U32 },
+ [TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
+ [TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
+ [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
+
+struct listener {
+ struct list_head list;
+ pid_t pid;
+ char valid;
+};
+
+struct listener_list {
+ struct rw_semaphore sem;
+ struct list_head list;
+};
+static DEFINE_PER_CPU(struct listener_list, listener_array);
+
+enum actions {
+ REGISTER,
+ DEREGISTER,
+ CPU_DONT_CARE
+};
+
+static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
+ void **replyp, size_t size)
+{
+ struct sk_buff *skb;
+ void *reply;
+
+ /*
+ * If new attributes are added, please revisit this allocation
+ */
+ skb = nlmsg_new(size);
+ if (!skb)
+ return -ENOMEM;
+
+ if (!info) {
+ int seq = get_cpu_var(taskstats_seqnum)++;
+ put_cpu_var(taskstats_seqnum);
+
+ reply = genlmsg_put(skb, 0, seq,
+ family.id, 0, 0,
+ cmd, family.version);
+ } else
+ reply = genlmsg_put(skb, info->snd_pid, info->snd_seq,
+ family.id, 0, 0,
+ cmd, family.version);
+ if (reply == NULL) {
+ nlmsg_free(skb);
+ return -EINVAL;
+ }
+
+ *skbp = skb;
+ *replyp = reply;
+ return 0;
+}
+
+/*
+ * Send taskstats data in @skb to listener with nl_pid @pid
+ */
+static int send_reply(struct sk_buff *skb, pid_t pid)
+{
+ struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
+ void *reply = genlmsg_data(genlhdr);
+ int rc;
+
+ rc = genlmsg_end(skb, reply);
+ if (rc < 0) {
+ nlmsg_free(skb);
+ return rc;
+ }
+
+ return genlmsg_unicast(skb, pid);
+}
+
+/*
+ * Send taskstats data in @skb to listeners registered for @cpu's exit data
+ */
+static int send_cpu_listeners(struct sk_buff *skb, unsigned int cpu)
+{
+ struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
+ struct listener_list *listeners;
+ struct listener *s, *tmp;
+ struct sk_buff *skb_next, *skb_cur = skb;
+ void *reply = genlmsg_data(genlhdr);
+ int rc, ret, delcount = 0;
+
+ rc = genlmsg_end(skb, reply);
+ if (rc < 0) {
+ nlmsg_free(skb);
+ return rc;
+ }
+
+ rc = 0;
+ listeners = &per_cpu(listener_array, cpu);
+ down_read(&listeners->sem);
+ list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+ skb_next = NULL;
+ if (!list_is_last(&s->list, &listeners->list)) {
+ skb_next = skb_clone(skb_cur, GFP_KERNEL);
+ if (!skb_next) {
+ nlmsg_free(skb_cur);
+ rc = -ENOMEM;
+ break;
+ }
+ }
+ ret = genlmsg_unicast(skb_cur, s->pid);
+ if (ret == -ECONNREFUSED) {
+ s->valid = 0;
+ delcount++;
+ rc = ret;
+ }
+ skb_cur = skb_next;
+ }
+ up_read(&listeners->sem);
+
+ if (!delcount)
+ return rc;
+
+ /* Delete invalidated entries */
+ down_write(&listeners->sem);
+ list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+ if (!s->valid) {
+ list_del(&s->list);
+ kfree(s);
+ }
+ }
+ up_write(&listeners->sem);
+ return rc;
+}
+
+static int fill_pid(pid_t pid, struct task_struct *pidtsk,
+ struct taskstats *stats)
+{
+ int rc;
+ struct task_struct *tsk = pidtsk;
+
+ if (!pidtsk) {
+ read_lock(&tasklist_lock);
+ tsk = find_task_by_pid(pid);
+ if (!tsk) {
+ read_unlock(&tasklist_lock);
+ return -ESRCH;
+ }
+ get_task_struct(tsk);
+ read_unlock(&tasklist_lock);
+ } else
+ get_task_struct(tsk);
+
+ /*
+ * Each accounting subsystem adds calls to its functions to
+ * fill in relevant parts of struct taskstsats as follows
+ *
+ * rc = per-task-foo(stats, tsk);
+ * if (rc)
+ * goto err;
+ */
+
+ rc = delayacct_add_tsk(stats, tsk);
+ stats->version = TASKSTATS_VERSION;
+
+ /* Define err: label here if needed */
+ put_task_struct(tsk);
+ return rc;
+
+}
+
+static int fill_tgid(pid_t tgid, struct task_struct *tgidtsk,
+ struct taskstats *stats)
+{
+ struct task_struct *tsk, *first;
+ unsigned long flags;
+
+ /*
+ * Add additional stats from live tasks except zombie thread group
+ * leaders who are already counted with the dead tasks
+ */
+ first = tgidtsk;
+ if (!first) {
+ read_lock(&tasklist_lock);
+ first = find_task_by_pid(tgid);
+ if (!first) {
+ read_unlock(&tasklist_lock);
+ return -ESRCH;
+ }
+ get_task_struct(first);
+ read_unlock(&tasklist_lock);
+ } else
+ get_task_struct(first);
+
+ /* Start with stats from dead tasks */
+ spin_lock_irqsave(&first->signal->stats_lock, flags);
+ if (first->signal->stats)
+ memcpy(stats, first->signal->stats, sizeof(*stats));
+ spin_unlock_irqrestore(&first->signal->stats_lock, flags);
+
+ tsk = first;
+ read_lock(&tasklist_lock);
+ do {
+ if (tsk->exit_state == EXIT_ZOMBIE && thread_group_leader(tsk))
+ continue;
+ /*
+ * Accounting subsystem can call its functions here to
+ * fill in relevant parts of struct taskstsats as follows
+ *
+ * per-task-foo(stats, tsk);
+ */
+ delayacct_add_tsk(stats, tsk);
+
+ } while_each_thread(first, tsk);
+ read_unlock(&tasklist_lock);
+ stats->version = TASKSTATS_VERSION;
+
+ /*
+ * Accounting subsytems can also add calls here to modify
+ * fields of taskstats.
+ */
+
+ return 0;
+}
+
+
+static void fill_tgid_exit(struct task_struct *tsk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&tsk->signal->stats_lock, flags);
+ if (!tsk->signal->stats)
+ goto ret;
+
+ /*
+ * Each accounting subsystem calls its functions here to
+ * accumalate its per-task stats for tsk, into the per-tgid structure
+ *
+ * per-task-foo(tsk->signal->stats, tsk);
+ */
+ delayacct_add_tsk(tsk->signal->stats, tsk);
+ret:
+ spin_unlock_irqrestore(&tsk->signal->stats_lock, flags);
+ return;
+}
+
+static int add_del_listener(pid_t pid, cpumask_t *maskp, int isadd)
+{
+ struct listener_list *listeners;
+ struct listener *s, *tmp;
+ unsigned int cpu;
+ cpumask_t mask = *maskp;
+
+ if (!cpus_subset(mask, cpu_possible_map))
+ return -EINVAL;
+
+ if (isadd == REGISTER) {
+ for_each_cpu_mask(cpu, mask) {
+ s = kmalloc_node(sizeof(struct listener), GFP_KERNEL,
+ cpu_to_node(cpu));
+ if (!s)
+ goto cleanup;
+ s->pid = pid;
+ INIT_LIST_HEAD(&s->list);
+ s->valid = 1;
+
+ listeners = &per_cpu(listener_array, cpu);
+ down_write(&listeners->sem);
+ list_add(&s->list, &listeners->list);
+ up_write(&listeners->sem);
+ }
+ return 0;
+ }
+
+ /* Deregister or cleanup */
+cleanup:
+ for_each_cpu_mask(cpu, mask) {
+ listeners = &per_cpu(listener_array, cpu);
+ down_write(&listeners->sem);
+ list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+ if (s->pid == pid) {
+ list_del(&s->list);
+ kfree(s);
+ break;
+ }
+ }
+ up_write(&listeners->sem);
+ }
+ return 0;
+}
+
+static int parse(struct nlattr *na, cpumask_t *mask)
+{
+ char *data;
+ int len;
+ int ret;
+
+ if (na == NULL)
+ return 1;
+ len = nla_len(na);
+ if (len > TASKSTATS_CPUMASK_MAXLEN)
+ return -E2BIG;
+ if (len < 1)
+ return -EINVAL;
+ data = kmalloc(len, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ nla_strlcpy(data, na, len);
+ ret = cpulist_parse(data, *mask);
+ kfree(data);
+ return ret;
+}
+
+static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+ int rc = 0;
+ struct sk_buff *rep_skb;
+ struct taskstats stats;
+ void *reply;
+ size_t size;
+ struct nlattr *na;
+ cpumask_t mask;
+
+ rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], &mask);
+ if (rc < 0)
+ return rc;
+ if (rc == 0)
+ return add_del_listener(info->snd_pid, &mask, REGISTER);
+
+ rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], &mask);
+ if (rc < 0)
+ return rc;
+ if (rc == 0)
+ return add_del_listener(info->snd_pid, &mask, DEREGISTER);
+
+ /*
+ * Size includes space for nested attributes
+ */
+ size = nla_total_size(sizeof(u32)) +
+ nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+
+ memset(&stats, 0, sizeof(stats));
+ rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, &reply, size);
+ if (rc < 0)
+ return rc;
+
+ if (info->attrs[TASKSTATS_CMD_ATTR_PID]) {
+ u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
+ rc = fill_pid(pid, NULL, &stats);
+ if (rc < 0)
+ goto err;
+
+ na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_PID);
+ NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_PID, pid);
+ NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS,
+ stats);
+ } else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) {
+ u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
+ rc = fill_tgid(tgid, NULL, &stats);
+ if (rc < 0)
+ goto err;
+
+ na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_TGID);
+ NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_TGID, tgid);
+ NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS,
+ stats);
+ } else {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ nla_nest_end(rep_skb, na);
+
+ return send_reply(rep_skb, info->snd_pid);
+
+nla_put_failure:
+ return genlmsg_cancel(rep_skb, reply);
+err:
+ nlmsg_free(rep_skb);
+ return rc;
+}
+
+void taskstats_exit_alloc(struct taskstats **ptidstats, unsigned int *mycpu)
+{
+ struct listener_list *listeners;
+ struct taskstats *tmp;
+ /*
+ * This is the cpu on which the task is exiting currently and will
+ * be the one for which the exit event is sent, even if the cpu
+ * on which this function is running changes later.
+ */
+ *mycpu = raw_smp_processor_id();
+
+ *ptidstats = NULL;
+ tmp = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL);
+ if (!tmp)
+ return;
+
+ listeners = &per_cpu(listener_array, *mycpu);
+ down_read(&listeners->sem);
+ if (!list_empty(&listeners->list)) {
+ *ptidstats = tmp;
+ tmp = NULL;
+ }
+ up_read(&listeners->sem);
+ kfree(tmp);
+}
+
+/* Send pid data out on exit */
+void taskstats_exit_send(struct task_struct *tsk, struct taskstats *tidstats,
+ int group_dead, unsigned int mycpu)
+{
+ int rc;
+ struct sk_buff *rep_skb;
+ void *reply;
+ size_t size;
+ int is_thread_group;
+ struct nlattr *na;
+ unsigned long flags;
+
+ if (!family_registered || !tidstats)
+ return;
+
+ spin_lock_irqsave(&tsk->signal->stats_lock, flags);
+ is_thread_group = tsk->signal->stats ? 1 : 0;
+ spin_unlock_irqrestore(&tsk->signal->stats_lock, flags);
+
+ rc = 0;
+ /*
+ * Size includes space for nested attributes
+ */
+ size = nla_total_size(sizeof(u32)) +
+ nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+
+ if (is_thread_group)
+ size = 2 * size; /* PID + STATS + TGID + STATS */
+
+ rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, &reply, size);
+ if (rc < 0)
+ goto ret;
+
+ rc = fill_pid(tsk->pid, tsk, tidstats);
+ if (rc < 0)
+ goto err_skb;
+
+ na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_PID);
+ NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_PID, (u32)tsk->pid);
+ NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS,
+ *tidstats);
+ nla_nest_end(rep_skb, na);
+
+ if (!is_thread_group)
+ goto send;
+
+ /*
+ * tsk has/had a thread group so fill the tsk->signal->stats structure
+ * Doesn't matter if tsk is the leader or the last group member leaving
+ */
+
+ fill_tgid_exit(tsk);
+ if (!group_dead)
+ goto send;
+
+ na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_TGID);
+ NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_TGID, (u32)tsk->tgid);
+ /* No locking needed for tsk->signal->stats since group is dead */
+ NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS,
+ *tsk->signal->stats);
+ nla_nest_end(rep_skb, na);
+
+send:
+ send_cpu_listeners(rep_skb, mycpu);
+ return;
+
+nla_put_failure:
+ genlmsg_cancel(rep_skb, reply);
+ goto ret;
+err_skb:
+ nlmsg_free(rep_skb);
+ret:
+ return;
+}
+
+static struct genl_ops taskstats_ops = {
+ .cmd = TASKSTATS_CMD_GET,
+ .doit = taskstats_user_cmd,
+ .policy = taskstats_cmd_get_policy,
+};
+
+/* Needed early in initialization */
+void __init taskstats_init_early(void)
+{
+ unsigned int i;
+
+ taskstats_cache = kmem_cache_create("taskstats_cache",
+ sizeof(struct taskstats),
+ 0, SLAB_PANIC, NULL, NULL);
+ for_each_possible_cpu(i) {
+ INIT_LIST_HEAD(&(per_cpu(listener_array, i).list));
+ init_rwsem(&(per_cpu(listener_array, i).sem));
+ }
+}
+
+static int __init taskstats_init(void)
+{
+ int rc;
+
+ rc = genl_register_family(&family);
+ if (rc)
+ return rc;
+
+ rc = genl_register_ops(&family, &taskstats_ops);
+ if (rc < 0)
+ goto err;
+
+ family_registered = 1;
+ return 0;
+err:
+ genl_unregister_family(&family);
+ return rc;
+}
+
+/*
+ * late initcall ensures initialization of statistics collection
+ * mechanisms precedes initialization of the taskstats interface
+ */
+late_initcall(taskstats_init);
diff --git a/kernel/timer.c b/kernel/timer.c
index 2a87430a58d..05809c2e2fd 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -374,6 +374,7 @@ int del_timer_sync(struct timer_list *timer)
int ret = try_to_del_timer_sync(timer);
if (ret >= 0)
return ret;
+ cpu_relax();
}
}
@@ -968,6 +969,7 @@ void __init timekeeping_init(void)
}
+static int timekeeping_suspended;
/*
* timekeeping_resume - Resumes the generic timekeeping subsystem.
* @dev: unused
@@ -983,6 +985,18 @@ static int timekeeping_resume(struct sys_device *dev)
write_seqlock_irqsave(&xtime_lock, flags);
/* restart the last cycle value */
clock->cycle_last = clocksource_read(clock);
+ clock->error = 0;
+ timekeeping_suspended = 0;
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+ return 0;
+}
+
+static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
+{
+ unsigned long flags;
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+ timekeeping_suspended = 1;
write_sequnlock_irqrestore(&xtime_lock, flags);
return 0;
}
@@ -990,6 +1004,7 @@ static int timekeeping_resume(struct sys_device *dev)
/* sysfs resume/suspend bits for timekeeping */
static struct sysdev_class timekeeping_sysclass = {
.resume = timekeeping_resume,
+ .suspend = timekeeping_suspend,
set_kset_name("timekeeping"),
};
@@ -1100,13 +1115,16 @@ static void update_wall_time(void)
{
cycle_t offset;
- clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;
+ /* Make sure we're fully resumed: */
+ if (unlikely(timekeeping_suspended))
+ return;
#ifdef CONFIG_GENERIC_TIME
offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask;
#else
offset = clock->cycle_interval;
#endif
+ clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;
/* normally this loop will run just once, however in the
* case of lost or late ticks, it will accumulate correctly.
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index e5889b1a33f..554ee688a9f 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -158,7 +158,7 @@ config DEBUG_RWSEMS
config DEBUG_LOCK_ALLOC
bool "Lock debugging: detect incorrect freeing of live locks"
- depends on TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
+ depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
select DEBUG_SPINLOCK
select DEBUG_MUTEXES
select DEBUG_RWSEMS
@@ -173,7 +173,7 @@ config DEBUG_LOCK_ALLOC
config PROVE_LOCKING
bool "Lock debugging: prove locking correctness"
- depends on TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
+ depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
select LOCKDEP
select DEBUG_SPINLOCK
select DEBUG_MUTEXES
@@ -216,7 +216,7 @@ config PROVE_LOCKING
config LOCKDEP
bool
- depends on TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
+ depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
select STACKTRACE
select FRAME_POINTER
select KALLSYMS
@@ -224,13 +224,14 @@ config LOCKDEP
config DEBUG_LOCKDEP
bool "Lock dependency engine debugging"
- depends on LOCKDEP
+ depends on DEBUG_KERNEL && LOCKDEP
help
If you say Y here, the lock dependency engine will do
additional runtime checks to debug itself, at the price
of more runtime overhead.
config TRACE_IRQFLAGS
+ depends on DEBUG_KERNEL
bool
default y
depends on TRACE_IRQFLAGS_SUPPORT
@@ -256,6 +257,7 @@ config DEBUG_LOCKING_API_SELFTESTS
config STACKTRACE
bool
+ depends on DEBUG_KERNEL
depends on STACKTRACE_SUPPORT
config DEBUG_KOBJECT
diff --git a/lib/idr.c b/lib/idr.c
index 4d096819511..16d2143fea4 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -38,14 +38,15 @@ static kmem_cache_t *idr_layer_cache;
static struct idr_layer *alloc_layer(struct idr *idp)
{
struct idr_layer *p;
+ unsigned long flags;
- spin_lock(&idp->lock);
+ spin_lock_irqsave(&idp->lock, flags);
if ((p = idp->id_free)) {
idp->id_free = p->ary[0];
idp->id_free_cnt--;
p->ary[0] = NULL;
}
- spin_unlock(&idp->lock);
+ spin_unlock_irqrestore(&idp->lock, flags);
return(p);
}
@@ -59,12 +60,14 @@ static void __free_layer(struct idr *idp, struct idr_layer *p)
static void free_layer(struct idr *idp, struct idr_layer *p)
{
+ unsigned long flags;
+
/*
* Depends on the return element being zeroed.
*/
- spin_lock(&idp->lock);
+ spin_lock_irqsave(&idp->lock, flags);
__free_layer(idp, p);
- spin_unlock(&idp->lock);
+ spin_unlock_irqrestore(&idp->lock, flags);
}
/**
@@ -168,6 +171,7 @@ static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
{
struct idr_layer *p, *new;
int layers, v, id;
+ unsigned long flags;
id = starting_id;
build_up:
@@ -191,14 +195,14 @@ build_up:
* The allocation failed. If we built part of
* the structure tear it down.
*/
- spin_lock(&idp->lock);
+ spin_lock_irqsave(&idp->lock, flags);
for (new = p; p && p != idp->top; new = p) {
p = p->ary[0];
new->ary[0] = NULL;
new->bitmap = new->count = 0;
__free_layer(idp, new);
}
- spin_unlock(&idp->lock);
+ spin_unlock_irqrestore(&idp->lock, flags);
return -1;
}
new->ary[0] = p;
diff --git a/mm/memory.c b/mm/memory.c
index dc0d82cf2a1..109e9866237 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -47,6 +47,7 @@
#include <linux/pagemap.h>
#include <linux/rmap.h>
#include <linux/module.h>
+#include <linux/delayacct.h>
#include <linux/init.h>
#include <asm/pgalloc.h>
@@ -1549,9 +1550,9 @@ gotten:
flush_cache_page(vma, address, pte_pfn(orig_pte));
entry = mk_pte(new_page, vma->vm_page_prot);
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
+ lazy_mmu_prot_update(entry);
ptep_establish(vma, address, page_table, entry);
update_mmu_cache(vma, address, entry);
- lazy_mmu_prot_update(entry);
lru_cache_add_active(new_page);
page_add_new_anon_rmap(new_page, vma, address);
@@ -1934,6 +1935,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
migration_entry_wait(mm, pmd, address);
goto out;
}
+ delayacct_set_flag(DELAYACCT_PF_SWAPIN);
page = lookup_swap_cache(entry);
if (!page) {
swapin_readahead(entry, address, vma);
@@ -1946,6 +1948,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
if (likely(pte_same(*page_table, orig_pte)))
ret = VM_FAULT_OOM;
+ delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
goto unlock;
}
@@ -1955,6 +1958,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
grab_swap_token();
}
+ delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
mark_page_accessed(page);
lock_page(page);
diff --git a/mm/nommu.c b/mm/nommu.c
index 5151c44a825..c576df71e3b 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1070,6 +1070,7 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
vma->vm_start = vma->vm_pgoff << PAGE_SHIFT;
return 0;
}
+EXPORT_SYMBOL(remap_pfn_range);
void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
{
@@ -1090,6 +1091,7 @@ void unmap_mapping_range(struct address_space *mapping,
int even_cows)
{
}
+EXPORT_SYMBOL(unmap_mapping_range);
/*
* Check that a process has enough memory to allocate a new virtual
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 7b450798b45..266162d2ba2 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -340,7 +340,7 @@ void __vunmap(void *addr, int deallocate_pages)
__free_page(area->pages[i]);
}
- if (area->nr_pages > PAGE_SIZE/sizeof(struct page *))
+ if (area->flags & VM_VPAGES)
vfree(area->pages);
else
kfree(area->pages);
@@ -427,9 +427,10 @@ void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
area->nr_pages = nr_pages;
/* Please note that the recursion is strictly bounded. */
- if (array_size > PAGE_SIZE)
+ if (array_size > PAGE_SIZE) {
pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node);
- else
+ area->flags |= VM_VPAGES;
+ } else
pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node);
area->pages = pages;
if (!area->pages) {
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 44f6a181a75..476aa397850 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -257,11 +257,11 @@ nodata:
}
-static void skb_drop_fraglist(struct sk_buff *skb)
+static void skb_drop_list(struct sk_buff **listp)
{
- struct sk_buff *list = skb_shinfo(skb)->frag_list;
+ struct sk_buff *list = *listp;
- skb_shinfo(skb)->frag_list = NULL;
+ *listp = NULL;
do {
struct sk_buff *this = list;
@@ -270,6 +270,11 @@ static void skb_drop_fraglist(struct sk_buff *skb)
} while (list);
}
+static inline void skb_drop_fraglist(struct sk_buff *skb)
+{
+ skb_drop_list(&skb_shinfo(skb)->frag_list);
+}
+
static void skb_clone_fraglist(struct sk_buff *skb)
{
struct sk_buff *list;
@@ -830,41 +835,75 @@ free_skb:
int ___pskb_trim(struct sk_buff *skb, unsigned int len)
{
+ struct sk_buff **fragp;
+ struct sk_buff *frag;
int offset = skb_headlen(skb);
int nfrags = skb_shinfo(skb)->nr_frags;
int i;
+ int err;
+
+ if (skb_cloned(skb) &&
+ unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))))
+ return err;
for (i = 0; i < nfrags; i++) {
int end = offset + skb_shinfo(skb)->frags[i].size;
- if (end > len) {
- if (skb_cloned(skb)) {
- if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
- return -ENOMEM;
- }
- if (len <= offset) {
- put_page(skb_shinfo(skb)->frags[i].page);
- skb_shinfo(skb)->nr_frags--;
- } else {
- skb_shinfo(skb)->frags[i].size = len - offset;
- }
+
+ if (end < len) {
+ offset = end;
+ continue;
}
- offset = end;
+
+ if (len > offset)
+ skb_shinfo(skb)->frags[i++].size = len - offset;
+
+ skb_shinfo(skb)->nr_frags = i;
+
+ for (; i < nfrags; i++)
+ put_page(skb_shinfo(skb)->frags[i].page);
+
+ if (skb_shinfo(skb)->frag_list)
+ skb_drop_fraglist(skb);
+ break;
}
- if (offset < len) {
+ for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp);
+ fragp = &frag->next) {
+ int end = offset + frag->len;
+
+ if (skb_shared(frag)) {
+ struct sk_buff *nfrag;
+
+ nfrag = skb_clone(frag, GFP_ATOMIC);
+ if (unlikely(!nfrag))
+ return -ENOMEM;
+
+ nfrag->next = frag->next;
+ frag = nfrag;
+ *fragp = frag;
+ }
+
+ if (end < len) {
+ offset = end;
+ continue;
+ }
+
+ if (end > len &&
+ unlikely((err = pskb_trim(frag, len - offset))))
+ return err;
+
+ if (frag->next)
+ skb_drop_list(&frag->next);
+ break;
+ }
+
+ if (len > skb_headlen(skb)) {
skb->data_len -= skb->len - len;
skb->len = len;
} else {
- if (len <= skb_headlen(skb)) {
- skb->len = len;
- skb->data_len = 0;
- skb->tail = skb->data + len;
- if (skb_shinfo(skb)->frag_list && !skb_cloned(skb))
- skb_drop_fraglist(skb);
- } else {
- skb->data_len -= skb->len - len;
- skb->len = len;
- }
+ skb->len = len;
+ skb->data_len = 0;
+ skb->tail = skb->data + len;
}
return 0;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index e1a7dba2fa8..184c78ca79e 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -428,6 +428,9 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
goto drop;
}
+ /* Remove any debris in the socket control block */
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+
return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
ip_rcv_finish);
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 34afe41fa2f..cd0a973b112 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -196,7 +196,7 @@ struct htb_class
struct qdisc_rate_table *rate; /* rate table of the class itself */
struct qdisc_rate_table *ceil; /* ceiling rate (limits borrows too) */
long buffer,cbuffer; /* token bucket depth/rate */
- long mbuffer; /* max wait time */
+ psched_tdiff_t mbuffer; /* max wait time */
long tokens,ctokens; /* current number of tokens */
psched_time_t t_c; /* checkpoint time */
};
@@ -1601,7 +1601,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
/* set class to be in HTB_CAN_SEND state */
cl->tokens = hopt->buffer;
cl->ctokens = hopt->cbuffer;
- cl->mbuffer = 60000000; /* 1min */
+ cl->mbuffer = PSCHED_JIFFIE2US(HZ*60) /* 1min */
PSCHED_GET_TIME(cl->t_c);
cl->cmode = HTB_CAN_SEND;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 2e8b4dfcbc7..a91c961ba38 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -523,12 +523,16 @@ static int try_context_mount(struct super_block *sb, void *data)
goto out_free;
}
- rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
- if (rc)
- goto out_free;
-
- if (!fscontext)
+ if (!fscontext) {
+ rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
+ if (rc)
+ goto out_free;
sbsec->sid = sid;
+ } else {
+ rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+ if (rc)
+ goto out_free;
+ }
sbsec->mntpoint_sid = sid;
sbsec->behavior = SECURITY_FS_USE_MNTPOINT;