diff options
428 files changed, 17256 insertions, 10604 deletions
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt index 9691c7f5166c..0705040531a5 100644 --- a/Documentation/kdump/kdump.txt +++ b/Documentation/kdump/kdump.txt | |||
@@ -65,26 +65,26 @@ Install kexec-tools | |||
65 | 65 | ||
66 | 2) Download the kexec-tools user-space package from the following URL: | 66 | 2) Download the kexec-tools user-space package from the following URL: |
67 | 67 | ||
68 | http://www.kernel.org/pub/linux/kernel/people/horms/kexec-tools/kexec-tools-testing.tar.gz | 68 | http://www.kernel.org/pub/linux/kernel/people/horms/kexec-tools/kexec-tools.tar.gz |
69 | 69 | ||
70 | This is a symlink to the latest version, which at the time of writing is | 70 | This is a symlink to the latest version. |
71 | 20061214, the only release of kexec-tools-testing so far. As other versions | ||
72 | are released, the older ones will remain available at | ||
73 | http://www.kernel.org/pub/linux/kernel/people/horms/kexec-tools/ | ||
74 | 71 | ||
75 | Note: Latest kexec-tools-testing git tree is available at | 72 | The latest kexec-tools git tree is available at: |
76 | 73 | ||
77 | git://git.kernel.org/pub/scm/linux/kernel/git/horms/kexec-tools-testing.git | 74 | git://git.kernel.org/pub/scm/linux/kernel/git/horms/kexec-tools.git |
78 | or | 75 | or |
79 | http://www.kernel.org/git/?p=linux/kernel/git/horms/kexec-tools-testing.git;a=summary | 76 | http://www.kernel.org/git/?p=linux/kernel/git/horms/kexec-tools.git |
77 | |||
78 | More information about kexec-tools can be found at | ||
79 | http://www.kernel.org/pub/linux/kernel/people/horms/kexec-tools/README.html | ||
80 | 80 | ||
81 | 3) Unpack the tarball with the tar command, as follows: | 81 | 3) Unpack the tarball with the tar command, as follows: |
82 | 82 | ||
83 | tar xvpzf kexec-tools-testing.tar.gz | 83 | tar xvpzf kexec-tools.tar.gz |
84 | 84 | ||
85 | 4) Change to the kexec-tools directory, as follows: | 85 | 4) Change to the kexec-tools directory, as follows: |
86 | 86 | ||
87 | cd kexec-tools-testing-VERSION | 87 | cd kexec-tools-VERSION |
88 | 88 | ||
89 | 5) Configure the package, as follows: | 89 | 5) Configure the package, as follows: |
90 | 90 | ||
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index 82fafe0429fe..b88b0ea54e90 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c | |||
@@ -36,11 +36,13 @@ | |||
36 | #include <sched.h> | 36 | #include <sched.h> |
37 | #include <limits.h> | 37 | #include <limits.h> |
38 | #include <stddef.h> | 38 | #include <stddef.h> |
39 | #include <signal.h> | ||
39 | #include "linux/lguest_launcher.h" | 40 | #include "linux/lguest_launcher.h" |
40 | #include "linux/virtio_config.h" | 41 | #include "linux/virtio_config.h" |
41 | #include "linux/virtio_net.h" | 42 | #include "linux/virtio_net.h" |
42 | #include "linux/virtio_blk.h" | 43 | #include "linux/virtio_blk.h" |
43 | #include "linux/virtio_console.h" | 44 | #include "linux/virtio_console.h" |
45 | #include "linux/virtio_rng.h" | ||
44 | #include "linux/virtio_ring.h" | 46 | #include "linux/virtio_ring.h" |
45 | #include "asm-x86/bootparam.h" | 47 | #include "asm-x86/bootparam.h" |
46 | /*L:110 We can ignore the 39 include files we need for this program, but I do | 48 | /*L:110 We can ignore the 39 include files we need for this program, but I do |
@@ -64,8 +66,8 @@ typedef uint8_t u8; | |||
64 | #endif | 66 | #endif |
65 | /* We can have up to 256 pages for devices. */ | 67 | /* We can have up to 256 pages for devices. */ |
66 | #define DEVICE_PAGES 256 | 68 | #define DEVICE_PAGES 256 |
67 | /* This will occupy 2 pages: it must be a power of 2. */ | 69 | /* This will occupy 3 pages: it must be a power of 2. */ |
68 | #define VIRTQUEUE_NUM 128 | 70 | #define VIRTQUEUE_NUM 256 |
69 | 71 | ||
70 | /*L:120 verbose is both a global flag and a macro. The C preprocessor allows | 72 | /*L:120 verbose is both a global flag and a macro. The C preprocessor allows |
71 | * this, and although I wouldn't recommend it, it works quite nicely here. */ | 73 | * this, and although I wouldn't recommend it, it works quite nicely here. */ |
@@ -74,12 +76,19 @@ static bool verbose; | |||
74 | do { if (verbose) printf(args); } while(0) | 76 | do { if (verbose) printf(args); } while(0) |
75 | /*:*/ | 77 | /*:*/ |
76 | 78 | ||
77 | /* The pipe to send commands to the waker process */ | 79 | /* File descriptors for the Waker. */ |
78 | static int waker_fd; | 80 | struct { |
81 | int pipe[2]; | ||
82 | int lguest_fd; | ||
83 | } waker_fds; | ||
84 | |||
79 | /* The pointer to the start of guest memory. */ | 85 | /* The pointer to the start of guest memory. */ |
80 | static void *guest_base; | 86 | static void *guest_base; |
81 | /* The maximum guest physical address allowed, and maximum possible. */ | 87 | /* The maximum guest physical address allowed, and maximum possible. */ |
82 | static unsigned long guest_limit, guest_max; | 88 | static unsigned long guest_limit, guest_max; |
89 | /* The pipe for signal hander to write to. */ | ||
90 | static int timeoutpipe[2]; | ||
91 | static unsigned int timeout_usec = 500; | ||
83 | 92 | ||
84 | /* a per-cpu variable indicating whose vcpu is currently running */ | 93 | /* a per-cpu variable indicating whose vcpu is currently running */ |
85 | static unsigned int __thread cpu_id; | 94 | static unsigned int __thread cpu_id; |
@@ -155,11 +164,14 @@ struct virtqueue | |||
155 | /* Last available index we saw. */ | 164 | /* Last available index we saw. */ |
156 | u16 last_avail_idx; | 165 | u16 last_avail_idx; |
157 | 166 | ||
158 | /* The routine to call when the Guest pings us. */ | 167 | /* The routine to call when the Guest pings us, or timeout. */ |
159 | void (*handle_output)(int fd, struct virtqueue *me); | 168 | void (*handle_output)(int fd, struct virtqueue *me, bool timeout); |
160 | 169 | ||
161 | /* Outstanding buffers */ | 170 | /* Outstanding buffers */ |
162 | unsigned int inflight; | 171 | unsigned int inflight; |
172 | |||
173 | /* Is this blocked awaiting a timer? */ | ||
174 | bool blocked; | ||
163 | }; | 175 | }; |
164 | 176 | ||
165 | /* Remember the arguments to the program so we can "reboot" */ | 177 | /* Remember the arguments to the program so we can "reboot" */ |
@@ -190,6 +202,9 @@ static void *_convert(struct iovec *iov, size_t size, size_t align, | |||
190 | return iov->iov_base; | 202 | return iov->iov_base; |
191 | } | 203 | } |
192 | 204 | ||
205 | /* Wrapper for the last available index. Makes it easier to change. */ | ||
206 | #define lg_last_avail(vq) ((vq)->last_avail_idx) | ||
207 | |||
193 | /* The virtio configuration space is defined to be little-endian. x86 is | 208 | /* The virtio configuration space is defined to be little-endian. x86 is |
194 | * little-endian too, but it's nice to be explicit so we have these helpers. */ | 209 | * little-endian too, but it's nice to be explicit so we have these helpers. */ |
195 | #define cpu_to_le16(v16) (v16) | 210 | #define cpu_to_le16(v16) (v16) |
@@ -199,6 +214,33 @@ static void *_convert(struct iovec *iov, size_t size, size_t align, | |||
199 | #define le32_to_cpu(v32) (v32) | 214 | #define le32_to_cpu(v32) (v32) |
200 | #define le64_to_cpu(v64) (v64) | 215 | #define le64_to_cpu(v64) (v64) |
201 | 216 | ||
217 | /* Is this iovec empty? */ | ||
218 | static bool iov_empty(const struct iovec iov[], unsigned int num_iov) | ||
219 | { | ||
220 | unsigned int i; | ||
221 | |||
222 | for (i = 0; i < num_iov; i++) | ||
223 | if (iov[i].iov_len) | ||
224 | return false; | ||
225 | return true; | ||
226 | } | ||
227 | |||
228 | /* Take len bytes from the front of this iovec. */ | ||
229 | static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) | ||
230 | { | ||
231 | unsigned int i; | ||
232 | |||
233 | for (i = 0; i < num_iov; i++) { | ||
234 | unsigned int used; | ||
235 | |||
236 | used = iov[i].iov_len < len ? iov[i].iov_len : len; | ||
237 | iov[i].iov_base += used; | ||
238 | iov[i].iov_len -= used; | ||
239 | len -= used; | ||
240 | } | ||
241 | assert(len == 0); | ||
242 | } | ||
243 | |||
202 | /* The device virtqueue descriptors are followed by feature bitmasks. */ | 244 | /* The device virtqueue descriptors are followed by feature bitmasks. */ |
203 | static u8 *get_feature_bits(struct device *dev) | 245 | static u8 *get_feature_bits(struct device *dev) |
204 | { | 246 | { |
@@ -254,6 +296,7 @@ static void *map_zeroed_pages(unsigned int num) | |||
254 | PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0); | 296 | PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0); |
255 | if (addr == MAP_FAILED) | 297 | if (addr == MAP_FAILED) |
256 | err(1, "Mmaping %u pages of /dev/zero", num); | 298 | err(1, "Mmaping %u pages of /dev/zero", num); |
299 | close(fd); | ||
257 | 300 | ||
258 | return addr; | 301 | return addr; |
259 | } | 302 | } |
@@ -540,69 +583,64 @@ static void add_device_fd(int fd) | |||
540 | * watch, but handing a file descriptor mask through to the kernel is fairly | 583 | * watch, but handing a file descriptor mask through to the kernel is fairly |
541 | * icky. | 584 | * icky. |
542 | * | 585 | * |
543 | * Instead, we fork off a process which watches the file descriptors and writes | 586 | * Instead, we clone off a thread which watches the file descriptors and writes |
544 | * the LHREQ_BREAK command to the /dev/lguest file descriptor to tell the Host | 587 | * the LHREQ_BREAK command to the /dev/lguest file descriptor to tell the Host |
545 | * stop running the Guest. This causes the Launcher to return from the | 588 | * stop running the Guest. This causes the Launcher to return from the |
546 | * /dev/lguest read with -EAGAIN, where it will write to /dev/lguest to reset | 589 | * /dev/lguest read with -EAGAIN, where it will write to /dev/lguest to reset |
547 | * the LHREQ_BREAK and wake us up again. | 590 | * the LHREQ_BREAK and wake us up again. |
548 | * | 591 | * |
549 | * This, of course, is merely a different *kind* of icky. | 592 | * This, of course, is merely a different *kind* of icky. |
593 | * | ||
594 | * Given my well-known antipathy to threads, I'd prefer to use processes. But | ||
595 | * it's easier to share Guest memory with threads, and trivial to share the | ||
596 | * devices.infds as the Launcher changes it. | ||
550 | */ | 597 | */ |
551 | static void wake_parent(int pipefd, int lguest_fd) | 598 | static int waker(void *unused) |
552 | { | 599 | { |
553 | /* Add the pipe from the Launcher to the fdset in the device_list, so | 600 | /* Close the write end of the pipe: only the Launcher has it open. */ |
554 | * we watch it, too. */ | 601 | close(waker_fds.pipe[1]); |
555 | add_device_fd(pipefd); | ||
556 | 602 | ||
557 | for (;;) { | 603 | for (;;) { |
558 | fd_set rfds = devices.infds; | 604 | fd_set rfds = devices.infds; |
559 | unsigned long args[] = { LHREQ_BREAK, 1 }; | 605 | unsigned long args[] = { LHREQ_BREAK, 1 }; |
606 | unsigned int maxfd = devices.max_infd; | ||
607 | |||
608 | /* We also listen to the pipe from the Launcher. */ | ||
609 | FD_SET(waker_fds.pipe[0], &rfds); | ||
610 | if (waker_fds.pipe[0] > maxfd) | ||
611 | maxfd = waker_fds.pipe[0]; | ||
560 | 612 | ||
561 | /* Wait until input is ready from one of the devices. */ | 613 | /* Wait until input is ready from one of the devices. */ |
562 | select(devices.max_infd+1, &rfds, NULL, NULL, NULL); | 614 | select(maxfd+1, &rfds, NULL, NULL, NULL); |
563 | /* Is it a message from the Launcher? */ | 615 | |
564 | if (FD_ISSET(pipefd, &rfds)) { | 616 | /* Message from Launcher? */ |
565 | int fd; | 617 | if (FD_ISSET(waker_fds.pipe[0], &rfds)) { |
566 | /* If read() returns 0, it means the Launcher has | 618 | char c; |
567 | * exited. We silently follow. */ | 619 | /* If this fails, then assume Launcher has exited. |
568 | if (read(pipefd, &fd, sizeof(fd)) == 0) | 620 | * Don't do anything on exit: we're just a thread! */ |
569 | exit(0); | 621 | if (read(waker_fds.pipe[0], &c, 1) != 1) |
570 | /* Otherwise it's telling us to change what file | 622 | _exit(0); |
571 | * descriptors we're to listen to. Positive means | 623 | continue; |
572 | * listen to a new one, negative means stop | 624 | } |
573 | * listening. */ | 625 | |
574 | if (fd >= 0) | 626 | /* Send LHREQ_BREAK command to snap the Launcher out of it. */ |
575 | FD_SET(fd, &devices.infds); | 627 | pwrite(waker_fds.lguest_fd, args, sizeof(args), cpu_id); |
576 | else | ||
577 | FD_CLR(-fd - 1, &devices.infds); | ||
578 | } else /* Send LHREQ_BREAK command. */ | ||
579 | pwrite(lguest_fd, args, sizeof(args), cpu_id); | ||
580 | } | 628 | } |
629 | return 0; | ||
581 | } | 630 | } |
582 | 631 | ||
583 | /* This routine just sets up a pipe to the Waker process. */ | 632 | /* This routine just sets up a pipe to the Waker process. */ |
584 | static int setup_waker(int lguest_fd) | 633 | static void setup_waker(int lguest_fd) |
585 | { | 634 | { |
586 | int pipefd[2], child; | 635 | /* This pipe is closed when Launcher dies, telling Waker. */ |
587 | 636 | if (pipe(waker_fds.pipe) != 0) | |
588 | /* We create a pipe to talk to the Waker, and also so it knows when the | 637 | err(1, "Creating pipe for Waker"); |
589 | * Launcher dies (and closes pipe). */ | ||
590 | pipe(pipefd); | ||
591 | child = fork(); | ||
592 | if (child == -1) | ||
593 | err(1, "forking"); | ||
594 | |||
595 | if (child == 0) { | ||
596 | /* We are the Waker: close the "writing" end of our copy of the | ||
597 | * pipe and start waiting for input. */ | ||
598 | close(pipefd[1]); | ||
599 | wake_parent(pipefd[0], lguest_fd); | ||
600 | } | ||
601 | /* Close the reading end of our copy of the pipe. */ | ||
602 | close(pipefd[0]); | ||
603 | 638 | ||
604 | /* Here is the fd used to talk to the waker. */ | 639 | /* Waker also needs to know the lguest fd */ |
605 | return pipefd[1]; | 640 | waker_fds.lguest_fd = lguest_fd; |
641 | |||
642 | if (clone(waker, malloc(4096) + 4096, CLONE_VM | SIGCHLD, NULL) == -1) | ||
643 | err(1, "Creating Waker"); | ||
606 | } | 644 | } |
607 | 645 | ||
608 | /* | 646 | /* |
@@ -661,19 +699,22 @@ static unsigned get_vq_desc(struct virtqueue *vq, | |||
661 | unsigned int *out_num, unsigned int *in_num) | 699 | unsigned int *out_num, unsigned int *in_num) |
662 | { | 700 | { |
663 | unsigned int i, head; | 701 | unsigned int i, head; |
702 | u16 last_avail; | ||
664 | 703 | ||
665 | /* Check it isn't doing very strange things with descriptor numbers. */ | 704 | /* Check it isn't doing very strange things with descriptor numbers. */ |
666 | if ((u16)(vq->vring.avail->idx - vq->last_avail_idx) > vq->vring.num) | 705 | last_avail = lg_last_avail(vq); |
706 | if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num) | ||
667 | errx(1, "Guest moved used index from %u to %u", | 707 | errx(1, "Guest moved used index from %u to %u", |
668 | vq->last_avail_idx, vq->vring.avail->idx); | 708 | last_avail, vq->vring.avail->idx); |
669 | 709 | ||
670 | /* If there's nothing new since last we looked, return invalid. */ | 710 | /* If there's nothing new since last we looked, return invalid. */ |
671 | if (vq->vring.avail->idx == vq->last_avail_idx) | 711 | if (vq->vring.avail->idx == last_avail) |
672 | return vq->vring.num; | 712 | return vq->vring.num; |
673 | 713 | ||
674 | /* Grab the next descriptor number they're advertising, and increment | 714 | /* Grab the next descriptor number they're advertising, and increment |
675 | * the index we've seen. */ | 715 | * the index we've seen. */ |
676 | head = vq->vring.avail->ring[vq->last_avail_idx++ % vq->vring.num]; | 716 | head = vq->vring.avail->ring[last_avail % vq->vring.num]; |
717 | lg_last_avail(vq)++; | ||
677 | 718 | ||
678 | /* If their number is silly, that's a fatal mistake. */ | 719 | /* If their number is silly, that's a fatal mistake. */ |
679 | if (head >= vq->vring.num) | 720 | if (head >= vq->vring.num) |
@@ -821,8 +862,8 @@ static bool handle_console_input(int fd, struct device *dev) | |||
821 | unsigned long args[] = { LHREQ_BREAK, 0 }; | 862 | unsigned long args[] = { LHREQ_BREAK, 0 }; |
822 | /* Close the fd so Waker will know it has to | 863 | /* Close the fd so Waker will know it has to |
823 | * exit. */ | 864 | * exit. */ |
824 | close(waker_fd); | 865 | close(waker_fds.pipe[1]); |
825 | /* Just in case waker is blocked in BREAK, send | 866 | /* Just in case Waker is blocked in BREAK, send |
826 | * unbreak now. */ | 867 | * unbreak now. */ |
827 | write(fd, args, sizeof(args)); | 868 | write(fd, args, sizeof(args)); |
828 | exit(2); | 869 | exit(2); |
@@ -839,7 +880,7 @@ static bool handle_console_input(int fd, struct device *dev) | |||
839 | 880 | ||
840 | /* Handling output for console is simple: we just get all the output buffers | 881 | /* Handling output for console is simple: we just get all the output buffers |
841 | * and write them to stdout. */ | 882 | * and write them to stdout. */ |
842 | static void handle_console_output(int fd, struct virtqueue *vq) | 883 | static void handle_console_output(int fd, struct virtqueue *vq, bool timeout) |
843 | { | 884 | { |
844 | unsigned int head, out, in; | 885 | unsigned int head, out, in; |
845 | int len; | 886 | int len; |
@@ -854,6 +895,21 @@ static void handle_console_output(int fd, struct virtqueue *vq) | |||
854 | } | 895 | } |
855 | } | 896 | } |
856 | 897 | ||
898 | static void block_vq(struct virtqueue *vq) | ||
899 | { | ||
900 | struct itimerval itm; | ||
901 | |||
902 | vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; | ||
903 | vq->blocked = true; | ||
904 | |||
905 | itm.it_interval.tv_sec = 0; | ||
906 | itm.it_interval.tv_usec = 0; | ||
907 | itm.it_value.tv_sec = 0; | ||
908 | itm.it_value.tv_usec = timeout_usec; | ||
909 | |||
910 | setitimer(ITIMER_REAL, &itm, NULL); | ||
911 | } | ||
912 | |||
857 | /* | 913 | /* |
858 | * The Network | 914 | * The Network |
859 | * | 915 | * |
@@ -861,22 +917,34 @@ static void handle_console_output(int fd, struct virtqueue *vq) | |||
861 | * and write them (ignoring the first element) to this device's file descriptor | 917 | * and write them (ignoring the first element) to this device's file descriptor |
862 | * (/dev/net/tun). | 918 | * (/dev/net/tun). |
863 | */ | 919 | */ |
864 | static void handle_net_output(int fd, struct virtqueue *vq) | 920 | static void handle_net_output(int fd, struct virtqueue *vq, bool timeout) |
865 | { | 921 | { |
866 | unsigned int head, out, in; | 922 | unsigned int head, out, in, num = 0; |
867 | int len; | 923 | int len; |
868 | struct iovec iov[vq->vring.num]; | 924 | struct iovec iov[vq->vring.num]; |
925 | static int last_timeout_num; | ||
869 | 926 | ||
870 | /* Keep getting output buffers from the Guest until we run out. */ | 927 | /* Keep getting output buffers from the Guest until we run out. */ |
871 | while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) { | 928 | while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) { |
872 | if (in) | 929 | if (in) |
873 | errx(1, "Input buffers in output queue?"); | 930 | errx(1, "Input buffers in output queue?"); |
874 | /* Check header, but otherwise ignore it (we told the Guest we | 931 | len = writev(vq->dev->fd, iov, out); |
875 | * supported no features, so it shouldn't have anything | 932 | if (len < 0) |
876 | * interesting). */ | 933 | err(1, "Writing network packet to tun"); |
877 | (void)convert(&iov[0], struct virtio_net_hdr); | ||
878 | len = writev(vq->dev->fd, iov+1, out-1); | ||
879 | add_used_and_trigger(fd, vq, head, len); | 934 | add_used_and_trigger(fd, vq, head, len); |
935 | num++; | ||
936 | } | ||
937 | |||
938 | /* Block further kicks and set up a timer if we saw anything. */ | ||
939 | if (!timeout && num) | ||
940 | block_vq(vq); | ||
941 | |||
942 | if (timeout) { | ||
943 | if (num < last_timeout_num) | ||
944 | timeout_usec += 10; | ||
945 | else if (timeout_usec > 1) | ||
946 | timeout_usec--; | ||
947 | last_timeout_num = num; | ||
880 | } | 948 | } |
881 | } | 949 | } |
882 | 950 | ||
@@ -887,7 +955,6 @@ static bool handle_tun_input(int fd, struct device *dev) | |||
887 | unsigned int head, in_num, out_num; | 955 | unsigned int head, in_num, out_num; |
888 | int len; | 956 | int len; |
889 | struct iovec iov[dev->vq->vring.num]; | 957 | struct iovec iov[dev->vq->vring.num]; |
890 | struct virtio_net_hdr *hdr; | ||
891 | 958 | ||
892 | /* First we need a network buffer from the Guests's recv virtqueue. */ | 959 | /* First we need a network buffer from the Guests's recv virtqueue. */ |
893 | head = get_vq_desc(dev->vq, iov, &out_num, &in_num); | 960 | head = get_vq_desc(dev->vq, iov, &out_num, &in_num); |
@@ -896,25 +963,23 @@ static bool handle_tun_input(int fd, struct device *dev) | |||
896 | * early, the Guest won't be ready yet. Wait until the device | 963 | * early, the Guest won't be ready yet. Wait until the device |
897 | * status says it's ready. */ | 964 | * status says it's ready. */ |
898 | /* FIXME: Actually want DRIVER_ACTIVE here. */ | 965 | /* FIXME: Actually want DRIVER_ACTIVE here. */ |
899 | if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) | 966 | |
900 | warn("network: no dma buffer!"); | 967 | /* Now tell it we want to know if new things appear. */ |
968 | dev->vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; | ||
969 | wmb(); | ||
970 | |||
901 | /* We'll turn this back on if input buffers are registered. */ | 971 | /* We'll turn this back on if input buffers are registered. */ |
902 | return false; | 972 | return false; |
903 | } else if (out_num) | 973 | } else if (out_num) |
904 | errx(1, "Output buffers in network recv queue?"); | 974 | errx(1, "Output buffers in network recv queue?"); |
905 | 975 | ||
906 | /* First element is the header: we set it to 0 (no features). */ | ||
907 | hdr = convert(&iov[0], struct virtio_net_hdr); | ||
908 | hdr->flags = 0; | ||
909 | hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE; | ||
910 | |||
911 | /* Read the packet from the device directly into the Guest's buffer. */ | 976 | /* Read the packet from the device directly into the Guest's buffer. */ |
912 | len = readv(dev->fd, iov+1, in_num-1); | 977 | len = readv(dev->fd, iov, in_num); |
913 | if (len <= 0) | 978 | if (len <= 0) |
914 | err(1, "reading network"); | 979 | err(1, "reading network"); |
915 | 980 | ||
916 | /* Tell the Guest about the new packet. */ | 981 | /* Tell the Guest about the new packet. */ |
917 | add_used_and_trigger(fd, dev->vq, head, sizeof(*hdr) + len); | 982 | add_used_and_trigger(fd, dev->vq, head, len); |
918 | 983 | ||
919 | verbose("tun input packet len %i [%02x %02x] (%s)\n", len, | 984 | verbose("tun input packet len %i [%02x %02x] (%s)\n", len, |
920 | ((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1], | 985 | ((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1], |
@@ -927,11 +992,18 @@ static bool handle_tun_input(int fd, struct device *dev) | |||
927 | /*L:215 This is the callback attached to the network and console input | 992 | /*L:215 This is the callback attached to the network and console input |
928 | * virtqueues: it ensures we try again, in case we stopped console or net | 993 | * virtqueues: it ensures we try again, in case we stopped console or net |
929 | * delivery because Guest didn't have any buffers. */ | 994 | * delivery because Guest didn't have any buffers. */ |
930 | static void enable_fd(int fd, struct virtqueue *vq) | 995 | static void enable_fd(int fd, struct virtqueue *vq, bool timeout) |
931 | { | 996 | { |
932 | add_device_fd(vq->dev->fd); | 997 | add_device_fd(vq->dev->fd); |
933 | /* Tell waker to listen to it again */ | 998 | /* Snap the Waker out of its select loop. */ |
934 | write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); | 999 | write(waker_fds.pipe[1], "", 1); |
1000 | } | ||
1001 | |||
1002 | static void net_enable_fd(int fd, struct virtqueue *vq, bool timeout) | ||
1003 | { | ||
1004 | /* We don't need to know again when Guest refills receive buffer. */ | ||
1005 | vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; | ||
1006 | enable_fd(fd, vq, timeout); | ||
935 | } | 1007 | } |
936 | 1008 | ||
937 | /* When the Guest tells us they updated the status field, we handle it. */ | 1009 | /* When the Guest tells us they updated the status field, we handle it. */ |
@@ -951,7 +1023,7 @@ static void update_device_status(struct device *dev) | |||
951 | for (vq = dev->vq; vq; vq = vq->next) { | 1023 | for (vq = dev->vq; vq; vq = vq->next) { |
952 | memset(vq->vring.desc, 0, | 1024 | memset(vq->vring.desc, 0, |
953 | vring_size(vq->config.num, getpagesize())); | 1025 | vring_size(vq->config.num, getpagesize())); |
954 | vq->last_avail_idx = 0; | 1026 | lg_last_avail(vq) = 0; |
955 | } | 1027 | } |
956 | } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { | 1028 | } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { |
957 | warnx("Device %s configuration FAILED", dev->name); | 1029 | warnx("Device %s configuration FAILED", dev->name); |
@@ -960,10 +1032,10 @@ static void update_device_status(struct device *dev) | |||
960 | 1032 | ||
961 | verbose("Device %s OK: offered", dev->name); | 1033 | verbose("Device %s OK: offered", dev->name); |
962 | for (i = 0; i < dev->desc->feature_len; i++) | 1034 | for (i = 0; i < dev->desc->feature_len; i++) |
963 | verbose(" %08x", get_feature_bits(dev)[i]); | 1035 | verbose(" %02x", get_feature_bits(dev)[i]); |
964 | verbose(", accepted"); | 1036 | verbose(", accepted"); |
965 | for (i = 0; i < dev->desc->feature_len; i++) | 1037 | for (i = 0; i < dev->desc->feature_len; i++) |
966 | verbose(" %08x", get_feature_bits(dev) | 1038 | verbose(" %02x", get_feature_bits(dev) |
967 | [dev->desc->feature_len+i]); | 1039 | [dev->desc->feature_len+i]); |
968 | 1040 | ||
969 | if (dev->ready) | 1041 | if (dev->ready) |
@@ -1000,7 +1072,7 @@ static void handle_output(int fd, unsigned long addr) | |||
1000 | if (strcmp(vq->dev->name, "console") != 0) | 1072 | if (strcmp(vq->dev->name, "console") != 0) |
1001 | verbose("Output to %s\n", vq->dev->name); | 1073 | verbose("Output to %s\n", vq->dev->name); |
1002 | if (vq->handle_output) | 1074 | if (vq->handle_output) |
1003 | vq->handle_output(fd, vq); | 1075 | vq->handle_output(fd, vq, false); |
1004 | return; | 1076 | return; |
1005 | } | 1077 | } |
1006 | } | 1078 | } |
@@ -1014,6 +1086,29 @@ static void handle_output(int fd, unsigned long addr) | |||
1014 | strnlen(from_guest_phys(addr), guest_limit - addr)); | 1086 | strnlen(from_guest_phys(addr), guest_limit - addr)); |
1015 | } | 1087 | } |
1016 | 1088 | ||
1089 | static void handle_timeout(int fd) | ||
1090 | { | ||
1091 | char buf[32]; | ||
1092 | struct device *i; | ||
1093 | struct virtqueue *vq; | ||
1094 | |||
1095 | /* Clear the pipe */ | ||
1096 | read(timeoutpipe[0], buf, sizeof(buf)); | ||
1097 | |||
1098 | /* Check each device and virtqueue: flush blocked ones. */ | ||
1099 | for (i = devices.dev; i; i = i->next) { | ||
1100 | for (vq = i->vq; vq; vq = vq->next) { | ||
1101 | if (!vq->blocked) | ||
1102 | continue; | ||
1103 | |||
1104 | vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; | ||
1105 | vq->blocked = false; | ||
1106 | if (vq->handle_output) | ||
1107 | vq->handle_output(fd, vq, true); | ||
1108 | } | ||
1109 | } | ||
1110 | } | ||
1111 | |||
1017 | /* This is called when the Waker wakes us up: check for incoming file | 1112 | /* This is called when the Waker wakes us up: check for incoming file |
1018 | * descriptors. */ | 1113 | * descriptors. */ |
1019 | static void handle_input(int fd) | 1114 | static void handle_input(int fd) |
@@ -1024,16 +1119,20 @@ static void handle_input(int fd) | |||
1024 | for (;;) { | 1119 | for (;;) { |
1025 | struct device *i; | 1120 | struct device *i; |
1026 | fd_set fds = devices.infds; | 1121 | fd_set fds = devices.infds; |
1122 | int num; | ||
1027 | 1123 | ||
1124 | num = select(devices.max_infd+1, &fds, NULL, NULL, &poll); | ||
1125 | /* Could get interrupted */ | ||
1126 | if (num < 0) | ||
1127 | continue; | ||
1028 | /* If nothing is ready, we're done. */ | 1128 | /* If nothing is ready, we're done. */ |
1029 | if (select(devices.max_infd+1, &fds, NULL, NULL, &poll) == 0) | 1129 | if (num == 0) |
1030 | break; | 1130 | break; |
1031 | 1131 | ||
1032 | /* Otherwise, call the device(s) which have readable file | 1132 | /* Otherwise, call the device(s) which have readable file |
1033 | * descriptors and a method of handling them. */ | 1133 | * descriptors and a method of handling them. */ |
1034 | for (i = devices.dev; i; i = i->next) { | 1134 | for (i = devices.dev; i; i = i->next) { |
1035 | if (i->handle_input && FD_ISSET(i->fd, &fds)) { | 1135 | if (i->handle_input && FD_ISSET(i->fd, &fds)) { |
1036 | int dev_fd; | ||
1037 | if (i->handle_input(fd, i)) | 1136 | if (i->handle_input(fd, i)) |
1038 | continue; | 1137 | continue; |
1039 | 1138 | ||
@@ -1043,13 +1142,12 @@ static void handle_input(int fd) | |||
1043 | * buffers to deliver into. Console also uses | 1142 | * buffers to deliver into. Console also uses |
1044 | * it when it discovers that stdin is closed. */ | 1143 | * it when it discovers that stdin is closed. */ |
1045 | FD_CLR(i->fd, &devices.infds); | 1144 | FD_CLR(i->fd, &devices.infds); |
1046 | /* Tell waker to ignore it too, by sending a | ||
1047 | * negative fd number (-1, since 0 is a valid | ||
1048 | * FD number). */ | ||
1049 | dev_fd = -i->fd - 1; | ||
1050 | write(waker_fd, &dev_fd, sizeof(dev_fd)); | ||
1051 | } | 1145 | } |
1052 | } | 1146 | } |
1147 | |||
1148 | /* Is this the timeout fd? */ | ||
1149 | if (FD_ISSET(timeoutpipe[0], &fds)) | ||
1150 | handle_timeout(fd); | ||
1053 | } | 1151 | } |
1054 | } | 1152 | } |
1055 | 1153 | ||
@@ -1098,7 +1196,7 @@ static struct lguest_device_desc *new_dev_desc(u16 type) | |||
1098 | /* Each device descriptor is followed by the description of its virtqueues. We | 1196 | /* Each device descriptor is followed by the description of its virtqueues. We |
1099 | * specify how many descriptors the virtqueue is to have. */ | 1197 | * specify how many descriptors the virtqueue is to have. */ |
1100 | static void add_virtqueue(struct device *dev, unsigned int num_descs, | 1198 | static void add_virtqueue(struct device *dev, unsigned int num_descs, |
1101 | void (*handle_output)(int fd, struct virtqueue *me)) | 1199 | void (*handle_output)(int, struct virtqueue *, bool)) |
1102 | { | 1200 | { |
1103 | unsigned int pages; | 1201 | unsigned int pages; |
1104 | struct virtqueue **i, *vq = malloc(sizeof(*vq)); | 1202 | struct virtqueue **i, *vq = malloc(sizeof(*vq)); |
@@ -1114,6 +1212,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs, | |||
1114 | vq->last_avail_idx = 0; | 1212 | vq->last_avail_idx = 0; |
1115 | vq->dev = dev; | 1213 | vq->dev = dev; |
1116 | vq->inflight = 0; | 1214 | vq->inflight = 0; |
1215 | vq->blocked = false; | ||
1117 | 1216 | ||
1118 | /* Initialize the configuration. */ | 1217 | /* Initialize the configuration. */ |
1119 | vq->config.num = num_descs; | 1218 | vq->config.num = num_descs; |
@@ -1246,6 +1345,24 @@ static void setup_console(void) | |||
1246 | } | 1345 | } |
1247 | /*:*/ | 1346 | /*:*/ |
1248 | 1347 | ||
1348 | static void timeout_alarm(int sig) | ||
1349 | { | ||
1350 | write(timeoutpipe[1], "", 1); | ||
1351 | } | ||
1352 | |||
1353 | static void setup_timeout(void) | ||
1354 | { | ||
1355 | if (pipe(timeoutpipe) != 0) | ||
1356 | err(1, "Creating timeout pipe"); | ||
1357 | |||
1358 | if (fcntl(timeoutpipe[1], F_SETFL, | ||
1359 | fcntl(timeoutpipe[1], F_GETFL) | O_NONBLOCK) != 0) | ||
1360 | err(1, "Making timeout pipe nonblocking"); | ||
1361 | |||
1362 | add_device_fd(timeoutpipe[0]); | ||
1363 | signal(SIGALRM, timeout_alarm); | ||
1364 | } | ||
1365 | |||
1249 | /*M:010 Inter-guest networking is an interesting area. Simplest is to have a | 1366 | /*M:010 Inter-guest networking is an interesting area. Simplest is to have a |
1250 | * --sharenet=<name> option which opens or creates a named pipe. This can be | 1367 | * --sharenet=<name> option which opens or creates a named pipe. This can be |
1251 | * used to send packets to another guest in a 1:1 manner. | 1368 | * used to send packets to another guest in a 1:1 manner. |
@@ -1264,10 +1381,25 @@ static void setup_console(void) | |||
1264 | 1381 | ||
1265 | static u32 str2ip(const char *ipaddr) | 1382 | static u32 str2ip(const char *ipaddr) |
1266 | { | 1383 | { |
1267 | unsigned int byte[4]; | 1384 | unsigned int b[4]; |
1268 | 1385 | ||
1269 | sscanf(ipaddr, "%u.%u.%u.%u", &byte[0], &byte[1], &byte[2], &byte[3]); | 1386 | if (sscanf(ipaddr, "%u.%u.%u.%u", &b[0], &b[1], &b[2], &b[3]) != 4) |
1270 | return (byte[0] << 24) | (byte[1] << 16) | (byte[2] << 8) | byte[3]; | 1387 | errx(1, "Failed to parse IP address '%s'", ipaddr); |
1388 | return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; | ||
1389 | } | ||
1390 | |||
1391 | static void str2mac(const char *macaddr, unsigned char mac[6]) | ||
1392 | { | ||
1393 | unsigned int m[6]; | ||
1394 | if (sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x", | ||
1395 | &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]) != 6) | ||
1396 | errx(1, "Failed to parse mac address '%s'", macaddr); | ||
1397 | mac[0] = m[0]; | ||
1398 | mac[1] = m[1]; | ||
1399 | mac[2] = m[2]; | ||
1400 | mac[3] = m[3]; | ||
1401 | mac[4] = m[4]; | ||
1402 | mac[5] = m[5]; | ||
1271 | } | 1403 | } |
1272 | 1404 | ||
1273 | /* This code is "adapted" from libbridge: it attaches the Host end of the | 1405 | /* This code is "adapted" from libbridge: it attaches the Host end of the |
@@ -1288,6 +1420,7 @@ static void add_to_bridge(int fd, const char *if_name, const char *br_name) | |||
1288 | errx(1, "interface %s does not exist!", if_name); | 1420 | errx(1, "interface %s does not exist!", if_name); |
1289 | 1421 | ||
1290 | strncpy(ifr.ifr_name, br_name, IFNAMSIZ); | 1422 | strncpy(ifr.ifr_name, br_name, IFNAMSIZ); |
1423 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; | ||
1291 | ifr.ifr_ifindex = ifidx; | 1424 | ifr.ifr_ifindex = ifidx; |
1292 | if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) | 1425 | if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) |
1293 | err(1, "can't add %s to bridge %s", if_name, br_name); | 1426 | err(1, "can't add %s to bridge %s", if_name, br_name); |
@@ -1296,64 +1429,90 @@ static void add_to_bridge(int fd, const char *if_name, const char *br_name) | |||
1296 | /* This sets up the Host end of the network device with an IP address, brings | 1429 | /* This sets up the Host end of the network device with an IP address, brings |
1297 | * it up so packets will flow, the copies the MAC address into the hwaddr | 1430 | * it up so packets will flow, the copies the MAC address into the hwaddr |
1298 | * pointer. */ | 1431 | * pointer. */ |
1299 | static void configure_device(int fd, const char *devname, u32 ipaddr, | 1432 | static void configure_device(int fd, const char *tapif, u32 ipaddr) |
1300 | unsigned char hwaddr[6]) | ||
1301 | { | 1433 | { |
1302 | struct ifreq ifr; | 1434 | struct ifreq ifr; |
1303 | struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; | 1435 | struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; |
1304 | 1436 | ||
1305 | /* Don't read these incantations. Just cut & paste them like I did! */ | ||
1306 | memset(&ifr, 0, sizeof(ifr)); | 1437 | memset(&ifr, 0, sizeof(ifr)); |
1307 | strcpy(ifr.ifr_name, devname); | 1438 | strcpy(ifr.ifr_name, tapif); |
1439 | |||
1440 | /* Don't read these incantations. Just cut & paste them like I did! */ | ||
1308 | sin->sin_family = AF_INET; | 1441 | sin->sin_family = AF_INET; |
1309 | sin->sin_addr.s_addr = htonl(ipaddr); | 1442 | sin->sin_addr.s_addr = htonl(ipaddr); |
1310 | if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) | 1443 | if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) |
1311 | err(1, "Setting %s interface address", devname); | 1444 | err(1, "Setting %s interface address", tapif); |
1312 | ifr.ifr_flags = IFF_UP; | 1445 | ifr.ifr_flags = IFF_UP; |
1313 | if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) | 1446 | if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) |
1314 | err(1, "Bringing interface %s up", devname); | 1447 | err(1, "Bringing interface %s up", tapif); |
1448 | } | ||
1449 | |||
1450 | static void get_mac(int fd, const char *tapif, unsigned char hwaddr[6]) | ||
1451 | { | ||
1452 | struct ifreq ifr; | ||
1453 | |||
1454 | memset(&ifr, 0, sizeof(ifr)); | ||
1455 | strcpy(ifr.ifr_name, tapif); | ||
1315 | 1456 | ||
1316 | /* SIOC stands for Socket I/O Control. G means Get (vs S for Set | 1457 | /* SIOC stands for Socket I/O Control. G means Get (vs S for Set |
1317 | * above). IF means Interface, and HWADDR is hardware address. | 1458 | * above). IF means Interface, and HWADDR is hardware address. |
1318 | * Simple! */ | 1459 | * Simple! */ |
1319 | if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0) | 1460 | if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0) |
1320 | err(1, "getting hw address for %s", devname); | 1461 | err(1, "getting hw address for %s", tapif); |
1321 | memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6); | 1462 | memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6); |
1322 | } | 1463 | } |
1323 | 1464 | ||
1324 | /*L:195 Our network is a Host<->Guest network. This can either use bridging or | 1465 | static int get_tun_device(char tapif[IFNAMSIZ]) |
1325 | * routing, but the principle is the same: it uses the "tun" device to inject | ||
1326 | * packets into the Host as if they came in from a normal network card. We | ||
1327 | * just shunt packets between the Guest and the tun device. */ | ||
1328 | static void setup_tun_net(const char *arg) | ||
1329 | { | 1466 | { |
1330 | struct device *dev; | ||
1331 | struct ifreq ifr; | 1467 | struct ifreq ifr; |
1332 | int netfd, ipfd; | 1468 | int netfd; |
1333 | u32 ip; | 1469 | |
1334 | const char *br_name = NULL; | 1470 | /* Start with this zeroed. Messy but sure. */ |
1335 | struct virtio_net_config conf; | 1471 | memset(&ifr, 0, sizeof(ifr)); |
1336 | 1472 | ||
1337 | /* We open the /dev/net/tun device and tell it we want a tap device. A | 1473 | /* We open the /dev/net/tun device and tell it we want a tap device. A |
1338 | * tap device is like a tun device, only somehow different. To tell | 1474 | * tap device is like a tun device, only somehow different. To tell |
1339 | * the truth, I completely blundered my way through this code, but it | 1475 | * the truth, I completely blundered my way through this code, but it |
1340 | * works now! */ | 1476 | * works now! */ |
1341 | netfd = open_or_die("/dev/net/tun", O_RDWR); | 1477 | netfd = open_or_die("/dev/net/tun", O_RDWR); |
1342 | memset(&ifr, 0, sizeof(ifr)); | 1478 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; |
1343 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI; | ||
1344 | strcpy(ifr.ifr_name, "tap%d"); | 1479 | strcpy(ifr.ifr_name, "tap%d"); |
1345 | if (ioctl(netfd, TUNSETIFF, &ifr) != 0) | 1480 | if (ioctl(netfd, TUNSETIFF, &ifr) != 0) |
1346 | err(1, "configuring /dev/net/tun"); | 1481 | err(1, "configuring /dev/net/tun"); |
1482 | |||
1483 | if (ioctl(netfd, TUNSETOFFLOAD, | ||
1484 | TUN_F_CSUM|TUN_F_TSO4|TUN_F_TSO6|TUN_F_TSO_ECN) != 0) | ||
1485 | err(1, "Could not set features for tun device"); | ||
1486 | |||
1347 | /* We don't need checksums calculated for packets coming in this | 1487 | /* We don't need checksums calculated for packets coming in this |
1348 | * device: trust us! */ | 1488 | * device: trust us! */ |
1349 | ioctl(netfd, TUNSETNOCSUM, 1); | 1489 | ioctl(netfd, TUNSETNOCSUM, 1); |
1350 | 1490 | ||
1491 | memcpy(tapif, ifr.ifr_name, IFNAMSIZ); | ||
1492 | return netfd; | ||
1493 | } | ||
1494 | |||
1495 | /*L:195 Our network is a Host<->Guest network. This can either use bridging or | ||
1496 | * routing, but the principle is the same: it uses the "tun" device to inject | ||
1497 | * packets into the Host as if they came in from a normal network card. We | ||
1498 | * just shunt packets between the Guest and the tun device. */ | ||
1499 | static void setup_tun_net(char *arg) | ||
1500 | { | ||
1501 | struct device *dev; | ||
1502 | int netfd, ipfd; | ||
1503 | u32 ip = INADDR_ANY; | ||
1504 | bool bridging = false; | ||
1505 | char tapif[IFNAMSIZ], *p; | ||
1506 | struct virtio_net_config conf; | ||
1507 | |||
1508 | netfd = get_tun_device(tapif); | ||
1509 | |||
1351 | /* First we create a new network device. */ | 1510 | /* First we create a new network device. */ |
1352 | dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input); | 1511 | dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input); |
1353 | 1512 | ||
1354 | /* Network devices need a receive and a send queue, just like | 1513 | /* Network devices need a receive and a send queue, just like |
1355 | * console. */ | 1514 | * console. */ |
1356 | add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd); | 1515 | add_virtqueue(dev, VIRTQUEUE_NUM, net_enable_fd); |
1357 | add_virtqueue(dev, VIRTQUEUE_NUM, handle_net_output); | 1516 | add_virtqueue(dev, VIRTQUEUE_NUM, handle_net_output); |
1358 | 1517 | ||
1359 | /* We need a socket to perform the magic network ioctls to bring up the | 1518 | /* We need a socket to perform the magic network ioctls to bring up the |
@@ -1364,28 +1523,56 @@ static void setup_tun_net(const char *arg) | |||
1364 | 1523 | ||
1365 | /* If the command line was --tunnet=bridge:<name> do bridging. */ | 1524 | /* If the command line was --tunnet=bridge:<name> do bridging. */ |
1366 | if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) { | 1525 | if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) { |
1367 | ip = INADDR_ANY; | 1526 | arg += strlen(BRIDGE_PFX); |
1368 | br_name = arg + strlen(BRIDGE_PFX); | 1527 | bridging = true; |
1369 | add_to_bridge(ipfd, ifr.ifr_name, br_name); | 1528 | } |
1370 | } else /* It is an IP address to set up the device with */ | 1529 | |
1530 | /* A mac address may follow the bridge name or IP address */ | ||
1531 | p = strchr(arg, ':'); | ||
1532 | if (p) { | ||
1533 | str2mac(p+1, conf.mac); | ||
1534 | *p = '\0'; | ||
1535 | } else { | ||
1536 | p = arg + strlen(arg); | ||
1537 | /* None supplied; query the randomly assigned mac. */ | ||
1538 | get_mac(ipfd, tapif, conf.mac); | ||
1539 | } | ||
1540 | |||
1541 | /* arg is now either an IP address or a bridge name */ | ||
1542 | if (bridging) | ||
1543 | add_to_bridge(ipfd, tapif, arg); | ||
1544 | else | ||
1371 | ip = str2ip(arg); | 1545 | ip = str2ip(arg); |
1372 | 1546 | ||
1373 | /* Set up the tun device, and get the mac address for the interface. */ | 1547 | /* Set up the tun device. */ |
1374 | configure_device(ipfd, ifr.ifr_name, ip, conf.mac); | 1548 | configure_device(ipfd, tapif, ip); |
1375 | 1549 | ||
1376 | /* Tell Guest what MAC address to use. */ | 1550 | /* Tell Guest what MAC address to use. */ |
1377 | add_feature(dev, VIRTIO_NET_F_MAC); | 1551 | add_feature(dev, VIRTIO_NET_F_MAC); |
1378 | add_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY); | 1552 | add_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY); |
1553 | /* Expect Guest to handle everything except UFO */ | ||
1554 | add_feature(dev, VIRTIO_NET_F_CSUM); | ||
1555 | add_feature(dev, VIRTIO_NET_F_GUEST_CSUM); | ||
1556 | add_feature(dev, VIRTIO_NET_F_MAC); | ||
1557 | add_feature(dev, VIRTIO_NET_F_GUEST_TSO4); | ||
1558 | add_feature(dev, VIRTIO_NET_F_GUEST_TSO6); | ||
1559 | add_feature(dev, VIRTIO_NET_F_GUEST_ECN); | ||
1560 | add_feature(dev, VIRTIO_NET_F_HOST_TSO4); | ||
1561 | add_feature(dev, VIRTIO_NET_F_HOST_TSO6); | ||
1562 | add_feature(dev, VIRTIO_NET_F_HOST_ECN); | ||
1379 | set_config(dev, sizeof(conf), &conf); | 1563 | set_config(dev, sizeof(conf), &conf); |
1380 | 1564 | ||
1381 | /* We don't need the socket any more; setup is done. */ | 1565 | /* We don't need the socket any more; setup is done. */ |
1382 | close(ipfd); | 1566 | close(ipfd); |
1383 | 1567 | ||
1384 | verbose("device %u: tun net %u.%u.%u.%u\n", | 1568 | devices.device_num++; |
1385 | devices.device_num++, | 1569 | |
1386 | (u8)(ip>>24),(u8)(ip>>16),(u8)(ip>>8),(u8)ip); | 1570 | if (bridging) |
1387 | if (br_name) | 1571 | verbose("device %u: tun %s attached to bridge: %s\n", |
1388 | verbose("attached to bridge: %s\n", br_name); | 1572 | devices.device_num, tapif, arg); |
1573 | else | ||
1574 | verbose("device %u: tun %s: %s\n", | ||
1575 | devices.device_num, tapif, arg); | ||
1389 | } | 1576 | } |
1390 | 1577 | ||
1391 | /* Our block (disk) device should be really simple: the Guest asks for a block | 1578 | /* Our block (disk) device should be really simple: the Guest asks for a block |
@@ -1550,7 +1737,7 @@ static bool handle_io_finish(int fd, struct device *dev) | |||
1550 | } | 1737 | } |
1551 | 1738 | ||
1552 | /* When the Guest submits some I/O, we just need to wake the I/O thread. */ | 1739 | /* When the Guest submits some I/O, we just need to wake the I/O thread. */ |
1553 | static void handle_virtblk_output(int fd, struct virtqueue *vq) | 1740 | static void handle_virtblk_output(int fd, struct virtqueue *vq, bool timeout) |
1554 | { | 1741 | { |
1555 | struct vblk_info *vblk = vq->dev->priv; | 1742 | struct vblk_info *vblk = vq->dev->priv; |
1556 | char c = 0; | 1743 | char c = 0; |
@@ -1621,6 +1808,64 @@ static void setup_block_file(const char *filename) | |||
1621 | verbose("device %u: virtblock %llu sectors\n", | 1808 | verbose("device %u: virtblock %llu sectors\n", |
1622 | devices.device_num, le64_to_cpu(conf.capacity)); | 1809 | devices.device_num, le64_to_cpu(conf.capacity)); |
1623 | } | 1810 | } |
1811 | |||
1812 | /* Our random number generator device reads from /dev/random into the Guest's | ||
1813 | * input buffers. The usual case is that the Guest doesn't want random numbers | ||
1814 | * and so has no buffers although /dev/random is still readable, whereas | ||
1815 | * console is the reverse. | ||
1816 | * | ||
1817 | * The same logic applies, however. */ | ||
1818 | static bool handle_rng_input(int fd, struct device *dev) | ||
1819 | { | ||
1820 | int len; | ||
1821 | unsigned int head, in_num, out_num, totlen = 0; | ||
1822 | struct iovec iov[dev->vq->vring.num]; | ||
1823 | |||
1824 | /* First we need a buffer from the Guests's virtqueue. */ | ||
1825 | head = get_vq_desc(dev->vq, iov, &out_num, &in_num); | ||
1826 | |||
1827 | /* If they're not ready for input, stop listening to this file | ||
1828 | * descriptor. We'll start again once they add an input buffer. */ | ||
1829 | if (head == dev->vq->vring.num) | ||
1830 | return false; | ||
1831 | |||
1832 | if (out_num) | ||
1833 | errx(1, "Output buffers in rng?"); | ||
1834 | |||
1835 | /* This is why we convert to iovecs: the readv() call uses them, and so | ||
1836 | * it reads straight into the Guest's buffer. We loop to make sure we | ||
1837 | * fill it. */ | ||
1838 | while (!iov_empty(iov, in_num)) { | ||
1839 | len = readv(dev->fd, iov, in_num); | ||
1840 | if (len <= 0) | ||
1841 | err(1, "Read from /dev/random gave %i", len); | ||
1842 | iov_consume(iov, in_num, len); | ||
1843 | totlen += len; | ||
1844 | } | ||
1845 | |||
1846 | /* Tell the Guest about the new input. */ | ||
1847 | add_used_and_trigger(fd, dev->vq, head, totlen); | ||
1848 | |||
1849 | /* Everything went OK! */ | ||
1850 | return true; | ||
1851 | } | ||
1852 | |||
1853 | /* And this creates a "hardware" random number device for the Guest. */ | ||
1854 | static void setup_rng(void) | ||
1855 | { | ||
1856 | struct device *dev; | ||
1857 | int fd; | ||
1858 | |||
1859 | fd = open_or_die("/dev/random", O_RDONLY); | ||
1860 | |||
1861 | /* The device responds to return from I/O thread. */ | ||
1862 | dev = new_device("rng", VIRTIO_ID_RNG, fd, handle_rng_input); | ||
1863 | |||
1864 | /* The device has one virtqueue, where the Guest places inbufs. */ | ||
1865 | add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd); | ||
1866 | |||
1867 | verbose("device %u: rng\n", devices.device_num++); | ||
1868 | } | ||
1624 | /* That's the end of device setup. */ | 1869 | /* That's the end of device setup. */ |
1625 | 1870 | ||
1626 | /*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */ | 1871 | /*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */ |
@@ -1628,11 +1873,12 @@ static void __attribute__((noreturn)) restart_guest(void) | |||
1628 | { | 1873 | { |
1629 | unsigned int i; | 1874 | unsigned int i; |
1630 | 1875 | ||
1631 | /* Closing pipes causes the Waker thread and io_threads to die, and | 1876 | /* Since we don't track all open fds, we simply close everything beyond |
1632 | * closing /dev/lguest cleans up the Guest. Since we don't track all | 1877 | * stderr. */ |
1633 | * open fds, we simply close everything beyond stderr. */ | ||
1634 | for (i = 3; i < FD_SETSIZE; i++) | 1878 | for (i = 3; i < FD_SETSIZE; i++) |
1635 | close(i); | 1879 | close(i); |
1880 | |||
1881 | /* The exec automatically gets rid of the I/O and Waker threads. */ | ||
1636 | execv(main_args[0], main_args); | 1882 | execv(main_args[0], main_args); |
1637 | err(1, "Could not exec %s", main_args[0]); | 1883 | err(1, "Could not exec %s", main_args[0]); |
1638 | } | 1884 | } |
@@ -1663,7 +1909,7 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd) | |||
1663 | /* ERESTART means that we need to reboot the guest */ | 1909 | /* ERESTART means that we need to reboot the guest */ |
1664 | } else if (errno == ERESTART) { | 1910 | } else if (errno == ERESTART) { |
1665 | restart_guest(); | 1911 | restart_guest(); |
1666 | /* EAGAIN means the Waker wanted us to look at some input. | 1912 | /* EAGAIN means a signal (timeout). |
1667 | * Anything else means a bug or incompatible change. */ | 1913 | * Anything else means a bug or incompatible change. */ |
1668 | } else if (errno != EAGAIN) | 1914 | } else if (errno != EAGAIN) |
1669 | err(1, "Running guest failed"); | 1915 | err(1, "Running guest failed"); |
@@ -1691,13 +1937,14 @@ static struct option opts[] = { | |||
1691 | { "verbose", 0, NULL, 'v' }, | 1937 | { "verbose", 0, NULL, 'v' }, |
1692 | { "tunnet", 1, NULL, 't' }, | 1938 | { "tunnet", 1, NULL, 't' }, |
1693 | { "block", 1, NULL, 'b' }, | 1939 | { "block", 1, NULL, 'b' }, |
1940 | { "rng", 0, NULL, 'r' }, | ||
1694 | { "initrd", 1, NULL, 'i' }, | 1941 | { "initrd", 1, NULL, 'i' }, |
1695 | { NULL }, | 1942 | { NULL }, |
1696 | }; | 1943 | }; |
1697 | static void usage(void) | 1944 | static void usage(void) |
1698 | { | 1945 | { |
1699 | errx(1, "Usage: lguest [--verbose] " | 1946 | errx(1, "Usage: lguest [--verbose] " |
1700 | "[--tunnet=(<ipaddr>|bridge:<bridgename>)\n" | 1947 | "[--tunnet=(<ipaddr>:<macaddr>|bridge:<bridgename>:<macaddr>)\n" |
1701 | "|--block=<filename>|--initrd=<filename>]...\n" | 1948 | "|--block=<filename>|--initrd=<filename>]...\n" |
1702 | "<mem-in-mb> vmlinux [args...]"); | 1949 | "<mem-in-mb> vmlinux [args...]"); |
1703 | } | 1950 | } |
@@ -1765,6 +2012,9 @@ int main(int argc, char *argv[]) | |||
1765 | case 'b': | 2012 | case 'b': |
1766 | setup_block_file(optarg); | 2013 | setup_block_file(optarg); |
1767 | break; | 2014 | break; |
2015 | case 'r': | ||
2016 | setup_rng(); | ||
2017 | break; | ||
1768 | case 'i': | 2018 | case 'i': |
1769 | initrd_name = optarg; | 2019 | initrd_name = optarg; |
1770 | break; | 2020 | break; |
@@ -1783,6 +2033,9 @@ int main(int argc, char *argv[]) | |||
1783 | /* We always have a console device */ | 2033 | /* We always have a console device */ |
1784 | setup_console(); | 2034 | setup_console(); |
1785 | 2035 | ||
2036 | /* We can timeout waiting for Guest network transmit. */ | ||
2037 | setup_timeout(); | ||
2038 | |||
1786 | /* Now we load the kernel */ | 2039 | /* Now we load the kernel */ |
1787 | start = load_kernel(open_or_die(argv[optind+1], O_RDONLY)); | 2040 | start = load_kernel(open_or_die(argv[optind+1], O_RDONLY)); |
1788 | 2041 | ||
@@ -1826,10 +2079,10 @@ int main(int argc, char *argv[]) | |||
1826 | * /dev/lguest file descriptor. */ | 2079 | * /dev/lguest file descriptor. */ |
1827 | lguest_fd = tell_kernel(pgdir, start); | 2080 | lguest_fd = tell_kernel(pgdir, start); |
1828 | 2081 | ||
1829 | /* We fork off a child process, which wakes the Launcher whenever one | 2082 | /* We clone off a thread, which wakes the Launcher whenever one of the |
1830 | * of the input file descriptors needs attention. We call this the | 2083 | * input file descriptors needs attention. We call this the Waker, and |
1831 | * Waker, and we'll cover it in a moment. */ | 2084 | * we'll cover it in a moment. */ |
1832 | waker_fd = setup_waker(lguest_fd); | 2085 | setup_waker(lguest_fd); |
1833 | 2086 | ||
1834 | /* Finally, run the Guest. This doesn't return. */ | 2087 | /* Finally, run the Guest. This doesn't return. */ |
1835 | run_guest(lguest_fd); | 2088 | run_guest(lguest_fd); |
diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX index 3be84aa38dfe..29d839ce7327 100644 --- a/Documentation/powerpc/00-INDEX +++ b/Documentation/powerpc/00-INDEX | |||
@@ -20,8 +20,6 @@ mpc52xx-device-tree-bindings.txt | |||
20 | - MPC5200 Device Tree Bindings | 20 | - MPC5200 Device Tree Bindings |
21 | ppc_htab.txt | 21 | ppc_htab.txt |
22 | - info about the Linux/PPC /proc/ppc_htab entry | 22 | - info about the Linux/PPC /proc/ppc_htab entry |
23 | SBC8260_memory_mapping.txt | ||
24 | - EST SBC8260 board info | ||
25 | smp.txt | 23 | smp.txt |
26 | - use and state info about Linux/PPC on MP machines | 24 | - use and state info about Linux/PPC on MP machines |
27 | sound.txt | 25 | sound.txt |
diff --git a/Documentation/powerpc/SBC8260_memory_mapping.txt b/Documentation/powerpc/SBC8260_memory_mapping.txt deleted file mode 100644 index e6e9ee0506c3..000000000000 --- a/Documentation/powerpc/SBC8260_memory_mapping.txt +++ /dev/null | |||
@@ -1,197 +0,0 @@ | |||
1 | Please mail me (Jon Diekema, diekema_jon@si.com or diekema@cideas.com) | ||
2 | if you have questions, comments or corrections. | ||
3 | |||
4 | * EST SBC8260 Linux memory mapping rules | ||
5 | |||
6 | http://www.estc.com/ | ||
7 | http://www.estc.com/products/boards/SBC8260-8240_ds.html | ||
8 | |||
9 | Initial conditions: | ||
10 | ------------------- | ||
11 | |||
12 | Tasks that need to be perform by the boot ROM before control is | ||
13 | transferred to zImage (compressed Linux kernel): | ||
14 | |||
15 | - Define the IMMR to 0xf0000000 | ||
16 | |||
17 | - Initialize the memory controller so that RAM is available at | ||
18 | physical address 0x00000000. On the SBC8260 is this 16M (64M) | ||
19 | SDRAM. | ||
20 | |||
21 | - The boot ROM should only clear the RAM that it is using. | ||
22 | |||
23 | The reason for doing this is to enhances the chances of a | ||
24 | successful post mortem on a Linux panic. One of the first | ||
25 | items to examine is the 16k (LOG_BUF_LEN) circular console | ||
26 | buffer called log_buf which is defined in kernel/printk.c. | ||
27 | |||
28 | - To enhance boot ROM performance, the I-cache can be enabled. | ||
29 | |||
30 | Date: Mon, 22 May 2000 14:21:10 -0700 | ||
31 | From: Neil Russell <caret@c-side.com> | ||
32 | |||
33 | LiMon (LInux MONitor) runs with and starts Linux with MMU | ||
34 | off, I-cache enabled, D-cache disabled. The I-cache doesn't | ||
35 | need hints from the MMU to work correctly as the D-cache | ||
36 | does. No D-cache means no special code to handle devices in | ||
37 | the presence of cache (no snooping, etc). The use of the | ||
38 | I-cache means that the monitor can run acceptably fast | ||
39 | directly from ROM, rather than having to copy it to RAM. | ||
40 | |||
41 | - Build the board information structure (see | ||
42 | include/asm-ppc/est8260.h for its definition) | ||
43 | |||
44 | - The compressed Linux kernel (zImage) contains a bootstrap loader | ||
45 | that is position independent; you can load it into any RAM, | ||
46 | ROM or FLASH memory address >= 0x00500000 (above 5 MB), or | ||
47 | at its link address of 0x00400000 (4 MB). | ||
48 | |||
49 | Note: If zImage is loaded at its link address of 0x00400000 (4 MB), | ||
50 | then zImage will skip the step of moving itself to | ||
51 | its link address. | ||
52 | |||
53 | - Load R3 with the address of the board information structure | ||
54 | |||
55 | - Transfer control to zImage | ||
56 | |||
57 | - The Linux console port is SMC1, and the baud rate is controlled | ||
58 | from the bi_baudrate field of the board information structure. | ||
59 | On thing to keep in mind when picking the baud rate, is that | ||
60 | there is no flow control on the SMC ports. I would stick | ||
61 | with something safe and standard like 19200. | ||
62 | |||
63 | On the EST SBC8260, the SMC1 port is on the COM1 connector of | ||
64 | the board. | ||
65 | |||
66 | |||
67 | EST SBC8260 defaults: | ||
68 | --------------------- | ||
69 | |||
70 | Chip | ||
71 | Memory Sel Bus Use | ||
72 | --------------------- --- --- ---------------------------------- | ||
73 | 0x00000000-0x03FFFFFF CS2 60x (16M or 64M)/64M SDRAM | ||
74 | 0x04000000-0x04FFFFFF CS4 local 4M/16M SDRAM (soldered to the board) | ||
75 | 0x21000000-0x21000000 CS7 60x 1B/64K Flash present detect (from the flash SIMM) | ||
76 | 0x21000001-0x21000001 CS7 60x 1B/64K Switches (read) and LEDs (write) | ||
77 | 0x22000000-0x2200FFFF CS5 60x 8K/64K EEPROM | ||
78 | 0xFC000000-0xFCFFFFFF CS6 60x 2M/16M flash (8 bits wide, soldered to the board) | ||
79 | 0xFE000000-0xFFFFFFFF CS0 60x 4M/16M flash (SIMM) | ||
80 | |||
81 | Notes: | ||
82 | ------ | ||
83 | |||
84 | - The chip selects can map 32K blocks and up (powers of 2) | ||
85 | |||
86 | - The SDRAM machine can handled up to 128Mbytes per chip select | ||
87 | |||
88 | - Linux uses the 60x bus memory (the SDRAM DIMM) for the | ||
89 | communications buffers. | ||
90 | |||
91 | - BATs can map 128K-256Mbytes each. There are four data BATs and | ||
92 | four instruction BATs. Generally the data and instruction BATs | ||
93 | are mapped the same. | ||
94 | |||
95 | - The IMMR must be set above the kernel virtual memory addresses, | ||
96 | which start at 0xC0000000. Otherwise, the kernel may crash as | ||
97 | soon as you start any threads or processes due to VM collisions | ||
98 | in the kernel or user process space. | ||
99 | |||
100 | |||
101 | Details from Dan Malek <dan_malek@mvista.com> on 10/29/1999: | ||
102 | |||
103 | The user application virtual space consumes the first 2 Gbytes | ||
104 | (0x00000000 to 0x7FFFFFFF). The kernel virtual text starts at | ||
105 | 0xC0000000, with data following. There is a "protection hole" | ||
106 | between the end of kernel data and the start of the kernel | ||
107 | dynamically allocated space, but this space is still within | ||
108 | 0xCxxxxxxx. | ||
109 | |||
110 | Obviously the kernel can't map any physical addresses 1:1 in | ||
111 | these ranges. | ||
112 | |||
113 | |||
114 | Details from Dan Malek <dan_malek@mvista.com> on 5/19/2000: | ||
115 | |||
116 | During the early kernel initialization, the kernel virtual | ||
117 | memory allocator is not operational. Prior to this KVM | ||
118 | initialization, we choose to map virtual to physical addresses | ||
119 | 1:1. That is, the kernel virtual address exactly matches the | ||
120 | physical address on the bus. These mappings are typically done | ||
121 | in arch/ppc/kernel/head.S, or arch/ppc/mm/init.c. Only | ||
122 | absolutely necessary mappings should be done at this time, for | ||
123 | example board control registers or a serial uart. Normal device | ||
124 | driver initialization should map resources later when necessary. | ||
125 | |||
126 | Although platform dependent, and certainly the case for embedded | ||
127 | 8xx, traditionally memory is mapped at physical address zero, | ||
128 | and I/O devices above physical address 0x80000000. The lowest | ||
129 | and highest (above 0xf0000000) I/O addresses are traditionally | ||
130 | used for devices or registers we need to map during kernel | ||
131 | initialization and prior to KVM operation. For this reason, | ||
132 | and since it followed prior PowerPC platform examples, I chose | ||
133 | to map the embedded 8xx kernel to the 0xc0000000 virtual address. | ||
134 | This way, we can enable the MMU to map the kernel for proper | ||
135 | operation, and still map a few windows before the KVM is operational. | ||
136 | |||
137 | On some systems, you could possibly run the kernel at the | ||
138 | 0x80000000 or any other virtual address. It just depends upon | ||
139 | mapping that must be done prior to KVM operational. You can never | ||
140 | map devices or kernel spaces that overlap with the user virtual | ||
141 | space. This is why default IMMR mapping used by most BDM tools | ||
142 | won't work. They put the IMMR at something like 0x10000000 or | ||
143 | 0x02000000 for example. You simply can't map these addresses early | ||
144 | in the kernel, and continue proper system operation. | ||
145 | |||
146 | The embedded 8xx/82xx kernel is mature enough that all you should | ||
147 | need to do is map the IMMR someplace at or above 0xf0000000 and it | ||
148 | should boot far enough to get serial console messages and KGDB | ||
149 | connected on any platform. There are lots of other subtle memory | ||
150 | management design features that you simply don't need to worry | ||
151 | about. If you are changing functions related to MMU initialization, | ||
152 | you are likely breaking things that are known to work and are | ||
153 | heading down a path of disaster and frustration. Your changes | ||
154 | should be to make the flexibility of the processor fit Linux, | ||
155 | not force arbitrary and non-workable memory mappings into Linux. | ||
156 | |||
157 | - You don't want to change KERNELLOAD or KERNELBASE, otherwise the | ||
158 | virtual memory and MMU code will get confused. | ||
159 | |||
160 | arch/ppc/Makefile:KERNELLOAD = 0xc0000000 | ||
161 | |||
162 | include/asm-ppc/page.h:#define PAGE_OFFSET 0xc0000000 | ||
163 | include/asm-ppc/page.h:#define KERNELBASE PAGE_OFFSET | ||
164 | |||
165 | - RAM is at physical address 0x00000000, and gets mapped to | ||
166 | virtual address 0xC0000000 for the kernel. | ||
167 | |||
168 | |||
169 | Physical addresses used by the Linux kernel: | ||
170 | -------------------------------------------- | ||
171 | |||
172 | 0x00000000-0x3FFFFFFF 1GB reserved for RAM | ||
173 | 0xF0000000-0xF001FFFF 128K IMMR 64K used for dual port memory, | ||
174 | 64K for 8260 registers | ||
175 | |||
176 | |||
177 | Logical addresses used by the Linux kernel: | ||
178 | ------------------------------------------- | ||
179 | |||
180 | 0xF0000000-0xFFFFFFFF 256M BAT0 (IMMR: dual port RAM, registers) | ||
181 | 0xE0000000-0xEFFFFFFF 256M BAT1 (I/O space for custom boards) | ||
182 | 0xC0000000-0xCFFFFFFF 256M BAT2 (RAM) | ||
183 | 0xD0000000-0xDFFFFFFF 256M BAT3 (if RAM > 256MByte) | ||
184 | |||
185 | |||
186 | EST SBC8260 Linux mapping: | ||
187 | -------------------------- | ||
188 | |||
189 | DBAT0, IBAT0, cache inhibited: | ||
190 | |||
191 | Chip | ||
192 | Memory Sel Use | ||
193 | --------------------- --- --------------------------------- | ||
194 | 0xF0000000-0xF001FFFF n/a IMMR: dual port RAM, registers | ||
195 | |||
196 | DBAT1, IBAT1, cache inhibited: | ||
197 | |||
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt index b35f3482e3e4..2ea76d9d137c 100644 --- a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt +++ b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt | |||
@@ -7,6 +7,15 @@ Currently defined compatibles: | |||
7 | - fsl,cpm2-scc-uart | 7 | - fsl,cpm2-scc-uart |
8 | - fsl,qe-uart | 8 | - fsl,qe-uart |
9 | 9 | ||
10 | Modem control lines connected to GPIO controllers are listed in the gpios | ||
11 | property as described in booting-without-of.txt, section IX.1 in the following | ||
12 | order: | ||
13 | |||
14 | CTS, RTS, DCD, DSR, DTR, and RI. | ||
15 | |||
16 | The gpios property is optional and can be left out when control lines are | ||
17 | not used. | ||
18 | |||
10 | Example: | 19 | Example: |
11 | 20 | ||
12 | serial@11a00 { | 21 | serial@11a00 { |
@@ -18,4 +27,6 @@ Example: | |||
18 | interrupt-parent = <&PIC>; | 27 | interrupt-parent = <&PIC>; |
19 | fsl,cpm-brg = <1>; | 28 | fsl,cpm-brg = <1>; |
20 | fsl,cpm-command = <00800000>; | 29 | fsl,cpm-command = <00800000>; |
30 | gpios = <&gpio_c 15 0 | ||
31 | &gpio_d 29 0>; | ||
21 | }; | 32 | }; |
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index 0843ed0163a5..28b6ec87c642 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt | |||
@@ -390,9 +390,10 @@ rfkill lines are inactive, it must return RFKILL_STATE_SOFT_BLOCKED if its soft | |||
390 | rfkill input line is active. Only if none of the rfkill input lines are | 390 | rfkill input line is active. Only if none of the rfkill input lines are |
391 | active, will it return RFKILL_STATE_UNBLOCKED. | 391 | active, will it return RFKILL_STATE_UNBLOCKED. |
392 | 392 | ||
393 | If it doesn't implement the get_state() hook, it must make sure that its calls | 393 | Since the device has a hardware rfkill line, it IS subject to state changes |
394 | to rfkill_force_state() are enough to keep the status always up-to-date, and it | 394 | external to rfkill. Therefore, the driver must make sure that it calls |
395 | must do a rfkill_force_state() on resume from sleep. | 395 | rfkill_force_state() to keep the status always up-to-date, and it must do a |
396 | rfkill_force_state() on resume from sleep. | ||
396 | 397 | ||
397 | Every time the driver gets a notification from the card that one of its rfkill | 398 | Every time the driver gets a notification from the card that one of its rfkill |
398 | lines changed state (polling might be needed on badly designed cards that don't | 399 | lines changed state (polling might be needed on badly designed cards that don't |
@@ -422,13 +423,24 @@ of the hardware is unknown), or read-write (where the hardware can be queried | |||
422 | about its current state). | 423 | about its current state). |
423 | 424 | ||
424 | The rfkill class will call the get_state hook of a device every time it needs | 425 | The rfkill class will call the get_state hook of a device every time it needs |
425 | to know the *real* current state of the hardware. This can happen often. | 426 | to know the *real* current state of the hardware. This can happen often, but |
427 | it does not do any polling, so it is not enough on hardware that is subject | ||
428 | to state changes outside of the rfkill subsystem. | ||
429 | |||
430 | Therefore, calling rfkill_force_state() when a state change happens is | ||
431 | mandatory when the device has a hardware rfkill line, or when something else | ||
432 | like the firmware could cause its state to be changed without going through the | ||
433 | rfkill class. | ||
426 | 434 | ||
427 | Some hardware provides events when its status changes. In these cases, it is | 435 | Some hardware provides events when its status changes. In these cases, it is |
428 | best for the driver to not provide a get_state hook, and instead register the | 436 | best for the driver to not provide a get_state hook, and instead register the |
429 | rfkill class *already* with the correct status, and keep it updated using | 437 | rfkill class *already* with the correct status, and keep it updated using |
430 | rfkill_force_state() when it gets an event from the hardware. | 438 | rfkill_force_state() when it gets an event from the hardware. |
431 | 439 | ||
440 | rfkill_force_state() must be used on the device resume handlers to update the | ||
441 | rfkill status, should there be any chance of the device status changing during | ||
442 | the sleep. | ||
443 | |||
432 | There is no provision for a statically-allocated rfkill struct. You must | 444 | There is no provision for a statically-allocated rfkill struct. You must |
433 | use rfkill_allocate() to allocate one. | 445 | use rfkill_allocate() to allocate one. |
434 | 446 | ||
@@ -1,7 +1,7 @@ | |||
1 | VERSION = 2 | 1 | VERSION = 2 |
2 | PATCHLEVEL = 6 | 2 | PATCHLEVEL = 6 |
3 | SUBLEVEL = 26 | 3 | SUBLEVEL = 27 |
4 | EXTRAVERSION = | 4 | EXTRAVERSION = -rc1 |
5 | NAME = Rotary Wombat | 5 | NAME = Rotary Wombat |
6 | 6 | ||
7 | # *DOCUMENTATION* | 7 | # *DOCUMENTATION* |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c8f528284a94..257033c691f2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -17,6 +17,7 @@ config ARM | |||
17 | select HAVE_KRETPROBES if (HAVE_KPROBES) | 17 | select HAVE_KRETPROBES if (HAVE_KPROBES) |
18 | select HAVE_FTRACE if (!XIP_KERNEL) | 18 | select HAVE_FTRACE if (!XIP_KERNEL) |
19 | select HAVE_DYNAMIC_FTRACE if (HAVE_FTRACE) | 19 | select HAVE_DYNAMIC_FTRACE if (HAVE_FTRACE) |
20 | select HAVE_GENERIC_DMA_COHERENT | ||
20 | help | 21 | help |
21 | The ARM series is a line of low-power-consumption RISC chip designs | 22 | The ARM series is a line of low-power-consumption RISC chip designs |
22 | licensed by ARM Ltd and targeted at embedded applications and | 23 | licensed by ARM Ltd and targeted at embedded applications and |
@@ -234,6 +235,7 @@ config ARCH_VERSATILE | |||
234 | config ARCH_AT91 | 235 | config ARCH_AT91 |
235 | bool "Atmel AT91" | 236 | bool "Atmel AT91" |
236 | select GENERIC_GPIO | 237 | select GENERIC_GPIO |
238 | select HAVE_CLK | ||
237 | help | 239 | help |
238 | This enables support for systems based on the Atmel AT91RM9200, | 240 | This enables support for systems based on the Atmel AT91RM9200, |
239 | AT91SAM9 and AT91CAP9 processors. | 241 | AT91SAM9 and AT91CAP9 processors. |
@@ -267,7 +269,6 @@ config ARCH_EP93XX | |||
267 | select ARM_VIC | 269 | select ARM_VIC |
268 | select GENERIC_GPIO | 270 | select GENERIC_GPIO |
269 | select HAVE_CLK | 271 | select HAVE_CLK |
270 | select HAVE_CLK | ||
271 | select ARCH_REQUIRE_GPIOLIB | 272 | select ARCH_REQUIRE_GPIOLIB |
272 | help | 273 | help |
273 | This enables support for the Cirrus EP93xx series of CPUs. | 274 | This enables support for the Cirrus EP93xx series of CPUs. |
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 333a82a3717e..db7b3e38ef1d 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c | |||
@@ -274,6 +274,11 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, | |||
274 | void * | 274 | void * |
275 | dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) | 275 | dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) |
276 | { | 276 | { |
277 | void *memory; | ||
278 | |||
279 | if (dma_alloc_from_coherent(dev, size, handle, &memory)) | ||
280 | return memory; | ||
281 | |||
277 | if (arch_is_coherent()) { | 282 | if (arch_is_coherent()) { |
278 | void *virt; | 283 | void *virt; |
279 | 284 | ||
@@ -362,6 +367,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr | |||
362 | 367 | ||
363 | WARN_ON(irqs_disabled()); | 368 | WARN_ON(irqs_disabled()); |
364 | 369 | ||
370 | if (dma_release_from_coherent(dev, get_order(size), cpu_addr)) | ||
371 | return; | ||
372 | |||
365 | if (arch_is_coherent()) { | 373 | if (arch_is_coherent()) { |
366 | kfree(cpu_addr); | 374 | kfree(cpu_addr); |
367 | return; | 375 | return; |
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index 2a92cb1886ca..7a64fcef9d07 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig | |||
@@ -641,6 +641,7 @@ config PCI | |||
641 | bool | 641 | bool |
642 | depends on ETRAX_CARDBUS | 642 | depends on ETRAX_CARDBUS |
643 | default y | 643 | default y |
644 | select HAVE_GENERIC_DMA_COHERENT | ||
644 | 645 | ||
645 | config ETRAX_IOP_FW_LOAD | 646 | config ETRAX_IOP_FW_LOAD |
646 | tristate "IO-processor hotplug firmware loading support" | 647 | tristate "IO-processor hotplug firmware loading support" |
diff --git a/arch/cris/arch-v32/drivers/pci/dma.c b/arch/cris/arch-v32/drivers/pci/dma.c index e0364654fc44..fbe65954ee6c 100644 --- a/arch/cris/arch-v32/drivers/pci/dma.c +++ b/arch/cris/arch-v32/drivers/pci/dma.c | |||
@@ -15,35 +15,16 @@ | |||
15 | #include <linux/pci.h> | 15 | #include <linux/pci.h> |
16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
17 | 17 | ||
18 | struct dma_coherent_mem { | ||
19 | void *virt_base; | ||
20 | u32 device_base; | ||
21 | int size; | ||
22 | int flags; | ||
23 | unsigned long *bitmap; | ||
24 | }; | ||
25 | |||
26 | void *dma_alloc_coherent(struct device *dev, size_t size, | 18 | void *dma_alloc_coherent(struct device *dev, size_t size, |
27 | dma_addr_t *dma_handle, gfp_t gfp) | 19 | dma_addr_t *dma_handle, gfp_t gfp) |
28 | { | 20 | { |
29 | void *ret; | 21 | void *ret; |
30 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
31 | int order = get_order(size); | 22 | int order = get_order(size); |
32 | /* ignore region specifiers */ | 23 | /* ignore region specifiers */ |
33 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); | 24 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); |
34 | 25 | ||
35 | if (mem) { | 26 | if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) |
36 | int page = bitmap_find_free_region(mem->bitmap, mem->size, | 27 | return ret; |
37 | order); | ||
38 | if (page >= 0) { | ||
39 | *dma_handle = mem->device_base + (page << PAGE_SHIFT); | ||
40 | ret = mem->virt_base + (page << PAGE_SHIFT); | ||
41 | memset(ret, 0, size); | ||
42 | return ret; | ||
43 | } | ||
44 | if (mem->flags & DMA_MEMORY_EXCLUSIVE) | ||
45 | return NULL; | ||
46 | } | ||
47 | 28 | ||
48 | if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) | 29 | if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) |
49 | gfp |= GFP_DMA; | 30 | gfp |= GFP_DMA; |
@@ -60,90 +41,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size, | |||
60 | void dma_free_coherent(struct device *dev, size_t size, | 41 | void dma_free_coherent(struct device *dev, size_t size, |
61 | void *vaddr, dma_addr_t dma_handle) | 42 | void *vaddr, dma_addr_t dma_handle) |
62 | { | 43 | { |
63 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
64 | int order = get_order(size); | 44 | int order = get_order(size); |
65 | 45 | ||
66 | if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { | 46 | if (!dma_release_from_coherent(dev, order, vaddr)) |
67 | int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; | ||
68 | |||
69 | bitmap_release_region(mem->bitmap, page, order); | ||
70 | } else | ||
71 | free_pages((unsigned long)vaddr, order); | 47 | free_pages((unsigned long)vaddr, order); |
72 | } | 48 | } |
73 | 49 | ||
74 | int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
75 | dma_addr_t device_addr, size_t size, int flags) | ||
76 | { | ||
77 | void __iomem *mem_base; | ||
78 | int pages = size >> PAGE_SHIFT; | ||
79 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
80 | |||
81 | if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) | ||
82 | goto out; | ||
83 | if (!size) | ||
84 | goto out; | ||
85 | if (dev->dma_mem) | ||
86 | goto out; | ||
87 | |||
88 | /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ | ||
89 | |||
90 | mem_base = ioremap(bus_addr, size); | ||
91 | if (!mem_base) | ||
92 | goto out; | ||
93 | |||
94 | dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); | ||
95 | if (!dev->dma_mem) | ||
96 | goto iounmap_out; | ||
97 | dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
98 | if (!dev->dma_mem->bitmap) | ||
99 | goto free1_out; | ||
100 | |||
101 | dev->dma_mem->virt_base = mem_base; | ||
102 | dev->dma_mem->device_base = device_addr; | ||
103 | dev->dma_mem->size = pages; | ||
104 | dev->dma_mem->flags = flags; | ||
105 | |||
106 | if (flags & DMA_MEMORY_MAP) | ||
107 | return DMA_MEMORY_MAP; | ||
108 | |||
109 | return DMA_MEMORY_IO; | ||
110 | |||
111 | free1_out: | ||
112 | kfree(dev->dma_mem); | ||
113 | iounmap_out: | ||
114 | iounmap(mem_base); | ||
115 | out: | ||
116 | return 0; | ||
117 | } | ||
118 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
119 | |||
120 | void dma_release_declared_memory(struct device *dev) | ||
121 | { | ||
122 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
123 | |||
124 | if(!mem) | ||
125 | return; | ||
126 | dev->dma_mem = NULL; | ||
127 | iounmap(mem->virt_base); | ||
128 | kfree(mem->bitmap); | ||
129 | kfree(mem); | ||
130 | } | ||
131 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
132 | |||
133 | void *dma_mark_declared_memory_occupied(struct device *dev, | ||
134 | dma_addr_t device_addr, size_t size) | ||
135 | { | ||
136 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
137 | int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
138 | int pos, err; | ||
139 | |||
140 | if (!mem) | ||
141 | return ERR_PTR(-EINVAL); | ||
142 | |||
143 | pos = (device_addr - mem->device_base) >> PAGE_SHIFT; | ||
144 | err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); | ||
145 | if (err != 0) | ||
146 | return ERR_PTR(err); | ||
147 | return mem->virt_base + (pos << PAGE_SHIFT); | ||
148 | } | ||
149 | EXPORT_SYMBOL(dma_mark_declared_memory_occupied); | ||
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index c45fc7f5a979..b0f615759e97 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/mm.h> | 13 | #include <linux/mm.h> |
14 | #include <linux/hugetlb.h> | 14 | #include <linux/hugetlb.h> |
15 | #include <linux/pagemap.h> | 15 | #include <linux/pagemap.h> |
16 | #include <linux/module.h> | ||
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
17 | #include <linux/sysctl.h> | 18 | #include <linux/sysctl.h> |
18 | #include <linux/log2.h> | 19 | #include <linux/log2.h> |
@@ -21,7 +22,8 @@ | |||
21 | #include <asm/tlb.h> | 22 | #include <asm/tlb.h> |
22 | #include <asm/tlbflush.h> | 23 | #include <asm/tlbflush.h> |
23 | 24 | ||
24 | unsigned int hpage_shift=HPAGE_SHIFT_DEFAULT; | 25 | unsigned int hpage_shift = HPAGE_SHIFT_DEFAULT; |
26 | EXPORT_SYMBOL(hpage_shift); | ||
25 | 27 | ||
26 | pte_t * | 28 | pte_t * |
27 | huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz) | 29 | huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz) |
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b4c4eaa5dd26..4da736e25333 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -3,6 +3,7 @@ config MIPS | |||
3 | default y | 3 | default y |
4 | select HAVE_IDE | 4 | select HAVE_IDE |
5 | select HAVE_OPROFILE | 5 | select HAVE_OPROFILE |
6 | select HAVE_ARCH_KGDB | ||
6 | # Horrible source of confusion. Die, die, die ... | 7 | # Horrible source of confusion. Die, die, die ... |
7 | select EMBEDDED | 8 | select EMBEDDED |
8 | select RTC_LIB | 9 | select RTC_LIB |
@@ -34,7 +35,6 @@ config BASLER_EXCITE | |||
34 | select SYS_HAS_CPU_RM9000 | 35 | select SYS_HAS_CPU_RM9000 |
35 | select SYS_SUPPORTS_32BIT_KERNEL | 36 | select SYS_SUPPORTS_32BIT_KERNEL |
36 | select SYS_SUPPORTS_BIG_ENDIAN | 37 | select SYS_SUPPORTS_BIG_ENDIAN |
37 | select SYS_SUPPORTS_KGDB | ||
38 | help | 38 | help |
39 | The eXcite is a smart camera platform manufactured by | 39 | The eXcite is a smart camera platform manufactured by |
40 | Basler Vision Technologies AG. | 40 | Basler Vision Technologies AG. |
@@ -280,7 +280,6 @@ config PMC_MSP | |||
280 | select SYS_HAS_CPU_MIPS32_R2 | 280 | select SYS_HAS_CPU_MIPS32_R2 |
281 | select SYS_SUPPORTS_32BIT_KERNEL | 281 | select SYS_SUPPORTS_32BIT_KERNEL |
282 | select SYS_SUPPORTS_BIG_ENDIAN | 282 | select SYS_SUPPORTS_BIG_ENDIAN |
283 | select SYS_SUPPORTS_KGDB | ||
284 | select IRQ_CPU | 283 | select IRQ_CPU |
285 | select SERIAL_8250 | 284 | select SERIAL_8250 |
286 | select SERIAL_8250_CONSOLE | 285 | select SERIAL_8250_CONSOLE |
@@ -306,7 +305,6 @@ config PMC_YOSEMITE | |||
306 | select SYS_SUPPORTS_64BIT_KERNEL | 305 | select SYS_SUPPORTS_64BIT_KERNEL |
307 | select SYS_SUPPORTS_BIG_ENDIAN | 306 | select SYS_SUPPORTS_BIG_ENDIAN |
308 | select SYS_SUPPORTS_HIGHMEM | 307 | select SYS_SUPPORTS_HIGHMEM |
309 | select SYS_SUPPORTS_KGDB | ||
310 | select SYS_SUPPORTS_SMP | 308 | select SYS_SUPPORTS_SMP |
311 | help | 309 | help |
312 | Yosemite is an evaluation board for the RM9000x2 processor | 310 | Yosemite is an evaluation board for the RM9000x2 processor |
@@ -359,7 +357,6 @@ config SGI_IP27 | |||
359 | select SYS_HAS_CPU_R10000 | 357 | select SYS_HAS_CPU_R10000 |
360 | select SYS_SUPPORTS_64BIT_KERNEL | 358 | select SYS_SUPPORTS_64BIT_KERNEL |
361 | select SYS_SUPPORTS_BIG_ENDIAN | 359 | select SYS_SUPPORTS_BIG_ENDIAN |
362 | select SYS_SUPPORTS_KGDB | ||
363 | select SYS_SUPPORTS_NUMA | 360 | select SYS_SUPPORTS_NUMA |
364 | select SYS_SUPPORTS_SMP | 361 | select SYS_SUPPORTS_SMP |
365 | select GENERIC_HARDIRQS_NO__DO_IRQ | 362 | select GENERIC_HARDIRQS_NO__DO_IRQ |
@@ -475,7 +472,6 @@ config SIBYTE_SWARM | |||
475 | select SYS_HAS_CPU_SB1 | 472 | select SYS_HAS_CPU_SB1 |
476 | select SYS_SUPPORTS_BIG_ENDIAN | 473 | select SYS_SUPPORTS_BIG_ENDIAN |
477 | select SYS_SUPPORTS_HIGHMEM | 474 | select SYS_SUPPORTS_HIGHMEM |
478 | select SYS_SUPPORTS_KGDB | ||
479 | select SYS_SUPPORTS_LITTLE_ENDIAN | 475 | select SYS_SUPPORTS_LITTLE_ENDIAN |
480 | select ZONE_DMA32 if 64BIT | 476 | select ZONE_DMA32 if 64BIT |
481 | 477 | ||
@@ -868,7 +864,6 @@ config SOC_PNX8550 | |||
868 | select SYS_HAS_EARLY_PRINTK | 864 | select SYS_HAS_EARLY_PRINTK |
869 | select SYS_SUPPORTS_32BIT_KERNEL | 865 | select SYS_SUPPORTS_32BIT_KERNEL |
870 | select GENERIC_HARDIRQS_NO__DO_IRQ | 866 | select GENERIC_HARDIRQS_NO__DO_IRQ |
871 | select SYS_SUPPORTS_KGDB | ||
872 | select GENERIC_GPIO | 867 | select GENERIC_GPIO |
873 | 868 | ||
874 | config SWAP_IO_SPACE | 869 | config SWAP_IO_SPACE |
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index f18cf92650e3..765c8e287d2b 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug | |||
@@ -34,28 +34,6 @@ config SMTC_IDLE_HOOK_DEBUG | |||
34 | arch/mips/kernel/smtc.c. This debugging option result in significant | 34 | arch/mips/kernel/smtc.c. This debugging option result in significant |
35 | overhead so should be disabled in production kernels. | 35 | overhead so should be disabled in production kernels. |
36 | 36 | ||
37 | config KGDB | ||
38 | bool "Remote GDB kernel debugging" | ||
39 | depends on DEBUG_KERNEL && SYS_SUPPORTS_KGDB | ||
40 | select DEBUG_INFO | ||
41 | help | ||
42 | If you say Y here, it will be possible to remotely debug the MIPS | ||
43 | kernel using gdb. This enlarges your kernel image disk size by | ||
44 | several megabytes and requires a machine with more than 16 MB, | ||
45 | better 32 MB RAM to avoid excessive linking time. This is only | ||
46 | useful for kernel hackers. If unsure, say N. | ||
47 | |||
48 | config SYS_SUPPORTS_KGDB | ||
49 | bool | ||
50 | |||
51 | config GDB_CONSOLE | ||
52 | bool "Console output to GDB" | ||
53 | depends on KGDB | ||
54 | help | ||
55 | If you are using GDB for remote debugging over a serial port and | ||
56 | would like kernel messages to be formatted into GDB $O packets so | ||
57 | that GDB prints them as program output, say 'Y'. | ||
58 | |||
59 | config SB1XXX_CORELIS | 37 | config SB1XXX_CORELIS |
60 | bool "Corelis Debugger" | 38 | bool "Corelis Debugger" |
61 | depends on SIBYTE_SB1xxx_SOC | 39 | depends on SIBYTE_SB1xxx_SOC |
diff --git a/arch/mips/au1000/Kconfig b/arch/mips/au1000/Kconfig index 1fe97cccead1..e4a057d80ab6 100644 --- a/arch/mips/au1000/Kconfig +++ b/arch/mips/au1000/Kconfig | |||
@@ -134,4 +134,3 @@ config SOC_AU1X00 | |||
134 | select SYS_HAS_CPU_MIPS32_R1 | 134 | select SYS_HAS_CPU_MIPS32_R1 |
135 | select SYS_SUPPORTS_32BIT_KERNEL | 135 | select SYS_SUPPORTS_32BIT_KERNEL |
136 | select SYS_SUPPORTS_APM_EMULATION | 136 | select SYS_SUPPORTS_APM_EMULATION |
137 | select SYS_SUPPORTS_KGDB | ||
diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile index dd0e19dacfcf..df48fd65bbf3 100644 --- a/arch/mips/au1000/common/Makefile +++ b/arch/mips/au1000/common/Makefile | |||
@@ -9,7 +9,6 @@ obj-y += prom.o irq.o puts.o time.o reset.o \ | |||
9 | au1xxx_irqmap.o clocks.o platform.o power.o setup.o \ | 9 | au1xxx_irqmap.o clocks.o platform.o power.o setup.o \ |
10 | sleeper.o cputable.o dma.o dbdma.o gpio.o | 10 | sleeper.o cputable.o dma.o dbdma.o gpio.o |
11 | 11 | ||
12 | obj-$(CONFIG_KGDB) += dbg_io.o | ||
13 | obj-$(CONFIG_PCI) += pci.o | 12 | obj-$(CONFIG_PCI) += pci.o |
14 | 13 | ||
15 | EXTRA_CFLAGS += -Werror | 14 | EXTRA_CFLAGS += -Werror |
diff --git a/arch/mips/au1000/common/dbg_io.c b/arch/mips/au1000/common/dbg_io.c deleted file mode 100644 index af5be7df2f2a..000000000000 --- a/arch/mips/au1000/common/dbg_io.c +++ /dev/null | |||
@@ -1,109 +0,0 @@ | |||
1 | #include <linux/types.h> | ||
2 | |||
3 | #include <asm/mach-au1x00/au1000.h> | ||
4 | |||
5 | #ifdef CONFIG_KGDB | ||
6 | |||
7 | /* | ||
8 | * FIXME the user should be able to select the | ||
9 | * uart to be used for debugging. | ||
10 | */ | ||
11 | #define DEBUG_BASE UART_DEBUG_BASE | ||
12 | |||
13 | #define UART16550_BAUD_2400 2400 | ||
14 | #define UART16550_BAUD_4800 4800 | ||
15 | #define UART16550_BAUD_9600 9600 | ||
16 | #define UART16550_BAUD_19200 19200 | ||
17 | #define UART16550_BAUD_38400 38400 | ||
18 | #define UART16550_BAUD_57600 57600 | ||
19 | #define UART16550_BAUD_115200 115200 | ||
20 | |||
21 | #define UART16550_PARITY_NONE 0 | ||
22 | #define UART16550_PARITY_ODD 0x08 | ||
23 | #define UART16550_PARITY_EVEN 0x18 | ||
24 | #define UART16550_PARITY_MARK 0x28 | ||
25 | #define UART16550_PARITY_SPACE 0x38 | ||
26 | |||
27 | #define UART16550_DATA_5BIT 0x0 | ||
28 | #define UART16550_DATA_6BIT 0x1 | ||
29 | #define UART16550_DATA_7BIT 0x2 | ||
30 | #define UART16550_DATA_8BIT 0x3 | ||
31 | |||
32 | #define UART16550_STOP_1BIT 0x0 | ||
33 | #define UART16550_STOP_2BIT 0x4 | ||
34 | |||
35 | |||
36 | #define UART_RX 0 /* Receive buffer */ | ||
37 | #define UART_TX 4 /* Transmit buffer */ | ||
38 | #define UART_IER 8 /* Interrupt Enable Register */ | ||
39 | #define UART_IIR 0xC /* Interrupt ID Register */ | ||
40 | #define UART_FCR 0x10 /* FIFO Control Register */ | ||
41 | #define UART_LCR 0x14 /* Line Control Register */ | ||
42 | #define UART_MCR 0x18 /* Modem Control Register */ | ||
43 | #define UART_LSR 0x1C /* Line Status Register */ | ||
44 | #define UART_MSR 0x20 /* Modem Status Register */ | ||
45 | #define UART_CLK 0x28 /* Baud Rat4e Clock Divider */ | ||
46 | #define UART_MOD_CNTRL 0x100 /* Module Control */ | ||
47 | |||
48 | /* memory-mapped read/write of the port */ | ||
49 | #define UART16550_READ(y) (au_readl(DEBUG_BASE + y) & 0xff) | ||
50 | #define UART16550_WRITE(y, z) (au_writel(z & 0xff, DEBUG_BASE + y)) | ||
51 | |||
52 | extern unsigned long calc_clock(void); | ||
53 | |||
54 | void debugInit(u32 baud, u8 data, u8 parity, u8 stop) | ||
55 | { | ||
56 | if (UART16550_READ(UART_MOD_CNTRL) != 0x3) | ||
57 | UART16550_WRITE(UART_MOD_CNTRL, 3); | ||
58 | calc_clock(); | ||
59 | |||
60 | /* disable interrupts */ | ||
61 | UART16550_WRITE(UART_IER, 0); | ||
62 | |||
63 | /* set up baud rate */ | ||
64 | { | ||
65 | u32 divisor; | ||
66 | |||
67 | /* set divisor */ | ||
68 | divisor = get_au1x00_uart_baud_base() / baud; | ||
69 | UART16550_WRITE(UART_CLK, divisor & 0xffff); | ||
70 | } | ||
71 | |||
72 | /* set data format */ | ||
73 | UART16550_WRITE(UART_LCR, (data | parity | stop)); | ||
74 | } | ||
75 | |||
76 | static int remoteDebugInitialized; | ||
77 | |||
78 | u8 getDebugChar(void) | ||
79 | { | ||
80 | if (!remoteDebugInitialized) { | ||
81 | remoteDebugInitialized = 1; | ||
82 | debugInit(UART16550_BAUD_115200, | ||
83 | UART16550_DATA_8BIT, | ||
84 | UART16550_PARITY_NONE, | ||
85 | UART16550_STOP_1BIT); | ||
86 | } | ||
87 | |||
88 | while ((UART16550_READ(UART_LSR) & 0x1) == 0); | ||
89 | return UART16550_READ(UART_RX); | ||
90 | } | ||
91 | |||
92 | |||
93 | int putDebugChar(u8 byte) | ||
94 | { | ||
95 | if (!remoteDebugInitialized) { | ||
96 | remoteDebugInitialized = 1; | ||
97 | debugInit(UART16550_BAUD_115200, | ||
98 | UART16550_DATA_8BIT, | ||
99 | UART16550_PARITY_NONE, | ||
100 | UART16550_STOP_1BIT); | ||
101 | } | ||
102 | |||
103 | while ((UART16550_READ(UART_LSR) & 0x40) == 0); | ||
104 | UART16550_WRITE(UART_TX, byte); | ||
105 | |||
106 | return 1; | ||
107 | } | ||
108 | |||
109 | #endif | ||
diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/au1000/db1x00/init.c index 5ebe0de5e459..847413514964 100644 --- a/arch/mips/au1000/db1x00/init.c +++ b/arch/mips/au1000/db1x00/init.c | |||
@@ -57,6 +57,6 @@ void __init prom_init(void) | |||
57 | if (!memsize_str) | 57 | if (!memsize_str) |
58 | memsize = 0x04000000; | 58 | memsize = 0x04000000; |
59 | else | 59 | else |
60 | memsize = strict_strtol(memsize_str, 0, NULL); | 60 | strict_strtol(memsize_str, 0, &memsize); |
61 | add_memory_region(0, memsize, BOOT_MEM_RAM); | 61 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
62 | } | 62 | } |
diff --git a/arch/mips/au1000/mtx-1/init.c b/arch/mips/au1000/mtx-1/init.c index 33a4aebe0cba..3bae13c28954 100644 --- a/arch/mips/au1000/mtx-1/init.c +++ b/arch/mips/au1000/mtx-1/init.c | |||
@@ -55,6 +55,6 @@ void __init prom_init(void) | |||
55 | if (!memsize_str) | 55 | if (!memsize_str) |
56 | memsize = 0x04000000; | 56 | memsize = 0x04000000; |
57 | else | 57 | else |
58 | memsize = strict_strtol(memsize_str, 0, NULL); | 58 | strict_strtol(memsize_str, 0, &memsize); |
59 | add_memory_region(0, memsize, BOOT_MEM_RAM); | 59 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
60 | } | 60 | } |
diff --git a/arch/mips/au1000/pb1000/init.c b/arch/mips/au1000/pb1000/init.c index 3837365d613d..8a9c7d57208d 100644 --- a/arch/mips/au1000/pb1000/init.c +++ b/arch/mips/au1000/pb1000/init.c | |||
@@ -52,6 +52,6 @@ void __init prom_init(void) | |||
52 | if (!memsize_str) | 52 | if (!memsize_str) |
53 | memsize = 0x04000000; | 53 | memsize = 0x04000000; |
54 | else | 54 | else |
55 | memsize = strict_strtol(memsize_str, 0, NULL); | 55 | strict_strtol(memsize_str, 0, &memsize); |
56 | add_memory_region(0, memsize, BOOT_MEM_RAM); | 56 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
57 | } | 57 | } |
diff --git a/arch/mips/au1000/pb1100/init.c b/arch/mips/au1000/pb1100/init.c index 8355483f3de2..7c6792308bc5 100644 --- a/arch/mips/au1000/pb1100/init.c +++ b/arch/mips/au1000/pb1100/init.c | |||
@@ -54,7 +54,7 @@ void __init prom_init(void) | |||
54 | if (!memsize_str) | 54 | if (!memsize_str) |
55 | memsize = 0x04000000; | 55 | memsize = 0x04000000; |
56 | else | 56 | else |
57 | memsize = strict_strtol(memsize_str, 0, NULL); | 57 | strict_strtol(memsize_str, 0, &memsize); |
58 | 58 | ||
59 | add_memory_region(0, memsize, BOOT_MEM_RAM); | 59 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
60 | } | 60 | } |
diff --git a/arch/mips/au1000/pb1200/init.c b/arch/mips/au1000/pb1200/init.c index 09fd63b86062..e9b2a0fd48ae 100644 --- a/arch/mips/au1000/pb1200/init.c +++ b/arch/mips/au1000/pb1200/init.c | |||
@@ -53,6 +53,6 @@ void __init prom_init(void) | |||
53 | if (!memsize_str) | 53 | if (!memsize_str) |
54 | memsize = 0x08000000; | 54 | memsize = 0x08000000; |
55 | else | 55 | else |
56 | memsize = strict_strtol(memsize_str, 0, NULL); | 56 | strict_strtol(memsize_str, 0, &memsize); |
57 | add_memory_region(0, memsize, BOOT_MEM_RAM); | 57 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
58 | } | 58 | } |
diff --git a/arch/mips/au1000/pb1500/init.c b/arch/mips/au1000/pb1500/init.c index 49f51e165863..3b6e395cf952 100644 --- a/arch/mips/au1000/pb1500/init.c +++ b/arch/mips/au1000/pb1500/init.c | |||
@@ -53,6 +53,6 @@ void __init prom_init(void) | |||
53 | if (!memsize_str) | 53 | if (!memsize_str) |
54 | memsize = 0x04000000; | 54 | memsize = 0x04000000; |
55 | else | 55 | else |
56 | memsize = strict_strtol(memsize_str, 0, NULL); | 56 | strict_strtol(memsize_str, 0, &memsize); |
57 | add_memory_region(0, memsize, BOOT_MEM_RAM); | 57 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
58 | } | 58 | } |
diff --git a/arch/mips/au1000/pb1550/init.c b/arch/mips/au1000/pb1550/init.c index 1b5f58434bb7..e1055a13a1a0 100644 --- a/arch/mips/au1000/pb1550/init.c +++ b/arch/mips/au1000/pb1550/init.c | |||
@@ -53,6 +53,6 @@ void __init prom_init(void) | |||
53 | if (!memsize_str) | 53 | if (!memsize_str) |
54 | memsize = 0x08000000; | 54 | memsize = 0x08000000; |
55 | else | 55 | else |
56 | memsize = strict_strtol(memsize_str, 0, NULL); | 56 | strict_strtol(memsize_str, 0, &memsize); |
57 | add_memory_region(0, memsize, BOOT_MEM_RAM); | 57 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
58 | } | 58 | } |
diff --git a/arch/mips/au1000/xxs1500/init.c b/arch/mips/au1000/xxs1500/init.c index b849bf501c04..7516434760a1 100644 --- a/arch/mips/au1000/xxs1500/init.c +++ b/arch/mips/au1000/xxs1500/init.c | |||
@@ -53,6 +53,6 @@ void __init prom_init(void) | |||
53 | if (!memsize_str) | 53 | if (!memsize_str) |
54 | memsize = 0x04000000; | 54 | memsize = 0x04000000; |
55 | else | 55 | else |
56 | memsize = strict_strtol(memsize_str, 0, NULL); | 56 | strict_strtol(memsize_str, 0, &memsize); |
57 | add_memory_region(0, memsize, BOOT_MEM_RAM); | 57 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
58 | } | 58 | } |
diff --git a/arch/mips/basler/excite/Makefile b/arch/mips/basler/excite/Makefile index 519142c2e4ef..cff29cf46d03 100644 --- a/arch/mips/basler/excite/Makefile +++ b/arch/mips/basler/excite/Makefile | |||
@@ -5,5 +5,4 @@ | |||
5 | obj-$(CONFIG_BASLER_EXCITE) += excite_irq.o excite_prom.o excite_setup.o \ | 5 | obj-$(CONFIG_BASLER_EXCITE) += excite_irq.o excite_prom.o excite_setup.o \ |
6 | excite_device.o excite_procfs.o | 6 | excite_device.o excite_procfs.o |
7 | 7 | ||
8 | obj-$(CONFIG_KGDB) += excite_dbg_io.o | ||
9 | obj-m += excite_iodev.o | 8 | obj-m += excite_iodev.o |
diff --git a/arch/mips/basler/excite/excite_dbg_io.c b/arch/mips/basler/excite/excite_dbg_io.c deleted file mode 100644 index d289e3a868cf..000000000000 --- a/arch/mips/basler/excite/excite_dbg_io.c +++ /dev/null | |||
@@ -1,121 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 by Basler Vision Technologies AG | ||
3 | * Author: Thomas Koeller <thomas.koeller@baslerweb.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/linkage.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <asm/gdb-stub.h> | ||
24 | #include <asm/rm9k-ocd.h> | ||
25 | #include <excite.h> | ||
26 | |||
27 | #if defined(CONFIG_SERIAL_8250) && CONFIG_SERIAL_8250_NR_UARTS > 1 | ||
28 | #error Debug port used by serial driver | ||
29 | #endif | ||
30 | |||
31 | #define UART_CLK 25000000 | ||
32 | #define BASE_BAUD (UART_CLK / 16) | ||
33 | #define REGISTER_BASE_0 0x0208UL | ||
34 | #define REGISTER_BASE_1 0x0238UL | ||
35 | |||
36 | #define REGISTER_BASE_DBG REGISTER_BASE_1 | ||
37 | |||
38 | #define CPRR 0x0004 | ||
39 | #define UACFG 0x0200 | ||
40 | #define UAINTS 0x0204 | ||
41 | #define UARBR (REGISTER_BASE_DBG + 0x0000) | ||
42 | #define UATHR (REGISTER_BASE_DBG + 0x0004) | ||
43 | #define UADLL (REGISTER_BASE_DBG + 0x0008) | ||
44 | #define UAIER (REGISTER_BASE_DBG + 0x000c) | ||
45 | #define UADLH (REGISTER_BASE_DBG + 0x0010) | ||
46 | #define UAIIR (REGISTER_BASE_DBG + 0x0014) | ||
47 | #define UAFCR (REGISTER_BASE_DBG + 0x0018) | ||
48 | #define UALCR (REGISTER_BASE_DBG + 0x001c) | ||
49 | #define UAMCR (REGISTER_BASE_DBG + 0x0020) | ||
50 | #define UALSR (REGISTER_BASE_DBG + 0x0024) | ||
51 | #define UAMSR (REGISTER_BASE_DBG + 0x0028) | ||
52 | #define UASCR (REGISTER_BASE_DBG + 0x002c) | ||
53 | |||
54 | #define PARITY_NONE 0 | ||
55 | #define PARITY_ODD 0x08 | ||
56 | #define PARITY_EVEN 0x18 | ||
57 | #define PARITY_MARK 0x28 | ||
58 | #define PARITY_SPACE 0x38 | ||
59 | |||
60 | #define DATA_5BIT 0x0 | ||
61 | #define DATA_6BIT 0x1 | ||
62 | #define DATA_7BIT 0x2 | ||
63 | #define DATA_8BIT 0x3 | ||
64 | |||
65 | #define STOP_1BIT 0x0 | ||
66 | #define STOP_2BIT 0x4 | ||
67 | |||
68 | #define BAUD_DBG 57600 | ||
69 | #define PARITY_DBG PARITY_NONE | ||
70 | #define DATA_DBG DATA_8BIT | ||
71 | #define STOP_DBG STOP_1BIT | ||
72 | |||
73 | /* Initialize the serial port for KGDB debugging */ | ||
74 | void __init excite_kgdb_init(void) | ||
75 | { | ||
76 | const u32 divisor = BASE_BAUD / BAUD_DBG; | ||
77 | |||
78 | /* Take the UART out of reset */ | ||
79 | titan_writel(0x00ff1cff, CPRR); | ||
80 | titan_writel(0x00000000, UACFG); | ||
81 | titan_writel(0x00000002, UACFG); | ||
82 | |||
83 | titan_writel(0x0, UALCR); | ||
84 | titan_writel(0x0, UAIER); | ||
85 | |||
86 | /* Disable FIFOs */ | ||
87 | titan_writel(0x00, UAFCR); | ||
88 | |||
89 | titan_writel(0x80, UALCR); | ||
90 | titan_writel(divisor & 0xff, UADLL); | ||
91 | titan_writel((divisor & 0xff00) >> 8, UADLH); | ||
92 | titan_writel(0x0, UALCR); | ||
93 | |||
94 | titan_writel(DATA_DBG | PARITY_DBG | STOP_DBG, UALCR); | ||
95 | |||
96 | /* Enable receiver interrupt */ | ||
97 | titan_readl(UARBR); | ||
98 | titan_writel(0x1, UAIER); | ||
99 | } | ||
100 | |||
101 | int getDebugChar(void) | ||
102 | { | ||
103 | while (!(titan_readl(UALSR) & 0x1)); | ||
104 | return titan_readl(UARBR); | ||
105 | } | ||
106 | |||
107 | int putDebugChar(int data) | ||
108 | { | ||
109 | while (!(titan_readl(UALSR) & 0x20)); | ||
110 | titan_writel(data, UATHR); | ||
111 | return 1; | ||
112 | } | ||
113 | |||
114 | /* KGDB interrupt handler */ | ||
115 | asmlinkage void excite_kgdb_inthdl(void) | ||
116 | { | ||
117 | if (unlikely( | ||
118 | ((titan_readl(UAIIR) & 0x7) == 4) | ||
119 | && ((titan_readl(UARBR) & 0xff) == 0x3))) | ||
120 | set_async_breakpoint(®s->cp0_epc); | ||
121 | } | ||
diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c index 4903e067916b..934e0a6b1011 100644 --- a/arch/mips/basler/excite/excite_irq.c +++ b/arch/mips/basler/excite/excite_irq.c | |||
@@ -50,10 +50,6 @@ void __init arch_init_irq(void) | |||
50 | mips_cpu_irq_init(); | 50 | mips_cpu_irq_init(); |
51 | rm7k_cpu_irq_init(); | 51 | rm7k_cpu_irq_init(); |
52 | rm9k_cpu_irq_init(); | 52 | rm9k_cpu_irq_init(); |
53 | |||
54 | #ifdef CONFIG_KGDB | ||
55 | excite_kgdb_init(); | ||
56 | #endif | ||
57 | } | 53 | } |
58 | 54 | ||
59 | asmlinkage void plat_irq_dispatch(void) | 55 | asmlinkage void plat_irq_dispatch(void) |
@@ -90,9 +86,6 @@ asmlinkage void plat_irq_dispatch(void) | |||
90 | msgint = msgintflags & msgintmask & (0x1 << (TITAN_MSGINT % 0x20)); | 86 | msgint = msgintflags & msgintmask & (0x1 << (TITAN_MSGINT % 0x20)); |
91 | if ((pending & (1 << TITAN_IRQ)) && msgint) { | 87 | if ((pending & (1 << TITAN_IRQ)) && msgint) { |
92 | ocd_writel(msgint, INTP0Clear0 + (TITAN_MSGINT / 0x20 * 0x10)); | 88 | ocd_writel(msgint, INTP0Clear0 + (TITAN_MSGINT / 0x20 * 0x10)); |
93 | #if defined(CONFIG_KGDB) | ||
94 | excite_kgdb_inthdl(); | ||
95 | #endif | ||
96 | do_IRQ(TITAN_IRQ); | 89 | do_IRQ(TITAN_IRQ); |
97 | return; | 90 | return; |
98 | } | 91 | } |
diff --git a/arch/mips/basler/excite/excite_setup.c b/arch/mips/basler/excite/excite_setup.c index 6dd8f0d46d09..d66b3b8edf2a 100644 --- a/arch/mips/basler/excite/excite_setup.c +++ b/arch/mips/basler/excite/excite_setup.c | |||
@@ -95,13 +95,13 @@ static int __init excite_init_console(void) | |||
95 | /* Take the DUART out of reset */ | 95 | /* Take the DUART out of reset */ |
96 | titan_writel(0x00ff1cff, CPRR); | 96 | titan_writel(0x00ff1cff, CPRR); |
97 | 97 | ||
98 | #if defined(CONFIG_KGDB) || (CONFIG_SERIAL_8250_NR_UARTS > 1) | 98 | #if (CONFIG_SERIAL_8250_NR_UARTS > 1) |
99 | /* Enable both ports */ | 99 | /* Enable both ports */ |
100 | titan_writel(MASK_SER0 | MASK_SER1, UACFG); | 100 | titan_writel(MASK_SER0 | MASK_SER1, UACFG); |
101 | #else | 101 | #else |
102 | /* Enable port #0 only */ | 102 | /* Enable port #0 only */ |
103 | titan_writel(MASK_SER0, UACFG); | 103 | titan_writel(MASK_SER0, UACFG); |
104 | #endif /* defined(CONFIG_KGDB) */ | 104 | #endif |
105 | 105 | ||
106 | /* | 106 | /* |
107 | * Set up serial port #0. Do not use autodetection; the result is | 107 | * Set up serial port #0. Do not use autodetection; the result is |
diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig index 2678b7ec3351..eb44b72254af 100644 --- a/arch/mips/configs/cobalt_defconfig +++ b/arch/mips/configs/cobalt_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Linux kernel version: 2.6.23-rc5 | 3 | # Linux kernel version: 2.6.26 |
4 | # Thu Sep 6 13:14:29 2007 | 4 | # Fri Jul 25 10:25:34 2008 |
5 | # | 5 | # |
6 | CONFIG_MIPS=y | 6 | CONFIG_MIPS=y |
7 | 7 | ||
@@ -10,9 +10,11 @@ CONFIG_MIPS=y | |||
10 | # | 10 | # |
11 | # CONFIG_MACH_ALCHEMY is not set | 11 | # CONFIG_MACH_ALCHEMY is not set |
12 | # CONFIG_BASLER_EXCITE is not set | 12 | # CONFIG_BASLER_EXCITE is not set |
13 | # CONFIG_BCM47XX is not set | ||
13 | CONFIG_MIPS_COBALT=y | 14 | CONFIG_MIPS_COBALT=y |
14 | # CONFIG_MACH_DECSTATION is not set | 15 | # CONFIG_MACH_DECSTATION is not set |
15 | # CONFIG_MACH_JAZZ is not set | 16 | # CONFIG_MACH_JAZZ is not set |
17 | # CONFIG_LASAT is not set | ||
16 | # CONFIG_LEMOTE_FULONG is not set | 18 | # CONFIG_LEMOTE_FULONG is not set |
17 | # CONFIG_MIPS_MALTA is not set | 19 | # CONFIG_MIPS_MALTA is not set |
18 | # CONFIG_MIPS_SIM is not set | 20 | # CONFIG_MIPS_SIM is not set |
@@ -24,6 +26,7 @@ CONFIG_MIPS_COBALT=y | |||
24 | # CONFIG_PMC_YOSEMITE is not set | 26 | # CONFIG_PMC_YOSEMITE is not set |
25 | # CONFIG_SGI_IP22 is not set | 27 | # CONFIG_SGI_IP22 is not set |
26 | # CONFIG_SGI_IP27 is not set | 28 | # CONFIG_SGI_IP27 is not set |
29 | # CONFIG_SGI_IP28 is not set | ||
27 | # CONFIG_SGI_IP32 is not set | 30 | # CONFIG_SGI_IP32 is not set |
28 | # CONFIG_SIBYTE_CRHINE is not set | 31 | # CONFIG_SIBYTE_CRHINE is not set |
29 | # CONFIG_SIBYTE_CARMEL is not set | 32 | # CONFIG_SIBYTE_CARMEL is not set |
@@ -34,19 +37,25 @@ CONFIG_MIPS_COBALT=y | |||
34 | # CONFIG_SIBYTE_SENTOSA is not set | 37 | # CONFIG_SIBYTE_SENTOSA is not set |
35 | # CONFIG_SIBYTE_BIGSUR is not set | 38 | # CONFIG_SIBYTE_BIGSUR is not set |
36 | # CONFIG_SNI_RM is not set | 39 | # CONFIG_SNI_RM is not set |
37 | # CONFIG_TOSHIBA_JMR3927 is not set | 40 | # CONFIG_MACH_TX39XX is not set |
38 | # CONFIG_TOSHIBA_RBTX4927 is not set | 41 | # CONFIG_MACH_TX49XX is not set |
39 | # CONFIG_TOSHIBA_RBTX4938 is not set | 42 | # CONFIG_MIKROTIK_RB532 is not set |
40 | # CONFIG_WR_PPMC is not set | 43 | # CONFIG_WR_PPMC is not set |
41 | CONFIG_RWSEM_GENERIC_SPINLOCK=y | 44 | CONFIG_RWSEM_GENERIC_SPINLOCK=y |
42 | # CONFIG_ARCH_HAS_ILOG2_U32 is not set | 45 | # CONFIG_ARCH_HAS_ILOG2_U32 is not set |
43 | # CONFIG_ARCH_HAS_ILOG2_U64 is not set | 46 | # CONFIG_ARCH_HAS_ILOG2_U64 is not set |
47 | CONFIG_ARCH_SUPPORTS_OPROFILE=y | ||
44 | CONFIG_GENERIC_FIND_NEXT_BIT=y | 48 | CONFIG_GENERIC_FIND_NEXT_BIT=y |
45 | CONFIG_GENERIC_HWEIGHT=y | 49 | CONFIG_GENERIC_HWEIGHT=y |
46 | CONFIG_GENERIC_CALIBRATE_DELAY=y | 50 | CONFIG_GENERIC_CALIBRATE_DELAY=y |
51 | CONFIG_GENERIC_CLOCKEVENTS=y | ||
47 | CONFIG_GENERIC_TIME=y | 52 | CONFIG_GENERIC_TIME=y |
53 | CONFIG_GENERIC_CMOS_UPDATE=y | ||
48 | CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y | 54 | CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y |
49 | CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y | 55 | CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y |
56 | CONFIG_CEVT_GT641XX=y | ||
57 | CONFIG_CEVT_R4K=y | ||
58 | CONFIG_CSRC_R4K=y | ||
50 | CONFIG_DMA_NONCOHERENT=y | 59 | CONFIG_DMA_NONCOHERENT=y |
51 | CONFIG_DMA_NEED_PCI_MAP_STATE=y | 60 | CONFIG_DMA_NEED_PCI_MAP_STATE=y |
52 | CONFIG_EARLY_PRINTK=y | 61 | CONFIG_EARLY_PRINTK=y |
@@ -108,6 +117,7 @@ CONFIG_CPU_HAS_SYNC=y | |||
108 | CONFIG_GENERIC_HARDIRQS=y | 117 | CONFIG_GENERIC_HARDIRQS=y |
109 | CONFIG_GENERIC_IRQ_PROBE=y | 118 | CONFIG_GENERIC_IRQ_PROBE=y |
110 | CONFIG_ARCH_FLATMEM_ENABLE=y | 119 | CONFIG_ARCH_FLATMEM_ENABLE=y |
120 | CONFIG_ARCH_POPULATES_NODE_MAP=y | ||
111 | CONFIG_SELECT_MEMORY_MODEL=y | 121 | CONFIG_SELECT_MEMORY_MODEL=y |
112 | CONFIG_FLATMEM_MANUAL=y | 122 | CONFIG_FLATMEM_MANUAL=y |
113 | # CONFIG_DISCONTIGMEM_MANUAL is not set | 123 | # CONFIG_DISCONTIGMEM_MANUAL is not set |
@@ -115,10 +125,16 @@ CONFIG_FLATMEM_MANUAL=y | |||
115 | CONFIG_FLATMEM=y | 125 | CONFIG_FLATMEM=y |
116 | CONFIG_FLAT_NODE_MEM_MAP=y | 126 | CONFIG_FLAT_NODE_MEM_MAP=y |
117 | # CONFIG_SPARSEMEM_STATIC is not set | 127 | # CONFIG_SPARSEMEM_STATIC is not set |
128 | # CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set | ||
129 | CONFIG_PAGEFLAGS_EXTENDED=y | ||
118 | CONFIG_SPLIT_PTLOCK_CPUS=4 | 130 | CONFIG_SPLIT_PTLOCK_CPUS=4 |
119 | # CONFIG_RESOURCES_64BIT is not set | 131 | # CONFIG_RESOURCES_64BIT is not set |
120 | CONFIG_ZONE_DMA_FLAG=0 | 132 | CONFIG_ZONE_DMA_FLAG=0 |
121 | CONFIG_VIRT_TO_BUS=y | 133 | CONFIG_VIRT_TO_BUS=y |
134 | # CONFIG_TICK_ONESHOT is not set | ||
135 | # CONFIG_NO_HZ is not set | ||
136 | # CONFIG_HIGH_RES_TIMERS is not set | ||
137 | CONFIG_GENERIC_CLOCKEVENTS_BUILD=y | ||
122 | # CONFIG_HZ_48 is not set | 138 | # CONFIG_HZ_48 is not set |
123 | # CONFIG_HZ_100 is not set | 139 | # CONFIG_HZ_100 is not set |
124 | # CONFIG_HZ_128 is not set | 140 | # CONFIG_HZ_128 is not set |
@@ -151,23 +167,28 @@ CONFIG_SYSVIPC_SYSCTL=y | |||
151 | # CONFIG_POSIX_MQUEUE is not set | 167 | # CONFIG_POSIX_MQUEUE is not set |
152 | # CONFIG_BSD_PROCESS_ACCT is not set | 168 | # CONFIG_BSD_PROCESS_ACCT is not set |
153 | # CONFIG_TASKSTATS is not set | 169 | # CONFIG_TASKSTATS is not set |
154 | # CONFIG_USER_NS is not set | ||
155 | # CONFIG_AUDIT is not set | 170 | # CONFIG_AUDIT is not set |
156 | # CONFIG_IKCONFIG is not set | 171 | # CONFIG_IKCONFIG is not set |
157 | CONFIG_LOG_BUF_SHIFT=14 | 172 | CONFIG_LOG_BUF_SHIFT=14 |
158 | CONFIG_SYSFS_DEPRECATED=y | 173 | # CONFIG_CGROUPS is not set |
174 | # CONFIG_GROUP_SCHED is not set | ||
175 | # CONFIG_SYSFS_DEPRECATED_V2 is not set | ||
159 | CONFIG_RELAY=y | 176 | CONFIG_RELAY=y |
177 | # CONFIG_NAMESPACES is not set | ||
160 | # CONFIG_BLK_DEV_INITRD is not set | 178 | # CONFIG_BLK_DEV_INITRD is not set |
161 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | 179 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set |
162 | CONFIG_SYSCTL=y | 180 | CONFIG_SYSCTL=y |
163 | CONFIG_EMBEDDED=y | 181 | CONFIG_EMBEDDED=y |
164 | CONFIG_SYSCTL_SYSCALL=y | 182 | CONFIG_SYSCTL_SYSCALL=y |
183 | CONFIG_SYSCTL_SYSCALL_CHECK=y | ||
165 | CONFIG_KALLSYMS=y | 184 | CONFIG_KALLSYMS=y |
166 | # CONFIG_KALLSYMS_EXTRA_PASS is not set | 185 | # CONFIG_KALLSYMS_EXTRA_PASS is not set |
167 | CONFIG_HOTPLUG=y | 186 | CONFIG_HOTPLUG=y |
168 | CONFIG_PRINTK=y | 187 | CONFIG_PRINTK=y |
169 | CONFIG_BUG=y | 188 | CONFIG_BUG=y |
170 | CONFIG_ELF_CORE=y | 189 | CONFIG_ELF_CORE=y |
190 | CONFIG_PCSPKR_PLATFORM=y | ||
191 | CONFIG_COMPAT_BRK=y | ||
171 | CONFIG_BASE_FULL=y | 192 | CONFIG_BASE_FULL=y |
172 | CONFIG_FUTEX=y | 193 | CONFIG_FUTEX=y |
173 | CONFIG_ANON_INODES=y | 194 | CONFIG_ANON_INODES=y |
@@ -177,23 +198,37 @@ CONFIG_TIMERFD=y | |||
177 | CONFIG_EVENTFD=y | 198 | CONFIG_EVENTFD=y |
178 | CONFIG_SHMEM=y | 199 | CONFIG_SHMEM=y |
179 | CONFIG_VM_EVENT_COUNTERS=y | 200 | CONFIG_VM_EVENT_COUNTERS=y |
180 | CONFIG_SLAB=y | 201 | CONFIG_SLUB_DEBUG=y |
181 | # CONFIG_SLUB is not set | 202 | # CONFIG_SLAB is not set |
203 | CONFIG_SLUB=y | ||
182 | # CONFIG_SLOB is not set | 204 | # CONFIG_SLOB is not set |
205 | # CONFIG_PROFILING is not set | ||
206 | # CONFIG_MARKERS is not set | ||
207 | CONFIG_HAVE_OPROFILE=y | ||
208 | # CONFIG_HAVE_IOREMAP_PROT is not set | ||
209 | # CONFIG_HAVE_KPROBES is not set | ||
210 | # CONFIG_HAVE_KRETPROBES is not set | ||
211 | # CONFIG_HAVE_DMA_ATTRS is not set | ||
212 | # CONFIG_USE_GENERIC_SMP_HELPERS is not set | ||
213 | # CONFIG_HAVE_CLK is not set | ||
214 | CONFIG_PROC_PAGE_MONITOR=y | ||
215 | CONFIG_SLABINFO=y | ||
183 | CONFIG_RT_MUTEXES=y | 216 | CONFIG_RT_MUTEXES=y |
184 | # CONFIG_TINY_SHMEM is not set | 217 | # CONFIG_TINY_SHMEM is not set |
185 | CONFIG_BASE_SMALL=0 | 218 | CONFIG_BASE_SMALL=0 |
186 | CONFIG_MODULES=y | 219 | CONFIG_MODULES=y |
220 | # CONFIG_MODULE_FORCE_LOAD is not set | ||
187 | CONFIG_MODULE_UNLOAD=y | 221 | CONFIG_MODULE_UNLOAD=y |
188 | # CONFIG_MODULE_FORCE_UNLOAD is not set | 222 | # CONFIG_MODULE_FORCE_UNLOAD is not set |
189 | # CONFIG_MODVERSIONS is not set | 223 | # CONFIG_MODVERSIONS is not set |
190 | # CONFIG_MODULE_SRCVERSION_ALL is not set | 224 | # CONFIG_MODULE_SRCVERSION_ALL is not set |
191 | # CONFIG_KMOD is not set | 225 | CONFIG_KMOD=y |
192 | CONFIG_BLOCK=y | 226 | CONFIG_BLOCK=y |
193 | # CONFIG_LBD is not set | 227 | # CONFIG_LBD is not set |
194 | # CONFIG_BLK_DEV_IO_TRACE is not set | 228 | # CONFIG_BLK_DEV_IO_TRACE is not set |
195 | # CONFIG_LSF is not set | 229 | # CONFIG_LSF is not set |
196 | # CONFIG_BLK_DEV_BSG is not set | 230 | # CONFIG_BLK_DEV_BSG is not set |
231 | # CONFIG_BLK_DEV_INTEGRITY is not set | ||
197 | 232 | ||
198 | # | 233 | # |
199 | # IO Schedulers | 234 | # IO Schedulers |
@@ -207,18 +242,18 @@ CONFIG_DEFAULT_AS=y | |||
207 | # CONFIG_DEFAULT_CFQ is not set | 242 | # CONFIG_DEFAULT_CFQ is not set |
208 | # CONFIG_DEFAULT_NOOP is not set | 243 | # CONFIG_DEFAULT_NOOP is not set |
209 | CONFIG_DEFAULT_IOSCHED="anticipatory" | 244 | CONFIG_DEFAULT_IOSCHED="anticipatory" |
245 | CONFIG_CLASSIC_RCU=y | ||
210 | 246 | ||
211 | # | 247 | # |
212 | # Bus options (PCI, PCMCIA, EISA, ISA, TC) | 248 | # Bus options (PCI, PCMCIA, EISA, ISA, TC) |
213 | # | 249 | # |
214 | CONFIG_HW_HAS_PCI=y | 250 | CONFIG_HW_HAS_PCI=y |
215 | CONFIG_PCI=y | 251 | CONFIG_PCI=y |
252 | CONFIG_PCI_DOMAINS=y | ||
216 | # CONFIG_ARCH_SUPPORTS_MSI is not set | 253 | # CONFIG_ARCH_SUPPORTS_MSI is not set |
254 | CONFIG_PCI_LEGACY=y | ||
217 | CONFIG_MMU=y | 255 | CONFIG_MMU=y |
218 | 256 | CONFIG_I8253=y | |
219 | # | ||
220 | # PCCARD (PCMCIA/CardBus) support | ||
221 | # | ||
222 | # CONFIG_PCCARD is not set | 257 | # CONFIG_PCCARD is not set |
223 | # CONFIG_HOTPLUG_PCI is not set | 258 | # CONFIG_HOTPLUG_PCI is not set |
224 | 259 | ||
@@ -232,8 +267,8 @@ CONFIG_TRAD_SIGNALS=y | |||
232 | # | 267 | # |
233 | # Power management options | 268 | # Power management options |
234 | # | 269 | # |
270 | CONFIG_ARCH_SUSPEND_POSSIBLE=y | ||
235 | # CONFIG_PM is not set | 271 | # CONFIG_PM is not set |
236 | CONFIG_SUSPEND_UP_POSSIBLE=y | ||
237 | 272 | ||
238 | # | 273 | # |
239 | # Networking | 274 | # Networking |
@@ -250,6 +285,7 @@ CONFIG_XFRM=y | |||
250 | CONFIG_XFRM_USER=y | 285 | CONFIG_XFRM_USER=y |
251 | # CONFIG_XFRM_SUB_POLICY is not set | 286 | # CONFIG_XFRM_SUB_POLICY is not set |
252 | CONFIG_XFRM_MIGRATE=y | 287 | CONFIG_XFRM_MIGRATE=y |
288 | # CONFIG_XFRM_STATISTICS is not set | ||
253 | CONFIG_NET_KEY=y | 289 | CONFIG_NET_KEY=y |
254 | CONFIG_NET_KEY_MIGRATE=y | 290 | CONFIG_NET_KEY_MIGRATE=y |
255 | CONFIG_INET=y | 291 | CONFIG_INET=y |
@@ -269,6 +305,7 @@ CONFIG_IP_FIB_HASH=y | |||
269 | CONFIG_INET_XFRM_MODE_TRANSPORT=y | 305 | CONFIG_INET_XFRM_MODE_TRANSPORT=y |
270 | CONFIG_INET_XFRM_MODE_TUNNEL=y | 306 | CONFIG_INET_XFRM_MODE_TUNNEL=y |
271 | CONFIG_INET_XFRM_MODE_BEET=y | 307 | CONFIG_INET_XFRM_MODE_BEET=y |
308 | # CONFIG_INET_LRO is not set | ||
272 | CONFIG_INET_DIAG=y | 309 | CONFIG_INET_DIAG=y |
273 | CONFIG_INET_TCP_DIAG=y | 310 | CONFIG_INET_TCP_DIAG=y |
274 | # CONFIG_TCP_CONG_ADVANCED is not set | 311 | # CONFIG_TCP_CONG_ADVANCED is not set |
@@ -276,8 +313,6 @@ CONFIG_TCP_CONG_CUBIC=y | |||
276 | CONFIG_DEFAULT_TCP_CONG="cubic" | 313 | CONFIG_DEFAULT_TCP_CONG="cubic" |
277 | # CONFIG_TCP_MD5SIG is not set | 314 | # CONFIG_TCP_MD5SIG is not set |
278 | # CONFIG_IPV6 is not set | 315 | # CONFIG_IPV6 is not set |
279 | # CONFIG_INET6_XFRM_TUNNEL is not set | ||
280 | # CONFIG_INET6_TUNNEL is not set | ||
281 | # CONFIG_NETWORK_SECMARK is not set | 316 | # CONFIG_NETWORK_SECMARK is not set |
282 | # CONFIG_NETFILTER is not set | 317 | # CONFIG_NETFILTER is not set |
283 | # CONFIG_IP_DCCP is not set | 318 | # CONFIG_IP_DCCP is not set |
@@ -294,10 +329,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic" | |||
294 | # CONFIG_LAPB is not set | 329 | # CONFIG_LAPB is not set |
295 | # CONFIG_ECONET is not set | 330 | # CONFIG_ECONET is not set |
296 | # CONFIG_WAN_ROUTER is not set | 331 | # CONFIG_WAN_ROUTER is not set |
297 | |||
298 | # | ||
299 | # QoS and/or fair queueing | ||
300 | # | ||
301 | # CONFIG_NET_SCHED is not set | 332 | # CONFIG_NET_SCHED is not set |
302 | 333 | ||
303 | # | 334 | # |
@@ -305,6 +336,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" | |||
305 | # | 336 | # |
306 | # CONFIG_NET_PKTGEN is not set | 337 | # CONFIG_NET_PKTGEN is not set |
307 | # CONFIG_HAMRADIO is not set | 338 | # CONFIG_HAMRADIO is not set |
339 | # CONFIG_CAN is not set | ||
308 | # CONFIG_IRDA is not set | 340 | # CONFIG_IRDA is not set |
309 | # CONFIG_BT is not set | 341 | # CONFIG_BT is not set |
310 | # CONFIG_AF_RXRPC is not set | 342 | # CONFIG_AF_RXRPC is not set |
@@ -326,9 +358,12 @@ CONFIG_DEFAULT_TCP_CONG="cubic" | |||
326 | # | 358 | # |
327 | # Generic Driver Options | 359 | # Generic Driver Options |
328 | # | 360 | # |
361 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | ||
329 | CONFIG_STANDALONE=y | 362 | CONFIG_STANDALONE=y |
330 | CONFIG_PREVENT_FIRMWARE_BUILD=y | 363 | CONFIG_PREVENT_FIRMWARE_BUILD=y |
331 | CONFIG_FW_LOADER=y | 364 | CONFIG_FW_LOADER=y |
365 | CONFIG_FIRMWARE_IN_KERNEL=y | ||
366 | CONFIG_EXTRA_FIRMWARE="" | ||
332 | # CONFIG_SYS_HYPERVISOR is not set | 367 | # CONFIG_SYS_HYPERVISOR is not set |
333 | # CONFIG_CONNECTOR is not set | 368 | # CONFIG_CONNECTOR is not set |
334 | CONFIG_MTD=y | 369 | CONFIG_MTD=y |
@@ -337,6 +372,7 @@ CONFIG_MTD=y | |||
337 | CONFIG_MTD_PARTITIONS=y | 372 | CONFIG_MTD_PARTITIONS=y |
338 | # CONFIG_MTD_REDBOOT_PARTS is not set | 373 | # CONFIG_MTD_REDBOOT_PARTS is not set |
339 | # CONFIG_MTD_CMDLINE_PARTS is not set | 374 | # CONFIG_MTD_CMDLINE_PARTS is not set |
375 | # CONFIG_MTD_AR7_PARTS is not set | ||
340 | 376 | ||
341 | # | 377 | # |
342 | # User Modules And Translation Layers | 378 | # User Modules And Translation Layers |
@@ -350,6 +386,7 @@ CONFIG_MTD_BLKDEVS=y | |||
350 | # CONFIG_INFTL is not set | 386 | # CONFIG_INFTL is not set |
351 | # CONFIG_RFD_FTL is not set | 387 | # CONFIG_RFD_FTL is not set |
352 | # CONFIG_SSFDC is not set | 388 | # CONFIG_SSFDC is not set |
389 | # CONFIG_MTD_OOPS is not set | ||
353 | 390 | ||
354 | # | 391 | # |
355 | # RAM/ROM/Flash chip drivers | 392 | # RAM/ROM/Flash chip drivers |
@@ -384,6 +421,7 @@ CONFIG_MTD_PHYSMAP=y | |||
384 | CONFIG_MTD_PHYSMAP_START=0x0 | 421 | CONFIG_MTD_PHYSMAP_START=0x0 |
385 | CONFIG_MTD_PHYSMAP_LEN=0x0 | 422 | CONFIG_MTD_PHYSMAP_LEN=0x0 |
386 | CONFIG_MTD_PHYSMAP_BANKWIDTH=0 | 423 | CONFIG_MTD_PHYSMAP_BANKWIDTH=0 |
424 | # CONFIG_MTD_INTEL_VR_NOR is not set | ||
387 | # CONFIG_MTD_PLATRAM is not set | 425 | # CONFIG_MTD_PLATRAM is not set |
388 | 426 | ||
389 | # | 427 | # |
@@ -423,7 +461,9 @@ CONFIG_BLK_DEV_LOOP=y | |||
423 | # CONFIG_BLK_DEV_RAM is not set | 461 | # CONFIG_BLK_DEV_RAM is not set |
424 | # CONFIG_CDROM_PKTCDVD is not set | 462 | # CONFIG_CDROM_PKTCDVD is not set |
425 | # CONFIG_ATA_OVER_ETH is not set | 463 | # CONFIG_ATA_OVER_ETH is not set |
464 | # CONFIG_BLK_DEV_HD is not set | ||
426 | # CONFIG_MISC_DEVICES is not set | 465 | # CONFIG_MISC_DEVICES is not set |
466 | CONFIG_HAVE_IDE=y | ||
427 | # CONFIG_IDE is not set | 467 | # CONFIG_IDE is not set |
428 | 468 | ||
429 | # | 469 | # |
@@ -462,10 +502,15 @@ CONFIG_SCSI_WAIT_SCAN=m | |||
462 | # CONFIG_SCSI_FC_ATTRS is not set | 502 | # CONFIG_SCSI_FC_ATTRS is not set |
463 | # CONFIG_SCSI_ISCSI_ATTRS is not set | 503 | # CONFIG_SCSI_ISCSI_ATTRS is not set |
464 | # CONFIG_SCSI_SAS_LIBSAS is not set | 504 | # CONFIG_SCSI_SAS_LIBSAS is not set |
505 | # CONFIG_SCSI_SRP_ATTRS is not set | ||
465 | # CONFIG_SCSI_LOWLEVEL is not set | 506 | # CONFIG_SCSI_LOWLEVEL is not set |
507 | # CONFIG_SCSI_DH is not set | ||
466 | CONFIG_ATA=y | 508 | CONFIG_ATA=y |
467 | # CONFIG_ATA_NONSTANDARD is not set | 509 | # CONFIG_ATA_NONSTANDARD is not set |
510 | CONFIG_SATA_PMP=y | ||
468 | # CONFIG_SATA_AHCI is not set | 511 | # CONFIG_SATA_AHCI is not set |
512 | # CONFIG_SATA_SIL24 is not set | ||
513 | CONFIG_ATA_SFF=y | ||
469 | # CONFIG_SATA_SVW is not set | 514 | # CONFIG_SATA_SVW is not set |
470 | # CONFIG_ATA_PIIX is not set | 515 | # CONFIG_ATA_PIIX is not set |
471 | # CONFIG_SATA_MV is not set | 516 | # CONFIG_SATA_MV is not set |
@@ -475,7 +520,6 @@ CONFIG_ATA=y | |||
475 | # CONFIG_SATA_PROMISE is not set | 520 | # CONFIG_SATA_PROMISE is not set |
476 | # CONFIG_SATA_SX4 is not set | 521 | # CONFIG_SATA_SX4 is not set |
477 | # CONFIG_SATA_SIL is not set | 522 | # CONFIG_SATA_SIL is not set |
478 | # CONFIG_SATA_SIL24 is not set | ||
479 | # CONFIG_SATA_SIS is not set | 523 | # CONFIG_SATA_SIS is not set |
480 | # CONFIG_SATA_ULI is not set | 524 | # CONFIG_SATA_ULI is not set |
481 | # CONFIG_SATA_VIA is not set | 525 | # CONFIG_SATA_VIA is not set |
@@ -504,7 +548,9 @@ CONFIG_ATA=y | |||
504 | # CONFIG_PATA_MPIIX is not set | 548 | # CONFIG_PATA_MPIIX is not set |
505 | # CONFIG_PATA_OLDPIIX is not set | 549 | # CONFIG_PATA_OLDPIIX is not set |
506 | # CONFIG_PATA_NETCELL is not set | 550 | # CONFIG_PATA_NETCELL is not set |
551 | # CONFIG_PATA_NINJA32 is not set | ||
507 | # CONFIG_PATA_NS87410 is not set | 552 | # CONFIG_PATA_NS87410 is not set |
553 | # CONFIG_PATA_NS87415 is not set | ||
508 | # CONFIG_PATA_OPTI is not set | 554 | # CONFIG_PATA_OPTI is not set |
509 | # CONFIG_PATA_OPTIDMA is not set | 555 | # CONFIG_PATA_OPTIDMA is not set |
510 | # CONFIG_PATA_PDC_OLD is not set | 556 | # CONFIG_PATA_PDC_OLD is not set |
@@ -518,29 +564,27 @@ CONFIG_ATA=y | |||
518 | CONFIG_PATA_VIA=y | 564 | CONFIG_PATA_VIA=y |
519 | # CONFIG_PATA_WINBOND is not set | 565 | # CONFIG_PATA_WINBOND is not set |
520 | # CONFIG_PATA_PLATFORM is not set | 566 | # CONFIG_PATA_PLATFORM is not set |
567 | # CONFIG_PATA_SCH is not set | ||
521 | # CONFIG_MD is not set | 568 | # CONFIG_MD is not set |
569 | # CONFIG_FUSION is not set | ||
522 | 570 | ||
523 | # | 571 | # |
524 | # Fusion MPT device support | 572 | # IEEE 1394 (FireWire) support |
525 | # | 573 | # |
526 | # CONFIG_FUSION is not set | ||
527 | # CONFIG_FUSION_SPI is not set | ||
528 | # CONFIG_FUSION_FC is not set | ||
529 | # CONFIG_FUSION_SAS is not set | ||
530 | 574 | ||
531 | # | 575 | # |
532 | # IEEE 1394 (FireWire) support | 576 | # Enable only one of the two stacks, unless you know what you are doing |
533 | # | 577 | # |
534 | # CONFIG_FIREWIRE is not set | 578 | # CONFIG_FIREWIRE is not set |
535 | # CONFIG_IEEE1394 is not set | 579 | # CONFIG_IEEE1394 is not set |
536 | # CONFIG_I2O is not set | 580 | # CONFIG_I2O is not set |
537 | CONFIG_NETDEVICES=y | 581 | CONFIG_NETDEVICES=y |
538 | # CONFIG_NETDEVICES_MULTIQUEUE is not set | ||
539 | # CONFIG_DUMMY is not set | 582 | # CONFIG_DUMMY is not set |
540 | # CONFIG_BONDING is not set | 583 | # CONFIG_BONDING is not set |
541 | # CONFIG_MACVLAN is not set | 584 | # CONFIG_MACVLAN is not set |
542 | # CONFIG_EQUALIZER is not set | 585 | # CONFIG_EQUALIZER is not set |
543 | # CONFIG_TUN is not set | 586 | # CONFIG_TUN is not set |
587 | # CONFIG_VETH is not set | ||
544 | # CONFIG_ARCNET is not set | 588 | # CONFIG_ARCNET is not set |
545 | # CONFIG_PHYLIB is not set | 589 | # CONFIG_PHYLIB is not set |
546 | CONFIG_NET_ETHERNET=y | 590 | CONFIG_NET_ETHERNET=y |
@@ -562,7 +606,12 @@ CONFIG_TULIP=y | |||
562 | # CONFIG_DM9102 is not set | 606 | # CONFIG_DM9102 is not set |
563 | # CONFIG_ULI526X is not set | 607 | # CONFIG_ULI526X is not set |
564 | # CONFIG_HP100 is not set | 608 | # CONFIG_HP100 is not set |
609 | # CONFIG_IBM_NEW_EMAC_ZMII is not set | ||
610 | # CONFIG_IBM_NEW_EMAC_RGMII is not set | ||
611 | # CONFIG_IBM_NEW_EMAC_TAH is not set | ||
612 | # CONFIG_IBM_NEW_EMAC_EMAC4 is not set | ||
565 | # CONFIG_NET_PCI is not set | 613 | # CONFIG_NET_PCI is not set |
614 | # CONFIG_B44 is not set | ||
566 | # CONFIG_NETDEV_1000 is not set | 615 | # CONFIG_NETDEV_1000 is not set |
567 | # CONFIG_NETDEV_10000 is not set | 616 | # CONFIG_NETDEV_10000 is not set |
568 | # CONFIG_TR is not set | 617 | # CONFIG_TR is not set |
@@ -572,6 +621,7 @@ CONFIG_TULIP=y | |||
572 | # | 621 | # |
573 | # CONFIG_WLAN_PRE80211 is not set | 622 | # CONFIG_WLAN_PRE80211 is not set |
574 | # CONFIG_WLAN_80211 is not set | 623 | # CONFIG_WLAN_80211 is not set |
624 | # CONFIG_IWLWIFI_LEDS is not set | ||
575 | 625 | ||
576 | # | 626 | # |
577 | # USB Network Adapters | 627 | # USB Network Adapters |
@@ -580,7 +630,6 @@ CONFIG_TULIP=y | |||
580 | # CONFIG_USB_KAWETH is not set | 630 | # CONFIG_USB_KAWETH is not set |
581 | # CONFIG_USB_PEGASUS is not set | 631 | # CONFIG_USB_PEGASUS is not set |
582 | # CONFIG_USB_RTL8150 is not set | 632 | # CONFIG_USB_RTL8150 is not set |
583 | # CONFIG_USB_USBNET_MII is not set | ||
584 | # CONFIG_USB_USBNET is not set | 633 | # CONFIG_USB_USBNET is not set |
585 | # CONFIG_WAN is not set | 634 | # CONFIG_WAN is not set |
586 | # CONFIG_FDDI is not set | 635 | # CONFIG_FDDI is not set |
@@ -588,7 +637,6 @@ CONFIG_TULIP=y | |||
588 | # CONFIG_PPP is not set | 637 | # CONFIG_PPP is not set |
589 | # CONFIG_SLIP is not set | 638 | # CONFIG_SLIP is not set |
590 | # CONFIG_NET_FC is not set | 639 | # CONFIG_NET_FC is not set |
591 | # CONFIG_SHAPER is not set | ||
592 | # CONFIG_NETCONSOLE is not set | 640 | # CONFIG_NETCONSOLE is not set |
593 | # CONFIG_NETPOLL is not set | 641 | # CONFIG_NETPOLL is not set |
594 | # CONFIG_NET_POLL_CONTROLLER is not set | 642 | # CONFIG_NET_POLL_CONTROLLER is not set |
@@ -607,7 +655,6 @@ CONFIG_INPUT_POLLDEV=y | |||
607 | # | 655 | # |
608 | # CONFIG_INPUT_MOUSEDEV is not set | 656 | # CONFIG_INPUT_MOUSEDEV is not set |
609 | # CONFIG_INPUT_JOYDEV is not set | 657 | # CONFIG_INPUT_JOYDEV is not set |
610 | # CONFIG_INPUT_TSDEV is not set | ||
611 | CONFIG_INPUT_EVDEV=y | 658 | CONFIG_INPUT_EVDEV=y |
612 | # CONFIG_INPUT_EVBUG is not set | 659 | # CONFIG_INPUT_EVBUG is not set |
613 | 660 | ||
@@ -642,7 +689,9 @@ CONFIG_VT=y | |||
642 | CONFIG_VT_CONSOLE=y | 689 | CONFIG_VT_CONSOLE=y |
643 | CONFIG_HW_CONSOLE=y | 690 | CONFIG_HW_CONSOLE=y |
644 | CONFIG_VT_HW_CONSOLE_BINDING=y | 691 | CONFIG_VT_HW_CONSOLE_BINDING=y |
692 | CONFIG_DEVKMEM=y | ||
645 | # CONFIG_SERIAL_NONSTANDARD is not set | 693 | # CONFIG_SERIAL_NONSTANDARD is not set |
694 | # CONFIG_NOZOMI is not set | ||
646 | 695 | ||
647 | # | 696 | # |
648 | # Serial drivers | 697 | # Serial drivers |
@@ -664,65 +713,122 @@ CONFIG_UNIX98_PTYS=y | |||
664 | CONFIG_LEGACY_PTYS=y | 713 | CONFIG_LEGACY_PTYS=y |
665 | CONFIG_LEGACY_PTY_COUNT=256 | 714 | CONFIG_LEGACY_PTY_COUNT=256 |
666 | # CONFIG_IPMI_HANDLER is not set | 715 | # CONFIG_IPMI_HANDLER is not set |
667 | # CONFIG_WATCHDOG is not set | ||
668 | # CONFIG_HW_RANDOM is not set | 716 | # CONFIG_HW_RANDOM is not set |
669 | # CONFIG_RTC is not set | ||
670 | CONFIG_COBALT_LCD=y | ||
671 | # CONFIG_R3964 is not set | 717 | # CONFIG_R3964 is not set |
672 | # CONFIG_APPLICOM is not set | 718 | # CONFIG_APPLICOM is not set |
673 | # CONFIG_DRM is not set | ||
674 | # CONFIG_RAW_DRIVER is not set | 719 | # CONFIG_RAW_DRIVER is not set |
675 | # CONFIG_TCG_TPM is not set | 720 | # CONFIG_TCG_TPM is not set |
676 | CONFIG_DEVPORT=y | 721 | CONFIG_DEVPORT=y |
677 | # CONFIG_I2C is not set | 722 | # CONFIG_I2C is not set |
678 | |||
679 | # | ||
680 | # SPI support | ||
681 | # | ||
682 | # CONFIG_SPI is not set | 723 | # CONFIG_SPI is not set |
683 | # CONFIG_SPI_MASTER is not set | ||
684 | # CONFIG_W1 is not set | 724 | # CONFIG_W1 is not set |
685 | # CONFIG_POWER_SUPPLY is not set | 725 | # CONFIG_POWER_SUPPLY is not set |
686 | # CONFIG_HWMON is not set | 726 | # CONFIG_HWMON is not set |
727 | # CONFIG_THERMAL is not set | ||
728 | # CONFIG_THERMAL_HWMON is not set | ||
729 | # CONFIG_WATCHDOG is not set | ||
730 | |||
731 | # | ||
732 | # Sonics Silicon Backplane | ||
733 | # | ||
734 | CONFIG_SSB_POSSIBLE=y | ||
735 | # CONFIG_SSB is not set | ||
687 | 736 | ||
688 | # | 737 | # |
689 | # Multifunction device drivers | 738 | # Multifunction device drivers |
690 | # | 739 | # |
740 | # CONFIG_MFD_CORE is not set | ||
691 | # CONFIG_MFD_SM501 is not set | 741 | # CONFIG_MFD_SM501 is not set |
742 | # CONFIG_HTC_PASIC3 is not set | ||
692 | 743 | ||
693 | # | 744 | # |
694 | # Multimedia devices | 745 | # Multimedia devices |
695 | # | 746 | # |
747 | |||
748 | # | ||
749 | # Multimedia core support | ||
750 | # | ||
696 | # CONFIG_VIDEO_DEV is not set | 751 | # CONFIG_VIDEO_DEV is not set |
697 | # CONFIG_DVB_CORE is not set | 752 | # CONFIG_DVB_CORE is not set |
753 | # CONFIG_VIDEO_MEDIA is not set | ||
754 | |||
755 | # | ||
756 | # Multimedia drivers | ||
757 | # | ||
698 | # CONFIG_DAB is not set | 758 | # CONFIG_DAB is not set |
699 | 759 | ||
700 | # | 760 | # |
701 | # Graphics support | 761 | # Graphics support |
702 | # | 762 | # |
763 | # CONFIG_DRM is not set | ||
764 | # CONFIG_VGASTATE is not set | ||
765 | # CONFIG_VIDEO_OUTPUT_CONTROL is not set | ||
766 | CONFIG_FB=y | ||
767 | # CONFIG_FIRMWARE_EDID is not set | ||
768 | # CONFIG_FB_DDC is not set | ||
769 | # CONFIG_FB_CFB_FILLRECT is not set | ||
770 | # CONFIG_FB_CFB_COPYAREA is not set | ||
771 | # CONFIG_FB_CFB_IMAGEBLIT is not set | ||
772 | # CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set | ||
773 | # CONFIG_FB_SYS_FILLRECT is not set | ||
774 | # CONFIG_FB_SYS_COPYAREA is not set | ||
775 | # CONFIG_FB_SYS_IMAGEBLIT is not set | ||
776 | # CONFIG_FB_FOREIGN_ENDIAN is not set | ||
777 | # CONFIG_FB_SYS_FOPS is not set | ||
778 | # CONFIG_FB_SVGALIB is not set | ||
779 | # CONFIG_FB_MACMODES is not set | ||
780 | # CONFIG_FB_BACKLIGHT is not set | ||
781 | # CONFIG_FB_MODE_HELPERS is not set | ||
782 | # CONFIG_FB_TILEBLITTING is not set | ||
783 | |||
784 | # | ||
785 | # Frame buffer hardware drivers | ||
786 | # | ||
787 | # CONFIG_FB_CIRRUS is not set | ||
788 | # CONFIG_FB_PM2 is not set | ||
789 | # CONFIG_FB_CYBER2000 is not set | ||
790 | # CONFIG_FB_ASILIANT is not set | ||
791 | # CONFIG_FB_IMSTT is not set | ||
792 | # CONFIG_FB_S1D13XXX is not set | ||
793 | # CONFIG_FB_NVIDIA is not set | ||
794 | # CONFIG_FB_RIVA is not set | ||
795 | # CONFIG_FB_MATROX is not set | ||
796 | # CONFIG_FB_RADEON is not set | ||
797 | # CONFIG_FB_ATY128 is not set | ||
798 | # CONFIG_FB_ATY is not set | ||
799 | # CONFIG_FB_S3 is not set | ||
800 | # CONFIG_FB_SAVAGE is not set | ||
801 | # CONFIG_FB_SIS is not set | ||
802 | # CONFIG_FB_NEOMAGIC is not set | ||
803 | # CONFIG_FB_KYRO is not set | ||
804 | # CONFIG_FB_3DFX is not set | ||
805 | # CONFIG_FB_VOODOO1 is not set | ||
806 | # CONFIG_FB_VT8623 is not set | ||
807 | # CONFIG_FB_TRIDENT is not set | ||
808 | # CONFIG_FB_ARK is not set | ||
809 | # CONFIG_FB_PM3 is not set | ||
810 | # CONFIG_FB_CARMINE is not set | ||
811 | CONFIG_FB_COBALT=y | ||
812 | # CONFIG_FB_VIRTUAL is not set | ||
703 | # CONFIG_BACKLIGHT_LCD_SUPPORT is not set | 813 | # CONFIG_BACKLIGHT_LCD_SUPPORT is not set |
704 | 814 | ||
705 | # | 815 | # |
706 | # Display device support | 816 | # Display device support |
707 | # | 817 | # |
708 | # CONFIG_DISPLAY_SUPPORT is not set | 818 | # CONFIG_DISPLAY_SUPPORT is not set |
709 | # CONFIG_VGASTATE is not set | ||
710 | # CONFIG_VIDEO_OUTPUT_CONTROL is not set | ||
711 | # CONFIG_FB is not set | ||
712 | 819 | ||
713 | # | 820 | # |
714 | # Console display driver support | 821 | # Console display driver support |
715 | # | 822 | # |
716 | # CONFIG_VGA_CONSOLE is not set | 823 | # CONFIG_VGA_CONSOLE is not set |
717 | CONFIG_DUMMY_CONSOLE=y | 824 | CONFIG_DUMMY_CONSOLE=y |
718 | 825 | # CONFIG_FRAMEBUFFER_CONSOLE is not set | |
719 | # | 826 | # CONFIG_LOGO is not set |
720 | # Sound | ||
721 | # | ||
722 | # CONFIG_SOUND is not set | 827 | # CONFIG_SOUND is not set |
723 | CONFIG_HID_SUPPORT=y | 828 | CONFIG_HID_SUPPORT=y |
724 | CONFIG_HID=m | 829 | CONFIG_HID=m |
725 | # CONFIG_HID_DEBUG is not set | 830 | # CONFIG_HID_DEBUG is not set |
831 | # CONFIG_HIDRAW is not set | ||
726 | 832 | ||
727 | # | 833 | # |
728 | # USB Input Devices | 834 | # USB Input Devices |
@@ -743,6 +849,7 @@ CONFIG_USB_ARCH_HAS_OHCI=y | |||
743 | CONFIG_USB_ARCH_HAS_EHCI=y | 849 | CONFIG_USB_ARCH_HAS_EHCI=y |
744 | CONFIG_USB=m | 850 | CONFIG_USB=m |
745 | # CONFIG_USB_DEBUG is not set | 851 | # CONFIG_USB_DEBUG is not set |
852 | # CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set | ||
746 | 853 | ||
747 | # | 854 | # |
748 | # Miscellaneous USB options | 855 | # Miscellaneous USB options |
@@ -751,15 +858,18 @@ CONFIG_USB=m | |||
751 | # CONFIG_USB_DEVICE_CLASS is not set | 858 | # CONFIG_USB_DEVICE_CLASS is not set |
752 | # CONFIG_USB_DYNAMIC_MINORS is not set | 859 | # CONFIG_USB_DYNAMIC_MINORS is not set |
753 | # CONFIG_USB_OTG is not set | 860 | # CONFIG_USB_OTG is not set |
861 | # CONFIG_USB_OTG_WHITELIST is not set | ||
862 | # CONFIG_USB_OTG_BLACKLIST_HUB is not set | ||
754 | 863 | ||
755 | # | 864 | # |
756 | # USB Host Controller Drivers | 865 | # USB Host Controller Drivers |
757 | # | 866 | # |
867 | # CONFIG_USB_C67X00_HCD is not set | ||
758 | CONFIG_USB_EHCI_HCD=m | 868 | CONFIG_USB_EHCI_HCD=m |
759 | # CONFIG_USB_EHCI_SPLIT_ISO is not set | ||
760 | # CONFIG_USB_EHCI_ROOT_HUB_TT is not set | 869 | # CONFIG_USB_EHCI_ROOT_HUB_TT is not set |
761 | # CONFIG_USB_EHCI_TT_NEWSCHED is not set | 870 | # CONFIG_USB_EHCI_TT_NEWSCHED is not set |
762 | # CONFIG_USB_ISP116X_HCD is not set | 871 | # CONFIG_USB_ISP116X_HCD is not set |
872 | # CONFIG_USB_ISP1760_HCD is not set | ||
763 | CONFIG_USB_OHCI_HCD=m | 873 | CONFIG_USB_OHCI_HCD=m |
764 | # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set | 874 | # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set |
765 | # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set | 875 | # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set |
@@ -773,6 +883,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y | |||
773 | # | 883 | # |
774 | # CONFIG_USB_ACM is not set | 884 | # CONFIG_USB_ACM is not set |
775 | # CONFIG_USB_PRINTER is not set | 885 | # CONFIG_USB_PRINTER is not set |
886 | # CONFIG_USB_WDM is not set | ||
776 | 887 | ||
777 | # | 888 | # |
778 | # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' | 889 | # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' |
@@ -785,6 +896,7 @@ CONFIG_USB_STORAGE=m | |||
785 | # CONFIG_USB_STORAGE_DEBUG is not set | 896 | # CONFIG_USB_STORAGE_DEBUG is not set |
786 | # CONFIG_USB_STORAGE_DATAFAB is not set | 897 | # CONFIG_USB_STORAGE_DATAFAB is not set |
787 | # CONFIG_USB_STORAGE_FREECOM is not set | 898 | # CONFIG_USB_STORAGE_FREECOM is not set |
899 | # CONFIG_USB_STORAGE_ISD200 is not set | ||
788 | # CONFIG_USB_STORAGE_DPCM is not set | 900 | # CONFIG_USB_STORAGE_DPCM is not set |
789 | # CONFIG_USB_STORAGE_USBAT is not set | 901 | # CONFIG_USB_STORAGE_USBAT is not set |
790 | # CONFIG_USB_STORAGE_SDDR09 is not set | 902 | # CONFIG_USB_STORAGE_SDDR09 is not set |
@@ -793,6 +905,7 @@ CONFIG_USB_STORAGE=m | |||
793 | # CONFIG_USB_STORAGE_ALAUDA is not set | 905 | # CONFIG_USB_STORAGE_ALAUDA is not set |
794 | # CONFIG_USB_STORAGE_ONETOUCH is not set | 906 | # CONFIG_USB_STORAGE_ONETOUCH is not set |
795 | # CONFIG_USB_STORAGE_KARMA is not set | 907 | # CONFIG_USB_STORAGE_KARMA is not set |
908 | # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set | ||
796 | # CONFIG_USB_LIBUSUAL is not set | 909 | # CONFIG_USB_LIBUSUAL is not set |
797 | 910 | ||
798 | # | 911 | # |
@@ -800,15 +913,11 @@ CONFIG_USB_STORAGE=m | |||
800 | # | 913 | # |
801 | # CONFIG_USB_MDC800 is not set | 914 | # CONFIG_USB_MDC800 is not set |
802 | # CONFIG_USB_MICROTEK is not set | 915 | # CONFIG_USB_MICROTEK is not set |
803 | CONFIG_USB_MON=y | 916 | # CONFIG_USB_MON is not set |
804 | 917 | ||
805 | # | 918 | # |
806 | # USB port drivers | 919 | # USB port drivers |
807 | # | 920 | # |
808 | |||
809 | # | ||
810 | # USB Serial Converter support | ||
811 | # | ||
812 | # CONFIG_USB_SERIAL is not set | 921 | # CONFIG_USB_SERIAL is not set |
813 | 922 | ||
814 | # | 923 | # |
@@ -833,16 +942,10 @@ CONFIG_USB_MON=y | |||
833 | # CONFIG_USB_LD is not set | 942 | # CONFIG_USB_LD is not set |
834 | # CONFIG_USB_TRANCEVIBRATOR is not set | 943 | # CONFIG_USB_TRANCEVIBRATOR is not set |
835 | # CONFIG_USB_IOWARRIOR is not set | 944 | # CONFIG_USB_IOWARRIOR is not set |
836 | 945 | # CONFIG_USB_ISIGHTFW is not set | |
837 | # | ||
838 | # USB DSL modem support | ||
839 | # | ||
840 | |||
841 | # | ||
842 | # USB Gadget Support | ||
843 | # | ||
844 | # CONFIG_USB_GADGET is not set | 946 | # CONFIG_USB_GADGET is not set |
845 | # CONFIG_MMC is not set | 947 | # CONFIG_MMC is not set |
948 | # CONFIG_MEMSTICK is not set | ||
846 | CONFIG_NEW_LEDS=y | 949 | CONFIG_NEW_LEDS=y |
847 | CONFIG_LEDS_CLASS=y | 950 | CONFIG_LEDS_CLASS=y |
848 | 951 | ||
@@ -858,6 +961,8 @@ CONFIG_LEDS_COBALT_RAQ=y | |||
858 | CONFIG_LEDS_TRIGGERS=y | 961 | CONFIG_LEDS_TRIGGERS=y |
859 | # CONFIG_LEDS_TRIGGER_TIMER is not set | 962 | # CONFIG_LEDS_TRIGGER_TIMER is not set |
860 | # CONFIG_LEDS_TRIGGER_HEARTBEAT is not set | 963 | # CONFIG_LEDS_TRIGGER_HEARTBEAT is not set |
964 | # CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set | ||
965 | # CONFIG_ACCESSIBILITY is not set | ||
861 | # CONFIG_INFINIBAND is not set | 966 | # CONFIG_INFINIBAND is not set |
862 | CONFIG_RTC_LIB=y | 967 | CONFIG_RTC_LIB=y |
863 | CONFIG_RTC_CLASS=y | 968 | CONFIG_RTC_CLASS=y |
@@ -882,9 +987,10 @@ CONFIG_RTC_INTF_DEV=y | |||
882 | # Platform RTC drivers | 987 | # Platform RTC drivers |
883 | # | 988 | # |
884 | CONFIG_RTC_DRV_CMOS=y | 989 | CONFIG_RTC_DRV_CMOS=y |
990 | # CONFIG_RTC_DRV_DS1511 is not set | ||
885 | # CONFIG_RTC_DRV_DS1553 is not set | 991 | # CONFIG_RTC_DRV_DS1553 is not set |
886 | # CONFIG_RTC_DRV_STK17TA8 is not set | ||
887 | # CONFIG_RTC_DRV_DS1742 is not set | 992 | # CONFIG_RTC_DRV_DS1742 is not set |
993 | # CONFIG_RTC_DRV_STK17TA8 is not set | ||
888 | # CONFIG_RTC_DRV_M48T86 is not set | 994 | # CONFIG_RTC_DRV_M48T86 is not set |
889 | # CONFIG_RTC_DRV_M48T59 is not set | 995 | # CONFIG_RTC_DRV_M48T59 is not set |
890 | # CONFIG_RTC_DRV_V3020 is not set | 996 | # CONFIG_RTC_DRV_V3020 is not set |
@@ -892,23 +998,7 @@ CONFIG_RTC_DRV_CMOS=y | |||
892 | # | 998 | # |
893 | # on-CPU RTC drivers | 999 | # on-CPU RTC drivers |
894 | # | 1000 | # |
895 | 1001 | # CONFIG_DMADEVICES is not set | |
896 | # | ||
897 | # DMA Engine support | ||
898 | # | ||
899 | # CONFIG_DMA_ENGINE is not set | ||
900 | |||
901 | # | ||
902 | # DMA Clients | ||
903 | # | ||
904 | |||
905 | # | ||
906 | # DMA Devices | ||
907 | # | ||
908 | |||
909 | # | ||
910 | # Userspace I/O | ||
911 | # | ||
912 | # CONFIG_UIO is not set | 1002 | # CONFIG_UIO is not set |
913 | 1003 | ||
914 | # | 1004 | # |
@@ -923,22 +1013,22 @@ CONFIG_EXT3_FS=y | |||
923 | CONFIG_EXT3_FS_XATTR=y | 1013 | CONFIG_EXT3_FS_XATTR=y |
924 | CONFIG_EXT3_FS_POSIX_ACL=y | 1014 | CONFIG_EXT3_FS_POSIX_ACL=y |
925 | CONFIG_EXT3_FS_SECURITY=y | 1015 | CONFIG_EXT3_FS_SECURITY=y |
926 | # CONFIG_EXT4DEV_FS is not set | 1016 | CONFIG_EXT4DEV_FS=y |
1017 | CONFIG_EXT4DEV_FS_XATTR=y | ||
1018 | CONFIG_EXT4DEV_FS_POSIX_ACL=y | ||
1019 | CONFIG_EXT4DEV_FS_SECURITY=y | ||
927 | CONFIG_JBD=y | 1020 | CONFIG_JBD=y |
928 | # CONFIG_JBD_DEBUG is not set | 1021 | CONFIG_JBD2=y |
929 | CONFIG_FS_MBCACHE=y | 1022 | CONFIG_FS_MBCACHE=y |
930 | # CONFIG_REISERFS_FS is not set | 1023 | # CONFIG_REISERFS_FS is not set |
931 | # CONFIG_JFS_FS is not set | 1024 | # CONFIG_JFS_FS is not set |
932 | CONFIG_FS_POSIX_ACL=y | 1025 | CONFIG_FS_POSIX_ACL=y |
933 | # CONFIG_XFS_FS is not set | 1026 | # CONFIG_XFS_FS is not set |
934 | # CONFIG_GFS2_FS is not set | ||
935 | # CONFIG_OCFS2_FS is not set | 1027 | # CONFIG_OCFS2_FS is not set |
936 | # CONFIG_MINIX_FS is not set | 1028 | CONFIG_DNOTIFY=y |
937 | # CONFIG_ROMFS_FS is not set | ||
938 | CONFIG_INOTIFY=y | 1029 | CONFIG_INOTIFY=y |
939 | CONFIG_INOTIFY_USER=y | 1030 | CONFIG_INOTIFY_USER=y |
940 | # CONFIG_QUOTA is not set | 1031 | # CONFIG_QUOTA is not set |
941 | CONFIG_DNOTIFY=y | ||
942 | # CONFIG_AUTOFS_FS is not set | 1032 | # CONFIG_AUTOFS_FS is not set |
943 | # CONFIG_AUTOFS4_FS is not set | 1033 | # CONFIG_AUTOFS4_FS is not set |
944 | # CONFIG_FUSE_FS is not set | 1034 | # CONFIG_FUSE_FS is not set |
@@ -967,7 +1057,6 @@ CONFIG_SYSFS=y | |||
967 | CONFIG_TMPFS=y | 1057 | CONFIG_TMPFS=y |
968 | CONFIG_TMPFS_POSIX_ACL=y | 1058 | CONFIG_TMPFS_POSIX_ACL=y |
969 | # CONFIG_HUGETLB_PAGE is not set | 1059 | # CONFIG_HUGETLB_PAGE is not set |
970 | CONFIG_RAMFS=y | ||
971 | CONFIG_CONFIGFS_FS=y | 1060 | CONFIG_CONFIGFS_FS=y |
972 | 1061 | ||
973 | # | 1062 | # |
@@ -983,32 +1072,28 @@ CONFIG_CONFIGFS_FS=y | |||
983 | # CONFIG_JFFS2_FS is not set | 1072 | # CONFIG_JFFS2_FS is not set |
984 | # CONFIG_CRAMFS is not set | 1073 | # CONFIG_CRAMFS is not set |
985 | # CONFIG_VXFS_FS is not set | 1074 | # CONFIG_VXFS_FS is not set |
1075 | # CONFIG_MINIX_FS is not set | ||
986 | # CONFIG_HPFS_FS is not set | 1076 | # CONFIG_HPFS_FS is not set |
987 | # CONFIG_QNX4FS_FS is not set | 1077 | # CONFIG_QNX4FS_FS is not set |
1078 | # CONFIG_ROMFS_FS is not set | ||
988 | # CONFIG_SYSV_FS is not set | 1079 | # CONFIG_SYSV_FS is not set |
989 | # CONFIG_UFS_FS is not set | 1080 | # CONFIG_UFS_FS is not set |
990 | 1081 | CONFIG_NETWORK_FILESYSTEMS=y | |
991 | # | ||
992 | # Network File Systems | ||
993 | # | ||
994 | CONFIG_NFS_FS=y | 1082 | CONFIG_NFS_FS=y |
995 | CONFIG_NFS_V3=y | 1083 | CONFIG_NFS_V3=y |
996 | CONFIG_NFS_V3_ACL=y | 1084 | CONFIG_NFS_V3_ACL=y |
997 | # CONFIG_NFS_V4 is not set | 1085 | # CONFIG_NFS_V4 is not set |
998 | # CONFIG_NFS_DIRECTIO is not set | ||
999 | CONFIG_NFSD=y | 1086 | CONFIG_NFSD=y |
1000 | CONFIG_NFSD_V2_ACL=y | 1087 | CONFIG_NFSD_V2_ACL=y |
1001 | CONFIG_NFSD_V3=y | 1088 | CONFIG_NFSD_V3=y |
1002 | CONFIG_NFSD_V3_ACL=y | 1089 | CONFIG_NFSD_V3_ACL=y |
1003 | # CONFIG_NFSD_V4 is not set | 1090 | # CONFIG_NFSD_V4 is not set |
1004 | CONFIG_NFSD_TCP=y | ||
1005 | CONFIG_LOCKD=y | 1091 | CONFIG_LOCKD=y |
1006 | CONFIG_LOCKD_V4=y | 1092 | CONFIG_LOCKD_V4=y |
1007 | CONFIG_EXPORTFS=y | 1093 | CONFIG_EXPORTFS=y |
1008 | CONFIG_NFS_ACL_SUPPORT=y | 1094 | CONFIG_NFS_ACL_SUPPORT=y |
1009 | CONFIG_NFS_COMMON=y | 1095 | CONFIG_NFS_COMMON=y |
1010 | CONFIG_SUNRPC=y | 1096 | CONFIG_SUNRPC=y |
1011 | # CONFIG_SUNRPC_BIND34 is not set | ||
1012 | # CONFIG_RPCSEC_GSS_KRB5 is not set | 1097 | # CONFIG_RPCSEC_GSS_KRB5 is not set |
1013 | # CONFIG_RPCSEC_GSS_SPKM3 is not set | 1098 | # CONFIG_RPCSEC_GSS_SPKM3 is not set |
1014 | # CONFIG_SMB_FS is not set | 1099 | # CONFIG_SMB_FS is not set |
@@ -1022,34 +1107,26 @@ CONFIG_SUNRPC=y | |||
1022 | # | 1107 | # |
1023 | # CONFIG_PARTITION_ADVANCED is not set | 1108 | # CONFIG_PARTITION_ADVANCED is not set |
1024 | CONFIG_MSDOS_PARTITION=y | 1109 | CONFIG_MSDOS_PARTITION=y |
1025 | |||
1026 | # | ||
1027 | # Native Language Support | ||
1028 | # | ||
1029 | # CONFIG_NLS is not set | 1110 | # CONFIG_NLS is not set |
1030 | |||
1031 | # | ||
1032 | # Distributed Lock Manager | ||
1033 | # | ||
1034 | # CONFIG_DLM is not set | 1111 | # CONFIG_DLM is not set |
1035 | 1112 | ||
1036 | # | 1113 | # |
1037 | # Profiling support | ||
1038 | # | ||
1039 | # CONFIG_PROFILING is not set | ||
1040 | |||
1041 | # | ||
1042 | # Kernel hacking | 1114 | # Kernel hacking |
1043 | # | 1115 | # |
1044 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | 1116 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y |
1045 | # CONFIG_PRINTK_TIME is not set | 1117 | # CONFIG_PRINTK_TIME is not set |
1118 | CONFIG_ENABLE_WARN_DEPRECATED=y | ||
1046 | CONFIG_ENABLE_MUST_CHECK=y | 1119 | CONFIG_ENABLE_MUST_CHECK=y |
1120 | CONFIG_FRAME_WARN=1024 | ||
1047 | # CONFIG_MAGIC_SYSRQ is not set | 1121 | # CONFIG_MAGIC_SYSRQ is not set |
1048 | # CONFIG_UNUSED_SYMBOLS is not set | 1122 | # CONFIG_UNUSED_SYMBOLS is not set |
1049 | # CONFIG_DEBUG_FS is not set | 1123 | # CONFIG_DEBUG_FS is not set |
1050 | # CONFIG_HEADERS_CHECK is not set | 1124 | # CONFIG_HEADERS_CHECK is not set |
1051 | # CONFIG_DEBUG_KERNEL is not set | 1125 | # CONFIG_DEBUG_KERNEL is not set |
1052 | CONFIG_CROSSCOMPILE=y | 1126 | # CONFIG_SLUB_DEBUG_ON is not set |
1127 | # CONFIG_SLUB_STATS is not set | ||
1128 | # CONFIG_DEBUG_MEMORY_INIT is not set | ||
1129 | # CONFIG_SAMPLES is not set | ||
1053 | CONFIG_CMDLINE="" | 1130 | CONFIG_CMDLINE="" |
1054 | 1131 | ||
1055 | # | 1132 | # |
@@ -1057,14 +1134,95 @@ CONFIG_CMDLINE="" | |||
1057 | # | 1134 | # |
1058 | # CONFIG_KEYS is not set | 1135 | # CONFIG_KEYS is not set |
1059 | # CONFIG_SECURITY is not set | 1136 | # CONFIG_SECURITY is not set |
1060 | # CONFIG_CRYPTO is not set | 1137 | # CONFIG_SECURITY_FILE_CAPABILITIES is not set |
1138 | CONFIG_CRYPTO=y | ||
1139 | |||
1140 | # | ||
1141 | # Crypto core or helper | ||
1142 | # | ||
1143 | # CONFIG_CRYPTO_MANAGER is not set | ||
1144 | # CONFIG_CRYPTO_GF128MUL is not set | ||
1145 | # CONFIG_CRYPTO_NULL is not set | ||
1146 | # CONFIG_CRYPTO_CRYPTD is not set | ||
1147 | # CONFIG_CRYPTO_AUTHENC is not set | ||
1148 | # CONFIG_CRYPTO_TEST is not set | ||
1149 | |||
1150 | # | ||
1151 | # Authenticated Encryption with Associated Data | ||
1152 | # | ||
1153 | # CONFIG_CRYPTO_CCM is not set | ||
1154 | # CONFIG_CRYPTO_GCM is not set | ||
1155 | # CONFIG_CRYPTO_SEQIV is not set | ||
1156 | |||
1157 | # | ||
1158 | # Block modes | ||
1159 | # | ||
1160 | # CONFIG_CRYPTO_CBC is not set | ||
1161 | # CONFIG_CRYPTO_CTR is not set | ||
1162 | # CONFIG_CRYPTO_CTS is not set | ||
1163 | # CONFIG_CRYPTO_ECB is not set | ||
1164 | # CONFIG_CRYPTO_LRW is not set | ||
1165 | # CONFIG_CRYPTO_PCBC is not set | ||
1166 | # CONFIG_CRYPTO_XTS is not set | ||
1167 | |||
1168 | # | ||
1169 | # Hash modes | ||
1170 | # | ||
1171 | # CONFIG_CRYPTO_HMAC is not set | ||
1172 | # CONFIG_CRYPTO_XCBC is not set | ||
1173 | |||
1174 | # | ||
1175 | # Digest | ||
1176 | # | ||
1177 | # CONFIG_CRYPTO_CRC32C is not set | ||
1178 | # CONFIG_CRYPTO_MD4 is not set | ||
1179 | # CONFIG_CRYPTO_MD5 is not set | ||
1180 | # CONFIG_CRYPTO_MICHAEL_MIC is not set | ||
1181 | # CONFIG_CRYPTO_RMD128 is not set | ||
1182 | # CONFIG_CRYPTO_RMD160 is not set | ||
1183 | # CONFIG_CRYPTO_RMD256 is not set | ||
1184 | # CONFIG_CRYPTO_RMD320 is not set | ||
1185 | # CONFIG_CRYPTO_SHA1 is not set | ||
1186 | # CONFIG_CRYPTO_SHA256 is not set | ||
1187 | # CONFIG_CRYPTO_SHA512 is not set | ||
1188 | # CONFIG_CRYPTO_TGR192 is not set | ||
1189 | # CONFIG_CRYPTO_WP512 is not set | ||
1190 | |||
1191 | # | ||
1192 | # Ciphers | ||
1193 | # | ||
1194 | # CONFIG_CRYPTO_AES is not set | ||
1195 | # CONFIG_CRYPTO_ANUBIS is not set | ||
1196 | # CONFIG_CRYPTO_ARC4 is not set | ||
1197 | # CONFIG_CRYPTO_BLOWFISH is not set | ||
1198 | # CONFIG_CRYPTO_CAMELLIA is not set | ||
1199 | # CONFIG_CRYPTO_CAST5 is not set | ||
1200 | # CONFIG_CRYPTO_CAST6 is not set | ||
1201 | # CONFIG_CRYPTO_DES is not set | ||
1202 | # CONFIG_CRYPTO_FCRYPT is not set | ||
1203 | # CONFIG_CRYPTO_KHAZAD is not set | ||
1204 | # CONFIG_CRYPTO_SALSA20 is not set | ||
1205 | # CONFIG_CRYPTO_SEED is not set | ||
1206 | # CONFIG_CRYPTO_SERPENT is not set | ||
1207 | # CONFIG_CRYPTO_TEA is not set | ||
1208 | # CONFIG_CRYPTO_TWOFISH is not set | ||
1209 | |||
1210 | # | ||
1211 | # Compression | ||
1212 | # | ||
1213 | # CONFIG_CRYPTO_DEFLATE is not set | ||
1214 | # CONFIG_CRYPTO_LZO is not set | ||
1215 | CONFIG_CRYPTO_HW=y | ||
1216 | # CONFIG_CRYPTO_DEV_HIFN_795X is not set | ||
1061 | 1217 | ||
1062 | # | 1218 | # |
1063 | # Library routines | 1219 | # Library routines |
1064 | # | 1220 | # |
1065 | CONFIG_BITREVERSE=y | 1221 | CONFIG_BITREVERSE=y |
1222 | # CONFIG_GENERIC_FIND_FIRST_BIT is not set | ||
1066 | # CONFIG_CRC_CCITT is not set | 1223 | # CONFIG_CRC_CCITT is not set |
1067 | # CONFIG_CRC16 is not set | 1224 | CONFIG_CRC16=y |
1225 | # CONFIG_CRC_T10DIF is not set | ||
1068 | # CONFIG_CRC_ITU_T is not set | 1226 | # CONFIG_CRC_ITU_T is not set |
1069 | CONFIG_CRC32=y | 1227 | CONFIG_CRC32=y |
1070 | # CONFIG_CRC7 is not set | 1228 | # CONFIG_CRC7 is not set |
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index ebb8ad62b3a3..a279165e3a7d 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig | |||
@@ -1092,7 +1092,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
1092 | CONFIG_LOG_BUF_SHIFT=14 | 1092 | CONFIG_LOG_BUF_SHIFT=14 |
1093 | CONFIG_CROSSCOMPILE=y | 1093 | CONFIG_CROSSCOMPILE=y |
1094 | CONFIG_CMDLINE="" | 1094 | CONFIG_CMDLINE="" |
1095 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1096 | 1095 | ||
1097 | # | 1096 | # |
1098 | # Security options | 1097 | # Security options |
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig index ad4e5ef65592..8944d15caf13 100644 --- a/arch/mips/configs/db1100_defconfig +++ b/arch/mips/configs/db1100_defconfig | |||
@@ -1092,7 +1092,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
1092 | CONFIG_LOG_BUF_SHIFT=14 | 1092 | CONFIG_LOG_BUF_SHIFT=14 |
1093 | CONFIG_CROSSCOMPILE=y | 1093 | CONFIG_CROSSCOMPILE=y |
1094 | CONFIG_CMDLINE="" | 1094 | CONFIG_CMDLINE="" |
1095 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1096 | 1095 | ||
1097 | # | 1096 | # |
1098 | # Security options | 1097 | # Security options |
diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig index d0dc2e83ad35..ab17973107fd 100644 --- a/arch/mips/configs/db1200_defconfig +++ b/arch/mips/configs/db1200_defconfig | |||
@@ -1174,7 +1174,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
1174 | CONFIG_LOG_BUF_SHIFT=14 | 1174 | CONFIG_LOG_BUF_SHIFT=14 |
1175 | CONFIG_CROSSCOMPILE=y | 1175 | CONFIG_CROSSCOMPILE=y |
1176 | CONFIG_CMDLINE="mem=48M" | 1176 | CONFIG_CMDLINE="mem=48M" |
1177 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1178 | 1177 | ||
1179 | # | 1178 | # |
1180 | # Security options | 1179 | # Security options |
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig index 9155082313c8..b65803f19352 100644 --- a/arch/mips/configs/db1500_defconfig +++ b/arch/mips/configs/db1500_defconfig | |||
@@ -1392,7 +1392,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
1392 | CONFIG_LOG_BUF_SHIFT=14 | 1392 | CONFIG_LOG_BUF_SHIFT=14 |
1393 | CONFIG_CROSSCOMPILE=y | 1393 | CONFIG_CROSSCOMPILE=y |
1394 | CONFIG_CMDLINE="" | 1394 | CONFIG_CMDLINE="" |
1395 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1396 | 1395 | ||
1397 | # | 1396 | # |
1398 | # Security options | 1397 | # Security options |
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig index e4e324422cd9..a190ac07740b 100644 --- a/arch/mips/configs/db1550_defconfig +++ b/arch/mips/configs/db1550_defconfig | |||
@@ -1209,7 +1209,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
1209 | CONFIG_LOG_BUF_SHIFT=14 | 1209 | CONFIG_LOG_BUF_SHIFT=14 |
1210 | CONFIG_CROSSCOMPILE=y | 1210 | CONFIG_CROSSCOMPILE=y |
1211 | CONFIG_CMDLINE="" | 1211 | CONFIG_CMDLINE="" |
1212 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1213 | 1212 | ||
1214 | # | 1213 | # |
1215 | # Security options | 1214 | # Security options |
diff --git a/arch/mips/configs/excite_defconfig b/arch/mips/configs/excite_defconfig index 3572e80356d2..4e465e945991 100644 --- a/arch/mips/configs/excite_defconfig +++ b/arch/mips/configs/excite_defconfig | |||
@@ -1269,7 +1269,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
1269 | CONFIG_LOG_BUF_SHIFT=14 | 1269 | CONFIG_LOG_BUF_SHIFT=14 |
1270 | CONFIG_CROSSCOMPILE=y | 1270 | CONFIG_CROSSCOMPILE=y |
1271 | CONFIG_CMDLINE="" | 1271 | CONFIG_CMDLINE="" |
1272 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1273 | 1272 | ||
1274 | # | 1273 | # |
1275 | # Security options | 1274 | # Security options |
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 138c575a0151..831d3e5a1ea6 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig | |||
@@ -943,7 +943,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
943 | # CONFIG_DEBUG_KERNEL is not set | 943 | # CONFIG_DEBUG_KERNEL is not set |
944 | CONFIG_CROSSCOMPILE=y | 944 | CONFIG_CROSSCOMPILE=y |
945 | CONFIG_CMDLINE="" | 945 | CONFIG_CMDLINE="" |
946 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
947 | 946 | ||
948 | # | 947 | # |
949 | # Security options | 948 | # Security options |
diff --git a/arch/mips/configs/msp71xx_defconfig b/arch/mips/configs/msp71xx_defconfig index 59d19472b161..dd13db4d0fb9 100644 --- a/arch/mips/configs/msp71xx_defconfig +++ b/arch/mips/configs/msp71xx_defconfig | |||
@@ -1415,8 +1415,6 @@ CONFIG_FORCED_INLINING=y | |||
1415 | CONFIG_CROSSCOMPILE=y | 1415 | CONFIG_CROSSCOMPILE=y |
1416 | CONFIG_CMDLINE="" | 1416 | CONFIG_CMDLINE="" |
1417 | # CONFIG_DEBUG_STACK_USAGE is not set | 1417 | # CONFIG_DEBUG_STACK_USAGE is not set |
1418 | # CONFIG_KGDB is not set | ||
1419 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1420 | # CONFIG_RUNTIME_DEBUG is not set | 1418 | # CONFIG_RUNTIME_DEBUG is not set |
1421 | # CONFIG_MIPS_UNCACHED is not set | 1419 | # CONFIG_MIPS_UNCACHED is not set |
1422 | 1420 | ||
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index bacf0dd0e345..db9272677aa2 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig | |||
@@ -3020,7 +3020,6 @@ CONFIG_MAGIC_SYSRQ=y | |||
3020 | # CONFIG_DEBUG_KERNEL is not set | 3020 | # CONFIG_DEBUG_KERNEL is not set |
3021 | CONFIG_CROSSCOMPILE=y | 3021 | CONFIG_CROSSCOMPILE=y |
3022 | CONFIG_CMDLINE="" | 3022 | CONFIG_CMDLINE="" |
3023 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
3024 | 3023 | ||
3025 | # | 3024 | # |
3026 | # Security options | 3025 | # Security options |
diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig index 6dfe6f793cef..9e21e333a2fc 100644 --- a/arch/mips/configs/pb1100_defconfig +++ b/arch/mips/configs/pb1100_defconfig | |||
@@ -1085,7 +1085,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
1085 | CONFIG_LOG_BUF_SHIFT=14 | 1085 | CONFIG_LOG_BUF_SHIFT=14 |
1086 | CONFIG_CROSSCOMPILE=y | 1086 | CONFIG_CROSSCOMPILE=y |
1087 | CONFIG_CMDLINE="" | 1087 | CONFIG_CMDLINE="" |
1088 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1089 | 1088 | ||
1090 | # | 1089 | # |
1091 | # Security options | 1090 | # Security options |
diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig index c965a87e6a96..af67ed4f71ae 100644 --- a/arch/mips/configs/pb1500_defconfig +++ b/arch/mips/configs/pb1500_defconfig | |||
@@ -1202,7 +1202,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
1202 | CONFIG_LOG_BUF_SHIFT=14 | 1202 | CONFIG_LOG_BUF_SHIFT=14 |
1203 | CONFIG_CROSSCOMPILE=y | 1203 | CONFIG_CROSSCOMPILE=y |
1204 | CONFIG_CMDLINE="" | 1204 | CONFIG_CMDLINE="" |
1205 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1206 | 1205 | ||
1207 | # | 1206 | # |
1208 | # Security options | 1207 | # Security options |
diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig index 0778996c682f..7956f56cbf3e 100644 --- a/arch/mips/configs/pb1550_defconfig +++ b/arch/mips/configs/pb1550_defconfig | |||
@@ -1195,7 +1195,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
1195 | CONFIG_LOG_BUF_SHIFT=14 | 1195 | CONFIG_LOG_BUF_SHIFT=14 |
1196 | CONFIG_CROSSCOMPILE=y | 1196 | CONFIG_CROSSCOMPILE=y |
1197 | CONFIG_CMDLINE="" | 1197 | CONFIG_CMDLINE="" |
1198 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1199 | 1198 | ||
1200 | # | 1199 | # |
1201 | # Security options | 1200 | # Security options |
diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 37c7b5ffd474..723bd5176a35 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig | |||
@@ -1216,10 +1216,8 @@ CONFIG_DEBUG_MUTEXES=y | |||
1216 | CONFIG_FORCED_INLINING=y | 1216 | CONFIG_FORCED_INLINING=y |
1217 | # CONFIG_RCU_TORTURE_TEST is not set | 1217 | # CONFIG_RCU_TORTURE_TEST is not set |
1218 | CONFIG_CROSSCOMPILE=y | 1218 | CONFIG_CROSSCOMPILE=y |
1219 | CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp" | 1219 | CONFIG_CMDLINE="console=ttyS1,38400n8 root=/dev/nfs ip=bootp" |
1220 | # CONFIG_DEBUG_STACK_USAGE is not set | 1220 | # CONFIG_DEBUG_STACK_USAGE is not set |
1221 | # CONFIG_KGDB is not set | ||
1222 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1223 | # CONFIG_RUNTIME_DEBUG is not set | 1221 | # CONFIG_RUNTIME_DEBUG is not set |
1224 | 1222 | ||
1225 | # | 1223 | # |
diff --git a/arch/mips/configs/pnx8550-stb810_defconfig b/arch/mips/configs/pnx8550-stb810_defconfig index 893e5c4ab66d..b5052fb42e9e 100644 --- a/arch/mips/configs/pnx8550-stb810_defconfig +++ b/arch/mips/configs/pnx8550-stb810_defconfig | |||
@@ -1206,10 +1206,8 @@ CONFIG_DEBUG_SLAB=y | |||
1206 | CONFIG_FORCED_INLINING=y | 1206 | CONFIG_FORCED_INLINING=y |
1207 | # CONFIG_RCU_TORTURE_TEST is not set | 1207 | # CONFIG_RCU_TORTURE_TEST is not set |
1208 | CONFIG_CROSSCOMPILE=y | 1208 | CONFIG_CROSSCOMPILE=y |
1209 | CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp" | 1209 | CONFIG_CMDLINE="console=ttyS1,38400n8 root=/dev/nfs ip=bootp" |
1210 | # CONFIG_DEBUG_STACK_USAGE is not set | 1210 | # CONFIG_DEBUG_STACK_USAGE is not set |
1211 | # CONFIG_KGDB is not set | ||
1212 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
1213 | # CONFIG_RUNTIME_DEBUG is not set | 1211 | # CONFIG_RUNTIME_DEBUG is not set |
1214 | 1212 | ||
1215 | # | 1213 | # |
diff --git a/arch/mips/configs/rbtx49xx_defconfig b/arch/mips/configs/rbtx49xx_defconfig index e42aed5a38bb..c7c0864b8ce9 100644 --- a/arch/mips/configs/rbtx49xx_defconfig +++ b/arch/mips/configs/rbtx49xx_defconfig | |||
@@ -742,7 +742,6 @@ CONFIG_DEBUG_FS=y | |||
742 | # CONFIG_DEBUG_KERNEL is not set | 742 | # CONFIG_DEBUG_KERNEL is not set |
743 | # CONFIG_SAMPLES is not set | 743 | # CONFIG_SAMPLES is not set |
744 | CONFIG_CMDLINE="" | 744 | CONFIG_CMDLINE="" |
745 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
746 | 745 | ||
747 | # | 746 | # |
748 | # Security options | 747 | # Security options |
diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index 1ea97865f2ce..a9acaa2f9da3 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig | |||
@@ -963,7 +963,6 @@ CONFIG_ENABLE_MUST_CHECK=y | |||
963 | # CONFIG_DEBUG_KERNEL is not set | 963 | # CONFIG_DEBUG_KERNEL is not set |
964 | # CONFIG_SAMPLES is not set | 964 | # CONFIG_SAMPLES is not set |
965 | CONFIG_CMDLINE="" | 965 | CONFIG_CMDLINE="" |
966 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
967 | # CONFIG_SB1XXX_CORELIS is not set | 966 | # CONFIG_SB1XXX_CORELIS is not set |
968 | 967 | ||
969 | # | 968 | # |
diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig index 7f86c43d1bda..ea8249c75b3f 100644 --- a/arch/mips/configs/yosemite_defconfig +++ b/arch/mips/configs/yosemite_defconfig | |||
@@ -827,8 +827,6 @@ CONFIG_FORCED_INLINING=y | |||
827 | CONFIG_CROSSCOMPILE=y | 827 | CONFIG_CROSSCOMPILE=y |
828 | CONFIG_CMDLINE="" | 828 | CONFIG_CMDLINE="" |
829 | # CONFIG_DEBUG_STACK_USAGE is not set | 829 | # CONFIG_DEBUG_STACK_USAGE is not set |
830 | # CONFIG_KGDB is not set | ||
831 | CONFIG_SYS_SUPPORTS_KGDB=y | ||
832 | # CONFIG_RUNTIME_DEBUG is not set | 830 | # CONFIG_RUNTIME_DEBUG is not set |
833 | 831 | ||
834 | # | 832 | # |
diff --git a/arch/mips/emma2rh/markeins/platform.c b/arch/mips/emma2rh/markeins/platform.c index 11567702b155..d70627de7cfe 100644 --- a/arch/mips/emma2rh/markeins/platform.c +++ b/arch/mips/emma2rh/markeins/platform.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include <asm/bcache.h> | 34 | #include <asm/bcache.h> |
35 | #include <asm/irq.h> | 35 | #include <asm/irq.h> |
36 | #include <asm/reboot.h> | 36 | #include <asm/reboot.h> |
37 | #include <asm/gdb-stub.h> | ||
38 | #include <asm/traps.h> | 37 | #include <asm/traps.h> |
39 | #include <asm/debug.h> | 38 | #include <asm/debug.h> |
40 | 39 | ||
diff --git a/arch/mips/emma2rh/markeins/setup.c b/arch/mips/emma2rh/markeins/setup.c index 62bfb455d1b1..a56c4b804b07 100644 --- a/arch/mips/emma2rh/markeins/setup.c +++ b/arch/mips/emma2rh/markeins/setup.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #include <asm/bcache.h> | 41 | #include <asm/bcache.h> |
42 | #include <asm/irq.h> | 42 | #include <asm/irq.h> |
43 | #include <asm/reboot.h> | 43 | #include <asm/reboot.h> |
44 | #include <asm/gdb-stub.h> | ||
45 | #include <asm/traps.h> | 44 | #include <asm/traps.h> |
46 | #include <asm/debug.h> | 45 | #include <asm/debug.h> |
47 | 46 | ||
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 0fd31974ba28..706f93974797 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
@@ -71,7 +71,7 @@ obj-$(CONFIG_MIPS32_COMPAT) += linux32.o ptrace32.o signal32.o | |||
71 | obj-$(CONFIG_MIPS32_N32) += binfmt_elfn32.o scall64-n32.o signal_n32.o | 71 | obj-$(CONFIG_MIPS32_N32) += binfmt_elfn32.o scall64-n32.o signal_n32.o |
72 | obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o | 72 | obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o |
73 | 73 | ||
74 | obj-$(CONFIG_KGDB) += gdb-low.o gdb-stub.o | 74 | obj-$(CONFIG_KGDB) += kgdb.o |
75 | obj-$(CONFIG_PROC_FS) += proc.o | 75 | obj-$(CONFIG_PROC_FS) += proc.o |
76 | 76 | ||
77 | obj-$(CONFIG_64BIT) += cpu-bugs64.o | 77 | obj-$(CONFIG_64BIT) += cpu-bugs64.o |
diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S deleted file mode 100644 index 2c446063636a..000000000000 --- a/arch/mips/kernel/gdb-low.S +++ /dev/null | |||
@@ -1,394 +0,0 @@ | |||
1 | /* | ||
2 | * gdb-low.S contains the low-level trap handler for the GDB stub. | ||
3 | * | ||
4 | * Copyright (C) 1995 Andreas Busse | ||
5 | */ | ||
6 | #include <linux/sys.h> | ||
7 | |||
8 | #include <asm/asm.h> | ||
9 | #include <asm/errno.h> | ||
10 | #include <asm/irqflags.h> | ||
11 | #include <asm/mipsregs.h> | ||
12 | #include <asm/regdef.h> | ||
13 | #include <asm/stackframe.h> | ||
14 | #include <asm/gdb-stub.h> | ||
15 | |||
16 | #ifdef CONFIG_32BIT | ||
17 | #define DMFC0 mfc0 | ||
18 | #define DMTC0 mtc0 | ||
19 | #define LDC1 lwc1 | ||
20 | #define SDC1 lwc1 | ||
21 | #endif | ||
22 | #ifdef CONFIG_64BIT | ||
23 | #define DMFC0 dmfc0 | ||
24 | #define DMTC0 dmtc0 | ||
25 | #define LDC1 ldc1 | ||
26 | #define SDC1 ldc1 | ||
27 | #endif | ||
28 | |||
29 | /* | ||
30 | * [jsun] We reserves about 2x GDB_FR_SIZE in stack. The lower (addressed) | ||
31 | * part is used to store registers and passed to exception handler. | ||
32 | * The upper part is reserved for "call func" feature where gdb client | ||
33 | * saves some of the regs, setups call frame and passes args. | ||
34 | * | ||
35 | * A trace shows about 200 bytes are used to store about half of all regs. | ||
36 | * The rest should be big enough for frame setup and passing args. | ||
37 | */ | ||
38 | |||
39 | /* | ||
40 | * The low level trap handler | ||
41 | */ | ||
42 | .align 5 | ||
43 | NESTED(trap_low, GDB_FR_SIZE, sp) | ||
44 | .set noat | ||
45 | .set noreorder | ||
46 | |||
47 | mfc0 k0, CP0_STATUS | ||
48 | sll k0, 3 /* extract cu0 bit */ | ||
49 | bltz k0, 1f | ||
50 | move k1, sp | ||
51 | |||
52 | /* | ||
53 | * Called from user mode, go somewhere else. | ||
54 | */ | ||
55 | mfc0 k0, CP0_CAUSE | ||
56 | andi k0, k0, 0x7c | ||
57 | #ifdef CONFIG_64BIT | ||
58 | dsll k0, k0, 1 | ||
59 | #endif | ||
60 | PTR_L k1, saved_vectors(k0) | ||
61 | jr k1 | ||
62 | nop | ||
63 | 1: | ||
64 | move k0, sp | ||
65 | PTR_SUBU sp, k1, GDB_FR_SIZE*2 # see comment above | ||
66 | LONG_S k0, GDB_FR_REG29(sp) | ||
67 | LONG_S $2, GDB_FR_REG2(sp) | ||
68 | |||
69 | /* | ||
70 | * First save the CP0 and special registers | ||
71 | */ | ||
72 | |||
73 | mfc0 v0, CP0_STATUS | ||
74 | LONG_S v0, GDB_FR_STATUS(sp) | ||
75 | mfc0 v0, CP0_CAUSE | ||
76 | LONG_S v0, GDB_FR_CAUSE(sp) | ||
77 | DMFC0 v0, CP0_EPC | ||
78 | LONG_S v0, GDB_FR_EPC(sp) | ||
79 | DMFC0 v0, CP0_BADVADDR | ||
80 | LONG_S v0, GDB_FR_BADVADDR(sp) | ||
81 | mfhi v0 | ||
82 | LONG_S v0, GDB_FR_HI(sp) | ||
83 | mflo v0 | ||
84 | LONG_S v0, GDB_FR_LO(sp) | ||
85 | |||
86 | /* | ||
87 | * Now the integer registers | ||
88 | */ | ||
89 | |||
90 | LONG_S zero, GDB_FR_REG0(sp) /* I know... */ | ||
91 | LONG_S $1, GDB_FR_REG1(sp) | ||
92 | /* v0 already saved */ | ||
93 | LONG_S $3, GDB_FR_REG3(sp) | ||
94 | LONG_S $4, GDB_FR_REG4(sp) | ||
95 | LONG_S $5, GDB_FR_REG5(sp) | ||
96 | LONG_S $6, GDB_FR_REG6(sp) | ||
97 | LONG_S $7, GDB_FR_REG7(sp) | ||
98 | LONG_S $8, GDB_FR_REG8(sp) | ||
99 | LONG_S $9, GDB_FR_REG9(sp) | ||
100 | LONG_S $10, GDB_FR_REG10(sp) | ||
101 | LONG_S $11, GDB_FR_REG11(sp) | ||
102 | LONG_S $12, GDB_FR_REG12(sp) | ||
103 | LONG_S $13, GDB_FR_REG13(sp) | ||
104 | LONG_S $14, GDB_FR_REG14(sp) | ||
105 | LONG_S $15, GDB_FR_REG15(sp) | ||
106 | LONG_S $16, GDB_FR_REG16(sp) | ||
107 | LONG_S $17, GDB_FR_REG17(sp) | ||
108 | LONG_S $18, GDB_FR_REG18(sp) | ||
109 | LONG_S $19, GDB_FR_REG19(sp) | ||
110 | LONG_S $20, GDB_FR_REG20(sp) | ||
111 | LONG_S $21, GDB_FR_REG21(sp) | ||
112 | LONG_S $22, GDB_FR_REG22(sp) | ||
113 | LONG_S $23, GDB_FR_REG23(sp) | ||
114 | LONG_S $24, GDB_FR_REG24(sp) | ||
115 | LONG_S $25, GDB_FR_REG25(sp) | ||
116 | LONG_S $26, GDB_FR_REG26(sp) | ||
117 | LONG_S $27, GDB_FR_REG27(sp) | ||
118 | LONG_S $28, GDB_FR_REG28(sp) | ||
119 | /* sp already saved */ | ||
120 | LONG_S $30, GDB_FR_REG30(sp) | ||
121 | LONG_S $31, GDB_FR_REG31(sp) | ||
122 | |||
123 | CLI /* disable interrupts */ | ||
124 | TRACE_IRQS_OFF | ||
125 | |||
126 | /* | ||
127 | * Followed by the floating point registers | ||
128 | */ | ||
129 | mfc0 v0, CP0_STATUS /* FPU enabled? */ | ||
130 | srl v0, v0, 16 | ||
131 | andi v0, v0, (ST0_CU1 >> 16) | ||
132 | |||
133 | beqz v0,2f /* disabled, skip */ | ||
134 | nop | ||
135 | |||
136 | SDC1 $0, GDB_FR_FPR0(sp) | ||
137 | SDC1 $1, GDB_FR_FPR1(sp) | ||
138 | SDC1 $2, GDB_FR_FPR2(sp) | ||
139 | SDC1 $3, GDB_FR_FPR3(sp) | ||
140 | SDC1 $4, GDB_FR_FPR4(sp) | ||
141 | SDC1 $5, GDB_FR_FPR5(sp) | ||
142 | SDC1 $6, GDB_FR_FPR6(sp) | ||
143 | SDC1 $7, GDB_FR_FPR7(sp) | ||
144 | SDC1 $8, GDB_FR_FPR8(sp) | ||
145 | SDC1 $9, GDB_FR_FPR9(sp) | ||
146 | SDC1 $10, GDB_FR_FPR10(sp) | ||
147 | SDC1 $11, GDB_FR_FPR11(sp) | ||
148 | SDC1 $12, GDB_FR_FPR12(sp) | ||
149 | SDC1 $13, GDB_FR_FPR13(sp) | ||
150 | SDC1 $14, GDB_FR_FPR14(sp) | ||
151 | SDC1 $15, GDB_FR_FPR15(sp) | ||
152 | SDC1 $16, GDB_FR_FPR16(sp) | ||
153 | SDC1 $17, GDB_FR_FPR17(sp) | ||
154 | SDC1 $18, GDB_FR_FPR18(sp) | ||
155 | SDC1 $19, GDB_FR_FPR19(sp) | ||
156 | SDC1 $20, GDB_FR_FPR20(sp) | ||
157 | SDC1 $21, GDB_FR_FPR21(sp) | ||
158 | SDC1 $22, GDB_FR_FPR22(sp) | ||
159 | SDC1 $23, GDB_FR_FPR23(sp) | ||
160 | SDC1 $24, GDB_FR_FPR24(sp) | ||
161 | SDC1 $25, GDB_FR_FPR25(sp) | ||
162 | SDC1 $26, GDB_FR_FPR26(sp) | ||
163 | SDC1 $27, GDB_FR_FPR27(sp) | ||
164 | SDC1 $28, GDB_FR_FPR28(sp) | ||
165 | SDC1 $29, GDB_FR_FPR29(sp) | ||
166 | SDC1 $30, GDB_FR_FPR30(sp) | ||
167 | SDC1 $31, GDB_FR_FPR31(sp) | ||
168 | |||
169 | /* | ||
170 | * FPU control registers | ||
171 | */ | ||
172 | |||
173 | cfc1 v0, CP1_STATUS | ||
174 | LONG_S v0, GDB_FR_FSR(sp) | ||
175 | cfc1 v0, CP1_REVISION | ||
176 | LONG_S v0, GDB_FR_FIR(sp) | ||
177 | |||
178 | /* | ||
179 | * Current stack frame ptr | ||
180 | */ | ||
181 | |||
182 | 2: | ||
183 | LONG_S sp, GDB_FR_FRP(sp) | ||
184 | |||
185 | /* | ||
186 | * CP0 registers (R4000/R4400 unused registers skipped) | ||
187 | */ | ||
188 | |||
189 | mfc0 v0, CP0_INDEX | ||
190 | LONG_S v0, GDB_FR_CP0_INDEX(sp) | ||
191 | mfc0 v0, CP0_RANDOM | ||
192 | LONG_S v0, GDB_FR_CP0_RANDOM(sp) | ||
193 | DMFC0 v0, CP0_ENTRYLO0 | ||
194 | LONG_S v0, GDB_FR_CP0_ENTRYLO0(sp) | ||
195 | DMFC0 v0, CP0_ENTRYLO1 | ||
196 | LONG_S v0, GDB_FR_CP0_ENTRYLO1(sp) | ||
197 | DMFC0 v0, CP0_CONTEXT | ||
198 | LONG_S v0, GDB_FR_CP0_CONTEXT(sp) | ||
199 | mfc0 v0, CP0_PAGEMASK | ||
200 | LONG_S v0, GDB_FR_CP0_PAGEMASK(sp) | ||
201 | mfc0 v0, CP0_WIRED | ||
202 | LONG_S v0, GDB_FR_CP0_WIRED(sp) | ||
203 | DMFC0 v0, CP0_ENTRYHI | ||
204 | LONG_S v0, GDB_FR_CP0_ENTRYHI(sp) | ||
205 | mfc0 v0, CP0_PRID | ||
206 | LONG_S v0, GDB_FR_CP0_PRID(sp) | ||
207 | |||
208 | .set at | ||
209 | |||
210 | /* | ||
211 | * Continue with the higher level handler | ||
212 | */ | ||
213 | |||
214 | move a0,sp | ||
215 | |||
216 | jal handle_exception | ||
217 | nop | ||
218 | |||
219 | /* | ||
220 | * Restore all writable registers, in reverse order | ||
221 | */ | ||
222 | |||
223 | .set noat | ||
224 | |||
225 | LONG_L v0, GDB_FR_CP0_ENTRYHI(sp) | ||
226 | LONG_L v1, GDB_FR_CP0_WIRED(sp) | ||
227 | DMTC0 v0, CP0_ENTRYHI | ||
228 | mtc0 v1, CP0_WIRED | ||
229 | LONG_L v0, GDB_FR_CP0_PAGEMASK(sp) | ||
230 | LONG_L v1, GDB_FR_CP0_ENTRYLO1(sp) | ||
231 | mtc0 v0, CP0_PAGEMASK | ||
232 | DMTC0 v1, CP0_ENTRYLO1 | ||
233 | LONG_L v0, GDB_FR_CP0_ENTRYLO0(sp) | ||
234 | LONG_L v1, GDB_FR_CP0_INDEX(sp) | ||
235 | DMTC0 v0, CP0_ENTRYLO0 | ||
236 | LONG_L v0, GDB_FR_CP0_CONTEXT(sp) | ||
237 | mtc0 v1, CP0_INDEX | ||
238 | DMTC0 v0, CP0_CONTEXT | ||
239 | |||
240 | |||
241 | /* | ||
242 | * Next, the floating point registers | ||
243 | */ | ||
244 | mfc0 v0, CP0_STATUS /* check if the FPU is enabled */ | ||
245 | srl v0, v0, 16 | ||
246 | andi v0, v0, (ST0_CU1 >> 16) | ||
247 | |||
248 | beqz v0, 3f /* disabled, skip */ | ||
249 | nop | ||
250 | |||
251 | LDC1 $31, GDB_FR_FPR31(sp) | ||
252 | LDC1 $30, GDB_FR_FPR30(sp) | ||
253 | LDC1 $29, GDB_FR_FPR29(sp) | ||
254 | LDC1 $28, GDB_FR_FPR28(sp) | ||
255 | LDC1 $27, GDB_FR_FPR27(sp) | ||
256 | LDC1 $26, GDB_FR_FPR26(sp) | ||
257 | LDC1 $25, GDB_FR_FPR25(sp) | ||
258 | LDC1 $24, GDB_FR_FPR24(sp) | ||
259 | LDC1 $23, GDB_FR_FPR23(sp) | ||
260 | LDC1 $22, GDB_FR_FPR22(sp) | ||
261 | LDC1 $21, GDB_FR_FPR21(sp) | ||
262 | LDC1 $20, GDB_FR_FPR20(sp) | ||
263 | LDC1 $19, GDB_FR_FPR19(sp) | ||
264 | LDC1 $18, GDB_FR_FPR18(sp) | ||
265 | LDC1 $17, GDB_FR_FPR17(sp) | ||
266 | LDC1 $16, GDB_FR_FPR16(sp) | ||
267 | LDC1 $15, GDB_FR_FPR15(sp) | ||
268 | LDC1 $14, GDB_FR_FPR14(sp) | ||
269 | LDC1 $13, GDB_FR_FPR13(sp) | ||
270 | LDC1 $12, GDB_FR_FPR12(sp) | ||
271 | LDC1 $11, GDB_FR_FPR11(sp) | ||
272 | LDC1 $10, GDB_FR_FPR10(sp) | ||
273 | LDC1 $9, GDB_FR_FPR9(sp) | ||
274 | LDC1 $8, GDB_FR_FPR8(sp) | ||
275 | LDC1 $7, GDB_FR_FPR7(sp) | ||
276 | LDC1 $6, GDB_FR_FPR6(sp) | ||
277 | LDC1 $5, GDB_FR_FPR5(sp) | ||
278 | LDC1 $4, GDB_FR_FPR4(sp) | ||
279 | LDC1 $3, GDB_FR_FPR3(sp) | ||
280 | LDC1 $2, GDB_FR_FPR2(sp) | ||
281 | LDC1 $1, GDB_FR_FPR1(sp) | ||
282 | LDC1 $0, GDB_FR_FPR0(sp) | ||
283 | |||
284 | /* | ||
285 | * Now the CP0 and integer registers | ||
286 | */ | ||
287 | |||
288 | 3: | ||
289 | #ifdef CONFIG_MIPS_MT_SMTC | ||
290 | /* Read-modify write of Status must be atomic */ | ||
291 | mfc0 t2, CP0_TCSTATUS | ||
292 | ori t1, t2, TCSTATUS_IXMT | ||
293 | mtc0 t1, CP0_TCSTATUS | ||
294 | andi t2, t2, TCSTATUS_IXMT | ||
295 | _ehb | ||
296 | DMT 9 # dmt t1 | ||
297 | jal mips_ihb | ||
298 | nop | ||
299 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
300 | mfc0 t0, CP0_STATUS | ||
301 | ori t0, 0x1f | ||
302 | xori t0, 0x1f | ||
303 | mtc0 t0, CP0_STATUS | ||
304 | #ifdef CONFIG_MIPS_MT_SMTC | ||
305 | andi t1, t1, VPECONTROL_TE | ||
306 | beqz t1, 9f | ||
307 | nop | ||
308 | EMT # emt | ||
309 | 9: | ||
310 | mfc0 t1, CP0_TCSTATUS | ||
311 | xori t1, t1, TCSTATUS_IXMT | ||
312 | or t1, t1, t2 | ||
313 | mtc0 t1, CP0_TCSTATUS | ||
314 | _ehb | ||
315 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
316 | LONG_L v0, GDB_FR_STATUS(sp) | ||
317 | LONG_L v1, GDB_FR_EPC(sp) | ||
318 | mtc0 v0, CP0_STATUS | ||
319 | DMTC0 v1, CP0_EPC | ||
320 | LONG_L v0, GDB_FR_HI(sp) | ||
321 | LONG_L v1, GDB_FR_LO(sp) | ||
322 | mthi v0 | ||
323 | mtlo v1 | ||
324 | LONG_L $31, GDB_FR_REG31(sp) | ||
325 | LONG_L $30, GDB_FR_REG30(sp) | ||
326 | LONG_L $28, GDB_FR_REG28(sp) | ||
327 | LONG_L $27, GDB_FR_REG27(sp) | ||
328 | LONG_L $26, GDB_FR_REG26(sp) | ||
329 | LONG_L $25, GDB_FR_REG25(sp) | ||
330 | LONG_L $24, GDB_FR_REG24(sp) | ||
331 | LONG_L $23, GDB_FR_REG23(sp) | ||
332 | LONG_L $22, GDB_FR_REG22(sp) | ||
333 | LONG_L $21, GDB_FR_REG21(sp) | ||
334 | LONG_L $20, GDB_FR_REG20(sp) | ||
335 | LONG_L $19, GDB_FR_REG19(sp) | ||
336 | LONG_L $18, GDB_FR_REG18(sp) | ||
337 | LONG_L $17, GDB_FR_REG17(sp) | ||
338 | LONG_L $16, GDB_FR_REG16(sp) | ||
339 | LONG_L $15, GDB_FR_REG15(sp) | ||
340 | LONG_L $14, GDB_FR_REG14(sp) | ||
341 | LONG_L $13, GDB_FR_REG13(sp) | ||
342 | LONG_L $12, GDB_FR_REG12(sp) | ||
343 | LONG_L $11, GDB_FR_REG11(sp) | ||
344 | LONG_L $10, GDB_FR_REG10(sp) | ||
345 | LONG_L $9, GDB_FR_REG9(sp) | ||
346 | LONG_L $8, GDB_FR_REG8(sp) | ||
347 | LONG_L $7, GDB_FR_REG7(sp) | ||
348 | LONG_L $6, GDB_FR_REG6(sp) | ||
349 | LONG_L $5, GDB_FR_REG5(sp) | ||
350 | LONG_L $4, GDB_FR_REG4(sp) | ||
351 | LONG_L $3, GDB_FR_REG3(sp) | ||
352 | LONG_L $2, GDB_FR_REG2(sp) | ||
353 | LONG_L $1, GDB_FR_REG1(sp) | ||
354 | #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) | ||
355 | LONG_L k0, GDB_FR_EPC(sp) | ||
356 | LONG_L $29, GDB_FR_REG29(sp) /* Deallocate stack */ | ||
357 | jr k0 | ||
358 | rfe | ||
359 | #else | ||
360 | LONG_L sp, GDB_FR_REG29(sp) /* Deallocate stack */ | ||
361 | |||
362 | .set mips3 | ||
363 | eret | ||
364 | .set mips0 | ||
365 | #endif | ||
366 | .set at | ||
367 | .set reorder | ||
368 | END(trap_low) | ||
369 | |||
370 | LEAF(kgdb_read_byte) | ||
371 | 4: lb t0, (a0) | ||
372 | sb t0, (a1) | ||
373 | li v0, 0 | ||
374 | jr ra | ||
375 | .section __ex_table,"a" | ||
376 | PTR 4b, kgdbfault | ||
377 | .previous | ||
378 | END(kgdb_read_byte) | ||
379 | |||
380 | LEAF(kgdb_write_byte) | ||
381 | 5: sb a0, (a1) | ||
382 | li v0, 0 | ||
383 | jr ra | ||
384 | .section __ex_table,"a" | ||
385 | PTR 5b, kgdbfault | ||
386 | .previous | ||
387 | END(kgdb_write_byte) | ||
388 | |||
389 | .type kgdbfault@function | ||
390 | .ent kgdbfault | ||
391 | |||
392 | kgdbfault: li v0, -EFAULT | ||
393 | jr ra | ||
394 | .end kgdbfault | ||
diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c deleted file mode 100644 index 25f4eab8ea9c..000000000000 --- a/arch/mips/kernel/gdb-stub.c +++ /dev/null | |||
@@ -1,1155 +0,0 @@ | |||
1 | /* | ||
2 | * arch/mips/kernel/gdb-stub.c | ||
3 | * | ||
4 | * Originally written by Glenn Engel, Lake Stevens Instrument Division | ||
5 | * | ||
6 | * Contributed by HP Systems | ||
7 | * | ||
8 | * Modified for SPARC by Stu Grossman, Cygnus Support. | ||
9 | * | ||
10 | * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse | ||
11 | * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de> | ||
12 | * | ||
13 | * Copyright (C) 1995 Andreas Busse | ||
14 | * | ||
15 | * Copyright (C) 2003 MontaVista Software Inc. | ||
16 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * To enable debugger support, two things need to happen. One, a | ||
21 | * call to set_debug_traps() is necessary in order to allow any breakpoints | ||
22 | * or error conditions to be properly intercepted and reported to gdb. | ||
23 | * Two, a breakpoint needs to be generated to begin communication. This | ||
24 | * is most easily accomplished by a call to breakpoint(). Breakpoint() | ||
25 | * simulates a breakpoint by executing a BREAK instruction. | ||
26 | * | ||
27 | * | ||
28 | * The following gdb commands are supported: | ||
29 | * | ||
30 | * command function Return value | ||
31 | * | ||
32 | * g return the value of the CPU registers hex data or ENN | ||
33 | * G set the value of the CPU registers OK or ENN | ||
34 | * | ||
35 | * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN | ||
36 | * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN | ||
37 | * | ||
38 | * c Resume at current address SNN ( signal NN) | ||
39 | * cAA..AA Continue at address AA..AA SNN | ||
40 | * | ||
41 | * s Step one instruction SNN | ||
42 | * sAA..AA Step one instruction from AA..AA SNN | ||
43 | * | ||
44 | * k kill | ||
45 | * | ||
46 | * ? What was the last sigval ? SNN (signal NN) | ||
47 | * | ||
48 | * bBB..BB Set baud rate to BB..BB OK or BNN, then sets | ||
49 | * baud rate | ||
50 | * | ||
51 | * All commands and responses are sent with a packet which includes a | ||
52 | * checksum. A packet consists of | ||
53 | * | ||
54 | * $<packet info>#<checksum>. | ||
55 | * | ||
56 | * where | ||
57 | * <packet info> :: <characters representing the command or response> | ||
58 | * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> | ||
59 | * | ||
60 | * When a packet is received, it is first acknowledged with either '+' or '-'. | ||
61 | * '+' indicates a successful transfer. '-' indicates a failed transfer. | ||
62 | * | ||
63 | * Example: | ||
64 | * | ||
65 | * Host: Reply: | ||
66 | * $m0,10#2a +$00010203040506070809101112131415#42 | ||
67 | * | ||
68 | * | ||
69 | * ============== | ||
70 | * MORE EXAMPLES: | ||
71 | * ============== | ||
72 | * | ||
73 | * For reference -- the following are the steps that one | ||
74 | * company took (RidgeRun Inc) to get remote gdb debugging | ||
75 | * going. In this scenario the host machine was a PC and the | ||
76 | * target platform was a Galileo EVB64120A MIPS evaluation | ||
77 | * board. | ||
78 | * | ||
79 | * Step 1: | ||
80 | * First download gdb-5.0.tar.gz from the internet. | ||
81 | * and then build/install the package. | ||
82 | * | ||
83 | * Example: | ||
84 | * $ tar zxf gdb-5.0.tar.gz | ||
85 | * $ cd gdb-5.0 | ||
86 | * $ ./configure --target=mips-linux-elf | ||
87 | * $ make | ||
88 | * $ install | ||
89 | * $ which mips-linux-elf-gdb | ||
90 | * /usr/local/bin/mips-linux-elf-gdb | ||
91 | * | ||
92 | * Step 2: | ||
93 | * Configure linux for remote debugging and build it. | ||
94 | * | ||
95 | * Example: | ||
96 | * $ cd ~/linux | ||
97 | * $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging> | ||
98 | * $ make | ||
99 | * | ||
100 | * Step 3: | ||
101 | * Download the kernel to the remote target and start | ||
102 | * the kernel running. It will promptly halt and wait | ||
103 | * for the host gdb session to connect. It does this | ||
104 | * since the "Kernel Hacking" option has defined | ||
105 | * CONFIG_KGDB which in turn enables your calls | ||
106 | * to: | ||
107 | * set_debug_traps(); | ||
108 | * breakpoint(); | ||
109 | * | ||
110 | * Step 4: | ||
111 | * Start the gdb session on the host. | ||
112 | * | ||
113 | * Example: | ||
114 | * $ mips-linux-elf-gdb vmlinux | ||
115 | * (gdb) set remotebaud 115200 | ||
116 | * (gdb) target remote /dev/ttyS1 | ||
117 | * ...at this point you are connected to | ||
118 | * the remote target and can use gdb | ||
119 | * in the normal fasion. Setting | ||
120 | * breakpoints, single stepping, | ||
121 | * printing variables, etc. | ||
122 | */ | ||
123 | #include <linux/string.h> | ||
124 | #include <linux/kernel.h> | ||
125 | #include <linux/signal.h> | ||
126 | #include <linux/sched.h> | ||
127 | #include <linux/mm.h> | ||
128 | #include <linux/console.h> | ||
129 | #include <linux/init.h> | ||
130 | #include <linux/smp.h> | ||
131 | #include <linux/spinlock.h> | ||
132 | #include <linux/slab.h> | ||
133 | #include <linux/reboot.h> | ||
134 | |||
135 | #include <asm/asm.h> | ||
136 | #include <asm/cacheflush.h> | ||
137 | #include <asm/mipsregs.h> | ||
138 | #include <asm/pgtable.h> | ||
139 | #include <asm/system.h> | ||
140 | #include <asm/gdb-stub.h> | ||
141 | #include <asm/inst.h> | ||
142 | |||
143 | /* | ||
144 | * external low-level support routines | ||
145 | */ | ||
146 | |||
147 | extern int putDebugChar(char c); /* write a single character */ | ||
148 | extern char getDebugChar(void); /* read and return a single char */ | ||
149 | extern void trap_low(void); | ||
150 | |||
151 | /* | ||
152 | * breakpoint and test functions | ||
153 | */ | ||
154 | extern void breakpoint(void); | ||
155 | extern void breakinst(void); | ||
156 | extern void async_breakpoint(void); | ||
157 | extern void async_breakinst(void); | ||
158 | extern void adel(void); | ||
159 | |||
160 | /* | ||
161 | * local prototypes | ||
162 | */ | ||
163 | |||
164 | static void getpacket(char *buffer); | ||
165 | static void putpacket(char *buffer); | ||
166 | static int computeSignal(int tt); | ||
167 | static int hex(unsigned char ch); | ||
168 | static int hexToInt(char **ptr, int *intValue); | ||
169 | static int hexToLong(char **ptr, long *longValue); | ||
170 | static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault); | ||
171 | void handle_exception(struct gdb_regs *regs); | ||
172 | |||
173 | int kgdb_enabled; | ||
174 | |||
175 | /* | ||
176 | * spin locks for smp case | ||
177 | */ | ||
178 | static DEFINE_SPINLOCK(kgdb_lock); | ||
179 | static raw_spinlock_t kgdb_cpulock[NR_CPUS] = { | ||
180 | [0 ... NR_CPUS-1] = __RAW_SPIN_LOCK_UNLOCKED, | ||
181 | }; | ||
182 | |||
183 | /* | ||
184 | * BUFMAX defines the maximum number of characters in inbound/outbound buffers | ||
185 | * at least NUMREGBYTES*2 are needed for register packets | ||
186 | */ | ||
187 | #define BUFMAX 2048 | ||
188 | |||
189 | static char input_buffer[BUFMAX]; | ||
190 | static char output_buffer[BUFMAX]; | ||
191 | static int initialized; /* !0 means we've been initialized */ | ||
192 | static int kgdb_started; | ||
193 | static const char hexchars[]="0123456789abcdef"; | ||
194 | |||
195 | /* Used to prevent crashes in memory access. Note that they'll crash anyway if | ||
196 | we haven't set up fault handlers yet... */ | ||
197 | int kgdb_read_byte(unsigned char *address, unsigned char *dest); | ||
198 | int kgdb_write_byte(unsigned char val, unsigned char *dest); | ||
199 | |||
200 | /* | ||
201 | * Convert ch from a hex digit to an int | ||
202 | */ | ||
203 | static int hex(unsigned char ch) | ||
204 | { | ||
205 | if (ch >= 'a' && ch <= 'f') | ||
206 | return ch-'a'+10; | ||
207 | if (ch >= '0' && ch <= '9') | ||
208 | return ch-'0'; | ||
209 | if (ch >= 'A' && ch <= 'F') | ||
210 | return ch-'A'+10; | ||
211 | return -1; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * scan for the sequence $<data>#<checksum> | ||
216 | */ | ||
217 | static void getpacket(char *buffer) | ||
218 | { | ||
219 | unsigned char checksum; | ||
220 | unsigned char xmitcsum; | ||
221 | int i; | ||
222 | int count; | ||
223 | unsigned char ch; | ||
224 | |||
225 | do { | ||
226 | /* | ||
227 | * wait around for the start character, | ||
228 | * ignore all other characters | ||
229 | */ | ||
230 | while ((ch = (getDebugChar() & 0x7f)) != '$') ; | ||
231 | |||
232 | checksum = 0; | ||
233 | xmitcsum = -1; | ||
234 | count = 0; | ||
235 | |||
236 | /* | ||
237 | * now, read until a # or end of buffer is found | ||
238 | */ | ||
239 | while (count < BUFMAX) { | ||
240 | ch = getDebugChar(); | ||
241 | if (ch == '#') | ||
242 | break; | ||
243 | checksum = checksum + ch; | ||
244 | buffer[count] = ch; | ||
245 | count = count + 1; | ||
246 | } | ||
247 | |||
248 | if (count >= BUFMAX) | ||
249 | continue; | ||
250 | |||
251 | buffer[count] = 0; | ||
252 | |||
253 | if (ch == '#') { | ||
254 | xmitcsum = hex(getDebugChar() & 0x7f) << 4; | ||
255 | xmitcsum |= hex(getDebugChar() & 0x7f); | ||
256 | |||
257 | if (checksum != xmitcsum) | ||
258 | putDebugChar('-'); /* failed checksum */ | ||
259 | else { | ||
260 | putDebugChar('+'); /* successful transfer */ | ||
261 | |||
262 | /* | ||
263 | * if a sequence char is present, | ||
264 | * reply the sequence ID | ||
265 | */ | ||
266 | if (buffer[2] == ':') { | ||
267 | putDebugChar(buffer[0]); | ||
268 | putDebugChar(buffer[1]); | ||
269 | |||
270 | /* | ||
271 | * remove sequence chars from buffer | ||
272 | */ | ||
273 | count = strlen(buffer); | ||
274 | for (i=3; i <= count; i++) | ||
275 | buffer[i-3] = buffer[i]; | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | while (checksum != xmitcsum); | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * send the packet in buffer. | ||
285 | */ | ||
286 | static void putpacket(char *buffer) | ||
287 | { | ||
288 | unsigned char checksum; | ||
289 | int count; | ||
290 | unsigned char ch; | ||
291 | |||
292 | /* | ||
293 | * $<packet info>#<checksum>. | ||
294 | */ | ||
295 | |||
296 | do { | ||
297 | putDebugChar('$'); | ||
298 | checksum = 0; | ||
299 | count = 0; | ||
300 | |||
301 | while ((ch = buffer[count]) != 0) { | ||
302 | if (!(putDebugChar(ch))) | ||
303 | return; | ||
304 | checksum += ch; | ||
305 | count += 1; | ||
306 | } | ||
307 | |||
308 | putDebugChar('#'); | ||
309 | putDebugChar(hexchars[checksum >> 4]); | ||
310 | putDebugChar(hexchars[checksum & 0xf]); | ||
311 | |||
312 | } | ||
313 | while ((getDebugChar() & 0x7f) != '+'); | ||
314 | } | ||
315 | |||
316 | |||
317 | /* | ||
318 | * Convert the memory pointed to by mem into hex, placing result in buf. | ||
319 | * Return a pointer to the last char put in buf (null), in case of mem fault, | ||
320 | * return 0. | ||
321 | * may_fault is non-zero if we are reading from arbitrary memory, but is currently | ||
322 | * not used. | ||
323 | */ | ||
324 | static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault) | ||
325 | { | ||
326 | unsigned char ch; | ||
327 | |||
328 | while (count-- > 0) { | ||
329 | if (kgdb_read_byte(mem++, &ch) != 0) | ||
330 | return 0; | ||
331 | *buf++ = hexchars[ch >> 4]; | ||
332 | *buf++ = hexchars[ch & 0xf]; | ||
333 | } | ||
334 | |||
335 | *buf = 0; | ||
336 | |||
337 | return buf; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * convert the hex array pointed to by buf into binary to be placed in mem | ||
342 | * return a pointer to the character AFTER the last byte written | ||
343 | * may_fault is non-zero if we are reading from arbitrary memory, but is currently | ||
344 | * not used. | ||
345 | */ | ||
346 | static char *hex2mem(char *buf, char *mem, int count, int binary, int may_fault) | ||
347 | { | ||
348 | int i; | ||
349 | unsigned char ch; | ||
350 | |||
351 | for (i=0; i<count; i++) | ||
352 | { | ||
353 | if (binary) { | ||
354 | ch = *buf++; | ||
355 | if (ch == 0x7d) | ||
356 | ch = 0x20 ^ *buf++; | ||
357 | } | ||
358 | else { | ||
359 | ch = hex(*buf++) << 4; | ||
360 | ch |= hex(*buf++); | ||
361 | } | ||
362 | if (kgdb_write_byte(ch, mem++) != 0) | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | return mem; | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | * This table contains the mapping between SPARC hardware trap types, and | ||
371 | * signals, which are primarily what GDB understands. It also indicates | ||
372 | * which hardware traps we need to commandeer when initializing the stub. | ||
373 | */ | ||
374 | static struct hard_trap_info { | ||
375 | unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */ | ||
376 | unsigned char signo; /* Signal that we map this trap into */ | ||
377 | } hard_trap_info[] = { | ||
378 | { 6, SIGBUS }, /* instruction bus error */ | ||
379 | { 7, SIGBUS }, /* data bus error */ | ||
380 | { 9, SIGTRAP }, /* break */ | ||
381 | { 10, SIGILL }, /* reserved instruction */ | ||
382 | /* { 11, SIGILL }, */ /* CPU unusable */ | ||
383 | { 12, SIGFPE }, /* overflow */ | ||
384 | { 13, SIGTRAP }, /* trap */ | ||
385 | { 14, SIGSEGV }, /* virtual instruction cache coherency */ | ||
386 | { 15, SIGFPE }, /* floating point exception */ | ||
387 | { 23, SIGSEGV }, /* watch */ | ||
388 | { 31, SIGSEGV }, /* virtual data cache coherency */ | ||
389 | { 0, 0} /* Must be last */ | ||
390 | }; | ||
391 | |||
392 | /* Save the normal trap handlers for user-mode traps. */ | ||
393 | void *saved_vectors[32]; | ||
394 | |||
395 | /* | ||
396 | * Set up exception handlers for tracing and breakpoints | ||
397 | */ | ||
398 | void set_debug_traps(void) | ||
399 | { | ||
400 | struct hard_trap_info *ht; | ||
401 | unsigned long flags; | ||
402 | unsigned char c; | ||
403 | |||
404 | local_irq_save(flags); | ||
405 | for (ht = hard_trap_info; ht->tt && ht->signo; ht++) | ||
406 | saved_vectors[ht->tt] = set_except_vector(ht->tt, trap_low); | ||
407 | |||
408 | putDebugChar('+'); /* 'hello world' */ | ||
409 | /* | ||
410 | * In case GDB is started before us, ack any packets | ||
411 | * (presumably "$?#xx") sitting there. | ||
412 | */ | ||
413 | while((c = getDebugChar()) != '$'); | ||
414 | while((c = getDebugChar()) != '#'); | ||
415 | c = getDebugChar(); /* eat first csum byte */ | ||
416 | c = getDebugChar(); /* eat second csum byte */ | ||
417 | putDebugChar('+'); /* ack it */ | ||
418 | |||
419 | initialized = 1; | ||
420 | local_irq_restore(flags); | ||
421 | } | ||
422 | |||
423 | void restore_debug_traps(void) | ||
424 | { | ||
425 | struct hard_trap_info *ht; | ||
426 | unsigned long flags; | ||
427 | |||
428 | local_irq_save(flags); | ||
429 | for (ht = hard_trap_info; ht->tt && ht->signo; ht++) | ||
430 | set_except_vector(ht->tt, saved_vectors[ht->tt]); | ||
431 | local_irq_restore(flags); | ||
432 | } | ||
433 | |||
434 | /* | ||
435 | * Convert the MIPS hardware trap type code to a Unix signal number. | ||
436 | */ | ||
437 | static int computeSignal(int tt) | ||
438 | { | ||
439 | struct hard_trap_info *ht; | ||
440 | |||
441 | for (ht = hard_trap_info; ht->tt && ht->signo; ht++) | ||
442 | if (ht->tt == tt) | ||
443 | return ht->signo; | ||
444 | |||
445 | return SIGHUP; /* default for things we don't know about */ | ||
446 | } | ||
447 | |||
448 | /* | ||
449 | * While we find nice hex chars, build an int. | ||
450 | * Return number of chars processed. | ||
451 | */ | ||
452 | static int hexToInt(char **ptr, int *intValue) | ||
453 | { | ||
454 | int numChars = 0; | ||
455 | int hexValue; | ||
456 | |||
457 | *intValue = 0; | ||
458 | |||
459 | while (**ptr) { | ||
460 | hexValue = hex(**ptr); | ||
461 | if (hexValue < 0) | ||
462 | break; | ||
463 | |||
464 | *intValue = (*intValue << 4) | hexValue; | ||
465 | numChars ++; | ||
466 | |||
467 | (*ptr)++; | ||
468 | } | ||
469 | |||
470 | return (numChars); | ||
471 | } | ||
472 | |||
473 | static int hexToLong(char **ptr, long *longValue) | ||
474 | { | ||
475 | int numChars = 0; | ||
476 | int hexValue; | ||
477 | |||
478 | *longValue = 0; | ||
479 | |||
480 | while (**ptr) { | ||
481 | hexValue = hex(**ptr); | ||
482 | if (hexValue < 0) | ||
483 | break; | ||
484 | |||
485 | *longValue = (*longValue << 4) | hexValue; | ||
486 | numChars ++; | ||
487 | |||
488 | (*ptr)++; | ||
489 | } | ||
490 | |||
491 | return numChars; | ||
492 | } | ||
493 | |||
494 | |||
495 | #if 0 | ||
496 | /* | ||
497 | * Print registers (on target console) | ||
498 | * Used only to debug the stub... | ||
499 | */ | ||
500 | void show_gdbregs(struct gdb_regs * regs) | ||
501 | { | ||
502 | /* | ||
503 | * Saved main processor registers | ||
504 | */ | ||
505 | printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", | ||
506 | regs->reg0, regs->reg1, regs->reg2, regs->reg3, | ||
507 | regs->reg4, regs->reg5, regs->reg6, regs->reg7); | ||
508 | printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", | ||
509 | regs->reg8, regs->reg9, regs->reg10, regs->reg11, | ||
510 | regs->reg12, regs->reg13, regs->reg14, regs->reg15); | ||
511 | printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", | ||
512 | regs->reg16, regs->reg17, regs->reg18, regs->reg19, | ||
513 | regs->reg20, regs->reg21, regs->reg22, regs->reg23); | ||
514 | printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", | ||
515 | regs->reg24, regs->reg25, regs->reg26, regs->reg27, | ||
516 | regs->reg28, regs->reg29, regs->reg30, regs->reg31); | ||
517 | |||
518 | /* | ||
519 | * Saved cp0 registers | ||
520 | */ | ||
521 | printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n", | ||
522 | regs->cp0_epc, regs->cp0_status, regs->cp0_cause); | ||
523 | } | ||
524 | #endif /* dead code */ | ||
525 | |||
526 | /* | ||
527 | * We single-step by setting breakpoints. When an exception | ||
528 | * is handled, we need to restore the instructions hoisted | ||
529 | * when the breakpoints were set. | ||
530 | * | ||
531 | * This is where we save the original instructions. | ||
532 | */ | ||
533 | static struct gdb_bp_save { | ||
534 | unsigned long addr; | ||
535 | unsigned int val; | ||
536 | } step_bp[2]; | ||
537 | |||
538 | #define BP 0x0000000d /* break opcode */ | ||
539 | |||
540 | /* | ||
541 | * Set breakpoint instructions for single stepping. | ||
542 | */ | ||
543 | static void single_step(struct gdb_regs *regs) | ||
544 | { | ||
545 | union mips_instruction insn; | ||
546 | unsigned long targ; | ||
547 | int is_branch, is_cond, i; | ||
548 | |||
549 | targ = regs->cp0_epc; | ||
550 | insn.word = *(unsigned int *)targ; | ||
551 | is_branch = is_cond = 0; | ||
552 | |||
553 | switch (insn.i_format.opcode) { | ||
554 | /* | ||
555 | * jr and jalr are in r_format format. | ||
556 | */ | ||
557 | case spec_op: | ||
558 | switch (insn.r_format.func) { | ||
559 | case jalr_op: | ||
560 | case jr_op: | ||
561 | targ = *(®s->reg0 + insn.r_format.rs); | ||
562 | is_branch = 1; | ||
563 | break; | ||
564 | } | ||
565 | break; | ||
566 | |||
567 | /* | ||
568 | * This group contains: | ||
569 | * bltz_op, bgez_op, bltzl_op, bgezl_op, | ||
570 | * bltzal_op, bgezal_op, bltzall_op, bgezall_op. | ||
571 | */ | ||
572 | case bcond_op: | ||
573 | is_branch = is_cond = 1; | ||
574 | targ += 4 + (insn.i_format.simmediate << 2); | ||
575 | break; | ||
576 | |||
577 | /* | ||
578 | * These are unconditional and in j_format. | ||
579 | */ | ||
580 | case jal_op: | ||
581 | case j_op: | ||
582 | is_branch = 1; | ||
583 | targ += 4; | ||
584 | targ >>= 28; | ||
585 | targ <<= 28; | ||
586 | targ |= (insn.j_format.target << 2); | ||
587 | break; | ||
588 | |||
589 | /* | ||
590 | * These are conditional. | ||
591 | */ | ||
592 | case beq_op: | ||
593 | case beql_op: | ||
594 | case bne_op: | ||
595 | case bnel_op: | ||
596 | case blez_op: | ||
597 | case blezl_op: | ||
598 | case bgtz_op: | ||
599 | case bgtzl_op: | ||
600 | case cop0_op: | ||
601 | case cop1_op: | ||
602 | case cop2_op: | ||
603 | case cop1x_op: | ||
604 | is_branch = is_cond = 1; | ||
605 | targ += 4 + (insn.i_format.simmediate << 2); | ||
606 | break; | ||
607 | } | ||
608 | |||
609 | if (is_branch) { | ||
610 | i = 0; | ||
611 | if (is_cond && targ != (regs->cp0_epc + 8)) { | ||
612 | step_bp[i].addr = regs->cp0_epc + 8; | ||
613 | step_bp[i++].val = *(unsigned *)(regs->cp0_epc + 8); | ||
614 | *(unsigned *)(regs->cp0_epc + 8) = BP; | ||
615 | } | ||
616 | step_bp[i].addr = targ; | ||
617 | step_bp[i].val = *(unsigned *)targ; | ||
618 | *(unsigned *)targ = BP; | ||
619 | } else { | ||
620 | step_bp[0].addr = regs->cp0_epc + 4; | ||
621 | step_bp[0].val = *(unsigned *)(regs->cp0_epc + 4); | ||
622 | *(unsigned *)(regs->cp0_epc + 4) = BP; | ||
623 | } | ||
624 | } | ||
625 | |||
626 | /* | ||
627 | * If asynchronously interrupted by gdb, then we need to set a breakpoint | ||
628 | * at the interrupted instruction so that we wind up stopped with a | ||
629 | * reasonable stack frame. | ||
630 | */ | ||
631 | static struct gdb_bp_save async_bp; | ||
632 | |||
633 | /* | ||
634 | * Swap the interrupted EPC with our asynchronous breakpoint routine. | ||
635 | * This is safer than stuffing the breakpoint in-place, since no cache | ||
636 | * flushes (or resulting smp_call_functions) are required. The | ||
637 | * assumption is that only one CPU will be handling asynchronous bp's, | ||
638 | * and only one can be active at a time. | ||
639 | */ | ||
640 | extern spinlock_t smp_call_lock; | ||
641 | |||
642 | void set_async_breakpoint(unsigned long *epc) | ||
643 | { | ||
644 | /* skip breaking into userland */ | ||
645 | if ((*epc & 0x80000000) == 0) | ||
646 | return; | ||
647 | |||
648 | #ifdef CONFIG_SMP | ||
649 | /* avoid deadlock if someone is make IPC */ | ||
650 | if (spin_is_locked(&smp_call_lock)) | ||
651 | return; | ||
652 | #endif | ||
653 | |||
654 | async_bp.addr = *epc; | ||
655 | *epc = (unsigned long)async_breakpoint; | ||
656 | } | ||
657 | |||
658 | #ifdef CONFIG_SMP | ||
659 | static void kgdb_wait(void *arg) | ||
660 | { | ||
661 | unsigned flags; | ||
662 | int cpu = smp_processor_id(); | ||
663 | |||
664 | local_irq_save(flags); | ||
665 | |||
666 | __raw_spin_lock(&kgdb_cpulock[cpu]); | ||
667 | __raw_spin_unlock(&kgdb_cpulock[cpu]); | ||
668 | |||
669 | local_irq_restore(flags); | ||
670 | } | ||
671 | #endif | ||
672 | |||
673 | /* | ||
674 | * GDB stub needs to call kgdb_wait on all processor with interrupts | ||
675 | * disabled, so it uses it's own special variant. | ||
676 | */ | ||
677 | static int kgdb_smp_call_kgdb_wait(void) | ||
678 | { | ||
679 | #ifdef CONFIG_SMP | ||
680 | cpumask_t mask = cpu_online_map; | ||
681 | struct call_data_struct data; | ||
682 | int cpu = smp_processor_id(); | ||
683 | int cpus; | ||
684 | |||
685 | /* | ||
686 | * Can die spectacularly if this CPU isn't yet marked online | ||
687 | */ | ||
688 | BUG_ON(!cpu_online(cpu)); | ||
689 | |||
690 | cpu_clear(cpu, mask); | ||
691 | cpus = cpus_weight(mask); | ||
692 | if (!cpus) | ||
693 | return 0; | ||
694 | |||
695 | if (spin_is_locked(&smp_call_lock)) { | ||
696 | /* | ||
697 | * Some other processor is trying to make us do something | ||
698 | * but we're not going to respond... give up | ||
699 | */ | ||
700 | return -1; | ||
701 | } | ||
702 | |||
703 | /* | ||
704 | * We will continue here, accepting the fact that | ||
705 | * the kernel may deadlock if another CPU attempts | ||
706 | * to call smp_call_function now... | ||
707 | */ | ||
708 | |||
709 | data.func = kgdb_wait; | ||
710 | data.info = NULL; | ||
711 | atomic_set(&data.started, 0); | ||
712 | data.wait = 0; | ||
713 | |||
714 | spin_lock(&smp_call_lock); | ||
715 | call_data = &data; | ||
716 | mb(); | ||
717 | |||
718 | core_send_ipi_mask(mask, SMP_CALL_FUNCTION); | ||
719 | |||
720 | /* Wait for response */ | ||
721 | /* FIXME: lock-up detection, backtrace on lock-up */ | ||
722 | while (atomic_read(&data.started) != cpus) | ||
723 | barrier(); | ||
724 | |||
725 | call_data = NULL; | ||
726 | spin_unlock(&smp_call_lock); | ||
727 | #endif | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | /* | ||
733 | * This function does all command processing for interfacing to gdb. It | ||
734 | * returns 1 if you should skip the instruction at the trap address, 0 | ||
735 | * otherwise. | ||
736 | */ | ||
737 | void handle_exception(struct gdb_regs *regs) | ||
738 | { | ||
739 | int trap; /* Trap type */ | ||
740 | int sigval; | ||
741 | long addr; | ||
742 | int length; | ||
743 | char *ptr; | ||
744 | unsigned long *stack; | ||
745 | int i; | ||
746 | int bflag = 0; | ||
747 | |||
748 | kgdb_started = 1; | ||
749 | |||
750 | /* | ||
751 | * acquire the big kgdb spinlock | ||
752 | */ | ||
753 | if (!spin_trylock(&kgdb_lock)) { | ||
754 | /* | ||
755 | * some other CPU has the lock, we should go back to | ||
756 | * receive the gdb_wait IPC | ||
757 | */ | ||
758 | return; | ||
759 | } | ||
760 | |||
761 | /* | ||
762 | * If we're in async_breakpoint(), restore the real EPC from | ||
763 | * the breakpoint. | ||
764 | */ | ||
765 | if (regs->cp0_epc == (unsigned long)async_breakinst) { | ||
766 | regs->cp0_epc = async_bp.addr; | ||
767 | async_bp.addr = 0; | ||
768 | } | ||
769 | |||
770 | /* | ||
771 | * acquire the CPU spinlocks | ||
772 | */ | ||
773 | for_each_online_cpu(i) | ||
774 | if (__raw_spin_trylock(&kgdb_cpulock[i]) == 0) | ||
775 | panic("kgdb: couldn't get cpulock %d\n", i); | ||
776 | |||
777 | /* | ||
778 | * force other cpus to enter kgdb | ||
779 | */ | ||
780 | kgdb_smp_call_kgdb_wait(); | ||
781 | |||
782 | /* | ||
783 | * If we're in breakpoint() increment the PC | ||
784 | */ | ||
785 | trap = (regs->cp0_cause & 0x7c) >> 2; | ||
786 | if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst) | ||
787 | regs->cp0_epc += 4; | ||
788 | |||
789 | /* | ||
790 | * If we were single_stepping, restore the opcodes hoisted | ||
791 | * for the breakpoint[s]. | ||
792 | */ | ||
793 | if (step_bp[0].addr) { | ||
794 | *(unsigned *)step_bp[0].addr = step_bp[0].val; | ||
795 | step_bp[0].addr = 0; | ||
796 | |||
797 | if (step_bp[1].addr) { | ||
798 | *(unsigned *)step_bp[1].addr = step_bp[1].val; | ||
799 | step_bp[1].addr = 0; | ||
800 | } | ||
801 | } | ||
802 | |||
803 | stack = (long *)regs->reg29; /* stack ptr */ | ||
804 | sigval = computeSignal(trap); | ||
805 | |||
806 | /* | ||
807 | * reply to host that an exception has occurred | ||
808 | */ | ||
809 | ptr = output_buffer; | ||
810 | |||
811 | /* | ||
812 | * Send trap type (converted to signal) | ||
813 | */ | ||
814 | *ptr++ = 'T'; | ||
815 | *ptr++ = hexchars[sigval >> 4]; | ||
816 | *ptr++ = hexchars[sigval & 0xf]; | ||
817 | |||
818 | /* | ||
819 | * Send Error PC | ||
820 | */ | ||
821 | *ptr++ = hexchars[REG_EPC >> 4]; | ||
822 | *ptr++ = hexchars[REG_EPC & 0xf]; | ||
823 | *ptr++ = ':'; | ||
824 | ptr = mem2hex((char *)®s->cp0_epc, ptr, sizeof(long), 0); | ||
825 | *ptr++ = ';'; | ||
826 | |||
827 | /* | ||
828 | * Send frame pointer | ||
829 | */ | ||
830 | *ptr++ = hexchars[REG_FP >> 4]; | ||
831 | *ptr++ = hexchars[REG_FP & 0xf]; | ||
832 | *ptr++ = ':'; | ||
833 | ptr = mem2hex((char *)®s->reg30, ptr, sizeof(long), 0); | ||
834 | *ptr++ = ';'; | ||
835 | |||
836 | /* | ||
837 | * Send stack pointer | ||
838 | */ | ||
839 | *ptr++ = hexchars[REG_SP >> 4]; | ||
840 | *ptr++ = hexchars[REG_SP & 0xf]; | ||
841 | *ptr++ = ':'; | ||
842 | ptr = mem2hex((char *)®s->reg29, ptr, sizeof(long), 0); | ||
843 | *ptr++ = ';'; | ||
844 | |||
845 | *ptr++ = 0; | ||
846 | putpacket(output_buffer); /* send it off... */ | ||
847 | |||
848 | /* | ||
849 | * Wait for input from remote GDB | ||
850 | */ | ||
851 | while (1) { | ||
852 | output_buffer[0] = 0; | ||
853 | getpacket(input_buffer); | ||
854 | |||
855 | switch (input_buffer[0]) | ||
856 | { | ||
857 | case '?': | ||
858 | output_buffer[0] = 'S'; | ||
859 | output_buffer[1] = hexchars[sigval >> 4]; | ||
860 | output_buffer[2] = hexchars[sigval & 0xf]; | ||
861 | output_buffer[3] = 0; | ||
862 | break; | ||
863 | |||
864 | /* | ||
865 | * Detach debugger; let CPU run | ||
866 | */ | ||
867 | case 'D': | ||
868 | putpacket(output_buffer); | ||
869 | goto finish_kgdb; | ||
870 | break; | ||
871 | |||
872 | case 'd': | ||
873 | /* toggle debug flag */ | ||
874 | break; | ||
875 | |||
876 | /* | ||
877 | * Return the value of the CPU registers | ||
878 | */ | ||
879 | case 'g': | ||
880 | ptr = output_buffer; | ||
881 | ptr = mem2hex((char *)®s->reg0, ptr, 32*sizeof(long), 0); /* r0...r31 */ | ||
882 | ptr = mem2hex((char *)®s->cp0_status, ptr, 6*sizeof(long), 0); /* cp0 */ | ||
883 | ptr = mem2hex((char *)®s->fpr0, ptr, 32*sizeof(long), 0); /* f0...31 */ | ||
884 | ptr = mem2hex((char *)®s->cp1_fsr, ptr, 2*sizeof(long), 0); /* cp1 */ | ||
885 | ptr = mem2hex((char *)®s->frame_ptr, ptr, 2*sizeof(long), 0); /* frp */ | ||
886 | ptr = mem2hex((char *)®s->cp0_index, ptr, 16*sizeof(long), 0); /* cp0 */ | ||
887 | break; | ||
888 | |||
889 | /* | ||
890 | * set the value of the CPU registers - return OK | ||
891 | */ | ||
892 | case 'G': | ||
893 | { | ||
894 | ptr = &input_buffer[1]; | ||
895 | hex2mem(ptr, (char *)®s->reg0, 32*sizeof(long), 0, 0); | ||
896 | ptr += 32*(2*sizeof(long)); | ||
897 | hex2mem(ptr, (char *)®s->cp0_status, 6*sizeof(long), 0, 0); | ||
898 | ptr += 6*(2*sizeof(long)); | ||
899 | hex2mem(ptr, (char *)®s->fpr0, 32*sizeof(long), 0, 0); | ||
900 | ptr += 32*(2*sizeof(long)); | ||
901 | hex2mem(ptr, (char *)®s->cp1_fsr, 2*sizeof(long), 0, 0); | ||
902 | ptr += 2*(2*sizeof(long)); | ||
903 | hex2mem(ptr, (char *)®s->frame_ptr, 2*sizeof(long), 0, 0); | ||
904 | ptr += 2*(2*sizeof(long)); | ||
905 | hex2mem(ptr, (char *)®s->cp0_index, 16*sizeof(long), 0, 0); | ||
906 | strcpy(output_buffer, "OK"); | ||
907 | } | ||
908 | break; | ||
909 | |||
910 | /* | ||
911 | * mAA..AA,LLLL Read LLLL bytes at address AA..AA | ||
912 | */ | ||
913 | case 'm': | ||
914 | ptr = &input_buffer[1]; | ||
915 | |||
916 | if (hexToLong(&ptr, &addr) | ||
917 | && *ptr++ == ',' | ||
918 | && hexToInt(&ptr, &length)) { | ||
919 | if (mem2hex((char *)addr, output_buffer, length, 1)) | ||
920 | break; | ||
921 | strcpy(output_buffer, "E03"); | ||
922 | } else | ||
923 | strcpy(output_buffer, "E01"); | ||
924 | break; | ||
925 | |||
926 | /* | ||
927 | * XAA..AA,LLLL: Write LLLL escaped binary bytes at address AA.AA | ||
928 | */ | ||
929 | case 'X': | ||
930 | bflag = 1; | ||
931 | /* fall through */ | ||
932 | |||
933 | /* | ||
934 | * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK | ||
935 | */ | ||
936 | case 'M': | ||
937 | ptr = &input_buffer[1]; | ||
938 | |||
939 | if (hexToLong(&ptr, &addr) | ||
940 | && *ptr++ == ',' | ||
941 | && hexToInt(&ptr, &length) | ||
942 | && *ptr++ == ':') { | ||
943 | if (hex2mem(ptr, (char *)addr, length, bflag, 1)) | ||
944 | strcpy(output_buffer, "OK"); | ||
945 | else | ||
946 | strcpy(output_buffer, "E03"); | ||
947 | } | ||
948 | else | ||
949 | strcpy(output_buffer, "E02"); | ||
950 | break; | ||
951 | |||
952 | /* | ||
953 | * cAA..AA Continue at address AA..AA(optional) | ||
954 | */ | ||
955 | case 'c': | ||
956 | /* try to read optional parameter, pc unchanged if no parm */ | ||
957 | |||
958 | ptr = &input_buffer[1]; | ||
959 | if (hexToLong(&ptr, &addr)) | ||
960 | regs->cp0_epc = addr; | ||
961 | |||
962 | goto exit_kgdb_exception; | ||
963 | break; | ||
964 | |||
965 | /* | ||
966 | * kill the program; let us try to restart the machine | ||
967 | * Reset the whole machine. | ||
968 | */ | ||
969 | case 'k': | ||
970 | case 'r': | ||
971 | machine_restart("kgdb restarts machine"); | ||
972 | break; | ||
973 | |||
974 | /* | ||
975 | * Step to next instruction | ||
976 | */ | ||
977 | case 's': | ||
978 | /* | ||
979 | * There is no single step insn in the MIPS ISA, so we | ||
980 | * use breakpoints and continue, instead. | ||
981 | */ | ||
982 | single_step(regs); | ||
983 | goto exit_kgdb_exception; | ||
984 | /* NOTREACHED */ | ||
985 | break; | ||
986 | |||
987 | /* | ||
988 | * Set baud rate (bBB) | ||
989 | * FIXME: Needs to be written | ||
990 | */ | ||
991 | case 'b': | ||
992 | { | ||
993 | #if 0 | ||
994 | int baudrate; | ||
995 | extern void set_timer_3(); | ||
996 | |||
997 | ptr = &input_buffer[1]; | ||
998 | if (!hexToInt(&ptr, &baudrate)) | ||
999 | { | ||
1000 | strcpy(output_buffer, "B01"); | ||
1001 | break; | ||
1002 | } | ||
1003 | |||
1004 | /* Convert baud rate to uart clock divider */ | ||
1005 | |||
1006 | switch (baudrate) | ||
1007 | { | ||
1008 | case 38400: | ||
1009 | baudrate = 16; | ||
1010 | break; | ||
1011 | case 19200: | ||
1012 | baudrate = 33; | ||
1013 | break; | ||
1014 | case 9600: | ||
1015 | baudrate = 65; | ||
1016 | break; | ||
1017 | default: | ||
1018 | baudrate = 0; | ||
1019 | strcpy(output_buffer, "B02"); | ||
1020 | goto x1; | ||
1021 | } | ||
1022 | |||
1023 | if (baudrate) { | ||
1024 | putpacket("OK"); /* Ack before changing speed */ | ||
1025 | set_timer_3(baudrate); /* Set it */ | ||
1026 | } | ||
1027 | #endif | ||
1028 | } | ||
1029 | break; | ||
1030 | |||
1031 | } /* switch */ | ||
1032 | |||
1033 | /* | ||
1034 | * reply to the request | ||
1035 | */ | ||
1036 | |||
1037 | putpacket(output_buffer); | ||
1038 | |||
1039 | } /* while */ | ||
1040 | |||
1041 | return; | ||
1042 | |||
1043 | finish_kgdb: | ||
1044 | restore_debug_traps(); | ||
1045 | |||
1046 | exit_kgdb_exception: | ||
1047 | /* release locks so other CPUs can go */ | ||
1048 | for_each_online_cpu(i) | ||
1049 | __raw_spin_unlock(&kgdb_cpulock[i]); | ||
1050 | spin_unlock(&kgdb_lock); | ||
1051 | |||
1052 | __flush_cache_all(); | ||
1053 | return; | ||
1054 | } | ||
1055 | |||
1056 | /* | ||
1057 | * This function will generate a breakpoint exception. It is used at the | ||
1058 | * beginning of a program to sync up with a debugger and can be used | ||
1059 | * otherwise as a quick means to stop program execution and "break" into | ||
1060 | * the debugger. | ||
1061 | */ | ||
1062 | void breakpoint(void) | ||
1063 | { | ||
1064 | if (!initialized) | ||
1065 | return; | ||
1066 | |||
1067 | __asm__ __volatile__( | ||
1068 | ".globl breakinst\n\t" | ||
1069 | ".set\tnoreorder\n\t" | ||
1070 | "nop\n" | ||
1071 | "breakinst:\tbreak\n\t" | ||
1072 | "nop\n\t" | ||
1073 | ".set\treorder" | ||
1074 | ); | ||
1075 | } | ||
1076 | |||
1077 | /* Nothing but the break; don't pollute any registers */ | ||
1078 | void async_breakpoint(void) | ||
1079 | { | ||
1080 | __asm__ __volatile__( | ||
1081 | ".globl async_breakinst\n\t" | ||
1082 | ".set\tnoreorder\n\t" | ||
1083 | "nop\n" | ||
1084 | "async_breakinst:\tbreak\n\t" | ||
1085 | "nop\n\t" | ||
1086 | ".set\treorder" | ||
1087 | ); | ||
1088 | } | ||
1089 | |||
1090 | void adel(void) | ||
1091 | { | ||
1092 | __asm__ __volatile__( | ||
1093 | ".globl\tadel\n\t" | ||
1094 | "lui\t$8,0x8000\n\t" | ||
1095 | "lw\t$9,1($8)\n\t" | ||
1096 | ); | ||
1097 | } | ||
1098 | |||
1099 | /* | ||
1100 | * malloc is needed by gdb client in "call func()", even a private one | ||
1101 | * will make gdb happy | ||
1102 | */ | ||
1103 | static void __used *malloc(size_t size) | ||
1104 | { | ||
1105 | return kmalloc(size, GFP_ATOMIC); | ||
1106 | } | ||
1107 | |||
1108 | static void __used free(void *where) | ||
1109 | { | ||
1110 | kfree(where); | ||
1111 | } | ||
1112 | |||
1113 | #ifdef CONFIG_GDB_CONSOLE | ||
1114 | |||
1115 | void gdb_putsn(const char *str, int l) | ||
1116 | { | ||
1117 | char outbuf[18]; | ||
1118 | |||
1119 | if (!kgdb_started) | ||
1120 | return; | ||
1121 | |||
1122 | outbuf[0]='O'; | ||
1123 | |||
1124 | while(l) { | ||
1125 | int i = (l>8)?8:l; | ||
1126 | mem2hex((char *)str, &outbuf[1], i, 0); | ||
1127 | outbuf[(i*2)+1]=0; | ||
1128 | putpacket(outbuf); | ||
1129 | str += i; | ||
1130 | l -= i; | ||
1131 | } | ||
1132 | } | ||
1133 | |||
1134 | static void gdb_console_write(struct console *con, const char *s, unsigned n) | ||
1135 | { | ||
1136 | gdb_putsn(s, n); | ||
1137 | } | ||
1138 | |||
1139 | static struct console gdb_console = { | ||
1140 | .name = "gdb", | ||
1141 | .write = gdb_console_write, | ||
1142 | .flags = CON_PRINTBUFFER, | ||
1143 | .index = -1 | ||
1144 | }; | ||
1145 | |||
1146 | static int __init register_gdb_console(void) | ||
1147 | { | ||
1148 | register_console(&gdb_console); | ||
1149 | |||
1150 | return 0; | ||
1151 | } | ||
1152 | |||
1153 | console_initcall(register_gdb_console); | ||
1154 | |||
1155 | #endif | ||
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 6045b9a51a35..4b4007b3083a 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c | |||
@@ -21,11 +21,16 @@ | |||
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/kallsyms.h> | 23 | #include <linux/kallsyms.h> |
24 | #include <linux/kgdb.h> | ||
24 | 25 | ||
25 | #include <asm/atomic.h> | 26 | #include <asm/atomic.h> |
26 | #include <asm/system.h> | 27 | #include <asm/system.h> |
27 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
28 | 29 | ||
30 | #ifdef CONFIG_KGDB | ||
31 | int kgdb_early_setup; | ||
32 | #endif | ||
33 | |||
29 | static unsigned long irq_map[NR_IRQS / BITS_PER_LONG]; | 34 | static unsigned long irq_map[NR_IRQS / BITS_PER_LONG]; |
30 | 35 | ||
31 | int allocate_irqno(void) | 36 | int allocate_irqno(void) |
@@ -126,33 +131,22 @@ asmlinkage void spurious_interrupt(void) | |||
126 | atomic_inc(&irq_err_count); | 131 | atomic_inc(&irq_err_count); |
127 | } | 132 | } |
128 | 133 | ||
129 | #ifdef CONFIG_KGDB | ||
130 | extern void breakpoint(void); | ||
131 | extern void set_debug_traps(void); | ||
132 | |||
133 | static int kgdb_flag = 1; | ||
134 | static int __init nokgdb(char *str) | ||
135 | { | ||
136 | kgdb_flag = 0; | ||
137 | return 1; | ||
138 | } | ||
139 | __setup("nokgdb", nokgdb); | ||
140 | #endif | ||
141 | |||
142 | void __init init_IRQ(void) | 134 | void __init init_IRQ(void) |
143 | { | 135 | { |
144 | int i; | 136 | int i; |
145 | 137 | ||
138 | #ifdef CONFIG_KGDB | ||
139 | if (kgdb_early_setup) | ||
140 | return; | ||
141 | #endif | ||
142 | |||
146 | for (i = 0; i < NR_IRQS; i++) | 143 | for (i = 0; i < NR_IRQS; i++) |
147 | set_irq_noprobe(i); | 144 | set_irq_noprobe(i); |
148 | 145 | ||
149 | arch_init_irq(); | 146 | arch_init_irq(); |
150 | 147 | ||
151 | #ifdef CONFIG_KGDB | 148 | #ifdef CONFIG_KGDB |
152 | if (kgdb_flag) { | 149 | if (!kgdb_early_setup) |
153 | printk("Wait for gdb client connection ...\n"); | 150 | kgdb_early_setup = 1; |
154 | set_debug_traps(); | ||
155 | breakpoint(); | ||
156 | } | ||
157 | #endif | 151 | #endif |
158 | } | 152 | } |
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c new file mode 100644 index 000000000000..c5a8b2d21ca4 --- /dev/null +++ b/arch/mips/kernel/kgdb.c | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * Originally written by Glenn Engel, Lake Stevens Instrument Division | ||
3 | * | ||
4 | * Contributed by HP Systems | ||
5 | * | ||
6 | * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse | ||
7 | * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de> | ||
8 | * | ||
9 | * Copyright (C) 1995 Andreas Busse | ||
10 | * | ||
11 | * Copyright (C) 2003 MontaVista Software Inc. | ||
12 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | ||
13 | * | ||
14 | * Copyright (C) 2004-2005 MontaVista Software Inc. | ||
15 | * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com | ||
16 | * | ||
17 | * Copyright (C) 2007-2008 Wind River Systems, Inc. | ||
18 | * Author/Maintainer: Jason Wessel, jason.wessel@windriver.com | ||
19 | * | ||
20 | * This file is licensed under the terms of the GNU General Public License | ||
21 | * version 2. This program is licensed "as is" without any warranty of any | ||
22 | * kind, whether express or implied. | ||
23 | */ | ||
24 | |||
25 | #include <linux/ptrace.h> /* for linux pt_regs struct */ | ||
26 | #include <linux/kgdb.h> | ||
27 | #include <linux/kdebug.h> | ||
28 | #include <linux/sched.h> | ||
29 | #include <asm/inst.h> | ||
30 | #include <asm/fpu.h> | ||
31 | #include <asm/cacheflush.h> | ||
32 | #include <asm/processor.h> | ||
33 | #include <asm/sigcontext.h> | ||
34 | |||
35 | static struct hard_trap_info { | ||
36 | unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */ | ||
37 | unsigned char signo; /* Signal that we map this trap into */ | ||
38 | } hard_trap_info[] = { | ||
39 | { 6, SIGBUS }, /* instruction bus error */ | ||
40 | { 7, SIGBUS }, /* data bus error */ | ||
41 | { 9, SIGTRAP }, /* break */ | ||
42 | /* { 11, SIGILL }, */ /* CPU unusable */ | ||
43 | { 12, SIGFPE }, /* overflow */ | ||
44 | { 13, SIGTRAP }, /* trap */ | ||
45 | { 14, SIGSEGV }, /* virtual instruction cache coherency */ | ||
46 | { 15, SIGFPE }, /* floating point exception */ | ||
47 | { 23, SIGSEGV }, /* watch */ | ||
48 | { 31, SIGSEGV }, /* virtual data cache coherency */ | ||
49 | { 0, 0} /* Must be last */ | ||
50 | }; | ||
51 | |||
52 | void arch_kgdb_breakpoint(void) | ||
53 | { | ||
54 | __asm__ __volatile__( | ||
55 | ".globl breakinst\n\t" | ||
56 | ".set\tnoreorder\n\t" | ||
57 | "nop\n" | ||
58 | "breakinst:\tbreak\n\t" | ||
59 | "nop\n\t" | ||
60 | ".set\treorder"); | ||
61 | } | ||
62 | |||
63 | static void kgdb_call_nmi_hook(void *ignored) | ||
64 | { | ||
65 | kgdb_nmicallback(raw_smp_processor_id(), (void *)0); | ||
66 | } | ||
67 | |||
68 | void kgdb_roundup_cpus(unsigned long flags) | ||
69 | { | ||
70 | local_irq_enable(); | ||
71 | smp_call_function(kgdb_call_nmi_hook, NULL, NULL); | ||
72 | local_irq_disable(); | ||
73 | } | ||
74 | |||
75 | static int compute_signal(int tt) | ||
76 | { | ||
77 | struct hard_trap_info *ht; | ||
78 | |||
79 | for (ht = hard_trap_info; ht->tt && ht->signo; ht++) | ||
80 | if (ht->tt == tt) | ||
81 | return ht->signo; | ||
82 | |||
83 | return SIGHUP; /* default for things we don't know about */ | ||
84 | } | ||
85 | |||
86 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
87 | { | ||
88 | int reg; | ||
89 | |||
90 | #if (KGDB_GDB_REG_SIZE == 32) | ||
91 | u32 *ptr = (u32 *)gdb_regs; | ||
92 | #else | ||
93 | u64 *ptr = (u64 *)gdb_regs; | ||
94 | #endif | ||
95 | |||
96 | for (reg = 0; reg < 32; reg++) | ||
97 | *(ptr++) = regs->regs[reg]; | ||
98 | |||
99 | *(ptr++) = regs->cp0_status; | ||
100 | *(ptr++) = regs->lo; | ||
101 | *(ptr++) = regs->hi; | ||
102 | *(ptr++) = regs->cp0_badvaddr; | ||
103 | *(ptr++) = regs->cp0_cause; | ||
104 | *(ptr++) = regs->cp0_epc; | ||
105 | |||
106 | /* FP REGS */ | ||
107 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
108 | return; | ||
109 | |||
110 | save_fp(current); | ||
111 | for (reg = 0; reg < 32; reg++) | ||
112 | *(ptr++) = current->thread.fpu.fpr[reg]; | ||
113 | } | ||
114 | |||
115 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
116 | { | ||
117 | int reg; | ||
118 | |||
119 | #if (KGDB_GDB_REG_SIZE == 32) | ||
120 | const u32 *ptr = (u32 *)gdb_regs; | ||
121 | #else | ||
122 | const u64 *ptr = (u64 *)gdb_regs; | ||
123 | #endif | ||
124 | |||
125 | for (reg = 0; reg < 32; reg++) | ||
126 | regs->regs[reg] = *(ptr++); | ||
127 | |||
128 | regs->cp0_status = *(ptr++); | ||
129 | regs->lo = *(ptr++); | ||
130 | regs->hi = *(ptr++); | ||
131 | regs->cp0_badvaddr = *(ptr++); | ||
132 | regs->cp0_cause = *(ptr++); | ||
133 | regs->cp0_epc = *(ptr++); | ||
134 | |||
135 | /* FP REGS from current */ | ||
136 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
137 | return; | ||
138 | |||
139 | for (reg = 0; reg < 32; reg++) | ||
140 | current->thread.fpu.fpr[reg] = *(ptr++); | ||
141 | restore_fp(current); | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Similar to regs_to_gdb_regs() except that process is sleeping and so | ||
146 | * we may not be able to get all the info. | ||
147 | */ | ||
148 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | ||
149 | { | ||
150 | int reg; | ||
151 | struct thread_info *ti = task_thread_info(p); | ||
152 | unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32; | ||
153 | struct pt_regs *regs = (struct pt_regs *)ksp - 1; | ||
154 | #if (KGDB_GDB_REG_SIZE == 32) | ||
155 | u32 *ptr = (u32 *)gdb_regs; | ||
156 | #else | ||
157 | u64 *ptr = (u64 *)gdb_regs; | ||
158 | #endif | ||
159 | |||
160 | for (reg = 0; reg < 16; reg++) | ||
161 | *(ptr++) = regs->regs[reg]; | ||
162 | |||
163 | /* S0 - S7 */ | ||
164 | for (reg = 16; reg < 24; reg++) | ||
165 | *(ptr++) = regs->regs[reg]; | ||
166 | |||
167 | for (reg = 24; reg < 28; reg++) | ||
168 | *(ptr++) = 0; | ||
169 | |||
170 | /* GP, SP, FP, RA */ | ||
171 | for (reg = 28; reg < 32; reg++) | ||
172 | *(ptr++) = regs->regs[reg]; | ||
173 | |||
174 | *(ptr++) = regs->cp0_status; | ||
175 | *(ptr++) = regs->lo; | ||
176 | *(ptr++) = regs->hi; | ||
177 | *(ptr++) = regs->cp0_badvaddr; | ||
178 | *(ptr++) = regs->cp0_cause; | ||
179 | *(ptr++) = regs->cp0_epc; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Calls linux_debug_hook before the kernel dies. If KGDB is enabled, | ||
184 | * then try to fall into the debugger | ||
185 | */ | ||
186 | static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd, | ||
187 | void *ptr) | ||
188 | { | ||
189 | struct die_args *args = (struct die_args *)ptr; | ||
190 | struct pt_regs *regs = args->regs; | ||
191 | int trap = (regs->cp0_cause & 0x7c) >> 2; | ||
192 | |||
193 | if (fixup_exception(regs)) | ||
194 | return NOTIFY_DONE; | ||
195 | |||
196 | /* Userpace events, ignore. */ | ||
197 | if (user_mode(regs)) | ||
198 | return NOTIFY_DONE; | ||
199 | |||
200 | if (atomic_read(&kgdb_active) != -1) | ||
201 | kgdb_nmicallback(smp_processor_id(), regs); | ||
202 | |||
203 | if (kgdb_handle_exception(trap, compute_signal(trap), 0, regs)) | ||
204 | return NOTIFY_DONE; | ||
205 | |||
206 | if (atomic_read(&kgdb_setting_breakpoint)) | ||
207 | if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst)) | ||
208 | regs->cp0_epc += 4; | ||
209 | |||
210 | /* In SMP mode, __flush_cache_all does IPI */ | ||
211 | local_irq_enable(); | ||
212 | __flush_cache_all(); | ||
213 | |||
214 | return NOTIFY_STOP; | ||
215 | } | ||
216 | |||
217 | static struct notifier_block kgdb_notifier = { | ||
218 | .notifier_call = kgdb_mips_notify, | ||
219 | }; | ||
220 | |||
221 | /* | ||
222 | * Handle the 's' and 'c' commands | ||
223 | */ | ||
224 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | ||
225 | char *remcom_in_buffer, char *remcom_out_buffer, | ||
226 | struct pt_regs *regs) | ||
227 | { | ||
228 | char *ptr; | ||
229 | unsigned long address; | ||
230 | int cpu = smp_processor_id(); | ||
231 | |||
232 | switch (remcom_in_buffer[0]) { | ||
233 | case 's': | ||
234 | case 'c': | ||
235 | /* handle the optional parameter */ | ||
236 | ptr = &remcom_in_buffer[1]; | ||
237 | if (kgdb_hex2long(&ptr, &address)) | ||
238 | regs->cp0_epc = address; | ||
239 | |||
240 | atomic_set(&kgdb_cpu_doing_single_step, -1); | ||
241 | if (remcom_in_buffer[0] == 's') | ||
242 | if (kgdb_contthread) | ||
243 | atomic_set(&kgdb_cpu_doing_single_step, cpu); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | return -1; | ||
249 | } | ||
250 | |||
251 | struct kgdb_arch arch_kgdb_ops; | ||
252 | |||
253 | /* | ||
254 | * We use kgdb_early_setup so that functions we need to call now don't | ||
255 | * cause trouble when called again later. | ||
256 | */ | ||
257 | int kgdb_arch_init(void) | ||
258 | { | ||
259 | union mips_instruction insn = { | ||
260 | .r_format = { | ||
261 | .opcode = spec_op, | ||
262 | .func = break_op, | ||
263 | } | ||
264 | }; | ||
265 | memcpy(arch_kgdb_ops.gdb_bpt_instr, insn.byte, BREAK_INSTR_SIZE); | ||
266 | |||
267 | register_die_notifier(&kgdb_notifier); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * kgdb_arch_exit - Perform any architecture specific uninitalization. | ||
274 | * | ||
275 | * This function will handle the uninitalization of any architecture | ||
276 | * specific callbacks, for dynamic registration and unregistration. | ||
277 | */ | ||
278 | void kgdb_arch_exit(void) | ||
279 | { | ||
280 | unregister_die_notifier(&kgdb_notifier); | ||
281 | } | ||
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b8ea4e9d0d87..426cced1e9dc 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
26 | #include <linux/kgdb.h> | ||
27 | #include <linux/kdebug.h> | ||
26 | 28 | ||
27 | #include <asm/bootinfo.h> | 29 | #include <asm/bootinfo.h> |
28 | #include <asm/branch.h> | 30 | #include <asm/branch.h> |
@@ -425,6 +427,10 @@ asmlinkage void do_be(struct pt_regs *regs) | |||
425 | printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", | 427 | printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", |
426 | data ? "Data" : "Instruction", | 428 | data ? "Data" : "Instruction", |
427 | field, regs->cp0_epc, field, regs->regs[31]); | 429 | field, regs->cp0_epc, field, regs->regs[31]); |
430 | if (notify_die(DIE_OOPS, "bus error", regs, SIGBUS, 0, 0) | ||
431 | == NOTIFY_STOP) | ||
432 | return; | ||
433 | |||
428 | die_if_kernel("Oops", regs); | 434 | die_if_kernel("Oops", regs); |
429 | force_sig(SIGBUS, current); | 435 | force_sig(SIGBUS, current); |
430 | } | 436 | } |
@@ -623,6 +629,9 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
623 | { | 629 | { |
624 | siginfo_t info; | 630 | siginfo_t info; |
625 | 631 | ||
632 | if (notify_die(DIE_FP, "FP exception", regs, SIGFPE, 0, 0) | ||
633 | == NOTIFY_STOP) | ||
634 | return; | ||
626 | die_if_kernel("FP exception in kernel code", regs); | 635 | die_if_kernel("FP exception in kernel code", regs); |
627 | 636 | ||
628 | if (fcr31 & FPU_CSR_UNI_X) { | 637 | if (fcr31 & FPU_CSR_UNI_X) { |
@@ -682,6 +691,9 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, | |||
682 | siginfo_t info; | 691 | siginfo_t info; |
683 | char b[40]; | 692 | char b[40]; |
684 | 693 | ||
694 | if (notify_die(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP) | ||
695 | return; | ||
696 | |||
685 | /* | 697 | /* |
686 | * A short test says that IRIX 5.3 sends SIGTRAP for all trap | 698 | * A short test says that IRIX 5.3 sends SIGTRAP for all trap |
687 | * insns, even for trap and break codes that indicate arithmetic | 699 | * insns, even for trap and break codes that indicate arithmetic |
@@ -762,6 +774,10 @@ asmlinkage void do_ri(struct pt_regs *regs) | |||
762 | unsigned int opcode = 0; | 774 | unsigned int opcode = 0; |
763 | int status = -1; | 775 | int status = -1; |
764 | 776 | ||
777 | if (notify_die(DIE_RI, "RI Fault", regs, SIGSEGV, 0, 0) | ||
778 | == NOTIFY_STOP) | ||
779 | return; | ||
780 | |||
765 | die_if_kernel("Reserved instruction in kernel code", regs); | 781 | die_if_kernel("Reserved instruction in kernel code", regs); |
766 | 782 | ||
767 | if (unlikely(compute_return_epc(regs) < 0)) | 783 | if (unlikely(compute_return_epc(regs) < 0)) |
@@ -1537,6 +1553,11 @@ void __init trap_init(void) | |||
1537 | extern char except_vec4; | 1553 | extern char except_vec4; |
1538 | unsigned long i; | 1554 | unsigned long i; |
1539 | 1555 | ||
1556 | #if defined(CONFIG_KGDB) | ||
1557 | if (kgdb_early_setup) | ||
1558 | return; /* Already done */ | ||
1559 | #endif | ||
1560 | |||
1540 | if (cpu_has_veic || cpu_has_vint) | 1561 | if (cpu_has_veic || cpu_has_vint) |
1541 | ebase = (unsigned long) alloc_bootmem_low_pages(0x200 + VECTORSPACING*64); | 1562 | ebase = (unsigned long) alloc_bootmem_low_pages(0x200 + VECTORSPACING*64); |
1542 | else | 1563 | else |
diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c index a782549ac80e..f0cf46adb978 100644 --- a/arch/mips/mm/tlb-r3k.c +++ b/arch/mips/mm/tlb-r3k.c | |||
@@ -246,10 +246,6 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, | |||
246 | old_pagemask = read_c0_pagemask(); | 246 | old_pagemask = read_c0_pagemask(); |
247 | w = read_c0_wired(); | 247 | w = read_c0_wired(); |
248 | write_c0_wired(w + 1); | 248 | write_c0_wired(w + 1); |
249 | if (read_c0_wired() != w + 1) { | ||
250 | printk("[tlbwired] No WIRED reg?\n"); | ||
251 | return; | ||
252 | } | ||
253 | write_c0_index(w << 8); | 249 | write_c0_index(w << 8); |
254 | write_c0_pagemask(pagemask); | 250 | write_c0_pagemask(pagemask); |
255 | write_c0_entryhi(entryhi); | 251 | write_c0_entryhi(entryhi); |
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile index f8064446e812..3b7dd722c32a 100644 --- a/arch/mips/mti-malta/Makefile +++ b/arch/mips/mti-malta/Makefile | |||
@@ -13,7 +13,6 @@ obj-y := malta-amon.o malta-cmdline.o \ | |||
13 | 13 | ||
14 | obj-$(CONFIG_EARLY_PRINTK) += malta-console.o | 14 | obj-$(CONFIG_EARLY_PRINTK) += malta-console.o |
15 | obj-$(CONFIG_PCI) += malta-pci.o | 15 | obj-$(CONFIG_PCI) += malta-pci.o |
16 | obj-$(CONFIG_KGDB) += malta-kgdb.o | ||
17 | 16 | ||
18 | # FIXME FIXME FIXME | 17 | # FIXME FIXME FIXME |
19 | obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o | 18 | obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o |
diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index c0653021a171..4832af251668 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c | |||
@@ -37,15 +37,6 @@ | |||
37 | 37 | ||
38 | #include <asm/mips-boards/malta.h> | 38 | #include <asm/mips-boards/malta.h> |
39 | 39 | ||
40 | #ifdef CONFIG_KGDB | ||
41 | extern int rs_kgdb_hook(int, int); | ||
42 | extern int rs_putDebugChar(char); | ||
43 | extern char rs_getDebugChar(void); | ||
44 | extern int saa9730_kgdb_hook(int); | ||
45 | extern int saa9730_putDebugChar(char); | ||
46 | extern char saa9730_getDebugChar(void); | ||
47 | #endif | ||
48 | |||
49 | int prom_argc; | 40 | int prom_argc; |
50 | int *_prom_argv, *_prom_envp; | 41 | int *_prom_argv, *_prom_envp; |
51 | 42 | ||
@@ -173,51 +164,6 @@ static void __init console_config(void) | |||
173 | } | 164 | } |
174 | #endif | 165 | #endif |
175 | 166 | ||
176 | #ifdef CONFIG_KGDB | ||
177 | void __init kgdb_config(void) | ||
178 | { | ||
179 | extern int (*generic_putDebugChar)(char); | ||
180 | extern char (*generic_getDebugChar)(void); | ||
181 | char *argptr; | ||
182 | int line, speed; | ||
183 | |||
184 | argptr = prom_getcmdline(); | ||
185 | if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { | ||
186 | argptr += strlen("kgdb=ttyS"); | ||
187 | if (*argptr != '0' && *argptr != '1') | ||
188 | printk("KGDB: Unknown serial line /dev/ttyS%c, " | ||
189 | "falling back to /dev/ttyS1\n", *argptr); | ||
190 | line = *argptr == '0' ? 0 : 1; | ||
191 | printk("KGDB: Using serial line /dev/ttyS%d for session\n", line); | ||
192 | |||
193 | speed = 0; | ||
194 | if (*++argptr == ',') | ||
195 | { | ||
196 | int c; | ||
197 | while ((c = *++argptr) && ('0' <= c && c <= '9')) | ||
198 | speed = speed * 10 + c - '0'; | ||
199 | } | ||
200 | { | ||
201 | speed = rs_kgdb_hook(line, speed); | ||
202 | generic_putDebugChar = rs_putDebugChar; | ||
203 | generic_getDebugChar = rs_getDebugChar; | ||
204 | } | ||
205 | |||
206 | pr_info("KGDB: Using serial line /dev/ttyS%d at %d for " | ||
207 | "session, please connect your debugger\n", | ||
208 | line ? 1 : 0, speed); | ||
209 | |||
210 | { | ||
211 | char *s; | ||
212 | for (s = "Please connect GDB to this port\r\n"; *s; ) | ||
213 | generic_putDebugChar(*s++); | ||
214 | } | ||
215 | |||
216 | /* Breakpoint is invoked after interrupts are initialised */ | ||
217 | } | ||
218 | } | ||
219 | #endif | ||
220 | |||
221 | static void __init mips_nmi_setup(void) | 167 | static void __init mips_nmi_setup(void) |
222 | { | 168 | { |
223 | void *base; | 169 | void *base; |
diff --git a/arch/mips/mti-malta/malta-kgdb.c b/arch/mips/mti-malta/malta-kgdb.c deleted file mode 100644 index 6a1854de4579..000000000000 --- a/arch/mips/mti-malta/malta-kgdb.c +++ /dev/null | |||
@@ -1,133 +0,0 @@ | |||
1 | /* | ||
2 | * Carsten Langgaard, carstenl@mips.com | ||
3 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can distribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License (Version 2) as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
12 | * for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
17 | * | ||
18 | * This is the interface to the remote debugger stub. | ||
19 | */ | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/serial.h> | ||
22 | #include <linux/serialP.h> | ||
23 | #include <linux/serial_reg.h> | ||
24 | |||
25 | #include <asm/serial.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | static struct serial_state rs_table[] = { | ||
29 | SERIAL_PORT_DFNS /* Defined in serial.h */ | ||
30 | }; | ||
31 | |||
32 | static struct async_struct kdb_port_info = {0}; | ||
33 | |||
34 | int (*generic_putDebugChar)(char); | ||
35 | char (*generic_getDebugChar)(void); | ||
36 | |||
37 | static __inline__ unsigned int serial_in(struct async_struct *info, int offset) | ||
38 | { | ||
39 | return inb(info->port + offset); | ||
40 | } | ||
41 | |||
42 | static __inline__ void serial_out(struct async_struct *info, int offset, | ||
43 | int value) | ||
44 | { | ||
45 | outb(value, info->port+offset); | ||
46 | } | ||
47 | |||
48 | int rs_kgdb_hook(int tty_no, int speed) { | ||
49 | int t; | ||
50 | struct serial_state *ser = &rs_table[tty_no]; | ||
51 | |||
52 | kdb_port_info.state = ser; | ||
53 | kdb_port_info.magic = SERIAL_MAGIC; | ||
54 | kdb_port_info.port = ser->port; | ||
55 | kdb_port_info.flags = ser->flags; | ||
56 | |||
57 | /* | ||
58 | * Clear all interrupts | ||
59 | */ | ||
60 | serial_in(&kdb_port_info, UART_LSR); | ||
61 | serial_in(&kdb_port_info, UART_RX); | ||
62 | serial_in(&kdb_port_info, UART_IIR); | ||
63 | serial_in(&kdb_port_info, UART_MSR); | ||
64 | |||
65 | /* | ||
66 | * Now, initialize the UART | ||
67 | */ | ||
68 | serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ | ||
69 | if (kdb_port_info.flags & ASYNC_FOURPORT) { | ||
70 | kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS; | ||
71 | t = UART_MCR_DTR | UART_MCR_OUT1; | ||
72 | } else { | ||
73 | kdb_port_info.MCR | ||
74 | = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; | ||
75 | t = UART_MCR_DTR | UART_MCR_RTS; | ||
76 | } | ||
77 | |||
78 | kdb_port_info.MCR = t; /* no interrupts, please */ | ||
79 | serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR); | ||
80 | |||
81 | /* | ||
82 | * and set the speed of the serial port | ||
83 | */ | ||
84 | if (speed == 0) | ||
85 | speed = 9600; | ||
86 | |||
87 | t = kdb_port_info.state->baud_base / speed; | ||
88 | /* set DLAB */ | ||
89 | serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); | ||
90 | serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */ | ||
91 | serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */ | ||
92 | /* reset DLAB */ | ||
93 | serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); | ||
94 | |||
95 | return speed; | ||
96 | } | ||
97 | |||
98 | int putDebugChar(char c) | ||
99 | { | ||
100 | return generic_putDebugChar(c); | ||
101 | } | ||
102 | |||
103 | char getDebugChar(void) | ||
104 | { | ||
105 | return generic_getDebugChar(); | ||
106 | } | ||
107 | |||
108 | int rs_putDebugChar(char c) | ||
109 | { | ||
110 | |||
111 | if (!kdb_port_info.state) { /* need to init device first */ | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0) | ||
116 | ; | ||
117 | |||
118 | serial_out(&kdb_port_info, UART_TX, c); | ||
119 | |||
120 | return 1; | ||
121 | } | ||
122 | |||
123 | char rs_getDebugChar(void) | ||
124 | { | ||
125 | if (!kdb_port_info.state) { /* need to init device first */ | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | while (!(serial_in(&kdb_port_info, UART_LSR) & 1)) | ||
130 | ; | ||
131 | |||
132 | return serial_in(&kdb_port_info, UART_RX); | ||
133 | } | ||
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c index e7cad54936ca..dc78b8983eeb 100644 --- a/arch/mips/mti-malta/malta-setup.c +++ b/arch/mips/mti-malta/malta-setup.c | |||
@@ -199,10 +199,6 @@ void __init plat_mem_setup(void) | |||
199 | */ | 199 | */ |
200 | enable_dma(4); | 200 | enable_dma(4); |
201 | 201 | ||
202 | #ifdef CONFIG_KGDB | ||
203 | kgdb_config(); | ||
204 | #endif | ||
205 | |||
206 | #ifdef CONFIG_DMA_COHERENT | 202 | #ifdef CONFIG_DMA_COHERENT |
207 | if (mips_revision_sconid != MIPS_REVISION_SCON_BONITO) | 203 | if (mips_revision_sconid != MIPS_REVISION_SCON_BONITO) |
208 | panic("Hardware DMA cache coherency not supported"); | 204 | panic("Hardware DMA cache coherency not supported"); |
diff --git a/arch/mips/nxp/pnx8550/common/Makefile b/arch/mips/nxp/pnx8550/common/Makefile index 31cc1a5cec3b..dd9e7b1f7fd3 100644 --- a/arch/mips/nxp/pnx8550/common/Makefile +++ b/arch/mips/nxp/pnx8550/common/Makefile | |||
@@ -24,6 +24,5 @@ | |||
24 | 24 | ||
25 | obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o | 25 | obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o |
26 | obj-$(CONFIG_PCI) += pci.o | 26 | obj-$(CONFIG_PCI) += pci.o |
27 | obj-$(CONFIG_KGDB) += gdb_hook.o | ||
28 | 27 | ||
29 | EXTRA_CFLAGS += -Werror | 28 | EXTRA_CFLAGS += -Werror |
diff --git a/arch/mips/nxp/pnx8550/common/gdb_hook.c b/arch/mips/nxp/pnx8550/common/gdb_hook.c deleted file mode 100644 index ad4624f6d9bc..000000000000 --- a/arch/mips/nxp/pnx8550/common/gdb_hook.c +++ /dev/null | |||
@@ -1,109 +0,0 @@ | |||
1 | /* | ||
2 | * Carsten Langgaard, carstenl@mips.com | ||
3 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. | ||
4 | * | ||
5 | * ######################################################################## | ||
6 | * | ||
7 | * This program is free software; you can distribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License (Version 2) as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
14 | * for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
19 | * | ||
20 | * ######################################################################## | ||
21 | * | ||
22 | * This is the interface to the remote debugger stub. | ||
23 | * | ||
24 | */ | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/serial.h> | ||
27 | #include <linux/serialP.h> | ||
28 | #include <linux/serial_reg.h> | ||
29 | #include <linux/serial_ip3106.h> | ||
30 | |||
31 | #include <asm/serial.h> | ||
32 | #include <asm/io.h> | ||
33 | |||
34 | #include <uart.h> | ||
35 | |||
36 | static struct serial_state rs_table[IP3106_NR_PORTS] = { | ||
37 | }; | ||
38 | static struct async_struct kdb_port_info = {0}; | ||
39 | |||
40 | void rs_kgdb_hook(int tty_no) | ||
41 | { | ||
42 | struct serial_state *ser = &rs_table[tty_no]; | ||
43 | |||
44 | kdb_port_info.state = ser; | ||
45 | kdb_port_info.magic = SERIAL_MAGIC; | ||
46 | kdb_port_info.port = tty_no; | ||
47 | kdb_port_info.flags = ser->flags; | ||
48 | |||
49 | /* | ||
50 | * Clear all interrupts | ||
51 | */ | ||
52 | /* Clear all the transmitter FIFO counters (pointer and status) */ | ||
53 | ip3106_lcr(UART_BASE, tty_no) |= IP3106_UART_LCR_TX_RST; | ||
54 | /* Clear all the receiver FIFO counters (pointer and status) */ | ||
55 | ip3106_lcr(UART_BASE, tty_no) |= IP3106_UART_LCR_RX_RST; | ||
56 | /* Clear all interrupts */ | ||
57 | ip3106_iclr(UART_BASE, tty_no) = IP3106_UART_INT_ALLRX | | ||
58 | IP3106_UART_INT_ALLTX; | ||
59 | |||
60 | /* | ||
61 | * Now, initialize the UART | ||
62 | */ | ||
63 | ip3106_lcr(UART_BASE, tty_no) = IP3106_UART_LCR_8BIT; | ||
64 | ip3106_baud(UART_BASE, tty_no) = 5; // 38400 Baud | ||
65 | } | ||
66 | |||
67 | int putDebugChar(char c) | ||
68 | { | ||
69 | /* Wait until FIFO not full */ | ||
70 | while (((ip3106_fifo(UART_BASE, kdb_port_info.port) & IP3106_UART_FIFO_TXFIFO) >> 16) >= 16) | ||
71 | ; | ||
72 | /* Send one char */ | ||
73 | ip3106_fifo(UART_BASE, kdb_port_info.port) = c; | ||
74 | |||
75 | return 1; | ||
76 | } | ||
77 | |||
78 | char getDebugChar(void) | ||
79 | { | ||
80 | char ch; | ||
81 | |||
82 | /* Wait until there is a char in the FIFO */ | ||
83 | while (!((ip3106_fifo(UART_BASE, kdb_port_info.port) & | ||
84 | IP3106_UART_FIFO_RXFIFO) >> 8)) | ||
85 | ; | ||
86 | /* Read one char */ | ||
87 | ch = ip3106_fifo(UART_BASE, kdb_port_info.port) & | ||
88 | IP3106_UART_FIFO_RBRTHR; | ||
89 | /* Advance the RX FIFO read pointer */ | ||
90 | ip3106_lcr(UART_BASE, kdb_port_info.port) |= IP3106_UART_LCR_RX_NEXT; | ||
91 | return (ch); | ||
92 | } | ||
93 | |||
94 | void rs_disable_debug_interrupts(void) | ||
95 | { | ||
96 | ip3106_ien(UART_BASE, kdb_port_info.port) = 0; /* Disable all interrupts */ | ||
97 | } | ||
98 | |||
99 | void rs_enable_debug_interrupts(void) | ||
100 | { | ||
101 | /* Clear all the transmitter FIFO counters (pointer and status) */ | ||
102 | ip3106_lcr(UART_BASE, kdb_port_info.port) |= IP3106_UART_LCR_TX_RST; | ||
103 | /* Clear all the receiver FIFO counters (pointer and status) */ | ||
104 | ip3106_lcr(UART_BASE, kdb_port_info.port) |= IP3106_UART_LCR_RX_RST; | ||
105 | /* Clear all interrupts */ | ||
106 | ip3106_iclr(UART_BASE, kdb_port_info.port) = IP3106_UART_INT_ALLRX | | ||
107 | IP3106_UART_INT_ALLTX; | ||
108 | ip3106_ien(UART_BASE, kdb_port_info.port) = IP3106_UART_INT_ALLRX; /* Enable RX interrupts */ | ||
109 | } | ||
diff --git a/arch/mips/nxp/pnx8550/common/int.c b/arch/mips/nxp/pnx8550/common/int.c index aad03429a5e3..f080f114a1bf 100644 --- a/arch/mips/nxp/pnx8550/common/int.c +++ b/arch/mips/nxp/pnx8550/common/int.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | 35 | ||
36 | #include <asm/io.h> | 36 | #include <asm/io.h> |
37 | #include <asm/gdb-stub.h> | ||
38 | #include <int.h> | 37 | #include <int.h> |
39 | #include <uart.h> | 38 | #include <uart.h> |
40 | 39 | ||
diff --git a/arch/mips/nxp/pnx8550/common/proc.c b/arch/mips/nxp/pnx8550/common/proc.c index 18b125e3b65d..acf1fa889444 100644 --- a/arch/mips/nxp/pnx8550/common/proc.c +++ b/arch/mips/nxp/pnx8550/common/proc.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/random.h> | 22 | #include <linux/random.h> |
23 | 23 | ||
24 | #include <asm/io.h> | 24 | #include <asm/io.h> |
25 | #include <asm/gdb-stub.h> | ||
26 | #include <int.h> | 25 | #include <int.h> |
27 | #include <uart.h> | 26 | #include <uart.h> |
28 | 27 | ||
diff --git a/arch/mips/nxp/pnx8550/common/setup.c b/arch/mips/nxp/pnx8550/common/setup.c index 92d764c97701..2aed50fef10f 100644 --- a/arch/mips/nxp/pnx8550/common/setup.c +++ b/arch/mips/nxp/pnx8550/common/setup.c | |||
@@ -47,7 +47,6 @@ extern void pnx8550_machine_halt(void); | |||
47 | extern void pnx8550_machine_power_off(void); | 47 | extern void pnx8550_machine_power_off(void); |
48 | extern struct resource ioport_resource; | 48 | extern struct resource ioport_resource; |
49 | extern struct resource iomem_resource; | 49 | extern struct resource iomem_resource; |
50 | extern void rs_kgdb_hook(int tty_no); | ||
51 | extern char *prom_getcmdline(void); | 50 | extern char *prom_getcmdline(void); |
52 | 51 | ||
53 | struct resource standard_io_resources[] = { | 52 | struct resource standard_io_resources[] = { |
@@ -142,16 +141,5 @@ void __init plat_mem_setup(void) | |||
142 | ip3106_baud(UART_BASE, pnx8550_console_port) = 5; | 141 | ip3106_baud(UART_BASE, pnx8550_console_port) = 5; |
143 | } | 142 | } |
144 | 143 | ||
145 | #ifdef CONFIG_KGDB | ||
146 | argptr = prom_getcmdline(); | ||
147 | if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { | ||
148 | int line; | ||
149 | argptr += strlen("kgdb=ttyS"); | ||
150 | line = *argptr == '0' ? 0 : 1; | ||
151 | rs_kgdb_hook(line); | ||
152 | pr_info("KGDB: Using ttyS%i for session, " | ||
153 | "please connect your debugger\n", line ? 1 : 0); | ||
154 | } | ||
155 | #endif | ||
156 | return; | 144 | return; |
157 | } | 145 | } |
diff --git a/arch/mips/pci/ops-tx3927.c b/arch/mips/pci/ops-tx3927.c index 8a17a39e5bf2..31c150196595 100644 --- a/arch/mips/pci/ops-tx3927.c +++ b/arch/mips/pci/ops-tx3927.c | |||
@@ -37,45 +37,48 @@ | |||
37 | #include <linux/pci.h> | 37 | #include <linux/pci.h> |
38 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/interrupt.h> | ||
40 | 41 | ||
41 | #include <asm/addrspace.h> | 42 | #include <asm/addrspace.h> |
43 | #include <asm/txx9irq.h> | ||
44 | #include <asm/txx9/pci.h> | ||
42 | #include <asm/txx9/tx3927.h> | 45 | #include <asm/txx9/tx3927.h> |
43 | 46 | ||
44 | static inline int mkaddr(unsigned char bus, unsigned char dev_fn, | 47 | static int mkaddr(struct pci_bus *bus, unsigned char devfn, unsigned char where) |
45 | unsigned char where) | ||
46 | { | 48 | { |
47 | if (bus == 0 && dev_fn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0)) | 49 | if (bus->parent == NULL && |
48 | return PCIBIOS_DEVICE_NOT_FOUND; | 50 | devfn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0)) |
49 | 51 | return -1; | |
50 | tx3927_pcicptr->ica = ((bus & 0xff) << 0x10) | | 52 | tx3927_pcicptr->ica = |
51 | ((dev_fn & 0xff) << 0x08) | | 53 | ((bus->number & 0xff) << 0x10) | |
52 | (where & 0xfc); | 54 | ((devfn & 0xff) << 0x08) | |
55 | (where & 0xfc) | (bus->parent ? 1 : 0); | ||
53 | 56 | ||
54 | /* clear M_ABORT and Disable M_ABORT Int. */ | 57 | /* clear M_ABORT and Disable M_ABORT Int. */ |
55 | tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; | 58 | tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; |
56 | tx3927_pcicptr->pcistatim &= ~PCI_STATUS_REC_MASTER_ABORT; | 59 | tx3927_pcicptr->pcistatim &= ~PCI_STATUS_REC_MASTER_ABORT; |
57 | 60 | return 0; | |
58 | return PCIBIOS_SUCCESSFUL; | ||
59 | } | 61 | } |
60 | 62 | ||
61 | static inline int check_abort(void) | 63 | static inline int check_abort(void) |
62 | { | 64 | { |
63 | if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT) | 65 | if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT) { |
64 | tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; | 66 | tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; |
65 | tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT; | 67 | tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT; |
68 | /* flush write buffer */ | ||
69 | iob(); | ||
66 | return PCIBIOS_DEVICE_NOT_FOUND; | 70 | return PCIBIOS_DEVICE_NOT_FOUND; |
67 | 71 | } | |
68 | return PCIBIOS_SUCCESSFUL; | 72 | return PCIBIOS_SUCCESSFUL; |
69 | } | 73 | } |
70 | 74 | ||
71 | static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn, | 75 | static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn, |
72 | int where, int size, u32 * val) | 76 | int where, int size, u32 * val) |
73 | { | 77 | { |
74 | int ret; | 78 | if (mkaddr(bus, devfn, where)) { |
75 | 79 | *val = 0xffffffff; | |
76 | ret = mkaddr(bus->number, devfn, where); | 80 | return PCIBIOS_DEVICE_NOT_FOUND; |
77 | if (ret) | 81 | } |
78 | return ret; | ||
79 | 82 | ||
80 | switch (size) { | 83 | switch (size) { |
81 | case 1: | 84 | case 1: |
@@ -97,11 +100,8 @@ static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn, | |||
97 | static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn, | 100 | static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn, |
98 | int where, int size, u32 val) | 101 | int where, int size, u32 val) |
99 | { | 102 | { |
100 | int ret; | 103 | if (mkaddr(bus, devfn, where)) |
101 | 104 | return PCIBIOS_DEVICE_NOT_FOUND; | |
102 | ret = mkaddr(bus->number, devfn, where); | ||
103 | if (ret) | ||
104 | return ret; | ||
105 | 105 | ||
106 | switch (size) { | 106 | switch (size) { |
107 | case 1: | 107 | case 1: |
@@ -117,11 +117,6 @@ static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn, | |||
117 | tx3927_pcicptr->icd = cpu_to_le32(val); | 117 | tx3927_pcicptr->icd = cpu_to_le32(val); |
118 | } | 118 | } |
119 | 119 | ||
120 | if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT) | ||
121 | tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; | ||
122 | tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT; | ||
123 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
124 | |||
125 | return check_abort(); | 120 | return check_abort(); |
126 | } | 121 | } |
127 | 122 | ||
@@ -202,3 +197,34 @@ void __init tx3927_pcic_setup(struct pci_controller *channel, | |||
202 | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; | 197 | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; |
203 | local_irq_restore(flags); | 198 | local_irq_restore(flags); |
204 | } | 199 | } |
200 | |||
201 | static irqreturn_t tx3927_pcierr_interrupt(int irq, void *dev_id) | ||
202 | { | ||
203 | struct pt_regs *regs = get_irq_regs(); | ||
204 | |||
205 | if (txx9_pci_err_action != TXX9_PCI_ERR_IGNORE) { | ||
206 | printk(KERN_WARNING "PCI error interrupt at 0x%08lx.\n", | ||
207 | regs->cp0_epc); | ||
208 | printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n", | ||
209 | tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat); | ||
210 | } | ||
211 | if (txx9_pci_err_action != TXX9_PCI_ERR_PANIC) { | ||
212 | /* clear all pci errors */ | ||
213 | tx3927_pcicptr->pcistat |= TX3927_PCIC_PCISTATIM_ALL; | ||
214 | tx3927_pcicptr->istat = TX3927_PCIC_IIM_ALL; | ||
215 | tx3927_pcicptr->tstat = TX3927_PCIC_TIM_ALL; | ||
216 | tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL; | ||
217 | return IRQ_HANDLED; | ||
218 | } | ||
219 | console_verbose(); | ||
220 | panic("PCI error."); | ||
221 | } | ||
222 | |||
223 | void __init tx3927_setup_pcierr_irq(void) | ||
224 | { | ||
225 | if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI, | ||
226 | tx3927_pcierr_interrupt, | ||
227 | IRQF_DISABLED, "PCI error", | ||
228 | (void *)TX3927_PCIC_REG)) | ||
229 | printk(KERN_WARNING "Failed to request irq for PCIERR\n"); | ||
230 | } | ||
diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c index c6b49bccd274..5989e747527f 100644 --- a/arch/mips/pci/ops-tx4927.c +++ b/arch/mips/pci/ops-tx4927.c | |||
@@ -16,6 +16,8 @@ | |||
16 | * option) any later version. | 16 | * option) any later version. |
17 | */ | 17 | */ |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/interrupt.h> | ||
20 | #include <asm/txx9/pci.h> | ||
19 | #include <asm/txx9/tx4927pcic.h> | 21 | #include <asm/txx9/tx4927pcic.h> |
20 | 22 | ||
21 | static struct { | 23 | static struct { |
@@ -85,6 +87,8 @@ static int check_abort(struct tx4927_pcic_reg __iomem *pcicptr) | |||
85 | __raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff) | 87 | __raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff) |
86 | | (PCI_STATUS_REC_MASTER_ABORT << 16), | 88 | | (PCI_STATUS_REC_MASTER_ABORT << 16), |
87 | &pcicptr->pcistatus); | 89 | &pcicptr->pcistatus); |
90 | /* flush write buffer */ | ||
91 | iob(); | ||
88 | code = PCIBIOS_DEVICE_NOT_FOUND; | 92 | code = PCIBIOS_DEVICE_NOT_FOUND; |
89 | } | 93 | } |
90 | return code; | 94 | return code; |
@@ -192,6 +196,28 @@ static struct { | |||
192 | .gbwc = 0xfe0, /* 4064 GBUSCLK for CCFG.GTOT=0b11 */ | 196 | .gbwc = 0xfe0, /* 4064 GBUSCLK for CCFG.GTOT=0b11 */ |
193 | }; | 197 | }; |
194 | 198 | ||
199 | char *__devinit tx4927_pcibios_setup(char *str) | ||
200 | { | ||
201 | unsigned long val; | ||
202 | |||
203 | if (!strncmp(str, "trdyto=", 7)) { | ||
204 | if (strict_strtoul(str + 7, 0, &val) == 0) | ||
205 | tx4927_pci_opts.trdyto = val; | ||
206 | return NULL; | ||
207 | } | ||
208 | if (!strncmp(str, "retryto=", 8)) { | ||
209 | if (strict_strtoul(str + 8, 0, &val) == 0) | ||
210 | tx4927_pci_opts.retryto = val; | ||
211 | return NULL; | ||
212 | } | ||
213 | if (!strncmp(str, "gbwc=", 5)) { | ||
214 | if (strict_strtoul(str + 5, 0, &val) == 0) | ||
215 | tx4927_pci_opts.gbwc = val; | ||
216 | return NULL; | ||
217 | } | ||
218 | return str; | ||
219 | } | ||
220 | |||
195 | void __init tx4927_pcic_setup(struct tx4927_pcic_reg __iomem *pcicptr, | 221 | void __init tx4927_pcic_setup(struct tx4927_pcic_reg __iomem *pcicptr, |
196 | struct pci_controller *channel, int extarb) | 222 | struct pci_controller *channel, int extarb) |
197 | { | 223 | { |
@@ -406,3 +432,95 @@ void tx4927_report_pcic_status(void) | |||
406 | tx4927_report_pcic_status1(pcicptrs[i].pcicptr); | 432 | tx4927_report_pcic_status1(pcicptrs[i].pcicptr); |
407 | } | 433 | } |
408 | } | 434 | } |
435 | |||
436 | static void tx4927_dump_pcic_settings1(struct tx4927_pcic_reg __iomem *pcicptr) | ||
437 | { | ||
438 | int i; | ||
439 | __u32 __iomem *preg = (__u32 __iomem *)pcicptr; | ||
440 | |||
441 | printk(KERN_INFO "tx4927 pcic (0x%p) settings:", pcicptr); | ||
442 | for (i = 0; i < sizeof(struct tx4927_pcic_reg); i += 4, preg++) { | ||
443 | if (i % 32 == 0) { | ||
444 | printk(KERN_CONT "\n"); | ||
445 | printk(KERN_INFO "%04x:", i); | ||
446 | } | ||
447 | /* skip registers with side-effects */ | ||
448 | if (i == offsetof(struct tx4927_pcic_reg, g2pintack) | ||
449 | || i == offsetof(struct tx4927_pcic_reg, g2pspc) | ||
450 | || i == offsetof(struct tx4927_pcic_reg, g2pcfgadrs) | ||
451 | || i == offsetof(struct tx4927_pcic_reg, g2pcfgdata)) { | ||
452 | printk(KERN_CONT " XXXXXXXX"); | ||
453 | continue; | ||
454 | } | ||
455 | printk(KERN_CONT " %08x", __raw_readl(preg)); | ||
456 | } | ||
457 | printk(KERN_CONT "\n"); | ||
458 | } | ||
459 | |||
460 | void tx4927_dump_pcic_settings(void) | ||
461 | { | ||
462 | int i; | ||
463 | |||
464 | for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) { | ||
465 | if (pcicptrs[i].pcicptr) | ||
466 | tx4927_dump_pcic_settings1(pcicptrs[i].pcicptr); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | irqreturn_t tx4927_pcierr_interrupt(int irq, void *dev_id) | ||
471 | { | ||
472 | struct pt_regs *regs = get_irq_regs(); | ||
473 | struct tx4927_pcic_reg __iomem *pcicptr = | ||
474 | (struct tx4927_pcic_reg __iomem *)(unsigned long)dev_id; | ||
475 | |||
476 | if (txx9_pci_err_action != TXX9_PCI_ERR_IGNORE) { | ||
477 | printk(KERN_WARNING "PCIERR interrupt at 0x%0*lx\n", | ||
478 | (int)(2 * sizeof(unsigned long)), regs->cp0_epc); | ||
479 | tx4927_report_pcic_status1(pcicptr); | ||
480 | } | ||
481 | if (txx9_pci_err_action != TXX9_PCI_ERR_PANIC) { | ||
482 | /* clear all pci errors */ | ||
483 | __raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff) | ||
484 | | (TX4927_PCIC_PCISTATUS_ALL << 16), | ||
485 | &pcicptr->pcistatus); | ||
486 | __raw_writel(TX4927_PCIC_G2PSTATUS_ALL, &pcicptr->g2pstatus); | ||
487 | __raw_writel(TX4927_PCIC_PBASTATUS_ALL, &pcicptr->pbastatus); | ||
488 | __raw_writel(TX4927_PCIC_PCICSTATUS_ALL, &pcicptr->pcicstatus); | ||
489 | return IRQ_HANDLED; | ||
490 | } | ||
491 | console_verbose(); | ||
492 | tx4927_dump_pcic_settings1(pcicptr); | ||
493 | panic("PCI error."); | ||
494 | } | ||
495 | |||
496 | #ifdef CONFIG_TOSHIBA_FPCIB0 | ||
497 | static void __init tx4927_quirk_slc90e66_bridge(struct pci_dev *dev) | ||
498 | { | ||
499 | struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(dev->bus); | ||
500 | |||
501 | if (!pcicptr) | ||
502 | return; | ||
503 | if (__raw_readl(&pcicptr->pbacfg) & TX4927_PCIC_PBACFG_PBAEN) { | ||
504 | /* Reset Bus Arbiter */ | ||
505 | __raw_writel(TX4927_PCIC_PBACFG_RPBA, &pcicptr->pbacfg); | ||
506 | /* | ||
507 | * swap reqBP and reqXP (raise priority of SLC90E66). | ||
508 | * SLC90E66(PCI-ISA bridge) is connected to REQ2 on | ||
509 | * PCI Backplane board. | ||
510 | */ | ||
511 | __raw_writel(0x72543610, &pcicptr->pbareqport); | ||
512 | __raw_writel(0, &pcicptr->pbabm); | ||
513 | /* Use Fixed ParkMaster (required by SLC90E66) */ | ||
514 | __raw_writel(TX4927_PCIC_PBACFG_FIXPA, &pcicptr->pbacfg); | ||
515 | /* Enable Bus Arbiter */ | ||
516 | __raw_writel(TX4927_PCIC_PBACFG_FIXPA | | ||
517 | TX4927_PCIC_PBACFG_PBAEN, | ||
518 | &pcicptr->pbacfg); | ||
519 | printk(KERN_INFO "PCI: Use Fixed Park Master (REQPORT %08x)\n", | ||
520 | __raw_readl(&pcicptr->pbareqport)); | ||
521 | } | ||
522 | } | ||
523 | #define PCI_DEVICE_ID_EFAR_SLC90E66_0 0x9460 | ||
524 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_0, | ||
525 | tx4927_quirk_slc90e66_bridge); | ||
526 | #endif | ||
diff --git a/arch/mips/pci/pci-tx4927.c b/arch/mips/pci/pci-tx4927.c index 27e86a09dd41..aaa900596792 100644 --- a/arch/mips/pci/pci-tx4927.c +++ b/arch/mips/pci/pci-tx4927.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/pci.h> | 16 | #include <linux/pci.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/interrupt.h> | ||
18 | #include <asm/txx9/generic.h> | 19 | #include <asm/txx9/generic.h> |
19 | #include <asm/txx9/tx4927.h> | 20 | #include <asm/txx9/tx4927.h> |
20 | 21 | ||
@@ -81,3 +82,12 @@ int __init tx4927_pciclk66_setup(void) | |||
81 | pciclk = -1; | 82 | pciclk = -1; |
82 | return pciclk; | 83 | return pciclk; |
83 | } | 84 | } |
85 | |||
86 | void __init tx4927_setup_pcierr_irq(void) | ||
87 | { | ||
88 | if (request_irq(TXX9_IRQ_BASE + TX4927_IR_PCIERR, | ||
89 | tx4927_pcierr_interrupt, | ||
90 | IRQF_DISABLED, "PCI error", | ||
91 | (void *)TX4927_PCIC_REG)) | ||
92 | printk(KERN_WARNING "Failed to request irq for PCIERR\n"); | ||
93 | } | ||
diff --git a/arch/mips/pci/pci-tx4938.c b/arch/mips/pci/pci-tx4938.c index e5375511c2b7..60e2c52c2c5e 100644 --- a/arch/mips/pci/pci-tx4938.c +++ b/arch/mips/pci/pci-tx4938.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/pci.h> | 16 | #include <linux/pci.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/interrupt.h> | ||
18 | #include <asm/txx9/generic.h> | 19 | #include <asm/txx9/generic.h> |
19 | #include <asm/txx9/tx4938.h> | 20 | #include <asm/txx9/tx4938.h> |
20 | 21 | ||
@@ -132,3 +133,12 @@ int tx4938_pcic1_map_irq(const struct pci_dev *dev, u8 slot) | |||
132 | } | 133 | } |
133 | return -1; | 134 | return -1; |
134 | } | 135 | } |
136 | |||
137 | void __init tx4938_setup_pcierr_irq(void) | ||
138 | { | ||
139 | if (request_irq(TXX9_IRQ_BASE + TX4938_IR_PCIERR, | ||
140 | tx4927_pcierr_interrupt, | ||
141 | IRQF_DISABLED, "PCI error", | ||
142 | (void *)TX4927_PCIC_REG)) | ||
143 | printk(KERN_WARNING "Failed to request irq for PCIERR\n"); | ||
144 | } | ||
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index 77bd5b68dc43..c7fe6ec621e6 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c | |||
@@ -328,7 +328,11 @@ EXPORT_SYMBOL(PCIBIOS_MIN_IO); | |||
328 | EXPORT_SYMBOL(PCIBIOS_MIN_MEM); | 328 | EXPORT_SYMBOL(PCIBIOS_MIN_MEM); |
329 | #endif | 329 | #endif |
330 | 330 | ||
331 | char *pcibios_setup(char *str) | 331 | char * (*pcibios_plat_setup)(char *str) __devinitdata; |
332 | |||
333 | char *__devinit pcibios_setup(char *str) | ||
332 | { | 334 | { |
335 | if (pcibios_plat_setup) | ||
336 | return pcibios_plat_setup(str); | ||
333 | return str; | 337 | return str; |
334 | } | 338 | } |
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_serial.c b/arch/mips/pmc-sierra/msp71xx/msp_serial.c index 9de34302e5f4..f7261628d8a6 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_serial.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_serial.c | |||
@@ -38,68 +38,6 @@ | |||
38 | #include <msp_int.h> | 38 | #include <msp_int.h> |
39 | #include <msp_regs.h> | 39 | #include <msp_regs.h> |
40 | 40 | ||
41 | #ifdef CONFIG_KGDB | ||
42 | /* | ||
43 | * kgdb uses serial port 1 so the console can remain on port 0. | ||
44 | * To use port 0 change the definition to read as follows: | ||
45 | * #define DEBUG_PORT_BASE KSEG1ADDR(MSP_UART0_BASE) | ||
46 | */ | ||
47 | #define DEBUG_PORT_BASE KSEG1ADDR(MSP_UART1_BASE) | ||
48 | |||
49 | int putDebugChar(char c) | ||
50 | { | ||
51 | volatile uint32_t *uart = (volatile uint32_t *)DEBUG_PORT_BASE; | ||
52 | uint32_t val = (uint32_t)c; | ||
53 | |||
54 | local_irq_disable(); | ||
55 | while( !(uart[5] & 0x20) ); /* Wait for TXRDY */ | ||
56 | uart[0] = val; | ||
57 | while( !(uart[5] & 0x20) ); /* Wait for TXRDY */ | ||
58 | local_irq_enable(); | ||
59 | |||
60 | return 1; | ||
61 | } | ||
62 | |||
63 | char getDebugChar(void) | ||
64 | { | ||
65 | volatile uint32_t *uart = (volatile uint32_t *)DEBUG_PORT_BASE; | ||
66 | uint32_t val; | ||
67 | |||
68 | while( !(uart[5] & 0x01) ); /* Wait for RXRDY */ | ||
69 | val = uart[0]; | ||
70 | |||
71 | return (char)val; | ||
72 | } | ||
73 | |||
74 | void initDebugPort(unsigned int uartclk, unsigned int baudrate) | ||
75 | { | ||
76 | unsigned int baud_divisor = (uartclk + 8 * baudrate)/(16 * baudrate); | ||
77 | |||
78 | /* Enable FIFOs */ | ||
79 | writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | | ||
80 | UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_4, | ||
81 | (char *)DEBUG_PORT_BASE + (UART_FCR * 4)); | ||
82 | |||
83 | /* Select brtc divisor */ | ||
84 | writeb(UART_LCR_DLAB, (char *)DEBUG_PORT_BASE + (UART_LCR * 4)); | ||
85 | |||
86 | /* Store divisor lsb */ | ||
87 | writeb(baud_divisor, (char *)DEBUG_PORT_BASE + (UART_TX * 4)); | ||
88 | |||
89 | /* Store divisor msb */ | ||
90 | writeb(baud_divisor >> 8, (char *)DEBUG_PORT_BASE + (UART_IER * 4)); | ||
91 | |||
92 | /* Set 8N1 mode */ | ||
93 | writeb(UART_LCR_WLEN8, (char *)DEBUG_PORT_BASE + (UART_LCR * 4)); | ||
94 | |||
95 | /* Disable flow control */ | ||
96 | writeb(0, (char *)DEBUG_PORT_BASE + (UART_MCR * 4)); | ||
97 | |||
98 | /* Disable receive interrupt(!) */ | ||
99 | writeb(0, (char *)DEBUG_PORT_BASE + (UART_IER * 4)); | ||
100 | } | ||
101 | #endif | ||
102 | |||
103 | void __init msp_serial_setup(void) | 41 | void __init msp_serial_setup(void) |
104 | { | 42 | { |
105 | char *s; | 43 | char *s; |
@@ -139,17 +77,6 @@ void __init msp_serial_setup(void) | |||
139 | case MACH_MSP7120_FPGA: | 77 | case MACH_MSP7120_FPGA: |
140 | /* Enable UART1 on MSP4200 and MSP7120 */ | 78 | /* Enable UART1 on MSP4200 and MSP7120 */ |
141 | *GPIO_CFG2_REG = 0x00002299; | 79 | *GPIO_CFG2_REG = 0x00002299; |
142 | |||
143 | #ifdef CONFIG_KGDB | ||
144 | /* Initialize UART1 for kgdb since PMON doesn't */ | ||
145 | if( DEBUG_PORT_BASE == KSEG1ADDR(MSP_UART1_BASE) ) { | ||
146 | if( mips_machtype == MACH_MSP4200_FPGA | ||
147 | || mips_machtype == MACH_MSP7120_FPGA ) | ||
148 | initDebugPort(uartclk, 19200); | ||
149 | else | ||
150 | initDebugPort(uartclk, 57600); | ||
151 | } | ||
152 | #endif | ||
153 | break; | 80 | break; |
154 | 81 | ||
155 | default: | 82 | default: |
diff --git a/arch/mips/pmc-sierra/yosemite/Makefile b/arch/mips/pmc-sierra/yosemite/Makefile index 8fd9a04e3534..b16f95c3df65 100644 --- a/arch/mips/pmc-sierra/yosemite/Makefile +++ b/arch/mips/pmc-sierra/yosemite/Makefile | |||
@@ -4,7 +4,6 @@ | |||
4 | 4 | ||
5 | obj-y += irq.o prom.o py-console.o setup.o | 5 | obj-y += irq.o prom.o py-console.o setup.o |
6 | 6 | ||
7 | obj-$(CONFIG_KGDB) += dbg_io.o | ||
8 | obj-$(CONFIG_SMP) += smp.o | 7 | obj-$(CONFIG_SMP) += smp.o |
9 | 8 | ||
10 | EXTRA_CFLAGS += -Werror | 9 | EXTRA_CFLAGS += -Werror |
diff --git a/arch/mips/pmc-sierra/yosemite/dbg_io.c b/arch/mips/pmc-sierra/yosemite/dbg_io.c deleted file mode 100644 index 6362c702e389..000000000000 --- a/arch/mips/pmc-sierra/yosemite/dbg_io.c +++ /dev/null | |||
@@ -1,180 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2003 PMC-Sierra | ||
3 | * Author: Manish Lachwani (lachwani@pmc-sierra.com) | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
11 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
12 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
13 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
14 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
15 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
16 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
17 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
18 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
19 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License along | ||
22 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
23 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * Support for KGDB for the Yosemite board. We make use of single serial | ||
28 | * port to be used for KGDB as well as console. The second serial port | ||
29 | * seems to be having a problem. Single IRQ is allocated for both the | ||
30 | * ports. Hence, the interrupt routing code needs to figure out whether | ||
31 | * the interrupt came from channel A or B. | ||
32 | */ | ||
33 | |||
34 | #include <asm/serial.h> | ||
35 | |||
36 | /* | ||
37 | * Baud rate, Parity, Data and Stop bit settings for the | ||
38 | * serial port on the Yosemite. Note that the Early printk | ||
39 | * patch has been added. So, we should be all set to go | ||
40 | */ | ||
41 | #define YOSEMITE_BAUD_2400 2400 | ||
42 | #define YOSEMITE_BAUD_4800 4800 | ||
43 | #define YOSEMITE_BAUD_9600 9600 | ||
44 | #define YOSEMITE_BAUD_19200 19200 | ||
45 | #define YOSEMITE_BAUD_38400 38400 | ||
46 | #define YOSEMITE_BAUD_57600 57600 | ||
47 | #define YOSEMITE_BAUD_115200 115200 | ||
48 | |||
49 | #define YOSEMITE_PARITY_NONE 0 | ||
50 | #define YOSEMITE_PARITY_ODD 0x08 | ||
51 | #define YOSEMITE_PARITY_EVEN 0x18 | ||
52 | #define YOSEMITE_PARITY_MARK 0x28 | ||
53 | #define YOSEMITE_PARITY_SPACE 0x38 | ||
54 | |||
55 | #define YOSEMITE_DATA_5BIT 0x0 | ||
56 | #define YOSEMITE_DATA_6BIT 0x1 | ||
57 | #define YOSEMITE_DATA_7BIT 0x2 | ||
58 | #define YOSEMITE_DATA_8BIT 0x3 | ||
59 | |||
60 | #define YOSEMITE_STOP_1BIT 0x0 | ||
61 | #define YOSEMITE_STOP_2BIT 0x4 | ||
62 | |||
63 | /* This is crucial */ | ||
64 | #define SERIAL_REG_OFS 0x1 | ||
65 | |||
66 | #define SERIAL_RCV_BUFFER 0x0 | ||
67 | #define SERIAL_TRANS_HOLD 0x0 | ||
68 | #define SERIAL_SEND_BUFFER 0x0 | ||
69 | #define SERIAL_INTR_ENABLE (1 * SERIAL_REG_OFS) | ||
70 | #define SERIAL_INTR_ID (2 * SERIAL_REG_OFS) | ||
71 | #define SERIAL_DATA_FORMAT (3 * SERIAL_REG_OFS) | ||
72 | #define SERIAL_LINE_CONTROL (3 * SERIAL_REG_OFS) | ||
73 | #define SERIAL_MODEM_CONTROL (4 * SERIAL_REG_OFS) | ||
74 | #define SERIAL_RS232_OUTPUT (4 * SERIAL_REG_OFS) | ||
75 | #define SERIAL_LINE_STATUS (5 * SERIAL_REG_OFS) | ||
76 | #define SERIAL_MODEM_STATUS (6 * SERIAL_REG_OFS) | ||
77 | #define SERIAL_RS232_INPUT (6 * SERIAL_REG_OFS) | ||
78 | #define SERIAL_SCRATCH_PAD (7 * SERIAL_REG_OFS) | ||
79 | |||
80 | #define SERIAL_DIVISOR_LSB (0 * SERIAL_REG_OFS) | ||
81 | #define SERIAL_DIVISOR_MSB (1 * SERIAL_REG_OFS) | ||
82 | |||
83 | /* | ||
84 | * Functions to READ and WRITE to serial port 0 | ||
85 | */ | ||
86 | #define SERIAL_READ(ofs) (*((volatile unsigned char*) \ | ||
87 | (TITAN_SERIAL_BASE + ofs))) | ||
88 | |||
89 | #define SERIAL_WRITE(ofs, val) ((*((volatile unsigned char*) \ | ||
90 | (TITAN_SERIAL_BASE + ofs))) = val) | ||
91 | |||
92 | /* | ||
93 | * Functions to READ and WRITE to serial port 1 | ||
94 | */ | ||
95 | #define SERIAL_READ_1(ofs) (*((volatile unsigned char*) \ | ||
96 | (TITAN_SERIAL_BASE_1 + ofs))) | ||
97 | |||
98 | #define SERIAL_WRITE_1(ofs, val) ((*((volatile unsigned char*) \ | ||
99 | (TITAN_SERIAL_BASE_1 + ofs))) = val) | ||
100 | |||
101 | /* | ||
102 | * Second serial port initialization | ||
103 | */ | ||
104 | void init_second_port(void) | ||
105 | { | ||
106 | /* Disable Interrupts */ | ||
107 | SERIAL_WRITE_1(SERIAL_LINE_CONTROL, 0x0); | ||
108 | SERIAL_WRITE_1(SERIAL_INTR_ENABLE, 0x0); | ||
109 | |||
110 | { | ||
111 | unsigned int divisor; | ||
112 | |||
113 | SERIAL_WRITE_1(SERIAL_LINE_CONTROL, 0x80); | ||
114 | divisor = TITAN_SERIAL_BASE_BAUD / YOSEMITE_BAUD_115200; | ||
115 | SERIAL_WRITE_1(SERIAL_DIVISOR_LSB, divisor & 0xff); | ||
116 | |||
117 | SERIAL_WRITE_1(SERIAL_DIVISOR_MSB, | ||
118 | (divisor & 0xff00) >> 8); | ||
119 | SERIAL_WRITE_1(SERIAL_LINE_CONTROL, 0x0); | ||
120 | } | ||
121 | |||
122 | SERIAL_WRITE_1(SERIAL_DATA_FORMAT, YOSEMITE_DATA_8BIT | | ||
123 | YOSEMITE_PARITY_NONE | YOSEMITE_STOP_1BIT); | ||
124 | |||
125 | /* Enable Interrupts */ | ||
126 | SERIAL_WRITE_1(SERIAL_INTR_ENABLE, 0xf); | ||
127 | } | ||
128 | |||
129 | /* Initialize the serial port for KGDB debugging */ | ||
130 | void debugInit(unsigned int baud, unsigned char data, unsigned char parity, | ||
131 | unsigned char stop) | ||
132 | { | ||
133 | /* Disable Interrupts */ | ||
134 | SERIAL_WRITE(SERIAL_LINE_CONTROL, 0x0); | ||
135 | SERIAL_WRITE(SERIAL_INTR_ENABLE, 0x0); | ||
136 | |||
137 | { | ||
138 | unsigned int divisor; | ||
139 | |||
140 | SERIAL_WRITE(SERIAL_LINE_CONTROL, 0x80); | ||
141 | |||
142 | divisor = TITAN_SERIAL_BASE_BAUD / baud; | ||
143 | SERIAL_WRITE(SERIAL_DIVISOR_LSB, divisor & 0xff); | ||
144 | |||
145 | SERIAL_WRITE(SERIAL_DIVISOR_MSB, (divisor & 0xff00) >> 8); | ||
146 | SERIAL_WRITE(SERIAL_LINE_CONTROL, 0x0); | ||
147 | } | ||
148 | |||
149 | SERIAL_WRITE(SERIAL_DATA_FORMAT, data | parity | stop); | ||
150 | } | ||
151 | |||
152 | static int remoteDebugInitialized = 0; | ||
153 | |||
154 | unsigned char getDebugChar(void) | ||
155 | { | ||
156 | if (!remoteDebugInitialized) { | ||
157 | remoteDebugInitialized = 1; | ||
158 | debugInit(YOSEMITE_BAUD_115200, | ||
159 | YOSEMITE_DATA_8BIT, | ||
160 | YOSEMITE_PARITY_NONE, YOSEMITE_STOP_1BIT); | ||
161 | } | ||
162 | |||
163 | while ((SERIAL_READ(SERIAL_LINE_STATUS) & 0x1) == 0); | ||
164 | return SERIAL_READ(SERIAL_RCV_BUFFER); | ||
165 | } | ||
166 | |||
167 | int putDebugChar(unsigned char byte) | ||
168 | { | ||
169 | if (!remoteDebugInitialized) { | ||
170 | remoteDebugInitialized = 1; | ||
171 | debugInit(YOSEMITE_BAUD_115200, | ||
172 | YOSEMITE_DATA_8BIT, | ||
173 | YOSEMITE_PARITY_NONE, YOSEMITE_STOP_1BIT); | ||
174 | } | ||
175 | |||
176 | while ((SERIAL_READ(SERIAL_LINE_STATUS) & 0x20) == 0); | ||
177 | SERIAL_WRITE(SERIAL_SEND_BUFFER, byte); | ||
178 | |||
179 | return 1; | ||
180 | } | ||
diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c index 4decc2807867..5f673eba142c 100644 --- a/arch/mips/pmc-sierra/yosemite/irq.c +++ b/arch/mips/pmc-sierra/yosemite/irq.c | |||
@@ -141,10 +141,6 @@ asmlinkage void plat_irq_dispatch(void) | |||
141 | } | 141 | } |
142 | } | 142 | } |
143 | 143 | ||
144 | #ifdef CONFIG_KGDB | ||
145 | extern void init_second_port(void); | ||
146 | #endif | ||
147 | |||
148 | /* | 144 | /* |
149 | * Initialize the next level interrupt handler | 145 | * Initialize the next level interrupt handler |
150 | */ | 146 | */ |
@@ -156,11 +152,6 @@ void __init arch_init_irq(void) | |||
156 | rm7k_cpu_irq_init(); | 152 | rm7k_cpu_irq_init(); |
157 | rm9k_cpu_irq_init(); | 153 | rm9k_cpu_irq_init(); |
158 | 154 | ||
159 | #ifdef CONFIG_KGDB | ||
160 | /* At this point, initialize the second serial port */ | ||
161 | init_second_port(); | ||
162 | #endif | ||
163 | |||
164 | #ifdef CONFIG_GDB_CONSOLE | 155 | #ifdef CONFIG_GDB_CONSOLE |
165 | register_gdb_console(); | 156 | register_gdb_console(); |
166 | #endif | 157 | #endif |
diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c index b2fe82dba0a5..00a1c7877bf4 100644 --- a/arch/mips/rb532/gpio.c +++ b/arch/mips/rb532/gpio.c | |||
@@ -64,7 +64,8 @@ static struct resource rb532_dev3_ctl_res[] = { | |||
64 | 64 | ||
65 | void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val) | 65 | void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val) |
66 | { | 66 | { |
67 | unsigned flags, data; | 67 | unsigned long flags; |
68 | unsigned data; | ||
68 | unsigned i = 0; | 69 | unsigned i = 0; |
69 | 70 | ||
70 | spin_lock_irqsave(&dev3.lock, flags); | 71 | spin_lock_irqsave(&dev3.lock, flags); |
@@ -90,7 +91,7 @@ EXPORT_SYMBOL(get_434_reg); | |||
90 | 91 | ||
91 | void set_latch_u5(unsigned char or_mask, unsigned char nand_mask) | 92 | void set_latch_u5(unsigned char or_mask, unsigned char nand_mask) |
92 | { | 93 | { |
93 | unsigned flags; | 94 | unsigned long flags; |
94 | 95 | ||
95 | spin_lock_irqsave(&dev3.lock, flags); | 96 | spin_lock_irqsave(&dev3.lock, flags); |
96 | 97 | ||
diff --git a/arch/mips/rb532/time.c b/arch/mips/rb532/time.c index db74edf8cefb..8e7a46855b50 100644 --- a/arch/mips/rb532/time.c +++ b/arch/mips/rb532/time.c | |||
@@ -49,8 +49,8 @@ static unsigned long __init cal_r4koff(void) | |||
49 | 49 | ||
50 | void __init plat_time_init(void) | 50 | void __init plat_time_init(void) |
51 | { | 51 | { |
52 | unsigned int est_freq, flags; | 52 | unsigned int est_freq; |
53 | unsigned long r4k_offset; | 53 | unsigned long flags, r4k_offset; |
54 | 54 | ||
55 | local_irq_save(flags); | 55 | local_irq_save(flags); |
56 | 56 | ||
diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c index 5f389ee26fca..896a1ef84829 100644 --- a/arch/mips/sgi-ip22/ip22-setup.c +++ b/arch/mips/sgi-ip22/ip22-setup.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <asm/irq.h> | 20 | #include <asm/irq.h> |
21 | #include <asm/reboot.h> | 21 | #include <asm/reboot.h> |
22 | #include <asm/time.h> | 22 | #include <asm/time.h> |
23 | #include <asm/gdb-stub.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <asm/traps.h> | 24 | #include <asm/traps.h> |
26 | #include <asm/sgialib.h> | 25 | #include <asm/sgialib.h> |
@@ -81,30 +80,6 @@ void __init plat_mem_setup(void) | |||
81 | add_preferred_console("arc", 0, NULL); | 80 | add_preferred_console("arc", 0, NULL); |
82 | } | 81 | } |
83 | 82 | ||
84 | #ifdef CONFIG_KGDB | ||
85 | { | ||
86 | char *kgdb_ttyd = prom_getcmdline(); | ||
87 | |||
88 | if ((kgdb_ttyd = strstr(kgdb_ttyd, "kgdb=ttyd")) != NULL) { | ||
89 | int line; | ||
90 | kgdb_ttyd += strlen("kgdb=ttyd"); | ||
91 | if (*kgdb_ttyd != '1' && *kgdb_ttyd != '2') | ||
92 | printk(KERN_INFO "KGDB: Uknown serial line /dev/ttyd%c" | ||
93 | ", falling back to /dev/ttyd1\n", *kgdb_ttyd); | ||
94 | line = *kgdb_ttyd == '2' ? 0 : 1; | ||
95 | printk(KERN_INFO "KGDB: Using serial line /dev/ttyd%d for " | ||
96 | "session\n", line ? 1 : 2); | ||
97 | rs_kgdb_hook(line); | ||
98 | |||
99 | printk(KERN_INFO "KGDB: Using serial line /dev/ttyd%d for " | ||
100 | "session, please connect your debugger\n", line ? 1:2); | ||
101 | |||
102 | kgdb_enabled = 1; | ||
103 | /* Breakpoints and stuff are in sgi_irq_setup() */ | ||
104 | } | ||
105 | } | ||
106 | #endif | ||
107 | |||
108 | #if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE) | 83 | #if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE) |
109 | { | 84 | { |
110 | ULONG *gfxinfo; | 85 | ULONG *gfxinfo; |
diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile index e0a6871d56e4..31f4931b8484 100644 --- a/arch/mips/sgi-ip27/Makefile +++ b/arch/mips/sgi-ip27/Makefile | |||
@@ -7,7 +7,6 @@ obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o ip27-klnuma.o \ | |||
7 | ip27-xtalk.o | 7 | ip27-xtalk.o |
8 | 8 | ||
9 | obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o | 9 | obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o |
10 | obj-$(CONFIG_KGDB) += ip27-dbgio.o | ||
11 | obj-$(CONFIG_SMP) += ip27-smp.o | 10 | obj-$(CONFIG_SMP) += ip27-smp.o |
12 | 11 | ||
13 | EXTRA_CFLAGS += -Werror | 12 | EXTRA_CFLAGS += -Werror |
diff --git a/arch/mips/sgi-ip27/ip27-dbgio.c b/arch/mips/sgi-ip27/ip27-dbgio.c deleted file mode 100644 index 08fd88b36f80..000000000000 --- a/arch/mips/sgi-ip27/ip27-dbgio.c +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify it | ||
3 | * under the terms of the GNU General Public License as published by the | ||
4 | * Free Software Foundation; either version 2 of the License, or (at your | ||
5 | * option) any later version. | ||
6 | * | ||
7 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
8 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
9 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
10 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
11 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
12 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
13 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
14 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
15 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
16 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | * Copyright 2004 Ralf Baechle <ralf@linux-mips.org> | ||
23 | */ | ||
24 | #include <asm/sn/addrs.h> | ||
25 | #include <asm/sn/sn0/hub.h> | ||
26 | #include <asm/sn/klconfig.h> | ||
27 | #include <asm/sn/ioc3.h> | ||
28 | #include <asm/sn/sn_private.h> | ||
29 | |||
30 | #include <linux/serial.h> | ||
31 | #include <linux/serial_core.h> | ||
32 | #include <linux/serial_reg.h> | ||
33 | |||
34 | #define IOC3_CLK (22000000 / 3) | ||
35 | #define IOC3_FLAGS (0) | ||
36 | |||
37 | static inline struct ioc3_uartregs *console_uart(void) | ||
38 | { | ||
39 | struct ioc3 *ioc3; | ||
40 | |||
41 | ioc3 = (struct ioc3 *)KL_CONFIG_CH_CONS_INFO(get_nasid())->memory_base; | ||
42 | |||
43 | return &ioc3->sregs.uarta; | ||
44 | } | ||
45 | |||
46 | unsigned char getDebugChar(void) | ||
47 | { | ||
48 | struct ioc3_uartregs *uart = console_uart(); | ||
49 | |||
50 | while ((uart->iu_lsr & UART_LSR_DR) == 0); | ||
51 | return uart->iu_rbr; | ||
52 | } | ||
53 | |||
54 | void putDebugChar(unsigned char c) | ||
55 | { | ||
56 | struct ioc3_uartregs *uart = console_uart(); | ||
57 | |||
58 | while ((uart->iu_lsr & UART_LSR_THRE) == 0); | ||
59 | uart->iu_thr = c; | ||
60 | } | ||
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index db372a0f106d..a35818ed4263 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c | |||
@@ -57,30 +57,6 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask); | |||
57 | extern unsigned long ht_eoi_space; | 57 | extern unsigned long ht_eoi_space; |
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | #ifdef CONFIG_KGDB | ||
61 | #include <asm/gdb-stub.h> | ||
62 | extern void breakpoint(void); | ||
63 | static int kgdb_irq; | ||
64 | #ifdef CONFIG_GDB_CONSOLE | ||
65 | extern void register_gdb_console(void); | ||
66 | #endif | ||
67 | |||
68 | /* kgdb is on when configured. Pass "nokgdb" kernel arg to turn it off */ | ||
69 | static int kgdb_flag = 1; | ||
70 | static int __init nokgdb(char *str) | ||
71 | { | ||
72 | kgdb_flag = 0; | ||
73 | return 1; | ||
74 | } | ||
75 | __setup("nokgdb", nokgdb); | ||
76 | |||
77 | /* Default to UART1 */ | ||
78 | int kgdb_port = 1; | ||
79 | #ifdef CONFIG_SERIAL_SB1250_DUART | ||
80 | extern char sb1250_duart_present[]; | ||
81 | #endif | ||
82 | #endif | ||
83 | |||
84 | static struct irq_chip bcm1480_irq_type = { | 60 | static struct irq_chip bcm1480_irq_type = { |
85 | .name = "BCM1480-IMR", | 61 | .name = "BCM1480-IMR", |
86 | .ack = ack_bcm1480_irq, | 62 | .ack = ack_bcm1480_irq, |
@@ -355,61 +331,10 @@ void __init arch_init_irq(void) | |||
355 | * does its own management of IP7. | 331 | * does its own management of IP7. |
356 | */ | 332 | */ |
357 | 333 | ||
358 | #ifdef CONFIG_KGDB | ||
359 | imask |= STATUSF_IP6; | ||
360 | #endif | ||
361 | /* Enable necessary IPs, disable the rest */ | 334 | /* Enable necessary IPs, disable the rest */ |
362 | change_c0_status(ST0_IM, imask); | 335 | change_c0_status(ST0_IM, imask); |
363 | |||
364 | #ifdef CONFIG_KGDB | ||
365 | if (kgdb_flag) { | ||
366 | kgdb_irq = K_BCM1480_INT_UART_0 + kgdb_port; | ||
367 | |||
368 | #ifdef CONFIG_SERIAL_SB1250_DUART | ||
369 | sb1250_duart_present[kgdb_port] = 0; | ||
370 | #endif | ||
371 | /* Setup uart 1 settings, mapper */ | ||
372 | /* QQQ FIXME */ | ||
373 | __raw_writeq(M_DUART_IMR_BRK, IOADDR(A_DUART_IMRREG(kgdb_port))); | ||
374 | |||
375 | __raw_writeq(IMR_IP6_VAL, | ||
376 | IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + | ||
377 | (kgdb_irq << 3))); | ||
378 | bcm1480_unmask_irq(0, kgdb_irq); | ||
379 | |||
380 | #ifdef CONFIG_GDB_CONSOLE | ||
381 | register_gdb_console(); | ||
382 | #endif | ||
383 | printk("Waiting for GDB on UART port %d\n", kgdb_port); | ||
384 | set_debug_traps(); | ||
385 | breakpoint(); | ||
386 | } | ||
387 | #endif | ||
388 | } | ||
389 | |||
390 | #ifdef CONFIG_KGDB | ||
391 | |||
392 | #include <linux/delay.h> | ||
393 | |||
394 | #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port, reg))) | ||
395 | #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port, reg))) | ||
396 | |||
397 | static void bcm1480_kgdb_interrupt(void) | ||
398 | { | ||
399 | /* | ||
400 | * Clear break-change status (allow some time for the remote | ||
401 | * host to stop the break, since we would see another | ||
402 | * interrupt on the end-of-break too) | ||
403 | */ | ||
404 | kstat.irqs[smp_processor_id()][kgdb_irq]++; | ||
405 | mdelay(500); | ||
406 | duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | | ||
407 | M_DUART_RX_EN | M_DUART_TX_EN); | ||
408 | set_async_breakpoint(&get_irq_regs()->cp0_epc); | ||
409 | } | 336 | } |
410 | 337 | ||
411 | #endif /* CONFIG_KGDB */ | ||
412 | |||
413 | extern void bcm1480_mailbox_interrupt(void); | 338 | extern void bcm1480_mailbox_interrupt(void); |
414 | 339 | ||
415 | static inline void dispatch_ip2(void) | 340 | static inline void dispatch_ip2(void) |
@@ -462,11 +387,6 @@ asmlinkage void plat_irq_dispatch(void) | |||
462 | bcm1480_mailbox_interrupt(); | 387 | bcm1480_mailbox_interrupt(); |
463 | #endif | 388 | #endif |
464 | 389 | ||
465 | #ifdef CONFIG_KGDB | ||
466 | else if (pending & CAUSEF_IP6) | ||
467 | bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */ | ||
468 | #endif | ||
469 | |||
470 | else if (pending & CAUSEF_IP2) | 390 | else if (pending & CAUSEF_IP2) |
471 | dispatch_ip2(); | 391 | dispatch_ip2(); |
472 | } | 392 | } |
diff --git a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c index fd9604d5555a..3de30f79db3f 100644 --- a/arch/mips/sibyte/cfe/setup.c +++ b/arch/mips/sibyte/cfe/setup.c | |||
@@ -59,10 +59,6 @@ int cfe_cons_handle; | |||
59 | extern unsigned long initrd_start, initrd_end; | 59 | extern unsigned long initrd_start, initrd_end; |
60 | #endif | 60 | #endif |
61 | 61 | ||
62 | #ifdef CONFIG_KGDB | ||
63 | extern int kgdb_port; | ||
64 | #endif | ||
65 | |||
66 | static void __noreturn cfe_linux_exit(void *arg) | 62 | static void __noreturn cfe_linux_exit(void *arg) |
67 | { | 63 | { |
68 | int warm = *(int *)arg; | 64 | int warm = *(int *)arg; |
@@ -246,9 +242,6 @@ void __init prom_init(void) | |||
246 | int argc = fw_arg0; | 242 | int argc = fw_arg0; |
247 | char **envp = (char **) fw_arg2; | 243 | char **envp = (char **) fw_arg2; |
248 | int *prom_vec = (int *) fw_arg3; | 244 | int *prom_vec = (int *) fw_arg3; |
249 | #ifdef CONFIG_KGDB | ||
250 | char *arg; | ||
251 | #endif | ||
252 | 245 | ||
253 | _machine_restart = cfe_linux_restart; | 246 | _machine_restart = cfe_linux_restart; |
254 | _machine_halt = cfe_linux_halt; | 247 | _machine_halt = cfe_linux_halt; |
@@ -309,13 +302,6 @@ void __init prom_init(void) | |||
309 | } | 302 | } |
310 | } | 303 | } |
311 | 304 | ||
312 | #ifdef CONFIG_KGDB | ||
313 | if ((arg = strstr(arcs_cmdline, "kgdb=duart")) != NULL) | ||
314 | kgdb_port = (arg[10] == '0') ? 0 : 1; | ||
315 | else | ||
316 | kgdb_port = 1; | ||
317 | #endif | ||
318 | |||
319 | #ifdef CONFIG_BLK_DEV_INITRD | 305 | #ifdef CONFIG_BLK_DEV_INITRD |
320 | { | 306 | { |
321 | char *ptr; | 307 | char *ptr; |
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index eac9065ffe0c..a5158483986e 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c | |||
@@ -57,16 +57,6 @@ static void sb1250_set_affinity(unsigned int irq, cpumask_t mask); | |||
57 | extern unsigned long ldt_eoi_space; | 57 | extern unsigned long ldt_eoi_space; |
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | #ifdef CONFIG_KGDB | ||
61 | static int kgdb_irq; | ||
62 | |||
63 | /* Default to UART1 */ | ||
64 | int kgdb_port = 1; | ||
65 | #ifdef CONFIG_SERIAL_SB1250_DUART | ||
66 | extern char sb1250_duart_present[]; | ||
67 | #endif | ||
68 | #endif | ||
69 | |||
70 | static struct irq_chip sb1250_irq_type = { | 60 | static struct irq_chip sb1250_irq_type = { |
71 | .name = "SB1250-IMR", | 61 | .name = "SB1250-IMR", |
72 | .ack = ack_sb1250_irq, | 62 | .ack = ack_sb1250_irq, |
@@ -313,55 +303,10 @@ void __init arch_init_irq(void) | |||
313 | * does its own management of IP7. | 303 | * does its own management of IP7. |
314 | */ | 304 | */ |
315 | 305 | ||
316 | #ifdef CONFIG_KGDB | ||
317 | imask |= STATUSF_IP6; | ||
318 | #endif | ||
319 | /* Enable necessary IPs, disable the rest */ | 306 | /* Enable necessary IPs, disable the rest */ |
320 | change_c0_status(ST0_IM, imask); | 307 | change_c0_status(ST0_IM, imask); |
321 | |||
322 | #ifdef CONFIG_KGDB | ||
323 | if (kgdb_flag) { | ||
324 | kgdb_irq = K_INT_UART_0 + kgdb_port; | ||
325 | |||
326 | #ifdef CONFIG_SERIAL_SB1250_DUART | ||
327 | sb1250_duart_present[kgdb_port] = 0; | ||
328 | #endif | ||
329 | /* Setup uart 1 settings, mapper */ | ||
330 | __raw_writeq(M_DUART_IMR_BRK, | ||
331 | IOADDR(A_DUART_IMRREG(kgdb_port))); | ||
332 | |||
333 | __raw_writeq(IMR_IP6_VAL, | ||
334 | IOADDR(A_IMR_REGISTER(0, | ||
335 | R_IMR_INTERRUPT_MAP_BASE) + | ||
336 | (kgdb_irq << 3))); | ||
337 | sb1250_unmask_irq(0, kgdb_irq); | ||
338 | } | ||
339 | #endif | ||
340 | } | ||
341 | |||
342 | #ifdef CONFIG_KGDB | ||
343 | |||
344 | #include <linux/delay.h> | ||
345 | |||
346 | #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port, reg))) | ||
347 | #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port, reg))) | ||
348 | |||
349 | static void sb1250_kgdb_interrupt(void) | ||
350 | { | ||
351 | /* | ||
352 | * Clear break-change status (allow some time for the remote | ||
353 | * host to stop the break, since we would see another | ||
354 | * interrupt on the end-of-break too) | ||
355 | */ | ||
356 | kstat_this_cpu.irqs[kgdb_irq]++; | ||
357 | mdelay(500); | ||
358 | duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | | ||
359 | M_DUART_RX_EN | M_DUART_TX_EN); | ||
360 | set_async_breakpoint(&get_irq_regs()->cp0_epc); | ||
361 | } | 308 | } |
362 | 309 | ||
363 | #endif /* CONFIG_KGDB */ | ||
364 | |||
365 | extern void sb1250_mailbox_interrupt(void); | 310 | extern void sb1250_mailbox_interrupt(void); |
366 | 311 | ||
367 | static inline void dispatch_ip2(void) | 312 | static inline void dispatch_ip2(void) |
@@ -407,11 +352,6 @@ asmlinkage void plat_irq_dispatch(void) | |||
407 | sb1250_mailbox_interrupt(); | 352 | sb1250_mailbox_interrupt(); |
408 | #endif | 353 | #endif |
409 | 354 | ||
410 | #ifdef CONFIG_KGDB | ||
411 | else if (pending & CAUSEF_IP6) /* KGDB (uart 1) */ | ||
412 | sb1250_kgdb_interrupt(); | ||
413 | #endif | ||
414 | |||
415 | else if (pending & CAUSEF_IP2) | 355 | else if (pending & CAUSEF_IP2) |
416 | dispatch_ip2(); | 356 | dispatch_ip2(); |
417 | else | 357 | else |
diff --git a/arch/mips/sibyte/swarm/Makefile b/arch/mips/sibyte/swarm/Makefile index 255d692bfa18..f18ba9201bbc 100644 --- a/arch/mips/sibyte/swarm/Makefile +++ b/arch/mips/sibyte/swarm/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | obj-y := setup.o rtc_xicor1241.o rtc_m41t81.o | 1 | obj-y := setup.o rtc_xicor1241.o rtc_m41t81.o |
2 | 2 | ||
3 | obj-$(CONFIG_I2C_BOARDINFO) += swarm-i2c.o | 3 | obj-$(CONFIG_I2C_BOARDINFO) += swarm-i2c.o |
4 | obj-$(CONFIG_KGDB) += dbg_io.o | ||
diff --git a/arch/mips/sibyte/swarm/dbg_io.c b/arch/mips/sibyte/swarm/dbg_io.c deleted file mode 100644 index b97ae3048482..000000000000 --- a/arch/mips/sibyte/swarm/dbg_io.c +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
1 | /* | ||
2 | * kgdb debug routines for SiByte boards. | ||
3 | * | ||
4 | * Copyright (C) 2001 MontaVista Software Inc. | ||
5 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | /* -------------------- BEGINNING OF CONFIG --------------------- */ | ||
15 | |||
16 | #include <linux/delay.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/sibyte/sb1250.h> | ||
19 | #include <asm/sibyte/sb1250_regs.h> | ||
20 | #include <asm/sibyte/sb1250_uart.h> | ||
21 | #include <asm/sibyte/sb1250_int.h> | ||
22 | #include <asm/addrspace.h> | ||
23 | |||
24 | /* | ||
25 | * We use the second serial port for kgdb traffic. | ||
26 | * 115200, 8, N, 1. | ||
27 | */ | ||
28 | |||
29 | #define BAUD_RATE 115200 | ||
30 | #define CLK_DIVISOR V_DUART_BAUD_RATE(BAUD_RATE) | ||
31 | #define DATA_BITS V_DUART_BITS_PER_CHAR_8 /* or 7 */ | ||
32 | #define PARITY V_DUART_PARITY_MODE_NONE /* or even */ | ||
33 | #define STOP_BITS M_DUART_STOP_BIT_LEN_1 /* or 2 */ | ||
34 | |||
35 | static int duart_initialized = 0; /* 0: need to be init'ed by kgdb */ | ||
36 | |||
37 | /* -------------------- END OF CONFIG --------------------- */ | ||
38 | extern int kgdb_port; | ||
39 | |||
40 | #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port, reg))) | ||
41 | #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port, reg))) | ||
42 | |||
43 | void putDebugChar(unsigned char c); | ||
44 | unsigned char getDebugChar(void); | ||
45 | static void | ||
46 | duart_init(int clk_divisor, int data, int parity, int stop) | ||
47 | { | ||
48 | duart_out(R_DUART_MODE_REG_1, data | parity); | ||
49 | duart_out(R_DUART_MODE_REG_2, stop); | ||
50 | duart_out(R_DUART_CLK_SEL, clk_divisor); | ||
51 | |||
52 | duart_out(R_DUART_CMD, M_DUART_RX_EN | M_DUART_TX_EN); /* enable rx and tx */ | ||
53 | } | ||
54 | |||
55 | void | ||
56 | putDebugChar(unsigned char c) | ||
57 | { | ||
58 | if (!duart_initialized) { | ||
59 | duart_initialized = 1; | ||
60 | duart_init(CLK_DIVISOR, DATA_BITS, PARITY, STOP_BITS); | ||
61 | } | ||
62 | while ((duart_in(R_DUART_STATUS) & M_DUART_TX_RDY) == 0); | ||
63 | duart_out(R_DUART_TX_HOLD, c); | ||
64 | } | ||
65 | |||
66 | unsigned char | ||
67 | getDebugChar(void) | ||
68 | { | ||
69 | if (!duart_initialized) { | ||
70 | duart_initialized = 1; | ||
71 | duart_init(CLK_DIVISOR, DATA_BITS, PARITY, STOP_BITS); | ||
72 | } | ||
73 | while ((duart_in(R_DUART_STATUS) & M_DUART_RX_RDY) == 0) ; | ||
74 | return duart_in(R_DUART_RX_HOLD); | ||
75 | } | ||
76 | |||
diff --git a/arch/mips/txx9/Kconfig b/arch/mips/txx9/Kconfig index 6de4c5aa92be..840fe757c48d 100644 --- a/arch/mips/txx9/Kconfig +++ b/arch/mips/txx9/Kconfig | |||
@@ -1,3 +1,27 @@ | |||
1 | config MACH_TX39XX | ||
2 | bool | ||
3 | select MACH_TXX9 | ||
4 | select SYS_HAS_CPU_TX39XX | ||
5 | |||
6 | config MACH_TX49XX | ||
7 | bool | ||
8 | select MACH_TXX9 | ||
9 | select CEVT_R4K | ||
10 | select CSRC_R4K | ||
11 | select IRQ_CPU | ||
12 | select SYS_HAS_CPU_TX49XX | ||
13 | select SYS_SUPPORTS_64BIT_KERNEL | ||
14 | |||
15 | config MACH_TXX9 | ||
16 | bool | ||
17 | select DMA_NONCOHERENT | ||
18 | select SWAP_IO_SPACE | ||
19 | select SYS_HAS_EARLY_PRINTK | ||
20 | select SYS_SUPPORTS_32BIT_KERNEL | ||
21 | select SYS_SUPPORTS_LITTLE_ENDIAN | ||
22 | select SYS_SUPPORTS_BIG_ENDIAN | ||
23 | select GENERIC_HARDIRQS_NO__DO_IRQ | ||
24 | |||
1 | config TOSHIBA_JMR3927 | 25 | config TOSHIBA_JMR3927 |
2 | bool "Toshiba JMR-TX3927 board" | 26 | bool "Toshiba JMR-TX3927 board" |
3 | depends on MACH_TX39XX | 27 | depends on MACH_TX39XX |
@@ -24,68 +48,37 @@ config TOSHIBA_RBTX4938 | |||
24 | config SOC_TX3927 | 48 | config SOC_TX3927 |
25 | bool | 49 | bool |
26 | select CEVT_TXX9 | 50 | select CEVT_TXX9 |
27 | select DMA_NONCOHERENT | ||
28 | select HAS_TXX9_SERIAL | 51 | select HAS_TXX9_SERIAL |
29 | select HW_HAS_PCI | 52 | select HW_HAS_PCI |
30 | select IRQ_TXX9 | 53 | select IRQ_TXX9 |
31 | select SWAP_IO_SPACE | ||
32 | select SYS_HAS_CPU_TX39XX | ||
33 | select SYS_SUPPORTS_32BIT_KERNEL | ||
34 | select SYS_SUPPORTS_LITTLE_ENDIAN | ||
35 | select SYS_SUPPORTS_BIG_ENDIAN | ||
36 | select GENERIC_HARDIRQS_NO__DO_IRQ | ||
37 | select GPIO_TXX9 | 54 | select GPIO_TXX9 |
38 | 55 | ||
39 | config SOC_TX4927 | 56 | config SOC_TX4927 |
40 | bool | 57 | bool |
41 | select CEVT_R4K | ||
42 | select CSRC_R4K | ||
43 | select CEVT_TXX9 | 58 | select CEVT_TXX9 |
44 | select DMA_NONCOHERENT | ||
45 | select HAS_TXX9_SERIAL | 59 | select HAS_TXX9_SERIAL |
46 | select HW_HAS_PCI | 60 | select HW_HAS_PCI |
47 | select IRQ_CPU | ||
48 | select IRQ_TXX9 | 61 | select IRQ_TXX9 |
49 | select PCI_TX4927 | 62 | select PCI_TX4927 |
50 | select SWAP_IO_SPACE | ||
51 | select SYS_HAS_CPU_TX49XX | ||
52 | select SYS_SUPPORTS_32BIT_KERNEL | ||
53 | select SYS_SUPPORTS_64BIT_KERNEL | ||
54 | select SYS_SUPPORTS_LITTLE_ENDIAN | ||
55 | select SYS_SUPPORTS_BIG_ENDIAN | ||
56 | select SYS_SUPPORTS_KGDB | ||
57 | select GENERIC_HARDIRQS_NO__DO_IRQ | ||
58 | select GPIO_TXX9 | 63 | select GPIO_TXX9 |
59 | 64 | ||
60 | config SOC_TX4938 | 65 | config SOC_TX4938 |
61 | bool | 66 | bool |
62 | select CEVT_R4K | ||
63 | select CSRC_R4K | ||
64 | select CEVT_TXX9 | 67 | select CEVT_TXX9 |
65 | select DMA_NONCOHERENT | ||
66 | select HAS_TXX9_SERIAL | 68 | select HAS_TXX9_SERIAL |
67 | select HW_HAS_PCI | 69 | select HW_HAS_PCI |
68 | select IRQ_CPU | ||
69 | select IRQ_TXX9 | 70 | select IRQ_TXX9 |
70 | select PCI_TX4927 | 71 | select PCI_TX4927 |
71 | select SWAP_IO_SPACE | ||
72 | select SYS_HAS_CPU_TX49XX | ||
73 | select SYS_SUPPORTS_32BIT_KERNEL | ||
74 | select SYS_SUPPORTS_64BIT_KERNEL | ||
75 | select SYS_SUPPORTS_LITTLE_ENDIAN | ||
76 | select SYS_SUPPORTS_BIG_ENDIAN | ||
77 | select SYS_SUPPORTS_KGDB | ||
78 | select GENERIC_HARDIRQS_NO__DO_IRQ | ||
79 | select GPIO_TXX9 | 72 | select GPIO_TXX9 |
80 | 73 | ||
81 | config TOSHIBA_FPCIB0 | 74 | config TOSHIBA_FPCIB0 |
82 | bool "FPCIB0 Backplane Support" | 75 | bool "FPCIB0 Backplane Support" |
83 | depends on PCI && (MACH_TX39XX || MACH_TX49XX) | 76 | depends on PCI && MACH_TXX9 |
84 | select I8259 | 77 | select I8259 |
85 | 78 | ||
86 | config PICMG_PCI_BACKPLANE_DEFAULT | 79 | config PICMG_PCI_BACKPLANE_DEFAULT |
87 | bool "Support for PICMG PCI Backplane" | 80 | bool "Support for PICMG PCI Backplane" |
88 | depends on PCI && (MACH_TX39XX || MACH_TX49XX) | 81 | depends on PCI && MACH_TXX9 |
89 | default y if !TOSHIBA_FPCIB0 | 82 | default y if !TOSHIBA_FPCIB0 |
90 | 83 | ||
91 | if TOSHIBA_RBTX4938 | 84 | if TOSHIBA_RBTX4938 |
diff --git a/arch/mips/txx9/generic/Makefile b/arch/mips/txx9/generic/Makefile index 9c120771e65f..9bb34af26b73 100644 --- a/arch/mips/txx9/generic/Makefile +++ b/arch/mips/txx9/generic/Makefile | |||
@@ -4,9 +4,9 @@ | |||
4 | 4 | ||
5 | obj-y += setup.o | 5 | obj-y += setup.o |
6 | obj-$(CONFIG_PCI) += pci.o | 6 | obj-$(CONFIG_PCI) += pci.o |
7 | obj-$(CONFIG_SOC_TX3927) += setup_tx3927.o irq_tx3927.o | ||
7 | obj-$(CONFIG_SOC_TX4927) += mem_tx4927.o setup_tx4927.o irq_tx4927.o | 8 | obj-$(CONFIG_SOC_TX4927) += mem_tx4927.o setup_tx4927.o irq_tx4927.o |
8 | obj-$(CONFIG_SOC_TX4938) += mem_tx4927.o setup_tx4938.o irq_tx4938.o | 9 | obj-$(CONFIG_SOC_TX4938) += mem_tx4927.o setup_tx4938.o irq_tx4938.o |
9 | obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o | 10 | obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o |
10 | obj-$(CONFIG_KGDB) += dbgio.o | ||
11 | 11 | ||
12 | EXTRA_CFLAGS += -Werror | 12 | EXTRA_CFLAGS += -Werror |
diff --git a/arch/mips/txx9/generic/dbgio.c b/arch/mips/txx9/generic/dbgio.c deleted file mode 100644 index 33b9c672a322..000000000000 --- a/arch/mips/txx9/generic/dbgio.c +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/tx4938/common/dbgio.c | ||
3 | * | ||
4 | * kgdb interface for gdb | ||
5 | * | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * source@mvista.com | ||
8 | * | ||
9 | * Copyright 2005 MontaVista Software Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||
24 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||
25 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License along | ||
28 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
29 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
30 | * | ||
31 | * Support for TX4938 in 2.6 - Hiroshi DOYU <Hiroshi_DOYU@montavista.co.jp> | ||
32 | */ | ||
33 | |||
34 | #include <linux/types> | ||
35 | |||
36 | extern u8 txx9_sio_kdbg_rd(void); | ||
37 | extern int txx9_sio_kdbg_wr( u8 ch ); | ||
38 | |||
39 | u8 getDebugChar(void) | ||
40 | { | ||
41 | return (txx9_sio_kdbg_rd()); | ||
42 | } | ||
43 | |||
44 | int putDebugChar(u8 byte) | ||
45 | { | ||
46 | return (txx9_sio_kdbg_wr(byte)); | ||
47 | } | ||
48 | |||
diff --git a/arch/mips/txx9/generic/irq_tx3927.c b/arch/mips/txx9/generic/irq_tx3927.c new file mode 100644 index 000000000000..c683f593eda2 --- /dev/null +++ b/arch/mips/txx9/generic/irq_tx3927.c | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Common tx3927 irq handler | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright 2001 MontaVista Software Inc. | ||
9 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
10 | */ | ||
11 | #include <linux/init.h> | ||
12 | #include <asm/txx9irq.h> | ||
13 | #include <asm/txx9/tx3927.h> | ||
14 | |||
15 | void __init tx3927_irq_init(void) | ||
16 | { | ||
17 | int i; | ||
18 | |||
19 | txx9_irq_init(TX3927_IRC_REG); | ||
20 | /* raise priority for timers, sio */ | ||
21 | for (i = 0; i < TX3927_NR_TMR; i++) | ||
22 | txx9_irq_set_pri(TX3927_IR_TMR(i), 6); | ||
23 | for (i = 0; i < TX3927_NR_SIO; i++) | ||
24 | txx9_irq_set_pri(TX3927_IR_SIO(i), 7); | ||
25 | } | ||
diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c index 0b92d8c13208..7b637a7c0e66 100644 --- a/arch/mips/txx9/generic/pci.c +++ b/arch/mips/txx9/generic/pci.c | |||
@@ -386,3 +386,39 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | |||
386 | { | 386 | { |
387 | return txx9_board_vec->pci_map_irq(dev, slot, pin); | 387 | return txx9_board_vec->pci_map_irq(dev, slot, pin); |
388 | } | 388 | } |
389 | |||
390 | char * (*txx9_board_pcibios_setup)(char *str) __devinitdata; | ||
391 | |||
392 | char *__devinit txx9_pcibios_setup(char *str) | ||
393 | { | ||
394 | if (txx9_board_pcibios_setup && !txx9_board_pcibios_setup(str)) | ||
395 | return NULL; | ||
396 | if (!strcmp(str, "picmg")) { | ||
397 | /* PICMG compliant backplane (TOSHIBA JMB-PICMG-ATX | ||
398 | (5V or 3.3V), JMB-PICMG-L2 (5V only), etc.) */ | ||
399 | txx9_pci_option |= TXX9_PCI_OPT_PICMG; | ||
400 | return NULL; | ||
401 | } else if (!strcmp(str, "nopicmg")) { | ||
402 | /* non-PICMG compliant backplane (TOSHIBA | ||
403 | RBHBK4100,RBHBK4200, Interface PCM-PCM05, etc.) */ | ||
404 | txx9_pci_option &= ~TXX9_PCI_OPT_PICMG; | ||
405 | return NULL; | ||
406 | } else if (!strncmp(str, "clk=", 4)) { | ||
407 | char *val = str + 4; | ||
408 | txx9_pci_option &= ~TXX9_PCI_OPT_CLK_MASK; | ||
409 | if (strcmp(val, "33") == 0) | ||
410 | txx9_pci_option |= TXX9_PCI_OPT_CLK_33; | ||
411 | else if (strcmp(val, "66") == 0) | ||
412 | txx9_pci_option |= TXX9_PCI_OPT_CLK_66; | ||
413 | else /* "auto" */ | ||
414 | txx9_pci_option |= TXX9_PCI_OPT_CLK_AUTO; | ||
415 | return NULL; | ||
416 | } else if (!strncmp(str, "err=", 4)) { | ||
417 | if (!strcmp(str + 4, "panic")) | ||
418 | txx9_pci_err_action = TXX9_PCI_ERR_PANIC; | ||
419 | else if (!strcmp(str + 4, "ignore")) | ||
420 | txx9_pci_err_action = TXX9_PCI_ERR_IGNORE; | ||
421 | return NULL; | ||
422 | } | ||
423 | return str; | ||
424 | } | ||
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 8c60c78b9a9e..1bc57d0f4c5c 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c | |||
@@ -20,9 +20,13 @@ | |||
20 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/serial_core.h> | ||
23 | #include <asm/bootinfo.h> | 25 | #include <asm/bootinfo.h> |
24 | #include <asm/time.h> | 26 | #include <asm/time.h> |
27 | #include <asm/reboot.h> | ||
25 | #include <asm/txx9/generic.h> | 28 | #include <asm/txx9/generic.h> |
29 | #include <asm/txx9/pci.h> | ||
26 | #ifdef CONFIG_CPU_TX49XX | 30 | #ifdef CONFIG_CPU_TX49XX |
27 | #include <asm/txx9/tx4938.h> | 31 | #include <asm/txx9/tx4938.h> |
28 | #endif | 32 | #endif |
@@ -187,6 +191,117 @@ char * __init prom_getcmdline(void) | |||
187 | return &(arcs_cmdline[0]); | 191 | return &(arcs_cmdline[0]); |
188 | } | 192 | } |
189 | 193 | ||
194 | static void __noreturn txx9_machine_halt(void) | ||
195 | { | ||
196 | local_irq_disable(); | ||
197 | clear_c0_status(ST0_IM); | ||
198 | while (1) { | ||
199 | if (cpu_wait) { | ||
200 | (*cpu_wait)(); | ||
201 | if (cpu_has_counter) { | ||
202 | /* | ||
203 | * Clear counter interrupt while it | ||
204 | * breaks WAIT instruction even if | ||
205 | * masked. | ||
206 | */ | ||
207 | write_c0_compare(0); | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | |||
213 | /* Watchdog support */ | ||
214 | void __init txx9_wdt_init(unsigned long base) | ||
215 | { | ||
216 | struct resource res = { | ||
217 | .start = base, | ||
218 | .end = base + 0x100 - 1, | ||
219 | .flags = IORESOURCE_MEM, | ||
220 | }; | ||
221 | platform_device_register_simple("txx9wdt", -1, &res, 1); | ||
222 | } | ||
223 | |||
224 | /* SPI support */ | ||
225 | void __init txx9_spi_init(int busid, unsigned long base, int irq) | ||
226 | { | ||
227 | struct resource res[] = { | ||
228 | { | ||
229 | .start = base, | ||
230 | .end = base + 0x20 - 1, | ||
231 | .flags = IORESOURCE_MEM, | ||
232 | }, { | ||
233 | .start = irq, | ||
234 | .flags = IORESOURCE_IRQ, | ||
235 | }, | ||
236 | }; | ||
237 | platform_device_register_simple("spi_txx9", busid, | ||
238 | res, ARRAY_SIZE(res)); | ||
239 | } | ||
240 | |||
241 | void __init txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr) | ||
242 | { | ||
243 | struct platform_device *pdev = | ||
244 | platform_device_alloc("tc35815-mac", id); | ||
245 | if (!pdev || | ||
246 | platform_device_add_data(pdev, ethaddr, 6) || | ||
247 | platform_device_add(pdev)) | ||
248 | platform_device_put(pdev); | ||
249 | } | ||
250 | |||
251 | void __init txx9_sio_init(unsigned long baseaddr, int irq, | ||
252 | unsigned int line, unsigned int sclk, int nocts) | ||
253 | { | ||
254 | #ifdef CONFIG_SERIAL_TXX9 | ||
255 | struct uart_port req; | ||
256 | |||
257 | memset(&req, 0, sizeof(req)); | ||
258 | req.line = line; | ||
259 | req.iotype = UPIO_MEM; | ||
260 | req.membase = ioremap(baseaddr, 0x24); | ||
261 | req.mapbase = baseaddr; | ||
262 | req.irq = irq; | ||
263 | if (!nocts) | ||
264 | req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; | ||
265 | if (sclk) { | ||
266 | req.flags |= UPF_MAGIC_MULTIPLIER /*USE_SCLK*/; | ||
267 | req.uartclk = sclk; | ||
268 | } else | ||
269 | req.uartclk = TXX9_IMCLK; | ||
270 | early_serial_txx9_setup(&req); | ||
271 | #endif /* CONFIG_SERIAL_TXX9 */ | ||
272 | } | ||
273 | |||
274 | #ifdef CONFIG_EARLY_PRINTK | ||
275 | static void __init null_prom_putchar(char c) | ||
276 | { | ||
277 | } | ||
278 | void (*txx9_prom_putchar)(char c) __initdata = null_prom_putchar; | ||
279 | |||
280 | void __init prom_putchar(char c) | ||
281 | { | ||
282 | txx9_prom_putchar(c); | ||
283 | } | ||
284 | |||
285 | static void __iomem *early_txx9_sio_port; | ||
286 | |||
287 | static void __init early_txx9_sio_putchar(char c) | ||
288 | { | ||
289 | #define TXX9_SICISR 0x0c | ||
290 | #define TXX9_SITFIFO 0x1c | ||
291 | #define TXX9_SICISR_TXALS 0x00000002 | ||
292 | while (!(__raw_readl(early_txx9_sio_port + TXX9_SICISR) & | ||
293 | TXX9_SICISR_TXALS)) | ||
294 | ; | ||
295 | __raw_writel(c, early_txx9_sio_port + TXX9_SITFIFO); | ||
296 | } | ||
297 | |||
298 | void __init txx9_sio_putchar_init(unsigned long baseaddr) | ||
299 | { | ||
300 | early_txx9_sio_port = ioremap(baseaddr, 0x24); | ||
301 | txx9_prom_putchar = early_txx9_sio_putchar; | ||
302 | } | ||
303 | #endif /* CONFIG_EARLY_PRINTK */ | ||
304 | |||
190 | /* wrappers */ | 305 | /* wrappers */ |
191 | void __init plat_mem_setup(void) | 306 | void __init plat_mem_setup(void) |
192 | { | 307 | { |
@@ -194,6 +309,15 @@ void __init plat_mem_setup(void) | |||
194 | ioport_resource.end = ~0UL; /* no limit */ | 309 | ioport_resource.end = ~0UL; /* no limit */ |
195 | iomem_resource.start = 0; | 310 | iomem_resource.start = 0; |
196 | iomem_resource.end = ~0UL; /* no limit */ | 311 | iomem_resource.end = ~0UL; /* no limit */ |
312 | |||
313 | /* fallback restart/halt routines */ | ||
314 | _machine_restart = (void (*)(char *))txx9_machine_halt; | ||
315 | _machine_halt = txx9_machine_halt; | ||
316 | pm_power_off = txx9_machine_halt; | ||
317 | |||
318 | #ifdef CONFIG_PCI | ||
319 | pcibios_plat_setup = txx9_pcibios_setup; | ||
320 | #endif | ||
197 | txx9_board_vec->mem_setup(); | 321 | txx9_board_vec->mem_setup(); |
198 | } | 322 | } |
199 | 323 | ||
diff --git a/arch/mips/txx9/generic/setup_tx3927.c b/arch/mips/txx9/generic/setup_tx3927.c new file mode 100644 index 000000000000..7bd963d37fc3 --- /dev/null +++ b/arch/mips/txx9/generic/setup_tx3927.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * TX3927 setup routines | ||
3 | * Based on linux/arch/mips/txx9/jmr3927/setup.c | ||
4 | * | ||
5 | * Copyright 2001 MontaVista Software Inc. | ||
6 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
7 | * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | */ | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/ioport.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/param.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <asm/mipsregs.h> | ||
19 | #include <asm/txx9irq.h> | ||
20 | #include <asm/txx9tmr.h> | ||
21 | #include <asm/txx9pio.h> | ||
22 | #include <asm/txx9/generic.h> | ||
23 | #include <asm/txx9/tx3927.h> | ||
24 | |||
25 | void __init tx3927_wdt_init(void) | ||
26 | { | ||
27 | txx9_wdt_init(TX3927_TMR_REG(2)); | ||
28 | } | ||
29 | |||
30 | void __init tx3927_setup(void) | ||
31 | { | ||
32 | int i; | ||
33 | unsigned int conf; | ||
34 | |||
35 | /* don't enable - see errata */ | ||
36 | txx9_ccfg_toeon = 0; | ||
37 | if (strstr(prom_getcmdline(), "toeon") != NULL) | ||
38 | txx9_ccfg_toeon = 1; | ||
39 | |||
40 | txx9_reg_res_init(TX3927_REV_PCODE(), TX3927_REG_BASE, | ||
41 | TX3927_REG_SIZE); | ||
42 | |||
43 | /* SDRAMC,ROMC are configured by PROM */ | ||
44 | for (i = 0; i < 8; i++) { | ||
45 | if (!(tx3927_romcptr->cr[i] & 0x8)) | ||
46 | continue; /* disabled */ | ||
47 | txx9_ce_res[i].start = (unsigned long)TX3927_ROMC_BA(i); | ||
48 | txx9_ce_res[i].end = | ||
49 | txx9_ce_res[i].start + TX3927_ROMC_SIZE(i) - 1; | ||
50 | request_resource(&iomem_resource, &txx9_ce_res[i]); | ||
51 | } | ||
52 | |||
53 | /* clocks */ | ||
54 | txx9_gbus_clock = txx9_cpu_clock / 2; | ||
55 | /* change default value to udelay/mdelay take reasonable time */ | ||
56 | loops_per_jiffy = txx9_cpu_clock / HZ / 2; | ||
57 | |||
58 | /* CCFG */ | ||
59 | /* enable Timeout BusError */ | ||
60 | if (txx9_ccfg_toeon) | ||
61 | tx3927_ccfgptr->ccfg |= TX3927_CCFG_TOE; | ||
62 | |||
63 | /* clear BusErrorOnWrite flag */ | ||
64 | tx3927_ccfgptr->ccfg &= ~TX3927_CCFG_BEOW; | ||
65 | if (read_c0_conf() & TX39_CONF_WBON) | ||
66 | /* Disable PCI snoop */ | ||
67 | tx3927_ccfgptr->ccfg &= ~TX3927_CCFG_PSNP; | ||
68 | else | ||
69 | /* Enable PCI SNOOP - with write through only */ | ||
70 | tx3927_ccfgptr->ccfg |= TX3927_CCFG_PSNP; | ||
71 | /* do reset on watchdog */ | ||
72 | tx3927_ccfgptr->ccfg |= TX3927_CCFG_WR; | ||
73 | |||
74 | printk(KERN_INFO "TX3927 -- CRIR:%08lx CCFG:%08lx PCFG:%08lx\n", | ||
75 | tx3927_ccfgptr->crir, | ||
76 | tx3927_ccfgptr->ccfg, tx3927_ccfgptr->pcfg); | ||
77 | |||
78 | /* TMR */ | ||
79 | for (i = 0; i < TX3927_NR_TMR; i++) | ||
80 | txx9_tmr_init(TX3927_TMR_REG(i)); | ||
81 | |||
82 | /* DMA */ | ||
83 | tx3927_dmaptr->mcr = 0; | ||
84 | for (i = 0; i < ARRAY_SIZE(tx3927_dmaptr->ch); i++) { | ||
85 | /* reset channel */ | ||
86 | tx3927_dmaptr->ch[i].ccr = TX3927_DMA_CCR_CHRST; | ||
87 | tx3927_dmaptr->ch[i].ccr = 0; | ||
88 | } | ||
89 | /* enable DMA */ | ||
90 | #ifdef __BIG_ENDIAN | ||
91 | tx3927_dmaptr->mcr = TX3927_DMA_MCR_MSTEN; | ||
92 | #else | ||
93 | tx3927_dmaptr->mcr = TX3927_DMA_MCR_MSTEN | TX3927_DMA_MCR_LE; | ||
94 | #endif | ||
95 | |||
96 | /* PIO */ | ||
97 | __raw_writel(0, &tx3927_pioptr->maskcpu); | ||
98 | __raw_writel(0, &tx3927_pioptr->maskext); | ||
99 | txx9_gpio_init(TX3927_PIO_REG, 0, 16); | ||
100 | |||
101 | conf = read_c0_conf(); | ||
102 | if (!(conf & TX39_CONF_ICE)) | ||
103 | printk(KERN_INFO "TX3927 I-Cache disabled.\n"); | ||
104 | if (!(conf & TX39_CONF_DCE)) | ||
105 | printk(KERN_INFO "TX3927 D-Cache disabled.\n"); | ||
106 | else if (!(conf & TX39_CONF_WBON)) | ||
107 | printk(KERN_INFO "TX3927 D-Cache WriteThrough.\n"); | ||
108 | else if (!(conf & TX39_CONF_CWFON)) | ||
109 | printk(KERN_INFO "TX3927 D-Cache WriteBack.\n"); | ||
110 | else | ||
111 | printk(KERN_INFO "TX3927 D-Cache WriteBack (CWF) .\n"); | ||
112 | } | ||
113 | |||
114 | void __init tx3927_time_init(unsigned int evt_tmrnr, unsigned int src_tmrnr) | ||
115 | { | ||
116 | txx9_clockevent_init(TX3927_TMR_REG(evt_tmrnr), | ||
117 | TXX9_IRQ_BASE + TX3927_IR_TMR(evt_tmrnr), | ||
118 | TXX9_IMCLK); | ||
119 | txx9_clocksource_init(TX3927_TMR_REG(src_tmrnr), TXX9_IMCLK); | ||
120 | } | ||
121 | |||
122 | void __init tx3927_sio_init(unsigned int sclk, unsigned int cts_mask) | ||
123 | { | ||
124 | int i; | ||
125 | |||
126 | for (i = 0; i < 2; i++) | ||
127 | txx9_sio_init(TX3927_SIO_REG(i), | ||
128 | TXX9_IRQ_BASE + TX3927_IR_SIO(i), | ||
129 | i, sclk, (1 << i) & cts_mask); | ||
130 | } | ||
diff --git a/arch/mips/txx9/generic/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c index 89d6e28add93..f80d4b7a694d 100644 --- a/arch/mips/txx9/generic/setup_tx4927.c +++ b/arch/mips/txx9/generic/setup_tx4927.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/ioport.h> | 14 | #include <linux/ioport.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/serial_core.h> | ||
17 | #include <linux/param.h> | 16 | #include <linux/param.h> |
18 | #include <asm/txx9irq.h> | 17 | #include <asm/txx9irq.h> |
19 | #include <asm/txx9tmr.h> | 18 | #include <asm/txx9tmr.h> |
@@ -21,7 +20,7 @@ | |||
21 | #include <asm/txx9/generic.h> | 20 | #include <asm/txx9/generic.h> |
22 | #include <asm/txx9/tx4927.h> | 21 | #include <asm/txx9/tx4927.h> |
23 | 22 | ||
24 | void __init tx4927_wdr_init(void) | 23 | static void __init tx4927_wdr_init(void) |
25 | { | 24 | { |
26 | /* clear WatchDogReset (W1C) */ | 25 | /* clear WatchDogReset (W1C) */ |
27 | tx4927_ccfg_set(TX4927_CCFG_WDRST); | 26 | tx4927_ccfg_set(TX4927_CCFG_WDRST); |
@@ -29,6 +28,11 @@ void __init tx4927_wdr_init(void) | |||
29 | tx4927_ccfg_set(TX4927_CCFG_WR); | 28 | tx4927_ccfg_set(TX4927_CCFG_WR); |
30 | } | 29 | } |
31 | 30 | ||
31 | void __init tx4927_wdt_init(void) | ||
32 | { | ||
33 | txx9_wdt_init(TX4927_TMR_REG(2) & 0xfffffffffULL); | ||
34 | } | ||
35 | |||
32 | static struct resource tx4927_sdram_resource[4]; | 36 | static struct resource tx4927_sdram_resource[4]; |
33 | 37 | ||
34 | void __init tx4927_setup(void) | 38 | void __init tx4927_setup(void) |
@@ -173,22 +177,12 @@ void __init tx4927_time_init(unsigned int tmrnr) | |||
173 | TXX9_IMCLK); | 177 | TXX9_IMCLK); |
174 | } | 178 | } |
175 | 179 | ||
176 | void __init tx4927_setup_serial(void) | 180 | void __init tx4927_sio_init(unsigned int sclk, unsigned int cts_mask) |
177 | { | 181 | { |
178 | #ifdef CONFIG_SERIAL_TXX9 | ||
179 | int i; | 182 | int i; |
180 | struct uart_port req; | 183 | |
181 | 184 | for (i = 0; i < 2; i++) | |
182 | for (i = 0; i < 2; i++) { | 185 | txx9_sio_init(TX4927_SIO_REG(i) & 0xfffffffffULL, |
183 | memset(&req, 0, sizeof(req)); | 186 | TXX9_IRQ_BASE + TX4927_IR_SIO(i), |
184 | req.line = i; | 187 | i, sclk, (1 << i) & cts_mask); |
185 | req.iotype = UPIO_MEM; | ||
186 | req.membase = (unsigned char __iomem *)TX4927_SIO_REG(i); | ||
187 | req.mapbase = TX4927_SIO_REG(i) & 0xfffffffffULL; | ||
188 | req.irq = TXX9_IRQ_BASE + TX4927_IR_SIO(i); | ||
189 | req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; | ||
190 | req.uartclk = TXX9_IMCLK; | ||
191 | early_serial_txx9_setup(&req); | ||
192 | } | ||
193 | #endif /* CONFIG_SERIAL_TXX9 */ | ||
194 | } | 188 | } |
diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c index 317378d8579d..f3040b9ba059 100644 --- a/arch/mips/txx9/generic/setup_tx4938.c +++ b/arch/mips/txx9/generic/setup_tx4938.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/ioport.h> | 14 | #include <linux/ioport.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/serial_core.h> | ||
17 | #include <linux/param.h> | 16 | #include <linux/param.h> |
18 | #include <asm/txx9irq.h> | 17 | #include <asm/txx9irq.h> |
19 | #include <asm/txx9tmr.h> | 18 | #include <asm/txx9tmr.h> |
@@ -21,7 +20,7 @@ | |||
21 | #include <asm/txx9/generic.h> | 20 | #include <asm/txx9/generic.h> |
22 | #include <asm/txx9/tx4938.h> | 21 | #include <asm/txx9/tx4938.h> |
23 | 22 | ||
24 | void __init tx4938_wdr_init(void) | 23 | static void __init tx4938_wdr_init(void) |
25 | { | 24 | { |
26 | /* clear WatchDogReset (W1C) */ | 25 | /* clear WatchDogReset (W1C) */ |
27 | tx4938_ccfg_set(TX4938_CCFG_WDRST); | 26 | tx4938_ccfg_set(TX4938_CCFG_WDRST); |
@@ -29,6 +28,11 @@ void __init tx4938_wdr_init(void) | |||
29 | tx4938_ccfg_set(TX4938_CCFG_WR); | 28 | tx4938_ccfg_set(TX4938_CCFG_WR); |
30 | } | 29 | } |
31 | 30 | ||
31 | void __init tx4938_wdt_init(void) | ||
32 | { | ||
33 | txx9_wdt_init(TX4938_TMR_REG(2) & 0xfffffffffULL); | ||
34 | } | ||
35 | |||
32 | static struct resource tx4938_sdram_resource[4]; | 36 | static struct resource tx4938_sdram_resource[4]; |
33 | static struct resource tx4938_sram_resource; | 37 | static struct resource tx4938_sram_resource; |
34 | 38 | ||
@@ -233,11 +237,9 @@ void __init tx4938_time_init(unsigned int tmrnr) | |||
233 | TXX9_IMCLK); | 237 | TXX9_IMCLK); |
234 | } | 238 | } |
235 | 239 | ||
236 | void __init tx4938_setup_serial(void) | 240 | void __init tx4938_sio_init(unsigned int sclk, unsigned int cts_mask) |
237 | { | 241 | { |
238 | #ifdef CONFIG_SERIAL_TXX9 | ||
239 | int i; | 242 | int i; |
240 | struct uart_port req; | ||
241 | unsigned int ch_mask = 0; | 243 | unsigned int ch_mask = 0; |
242 | 244 | ||
243 | if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_ETH0_SEL) | 245 | if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_ETH0_SEL) |
@@ -245,15 +247,24 @@ void __init tx4938_setup_serial(void) | |||
245 | for (i = 0; i < 2; i++) { | 247 | for (i = 0; i < 2; i++) { |
246 | if ((1 << i) & ch_mask) | 248 | if ((1 << i) & ch_mask) |
247 | continue; | 249 | continue; |
248 | memset(&req, 0, sizeof(req)); | 250 | txx9_sio_init(TX4938_SIO_REG(i) & 0xfffffffffULL, |
249 | req.line = i; | 251 | TXX9_IRQ_BASE + TX4938_IR_SIO(i), |
250 | req.iotype = UPIO_MEM; | 252 | i, sclk, (1 << i) & cts_mask); |
251 | req.membase = (unsigned char __iomem *)TX4938_SIO_REG(i); | ||
252 | req.mapbase = TX4938_SIO_REG(i) & 0xfffffffffULL; | ||
253 | req.irq = TXX9_IRQ_BASE + TX4938_IR_SIO(i); | ||
254 | req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; | ||
255 | req.uartclk = TXX9_IMCLK; | ||
256 | early_serial_txx9_setup(&req); | ||
257 | } | 253 | } |
258 | #endif /* CONFIG_SERIAL_TXX9 */ | 254 | } |
255 | |||
256 | void __init tx4938_spi_init(int busid) | ||
257 | { | ||
258 | txx9_spi_init(busid, TX4938_SPI_REG & 0xfffffffffULL, | ||
259 | TXX9_IRQ_BASE + TX4938_IR_SPI); | ||
260 | } | ||
261 | |||
262 | void __init tx4938_ethaddr_init(unsigned char *addr0, unsigned char *addr1) | ||
263 | { | ||
264 | u64 pcfg = __raw_readq(&tx4938_ccfgptr->pcfg); | ||
265 | |||
266 | if (addr0 && (pcfg & TX4938_PCFG_ETH0_SEL)) | ||
267 | txx9_ethaddr_init(TXX9_IRQ_BASE + TX4938_IR_ETH0, addr0); | ||
268 | if (addr1 && (pcfg & TX4938_PCFG_ETH1_SEL)) | ||
269 | txx9_ethaddr_init(TXX9_IRQ_BASE + TX4938_IR_ETH1, addr1); | ||
259 | } | 270 | } |
diff --git a/arch/mips/txx9/generic/smsc_fdc37m81x.c b/arch/mips/txx9/generic/smsc_fdc37m81x.c index 69e487467fa5..a2b2d62d88e3 100644 --- a/arch/mips/txx9/generic/smsc_fdc37m81x.c +++ b/arch/mips/txx9/generic/smsc_fdc37m81x.c | |||
@@ -15,8 +15,6 @@ | |||
15 | #include <asm/io.h> | 15 | #include <asm/io.h> |
16 | #include <asm/txx9/smsc_fdc37m81x.h> | 16 | #include <asm/txx9/smsc_fdc37m81x.h> |
17 | 17 | ||
18 | #define DEBUG | ||
19 | |||
20 | /* Common Registers */ | 18 | /* Common Registers */ |
21 | #define SMSC_FDC37M81X_CONFIG_INDEX 0x00 | 19 | #define SMSC_FDC37M81X_CONFIG_INDEX 0x00 |
22 | #define SMSC_FDC37M81X_CONFIG_DATA 0x01 | 20 | #define SMSC_FDC37M81X_CONFIG_DATA 0x01 |
@@ -55,7 +53,7 @@ | |||
55 | #define SMSC_FDC37M81X_CONFIG_EXIT 0xaa | 53 | #define SMSC_FDC37M81X_CONFIG_EXIT 0xaa |
56 | #define SMSC_FDC37M81X_CHIP_ID 0x4d | 54 | #define SMSC_FDC37M81X_CHIP_ID 0x4d |
57 | 55 | ||
58 | static unsigned long g_smsc_fdc37m81x_base = 0; | 56 | static unsigned long g_smsc_fdc37m81x_base; |
59 | 57 | ||
60 | static inline unsigned char smsc_fdc37m81x_rd(unsigned char index) | 58 | static inline unsigned char smsc_fdc37m81x_rd(unsigned char index) |
61 | { | 59 | { |
@@ -107,7 +105,8 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port) | |||
107 | u8 chip_id; | 105 | u8 chip_id; |
108 | 106 | ||
109 | if (g_smsc_fdc37m81x_base) | 107 | if (g_smsc_fdc37m81x_base) |
110 | printk("smsc_fdc37m81x_init() stepping on old base=0x%0*lx\n", | 108 | printk(KERN_WARNING "%s: stepping on old base=0x%0*lx\n", |
109 | __func__, | ||
111 | field, g_smsc_fdc37m81x_base); | 110 | field, g_smsc_fdc37m81x_base); |
112 | 111 | ||
113 | g_smsc_fdc37m81x_base = port; | 112 | g_smsc_fdc37m81x_base = port; |
@@ -118,7 +117,7 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port) | |||
118 | if (chip_id == SMSC_FDC37M81X_CHIP_ID) | 117 | if (chip_id == SMSC_FDC37M81X_CHIP_ID) |
119 | smsc_fdc37m81x_config_end(); | 118 | smsc_fdc37m81x_config_end(); |
120 | else { | 119 | else { |
121 | printk("smsc_fdc37m81x_init() unknow chip id 0x%02x\n", | 120 | printk(KERN_WARNING "%s: unknow chip id 0x%02x\n", __func__, |
122 | chip_id); | 121 | chip_id); |
123 | g_smsc_fdc37m81x_base = 0; | 122 | g_smsc_fdc37m81x_base = 0; |
124 | } | 123 | } |
@@ -127,22 +126,23 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port) | |||
127 | } | 126 | } |
128 | 127 | ||
129 | #ifdef DEBUG | 128 | #ifdef DEBUG |
130 | void smsc_fdc37m81x_config_dump_one(char *key, u8 dev, u8 reg) | 129 | static void smsc_fdc37m81x_config_dump_one(const char *key, u8 dev, u8 reg) |
131 | { | 130 | { |
132 | printk("%s: dev=0x%02x reg=0x%02x val=0x%02x\n", key, dev, reg, | 131 | printk(KERN_INFO "%s: dev=0x%02x reg=0x%02x val=0x%02x\n", |
132 | key, dev, reg, | ||
133 | smsc_fdc37m81x_rd(reg)); | 133 | smsc_fdc37m81x_rd(reg)); |
134 | } | 134 | } |
135 | 135 | ||
136 | void smsc_fdc37m81x_config_dump(void) | 136 | void smsc_fdc37m81x_config_dump(void) |
137 | { | 137 | { |
138 | u8 orig; | 138 | u8 orig; |
139 | char *fname = "smsc_fdc37m81x_config_dump()"; | 139 | const char *fname = __func__; |
140 | 140 | ||
141 | smsc_fdc37m81x_config_beg(); | 141 | smsc_fdc37m81x_config_beg(); |
142 | 142 | ||
143 | orig = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DNUM); | 143 | orig = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DNUM); |
144 | 144 | ||
145 | printk("%s: common\n", fname); | 145 | printk(KERN_INFO "%s: common\n", fname); |
146 | smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE, | 146 | smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE, |
147 | SMSC_FDC37M81X_DNUM); | 147 | SMSC_FDC37M81X_DNUM); |
148 | smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE, | 148 | smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE, |
@@ -154,7 +154,7 @@ void smsc_fdc37m81x_config_dump(void) | |||
154 | smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE, | 154 | smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE, |
155 | SMSC_FDC37M81X_PMGT); | 155 | SMSC_FDC37M81X_PMGT); |
156 | 156 | ||
157 | printk("%s: keyboard\n", fname); | 157 | printk(KERN_INFO "%s: keyboard\n", fname); |
158 | smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, SMSC_FDC37M81X_KBD); | 158 | smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, SMSC_FDC37M81X_KBD); |
159 | smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD, | 159 | smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD, |
160 | SMSC_FDC37M81X_ACTIVE); | 160 | SMSC_FDC37M81X_ACTIVE); |
diff --git a/arch/mips/txx9/jmr3927/Makefile b/arch/mips/txx9/jmr3927/Makefile index ba292c945669..20d61ac543e5 100644 --- a/arch/mips/txx9/jmr3927/Makefile +++ b/arch/mips/txx9/jmr3927/Makefile | |||
@@ -3,6 +3,5 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += prom.o irq.o setup.o | 5 | obj-y += prom.o irq.o setup.o |
6 | obj-$(CONFIG_KGDB) += kgdb_io.o | ||
7 | 6 | ||
8 | EXTRA_CFLAGS += -Werror | 7 | EXTRA_CFLAGS += -Werror |
diff --git a/arch/mips/txx9/jmr3927/irq.c b/arch/mips/txx9/jmr3927/irq.c index 070c9a115e57..6ec626c9473f 100644 --- a/arch/mips/txx9/jmr3927/irq.c +++ b/arch/mips/txx9/jmr3927/irq.c | |||
@@ -30,15 +30,11 @@ | |||
30 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 30 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
31 | */ | 31 | */ |
32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
33 | #include <linux/sched.h> | ||
34 | #include <linux/types.h> | 33 | #include <linux/types.h> |
35 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
36 | 35 | ||
37 | #include <asm/io.h> | 36 | #include <asm/io.h> |
38 | #include <asm/mipsregs.h> | 37 | #include <asm/mipsregs.h> |
39 | #include <asm/system.h> | ||
40 | |||
41 | #include <asm/processor.h> | ||
42 | #include <asm/txx9/generic.h> | 38 | #include <asm/txx9/generic.h> |
43 | #include <asm/txx9/jmr3927.h> | 39 | #include <asm/txx9/jmr3927.h> |
44 | 40 | ||
@@ -46,13 +42,6 @@ | |||
46 | #error JMR3927_IRQ_END > NR_IRQS | 42 | #error JMR3927_IRQ_END > NR_IRQS |
47 | #endif | 43 | #endif |
48 | 44 | ||
49 | static unsigned char irc_level[TX3927_NUM_IR] = { | ||
50 | 5, 5, 5, 5, 5, 5, /* INT[5:0] */ | ||
51 | 7, 7, /* SIO */ | ||
52 | 5, 5, 5, 0, 0, /* DMA, PIO, PCI */ | ||
53 | 6, 6, 6 /* TMR */ | ||
54 | }; | ||
55 | |||
56 | /* | 45 | /* |
57 | * CP0_STATUS is a thread's resource (saved/restored on context switch). | 46 | * CP0_STATUS is a thread's resource (saved/restored on context switch). |
58 | * So disable_irq/enable_irq MUST handle IOC/IRC registers. | 47 | * So disable_irq/enable_irq MUST handle IOC/IRC registers. |
@@ -103,26 +92,18 @@ static int jmr3927_irq_dispatch(int pending) | |||
103 | return irq; | 92 | return irq; |
104 | } | 93 | } |
105 | 94 | ||
106 | #ifdef CONFIG_PCI | 95 | static struct irq_chip jmr3927_irq_ioc = { |
107 | static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id) | 96 | .name = "jmr3927_ioc", |
108 | { | 97 | .ack = mask_irq_ioc, |
109 | printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq); | 98 | .mask = mask_irq_ioc, |
110 | printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n", | 99 | .mask_ack = mask_irq_ioc, |
111 | tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat); | 100 | .unmask = unmask_irq_ioc, |
112 | |||
113 | return IRQ_HANDLED; | ||
114 | } | ||
115 | static struct irqaction pcierr_action = { | ||
116 | .handler = jmr3927_pcierr_interrupt, | ||
117 | .mask = CPU_MASK_NONE, | ||
118 | .name = "PCI error", | ||
119 | }; | 101 | }; |
120 | #endif | ||
121 | |||
122 | static void __init jmr3927_irq_init(void); | ||
123 | 102 | ||
124 | void __init jmr3927_irq_setup(void) | 103 | void __init jmr3927_irq_setup(void) |
125 | { | 104 | { |
105 | int i; | ||
106 | |||
126 | txx9_irq_dispatch = jmr3927_irq_dispatch; | 107 | txx9_irq_dispatch = jmr3927_irq_dispatch; |
127 | /* Now, interrupt control disabled, */ | 108 | /* Now, interrupt control disabled, */ |
128 | /* all IRC interrupts are masked, */ | 109 | /* all IRC interrupts are masked, */ |
@@ -138,34 +119,10 @@ void __init jmr3927_irq_setup(void) | |||
138 | /* clear PCI Reset interrupts */ | 119 | /* clear PCI Reset interrupts */ |
139 | jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); | 120 | jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); |
140 | 121 | ||
141 | jmr3927_irq_init(); | 122 | tx3927_irq_init(); |
123 | for (i = JMR3927_IRQ_IOC; i < JMR3927_IRQ_IOC + JMR3927_NR_IRQ_IOC; i++) | ||
124 | set_irq_chip_and_handler(i, &jmr3927_irq_ioc, handle_level_irq); | ||
142 | 125 | ||
143 | /* setup IOC interrupt 1 (PCI, MODEM) */ | 126 | /* setup IOC interrupt 1 (PCI, MODEM) */ |
144 | set_irq_chained_handler(JMR3927_IRQ_IOCINT, handle_simple_irq); | 127 | set_irq_chained_handler(JMR3927_IRQ_IOCINT, handle_simple_irq); |
145 | |||
146 | #ifdef CONFIG_PCI | ||
147 | setup_irq(JMR3927_IRQ_IRC_PCI, &pcierr_action); | ||
148 | #endif | ||
149 | |||
150 | /* enable all CPU interrupt bits. */ | ||
151 | set_c0_status(ST0_IM); /* IE bit is still 0. */ | ||
152 | } | ||
153 | |||
154 | static struct irq_chip jmr3927_irq_ioc = { | ||
155 | .name = "jmr3927_ioc", | ||
156 | .ack = mask_irq_ioc, | ||
157 | .mask = mask_irq_ioc, | ||
158 | .mask_ack = mask_irq_ioc, | ||
159 | .unmask = unmask_irq_ioc, | ||
160 | }; | ||
161 | |||
162 | static void __init jmr3927_irq_init(void) | ||
163 | { | ||
164 | u32 i; | ||
165 | |||
166 | txx9_irq_init(TX3927_IRC_REG); | ||
167 | for (i = 0; i < TXx9_MAX_IR; i++) | ||
168 | txx9_irq_set_pri(i, irc_level[i]); | ||
169 | for (i = JMR3927_IRQ_IOC; i < JMR3927_IRQ_IOC + JMR3927_NR_IRQ_IOC; i++) | ||
170 | set_irq_chip_and_handler(i, &jmr3927_irq_ioc, handle_level_irq); | ||
171 | } | 128 | } |
diff --git a/arch/mips/txx9/jmr3927/kgdb_io.c b/arch/mips/txx9/jmr3927/kgdb_io.c deleted file mode 100644 index 5bd757e56f79..000000000000 --- a/arch/mips/txx9/jmr3927/kgdb_io.c +++ /dev/null | |||
@@ -1,105 +0,0 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Low level uart routines to directly access a TX[34]927 SIO. | ||
4 | * | ||
5 | * Copyright 2001 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * ahennessy@mvista.com or source@mvista.com | ||
8 | * | ||
9 | * Based on arch/mips/ddb5xxx/ddb5477/kgdb_io.c | ||
10 | * | ||
11 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
19 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
21 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
24 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
25 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License along | ||
30 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
31 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
32 | */ | ||
33 | |||
34 | #include <asm/txx9/jmr3927.h> | ||
35 | |||
36 | #define TIMEOUT 0xffffff | ||
37 | |||
38 | static int remoteDebugInitialized = 0; | ||
39 | static void debugInit(int baud); | ||
40 | |||
41 | int putDebugChar(unsigned char c) | ||
42 | { | ||
43 | int i = 0; | ||
44 | |||
45 | if (!remoteDebugInitialized) { | ||
46 | remoteDebugInitialized = 1; | ||
47 | debugInit(38400); | ||
48 | } | ||
49 | |||
50 | do { | ||
51 | slow_down(); | ||
52 | i++; | ||
53 | if (i>TIMEOUT) { | ||
54 | break; | ||
55 | } | ||
56 | } while (!(tx3927_sioptr(0)->cisr & TXx927_SICISR_TXALS)); | ||
57 | tx3927_sioptr(0)->tfifo = c; | ||
58 | |||
59 | return 1; | ||
60 | } | ||
61 | |||
62 | unsigned char getDebugChar(void) | ||
63 | { | ||
64 | int i = 0; | ||
65 | int dicr; | ||
66 | char c; | ||
67 | |||
68 | if (!remoteDebugInitialized) { | ||
69 | remoteDebugInitialized = 1; | ||
70 | debugInit(38400); | ||
71 | } | ||
72 | |||
73 | /* diable RX int. */ | ||
74 | dicr = tx3927_sioptr(0)->dicr; | ||
75 | tx3927_sioptr(0)->dicr = 0; | ||
76 | |||
77 | do { | ||
78 | slow_down(); | ||
79 | i++; | ||
80 | if (i>TIMEOUT) { | ||
81 | break; | ||
82 | } | ||
83 | } while (tx3927_sioptr(0)->disr & TXx927_SIDISR_UVALID) | ||
84 | ; | ||
85 | c = tx3927_sioptr(0)->rfifo; | ||
86 | |||
87 | /* clear RX int. status */ | ||
88 | tx3927_sioptr(0)->disr &= ~TXx927_SIDISR_RDIS; | ||
89 | /* enable RX int. */ | ||
90 | tx3927_sioptr(0)->dicr = dicr; | ||
91 | |||
92 | return c; | ||
93 | } | ||
94 | |||
95 | static void debugInit(int baud) | ||
96 | { | ||
97 | tx3927_sioptr(0)->lcr = 0x020; | ||
98 | tx3927_sioptr(0)->dicr = 0; | ||
99 | tx3927_sioptr(0)->disr = 0x4100; | ||
100 | tx3927_sioptr(0)->cisr = 0x014; | ||
101 | tx3927_sioptr(0)->fcr = 0; | ||
102 | tx3927_sioptr(0)->flcr = 0x02; | ||
103 | tx3927_sioptr(0)->bgr = ((JMR3927_BASE_BAUD + baud / 2) / baud) | | ||
104 | TXx927_SIBGR_BCLK_T0; | ||
105 | } | ||
diff --git a/arch/mips/txx9/jmr3927/prom.c b/arch/mips/txx9/jmr3927/prom.c index 2cadb423face..70c4c8ec3e84 100644 --- a/arch/mips/txx9/jmr3927/prom.c +++ b/arch/mips/txx9/jmr3927/prom.c | |||
@@ -36,41 +36,18 @@ | |||
36 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 36 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
37 | */ | 37 | */ |
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/kernel.h> | ||
39 | #include <asm/bootinfo.h> | 40 | #include <asm/bootinfo.h> |
40 | #include <asm/txx9/generic.h> | 41 | #include <asm/txx9/generic.h> |
41 | #include <asm/txx9/jmr3927.h> | 42 | #include <asm/txx9/jmr3927.h> |
42 | 43 | ||
43 | #define TIMEOUT 0xffffff | ||
44 | |||
45 | void | ||
46 | prom_putchar(char c) | ||
47 | { | ||
48 | int i = 0; | ||
49 | |||
50 | do { | ||
51 | i++; | ||
52 | if (i>TIMEOUT) | ||
53 | break; | ||
54 | } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); | ||
55 | tx3927_sioptr(1)->tfifo = c; | ||
56 | return; | ||
57 | } | ||
58 | |||
59 | void | ||
60 | puts(const char *cp) | ||
61 | { | ||
62 | while (*cp) | ||
63 | prom_putchar(*cp++); | ||
64 | prom_putchar('\r'); | ||
65 | prom_putchar('\n'); | ||
66 | } | ||
67 | |||
68 | void __init jmr3927_prom_init(void) | 44 | void __init jmr3927_prom_init(void) |
69 | { | 45 | { |
70 | /* CCFG */ | 46 | /* CCFG */ |
71 | if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0) | 47 | if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0) |
72 | puts("Warning: TX3927 TLB off\n"); | 48 | printk(KERN_ERR "TX3927 TLB off\n"); |
73 | 49 | ||
74 | prom_init_cmdline(); | 50 | prom_init_cmdline(); |
75 | add_memory_region(0, JMR3927_SDRAM_SIZE, BOOT_MEM_RAM); | 51 | add_memory_region(0, JMR3927_SDRAM_SIZE, BOOT_MEM_RAM); |
52 | txx9_sio_putchar_init(TX3927_SIO_REG(1)); | ||
76 | } | 53 | } |
diff --git a/arch/mips/txx9/jmr3927/setup.c b/arch/mips/txx9/jmr3927/setup.c index 03647ebe4130..87db41be8a56 100644 --- a/arch/mips/txx9/jmr3927/setup.c +++ b/arch/mips/txx9/jmr3927/setup.c | |||
@@ -32,27 +32,18 @@ | |||
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/ioport.h> | 33 | #include <linux/ioport.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/pm.h> | ||
36 | #include <linux/platform_device.h> | 35 | #include <linux/platform_device.h> |
37 | #include <linux/gpio.h> | 36 | #include <linux/gpio.h> |
38 | #ifdef CONFIG_SERIAL_TXX9 | ||
39 | #include <linux/serial_core.h> | ||
40 | #endif | ||
41 | #include <asm/txx9tmr.h> | ||
42 | #include <asm/txx9pio.h> | ||
43 | #include <asm/reboot.h> | 37 | #include <asm/reboot.h> |
38 | #include <asm/txx9pio.h> | ||
44 | #include <asm/txx9/generic.h> | 39 | #include <asm/txx9/generic.h> |
45 | #include <asm/txx9/pci.h> | 40 | #include <asm/txx9/pci.h> |
46 | #include <asm/txx9/jmr3927.h> | 41 | #include <asm/txx9/jmr3927.h> |
47 | #include <asm/mipsregs.h> | 42 | #include <asm/mipsregs.h> |
48 | 43 | ||
49 | extern void puts(const char *cp); | 44 | static void jmr3927_machine_restart(char *command) |
50 | |||
51 | /* don't enable - see errata */ | ||
52 | static int jmr3927_ccfg_toeon; | ||
53 | |||
54 | static inline void do_reset(void) | ||
55 | { | 45 | { |
46 | local_irq_disable(); | ||
56 | #if 1 /* Resetting PCI bus */ | 47 | #if 1 /* Resetting PCI bus */ |
57 | jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); | 48 | jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); |
58 | jmr3927_ioc_reg_out(JMR3927_IOC_RESET_PCI, JMR3927_IOC_RESET_ADDR); | 49 | jmr3927_ioc_reg_out(JMR3927_IOC_RESET_PCI, JMR3927_IOC_RESET_ADDR); |
@@ -61,33 +52,13 @@ static inline void do_reset(void) | |||
61 | jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); | 52 | jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); |
62 | #endif | 53 | #endif |
63 | jmr3927_ioc_reg_out(JMR3927_IOC_RESET_CPU, JMR3927_IOC_RESET_ADDR); | 54 | jmr3927_ioc_reg_out(JMR3927_IOC_RESET_CPU, JMR3927_IOC_RESET_ADDR); |
64 | } | 55 | /* fallback */ |
65 | 56 | (*_machine_halt)(); | |
66 | static void jmr3927_machine_restart(char *command) | ||
67 | { | ||
68 | local_irq_disable(); | ||
69 | puts("Rebooting..."); | ||
70 | do_reset(); | ||
71 | } | ||
72 | |||
73 | static void jmr3927_machine_halt(void) | ||
74 | { | ||
75 | puts("JMR-TX3927 halted.\n"); | ||
76 | while (1); | ||
77 | } | ||
78 | |||
79 | static void jmr3927_machine_power_off(void) | ||
80 | { | ||
81 | puts("JMR-TX3927 halted. Please turn off the power.\n"); | ||
82 | while (1); | ||
83 | } | 57 | } |
84 | 58 | ||
85 | static void __init jmr3927_time_init(void) | 59 | static void __init jmr3927_time_init(void) |
86 | { | 60 | { |
87 | txx9_clockevent_init(TX3927_TMR_REG(0), | 61 | tx3927_time_init(0, 1); |
88 | TXX9_IRQ_BASE + JMR3927_IRQ_IRC_TMR(0), | ||
89 | JMR3927_IMCLK); | ||
90 | txx9_clocksource_init(TX3927_TMR_REG(1), JMR3927_IMCLK); | ||
91 | } | 62 | } |
92 | 63 | ||
93 | #define DO_WRITE_THROUGH | 64 | #define DO_WRITE_THROUGH |
@@ -102,11 +73,6 @@ static void __init jmr3927_mem_setup(void) | |||
102 | set_io_port_base(JMR3927_PORT_BASE + JMR3927_PCIIO); | 73 | set_io_port_base(JMR3927_PORT_BASE + JMR3927_PCIIO); |
103 | 74 | ||
104 | _machine_restart = jmr3927_machine_restart; | 75 | _machine_restart = jmr3927_machine_restart; |
105 | _machine_halt = jmr3927_machine_halt; | ||
106 | pm_power_off = jmr3927_machine_power_off; | ||
107 | |||
108 | /* Reboot on panic */ | ||
109 | panic_timeout = 180; | ||
110 | 76 | ||
111 | /* cache setup */ | 77 | /* cache setup */ |
112 | { | 78 | { |
@@ -125,7 +91,8 @@ static void __init jmr3927_mem_setup(void) | |||
125 | #endif | 91 | #endif |
126 | 92 | ||
127 | conf = read_c0_conf(); | 93 | conf = read_c0_conf(); |
128 | conf &= ~(TX39_CONF_ICE | TX39_CONF_DCE | TX39_CONF_WBON | TX39_CONF_CWFON); | 94 | conf &= ~(TX39_CONF_ICE | TX39_CONF_DCE | |
95 | TX39_CONF_WBON | TX39_CONF_CWFON); | ||
129 | conf |= mips_ic_disable ? 0 : TX39_CONF_ICE; | 96 | conf |= mips_ic_disable ? 0 : TX39_CONF_ICE; |
130 | conf |= mips_dc_disable ? 0 : TX39_CONF_DCE; | 97 | conf |= mips_dc_disable ? 0 : TX39_CONF_DCE; |
131 | conf |= mips_config_wbon ? TX39_CONF_WBON : 0; | 98 | conf |= mips_config_wbon ? TX39_CONF_WBON : 0; |
@@ -138,47 +105,14 @@ static void __init jmr3927_mem_setup(void) | |||
138 | /* initialize board */ | 105 | /* initialize board */ |
139 | jmr3927_board_init(); | 106 | jmr3927_board_init(); |
140 | 107 | ||
141 | argptr = prom_getcmdline(); | 108 | tx3927_sio_init(0, 1 << 1); /* ch1: noCTS */ |
142 | |||
143 | if ((argptr = strstr(argptr, "toeon")) != NULL) | ||
144 | jmr3927_ccfg_toeon = 1; | ||
145 | argptr = prom_getcmdline(); | ||
146 | if ((argptr = strstr(argptr, "ip=")) == NULL) { | ||
147 | argptr = prom_getcmdline(); | ||
148 | strcat(argptr, " ip=bootp"); | ||
149 | } | ||
150 | |||
151 | #ifdef CONFIG_SERIAL_TXX9 | ||
152 | { | ||
153 | extern int early_serial_txx9_setup(struct uart_port *port); | ||
154 | int i; | ||
155 | struct uart_port req; | ||
156 | for(i = 0; i < 2; i++) { | ||
157 | memset(&req, 0, sizeof(req)); | ||
158 | req.line = i; | ||
159 | req.iotype = UPIO_MEM; | ||
160 | req.membase = (unsigned char __iomem *)TX3927_SIO_REG(i); | ||
161 | req.mapbase = TX3927_SIO_REG(i); | ||
162 | req.irq = i == 0 ? | ||
163 | JMR3927_IRQ_IRC_SIO0 : JMR3927_IRQ_IRC_SIO1; | ||
164 | if (i == 0) | ||
165 | req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; | ||
166 | req.uartclk = JMR3927_IMCLK; | ||
167 | early_serial_txx9_setup(&req); | ||
168 | } | ||
169 | } | ||
170 | #ifdef CONFIG_SERIAL_TXX9_CONSOLE | 109 | #ifdef CONFIG_SERIAL_TXX9_CONSOLE |
171 | argptr = prom_getcmdline(); | 110 | argptr = prom_getcmdline(); |
172 | if ((argptr = strstr(argptr, "console=")) == NULL) { | 111 | if (!strstr(argptr, "console=")) |
173 | argptr = prom_getcmdline(); | ||
174 | strcat(argptr, " console=ttyS1,115200"); | 112 | strcat(argptr, " console=ttyS1,115200"); |
175 | } | ||
176 | #endif | ||
177 | #endif | 113 | #endif |
178 | } | 114 | } |
179 | 115 | ||
180 | static void tx3927_setup(void); | ||
181 | |||
182 | static void __init jmr3927_pci_setup(void) | 116 | static void __init jmr3927_pci_setup(void) |
183 | { | 117 | { |
184 | #ifdef CONFIG_PCI | 118 | #ifdef CONFIG_PCI |
@@ -199,32 +133,13 @@ static void __init jmr3927_pci_setup(void) | |||
199 | jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); | 133 | jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); |
200 | } | 134 | } |
201 | tx3927_pcic_setup(c, JMR3927_SDRAM_SIZE, extarb); | 135 | tx3927_pcic_setup(c, JMR3927_SDRAM_SIZE, extarb); |
136 | tx3927_setup_pcierr_irq(); | ||
202 | #endif /* CONFIG_PCI */ | 137 | #endif /* CONFIG_PCI */ |
203 | } | 138 | } |
204 | 139 | ||
205 | static void __init jmr3927_board_init(void) | 140 | static void __init jmr3927_board_init(void) |
206 | { | 141 | { |
207 | tx3927_setup(); | ||
208 | jmr3927_pci_setup(); | ||
209 | |||
210 | /* SIO0 DTR on */ | ||
211 | jmr3927_ioc_reg_out(0, JMR3927_IOC_DTR_ADDR); | ||
212 | |||
213 | jmr3927_led_set(0); | ||
214 | |||
215 | printk("JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n", | ||
216 | jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK, | ||
217 | jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK, | ||
218 | jmr3927_dipsw1(), jmr3927_dipsw2(), | ||
219 | jmr3927_dipsw3(), jmr3927_dipsw4()); | ||
220 | } | ||
221 | |||
222 | static void __init tx3927_setup(void) | ||
223 | { | ||
224 | int i; | ||
225 | |||
226 | txx9_cpu_clock = JMR3927_CORECLK; | 142 | txx9_cpu_clock = JMR3927_CORECLK; |
227 | txx9_gbus_clock = JMR3927_GBUSCLK; | ||
228 | /* SDRAMC are configured by PROM */ | 143 | /* SDRAMC are configured by PROM */ |
229 | 144 | ||
230 | /* ROMC */ | 145 | /* ROMC */ |
@@ -233,74 +148,32 @@ static void __init tx3927_setup(void) | |||
233 | tx3927_romcptr->cr[3] = JMR3927_ROMCE3 | 0x0003f698; | 148 | tx3927_romcptr->cr[3] = JMR3927_ROMCE3 | 0x0003f698; |
234 | tx3927_romcptr->cr[5] = JMR3927_ROMCE5 | 0x0000f218; | 149 | tx3927_romcptr->cr[5] = JMR3927_ROMCE5 | 0x0000f218; |
235 | 150 | ||
236 | /* CCFG */ | ||
237 | /* enable Timeout BusError */ | ||
238 | if (jmr3927_ccfg_toeon) | ||
239 | tx3927_ccfgptr->ccfg |= TX3927_CCFG_TOE; | ||
240 | |||
241 | /* clear BusErrorOnWrite flag */ | ||
242 | tx3927_ccfgptr->ccfg &= ~TX3927_CCFG_BEOW; | ||
243 | /* Disable PCI snoop */ | ||
244 | tx3927_ccfgptr->ccfg &= ~TX3927_CCFG_PSNP; | ||
245 | /* do reset on watchdog */ | ||
246 | tx3927_ccfgptr->ccfg |= TX3927_CCFG_WR; | ||
247 | |||
248 | #ifdef DO_WRITE_THROUGH | ||
249 | /* Enable PCI SNOOP - with write through only */ | ||
250 | tx3927_ccfgptr->ccfg |= TX3927_CCFG_PSNP; | ||
251 | #endif | ||
252 | |||
253 | /* Pin selection */ | 151 | /* Pin selection */ |
254 | tx3927_ccfgptr->pcfg &= ~TX3927_PCFG_SELALL; | 152 | tx3927_ccfgptr->pcfg &= ~TX3927_PCFG_SELALL; |
255 | tx3927_ccfgptr->pcfg |= | 153 | tx3927_ccfgptr->pcfg |= |
256 | TX3927_PCFG_SELSIOC(0) | TX3927_PCFG_SELSIO_ALL | | 154 | TX3927_PCFG_SELSIOC(0) | TX3927_PCFG_SELSIO_ALL | |
257 | (TX3927_PCFG_SELDMA_ALL & ~TX3927_PCFG_SELDMA(1)); | 155 | (TX3927_PCFG_SELDMA_ALL & ~TX3927_PCFG_SELDMA(1)); |
258 | 156 | ||
259 | printk("TX3927 -- CRIR:%08lx CCFG:%08lx PCFG:%08lx\n", | 157 | tx3927_setup(); |
260 | tx3927_ccfgptr->crir, | ||
261 | tx3927_ccfgptr->ccfg, tx3927_ccfgptr->pcfg); | ||
262 | |||
263 | /* TMR */ | ||
264 | for (i = 0; i < TX3927_NR_TMR; i++) | ||
265 | txx9_tmr_init(TX3927_TMR_REG(i)); | ||
266 | |||
267 | /* DMA */ | ||
268 | tx3927_dmaptr->mcr = 0; | ||
269 | for (i = 0; i < ARRAY_SIZE(tx3927_dmaptr->ch); i++) { | ||
270 | /* reset channel */ | ||
271 | tx3927_dmaptr->ch[i].ccr = TX3927_DMA_CCR_CHRST; | ||
272 | tx3927_dmaptr->ch[i].ccr = 0; | ||
273 | } | ||
274 | /* enable DMA */ | ||
275 | #ifdef __BIG_ENDIAN | ||
276 | tx3927_dmaptr->mcr = TX3927_DMA_MCR_MSTEN; | ||
277 | #else | ||
278 | tx3927_dmaptr->mcr = TX3927_DMA_MCR_MSTEN | TX3927_DMA_MCR_LE; | ||
279 | #endif | ||
280 | 158 | ||
281 | /* PIO */ | ||
282 | /* PIO[15:12] connected to LEDs */ | 159 | /* PIO[15:12] connected to LEDs */ |
283 | __raw_writel(0x0000f000, &tx3927_pioptr->dir); | 160 | __raw_writel(0x0000f000, &tx3927_pioptr->dir); |
284 | __raw_writel(0, &tx3927_pioptr->maskcpu); | ||
285 | __raw_writel(0, &tx3927_pioptr->maskext); | ||
286 | txx9_gpio_init(TX3927_PIO_REG, 0, 16); | ||
287 | gpio_request(11, "dipsw1"); | 161 | gpio_request(11, "dipsw1"); |
288 | gpio_request(10, "dipsw2"); | 162 | gpio_request(10, "dipsw2"); |
289 | { | ||
290 | unsigned int conf; | ||
291 | 163 | ||
292 | conf = read_c0_conf(); | 164 | jmr3927_pci_setup(); |
293 | if (!(conf & TX39_CONF_ICE)) | 165 | |
294 | printk("TX3927 I-Cache disabled.\n"); | 166 | /* SIO0 DTR on */ |
295 | if (!(conf & TX39_CONF_DCE)) | 167 | jmr3927_ioc_reg_out(0, JMR3927_IOC_DTR_ADDR); |
296 | printk("TX3927 D-Cache disabled.\n"); | 168 | |
297 | else if (!(conf & TX39_CONF_WBON)) | 169 | jmr3927_led_set(0); |
298 | printk("TX3927 D-Cache WriteThrough.\n"); | 170 | |
299 | else if (!(conf & TX39_CONF_CWFON)) | 171 | printk(KERN_INFO |
300 | printk("TX3927 D-Cache WriteBack.\n"); | 172 | "JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n", |
301 | else | 173 | jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK, |
302 | printk("TX3927 D-Cache WriteBack (CWF) .\n"); | 174 | jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK, |
303 | } | 175 | jmr3927_dipsw1(), jmr3927_dipsw2(), |
176 | jmr3927_dipsw3(), jmr3927_dipsw4()); | ||
304 | } | 177 | } |
305 | 178 | ||
306 | /* This trick makes rtc-ds1742 driver usable as is. */ | 179 | /* This trick makes rtc-ds1742 driver usable as is. */ |
@@ -316,42 +189,21 @@ static unsigned long jmr3927_swizzle_addr_b(unsigned long port) | |||
316 | #endif | 189 | #endif |
317 | } | 190 | } |
318 | 191 | ||
319 | static int __init jmr3927_rtc_init(void) | 192 | static void __init jmr3927_rtc_init(void) |
320 | { | 193 | { |
321 | static struct resource __initdata res = { | 194 | static struct resource __initdata res = { |
322 | .start = JMR3927_IOC_NVRAMB_ADDR - IO_BASE, | 195 | .start = JMR3927_IOC_NVRAMB_ADDR - IO_BASE, |
323 | .end = JMR3927_IOC_NVRAMB_ADDR - IO_BASE + 0x800 - 1, | 196 | .end = JMR3927_IOC_NVRAMB_ADDR - IO_BASE + 0x800 - 1, |
324 | .flags = IORESOURCE_MEM, | 197 | .flags = IORESOURCE_MEM, |
325 | }; | 198 | }; |
326 | struct platform_device *dev; | 199 | platform_device_register_simple("rtc-ds1742", -1, &res, 1); |
327 | dev = platform_device_register_simple("rtc-ds1742", -1, &res, 1); | ||
328 | return IS_ERR(dev) ? PTR_ERR(dev) : 0; | ||
329 | } | ||
330 | |||
331 | /* Watchdog support */ | ||
332 | |||
333 | static int __init txx9_wdt_init(unsigned long base) | ||
334 | { | ||
335 | struct resource res = { | ||
336 | .start = base, | ||
337 | .end = base + 0x100 - 1, | ||
338 | .flags = IORESOURCE_MEM, | ||
339 | }; | ||
340 | struct platform_device *dev = | ||
341 | platform_device_register_simple("txx9wdt", -1, &res, 1); | ||
342 | return IS_ERR(dev) ? PTR_ERR(dev) : 0; | ||
343 | } | ||
344 | |||
345 | static int __init jmr3927_wdt_init(void) | ||
346 | { | ||
347 | return txx9_wdt_init(TX3927_TMR_REG(2)); | ||
348 | } | 200 | } |
349 | 201 | ||
350 | static void __init jmr3927_device_init(void) | 202 | static void __init jmr3927_device_init(void) |
351 | { | 203 | { |
352 | __swizzle_addr_b = jmr3927_swizzle_addr_b; | 204 | __swizzle_addr_b = jmr3927_swizzle_addr_b; |
353 | jmr3927_rtc_init(); | 205 | jmr3927_rtc_init(); |
354 | jmr3927_wdt_init(); | 206 | tx3927_wdt_init(); |
355 | } | 207 | } |
356 | 208 | ||
357 | struct txx9_board_vec jmr3927_vec __initdata = { | 209 | struct txx9_board_vec jmr3927_vec __initdata = { |
diff --git a/arch/mips/txx9/rbtx4927/irq.c b/arch/mips/txx9/rbtx4927/irq.c index cd748a930328..00cd5231da30 100644 --- a/arch/mips/txx9/rbtx4927/irq.c +++ b/arch/mips/txx9/rbtx4927/irq.c | |||
@@ -27,85 +27,86 @@ | |||
27 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 27 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
28 | */ | 28 | */ |
29 | /* | 29 | /* |
30 | IRQ Device | 30 | * I8259A_IRQ_BASE+00 |
31 | 00 RBTX4927-ISA/00 | 31 | * I8259A_IRQ_BASE+01 PS2/Keyboard |
32 | 01 RBTX4927-ISA/01 PS2/Keyboard | 32 | * I8259A_IRQ_BASE+02 Cascade RBTX4927-ISA (irqs 8-15) |
33 | 02 RBTX4927-ISA/02 Cascade RBTX4927-ISA (irqs 8-15) | 33 | * I8259A_IRQ_BASE+03 |
34 | 03 RBTX4927-ISA/03 | 34 | * I8259A_IRQ_BASE+04 |
35 | 04 RBTX4927-ISA/04 | 35 | * I8259A_IRQ_BASE+05 |
36 | 05 RBTX4927-ISA/05 | 36 | * I8259A_IRQ_BASE+06 |
37 | 06 RBTX4927-ISA/06 | 37 | * I8259A_IRQ_BASE+07 |
38 | 07 RBTX4927-ISA/07 | 38 | * I8259A_IRQ_BASE+08 |
39 | 08 RBTX4927-ISA/08 | 39 | * I8259A_IRQ_BASE+09 |
40 | 09 RBTX4927-ISA/09 | 40 | * I8259A_IRQ_BASE+10 |
41 | 10 RBTX4927-ISA/10 | 41 | * I8259A_IRQ_BASE+11 |
42 | 11 RBTX4927-ISA/11 | 42 | * I8259A_IRQ_BASE+12 PS2/Mouse (not supported at this time) |
43 | 12 RBTX4927-ISA/12 PS2/Mouse (not supported at this time) | 43 | * I8259A_IRQ_BASE+13 |
44 | 13 RBTX4927-ISA/13 | 44 | * I8259A_IRQ_BASE+14 IDE |
45 | 14 RBTX4927-ISA/14 IDE | 45 | * I8259A_IRQ_BASE+15 |
46 | 15 RBTX4927-ISA/15 | 46 | * |
47 | 47 | * MIPS_CPU_IRQ_BASE+00 Software 0 | |
48 | 16 TX4927-CP0/00 Software 0 | 48 | * MIPS_CPU_IRQ_BASE+01 Software 1 |
49 | 17 TX4927-CP0/01 Software 1 | 49 | * MIPS_CPU_IRQ_BASE+02 Cascade TX4927-CP0 |
50 | 18 TX4927-CP0/02 Cascade TX4927-CP0 | 50 | * MIPS_CPU_IRQ_BASE+03 Multiplexed -- do not use |
51 | 19 TX4927-CP0/03 Multiplexed -- do not use | 51 | * MIPS_CPU_IRQ_BASE+04 Multiplexed -- do not use |
52 | 20 TX4927-CP0/04 Multiplexed -- do not use | 52 | * MIPS_CPU_IRQ_BASE+05 Multiplexed -- do not use |
53 | 21 TX4927-CP0/05 Multiplexed -- do not use | 53 | * MIPS_CPU_IRQ_BASE+06 Multiplexed -- do not use |
54 | 22 TX4927-CP0/06 Multiplexed -- do not use | 54 | * MIPS_CPU_IRQ_BASE+07 CPU TIMER |
55 | 23 TX4927-CP0/07 CPU TIMER | 55 | * |
56 | 56 | * TXX9_IRQ_BASE+00 | |
57 | 24 TX4927-PIC/00 | 57 | * TXX9_IRQ_BASE+01 |
58 | 25 TX4927-PIC/01 | 58 | * TXX9_IRQ_BASE+02 |
59 | 26 TX4927-PIC/02 | 59 | * TXX9_IRQ_BASE+03 Cascade RBTX4927-IOC |
60 | 27 TX4927-PIC/03 Cascade RBTX4927-IOC | 60 | * TXX9_IRQ_BASE+04 |
61 | 28 TX4927-PIC/04 | 61 | * TXX9_IRQ_BASE+05 RBTX4927 RTL-8019AS ethernet |
62 | 29 TX4927-PIC/05 RBTX4927 RTL-8019AS ethernet | 62 | * TXX9_IRQ_BASE+06 |
63 | 30 TX4927-PIC/06 | 63 | * TXX9_IRQ_BASE+07 |
64 | 31 TX4927-PIC/07 | 64 | * TXX9_IRQ_BASE+08 TX4927 SerialIO Channel 0 |
65 | 32 TX4927-PIC/08 TX4927 SerialIO Channel 0 | 65 | * TXX9_IRQ_BASE+09 TX4927 SerialIO Channel 1 |
66 | 33 TX4927-PIC/09 TX4927 SerialIO Channel 1 | 66 | * TXX9_IRQ_BASE+10 |
67 | 34 TX4927-PIC/10 | 67 | * TXX9_IRQ_BASE+11 |
68 | 35 TX4927-PIC/11 | 68 | * TXX9_IRQ_BASE+12 |
69 | 36 TX4927-PIC/12 | 69 | * TXX9_IRQ_BASE+13 |
70 | 37 TX4927-PIC/13 | 70 | * TXX9_IRQ_BASE+14 |
71 | 38 TX4927-PIC/14 | 71 | * TXX9_IRQ_BASE+15 |
72 | 39 TX4927-PIC/15 | 72 | * TXX9_IRQ_BASE+16 TX4927 PCI PCI-C |
73 | 40 TX4927-PIC/16 TX4927 PCI PCI-C | 73 | * TXX9_IRQ_BASE+17 |
74 | 41 TX4927-PIC/17 | 74 | * TXX9_IRQ_BASE+18 |
75 | 42 TX4927-PIC/18 | 75 | * TXX9_IRQ_BASE+19 |
76 | 43 TX4927-PIC/19 | 76 | * TXX9_IRQ_BASE+20 |
77 | 44 TX4927-PIC/20 | 77 | * TXX9_IRQ_BASE+21 |
78 | 45 TX4927-PIC/21 | 78 | * TXX9_IRQ_BASE+22 TX4927 PCI PCI-ERR |
79 | 46 TX4927-PIC/22 TX4927 PCI PCI-ERR | 79 | * TXX9_IRQ_BASE+23 TX4927 PCI PCI-PMA (not used) |
80 | 47 TX4927-PIC/23 TX4927 PCI PCI-PMA (not used) | 80 | * TXX9_IRQ_BASE+24 |
81 | 48 TX4927-PIC/24 | 81 | * TXX9_IRQ_BASE+25 |
82 | 49 TX4927-PIC/25 | 82 | * TXX9_IRQ_BASE+26 |
83 | 50 TX4927-PIC/26 | 83 | * TXX9_IRQ_BASE+27 |
84 | 51 TX4927-PIC/27 | 84 | * TXX9_IRQ_BASE+28 |
85 | 52 TX4927-PIC/28 | 85 | * TXX9_IRQ_BASE+29 |
86 | 53 TX4927-PIC/29 | 86 | * TXX9_IRQ_BASE+30 |
87 | 54 TX4927-PIC/30 | 87 | * TXX9_IRQ_BASE+31 |
88 | 55 TX4927-PIC/31 | 88 | * |
89 | 89 | * RBTX4927_IRQ_IOC+00 FPCIB0 PCI-D (SouthBridge) | |
90 | 56 RBTX4927-IOC/00 FPCIB0 PCI-D PJ4/A PJ5/B SB/C PJ6/D PJ7/A (SouthBridge/NotUsed) [RTL-8139=PJ4] | 90 | * RBTX4927_IRQ_IOC+01 FPCIB0 PCI-C (SouthBridge) |
91 | 57 RBTX4927-IOC/01 FPCIB0 PCI-C PJ4/D PJ5/A SB/B PJ6/C PJ7/D (SouthBridge/NotUsed) [RTL-8139=PJ5] | 91 | * RBTX4927_IRQ_IOC+02 FPCIB0 PCI-B (SouthBridge/IDE/pin=1,INTR) |
92 | 58 RBTX4927-IOC/02 FPCIB0 PCI-B PJ4/C PJ5/D SB/A PJ6/B PJ7/C (SouthBridge/IDE/pin=1,INTR) [RTL-8139=NotSupported] | 92 | * RBTX4927_IRQ_IOC+03 FPCIB0 PCI-A (SouthBridge/USB/pin=4) |
93 | 59 RBTX4927-IOC/03 FPCIB0 PCI-A PJ4/B PJ5/C SB/D PJ6/A PJ7/B (SouthBridge/USB/pin=4) [RTL-8139=PJ6] | 93 | * RBTX4927_IRQ_IOC+04 |
94 | 60 RBTX4927-IOC/04 | 94 | * RBTX4927_IRQ_IOC+05 |
95 | 61 RBTX4927-IOC/05 | 95 | * RBTX4927_IRQ_IOC+06 |
96 | 62 RBTX4927-IOC/06 | 96 | * RBTX4927_IRQ_IOC+07 |
97 | 63 RBTX4927-IOC/07 | 97 | * |
98 | 98 | * NOTES: | |
99 | NOTES: | 99 | * SouthBridge/INTR is mapped to SouthBridge/A=PCI-B/#58 |
100 | SouthBridge/INTR is mapped to SouthBridge/A=PCI-B/#58 | 100 | * SouthBridge/ISA/pin=0 no pci irq used by this device |
101 | SouthBridge/ISA/pin=0 no pci irq used by this device | 101 | * SouthBridge/IDE/pin=1 no pci irq used by this device, using INTR |
102 | SouthBridge/IDE/pin=1 no pci irq used by this device, using INTR via ISA IRQ14 | 102 | * via ISA IRQ14 |
103 | SouthBridge/USB/pin=4 using pci irq SouthBridge/D=PCI-A=#59 | 103 | * SouthBridge/USB/pin=4 using pci irq SouthBridge/D=PCI-A=#59 |
104 | SouthBridge/PMC/pin=0 no pci irq used by this device | 104 | * SouthBridge/PMC/pin=0 no pci irq used by this device |
105 | SuperIO/PS2/Keyboard, using INTR via ISA IRQ1 | 105 | * SuperIO/PS2/Keyboard, using INTR via ISA IRQ1 |
106 | SuperIO/PS2/Mouse, using INTR via ISA IRQ12 (mouse not currently supported) | 106 | * SuperIO/PS2/Mouse, using INTR via ISA IRQ12 (mouse not currently supported) |
107 | JP7 is not bus master -- do NOT use -- only 4 pci bus master's allowed -- SouthBridge, JP4, JP5, JP6 | 107 | * JP7 is not bus master -- do NOT use -- only 4 pci bus master's |
108 | */ | 108 | * allowed -- SouthBridge, JP4, JP5, JP6 |
109 | */ | ||
109 | 110 | ||
110 | #include <linux/init.h> | 111 | #include <linux/init.h> |
111 | #include <linux/types.h> | 112 | #include <linux/types.h> |
@@ -134,7 +135,7 @@ static int toshiba_rbtx4927_irq_nested(int sw_irq) | |||
134 | level3 = readb(rbtx4927_imstat_addr) & 0x1f; | 135 | level3 = readb(rbtx4927_imstat_addr) & 0x1f; |
135 | if (level3) | 136 | if (level3) |
136 | sw_irq = RBTX4927_IRQ_IOC + fls(level3) - 1; | 137 | sw_irq = RBTX4927_IRQ_IOC + fls(level3) - 1; |
137 | return (sw_irq); | 138 | return sw_irq; |
138 | } | 139 | } |
139 | 140 | ||
140 | static void __init toshiba_rbtx4927_irq_ioc_init(void) | 141 | static void __init toshiba_rbtx4927_irq_ioc_init(void) |
diff --git a/arch/mips/txx9/rbtx4927/prom.c b/arch/mips/txx9/rbtx4927/prom.c index 5c0de54ebdd2..1dc0a5b1956b 100644 --- a/arch/mips/txx9/rbtx4927/prom.c +++ b/arch/mips/txx9/rbtx4927/prom.c | |||
@@ -38,4 +38,5 @@ void __init rbtx4927_prom_init(void) | |||
38 | { | 38 | { |
39 | prom_init_cmdline(); | 39 | prom_init_cmdline(); |
40 | add_memory_region(0, tx4927_get_mem_size(), BOOT_MEM_RAM); | 40 | add_memory_region(0, tx4927_get_mem_size(), BOOT_MEM_RAM); |
41 | txx9_sio_putchar_init(TX4927_SIO_REG(0) & 0xfffffffffULL); | ||
41 | } | 42 | } |
diff --git a/arch/mips/txx9/rbtx4927/setup.c b/arch/mips/txx9/rbtx4927/setup.c index 3da20ea3e55c..0d39bafea794 100644 --- a/arch/mips/txx9/rbtx4927/setup.c +++ b/arch/mips/txx9/rbtx4927/setup.c | |||
@@ -46,12 +46,9 @@ | |||
46 | #include <linux/kernel.h> | 46 | #include <linux/kernel.h> |
47 | #include <linux/types.h> | 47 | #include <linux/types.h> |
48 | #include <linux/ioport.h> | 48 | #include <linux/ioport.h> |
49 | #include <linux/interrupt.h> | ||
50 | #include <linux/pm.h> | ||
51 | #include <linux/platform_device.h> | 49 | #include <linux/platform_device.h> |
52 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
53 | #include <asm/io.h> | 51 | #include <asm/io.h> |
54 | #include <asm/processor.h> | ||
55 | #include <asm/reboot.h> | 52 | #include <asm/reboot.h> |
56 | #include <asm/txx9/generic.h> | 53 | #include <asm/txx9/generic.h> |
57 | #include <asm/txx9/pci.h> | 54 | #include <asm/txx9/pci.h> |
@@ -103,6 +100,7 @@ static void __init tx4927_pci_setup(void) | |||
103 | tx4927_report_pciclk(); | 100 | tx4927_report_pciclk(); |
104 | tx4927_pcic_setup(tx4927_pcicptr, c, extarb); | 101 | tx4927_pcic_setup(tx4927_pcicptr, c, extarb); |
105 | } | 102 | } |
103 | tx4927_setup_pcierr_irq(); | ||
106 | } | 104 | } |
107 | 105 | ||
108 | static void __init tx4937_pci_setup(void) | 106 | static void __init tx4937_pci_setup(void) |
@@ -149,6 +147,7 @@ static void __init tx4937_pci_setup(void) | |||
149 | tx4938_report_pciclk(); | 147 | tx4938_report_pciclk(); |
150 | tx4927_pcic_setup(tx4938_pcicptr, c, extarb); | 148 | tx4927_pcic_setup(tx4938_pcicptr, c, extarb); |
151 | } | 149 | } |
150 | tx4938_setup_pcierr_irq(); | ||
152 | } | 151 | } |
153 | 152 | ||
154 | static void __init rbtx4927_arch_init(void) | 153 | static void __init rbtx4927_arch_init(void) |
@@ -165,17 +164,8 @@ static void __init rbtx4937_arch_init(void) | |||
165 | #define rbtx4937_arch_init NULL | 164 | #define rbtx4937_arch_init NULL |
166 | #endif /* CONFIG_PCI */ | 165 | #endif /* CONFIG_PCI */ |
167 | 166 | ||
168 | static void __noreturn wait_forever(void) | ||
169 | { | ||
170 | while (1) | ||
171 | if (cpu_wait) | ||
172 | (*cpu_wait)(); | ||
173 | } | ||
174 | |||
175 | static void toshiba_rbtx4927_restart(char *command) | 167 | static void toshiba_rbtx4927_restart(char *command) |
176 | { | 168 | { |
177 | printk(KERN_NOTICE "System Rebooting...\n"); | ||
178 | |||
179 | /* enable the s/w reset register */ | 169 | /* enable the s/w reset register */ |
180 | writeb(1, rbtx4927_softresetlock_addr); | 170 | writeb(1, rbtx4927_softresetlock_addr); |
181 | 171 | ||
@@ -186,24 +176,8 @@ static void toshiba_rbtx4927_restart(char *command) | |||
186 | /* do a s/w reset */ | 176 | /* do a s/w reset */ |
187 | writeb(1, rbtx4927_softreset_addr); | 177 | writeb(1, rbtx4927_softreset_addr); |
188 | 178 | ||
189 | /* do something passive while waiting for reset */ | 179 | /* fallback */ |
190 | local_irq_disable(); | 180 | (*_machine_halt)(); |
191 | wait_forever(); | ||
192 | /* no return */ | ||
193 | } | ||
194 | |||
195 | static void toshiba_rbtx4927_halt(void) | ||
196 | { | ||
197 | printk(KERN_NOTICE "System Halted\n"); | ||
198 | local_irq_disable(); | ||
199 | wait_forever(); | ||
200 | /* no return */ | ||
201 | } | ||
202 | |||
203 | static void toshiba_rbtx4927_power_off(void) | ||
204 | { | ||
205 | toshiba_rbtx4927_halt(); | ||
206 | /* no return */ | ||
207 | } | 181 | } |
208 | 182 | ||
209 | static void __init rbtx4927_clock_init(void); | 183 | static void __init rbtx4927_clock_init(void); |
@@ -214,9 +188,6 @@ static void __init rbtx4927_mem_setup(void) | |||
214 | u32 cp0_config; | 188 | u32 cp0_config; |
215 | char *argptr; | 189 | char *argptr; |
216 | 190 | ||
217 | /* f/w leaves this on at startup */ | ||
218 | clear_c0_status(ST0_ERL); | ||
219 | |||
220 | /* enable caches -- HCP5 does this, pmon does not */ | 191 | /* enable caches -- HCP5 does this, pmon does not */ |
221 | cp0_config = read_c0_config(); | 192 | cp0_config = read_c0_config(); |
222 | cp0_config = cp0_config & ~(TX49_CONF_IC | TX49_CONF_DC); | 193 | cp0_config = cp0_config & ~(TX49_CONF_IC | TX49_CONF_DC); |
@@ -231,37 +202,21 @@ static void __init rbtx4927_mem_setup(void) | |||
231 | } | 202 | } |
232 | 203 | ||
233 | _machine_restart = toshiba_rbtx4927_restart; | 204 | _machine_restart = toshiba_rbtx4927_restart; |
234 | _machine_halt = toshiba_rbtx4927_halt; | ||
235 | pm_power_off = toshiba_rbtx4927_power_off; | ||
236 | 205 | ||
237 | #ifdef CONFIG_PCI | 206 | #ifdef CONFIG_PCI |
238 | txx9_alloc_pci_controller(&txx9_primary_pcic, | 207 | txx9_alloc_pci_controller(&txx9_primary_pcic, |
239 | RBTX4927_PCIMEM, RBTX4927_PCIMEM_SIZE, | 208 | RBTX4927_PCIMEM, RBTX4927_PCIMEM_SIZE, |
240 | RBTX4927_PCIIO, RBTX4927_PCIIO_SIZE); | 209 | RBTX4927_PCIIO, RBTX4927_PCIIO_SIZE); |
210 | txx9_board_pcibios_setup = tx4927_pcibios_setup; | ||
241 | #else | 211 | #else |
242 | set_io_port_base(KSEG1 + RBTX4927_ISA_IO_OFFSET); | 212 | set_io_port_base(KSEG1 + RBTX4927_ISA_IO_OFFSET); |
243 | #endif | 213 | #endif |
244 | 214 | ||
245 | tx4927_setup_serial(); | 215 | tx4927_sio_init(0, 0); |
246 | #ifdef CONFIG_SERIAL_TXX9_CONSOLE | 216 | #ifdef CONFIG_SERIAL_TXX9_CONSOLE |
247 | argptr = prom_getcmdline(); | 217 | argptr = prom_getcmdline(); |
248 | if (strstr(argptr, "console=") == NULL) { | 218 | if (!strstr(argptr, "console=")) |
249 | strcat(argptr, " console=ttyS0,38400"); | 219 | strcat(argptr, " console=ttyS0,38400"); |
250 | } | ||
251 | #endif | ||
252 | |||
253 | #ifdef CONFIG_ROOT_NFS | ||
254 | argptr = prom_getcmdline(); | ||
255 | if (strstr(argptr, "root=") == NULL) { | ||
256 | strcat(argptr, " root=/dev/nfs rw"); | ||
257 | } | ||
258 | #endif | ||
259 | |||
260 | #ifdef CONFIG_IP_PNP | ||
261 | argptr = prom_getcmdline(); | ||
262 | if (strstr(argptr, "ip=") == NULL) { | ||
263 | strcat(argptr, " ip=any"); | ||
264 | } | ||
265 | #endif | 220 | #endif |
266 | } | 221 | } |
267 | 222 | ||
@@ -324,19 +279,17 @@ static void __init rbtx4927_time_init(void) | |||
324 | tx4927_time_init(0); | 279 | tx4927_time_init(0); |
325 | } | 280 | } |
326 | 281 | ||
327 | static int __init toshiba_rbtx4927_rtc_init(void) | 282 | static void __init toshiba_rbtx4927_rtc_init(void) |
328 | { | 283 | { |
329 | struct resource res = { | 284 | struct resource res = { |
330 | .start = RBTX4927_BRAMRTC_BASE - IO_BASE, | 285 | .start = RBTX4927_BRAMRTC_BASE - IO_BASE, |
331 | .end = RBTX4927_BRAMRTC_BASE - IO_BASE + 0x800 - 1, | 286 | .end = RBTX4927_BRAMRTC_BASE - IO_BASE + 0x800 - 1, |
332 | .flags = IORESOURCE_MEM, | 287 | .flags = IORESOURCE_MEM, |
333 | }; | 288 | }; |
334 | struct platform_device *dev = | 289 | platform_device_register_simple("rtc-ds1742", -1, &res, 1); |
335 | platform_device_register_simple("rtc-ds1742", -1, &res, 1); | ||
336 | return IS_ERR(dev) ? PTR_ERR(dev) : 0; | ||
337 | } | 290 | } |
338 | 291 | ||
339 | static int __init rbtx4927_ne_init(void) | 292 | static void __init rbtx4927_ne_init(void) |
340 | { | 293 | { |
341 | struct resource res[] = { | 294 | struct resource res[] = { |
342 | { | 295 | { |
@@ -348,36 +301,14 @@ static int __init rbtx4927_ne_init(void) | |||
348 | .flags = IORESOURCE_IRQ, | 301 | .flags = IORESOURCE_IRQ, |
349 | } | 302 | } |
350 | }; | 303 | }; |
351 | struct platform_device *dev = | 304 | platform_device_register_simple("ne", -1, res, ARRAY_SIZE(res)); |
352 | platform_device_register_simple("ne", -1, | ||
353 | res, ARRAY_SIZE(res)); | ||
354 | return IS_ERR(dev) ? PTR_ERR(dev) : 0; | ||
355 | } | ||
356 | |||
357 | /* Watchdog support */ | ||
358 | |||
359 | static int __init txx9_wdt_init(unsigned long base) | ||
360 | { | ||
361 | struct resource res = { | ||
362 | .start = base, | ||
363 | .end = base + 0x100 - 1, | ||
364 | .flags = IORESOURCE_MEM, | ||
365 | }; | ||
366 | struct platform_device *dev = | ||
367 | platform_device_register_simple("txx9wdt", -1, &res, 1); | ||
368 | return IS_ERR(dev) ? PTR_ERR(dev) : 0; | ||
369 | } | ||
370 | |||
371 | static int __init rbtx4927_wdt_init(void) | ||
372 | { | ||
373 | return txx9_wdt_init(TX4927_TMR_REG(2) & 0xfffffffffULL); | ||
374 | } | 305 | } |
375 | 306 | ||
376 | static void __init rbtx4927_device_init(void) | 307 | static void __init rbtx4927_device_init(void) |
377 | { | 308 | { |
378 | toshiba_rbtx4927_rtc_init(); | 309 | toshiba_rbtx4927_rtc_init(); |
379 | rbtx4927_ne_init(); | 310 | rbtx4927_ne_init(); |
380 | rbtx4927_wdt_init(); | 311 | tx4927_wdt_init(); |
381 | } | 312 | } |
382 | 313 | ||
383 | struct txx9_board_vec rbtx4927_vec __initdata = { | 314 | struct txx9_board_vec rbtx4927_vec __initdata = { |
diff --git a/arch/mips/txx9/rbtx4938/irq.c b/arch/mips/txx9/rbtx4938/irq.c index 3971a061657a..ca2f8306ce93 100644 --- a/arch/mips/txx9/rbtx4938/irq.c +++ b/arch/mips/txx9/rbtx4938/irq.c | |||
@@ -11,59 +11,57 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | /* | 13 | /* |
14 | IRQ Device | 14 | * MIPS_CPU_IRQ_BASE+00 Software 0 |
15 | 15 | * MIPS_CPU_IRQ_BASE+01 Software 1 | |
16 | 16 TX4938-CP0/00 Software 0 | 16 | * MIPS_CPU_IRQ_BASE+02 Cascade TX4938-CP0 |
17 | 17 TX4938-CP0/01 Software 1 | 17 | * MIPS_CPU_IRQ_BASE+03 Multiplexed -- do not use |
18 | 18 TX4938-CP0/02 Cascade TX4938-CP0 | 18 | * MIPS_CPU_IRQ_BASE+04 Multiplexed -- do not use |
19 | 19 TX4938-CP0/03 Multiplexed -- do not use | 19 | * MIPS_CPU_IRQ_BASE+05 Multiplexed -- do not use |
20 | 20 TX4938-CP0/04 Multiplexed -- do not use | 20 | * MIPS_CPU_IRQ_BASE+06 Multiplexed -- do not use |
21 | 21 TX4938-CP0/05 Multiplexed -- do not use | 21 | * MIPS_CPU_IRQ_BASE+07 CPU TIMER |
22 | 22 TX4938-CP0/06 Multiplexed -- do not use | 22 | * |
23 | 23 TX4938-CP0/07 CPU TIMER | 23 | * TXX9_IRQ_BASE+00 |
24 | 24 | * TXX9_IRQ_BASE+01 | |
25 | 24 TX4938-PIC/00 | 25 | * TXX9_IRQ_BASE+02 Cascade RBTX4938-IOC |
26 | 25 TX4938-PIC/01 | 26 | * TXX9_IRQ_BASE+03 RBTX4938 RTL-8019AS Ethernet |
27 | 26 TX4938-PIC/02 Cascade RBTX4938-IOC | 27 | * TXX9_IRQ_BASE+04 |
28 | 27 TX4938-PIC/03 RBTX4938 RTL-8019AS Ethernet | 28 | * TXX9_IRQ_BASE+05 TX4938 ETH1 |
29 | 28 TX4938-PIC/04 | 29 | * TXX9_IRQ_BASE+06 TX4938 ETH0 |
30 | 29 TX4938-PIC/05 TX4938 ETH1 | 30 | * TXX9_IRQ_BASE+07 |
31 | 30 TX4938-PIC/06 TX4938 ETH0 | 31 | * TXX9_IRQ_BASE+08 TX4938 SIO 0 |
32 | 31 TX4938-PIC/07 | 32 | * TXX9_IRQ_BASE+09 TX4938 SIO 1 |
33 | 32 TX4938-PIC/08 TX4938 SIO 0 | 33 | * TXX9_IRQ_BASE+10 TX4938 DMA0 |
34 | 33 TX4938-PIC/09 TX4938 SIO 1 | 34 | * TXX9_IRQ_BASE+11 TX4938 DMA1 |
35 | 34 TX4938-PIC/10 TX4938 DMA0 | 35 | * TXX9_IRQ_BASE+12 TX4938 DMA2 |
36 | 35 TX4938-PIC/11 TX4938 DMA1 | 36 | * TXX9_IRQ_BASE+13 TX4938 DMA3 |
37 | 36 TX4938-PIC/12 TX4938 DMA2 | 37 | * TXX9_IRQ_BASE+14 |
38 | 37 TX4938-PIC/13 TX4938 DMA3 | 38 | * TXX9_IRQ_BASE+15 |
39 | 38 TX4938-PIC/14 | 39 | * TXX9_IRQ_BASE+16 TX4938 PCIC |
40 | 39 TX4938-PIC/15 | 40 | * TXX9_IRQ_BASE+17 TX4938 TMR0 |
41 | 40 TX4938-PIC/16 TX4938 PCIC | 41 | * TXX9_IRQ_BASE+18 TX4938 TMR1 |
42 | 41 TX4938-PIC/17 TX4938 TMR0 | 42 | * TXX9_IRQ_BASE+19 TX4938 TMR2 |
43 | 42 TX4938-PIC/18 TX4938 TMR1 | 43 | * TXX9_IRQ_BASE+20 |
44 | 43 TX4938-PIC/19 TX4938 TMR2 | 44 | * TXX9_IRQ_BASE+21 |
45 | 44 TX4938-PIC/20 | 45 | * TXX9_IRQ_BASE+22 TX4938 PCIERR |
46 | 45 TX4938-PIC/21 | 46 | * TXX9_IRQ_BASE+23 |
47 | 46 TX4938-PIC/22 TX4938 PCIERR | 47 | * TXX9_IRQ_BASE+24 |
48 | 47 TX4938-PIC/23 | 48 | * TXX9_IRQ_BASE+25 |
49 | 48 TX4938-PIC/24 | 49 | * TXX9_IRQ_BASE+26 |
50 | 49 TX4938-PIC/25 | 50 | * TXX9_IRQ_BASE+27 |
51 | 50 TX4938-PIC/26 | 51 | * TXX9_IRQ_BASE+28 |
52 | 51 TX4938-PIC/27 | 52 | * TXX9_IRQ_BASE+29 |
53 | 52 TX4938-PIC/28 | 53 | * TXX9_IRQ_BASE+30 |
54 | 53 TX4938-PIC/29 | 54 | * TXX9_IRQ_BASE+31 TX4938 SPI |
55 | 54 TX4938-PIC/30 | 55 | * |
56 | 55 TX4938-PIC/31 TX4938 SPI | 56 | * RBTX4938_IRQ_IOC+00 PCI-D |
57 | 57 | * RBTX4938_IRQ_IOC+01 PCI-C | |
58 | 56 RBTX4938-IOC/00 PCI-D | 58 | * RBTX4938_IRQ_IOC+02 PCI-B |
59 | 57 RBTX4938-IOC/01 PCI-C | 59 | * RBTX4938_IRQ_IOC+03 PCI-A |
60 | 58 RBTX4938-IOC/02 PCI-B | 60 | * RBTX4938_IRQ_IOC+04 RTC |
61 | 59 RBTX4938-IOC/03 PCI-A | 61 | * RBTX4938_IRQ_IOC+05 ATA |
62 | 60 RBTX4938-IOC/04 RTC | 62 | * RBTX4938_IRQ_IOC+06 MODEM |
63 | 61 RBTX4938-IOC/05 ATA | 63 | * RBTX4938_IRQ_IOC+07 SWINT |
64 | 62 RBTX4938-IOC/06 MODEM | 64 | */ |
65 | 63 RBTX4938-IOC/07 SWINT | ||
66 | */ | ||
67 | #include <linux/init.h> | 65 | #include <linux/init.h> |
68 | #include <linux/interrupt.h> | 66 | #include <linux/interrupt.h> |
69 | #include <asm/mipsregs.h> | 67 | #include <asm/mipsregs.h> |
@@ -93,9 +91,6 @@ static int toshiba_rbtx4938_irq_nested(int sw_irq) | |||
93 | return sw_irq; | 91 | return sw_irq; |
94 | } | 92 | } |
95 | 93 | ||
96 | /**********************************************************************************/ | ||
97 | /* Functions for ioc */ | ||
98 | /**********************************************************************************/ | ||
99 | static void __init | 94 | static void __init |
100 | toshiba_rbtx4938_irq_ioc_init(void) | 95 | toshiba_rbtx4938_irq_ioc_init(void) |
101 | { | 96 | { |
diff --git a/arch/mips/txx9/rbtx4938/prom.c b/arch/mips/txx9/rbtx4938/prom.c index ee189519ce5a..d73123cd2ab9 100644 --- a/arch/mips/txx9/rbtx4938/prom.c +++ b/arch/mips/txx9/rbtx4938/prom.c | |||
@@ -22,4 +22,5 @@ void __init rbtx4938_prom_init(void) | |||
22 | prom_init_cmdline(); | 22 | prom_init_cmdline(); |
23 | #endif | 23 | #endif |
24 | add_memory_region(0, tx4938_get_mem_size(), BOOT_MEM_RAM); | 24 | add_memory_region(0, tx4938_get_mem_size(), BOOT_MEM_RAM); |
25 | txx9_sio_putchar_init(TX4938_SIO_REG(0) & 0xfffffffffULL); | ||
25 | } | 26 | } |
diff --git a/arch/mips/txx9/rbtx4938/setup.c b/arch/mips/txx9/rbtx4938/setup.c index 6c2b99bb8af6..9ab48dec0fe8 100644 --- a/arch/mips/txx9/rbtx4938/setup.c +++ b/arch/mips/txx9/rbtx4938/setup.c | |||
@@ -13,9 +13,6 @@ | |||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/ioport.h> | 14 | #include <linux/ioport.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/console.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
20 | #include <linux/gpio.h> | 17 | #include <linux/gpio.h> |
21 | 18 | ||
@@ -28,33 +25,14 @@ | |||
28 | #include <asm/txx9/spi.h> | 25 | #include <asm/txx9/spi.h> |
29 | #include <asm/txx9pio.h> | 26 | #include <asm/txx9pio.h> |
30 | 27 | ||
31 | static void rbtx4938_machine_halt(void) | ||
32 | { | ||
33 | printk(KERN_NOTICE "System Halted\n"); | ||
34 | local_irq_disable(); | ||
35 | |||
36 | while (1) | ||
37 | __asm__(".set\tmips3\n\t" | ||
38 | "wait\n\t" | ||
39 | ".set\tmips0"); | ||
40 | } | ||
41 | |||
42 | static void rbtx4938_machine_power_off(void) | ||
43 | { | ||
44 | rbtx4938_machine_halt(); | ||
45 | /* no return */ | ||
46 | } | ||
47 | |||
48 | static void rbtx4938_machine_restart(char *command) | 28 | static void rbtx4938_machine_restart(char *command) |
49 | { | 29 | { |
50 | local_irq_disable(); | 30 | local_irq_disable(); |
51 | |||
52 | printk("Rebooting..."); | ||
53 | writeb(1, rbtx4938_softresetlock_addr); | 31 | writeb(1, rbtx4938_softresetlock_addr); |
54 | writeb(1, rbtx4938_sfvol_addr); | 32 | writeb(1, rbtx4938_sfvol_addr); |
55 | writeb(1, rbtx4938_softreset_addr); | 33 | writeb(1, rbtx4938_softreset_addr); |
56 | while(1) | 34 | /* fallback */ |
57 | ; | 35 | (*_machine_halt)(); |
58 | } | 36 | } |
59 | 37 | ||
60 | static void __init rbtx4938_pci_setup(void) | 38 | static void __init rbtx4938_pci_setup(void) |
@@ -121,6 +99,7 @@ static void __init rbtx4938_pci_setup(void) | |||
121 | register_pci_controller(c); | 99 | register_pci_controller(c); |
122 | tx4927_pcic_setup(tx4938_pcic1ptr, c, 0); | 100 | tx4927_pcic_setup(tx4938_pcic1ptr, c, 0); |
123 | } | 101 | } |
102 | tx4938_setup_pcierr_irq(); | ||
124 | #endif /* CONFIG_PCI */ | 103 | #endif /* CONFIG_PCI */ |
125 | } | 104 | } |
126 | 105 | ||
@@ -151,19 +130,7 @@ static int __init rbtx4938_ethaddr_init(void) | |||
151 | if (sum) | 130 | if (sum) |
152 | printk(KERN_WARNING "seeprom: bad checksum.\n"); | 131 | printk(KERN_WARNING "seeprom: bad checksum.\n"); |
153 | } | 132 | } |
154 | for (i = 0; i < 2; i++) { | 133 | tx4938_ethaddr_init(&dat[4], &dat[4 + 6]); |
155 | unsigned int id = | ||
156 | TXX9_IRQ_BASE + (i ? TX4938_IR_ETH1 : TX4938_IR_ETH0); | ||
157 | struct platform_device *pdev; | ||
158 | if (!(__raw_readq(&tx4938_ccfgptr->pcfg) & | ||
159 | (i ? TX4938_PCFG_ETH1_SEL : TX4938_PCFG_ETH0_SEL))) | ||
160 | continue; | ||
161 | pdev = platform_device_alloc("tc35815-mac", id); | ||
162 | if (!pdev || | ||
163 | platform_device_add_data(pdev, &dat[4 + 6 * i], 6) || | ||
164 | platform_device_add(pdev)) | ||
165 | platform_device_put(pdev); | ||
166 | } | ||
167 | #endif /* CONFIG_PCI */ | 134 | #endif /* CONFIG_PCI */ |
168 | return 0; | 135 | return 0; |
169 | } | 136 | } |
@@ -193,51 +160,36 @@ static void __init rbtx4938_mem_setup(void) | |||
193 | 160 | ||
194 | #ifdef CONFIG_PCI | 161 | #ifdef CONFIG_PCI |
195 | txx9_alloc_pci_controller(&txx9_primary_pcic, 0, 0, 0, 0); | 162 | txx9_alloc_pci_controller(&txx9_primary_pcic, 0, 0, 0, 0); |
163 | txx9_board_pcibios_setup = tx4927_pcibios_setup; | ||
196 | #else | 164 | #else |
197 | set_io_port_base(RBTX4938_ETHER_BASE); | 165 | set_io_port_base(RBTX4938_ETHER_BASE); |
198 | #endif | 166 | #endif |
199 | 167 | ||
200 | tx4938_setup_serial(); | 168 | tx4938_sio_init(7372800, 0); |
201 | #ifdef CONFIG_SERIAL_TXX9_CONSOLE | 169 | #ifdef CONFIG_SERIAL_TXX9_CONSOLE |
202 | argptr = prom_getcmdline(); | 170 | argptr = prom_getcmdline(); |
203 | if (strstr(argptr, "console=") == NULL) { | 171 | if (!strstr(argptr, "console=")) |
204 | strcat(argptr, " console=ttyS0,38400"); | 172 | strcat(argptr, " console=ttyS0,38400"); |
205 | } | ||
206 | #endif | 173 | #endif |
207 | 174 | ||
208 | #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_PIO58_61 | 175 | #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_PIO58_61 |
209 | printk("PIOSEL: disabling both ata and nand selection\n"); | 176 | printk(KERN_INFO "PIOSEL: disabling both ata and nand selection\n"); |
210 | local_irq_disable(); | ||
211 | txx9_clear64(&tx4938_ccfgptr->pcfg, | 177 | txx9_clear64(&tx4938_ccfgptr->pcfg, |
212 | TX4938_PCFG_NDF_SEL | TX4938_PCFG_ATA_SEL); | 178 | TX4938_PCFG_NDF_SEL | TX4938_PCFG_ATA_SEL); |
213 | #endif | 179 | #endif |
214 | 180 | ||
215 | #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_NAND | 181 | #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_NAND |
216 | printk("PIOSEL: enabling nand selection\n"); | 182 | printk(KERN_INFO "PIOSEL: enabling nand selection\n"); |
217 | txx9_set64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_NDF_SEL); | 183 | txx9_set64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_NDF_SEL); |
218 | txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_ATA_SEL); | 184 | txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_ATA_SEL); |
219 | #endif | 185 | #endif |
220 | 186 | ||
221 | #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_ATA | 187 | #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_ATA |
222 | printk("PIOSEL: enabling ata selection\n"); | 188 | printk(KERN_INFO "PIOSEL: enabling ata selection\n"); |
223 | txx9_set64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_ATA_SEL); | 189 | txx9_set64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_ATA_SEL); |
224 | txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_NDF_SEL); | 190 | txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_NDF_SEL); |
225 | #endif | 191 | #endif |
226 | 192 | ||
227 | #ifdef CONFIG_IP_PNP | ||
228 | argptr = prom_getcmdline(); | ||
229 | if (strstr(argptr, "ip=") == NULL) { | ||
230 | strcat(argptr, " ip=any"); | ||
231 | } | ||
232 | #endif | ||
233 | |||
234 | |||
235 | #ifdef CONFIG_FB | ||
236 | { | ||
237 | conswitchp = &dummy_con; | ||
238 | } | ||
239 | #endif | ||
240 | |||
241 | rbtx4938_spi_setup(); | 193 | rbtx4938_spi_setup(); |
242 | pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg); /* updated */ | 194 | pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg); /* updated */ |
243 | /* fixup piosel */ | 195 | /* fixup piosel */ |
@@ -258,11 +210,9 @@ static void __init rbtx4938_mem_setup(void) | |||
258 | rbtx4938_fpga_resource.end = CPHYSADDR(RBTX4938_FPGA_REG_ADDR) + 0xffff; | 210 | rbtx4938_fpga_resource.end = CPHYSADDR(RBTX4938_FPGA_REG_ADDR) + 0xffff; |
259 | rbtx4938_fpga_resource.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | 211 | rbtx4938_fpga_resource.flags = IORESOURCE_MEM | IORESOURCE_BUSY; |
260 | if (request_resource(&txx9_ce_res[2], &rbtx4938_fpga_resource)) | 212 | if (request_resource(&txx9_ce_res[2], &rbtx4938_fpga_resource)) |
261 | printk("request resource for fpga failed\n"); | 213 | printk(KERN_ERR "request resource for fpga failed\n"); |
262 | 214 | ||
263 | _machine_restart = rbtx4938_machine_restart; | 215 | _machine_restart = rbtx4938_machine_restart; |
264 | _machine_halt = rbtx4938_machine_halt; | ||
265 | pm_power_off = rbtx4938_machine_power_off; | ||
266 | 216 | ||
267 | writeb(0xff, rbtx4938_led_addr); | 217 | writeb(0xff, rbtx4938_led_addr); |
268 | printk(KERN_INFO "RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n", | 218 | printk(KERN_INFO "RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n", |
@@ -270,7 +220,7 @@ static void __init rbtx4938_mem_setup(void) | |||
270 | readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr)); | 220 | readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr)); |
271 | } | 221 | } |
272 | 222 | ||
273 | static int __init rbtx4938_ne_init(void) | 223 | static void __init rbtx4938_ne_init(void) |
274 | { | 224 | { |
275 | struct resource res[] = { | 225 | struct resource res[] = { |
276 | { | 226 | { |
@@ -282,10 +232,7 @@ static int __init rbtx4938_ne_init(void) | |||
282 | .flags = IORESOURCE_IRQ, | 232 | .flags = IORESOURCE_IRQ, |
283 | } | 233 | } |
284 | }; | 234 | }; |
285 | struct platform_device *dev = | 235 | platform_device_register_simple("ne", -1, res, ARRAY_SIZE(res)); |
286 | platform_device_register_simple("ne", -1, | ||
287 | res, ARRAY_SIZE(res)); | ||
288 | return IS_ERR(dev) ? PTR_ERR(dev) : 0; | ||
289 | } | 236 | } |
290 | 237 | ||
291 | static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock); | 238 | static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock); |
@@ -321,24 +268,6 @@ static struct gpio_chip rbtx4938_spi_gpio_chip = { | |||
321 | .ngpio = 3, | 268 | .ngpio = 3, |
322 | }; | 269 | }; |
323 | 270 | ||
324 | /* SPI support */ | ||
325 | |||
326 | static void __init txx9_spi_init(unsigned long base, int irq) | ||
327 | { | ||
328 | struct resource res[] = { | ||
329 | { | ||
330 | .start = base, | ||
331 | .end = base + 0x20 - 1, | ||
332 | .flags = IORESOURCE_MEM, | ||
333 | }, { | ||
334 | .start = irq, | ||
335 | .flags = IORESOURCE_IRQ, | ||
336 | }, | ||
337 | }; | ||
338 | platform_device_register_simple("spi_txx9", 0, | ||
339 | res, ARRAY_SIZE(res)); | ||
340 | } | ||
341 | |||
342 | static int __init rbtx4938_spi_init(void) | 271 | static int __init rbtx4938_spi_init(void) |
343 | { | 272 | { |
344 | struct spi_board_info srtc_info = { | 273 | struct spi_board_info srtc_info = { |
@@ -361,7 +290,7 @@ static int __init rbtx4938_spi_init(void) | |||
361 | gpio_direction_output(16 + SEEPROM2_CS, 1); | 290 | gpio_direction_output(16 + SEEPROM2_CS, 1); |
362 | gpio_request(16 + SEEPROM3_CS, "seeprom3"); | 291 | gpio_request(16 + SEEPROM3_CS, "seeprom3"); |
363 | gpio_direction_output(16 + SEEPROM3_CS, 1); | 292 | gpio_direction_output(16 + SEEPROM3_CS, 1); |
364 | txx9_spi_init(TX4938_SPI_REG & 0xfffffffffULL, RBTX4938_IRQ_IRC_SPI); | 293 | tx4938_spi_init(0); |
365 | return 0; | 294 | return 0; |
366 | } | 295 | } |
367 | 296 | ||
@@ -372,30 +301,11 @@ static void __init rbtx4938_arch_init(void) | |||
372 | rbtx4938_spi_init(); | 301 | rbtx4938_spi_init(); |
373 | } | 302 | } |
374 | 303 | ||
375 | /* Watchdog support */ | ||
376 | |||
377 | static int __init txx9_wdt_init(unsigned long base) | ||
378 | { | ||
379 | struct resource res = { | ||
380 | .start = base, | ||
381 | .end = base + 0x100 - 1, | ||
382 | .flags = IORESOURCE_MEM, | ||
383 | }; | ||
384 | struct platform_device *dev = | ||
385 | platform_device_register_simple("txx9wdt", -1, &res, 1); | ||
386 | return IS_ERR(dev) ? PTR_ERR(dev) : 0; | ||
387 | } | ||
388 | |||
389 | static int __init rbtx4938_wdt_init(void) | ||
390 | { | ||
391 | return txx9_wdt_init(TX4938_TMR_REG(2) & 0xfffffffffULL); | ||
392 | } | ||
393 | |||
394 | static void __init rbtx4938_device_init(void) | 304 | static void __init rbtx4938_device_init(void) |
395 | { | 305 | { |
396 | rbtx4938_ethaddr_init(); | 306 | rbtx4938_ethaddr_init(); |
397 | rbtx4938_ne_init(); | 307 | rbtx4938_ne_init(); |
398 | rbtx4938_wdt_init(); | 308 | tx4938_wdt_init(); |
399 | } | 309 | } |
400 | 310 | ||
401 | struct txx9_board_vec rbtx4938_vec __initdata = { | 311 | struct txx9_board_vec rbtx4938_vec __initdata = { |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 587da5e0990f..63c9cafda9c4 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -42,6 +42,9 @@ config GENERIC_HARDIRQS | |||
42 | bool | 42 | bool |
43 | default y | 43 | default y |
44 | 44 | ||
45 | config HAVE_GET_USER_PAGES_FAST | ||
46 | def_bool PPC64 | ||
47 | |||
45 | config HAVE_SETUP_PER_CPU_AREA | 48 | config HAVE_SETUP_PER_CPU_AREA |
46 | def_bool PPC64 | 49 | def_bool PPC64 |
47 | 50 | ||
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts index 7345743d3d96..fbc930410ff6 100644 --- a/arch/powerpc/boot/dts/mpc832x_mds.dts +++ b/arch/powerpc/boot/dts/mpc832x_mds.dts | |||
@@ -68,6 +68,7 @@ | |||
68 | #address-cells = <1>; | 68 | #address-cells = <1>; |
69 | #size-cells = <1>; | 69 | #size-cells = <1>; |
70 | device_type = "soc"; | 70 | device_type = "soc"; |
71 | compatible = "simple-bus"; | ||
71 | ranges = <0x0 0xe0000000 0x00100000>; | 72 | ranges = <0x0 0xe0000000 0x00100000>; |
72 | reg = <0xe0000000 0x00000200>; | 73 | reg = <0xe0000000 0x00000200>; |
73 | bus-frequency = <132000000>; | 74 | bus-frequency = <132000000>; |
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts index e74c045a0f8c..b157d1885a28 100644 --- a/arch/powerpc/boot/dts/mpc832x_rdb.dts +++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts | |||
@@ -51,6 +51,7 @@ | |||
51 | #address-cells = <1>; | 51 | #address-cells = <1>; |
52 | #size-cells = <1>; | 52 | #size-cells = <1>; |
53 | device_type = "soc"; | 53 | device_type = "soc"; |
54 | compatible = "simple-bus"; | ||
54 | ranges = <0x0 0xe0000000 0x00100000>; | 55 | ranges = <0x0 0xe0000000 0x00100000>; |
55 | reg = <0xe0000000 0x00000200>; | 56 | reg = <0xe0000000 0x00000200>; |
56 | bus-frequency = <0>; | 57 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index 8dfab5662585..700e076ef3f5 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts | |||
@@ -52,6 +52,7 @@ | |||
52 | #address-cells = <1>; | 52 | #address-cells = <1>; |
53 | #size-cells = <1>; | 53 | #size-cells = <1>; |
54 | device_type = "soc"; | 54 | device_type = "soc"; |
55 | compatible = "simple-bus"; | ||
55 | ranges = <0x0 0xe0000000 0x00100000>; | 56 | ranges = <0x0 0xe0000000 0x00100000>; |
56 | reg = <0xe0000000 0x00000200>; | 57 | reg = <0xe0000000 0x00000200>; |
57 | bus-frequency = <0>; // from bootloader | 58 | bus-frequency = <0>; // from bootloader |
diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts index 49ca3497eefb..cdd3063258ea 100644 --- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts | |||
@@ -50,6 +50,7 @@ | |||
50 | #address-cells = <1>; | 50 | #address-cells = <1>; |
51 | #size-cells = <1>; | 51 | #size-cells = <1>; |
52 | device_type = "soc"; | 52 | device_type = "soc"; |
53 | compatible = "simple-bus"; | ||
53 | ranges = <0x0 0xe0000000 0x00100000>; | 54 | ranges = <0x0 0xe0000000 0x00100000>; |
54 | reg = <0xe0000000 0x00000200>; | 55 | reg = <0xe0000000 0x00000200>; |
55 | bus-frequency = <0>; // from bootloader | 56 | bus-frequency = <0>; // from bootloader |
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index ba586cb7afbb..783241c00240 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts | |||
@@ -57,6 +57,7 @@ | |||
57 | #address-cells = <1>; | 57 | #address-cells = <1>; |
58 | #size-cells = <1>; | 58 | #size-cells = <1>; |
59 | device_type = "soc"; | 59 | device_type = "soc"; |
60 | compatible = "simple-bus"; | ||
60 | ranges = <0x0 0xe0000000 0x00100000>; | 61 | ranges = <0x0 0xe0000000 0x00100000>; |
61 | reg = <0xe0000000 0x00000200>; | 62 | reg = <0xe0000000 0x00000200>; |
62 | bus-frequency = <0>; | 63 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts index 3701dae1ee02..a3b76a709951 100644 --- a/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/arch/powerpc/boot/dts/mpc836x_mds.dts | |||
@@ -61,6 +61,7 @@ | |||
61 | #address-cells = <1>; | 61 | #address-cells = <1>; |
62 | #size-cells = <1>; | 62 | #size-cells = <1>; |
63 | device_type = "soc"; | 63 | device_type = "soc"; |
64 | compatible = "simple-bus"; | ||
64 | ranges = <0x0 0xe0000000 0x00100000>; | 65 | ranges = <0x0 0xe0000000 0x00100000>; |
65 | reg = <0xe0000000 0x00000200>; | 66 | reg = <0xe0000000 0x00000200>; |
66 | bus-frequency = <264000000>; | 67 | bus-frequency = <264000000>; |
diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts index 8acd1d6577f2..89c9202f8bd7 100644 --- a/arch/powerpc/boot/dts/mpc836x_rdk.dts +++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts | |||
@@ -149,18 +149,14 @@ | |||
149 | }; | 149 | }; |
150 | 150 | ||
151 | crypto@30000 { | 151 | crypto@30000 { |
152 | compatible = "fsl,sec2-crypto"; | 152 | compatible = "fsl,sec2.0"; |
153 | reg = <0x30000 0x10000>; | 153 | reg = <0x30000 0x10000>; |
154 | interrupts = <11 8>; | 154 | interrupts = <11 0x8>; |
155 | interrupt-parent = <&ipic>; | 155 | interrupt-parent = <&ipic>; |
156 | num-channels = <4>; | 156 | fsl,num-channels = <4>; |
157 | channel-fifo-len = <24>; | 157 | fsl,channel-fifo-len = <24>; |
158 | exec-units-mask = <0x7e>; | 158 | fsl,exec-units-mask = <0x7e>; |
159 | /* | 159 | fsl,descriptor-types-mask = <0x01010ebf>; |
160 | * desc mask is for rev1.x, we need runtime fixup | ||
161 | * for >=2.x | ||
162 | */ | ||
163 | descriptor-types-mask = <0x1010ebf>; | ||
164 | }; | 160 | }; |
165 | 161 | ||
166 | ipic: interrupt-controller@700 { | 162 | ipic: interrupt-controller@700 { |
diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts b/arch/powerpc/boot/dts/mpc8377_mds.dts index 0a700cb5f611..432782b6d20a 100644 --- a/arch/powerpc/boot/dts/mpc8377_mds.dts +++ b/arch/powerpc/boot/dts/mpc8377_mds.dts | |||
@@ -117,6 +117,7 @@ | |||
117 | #address-cells = <1>; | 117 | #address-cells = <1>; |
118 | #size-cells = <1>; | 118 | #size-cells = <1>; |
119 | device_type = "soc"; | 119 | device_type = "soc"; |
120 | compatible = "simple-bus"; | ||
120 | ranges = <0x0 0xe0000000 0x00100000>; | 121 | ranges = <0x0 0xe0000000 0x00100000>; |
121 | reg = <0xe0000000 0x00000200>; | 122 | reg = <0xe0000000 0x00000200>; |
122 | bus-frequency = <0>; | 123 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8378_mds.dts b/arch/powerpc/boot/dts/mpc8378_mds.dts index 29c8c76a58f7..ed32c8ddafe3 100644 --- a/arch/powerpc/boot/dts/mpc8378_mds.dts +++ b/arch/powerpc/boot/dts/mpc8378_mds.dts | |||
@@ -117,6 +117,7 @@ | |||
117 | #address-cells = <1>; | 117 | #address-cells = <1>; |
118 | #size-cells = <1>; | 118 | #size-cells = <1>; |
119 | device_type = "soc"; | 119 | device_type = "soc"; |
120 | compatible = "simple-bus"; | ||
120 | ranges = <0x0 0xe0000000 0x00100000>; | 121 | ranges = <0x0 0xe0000000 0x00100000>; |
121 | reg = <0xe0000000 0x00000200>; | 122 | reg = <0xe0000000 0x00000200>; |
122 | bus-frequency = <0>; | 123 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8379_mds.dts b/arch/powerpc/boot/dts/mpc8379_mds.dts index d641a8985ea3..f4db9ed4a301 100644 --- a/arch/powerpc/boot/dts/mpc8379_mds.dts +++ b/arch/powerpc/boot/dts/mpc8379_mds.dts | |||
@@ -117,6 +117,7 @@ | |||
117 | #address-cells = <1>; | 117 | #address-cells = <1>; |
118 | #size-cells = <1>; | 118 | #size-cells = <1>; |
119 | device_type = "soc"; | 119 | device_type = "soc"; |
120 | compatible = "simple-bus"; | ||
120 | ranges = <0x0 0xe0000000 0x00100000>; | 121 | ranges = <0x0 0xe0000000 0x00100000>; |
121 | reg = <0xe0000000 0x00000200>; | 122 | reg = <0xe0000000 0x00000200>; |
122 | bus-frequency = <0>; | 123 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts index 02cfa24a1695..1505d6855eff 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dts +++ b/arch/powerpc/boot/dts/mpc8536ds.dts | |||
@@ -49,6 +49,7 @@ | |||
49 | #address-cells = <1>; | 49 | #address-cells = <1>; |
50 | #size-cells = <1>; | 50 | #size-cells = <1>; |
51 | device_type = "soc"; | 51 | device_type = "soc"; |
52 | compatible = "simple-bus"; | ||
52 | ranges = <0x0 0xffe00000 0x100000>; | 53 | ranges = <0x0 0xffe00000 0x100000>; |
53 | reg = <0xffe00000 0x1000>; | 54 | reg = <0xffe00000 0x1000>; |
54 | bus-frequency = <0>; // Filled out by uboot. | 55 | bus-frequency = <0>; // Filled out by uboot. |
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts index f2273a872b11..9568bfaff8f7 100644 --- a/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/arch/powerpc/boot/dts/mpc8540ads.dts | |||
@@ -53,6 +53,7 @@ | |||
53 | #address-cells = <1>; | 53 | #address-cells = <1>; |
54 | #size-cells = <1>; | 54 | #size-cells = <1>; |
55 | device_type = "soc"; | 55 | device_type = "soc"; |
56 | compatible = "simple-bus"; | ||
56 | ranges = <0x0 0xe0000000 0x100000>; | 57 | ranges = <0x0 0xe0000000 0x100000>; |
57 | reg = <0xe0000000 0x100000>; // CCSRBAR 1M | 58 | reg = <0xe0000000 0x100000>; // CCSRBAR 1M |
58 | bus-frequency = <0>; | 59 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index c4469f19ff82..6480f4fd96e0 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts | |||
@@ -53,6 +53,7 @@ | |||
53 | #address-cells = <1>; | 53 | #address-cells = <1>; |
54 | #size-cells = <1>; | 54 | #size-cells = <1>; |
55 | device_type = "soc"; | 55 | device_type = "soc"; |
56 | compatible = "simple-bus"; | ||
56 | ranges = <0x0 0xe0000000 0x100000>; | 57 | ranges = <0x0 0xe0000000 0x100000>; |
57 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M | 58 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M |
58 | bus-frequency = <0>; | 59 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts index 7d3829d3495e..f1fb20737e3e 100644 --- a/arch/powerpc/boot/dts/mpc8544ds.dts +++ b/arch/powerpc/boot/dts/mpc8544ds.dts | |||
@@ -54,6 +54,7 @@ | |||
54 | #address-cells = <1>; | 54 | #address-cells = <1>; |
55 | #size-cells = <1>; | 55 | #size-cells = <1>; |
56 | device_type = "soc"; | 56 | device_type = "soc"; |
57 | compatible = "simple-bus"; | ||
57 | 58 | ||
58 | ranges = <0x0 0xe0000000 0x100000>; | 59 | ranges = <0x0 0xe0000000 0x100000>; |
59 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M | 60 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M |
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts index d84466bb7eca..431b496270dc 100644 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/arch/powerpc/boot/dts/mpc8548cds.dts | |||
@@ -58,6 +58,7 @@ | |||
58 | #address-cells = <1>; | 58 | #address-cells = <1>; |
59 | #size-cells = <1>; | 59 | #size-cells = <1>; |
60 | device_type = "soc"; | 60 | device_type = "soc"; |
61 | compatible = "simple-bus"; | ||
61 | ranges = <0x0 0xe0000000 0x100000>; | 62 | ranges = <0x0 0xe0000000 0x100000>; |
62 | reg = <0xe0000000 0x1000>; // CCSRBAR | 63 | reg = <0xe0000000 0x1000>; // CCSRBAR |
63 | bus-frequency = <0>; | 64 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index e03a78006283..d833a5c4f476 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts | |||
@@ -53,6 +53,7 @@ | |||
53 | #address-cells = <1>; | 53 | #address-cells = <1>; |
54 | #size-cells = <1>; | 54 | #size-cells = <1>; |
55 | device_type = "soc"; | 55 | device_type = "soc"; |
56 | compatible = "simple-bus"; | ||
56 | ranges = <0x0 0xe0000000 0x100000>; | 57 | ranges = <0x0 0xe0000000 0x100000>; |
57 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M | 58 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M |
58 | bus-frequency = <0>; | 59 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index ba8159de040b..4d1f2f284094 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts | |||
@@ -53,6 +53,7 @@ | |||
53 | #address-cells = <1>; | 53 | #address-cells = <1>; |
54 | #size-cells = <1>; | 54 | #size-cells = <1>; |
55 | device_type = "soc"; | 55 | device_type = "soc"; |
56 | compatible = "simple-bus"; | ||
56 | ranges = <0x0 0xe0000000 0x100000>; | 57 | ranges = <0x0 0xe0000000 0x100000>; |
57 | reg = <0xe0000000 0x200>; | 58 | reg = <0xe0000000 0x200>; |
58 | bus-frequency = <330000000>; | 59 | bus-frequency = <330000000>; |
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index 9c30a34821dc..a15f10343f53 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts | |||
@@ -60,6 +60,7 @@ | |||
60 | #address-cells = <1>; | 60 | #address-cells = <1>; |
61 | #size-cells = <1>; | 61 | #size-cells = <1>; |
62 | device_type = "soc"; | 62 | device_type = "soc"; |
63 | compatible = "simple-bus"; | ||
63 | ranges = <0x0 0xe0000000 0x100000>; | 64 | ranges = <0x0 0xe0000000 0x100000>; |
64 | reg = <0xe0000000 0x1000>; | 65 | reg = <0xe0000000 0x1000>; |
65 | bus-frequency = <0>; | 66 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8572ds.dts b/arch/powerpc/boot/dts/mpc8572ds.dts index 08c61e3daecc..e124dd18fb5a 100644 --- a/arch/powerpc/boot/dts/mpc8572ds.dts +++ b/arch/powerpc/boot/dts/mpc8572ds.dts | |||
@@ -68,6 +68,7 @@ | |||
68 | #address-cells = <1>; | 68 | #address-cells = <1>; |
69 | #size-cells = <1>; | 69 | #size-cells = <1>; |
70 | device_type = "soc"; | 70 | device_type = "soc"; |
71 | compatible = "simple-bus"; | ||
71 | ranges = <0x0 0xffe00000 0x100000>; | 72 | ranges = <0x0 0xffe00000 0x100000>; |
72 | reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed | 73 | reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed |
73 | bus-frequency = <0>; // Filled out by uboot. | 74 | bus-frequency = <0>; // Filled out by uboot. |
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 9f856a0c3e38..1a09719c7628 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c | |||
@@ -636,10 +636,6 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, | |||
636 | retval = -EIO; | 636 | retval = -EIO; |
637 | } else if (retval == H_PARAMETER) { | 637 | } else if (retval == H_PARAMETER) { |
638 | retval = -EINVAL; | 638 | retval = -EINVAL; |
639 | } else { | ||
640 | printk(KERN_WARNING "%s: received unknown hv return code %ld", | ||
641 | __func__, retval); | ||
642 | retval = -EIO; | ||
643 | } | 639 | } |
644 | 640 | ||
645 | return retval; | 641 | return retval; |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 6b66cd85b433..3635be61f899 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -375,7 +375,7 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset, | |||
375 | flush_vsx_to_thread(target); | 375 | flush_vsx_to_thread(target); |
376 | 376 | ||
377 | for (i = 0; i < 32 ; i++) | 377 | for (i = 0; i < 32 ; i++) |
378 | buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET]; | 378 | buf[i] = target->thread.fpr[i][TS_VSRLOWOFFSET]; |
379 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 379 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
380 | buf, 0, 32 * sizeof(double)); | 380 | buf, 0, 32 * sizeof(double)); |
381 | 381 | ||
@@ -394,7 +394,7 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset, | |||
394 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 394 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
395 | buf, 0, 32 * sizeof(double)); | 395 | buf, 0, 32 * sizeof(double)); |
396 | for (i = 0; i < 32 ; i++) | 396 | for (i = 0; i < 32 ; i++) |
397 | current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; | 397 | target->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; |
398 | 398 | ||
399 | 399 | ||
400 | return ret; | 400 | return ret; |
@@ -975,15 +975,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
975 | case PTRACE_GETVSRREGS: | 975 | case PTRACE_GETVSRREGS: |
976 | return copy_regset_to_user(child, &user_ppc_native_view, | 976 | return copy_regset_to_user(child, &user_ppc_native_view, |
977 | REGSET_VSX, | 977 | REGSET_VSX, |
978 | 0, (32 * sizeof(vector128) + | 978 | 0, 32 * sizeof(double), |
979 | sizeof(u32)), | ||
980 | (void __user *) data); | 979 | (void __user *) data); |
981 | 980 | ||
982 | case PTRACE_SETVSRREGS: | 981 | case PTRACE_SETVSRREGS: |
983 | return copy_regset_from_user(child, &user_ppc_native_view, | 982 | return copy_regset_from_user(child, &user_ppc_native_view, |
984 | REGSET_VSX, | 983 | REGSET_VSX, |
985 | 0, (32 * sizeof(vector128) + | 984 | 0, 32 * sizeof(double), |
986 | sizeof(u32)), | ||
987 | (const void __user *) data); | 985 | (const void __user *) data); |
988 | #endif | 986 | #endif |
989 | #ifdef CONFIG_SPE | 987 | #ifdef CONFIG_SPE |
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 67bf1a1e7e14..197d49c790ad 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
@@ -294,6 +294,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
294 | case PTRACE_SETFPREGS: | 294 | case PTRACE_SETFPREGS: |
295 | case PTRACE_GETVRREGS: | 295 | case PTRACE_GETVRREGS: |
296 | case PTRACE_SETVRREGS: | 296 | case PTRACE_SETVRREGS: |
297 | case PTRACE_GETVSRREGS: | ||
298 | case PTRACE_SETVSRREGS: | ||
297 | case PTRACE_GETREGS64: | 299 | case PTRACE_GETREGS64: |
298 | case PTRACE_SETREGS64: | 300 | case PTRACE_SETREGS64: |
299 | case PPC_PTRACE_GETFPREGS: | 301 | case PPC_PTRACE_GETFPREGS: |
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 1c00e0196f6c..e7392b45a5ef 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile | |||
@@ -12,7 +12,8 @@ obj-y := fault.o mem.o \ | |||
12 | mmu_context_$(CONFIG_WORD_SIZE).o | 12 | mmu_context_$(CONFIG_WORD_SIZE).o |
13 | hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o | 13 | hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o |
14 | obj-$(CONFIG_PPC64) += hash_utils_64.o \ | 14 | obj-$(CONFIG_PPC64) += hash_utils_64.o \ |
15 | slb_low.o slb.o stab.o mmap.o $(hash-y) | 15 | slb_low.o slb.o stab.o \ |
16 | gup.o mmap.o $(hash-y) | ||
16 | obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o | 17 | obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o |
17 | obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \ | 18 | obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \ |
18 | tlb_$(CONFIG_WORD_SIZE).o | 19 | tlb_$(CONFIG_WORD_SIZE).o |
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c new file mode 100644 index 000000000000..9fdf4d6335e4 --- /dev/null +++ b/arch/powerpc/mm/gup.c | |||
@@ -0,0 +1,280 @@ | |||
1 | /* | ||
2 | * Lockless get_user_pages_fast for powerpc | ||
3 | * | ||
4 | * Copyright (C) 2008 Nick Piggin | ||
5 | * Copyright (C) 2008 Novell Inc. | ||
6 | */ | ||
7 | #undef DEBUG | ||
8 | |||
9 | #include <linux/sched.h> | ||
10 | #include <linux/mm.h> | ||
11 | #include <linux/hugetlb.h> | ||
12 | #include <linux/vmstat.h> | ||
13 | #include <linux/pagemap.h> | ||
14 | #include <linux/rwsem.h> | ||
15 | #include <asm/pgtable.h> | ||
16 | |||
17 | /* | ||
18 | * The performance critical leaf functions are made noinline otherwise gcc | ||
19 | * inlines everything into a single function which results in too much | ||
20 | * register pressure. | ||
21 | */ | ||
22 | static noinline int gup_pte_range(pmd_t pmd, unsigned long addr, | ||
23 | unsigned long end, int write, struct page **pages, int *nr) | ||
24 | { | ||
25 | unsigned long mask, result; | ||
26 | pte_t *ptep; | ||
27 | |||
28 | result = _PAGE_PRESENT|_PAGE_USER; | ||
29 | if (write) | ||
30 | result |= _PAGE_RW; | ||
31 | mask = result | _PAGE_SPECIAL; | ||
32 | |||
33 | ptep = pte_offset_kernel(&pmd, addr); | ||
34 | do { | ||
35 | pte_t pte = *ptep; | ||
36 | struct page *page; | ||
37 | |||
38 | if ((pte_val(pte) & mask) != result) | ||
39 | return 0; | ||
40 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | ||
41 | page = pte_page(pte); | ||
42 | if (!page_cache_get_speculative(page)) | ||
43 | return 0; | ||
44 | if (unlikely(pte != *ptep)) { | ||
45 | put_page(page); | ||
46 | return 0; | ||
47 | } | ||
48 | pages[*nr] = page; | ||
49 | (*nr)++; | ||
50 | |||
51 | } while (ptep++, addr += PAGE_SIZE, addr != end); | ||
52 | |||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | #ifdef CONFIG_HUGETLB_PAGE | ||
57 | static noinline int gup_huge_pte(pte_t *ptep, struct hstate *hstate, | ||
58 | unsigned long *addr, unsigned long end, | ||
59 | int write, struct page **pages, int *nr) | ||
60 | { | ||
61 | unsigned long mask; | ||
62 | unsigned long pte_end; | ||
63 | struct page *head, *page; | ||
64 | pte_t pte; | ||
65 | int refs; | ||
66 | |||
67 | pte_end = (*addr + huge_page_size(hstate)) & huge_page_mask(hstate); | ||
68 | if (pte_end < end) | ||
69 | end = pte_end; | ||
70 | |||
71 | pte = *ptep; | ||
72 | mask = _PAGE_PRESENT|_PAGE_USER; | ||
73 | if (write) | ||
74 | mask |= _PAGE_RW; | ||
75 | if ((pte_val(pte) & mask) != mask) | ||
76 | return 0; | ||
77 | /* hugepages are never "special" */ | ||
78 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | ||
79 | |||
80 | refs = 0; | ||
81 | head = pte_page(pte); | ||
82 | page = head + ((*addr & ~huge_page_mask(hstate)) >> PAGE_SHIFT); | ||
83 | do { | ||
84 | VM_BUG_ON(compound_head(page) != head); | ||
85 | pages[*nr] = page; | ||
86 | (*nr)++; | ||
87 | page++; | ||
88 | refs++; | ||
89 | } while (*addr += PAGE_SIZE, *addr != end); | ||
90 | |||
91 | if (!page_cache_add_speculative(head, refs)) { | ||
92 | *nr -= refs; | ||
93 | return 0; | ||
94 | } | ||
95 | if (unlikely(pte != *ptep)) { | ||
96 | /* Could be optimized better */ | ||
97 | while (*nr) { | ||
98 | put_page(page); | ||
99 | (*nr)--; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | return 1; | ||
104 | } | ||
105 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
106 | |||
107 | static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, | ||
108 | int write, struct page **pages, int *nr) | ||
109 | { | ||
110 | unsigned long next; | ||
111 | pmd_t *pmdp; | ||
112 | |||
113 | pmdp = pmd_offset(&pud, addr); | ||
114 | do { | ||
115 | pmd_t pmd = *pmdp; | ||
116 | |||
117 | next = pmd_addr_end(addr, end); | ||
118 | if (pmd_none(pmd)) | ||
119 | return 0; | ||
120 | if (!gup_pte_range(pmd, addr, next, write, pages, nr)) | ||
121 | return 0; | ||
122 | } while (pmdp++, addr = next, addr != end); | ||
123 | |||
124 | return 1; | ||
125 | } | ||
126 | |||
127 | static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end, | ||
128 | int write, struct page **pages, int *nr) | ||
129 | { | ||
130 | unsigned long next; | ||
131 | pud_t *pudp; | ||
132 | |||
133 | pudp = pud_offset(&pgd, addr); | ||
134 | do { | ||
135 | pud_t pud = *pudp; | ||
136 | |||
137 | next = pud_addr_end(addr, end); | ||
138 | if (pud_none(pud)) | ||
139 | return 0; | ||
140 | if (!gup_pmd_range(pud, addr, next, write, pages, nr)) | ||
141 | return 0; | ||
142 | } while (pudp++, addr = next, addr != end); | ||
143 | |||
144 | return 1; | ||
145 | } | ||
146 | |||
147 | int get_user_pages_fast(unsigned long start, int nr_pages, int write, | ||
148 | struct page **pages) | ||
149 | { | ||
150 | struct mm_struct *mm = current->mm; | ||
151 | unsigned long addr, len, end; | ||
152 | unsigned long next; | ||
153 | pgd_t *pgdp; | ||
154 | int psize, nr = 0; | ||
155 | unsigned int shift; | ||
156 | |||
157 | pr_debug("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read"); | ||
158 | |||
159 | start &= PAGE_MASK; | ||
160 | addr = start; | ||
161 | len = (unsigned long) nr_pages << PAGE_SHIFT; | ||
162 | end = start + len; | ||
163 | |||
164 | if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, | ||
165 | start, len))) | ||
166 | goto slow_irqon; | ||
167 | |||
168 | pr_debug(" aligned: %lx .. %lx\n", start, end); | ||
169 | |||
170 | #ifdef CONFIG_HUGETLB_PAGE | ||
171 | /* We bail out on slice boundary crossing when hugetlb is | ||
172 | * enabled in order to not have to deal with two different | ||
173 | * page table formats | ||
174 | */ | ||
175 | if (addr < SLICE_LOW_TOP) { | ||
176 | if (end > SLICE_LOW_TOP) | ||
177 | goto slow_irqon; | ||
178 | |||
179 | if (unlikely(GET_LOW_SLICE_INDEX(addr) != | ||
180 | GET_LOW_SLICE_INDEX(end - 1))) | ||
181 | goto slow_irqon; | ||
182 | } else { | ||
183 | if (unlikely(GET_HIGH_SLICE_INDEX(addr) != | ||
184 | GET_HIGH_SLICE_INDEX(end - 1))) | ||
185 | goto slow_irqon; | ||
186 | } | ||
187 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
188 | |||
189 | /* | ||
190 | * XXX: batch / limit 'nr', to avoid large irq off latency | ||
191 | * needs some instrumenting to determine the common sizes used by | ||
192 | * important workloads (eg. DB2), and whether limiting the batch size | ||
193 | * will decrease performance. | ||
194 | * | ||
195 | * It seems like we're in the clear for the moment. Direct-IO is | ||
196 | * the main guy that batches up lots of get_user_pages, and even | ||
197 | * they are limited to 64-at-a-time which is not so many. | ||
198 | */ | ||
199 | /* | ||
200 | * This doesn't prevent pagetable teardown, but does prevent | ||
201 | * the pagetables from being freed on powerpc. | ||
202 | * | ||
203 | * So long as we atomically load page table pointers versus teardown, | ||
204 | * we can follow the address down to the the page and take a ref on it. | ||
205 | */ | ||
206 | local_irq_disable(); | ||
207 | |||
208 | psize = get_slice_psize(mm, addr); | ||
209 | shift = mmu_psize_defs[psize].shift; | ||
210 | |||
211 | #ifdef CONFIG_HUGETLB_PAGE | ||
212 | if (unlikely(mmu_huge_psizes[psize])) { | ||
213 | pte_t *ptep; | ||
214 | unsigned long a = addr; | ||
215 | unsigned long sz = ((1UL) << shift); | ||
216 | struct hstate *hstate = size_to_hstate(sz); | ||
217 | |||
218 | BUG_ON(!hstate); | ||
219 | /* | ||
220 | * XXX: could be optimized to avoid hstate | ||
221 | * lookup entirely (just use shift) | ||
222 | */ | ||
223 | |||
224 | do { | ||
225 | VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, a)].shift); | ||
226 | ptep = huge_pte_offset(mm, a); | ||
227 | pr_debug(" %016lx: huge ptep %p\n", a, ptep); | ||
228 | if (!ptep || !gup_huge_pte(ptep, hstate, &a, end, write, pages, | ||
229 | &nr)) | ||
230 | goto slow; | ||
231 | } while (a != end); | ||
232 | } else | ||
233 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
234 | { | ||
235 | pgdp = pgd_offset(mm, addr); | ||
236 | do { | ||
237 | pgd_t pgd = *pgdp; | ||
238 | |||
239 | VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift); | ||
240 | pr_debug(" %016lx: normal pgd %p\n", addr, (void *)pgd); | ||
241 | next = pgd_addr_end(addr, end); | ||
242 | if (pgd_none(pgd)) | ||
243 | goto slow; | ||
244 | if (!gup_pud_range(pgd, addr, next, write, pages, &nr)) | ||
245 | goto slow; | ||
246 | } while (pgdp++, addr = next, addr != end); | ||
247 | } | ||
248 | local_irq_enable(); | ||
249 | |||
250 | VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT); | ||
251 | return nr; | ||
252 | |||
253 | { | ||
254 | int ret; | ||
255 | |||
256 | slow: | ||
257 | local_irq_enable(); | ||
258 | slow_irqon: | ||
259 | pr_debug(" slow path ! nr = %d\n", nr); | ||
260 | |||
261 | /* Try to get the remaining pages with get_user_pages */ | ||
262 | start += nr << PAGE_SHIFT; | ||
263 | pages += nr; | ||
264 | |||
265 | down_read(&mm->mmap_sem); | ||
266 | ret = get_user_pages(current, mm, start, | ||
267 | (end - start) >> PAGE_SHIFT, write, 0, pages, NULL); | ||
268 | up_read(&mm->mmap_sem); | ||
269 | |||
270 | /* Have to be a bit careful with return values */ | ||
271 | if (nr > 0) { | ||
272 | if (ret < 0) | ||
273 | ret = nr; | ||
274 | else | ||
275 | ret += nr; | ||
276 | } | ||
277 | |||
278 | return ret; | ||
279 | } | ||
280 | } | ||
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index dd4be4aee314..ec43477caa63 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c | |||
@@ -105,6 +105,7 @@ static void __init mpc832x_sys_setup_arch(void) | |||
105 | static struct of_device_id mpc832x_ids[] = { | 105 | static struct of_device_id mpc832x_ids[] = { |
106 | { .type = "soc", }, | 106 | { .type = "soc", }, |
107 | { .compatible = "soc", }, | 107 | { .compatible = "soc", }, |
108 | { .compatible = "simple-bus", }, | ||
108 | { .type = "qe", }, | 109 | { .type = "qe", }, |
109 | { .compatible = "fsl,qe", }, | 110 | { .compatible = "fsl,qe", }, |
110 | {}, | 111 | {}, |
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index f049d692d4c8..0300268ce5b8 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c | |||
@@ -115,6 +115,7 @@ static void __init mpc832x_rdb_setup_arch(void) | |||
115 | static struct of_device_id mpc832x_ids[] = { | 115 | static struct of_device_id mpc832x_ids[] = { |
116 | { .type = "soc", }, | 116 | { .type = "soc", }, |
117 | { .compatible = "soc", }, | 117 | { .compatible = "soc", }, |
118 | { .compatible = "simple-bus", }, | ||
118 | { .type = "qe", }, | 119 | { .type = "qe", }, |
119 | { .compatible = "fsl,qe", }, | 120 | { .compatible = "fsl,qe", }, |
120 | {}, | 121 | {}, |
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 7301d77a08ee..76092d37c7d9 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c | |||
@@ -41,6 +41,7 @@ | |||
41 | 41 | ||
42 | static struct of_device_id __initdata mpc834x_itx_ids[] = { | 42 | static struct of_device_id __initdata mpc834x_itx_ids[] = { |
43 | { .compatible = "fsl,pq2pro-localbus", }, | 43 | { .compatible = "fsl,pq2pro-localbus", }, |
44 | { .compatible = "simple-bus", }, | ||
44 | {}, | 45 | {}, |
45 | }; | 46 | }; |
46 | 47 | ||
diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 30d509aa9f08..fc3f2ed1f3e9 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c | |||
@@ -111,6 +111,7 @@ static void __init mpc834x_mds_init_IRQ(void) | |||
111 | static struct of_device_id mpc834x_ids[] = { | 111 | static struct of_device_id mpc834x_ids[] = { |
112 | { .type = "soc", }, | 112 | { .type = "soc", }, |
113 | { .compatible = "soc", }, | 113 | { .compatible = "soc", }, |
114 | { .compatible = "simple-bus", }, | ||
114 | {}, | 115 | {}, |
115 | }; | 116 | }; |
116 | 117 | ||
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 75b80e836576..9d46e5bdd101 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c | |||
@@ -136,6 +136,7 @@ static void __init mpc836x_mds_setup_arch(void) | |||
136 | static struct of_device_id mpc836x_ids[] = { | 136 | static struct of_device_id mpc836x_ids[] = { |
137 | { .type = "soc", }, | 137 | { .type = "soc", }, |
138 | { .compatible = "soc", }, | 138 | { .compatible = "soc", }, |
139 | { .compatible = "simple-bus", }, | ||
139 | { .type = "qe", }, | 140 | { .type = "qe", }, |
140 | { .compatible = "fsl,qe", }, | 141 | { .compatible = "fsl,qe", }, |
141 | {}, | 142 | {}, |
diff --git a/arch/powerpc/platforms/83xx/sbc834x.c b/arch/powerpc/platforms/83xx/sbc834x.c index fc21f5c15bab..156c4e218009 100644 --- a/arch/powerpc/platforms/83xx/sbc834x.c +++ b/arch/powerpc/platforms/83xx/sbc834x.c | |||
@@ -83,6 +83,7 @@ static void __init sbc834x_init_IRQ(void) | |||
83 | static struct __initdata of_device_id sbc834x_ids[] = { | 83 | static struct __initdata of_device_id sbc834x_ids[] = { |
84 | { .type = "soc", }, | 84 | { .type = "soc", }, |
85 | { .compatible = "soc", }, | 85 | { .compatible = "soc", }, |
86 | { .compatible = "simple-bus", }, | ||
86 | {}, | 87 | {}, |
87 | }; | 88 | }; |
88 | 89 | ||
diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c index 2145adeb220c..8a3b117b6ce2 100644 --- a/arch/powerpc/platforms/85xx/ksi8560.c +++ b/arch/powerpc/platforms/85xx/ksi8560.c | |||
@@ -222,6 +222,7 @@ static void ksi8560_show_cpuinfo(struct seq_file *m) | |||
222 | 222 | ||
223 | static struct of_device_id __initdata of_bus_ids[] = { | 223 | static struct of_device_id __initdata of_bus_ids[] = { |
224 | { .type = "soc", }, | 224 | { .type = "soc", }, |
225 | { .type = "simple-bus", }, | ||
225 | { .name = "cpm", }, | 226 | { .name = "cpm", }, |
226 | { .name = "localbus", }, | 227 | { .name = "localbus", }, |
227 | {}, | 228 | {}, |
diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index 6b846aa1ced9..1bf5aefdfeb1 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c | |||
@@ -91,6 +91,7 @@ static void __init mpc8536_ds_setup_arch(void) | |||
91 | static struct of_device_id __initdata mpc8536_ds_ids[] = { | 91 | static struct of_device_id __initdata mpc8536_ds_ids[] = { |
92 | { .type = "soc", }, | 92 | { .type = "soc", }, |
93 | { .compatible = "soc", }, | 93 | { .compatible = "soc", }, |
94 | { .compatible = "simple-bus", }, | ||
94 | {}, | 95 | {}, |
95 | }; | 96 | }; |
96 | 97 | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index ba498d6f2d02..d17807a6b89a 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c | |||
@@ -230,6 +230,7 @@ static struct of_device_id __initdata of_bus_ids[] = { | |||
230 | { .type = "soc", }, | 230 | { .type = "soc", }, |
231 | { .name = "cpm", }, | 231 | { .name = "cpm", }, |
232 | { .name = "localbus", }, | 232 | { .name = "localbus", }, |
233 | { .compatible = "simple-bus", }, | ||
233 | {}, | 234 | {}, |
234 | }; | 235 | }; |
235 | 236 | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 00c535806647..483b65cbabae 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c | |||
@@ -186,6 +186,7 @@ static int __init mpc8544_ds_probe(void) | |||
186 | static struct of_device_id __initdata mpc85xxds_ids[] = { | 186 | static struct of_device_id __initdata mpc85xxds_ids[] = { |
187 | { .type = "soc", }, | 187 | { .type = "soc", }, |
188 | { .compatible = "soc", }, | 188 | { .compatible = "soc", }, |
189 | { .compatible = "simple-bus", }, | ||
189 | {}, | 190 | {}, |
190 | }; | 191 | }; |
191 | 192 | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 43a459f63e31..2494c5155919 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c | |||
@@ -260,6 +260,7 @@ machine_arch_initcall(mpc85xx_mds, board_fixups); | |||
260 | static struct of_device_id mpc85xx_ids[] = { | 260 | static struct of_device_id mpc85xx_ids[] = { |
261 | { .type = "soc", }, | 261 | { .type = "soc", }, |
262 | { .compatible = "soc", }, | 262 | { .compatible = "soc", }, |
263 | { .compatible = "simple-bus", }, | ||
263 | { .type = "qe", }, | 264 | { .type = "qe", }, |
264 | { .compatible = "fsl,qe", }, | 265 | { .compatible = "fsl,qe", }, |
265 | {}, | 266 | {}, |
diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c index 2c580cd24e4f..6509ade71668 100644 --- a/arch/powerpc/platforms/85xx/sbc8560.c +++ b/arch/powerpc/platforms/85xx/sbc8560.c | |||
@@ -217,6 +217,7 @@ static struct of_device_id __initdata of_bus_ids[] = { | |||
217 | { .type = "soc", }, | 217 | { .type = "soc", }, |
218 | { .name = "cpm", }, | 218 | { .name = "cpm", }, |
219 | { .name = "localbus", }, | 219 | { .name = "localbus", }, |
220 | { .compatible = "simple-bus", }, | ||
220 | {}, | 221 | {}, |
221 | }; | 222 | }; |
222 | 223 | ||
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 6fc849e51e48..71d7562e190b 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig | |||
@@ -105,6 +105,16 @@ config 8xx_COPYBACK | |||
105 | 105 | ||
106 | If in doubt, say Y here. | 106 | If in doubt, say Y here. |
107 | 107 | ||
108 | config 8xx_GPIO | ||
109 | bool "GPIO API Support" | ||
110 | select GENERIC_GPIO | ||
111 | select ARCH_REQUIRE_GPIOLIB | ||
112 | help | ||
113 | Saying Y here will cause the ports on an MPC8xx processor to be used | ||
114 | with the GPIO API. If you say N here, the kernel needs less memory. | ||
115 | |||
116 | If in doubt, say Y here. | ||
117 | |||
108 | config 8xx_CPU6 | 118 | config 8xx_CPU6 |
109 | bool "CPU6 Silicon Errata (860 Pre Rev. C)" | 119 | bool "CPU6 Silicon Errata (860 Pre Rev. C)" |
110 | help | 120 | help |
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 1d0968775c0a..4c900efa164e 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig | |||
@@ -254,6 +254,8 @@ config CPM2 | |||
254 | select CPM | 254 | select CPM |
255 | select PPC_LIB_RHEAP | 255 | select PPC_LIB_RHEAP |
256 | select PPC_PCI_CHOICE | 256 | select PPC_PCI_CHOICE |
257 | select ARCH_REQUIRE_GPIOLIB | ||
258 | select GENERIC_GPIO | ||
257 | help | 259 | help |
258 | The CPM2 (Communications Processor Module) is a coprocessor on | 260 | The CPM2 (Communications Processor Module) is a coprocessor on |
259 | embedded CPUs made by Freescale. Selecting this option means that | 261 | embedded CPUs made by Freescale. Selecting this option means that |
@@ -281,6 +283,7 @@ config FSL_ULI1575 | |||
281 | 283 | ||
282 | config CPM | 284 | config CPM |
283 | bool | 285 | bool |
286 | select PPC_CLOCK | ||
284 | 287 | ||
285 | config OF_RTC | 288 | config OF_RTC |
286 | bool | 289 | bool |
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c index 69288f653144..3233fe84d158 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c | |||
@@ -96,6 +96,12 @@ static int pmi_notifier(struct notifier_block *nb, | |||
96 | struct cpufreq_frequency_table *cbe_freqs; | 96 | struct cpufreq_frequency_table *cbe_freqs; |
97 | u8 node; | 97 | u8 node; |
98 | 98 | ||
99 | /* Should this really be called for CPUFREQ_ADJUST, CPUFREQ_INCOMPATIBLE | ||
100 | * and CPUFREQ_NOTIFY policy events?) | ||
101 | */ | ||
102 | if (event == CPUFREQ_START) | ||
103 | return 0; | ||
104 | |||
99 | cbe_freqs = cpufreq_frequency_get_table(policy->cpu); | 105 | cbe_freqs = cpufreq_frequency_get_table(policy->cpu); |
100 | node = cbe_cpu_to_node(policy->cpu); | 106 | node = cbe_cpu_to_node(policy->cpu); |
101 | 107 | ||
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 661df42830b9..4a04823e8423 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/irq.h> | 31 | #include <linux/irq.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/spinlock.h> | ||
33 | #include <asm/page.h> | 34 | #include <asm/page.h> |
34 | #include <asm/pgtable.h> | 35 | #include <asm/pgtable.h> |
35 | #include <asm/8xx_immap.h> | 36 | #include <asm/8xx_immap.h> |
@@ -42,6 +43,10 @@ | |||
42 | 43 | ||
43 | #include <asm/fs_pd.h> | 44 | #include <asm/fs_pd.h> |
44 | 45 | ||
46 | #ifdef CONFIG_8xx_GPIO | ||
47 | #include <linux/of_gpio.h> | ||
48 | #endif | ||
49 | |||
45 | #define CPM_MAP_SIZE (0x4000) | 50 | #define CPM_MAP_SIZE (0x4000) |
46 | 51 | ||
47 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ | 52 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ |
@@ -290,20 +295,24 @@ struct cpm_ioport16 { | |||
290 | __be16 res[3]; | 295 | __be16 res[3]; |
291 | }; | 296 | }; |
292 | 297 | ||
293 | struct cpm_ioport32 { | 298 | struct cpm_ioport32b { |
294 | __be32 dir, par, sor; | 299 | __be32 dir, par, odr, dat; |
300 | }; | ||
301 | |||
302 | struct cpm_ioport32e { | ||
303 | __be32 dir, par, sor, odr, dat; | ||
295 | }; | 304 | }; |
296 | 305 | ||
297 | static void cpm1_set_pin32(int port, int pin, int flags) | 306 | static void cpm1_set_pin32(int port, int pin, int flags) |
298 | { | 307 | { |
299 | struct cpm_ioport32 __iomem *iop; | 308 | struct cpm_ioport32e __iomem *iop; |
300 | pin = 1 << (31 - pin); | 309 | pin = 1 << (31 - pin); |
301 | 310 | ||
302 | if (port == CPM_PORTB) | 311 | if (port == CPM_PORTB) |
303 | iop = (struct cpm_ioport32 __iomem *) | 312 | iop = (struct cpm_ioport32e __iomem *) |
304 | &mpc8xx_immr->im_cpm.cp_pbdir; | 313 | &mpc8xx_immr->im_cpm.cp_pbdir; |
305 | else | 314 | else |
306 | iop = (struct cpm_ioport32 __iomem *) | 315 | iop = (struct cpm_ioport32e __iomem *) |
307 | &mpc8xx_immr->im_cpm.cp_pedir; | 316 | &mpc8xx_immr->im_cpm.cp_pedir; |
308 | 317 | ||
309 | if (flags & CPM_PIN_OUTPUT) | 318 | if (flags & CPM_PIN_OUTPUT) |
@@ -498,3 +507,251 @@ int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode) | |||
498 | 507 | ||
499 | return 0; | 508 | return 0; |
500 | } | 509 | } |
510 | |||
511 | /* | ||
512 | * GPIO LIB API implementation | ||
513 | */ | ||
514 | #ifdef CONFIG_8xx_GPIO | ||
515 | |||
516 | struct cpm1_gpio16_chip { | ||
517 | struct of_mm_gpio_chip mm_gc; | ||
518 | spinlock_t lock; | ||
519 | |||
520 | /* shadowed data register to clear/set bits safely */ | ||
521 | u16 cpdata; | ||
522 | }; | ||
523 | |||
524 | static inline struct cpm1_gpio16_chip * | ||
525 | to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc) | ||
526 | { | ||
527 | return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc); | ||
528 | } | ||
529 | |||
530 | static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
531 | { | ||
532 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); | ||
533 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
534 | |||
535 | cpm1_gc->cpdata = in_be16(&iop->dat); | ||
536 | } | ||
537 | |||
538 | static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio) | ||
539 | { | ||
540 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
541 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
542 | u16 pin_mask; | ||
543 | |||
544 | pin_mask = 1 << (15 - gpio); | ||
545 | |||
546 | return !!(in_be16(&iop->dat) & pin_mask); | ||
547 | } | ||
548 | |||
549 | static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
550 | { | ||
551 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
552 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); | ||
553 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
554 | unsigned long flags; | ||
555 | u16 pin_mask = 1 << (15 - gpio); | ||
556 | |||
557 | spin_lock_irqsave(&cpm1_gc->lock, flags); | ||
558 | |||
559 | if (value) | ||
560 | cpm1_gc->cpdata |= pin_mask; | ||
561 | else | ||
562 | cpm1_gc->cpdata &= ~pin_mask; | ||
563 | |||
564 | out_be16(&iop->dat, cpm1_gc->cpdata); | ||
565 | |||
566 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | ||
567 | } | ||
568 | |||
569 | static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
570 | { | ||
571 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
572 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
573 | u16 pin_mask; | ||
574 | |||
575 | pin_mask = 1 << (15 - gpio); | ||
576 | |||
577 | setbits16(&iop->dir, pin_mask); | ||
578 | |||
579 | cpm1_gpio16_set(gc, gpio, val); | ||
580 | |||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
585 | { | ||
586 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
587 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
588 | u16 pin_mask; | ||
589 | |||
590 | pin_mask = 1 << (15 - gpio); | ||
591 | |||
592 | clrbits16(&iop->dir, pin_mask); | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | int cpm1_gpiochip_add16(struct device_node *np) | ||
598 | { | ||
599 | struct cpm1_gpio16_chip *cpm1_gc; | ||
600 | struct of_mm_gpio_chip *mm_gc; | ||
601 | struct of_gpio_chip *of_gc; | ||
602 | struct gpio_chip *gc; | ||
603 | |||
604 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | ||
605 | if (!cpm1_gc) | ||
606 | return -ENOMEM; | ||
607 | |||
608 | spin_lock_init(&cpm1_gc->lock); | ||
609 | |||
610 | mm_gc = &cpm1_gc->mm_gc; | ||
611 | of_gc = &mm_gc->of_gc; | ||
612 | gc = &of_gc->gc; | ||
613 | |||
614 | mm_gc->save_regs = cpm1_gpio16_save_regs; | ||
615 | of_gc->gpio_cells = 2; | ||
616 | gc->ngpio = 16; | ||
617 | gc->direction_input = cpm1_gpio16_dir_in; | ||
618 | gc->direction_output = cpm1_gpio16_dir_out; | ||
619 | gc->get = cpm1_gpio16_get; | ||
620 | gc->set = cpm1_gpio16_set; | ||
621 | |||
622 | return of_mm_gpiochip_add(np, mm_gc); | ||
623 | } | ||
624 | |||
625 | struct cpm1_gpio32_chip { | ||
626 | struct of_mm_gpio_chip mm_gc; | ||
627 | spinlock_t lock; | ||
628 | |||
629 | /* shadowed data register to clear/set bits safely */ | ||
630 | u32 cpdata; | ||
631 | }; | ||
632 | |||
633 | static inline struct cpm1_gpio32_chip * | ||
634 | to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc) | ||
635 | { | ||
636 | return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc); | ||
637 | } | ||
638 | |||
639 | static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
640 | { | ||
641 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); | ||
642 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
643 | |||
644 | cpm1_gc->cpdata = in_be32(&iop->dat); | ||
645 | } | ||
646 | |||
647 | static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio) | ||
648 | { | ||
649 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
650 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
651 | u32 pin_mask; | ||
652 | |||
653 | pin_mask = 1 << (31 - gpio); | ||
654 | |||
655 | return !!(in_be32(&iop->dat) & pin_mask); | ||
656 | } | ||
657 | |||
658 | static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
659 | { | ||
660 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
661 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); | ||
662 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
663 | unsigned long flags; | ||
664 | u32 pin_mask = 1 << (31 - gpio); | ||
665 | |||
666 | spin_lock_irqsave(&cpm1_gc->lock, flags); | ||
667 | |||
668 | if (value) | ||
669 | cpm1_gc->cpdata |= pin_mask; | ||
670 | else | ||
671 | cpm1_gc->cpdata &= ~pin_mask; | ||
672 | |||
673 | out_be32(&iop->dat, cpm1_gc->cpdata); | ||
674 | |||
675 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | ||
676 | } | ||
677 | |||
678 | static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
679 | { | ||
680 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
681 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
682 | u32 pin_mask; | ||
683 | |||
684 | pin_mask = 1 << (31 - gpio); | ||
685 | |||
686 | setbits32(&iop->dir, pin_mask); | ||
687 | |||
688 | cpm1_gpio32_set(gc, gpio, val); | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
694 | { | ||
695 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
696 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
697 | u32 pin_mask; | ||
698 | |||
699 | pin_mask = 1 << (31 - gpio); | ||
700 | |||
701 | clrbits32(&iop->dir, pin_mask); | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | int cpm1_gpiochip_add32(struct device_node *np) | ||
707 | { | ||
708 | struct cpm1_gpio32_chip *cpm1_gc; | ||
709 | struct of_mm_gpio_chip *mm_gc; | ||
710 | struct of_gpio_chip *of_gc; | ||
711 | struct gpio_chip *gc; | ||
712 | |||
713 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | ||
714 | if (!cpm1_gc) | ||
715 | return -ENOMEM; | ||
716 | |||
717 | spin_lock_init(&cpm1_gc->lock); | ||
718 | |||
719 | mm_gc = &cpm1_gc->mm_gc; | ||
720 | of_gc = &mm_gc->of_gc; | ||
721 | gc = &of_gc->gc; | ||
722 | |||
723 | mm_gc->save_regs = cpm1_gpio32_save_regs; | ||
724 | of_gc->gpio_cells = 2; | ||
725 | gc->ngpio = 32; | ||
726 | gc->direction_input = cpm1_gpio32_dir_in; | ||
727 | gc->direction_output = cpm1_gpio32_dir_out; | ||
728 | gc->get = cpm1_gpio32_get; | ||
729 | gc->set = cpm1_gpio32_set; | ||
730 | |||
731 | return of_mm_gpiochip_add(np, mm_gc); | ||
732 | } | ||
733 | |||
734 | static int cpm_init_par_io(void) | ||
735 | { | ||
736 | struct device_node *np; | ||
737 | |||
738 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a") | ||
739 | cpm1_gpiochip_add16(np); | ||
740 | |||
741 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b") | ||
742 | cpm1_gpiochip_add32(np); | ||
743 | |||
744 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c") | ||
745 | cpm1_gpiochip_add16(np); | ||
746 | |||
747 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d") | ||
748 | cpm1_gpiochip_add16(np); | ||
749 | |||
750 | /* Port E uses CPM2 layout */ | ||
751 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e") | ||
752 | cpm2_gpiochip_add32(np); | ||
753 | return 0; | ||
754 | } | ||
755 | arch_initcall(cpm_init_par_io); | ||
756 | |||
757 | #endif /* CONFIG_8xx_GPIO */ | ||
diff --git a/arch/powerpc/sysdev/cpm2.c b/arch/powerpc/sysdev/cpm2.c index 5a6c5dfc53ef..f1c3395633b9 100644 --- a/arch/powerpc/sysdev/cpm2.c +++ b/arch/powerpc/sysdev/cpm2.c | |||
@@ -115,16 +115,10 @@ EXPORT_SYMBOL(cpm_command); | |||
115 | * Baud rate clocks are zero-based in the driver code (as that maps | 115 | * Baud rate clocks are zero-based in the driver code (as that maps |
116 | * to port numbers). Documentation uses 1-based numbering. | 116 | * to port numbers). Documentation uses 1-based numbering. |
117 | */ | 117 | */ |
118 | #define BRG_INT_CLK (get_brgfreq()) | 118 | void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src) |
119 | #define BRG_UART_CLK (BRG_INT_CLK/16) | ||
120 | |||
121 | /* This function is used by UARTS, or anything else that uses a 16x | ||
122 | * oversampled clock. | ||
123 | */ | ||
124 | void | ||
125 | cpm_setbrg(uint brg, uint rate) | ||
126 | { | 119 | { |
127 | u32 __iomem *bp; | 120 | u32 __iomem *bp; |
121 | u32 val; | ||
128 | 122 | ||
129 | /* This is good enough to get SMCs running..... | 123 | /* This is good enough to get SMCs running..... |
130 | */ | 124 | */ |
@@ -135,34 +129,14 @@ cpm_setbrg(uint brg, uint rate) | |||
135 | brg -= 4; | 129 | brg -= 4; |
136 | } | 130 | } |
137 | bp += brg; | 131 | bp += brg; |
138 | out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); | 132 | val = (((clk / rate) - 1) << 1) | CPM_BRG_EN | src; |
139 | |||
140 | cpm2_unmap(bp); | ||
141 | } | ||
142 | |||
143 | /* This function is used to set high speed synchronous baud rate | ||
144 | * clocks. | ||
145 | */ | ||
146 | void | ||
147 | cpm2_fastbrg(uint brg, uint rate, int div16) | ||
148 | { | ||
149 | u32 __iomem *bp; | ||
150 | u32 val; | ||
151 | |||
152 | if (brg < 4) { | ||
153 | bp = cpm2_map_size(im_brgc1, 16); | ||
154 | } else { | ||
155 | bp = cpm2_map_size(im_brgc5, 16); | ||
156 | brg -= 4; | ||
157 | } | ||
158 | bp += brg; | ||
159 | val = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN; | ||
160 | if (div16) | 133 | if (div16) |
161 | val |= CPM_BRG_DIV16; | 134 | val |= CPM_BRG_DIV16; |
162 | 135 | ||
163 | out_be32(bp, val); | 136 | out_be32(bp, val); |
164 | cpm2_unmap(bp); | 137 | cpm2_unmap(bp); |
165 | } | 138 | } |
139 | EXPORT_SYMBOL(__cpm2_setbrg); | ||
166 | 140 | ||
167 | int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) | 141 | int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) |
168 | { | 142 | { |
@@ -377,3 +351,14 @@ void cpm2_set_pin(int port, int pin, int flags) | |||
377 | else | 351 | else |
378 | clrbits32(&iop[port].odr, pin); | 352 | clrbits32(&iop[port].odr, pin); |
379 | } | 353 | } |
354 | |||
355 | static int cpm_init_par_io(void) | ||
356 | { | ||
357 | struct device_node *np; | ||
358 | |||
359 | for_each_compatible_node(np, NULL, "fsl,cpm2-pario-bank") | ||
360 | cpm2_gpiochip_add32(np); | ||
361 | return 0; | ||
362 | } | ||
363 | arch_initcall(cpm_init_par_io); | ||
364 | |||
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index e4b7296acb2c..53da8a079f96 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c | |||
@@ -19,6 +19,8 @@ | |||
19 | 19 | ||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/of_device.h> | 21 | #include <linux/of_device.h> |
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/of.h> | ||
22 | 24 | ||
23 | #include <asm/udbg.h> | 25 | #include <asm/udbg.h> |
24 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -28,6 +30,10 @@ | |||
28 | 30 | ||
29 | #include <mm/mmu_decl.h> | 31 | #include <mm/mmu_decl.h> |
30 | 32 | ||
33 | #if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO) | ||
34 | #include <linux/of_gpio.h> | ||
35 | #endif | ||
36 | |||
31 | #ifdef CONFIG_PPC_EARLY_DEBUG_CPM | 37 | #ifdef CONFIG_PPC_EARLY_DEBUG_CPM |
32 | static u32 __iomem *cpm_udbg_txdesc = | 38 | static u32 __iomem *cpm_udbg_txdesc = |
33 | (u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR; | 39 | (u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR; |
@@ -207,3 +213,120 @@ dma_addr_t cpm_muram_dma(void __iomem *addr) | |||
207 | return muram_pbase + ((u8 __iomem *)addr - muram_vbase); | 213 | return muram_pbase + ((u8 __iomem *)addr - muram_vbase); |
208 | } | 214 | } |
209 | EXPORT_SYMBOL(cpm_muram_dma); | 215 | EXPORT_SYMBOL(cpm_muram_dma); |
216 | |||
217 | #if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO) | ||
218 | |||
219 | struct cpm2_ioports { | ||
220 | u32 dir, par, sor, odr, dat; | ||
221 | u32 res[3]; | ||
222 | }; | ||
223 | |||
224 | struct cpm2_gpio32_chip { | ||
225 | struct of_mm_gpio_chip mm_gc; | ||
226 | spinlock_t lock; | ||
227 | |||
228 | /* shadowed data register to clear/set bits safely */ | ||
229 | u32 cpdata; | ||
230 | }; | ||
231 | |||
232 | static inline struct cpm2_gpio32_chip * | ||
233 | to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc) | ||
234 | { | ||
235 | return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc); | ||
236 | } | ||
237 | |||
238 | static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
239 | { | ||
240 | struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); | ||
241 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
242 | |||
243 | cpm2_gc->cpdata = in_be32(&iop->dat); | ||
244 | } | ||
245 | |||
246 | static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio) | ||
247 | { | ||
248 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
249 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
250 | u32 pin_mask; | ||
251 | |||
252 | pin_mask = 1 << (31 - gpio); | ||
253 | |||
254 | return !!(in_be32(&iop->dat) & pin_mask); | ||
255 | } | ||
256 | |||
257 | static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
258 | { | ||
259 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
260 | struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); | ||
261 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
262 | unsigned long flags; | ||
263 | u32 pin_mask = 1 << (31 - gpio); | ||
264 | |||
265 | spin_lock_irqsave(&cpm2_gc->lock, flags); | ||
266 | |||
267 | if (value) | ||
268 | cpm2_gc->cpdata |= pin_mask; | ||
269 | else | ||
270 | cpm2_gc->cpdata &= ~pin_mask; | ||
271 | |||
272 | out_be32(&iop->dat, cpm2_gc->cpdata); | ||
273 | |||
274 | spin_unlock_irqrestore(&cpm2_gc->lock, flags); | ||
275 | } | ||
276 | |||
277 | static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
278 | { | ||
279 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
280 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
281 | u32 pin_mask; | ||
282 | |||
283 | pin_mask = 1 << (31 - gpio); | ||
284 | |||
285 | setbits32(&iop->dir, pin_mask); | ||
286 | |||
287 | cpm2_gpio32_set(gc, gpio, val); | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
293 | { | ||
294 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
295 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
296 | u32 pin_mask; | ||
297 | |||
298 | pin_mask = 1 << (31 - gpio); | ||
299 | |||
300 | clrbits32(&iop->dir, pin_mask); | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | int cpm2_gpiochip_add32(struct device_node *np) | ||
306 | { | ||
307 | struct cpm2_gpio32_chip *cpm2_gc; | ||
308 | struct of_mm_gpio_chip *mm_gc; | ||
309 | struct of_gpio_chip *of_gc; | ||
310 | struct gpio_chip *gc; | ||
311 | |||
312 | cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL); | ||
313 | if (!cpm2_gc) | ||
314 | return -ENOMEM; | ||
315 | |||
316 | spin_lock_init(&cpm2_gc->lock); | ||
317 | |||
318 | mm_gc = &cpm2_gc->mm_gc; | ||
319 | of_gc = &mm_gc->of_gc; | ||
320 | gc = &of_gc->gc; | ||
321 | |||
322 | mm_gc->save_regs = cpm2_gpio32_save_regs; | ||
323 | of_gc->gpio_cells = 2; | ||
324 | gc->ngpio = 32; | ||
325 | gc->direction_input = cpm2_gpio32_dir_in; | ||
326 | gc->direction_output = cpm2_gpio32_dir_out; | ||
327 | gc->get = cpm2_gpio32_get; | ||
328 | gc->set = cpm2_gpio32_set; | ||
329 | |||
330 | return of_mm_gpiochip_add(np, mm_gc); | ||
331 | } | ||
332 | #endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */ | ||
diff --git a/arch/powerpc/sysdev/rtc_cmos_setup.c b/arch/powerpc/sysdev/rtc_cmos_setup.c index c09ddc0dbeb3..c1879ebfd4f4 100644 --- a/arch/powerpc/sysdev/rtc_cmos_setup.c +++ b/arch/powerpc/sysdev/rtc_cmos_setup.c | |||
@@ -21,6 +21,7 @@ static int __init add_rtc(void) | |||
21 | struct device_node *np; | 21 | struct device_node *np; |
22 | struct platform_device *pd; | 22 | struct platform_device *pd; |
23 | struct resource res[2]; | 23 | struct resource res[2]; |
24 | unsigned int num_res = 1; | ||
24 | int ret; | 25 | int ret; |
25 | 26 | ||
26 | memset(&res, 0, sizeof(res)); | 27 | memset(&res, 0, sizeof(res)); |
@@ -41,14 +42,24 @@ static int __init add_rtc(void) | |||
41 | if (res[0].start != RTC_PORT(0)) | 42 | if (res[0].start != RTC_PORT(0)) |
42 | return -EINVAL; | 43 | return -EINVAL; |
43 | 44 | ||
44 | /* Use a fixed interrupt value of 8 since on PPC if we are using this | 45 | np = of_find_compatible_node(NULL, NULL, "chrp,iic"); |
45 | * its off an i8259 which we ensure has interrupt numbers 0..15. */ | 46 | if (!np) |
46 | res[1].start = 8; | 47 | np = of_find_compatible_node(NULL, NULL, "pnpPNP,000"); |
47 | res[1].end = 8; | 48 | if (np) { |
48 | res[1].flags = IORESOURCE_IRQ; | 49 | of_node_put(np); |
50 | /* | ||
51 | * Use a fixed interrupt value of 8 since on PPC if we are | ||
52 | * using this its off an i8259 which we ensure has interrupt | ||
53 | * numbers 0..15. | ||
54 | */ | ||
55 | res[1].start = 8; | ||
56 | res[1].end = 8; | ||
57 | res[1].flags = IORESOURCE_IRQ; | ||
58 | num_res++; | ||
59 | } | ||
49 | 60 | ||
50 | pd = platform_device_register_simple("rtc_cmos", -1, | 61 | pd = platform_device_register_simple("rtc_cmos", -1, |
51 | &res[0], 2); | 62 | &res[0], num_res); |
52 | 63 | ||
53 | if (IS_ERR(pd)) | 64 | if (IS_ERR(pd)) |
54 | return PTR_ERR(pd); | 65 | return PTR_ERR(pd); |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 2ed88122be93..8d41908e2513 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -317,6 +317,9 @@ config ARCH_ENABLE_MEMORY_HOTPLUG | |||
317 | def_bool y | 317 | def_bool y |
318 | depends on SPARSEMEM | 318 | depends on SPARSEMEM |
319 | 319 | ||
320 | config ARCH_ENABLE_MEMORY_HOTREMOVE | ||
321 | def_bool y | ||
322 | |||
320 | source "mm/Kconfig" | 323 | source "mm/Kconfig" |
321 | 324 | ||
322 | comment "I/O subsystem configuration" | 325 | comment "I/O subsystem configuration" |
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index d003a6e16afb..328a20e880b5 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S | |||
@@ -1732,3 +1732,40 @@ compat_sys_timerfd_gettime_wrapper: | |||
1732 | lgfr %r2,%r2 # int | 1732 | lgfr %r2,%r2 # int |
1733 | llgtr %r3,%r3 # struct compat_itimerspec * | 1733 | llgtr %r3,%r3 # struct compat_itimerspec * |
1734 | jg compat_sys_timerfd_gettime | 1734 | jg compat_sys_timerfd_gettime |
1735 | |||
1736 | .globl compat_sys_signalfd4_wrapper | ||
1737 | compat_sys_signalfd4_wrapper: | ||
1738 | lgfr %r2,%r2 # int | ||
1739 | llgtr %r3,%r3 # compat_sigset_t * | ||
1740 | llgfr %r4,%r4 # compat_size_t | ||
1741 | lgfr %r5,%r5 # int | ||
1742 | jg compat_sys_signalfd4 | ||
1743 | |||
1744 | .globl sys_eventfd2_wrapper | ||
1745 | sys_eventfd2_wrapper: | ||
1746 | llgfr %r2,%r2 # unsigned int | ||
1747 | lgfr %r3,%r3 # int | ||
1748 | jg sys_eventfd2 | ||
1749 | |||
1750 | .globl sys_inotify_init1_wrapper | ||
1751 | sys_inotify_init1_wrapper: | ||
1752 | lgfr %r2,%r2 # int | ||
1753 | jg sys_inotify_init1 | ||
1754 | |||
1755 | .globl sys_pipe2_wrapper | ||
1756 | sys_pipe2_wrapper: | ||
1757 | llgtr %r2,%r2 # u32 * | ||
1758 | lgfr %r3,%r3 # int | ||
1759 | jg sys_pipe2 # branch to system call | ||
1760 | |||
1761 | .globl sys_dup3_wrapper | ||
1762 | sys_dup3_wrapper: | ||
1763 | llgfr %r2,%r2 # unsigned int | ||
1764 | llgfr %r3,%r3 # unsigned int | ||
1765 | lgfr %r4,%r4 # int | ||
1766 | jg sys_dup3 # branch to system call | ||
1767 | |||
1768 | .globl sys_epoll_create1_wrapper | ||
1769 | sys_epoll_create1_wrapper: | ||
1770 | lgfr %r2,%r2 # int | ||
1771 | jg sys_epoll_create1 # branch to system call | ||
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 54b2779b5e2f..2dcf590faba6 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -1705,7 +1705,10 @@ void __init setup_ipl(void) | |||
1705 | 1705 | ||
1706 | void __init ipl_update_parameters(void) | 1706 | void __init ipl_update_parameters(void) |
1707 | { | 1707 | { |
1708 | if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK) | 1708 | int rc; |
1709 | |||
1710 | rc = diag308(DIAG308_STORE, &ipl_block); | ||
1711 | if ((rc == DIAG308_RC_OK) || (rc == DIAG308_RC_NOCONFIG)) | ||
1709 | diag308_set_works = 1; | 1712 | diag308_set_works = 1; |
1710 | } | 1713 | } |
1711 | 1714 | ||
diff --git a/arch/s390/kernel/mem_detect.c b/arch/s390/kernel/mem_detect.c index 18ed7abe16c5..9872999c66d1 100644 --- a/arch/s390/kernel/mem_detect.c +++ b/arch/s390/kernel/mem_detect.c | |||
@@ -9,27 +9,6 @@ | |||
9 | #include <asm/sclp.h> | 9 | #include <asm/sclp.h> |
10 | #include <asm/setup.h> | 10 | #include <asm/setup.h> |
11 | 11 | ||
12 | static int memory_fast_detect(struct mem_chunk *chunk) | ||
13 | { | ||
14 | unsigned long val0 = 0; | ||
15 | unsigned long val1 = 0xc; | ||
16 | int rc = -EOPNOTSUPP; | ||
17 | |||
18 | if (ipl_flags & IPL_NSS_VALID) | ||
19 | return -EOPNOTSUPP; | ||
20 | asm volatile( | ||
21 | " diag %1,%2,0x260\n" | ||
22 | "0: lhi %0,0\n" | ||
23 | "1:\n" | ||
24 | EX_TABLE(0b,1b) | ||
25 | : "+d" (rc), "+d" (val0), "+d" (val1) : : "cc"); | ||
26 | |||
27 | if (rc || val0 != val1) | ||
28 | return -EOPNOTSUPP; | ||
29 | chunk->size = val0 + 1; | ||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | static inline int tprot(unsigned long addr) | 12 | static inline int tprot(unsigned long addr) |
34 | { | 13 | { |
35 | int rc = -EFAULT; | 14 | int rc = -EFAULT; |
@@ -84,8 +63,6 @@ void detect_memory_layout(struct mem_chunk chunk[]) | |||
84 | unsigned long flags, cr0; | 63 | unsigned long flags, cr0; |
85 | 64 | ||
86 | memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); | 65 | memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); |
87 | if (memory_fast_detect(&chunk[0]) == 0) | ||
88 | return; | ||
89 | /* Disable IRQs, DAT and low address protection so tprot does the | 66 | /* Disable IRQs, DAT and low address protection so tprot does the |
90 | * right thing and we don't get scheduled away with low address | 67 | * right thing and we don't get scheduled away with low address |
91 | * protection disabled. | 68 | * protection disabled. |
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index c87ec687d4c6..c66d35e55142 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
@@ -330,3 +330,9 @@ SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper) | |||
330 | SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper) | 330 | SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper) |
331 | SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime_wrapper) /* 320 */ | 331 | SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime_wrapper) /* 320 */ |
332 | SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime_wrapper) | 332 | SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime_wrapper) |
333 | SYSCALL(sys_signalfd4,sys_signalfd4,compat_sys_signalfd4_wrapper) | ||
334 | SYSCALL(sys_eventfd2,sys_eventfd2,sys_eventfd2_wrapper) | ||
335 | SYSCALL(sys_inotify_init1,sys_inotify_init1,sys_inotify_init1_wrapper) | ||
336 | SYSCALL(sys_pipe2,sys_pipe2,sys_pipe2_wrapper) /* 325 */ | ||
337 | SYSCALL(sys_dup3,sys_dup3,sys_dup3_wrapper) | ||
338 | SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper) | ||
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index ab70d9bd9261..ca114fe46ffb 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -1348,7 +1348,7 @@ early_param("stp", early_parse_stp); | |||
1348 | /* | 1348 | /* |
1349 | * Reset STP attachment. | 1349 | * Reset STP attachment. |
1350 | */ | 1350 | */ |
1351 | static void stp_reset(void) | 1351 | static void __init stp_reset(void) |
1352 | { | 1352 | { |
1353 | int rc; | 1353 | int rc; |
1354 | 1354 | ||
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index eae21a8ac72d..fc6ab6094df8 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c | |||
@@ -43,7 +43,7 @@ void __udelay(unsigned long usecs) | |||
43 | local_bh_disable(); | 43 | local_bh_disable(); |
44 | local_irq_save(flags); | 44 | local_irq_save(flags); |
45 | if (raw_irqs_disabled_flags(flags)) { | 45 | if (raw_irqs_disabled_flags(flags)) { |
46 | old_cc = S390_lowcore.clock_comparator; | 46 | old_cc = local_tick_disable(); |
47 | S390_lowcore.clock_comparator = -1ULL; | 47 | S390_lowcore.clock_comparator = -1ULL; |
48 | __ctl_store(cr0, 0, 0); | 48 | __ctl_store(cr0, 0, 0); |
49 | dummy = (cr0 & 0xffff00e0) | 0x00000800; | 49 | dummy = (cr0 & 0xffff00e0) | 0x00000800; |
@@ -65,7 +65,7 @@ void __udelay(unsigned long usecs) | |||
65 | 65 | ||
66 | if (raw_irqs_disabled_flags(flags)) { | 66 | if (raw_irqs_disabled_flags(flags)) { |
67 | __ctl_load(cr0, 0, 0); | 67 | __ctl_load(cr0, 0, 0); |
68 | S390_lowcore.clock_comparator = old_cc; | 68 | local_tick_enable(old_cc); |
69 | } | 69 | } |
70 | if (!irq_context) | 70 | if (!irq_context) |
71 | _local_bh_enable(); | 71 | _local_bh_enable(); |
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 4993b0f594eb..1169130a97ef 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c | |||
@@ -179,7 +179,7 @@ int arch_add_memory(int nid, u64 start, u64 size) | |||
179 | int rc; | 179 | int rc; |
180 | 180 | ||
181 | pgdat = NODE_DATA(nid); | 181 | pgdat = NODE_DATA(nid); |
182 | zone = pgdat->node_zones + ZONE_NORMAL; | 182 | zone = pgdat->node_zones + ZONE_MOVABLE; |
183 | rc = vmem_add_mapping(start, size); | 183 | rc = vmem_add_mapping(start, size); |
184 | if (rc) | 184 | if (rc) |
185 | return rc; | 185 | return rc; |
@@ -189,3 +189,14 @@ int arch_add_memory(int nid, u64 start, u64 size) | |||
189 | return rc; | 189 | return rc; |
190 | } | 190 | } |
191 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 191 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
192 | |||
193 | #ifdef CONFIG_MEMORY_HOTREMOVE | ||
194 | int remove_memory(u64 start, u64 size) | ||
195 | { | ||
196 | unsigned long start_pfn, end_pfn; | ||
197 | |||
198 | start_pfn = PFN_DOWN(start); | ||
199 | end_pfn = start_pfn + PFN_DOWN(size); | ||
200 | return offline_pages(start_pfn, end_pfn, 120 * HZ); | ||
201 | } | ||
202 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | ||
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 2b742206ba07..cb992c3d6b71 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -11,6 +11,7 @@ config SUPERH | |||
11 | select HAVE_CLK | 11 | select HAVE_CLK |
12 | select HAVE_IDE | 12 | select HAVE_IDE |
13 | select HAVE_OPROFILE | 13 | select HAVE_OPROFILE |
14 | select HAVE_GENERIC_DMA_COHERENT | ||
14 | help | 15 | help |
15 | The SuperH is a RISC processor targeted for use in embedded systems | 16 | The SuperH is a RISC processor targeted for use in embedded systems |
16 | and consumer electronics; it was also used in the Sega Dreamcast | 17 | and consumer electronics; it was also used in the Sega Dreamcast |
diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 6c0b8a2de143..627315ecdb52 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/scatterlist.h> | 5 | #include <linux/scatterlist.h> |
6 | #include <asm/cacheflush.h> | 6 | #include <asm/cacheflush.h> |
7 | #include <asm/io.h> | 7 | #include <asm/io.h> |
8 | #include <asm-generic/dma-coherent.h> | ||
8 | 9 | ||
9 | extern struct bus_type pci_bus_type; | 10 | extern struct bus_type pci_bus_type; |
10 | 11 | ||
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index 8277982d0938..b2ce014401b5 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c | |||
@@ -28,21 +28,10 @@ void *dma_alloc_coherent(struct device *dev, size_t size, | |||
28 | dma_addr_t *dma_handle, gfp_t gfp) | 28 | dma_addr_t *dma_handle, gfp_t gfp) |
29 | { | 29 | { |
30 | void *ret, *ret_nocache; | 30 | void *ret, *ret_nocache; |
31 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
32 | int order = get_order(size); | 31 | int order = get_order(size); |
33 | 32 | ||
34 | if (mem) { | 33 | if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) |
35 | int page = bitmap_find_free_region(mem->bitmap, mem->size, | 34 | return ret; |
36 | order); | ||
37 | if (page >= 0) { | ||
38 | *dma_handle = mem->device_base + (page << PAGE_SHIFT); | ||
39 | ret = mem->virt_base + (page << PAGE_SHIFT); | ||
40 | memset(ret, 0, size); | ||
41 | return ret; | ||
42 | } | ||
43 | if (mem->flags & DMA_MEMORY_EXCLUSIVE) | ||
44 | return NULL; | ||
45 | } | ||
46 | 35 | ||
47 | ret = (void *)__get_free_pages(gfp, order); | 36 | ret = (void *)__get_free_pages(gfp, order); |
48 | if (!ret) | 37 | if (!ret) |
@@ -72,11 +61,7 @@ void dma_free_coherent(struct device *dev, size_t size, | |||
72 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | 61 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; |
73 | int order = get_order(size); | 62 | int order = get_order(size); |
74 | 63 | ||
75 | if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { | 64 | if (!dma_release_from_coherent(dev, order, vaddr)) { |
76 | int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; | ||
77 | |||
78 | bitmap_release_region(mem->bitmap, page, order); | ||
79 | } else { | ||
80 | WARN_ON(irqs_disabled()); /* for portability */ | 65 | WARN_ON(irqs_disabled()); /* for portability */ |
81 | BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE); | 66 | BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE); |
82 | free_pages((unsigned long)phys_to_virt(dma_handle), order); | 67 | free_pages((unsigned long)phys_to_virt(dma_handle), order); |
@@ -85,83 +70,6 @@ void dma_free_coherent(struct device *dev, size_t size, | |||
85 | } | 70 | } |
86 | EXPORT_SYMBOL(dma_free_coherent); | 71 | EXPORT_SYMBOL(dma_free_coherent); |
87 | 72 | ||
88 | int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
89 | dma_addr_t device_addr, size_t size, int flags) | ||
90 | { | ||
91 | void __iomem *mem_base = NULL; | ||
92 | int pages = size >> PAGE_SHIFT; | ||
93 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
94 | |||
95 | if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) | ||
96 | goto out; | ||
97 | if (!size) | ||
98 | goto out; | ||
99 | if (dev->dma_mem) | ||
100 | goto out; | ||
101 | |||
102 | /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ | ||
103 | |||
104 | mem_base = ioremap_nocache(bus_addr, size); | ||
105 | if (!mem_base) | ||
106 | goto out; | ||
107 | |||
108 | dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); | ||
109 | if (!dev->dma_mem) | ||
110 | goto out; | ||
111 | dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
112 | if (!dev->dma_mem->bitmap) | ||
113 | goto free1_out; | ||
114 | |||
115 | dev->dma_mem->virt_base = mem_base; | ||
116 | dev->dma_mem->device_base = device_addr; | ||
117 | dev->dma_mem->size = pages; | ||
118 | dev->dma_mem->flags = flags; | ||
119 | |||
120 | if (flags & DMA_MEMORY_MAP) | ||
121 | return DMA_MEMORY_MAP; | ||
122 | |||
123 | return DMA_MEMORY_IO; | ||
124 | |||
125 | free1_out: | ||
126 | kfree(dev->dma_mem); | ||
127 | out: | ||
128 | if (mem_base) | ||
129 | iounmap(mem_base); | ||
130 | return 0; | ||
131 | } | ||
132 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
133 | |||
134 | void dma_release_declared_memory(struct device *dev) | ||
135 | { | ||
136 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
137 | |||
138 | if (!mem) | ||
139 | return; | ||
140 | dev->dma_mem = NULL; | ||
141 | iounmap(mem->virt_base); | ||
142 | kfree(mem->bitmap); | ||
143 | kfree(mem); | ||
144 | } | ||
145 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
146 | |||
147 | void *dma_mark_declared_memory_occupied(struct device *dev, | ||
148 | dma_addr_t device_addr, size_t size) | ||
149 | { | ||
150 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
151 | int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
152 | int pos, err; | ||
153 | |||
154 | if (!mem) | ||
155 | return ERR_PTR(-EINVAL); | ||
156 | |||
157 | pos = (device_addr - mem->device_base) >> PAGE_SHIFT; | ||
158 | err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); | ||
159 | if (err != 0) | ||
160 | return ERR_PTR(err); | ||
161 | return mem->virt_base + (pos << PAGE_SHIFT); | ||
162 | } | ||
163 | EXPORT_SYMBOL(dma_mark_declared_memory_occupied); | ||
164 | |||
165 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, | 73 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, |
166 | enum dma_data_direction direction) | 74 | enum dma_data_direction direction) |
167 | { | 75 | { |
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 5047490fc299..d741f35d7b3a 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -362,19 +362,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data) | |||
362 | if (tty == NULL) | 362 | if (tty == NULL) |
363 | return IRQ_NONE; | 363 | return IRQ_NONE; |
364 | 364 | ||
365 | if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && | 365 | tty_wakeup(tty); |
366 | (tty->ldisc.write_wakeup != NULL)) | ||
367 | (tty->ldisc.write_wakeup)(tty); | ||
368 | |||
369 | /* | ||
370 | * BLOCKING mode | ||
371 | * In blocking mode, everything sleeps on tty->write_wait. | ||
372 | * Sleeping in the console driver would break non-blocking | ||
373 | * writes. | ||
374 | */ | ||
375 | |||
376 | if (waitqueue_active(&tty->write_wait)) | ||
377 | wake_up_interruptible(&tty->write_wait); | ||
378 | return IRQ_HANDLED; | 366 | return IRQ_HANDLED; |
379 | } | 367 | } |
380 | 368 | ||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b6fa2877b173..3d0f2b6a5a16 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -30,6 +30,7 @@ config X86 | |||
30 | select HAVE_FTRACE | 30 | select HAVE_FTRACE |
31 | select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) | 31 | select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) |
32 | select HAVE_ARCH_KGDB if !X86_VOYAGER | 32 | select HAVE_ARCH_KGDB if !X86_VOYAGER |
33 | select HAVE_GENERIC_DMA_COHERENT if X86_32 | ||
33 | select HAVE_EFFICIENT_UNALIGNED_ACCESS | 34 | select HAVE_EFFICIENT_UNALIGNED_ACCESS |
34 | 35 | ||
35 | config ARCH_DEFCONFIG | 36 | config ARCH_DEFCONFIG |
diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c index 9220cf46aa10..c2502eb9aa83 100644 --- a/arch/x86/kernel/acpi/cstate.c +++ b/arch/x86/kernel/acpi/cstate.c | |||
@@ -73,7 +73,6 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu, | |||
73 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 73 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
74 | 74 | ||
75 | cpumask_t saved_mask; | 75 | cpumask_t saved_mask; |
76 | cpumask_of_cpu_ptr(new_mask, cpu); | ||
77 | int retval; | 76 | int retval; |
78 | unsigned int eax, ebx, ecx, edx; | 77 | unsigned int eax, ebx, ecx, edx; |
79 | unsigned int edx_part; | 78 | unsigned int edx_part; |
@@ -92,7 +91,7 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu, | |||
92 | 91 | ||
93 | /* Make sure we are running on right CPU */ | 92 | /* Make sure we are running on right CPU */ |
94 | saved_mask = current->cpus_allowed; | 93 | saved_mask = current->cpus_allowed; |
95 | retval = set_cpus_allowed_ptr(current, new_mask); | 94 | retval = set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
96 | if (retval) | 95 | if (retval) |
97 | return -1; | 96 | return -1; |
98 | 97 | ||
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 74697408576f..22d7d050905d 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
@@ -29,9 +29,6 @@ | |||
29 | 29 | ||
30 | #define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28)) | 30 | #define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28)) |
31 | 31 | ||
32 | #define to_pages(addr, size) \ | ||
33 | (round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT) | ||
34 | |||
35 | #define EXIT_LOOP_COUNT 10000000 | 32 | #define EXIT_LOOP_COUNT 10000000 |
36 | 33 | ||
37 | static DEFINE_RWLOCK(amd_iommu_devtable_lock); | 34 | static DEFINE_RWLOCK(amd_iommu_devtable_lock); |
@@ -185,7 +182,7 @@ static int iommu_flush_pages(struct amd_iommu *iommu, u16 domid, | |||
185 | u64 address, size_t size) | 182 | u64 address, size_t size) |
186 | { | 183 | { |
187 | int s = 0; | 184 | int s = 0; |
188 | unsigned pages = to_pages(address, size); | 185 | unsigned pages = iommu_num_pages(address, size); |
189 | 186 | ||
190 | address &= PAGE_MASK; | 187 | address &= PAGE_MASK; |
191 | 188 | ||
@@ -557,8 +554,8 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu, | |||
557 | if (iommu->exclusion_start && | 554 | if (iommu->exclusion_start && |
558 | iommu->exclusion_start < dma_dom->aperture_size) { | 555 | iommu->exclusion_start < dma_dom->aperture_size) { |
559 | unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT; | 556 | unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT; |
560 | int pages = to_pages(iommu->exclusion_start, | 557 | int pages = iommu_num_pages(iommu->exclusion_start, |
561 | iommu->exclusion_length); | 558 | iommu->exclusion_length); |
562 | dma_ops_reserve_addresses(dma_dom, startpage, pages); | 559 | dma_ops_reserve_addresses(dma_dom, startpage, pages); |
563 | } | 560 | } |
564 | 561 | ||
@@ -767,7 +764,7 @@ static dma_addr_t __map_single(struct device *dev, | |||
767 | unsigned int pages; | 764 | unsigned int pages; |
768 | int i; | 765 | int i; |
769 | 766 | ||
770 | pages = to_pages(paddr, size); | 767 | pages = iommu_num_pages(paddr, size); |
771 | paddr &= PAGE_MASK; | 768 | paddr &= PAGE_MASK; |
772 | 769 | ||
773 | address = dma_ops_alloc_addresses(dev, dma_dom, pages); | 770 | address = dma_ops_alloc_addresses(dev, dma_dom, pages); |
@@ -802,7 +799,7 @@ static void __unmap_single(struct amd_iommu *iommu, | |||
802 | if ((dma_addr == 0) || (dma_addr + size > dma_dom->aperture_size)) | 799 | if ((dma_addr == 0) || (dma_addr + size > dma_dom->aperture_size)) |
803 | return; | 800 | return; |
804 | 801 | ||
805 | pages = to_pages(dma_addr, size); | 802 | pages = iommu_num_pages(dma_addr, size); |
806 | dma_addr &= PAGE_MASK; | 803 | dma_addr &= PAGE_MASK; |
807 | start = dma_addr; | 804 | start = dma_addr; |
808 | 805 | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index ff2fff56f0a8..dd097b835839 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
@@ -200,12 +200,10 @@ static void drv_read(struct drv_cmd *cmd) | |||
200 | static void drv_write(struct drv_cmd *cmd) | 200 | static void drv_write(struct drv_cmd *cmd) |
201 | { | 201 | { |
202 | cpumask_t saved_mask = current->cpus_allowed; | 202 | cpumask_t saved_mask = current->cpus_allowed; |
203 | cpumask_of_cpu_ptr_declare(cpu_mask); | ||
204 | unsigned int i; | 203 | unsigned int i; |
205 | 204 | ||
206 | for_each_cpu_mask_nr(i, cmd->mask) { | 205 | for_each_cpu_mask_nr(i, cmd->mask) { |
207 | cpumask_of_cpu_ptr_next(cpu_mask, i); | 206 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(i)); |
208 | set_cpus_allowed_ptr(current, cpu_mask); | ||
209 | do_drv_write(cmd); | 207 | do_drv_write(cmd); |
210 | } | 208 | } |
211 | 209 | ||
@@ -269,12 +267,11 @@ static unsigned int get_measured_perf(unsigned int cpu) | |||
269 | } aperf_cur, mperf_cur; | 267 | } aperf_cur, mperf_cur; |
270 | 268 | ||
271 | cpumask_t saved_mask; | 269 | cpumask_t saved_mask; |
272 | cpumask_of_cpu_ptr(cpu_mask, cpu); | ||
273 | unsigned int perf_percent; | 270 | unsigned int perf_percent; |
274 | unsigned int retval; | 271 | unsigned int retval; |
275 | 272 | ||
276 | saved_mask = current->cpus_allowed; | 273 | saved_mask = current->cpus_allowed; |
277 | set_cpus_allowed_ptr(current, cpu_mask); | 274 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
278 | if (get_cpu() != cpu) { | 275 | if (get_cpu() != cpu) { |
279 | /* We were not able to run on requested processor */ | 276 | /* We were not able to run on requested processor */ |
280 | put_cpu(); | 277 | put_cpu(); |
@@ -340,7 +337,6 @@ static unsigned int get_measured_perf(unsigned int cpu) | |||
340 | 337 | ||
341 | static unsigned int get_cur_freq_on_cpu(unsigned int cpu) | 338 | static unsigned int get_cur_freq_on_cpu(unsigned int cpu) |
342 | { | 339 | { |
343 | cpumask_of_cpu_ptr(cpu_mask, cpu); | ||
344 | struct acpi_cpufreq_data *data = per_cpu(drv_data, cpu); | 340 | struct acpi_cpufreq_data *data = per_cpu(drv_data, cpu); |
345 | unsigned int freq; | 341 | unsigned int freq; |
346 | unsigned int cached_freq; | 342 | unsigned int cached_freq; |
@@ -353,7 +349,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) | |||
353 | } | 349 | } |
354 | 350 | ||
355 | cached_freq = data->freq_table[data->acpi_data->state].frequency; | 351 | cached_freq = data->freq_table[data->acpi_data->state].frequency; |
356 | freq = extract_freq(get_cur_val(cpu_mask), data); | 352 | freq = extract_freq(get_cur_val(&cpumask_of_cpu(cpu)), data); |
357 | if (freq != cached_freq) { | 353 | if (freq != cached_freq) { |
358 | /* | 354 | /* |
359 | * The dreaded BIOS frequency change behind our back. | 355 | * The dreaded BIOS frequency change behind our back. |
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c index 53c7b6936973..c45ca6d4dce1 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c | |||
@@ -479,12 +479,11 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvi | |||
479 | static int check_supported_cpu(unsigned int cpu) | 479 | static int check_supported_cpu(unsigned int cpu) |
480 | { | 480 | { |
481 | cpumask_t oldmask; | 481 | cpumask_t oldmask; |
482 | cpumask_of_cpu_ptr(cpu_mask, cpu); | ||
483 | u32 eax, ebx, ecx, edx; | 482 | u32 eax, ebx, ecx, edx; |
484 | unsigned int rc = 0; | 483 | unsigned int rc = 0; |
485 | 484 | ||
486 | oldmask = current->cpus_allowed; | 485 | oldmask = current->cpus_allowed; |
487 | set_cpus_allowed_ptr(current, cpu_mask); | 486 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
488 | 487 | ||
489 | if (smp_processor_id() != cpu) { | 488 | if (smp_processor_id() != cpu) { |
490 | printk(KERN_ERR PFX "limiting to cpu %u failed\n", cpu); | 489 | printk(KERN_ERR PFX "limiting to cpu %u failed\n", cpu); |
@@ -1017,7 +1016,6 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i | |||
1017 | static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsigned relation) | 1016 | static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsigned relation) |
1018 | { | 1017 | { |
1019 | cpumask_t oldmask; | 1018 | cpumask_t oldmask; |
1020 | cpumask_of_cpu_ptr(cpu_mask, pol->cpu); | ||
1021 | struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); | 1019 | struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); |
1022 | u32 checkfid; | 1020 | u32 checkfid; |
1023 | u32 checkvid; | 1021 | u32 checkvid; |
@@ -1032,7 +1030,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi | |||
1032 | 1030 | ||
1033 | /* only run on specific CPU from here on */ | 1031 | /* only run on specific CPU from here on */ |
1034 | oldmask = current->cpus_allowed; | 1032 | oldmask = current->cpus_allowed; |
1035 | set_cpus_allowed_ptr(current, cpu_mask); | 1033 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(pol->cpu)); |
1036 | 1034 | ||
1037 | if (smp_processor_id() != pol->cpu) { | 1035 | if (smp_processor_id() != pol->cpu) { |
1038 | printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); | 1036 | printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); |
@@ -1107,7 +1105,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) | |||
1107 | { | 1105 | { |
1108 | struct powernow_k8_data *data; | 1106 | struct powernow_k8_data *data; |
1109 | cpumask_t oldmask; | 1107 | cpumask_t oldmask; |
1110 | cpumask_of_cpu_ptr_declare(newmask); | ||
1111 | int rc; | 1108 | int rc; |
1112 | 1109 | ||
1113 | if (!cpu_online(pol->cpu)) | 1110 | if (!cpu_online(pol->cpu)) |
@@ -1159,8 +1156,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) | |||
1159 | 1156 | ||
1160 | /* only run on specific CPU from here on */ | 1157 | /* only run on specific CPU from here on */ |
1161 | oldmask = current->cpus_allowed; | 1158 | oldmask = current->cpus_allowed; |
1162 | cpumask_of_cpu_ptr_next(newmask, pol->cpu); | 1159 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(pol->cpu)); |
1163 | set_cpus_allowed_ptr(current, newmask); | ||
1164 | 1160 | ||
1165 | if (smp_processor_id() != pol->cpu) { | 1161 | if (smp_processor_id() != pol->cpu) { |
1166 | printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); | 1162 | printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); |
@@ -1182,7 +1178,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) | |||
1182 | set_cpus_allowed_ptr(current, &oldmask); | 1178 | set_cpus_allowed_ptr(current, &oldmask); |
1183 | 1179 | ||
1184 | if (cpu_family == CPU_HW_PSTATE) | 1180 | if (cpu_family == CPU_HW_PSTATE) |
1185 | pol->cpus = *newmask; | 1181 | pol->cpus = cpumask_of_cpu(pol->cpu); |
1186 | else | 1182 | else |
1187 | pol->cpus = per_cpu(cpu_core_map, pol->cpu); | 1183 | pol->cpus = per_cpu(cpu_core_map, pol->cpu); |
1188 | data->available_cores = &(pol->cpus); | 1184 | data->available_cores = &(pol->cpus); |
@@ -1248,7 +1244,6 @@ static unsigned int powernowk8_get (unsigned int cpu) | |||
1248 | { | 1244 | { |
1249 | struct powernow_k8_data *data; | 1245 | struct powernow_k8_data *data; |
1250 | cpumask_t oldmask = current->cpus_allowed; | 1246 | cpumask_t oldmask = current->cpus_allowed; |
1251 | cpumask_of_cpu_ptr(newmask, cpu); | ||
1252 | unsigned int khz = 0; | 1247 | unsigned int khz = 0; |
1253 | unsigned int first; | 1248 | unsigned int first; |
1254 | 1249 | ||
@@ -1258,7 +1253,7 @@ static unsigned int powernowk8_get (unsigned int cpu) | |||
1258 | if (!data) | 1253 | if (!data) |
1259 | return -EINVAL; | 1254 | return -EINVAL; |
1260 | 1255 | ||
1261 | set_cpus_allowed_ptr(current, newmask); | 1256 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
1262 | if (smp_processor_id() != cpu) { | 1257 | if (smp_processor_id() != cpu) { |
1263 | printk(KERN_ERR PFX | 1258 | printk(KERN_ERR PFX |
1264 | "limiting to CPU %d failed in powernowk8_get\n", cpu); | 1259 | "limiting to CPU %d failed in powernowk8_get\n", cpu); |
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c index ca2ac13b7af2..15e13c01cc36 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c | |||
@@ -324,10 +324,9 @@ static unsigned int get_cur_freq(unsigned int cpu) | |||
324 | unsigned l, h; | 324 | unsigned l, h; |
325 | unsigned clock_freq; | 325 | unsigned clock_freq; |
326 | cpumask_t saved_mask; | 326 | cpumask_t saved_mask; |
327 | cpumask_of_cpu_ptr(new_mask, cpu); | ||
328 | 327 | ||
329 | saved_mask = current->cpus_allowed; | 328 | saved_mask = current->cpus_allowed; |
330 | set_cpus_allowed_ptr(current, new_mask); | 329 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
331 | if (smp_processor_id() != cpu) | 330 | if (smp_processor_id() != cpu) |
332 | return 0; | 331 | return 0; |
333 | 332 | ||
@@ -585,15 +584,12 @@ static int centrino_target (struct cpufreq_policy *policy, | |||
585 | * Best effort undo.. | 584 | * Best effort undo.. |
586 | */ | 585 | */ |
587 | 586 | ||
588 | if (!cpus_empty(*covered_cpus)) { | 587 | if (!cpus_empty(*covered_cpus)) |
589 | cpumask_of_cpu_ptr_declare(new_mask); | ||
590 | |||
591 | for_each_cpu_mask_nr(j, *covered_cpus) { | 588 | for_each_cpu_mask_nr(j, *covered_cpus) { |
592 | cpumask_of_cpu_ptr_next(new_mask, j); | 589 | set_cpus_allowed_ptr(current, |
593 | set_cpus_allowed_ptr(current, new_mask); | 590 | &cpumask_of_cpu(j)); |
594 | wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); | 591 | wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); |
595 | } | 592 | } |
596 | } | ||
597 | 593 | ||
598 | tmp = freqs.new; | 594 | tmp = freqs.new; |
599 | freqs.new = freqs.old; | 595 | freqs.new = freqs.old; |
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c index 2f3728dc24f6..191f7263c61d 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c | |||
@@ -244,8 +244,7 @@ static unsigned int _speedstep_get(const cpumask_t *cpus) | |||
244 | 244 | ||
245 | static unsigned int speedstep_get(unsigned int cpu) | 245 | static unsigned int speedstep_get(unsigned int cpu) |
246 | { | 246 | { |
247 | cpumask_of_cpu_ptr(newmask, cpu); | 247 | return _speedstep_get(&cpumask_of_cpu(cpu)); |
248 | return _speedstep_get(newmask); | ||
249 | } | 248 | } |
250 | 249 | ||
251 | /** | 250 | /** |
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 650d40f7912b..6b0a10b002f1 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c | |||
@@ -516,7 +516,6 @@ static int __cpuinit detect_cache_attributes(unsigned int cpu) | |||
516 | unsigned long j; | 516 | unsigned long j; |
517 | int retval; | 517 | int retval; |
518 | cpumask_t oldmask; | 518 | cpumask_t oldmask; |
519 | cpumask_of_cpu_ptr(newmask, cpu); | ||
520 | 519 | ||
521 | if (num_cache_leaves == 0) | 520 | if (num_cache_leaves == 0) |
522 | return -ENOENT; | 521 | return -ENOENT; |
@@ -527,7 +526,7 @@ static int __cpuinit detect_cache_attributes(unsigned int cpu) | |||
527 | return -ENOMEM; | 526 | return -ENOMEM; |
528 | 527 | ||
529 | oldmask = current->cpus_allowed; | 528 | oldmask = current->cpus_allowed; |
530 | retval = set_cpus_allowed_ptr(current, newmask); | 529 | retval = set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
531 | if (retval) | 530 | if (retval) |
532 | goto out; | 531 | goto out; |
533 | 532 | ||
diff --git a/arch/x86/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c index 1fa8be5bd217..eaff0bbb1444 100644 --- a/arch/x86/kernel/genapic_64.c +++ b/arch/x86/kernel/genapic_64.c | |||
@@ -99,3 +99,4 @@ int is_uv_system(void) | |||
99 | { | 99 | { |
100 | return uv_system_type != UV_NONE; | 100 | return uv_system_type != UV_NONE; |
101 | } | 101 | } |
102 | EXPORT_SYMBOL_GPL(is_uv_system); | ||
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index 3fee2aa50f3f..b68e21f06f4f 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c | |||
@@ -62,12 +62,10 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload) | |||
62 | 62 | ||
63 | if (reload) { | 63 | if (reload) { |
64 | #ifdef CONFIG_SMP | 64 | #ifdef CONFIG_SMP |
65 | cpumask_of_cpu_ptr_declare(mask); | ||
66 | |||
67 | preempt_disable(); | 65 | preempt_disable(); |
68 | load_LDT(pc); | 66 | load_LDT(pc); |
69 | cpumask_of_cpu_ptr_next(mask, smp_processor_id()); | 67 | if (!cpus_equal(current->mm->cpu_vm_mask, |
70 | if (!cpus_equal(current->mm->cpu_vm_mask, *mask)) | 68 | cpumask_of_cpu(smp_processor_id()))) |
71 | smp_call_function(flush_ldt, current->mm, 1); | 69 | smp_call_function(flush_ldt, current->mm, 1); |
72 | preempt_enable(); | 70 | preempt_enable(); |
73 | #else | 71 | #else |
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c index 6994c751590e..652fa5c38ebe 100644 --- a/arch/x86/kernel/microcode.c +++ b/arch/x86/kernel/microcode.c | |||
@@ -388,7 +388,6 @@ static int do_microcode_update (void) | |||
388 | void *new_mc = NULL; | 388 | void *new_mc = NULL; |
389 | int cpu; | 389 | int cpu; |
390 | cpumask_t old; | 390 | cpumask_t old; |
391 | cpumask_of_cpu_ptr_declare(newmask); | ||
392 | 391 | ||
393 | old = current->cpus_allowed; | 392 | old = current->cpus_allowed; |
394 | 393 | ||
@@ -405,8 +404,7 @@ static int do_microcode_update (void) | |||
405 | 404 | ||
406 | if (!uci->valid) | 405 | if (!uci->valid) |
407 | continue; | 406 | continue; |
408 | cpumask_of_cpu_ptr_next(newmask, cpu); | 407 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
409 | set_cpus_allowed_ptr(current, newmask); | ||
410 | error = get_maching_microcode(new_mc, cpu); | 408 | error = get_maching_microcode(new_mc, cpu); |
411 | if (error < 0) | 409 | if (error < 0) |
412 | goto out; | 410 | goto out; |
@@ -576,7 +574,6 @@ static int apply_microcode_check_cpu(int cpu) | |||
576 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 574 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
577 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 575 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
578 | cpumask_t old; | 576 | cpumask_t old; |
579 | cpumask_of_cpu_ptr(newmask, cpu); | ||
580 | unsigned int val[2]; | 577 | unsigned int val[2]; |
581 | int err = 0; | 578 | int err = 0; |
582 | 579 | ||
@@ -585,7 +582,7 @@ static int apply_microcode_check_cpu(int cpu) | |||
585 | return 0; | 582 | return 0; |
586 | 583 | ||
587 | old = current->cpus_allowed; | 584 | old = current->cpus_allowed; |
588 | set_cpus_allowed_ptr(current, newmask); | 585 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
589 | 586 | ||
590 | /* Check if the microcode we have in memory matches the CPU */ | 587 | /* Check if the microcode we have in memory matches the CPU */ |
591 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || | 588 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || |
@@ -623,12 +620,11 @@ static int apply_microcode_check_cpu(int cpu) | |||
623 | static void microcode_init_cpu(int cpu, int resume) | 620 | static void microcode_init_cpu(int cpu, int resume) |
624 | { | 621 | { |
625 | cpumask_t old; | 622 | cpumask_t old; |
626 | cpumask_of_cpu_ptr(newmask, cpu); | ||
627 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 623 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
628 | 624 | ||
629 | old = current->cpus_allowed; | 625 | old = current->cpus_allowed; |
630 | 626 | ||
631 | set_cpus_allowed_ptr(current, newmask); | 627 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
632 | mutex_lock(µcode_mutex); | 628 | mutex_lock(µcode_mutex); |
633 | collect_cpu_info(cpu); | 629 | collect_cpu_info(cpu); |
634 | if (uci->valid && system_state == SYSTEM_RUNNING && !resume) | 630 | if (uci->valid && system_state == SYSTEM_RUNNING && !resume) |
@@ -661,13 +657,10 @@ static ssize_t reload_store(struct sys_device *dev, | |||
661 | if (end == buf) | 657 | if (end == buf) |
662 | return -EINVAL; | 658 | return -EINVAL; |
663 | if (val == 1) { | 659 | if (val == 1) { |
664 | cpumask_t old; | 660 | cpumask_t old = current->cpus_allowed; |
665 | cpumask_of_cpu_ptr(newmask, cpu); | ||
666 | |||
667 | old = current->cpus_allowed; | ||
668 | 661 | ||
669 | get_online_cpus(); | 662 | get_online_cpus(); |
670 | set_cpus_allowed_ptr(current, newmask); | 663 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
671 | 664 | ||
672 | mutex_lock(µcode_mutex); | 665 | mutex_lock(µcode_mutex); |
673 | if (uci->valid) | 666 | if (uci->valid) |
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 37544123896d..87d4d6964ec2 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c | |||
@@ -123,6 +123,14 @@ void __init pci_iommu_alloc(void) | |||
123 | 123 | ||
124 | pci_swiotlb_init(); | 124 | pci_swiotlb_init(); |
125 | } | 125 | } |
126 | |||
127 | unsigned long iommu_num_pages(unsigned long addr, unsigned long len) | ||
128 | { | ||
129 | unsigned long size = roundup((addr & ~PAGE_MASK) + len, PAGE_SIZE); | ||
130 | |||
131 | return size >> PAGE_SHIFT; | ||
132 | } | ||
133 | EXPORT_SYMBOL(iommu_num_pages); | ||
126 | #endif | 134 | #endif |
127 | 135 | ||
128 | /* | 136 | /* |
@@ -192,124 +200,6 @@ static __init int iommu_setup(char *p) | |||
192 | } | 200 | } |
193 | early_param("iommu", iommu_setup); | 201 | early_param("iommu", iommu_setup); |
194 | 202 | ||
195 | #ifdef CONFIG_X86_32 | ||
196 | int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
197 | dma_addr_t device_addr, size_t size, int flags) | ||
198 | { | ||
199 | void __iomem *mem_base = NULL; | ||
200 | int pages = size >> PAGE_SHIFT; | ||
201 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
202 | |||
203 | if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) | ||
204 | goto out; | ||
205 | if (!size) | ||
206 | goto out; | ||
207 | if (dev->dma_mem) | ||
208 | goto out; | ||
209 | |||
210 | /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ | ||
211 | |||
212 | mem_base = ioremap(bus_addr, size); | ||
213 | if (!mem_base) | ||
214 | goto out; | ||
215 | |||
216 | dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); | ||
217 | if (!dev->dma_mem) | ||
218 | goto out; | ||
219 | dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
220 | if (!dev->dma_mem->bitmap) | ||
221 | goto free1_out; | ||
222 | |||
223 | dev->dma_mem->virt_base = mem_base; | ||
224 | dev->dma_mem->device_base = device_addr; | ||
225 | dev->dma_mem->size = pages; | ||
226 | dev->dma_mem->flags = flags; | ||
227 | |||
228 | if (flags & DMA_MEMORY_MAP) | ||
229 | return DMA_MEMORY_MAP; | ||
230 | |||
231 | return DMA_MEMORY_IO; | ||
232 | |||
233 | free1_out: | ||
234 | kfree(dev->dma_mem); | ||
235 | out: | ||
236 | if (mem_base) | ||
237 | iounmap(mem_base); | ||
238 | return 0; | ||
239 | } | ||
240 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
241 | |||
242 | void dma_release_declared_memory(struct device *dev) | ||
243 | { | ||
244 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
245 | |||
246 | if (!mem) | ||
247 | return; | ||
248 | dev->dma_mem = NULL; | ||
249 | iounmap(mem->virt_base); | ||
250 | kfree(mem->bitmap); | ||
251 | kfree(mem); | ||
252 | } | ||
253 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
254 | |||
255 | void *dma_mark_declared_memory_occupied(struct device *dev, | ||
256 | dma_addr_t device_addr, size_t size) | ||
257 | { | ||
258 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
259 | int pos, err; | ||
260 | int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1); | ||
261 | |||
262 | pages >>= PAGE_SHIFT; | ||
263 | |||
264 | if (!mem) | ||
265 | return ERR_PTR(-EINVAL); | ||
266 | |||
267 | pos = (device_addr - mem->device_base) >> PAGE_SHIFT; | ||
268 | err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); | ||
269 | if (err != 0) | ||
270 | return ERR_PTR(err); | ||
271 | return mem->virt_base + (pos << PAGE_SHIFT); | ||
272 | } | ||
273 | EXPORT_SYMBOL(dma_mark_declared_memory_occupied); | ||
274 | |||
275 | static int dma_alloc_from_coherent_mem(struct device *dev, ssize_t size, | ||
276 | dma_addr_t *dma_handle, void **ret) | ||
277 | { | ||
278 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
279 | int order = get_order(size); | ||
280 | |||
281 | if (mem) { | ||
282 | int page = bitmap_find_free_region(mem->bitmap, mem->size, | ||
283 | order); | ||
284 | if (page >= 0) { | ||
285 | *dma_handle = mem->device_base + (page << PAGE_SHIFT); | ||
286 | *ret = mem->virt_base + (page << PAGE_SHIFT); | ||
287 | memset(*ret, 0, size); | ||
288 | } | ||
289 | if (mem->flags & DMA_MEMORY_EXCLUSIVE) | ||
290 | *ret = NULL; | ||
291 | } | ||
292 | return (mem != NULL); | ||
293 | } | ||
294 | |||
295 | static int dma_release_coherent(struct device *dev, int order, void *vaddr) | ||
296 | { | ||
297 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
298 | |||
299 | if (mem && vaddr >= mem->virt_base && vaddr < | ||
300 | (mem->virt_base + (mem->size << PAGE_SHIFT))) { | ||
301 | int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; | ||
302 | |||
303 | bitmap_release_region(mem->bitmap, page, order); | ||
304 | return 1; | ||
305 | } | ||
306 | return 0; | ||
307 | } | ||
308 | #else | ||
309 | #define dma_alloc_from_coherent_mem(dev, size, handle, ret) (0) | ||
310 | #define dma_release_coherent(dev, order, vaddr) (0) | ||
311 | #endif /* CONFIG_X86_32 */ | ||
312 | |||
313 | int dma_supported(struct device *dev, u64 mask) | 203 | int dma_supported(struct device *dev, u64 mask) |
314 | { | 204 | { |
315 | struct dma_mapping_ops *ops = get_dma_ops(dev); | 205 | struct dma_mapping_ops *ops = get_dma_ops(dev); |
@@ -379,7 +269,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, | |||
379 | /* ignore region specifiers */ | 269 | /* ignore region specifiers */ |
380 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); | 270 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); |
381 | 271 | ||
382 | if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &memory)) | 272 | if (dma_alloc_from_coherent(dev, size, dma_handle, &memory)) |
383 | return memory; | 273 | return memory; |
384 | 274 | ||
385 | if (!dev) { | 275 | if (!dev) { |
@@ -484,7 +374,7 @@ void dma_free_coherent(struct device *dev, size_t size, | |||
484 | 374 | ||
485 | int order = get_order(size); | 375 | int order = get_order(size); |
486 | WARN_ON(irqs_disabled()); /* for portability */ | 376 | WARN_ON(irqs_disabled()); /* for portability */ |
487 | if (dma_release_coherent(dev, order, vaddr)) | 377 | if (dma_release_from_coherent(dev, order, vaddr)) |
488 | return; | 378 | return; |
489 | if (ops->unmap_single) | 379 | if (ops->unmap_single) |
490 | ops->unmap_single(dev, bus, size, 0); | 380 | ops->unmap_single(dev, bus, size, 0); |
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 744126e64950..49285f8fd4d5 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c | |||
@@ -67,9 +67,6 @@ static u32 gart_unmapped_entry; | |||
67 | (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT) | 67 | (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT) |
68 | #define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28)) | 68 | #define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28)) |
69 | 69 | ||
70 | #define to_pages(addr, size) \ | ||
71 | (round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT) | ||
72 | |||
73 | #define EMERGENCY_PAGES 32 /* = 128KB */ | 70 | #define EMERGENCY_PAGES 32 /* = 128KB */ |
74 | 71 | ||
75 | #ifdef CONFIG_AGP | 72 | #ifdef CONFIG_AGP |
@@ -241,7 +238,7 @@ nonforced_iommu(struct device *dev, unsigned long addr, size_t size) | |||
241 | static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, | 238 | static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, |
242 | size_t size, int dir) | 239 | size_t size, int dir) |
243 | { | 240 | { |
244 | unsigned long npages = to_pages(phys_mem, size); | 241 | unsigned long npages = iommu_num_pages(phys_mem, size); |
245 | unsigned long iommu_page = alloc_iommu(dev, npages); | 242 | unsigned long iommu_page = alloc_iommu(dev, npages); |
246 | int i; | 243 | int i; |
247 | 244 | ||
@@ -304,7 +301,7 @@ static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr, | |||
304 | return; | 301 | return; |
305 | 302 | ||
306 | iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT; | 303 | iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT; |
307 | npages = to_pages(dma_addr, size); | 304 | npages = iommu_num_pages(dma_addr, size); |
308 | for (i = 0; i < npages; i++) { | 305 | for (i = 0; i < npages; i++) { |
309 | iommu_gatt_base[iommu_page + i] = gart_unmapped_entry; | 306 | iommu_gatt_base[iommu_page + i] = gart_unmapped_entry; |
310 | CLEAR_LEAK(iommu_page + i); | 307 | CLEAR_LEAK(iommu_page + i); |
@@ -387,7 +384,7 @@ static int __dma_map_cont(struct device *dev, struct scatterlist *start, | |||
387 | } | 384 | } |
388 | 385 | ||
389 | addr = phys_addr; | 386 | addr = phys_addr; |
390 | pages = to_pages(s->offset, s->length); | 387 | pages = iommu_num_pages(s->offset, s->length); |
391 | while (pages--) { | 388 | while (pages--) { |
392 | iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr); | 389 | iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr); |
393 | SET_LEAK(iommu_page); | 390 | SET_LEAK(iommu_page); |
@@ -470,7 +467,7 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) | |||
470 | 467 | ||
471 | seg_size += s->length; | 468 | seg_size += s->length; |
472 | need = nextneed; | 469 | need = nextneed; |
473 | pages += to_pages(s->offset, s->length); | 470 | pages += iommu_num_pages(s->offset, s->length); |
474 | ps = s; | 471 | ps = s; |
475 | } | 472 | } |
476 | if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0) | 473 | if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0) |
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 06a9f643817e..724adfc63cb9 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -414,25 +414,20 @@ void native_machine_shutdown(void) | |||
414 | 414 | ||
415 | /* The boot cpu is always logical cpu 0 */ | 415 | /* The boot cpu is always logical cpu 0 */ |
416 | int reboot_cpu_id = 0; | 416 | int reboot_cpu_id = 0; |
417 | cpumask_of_cpu_ptr(newmask, reboot_cpu_id); | ||
418 | 417 | ||
419 | #ifdef CONFIG_X86_32 | 418 | #ifdef CONFIG_X86_32 |
420 | /* See if there has been given a command line override */ | 419 | /* See if there has been given a command line override */ |
421 | if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) && | 420 | if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) && |
422 | cpu_online(reboot_cpu)) { | 421 | cpu_online(reboot_cpu)) |
423 | reboot_cpu_id = reboot_cpu; | 422 | reboot_cpu_id = reboot_cpu; |
424 | cpumask_of_cpu_ptr_next(newmask, reboot_cpu_id); | ||
425 | } | ||
426 | #endif | 423 | #endif |
427 | 424 | ||
428 | /* Make certain the cpu I'm about to reboot on is online */ | 425 | /* Make certain the cpu I'm about to reboot on is online */ |
429 | if (!cpu_online(reboot_cpu_id)) { | 426 | if (!cpu_online(reboot_cpu_id)) |
430 | reboot_cpu_id = smp_processor_id(); | 427 | reboot_cpu_id = smp_processor_id(); |
431 | cpumask_of_cpu_ptr_next(newmask, reboot_cpu_id); | ||
432 | } | ||
433 | 428 | ||
434 | /* Make certain I only run on the appropriate processor */ | 429 | /* Make certain I only run on the appropriate processor */ |
435 | set_cpus_allowed_ptr(current, newmask); | 430 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(reboot_cpu_id)); |
436 | 431 | ||
437 | /* O.K Now that I'm on the appropriate processor, | 432 | /* O.K Now that I'm on the appropriate processor, |
438 | * stop all of the others. | 433 | * stop all of the others. |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index b520dae02bf4..2d888586385d 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -788,10 +788,6 @@ void __init setup_arch(char **cmdline_p) | |||
788 | 788 | ||
789 | initmem_init(0, max_pfn); | 789 | initmem_init(0, max_pfn); |
790 | 790 | ||
791 | #ifdef CONFIG_X86_64 | ||
792 | dma32_reserve_bootmem(); | ||
793 | #endif | ||
794 | |||
795 | #ifdef CONFIG_ACPI_SLEEP | 791 | #ifdef CONFIG_ACPI_SLEEP |
796 | /* | 792 | /* |
797 | * Reserve low memory region for sleep support. | 793 | * Reserve low memory region for sleep support. |
@@ -806,6 +802,15 @@ void __init setup_arch(char **cmdline_p) | |||
806 | #endif | 802 | #endif |
807 | reserve_crashkernel(); | 803 | reserve_crashkernel(); |
808 | 804 | ||
805 | #ifdef CONFIG_X86_64 | ||
806 | /* | ||
807 | * dma32_reserve_bootmem() allocates bootmem which may conflict | ||
808 | * with the crashkernel command line, so do that after | ||
809 | * reserve_crashkernel() | ||
810 | */ | ||
811 | dma32_reserve_bootmem(); | ||
812 | #endif | ||
813 | |||
809 | reserve_ibft_region(); | 814 | reserve_ibft_region(); |
810 | 815 | ||
811 | #ifdef CONFIG_KVM_CLOCK | 816 | #ifdef CONFIG_KVM_CLOCK |
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index f7745f94c006..76e305e064f9 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -80,24 +80,6 @@ static void __init setup_per_cpu_maps(void) | |||
80 | #endif | 80 | #endif |
81 | } | 81 | } |
82 | 82 | ||
83 | #ifdef CONFIG_HAVE_CPUMASK_OF_CPU_MAP | ||
84 | cpumask_t *cpumask_of_cpu_map __read_mostly; | ||
85 | EXPORT_SYMBOL(cpumask_of_cpu_map); | ||
86 | |||
87 | /* requires nr_cpu_ids to be initialized */ | ||
88 | static void __init setup_cpumask_of_cpu(void) | ||
89 | { | ||
90 | int i; | ||
91 | |||
92 | /* alloc_bootmem zeroes memory */ | ||
93 | cpumask_of_cpu_map = alloc_bootmem_low(sizeof(cpumask_t) * nr_cpu_ids); | ||
94 | for (i = 0; i < nr_cpu_ids; i++) | ||
95 | cpu_set(i, cpumask_of_cpu_map[i]); | ||
96 | } | ||
97 | #else | ||
98 | static inline void setup_cpumask_of_cpu(void) { } | ||
99 | #endif | ||
100 | |||
101 | #ifdef CONFIG_X86_32 | 83 | #ifdef CONFIG_X86_32 |
102 | /* | 84 | /* |
103 | * Great future not-so-futuristic plan: make i386 and x86_64 do it | 85 | * Great future not-so-futuristic plan: make i386 and x86_64 do it |
@@ -197,9 +179,6 @@ void __init setup_per_cpu_areas(void) | |||
197 | 179 | ||
198 | /* Setup node to cpumask map */ | 180 | /* Setup node to cpumask map */ |
199 | setup_node_to_cpumask_map(); | 181 | setup_node_to_cpumask_map(); |
200 | |||
201 | /* Setup cpumask_of_cpu map */ | ||
202 | setup_cpumask_of_cpu(); | ||
203 | } | 182 | } |
204 | 183 | ||
205 | #endif | 184 | #endif |
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 8d45fabc5f3b..ce3251ce5504 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig | |||
@@ -21,6 +21,7 @@ config KVM | |||
21 | tristate "Kernel-based Virtual Machine (KVM) support" | 21 | tristate "Kernel-based Virtual Machine (KVM) support" |
22 | depends on HAVE_KVM | 22 | depends on HAVE_KVM |
23 | select PREEMPT_NOTIFIERS | 23 | select PREEMPT_NOTIFIERS |
24 | select MMU_NOTIFIER | ||
24 | select ANON_INODES | 25 | select ANON_INODES |
25 | ---help--- | 26 | ---help--- |
26 | Support hosting fully virtualized guest machines using hardware | 27 | Support hosting fully virtualized guest machines using hardware |
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 0313a5eec412..d9249a882aa5 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c | |||
@@ -1014,6 +1014,9 @@ __init void lguest_init(void) | |||
1014 | init_pg_tables_start = __pa(pg0); | 1014 | init_pg_tables_start = __pa(pg0); |
1015 | init_pg_tables_end = __pa(pg0); | 1015 | init_pg_tables_end = __pa(pg0); |
1016 | 1016 | ||
1017 | /* As described in head_32.S, we map the first 128M of memory. */ | ||
1018 | max_pfn_mapped = (128*1024*1024) >> PAGE_SHIFT; | ||
1019 | |||
1017 | /* Load the %fs segment register (the per-cpu segment register) with | 1020 | /* Load the %fs segment register (the per-cpu segment register) with |
1018 | * the normal data segment to get through booting. */ | 1021 | * the normal data segment to get through booting. */ |
1019 | asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory"); | 1022 | asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory"); |
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index dfdf428975c0..f118c110af32 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S | |||
@@ -52,7 +52,7 @@ | |||
52 | jnz 100b | 52 | jnz 100b |
53 | 102: | 53 | 102: |
54 | .section .fixup,"ax" | 54 | .section .fixup,"ax" |
55 | 103: addl %r8d,%edx /* ecx is zerorest also */ | 55 | 103: addl %ecx,%edx /* ecx is zerorest also */ |
56 | jmp copy_user_handle_tail | 56 | jmp copy_user_handle_tail |
57 | .previous | 57 | .previous |
58 | 58 | ||
diff --git a/arch/x86/lib/copy_user_nocache_64.S b/arch/x86/lib/copy_user_nocache_64.S index 40e0e309d27e..cb0c112386fb 100644 --- a/arch/x86/lib/copy_user_nocache_64.S +++ b/arch/x86/lib/copy_user_nocache_64.S | |||
@@ -32,7 +32,7 @@ | |||
32 | jnz 100b | 32 | jnz 100b |
33 | 102: | 33 | 102: |
34 | .section .fixup,"ax" | 34 | .section .fixup,"ax" |
35 | 103: addl %r8d,%edx /* ecx is zerorest also */ | 35 | 103: addl %ecx,%edx /* ecx is zerorest also */ |
36 | jmp copy_user_handle_tail | 36 | jmp copy_user_handle_tail |
37 | .previous | 37 | .previous |
38 | 38 | ||
@@ -108,7 +108,6 @@ ENTRY(__copy_user_nocache) | |||
108 | jmp 60f | 108 | jmp 60f |
109 | 50: movl %ecx,%edx | 109 | 50: movl %ecx,%edx |
110 | 60: sfence | 110 | 60: sfence |
111 | movl %r8d,%ecx | ||
112 | jmp copy_user_handle_tail | 111 | jmp copy_user_handle_tail |
113 | .previous | 112 | .previous |
114 | 113 | ||
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index 3085f25b4355..007bb06c7504 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c | |||
@@ -223,14 +223,17 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, | |||
223 | struct page **pages) | 223 | struct page **pages) |
224 | { | 224 | { |
225 | struct mm_struct *mm = current->mm; | 225 | struct mm_struct *mm = current->mm; |
226 | unsigned long end = start + (nr_pages << PAGE_SHIFT); | 226 | unsigned long addr, len, end; |
227 | unsigned long addr = start; | ||
228 | unsigned long next; | 227 | unsigned long next; |
229 | pgd_t *pgdp; | 228 | pgd_t *pgdp; |
230 | int nr = 0; | 229 | int nr = 0; |
231 | 230 | ||
231 | start &= PAGE_MASK; | ||
232 | addr = start; | ||
233 | len = (unsigned long) nr_pages << PAGE_SHIFT; | ||
234 | end = start + len; | ||
232 | if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, | 235 | if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, |
233 | start, nr_pages*PAGE_SIZE))) | 236 | start, len))) |
234 | goto slow_irqon; | 237 | goto slow_irqon; |
235 | 238 | ||
236 | /* | 239 | /* |
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index ff3a6a336342..4bdaa590375d 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c | |||
@@ -23,7 +23,8 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) | |||
23 | pci_read_config_byte(d, reg++, &busno); | 23 | pci_read_config_byte(d, reg++, &busno); |
24 | pci_read_config_byte(d, reg++, &suba); | 24 | pci_read_config_byte(d, reg++, &suba); |
25 | pci_read_config_byte(d, reg++, &subb); | 25 | pci_read_config_byte(d, reg++, &subb); |
26 | DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); | 26 | dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, |
27 | suba, subb); | ||
27 | if (busno) | 28 | if (busno) |
28 | pci_scan_bus_with_sysdata(busno); /* Bus A */ | 29 | pci_scan_bus_with_sysdata(busno); /* Bus A */ |
29 | if (suba < subb) | 30 | if (suba < subb) |
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index a09505806b82..5807d1bc73f7 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c | |||
@@ -128,10 +128,8 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) | |||
128 | pr = pci_find_parent_resource(dev, r); | 128 | pr = pci_find_parent_resource(dev, r); |
129 | if (!r->start || !pr || | 129 | if (!r->start || !pr || |
130 | request_resource(pr, r) < 0) { | 130 | request_resource(pr, r) < 0) { |
131 | printk(KERN_ERR "PCI: Cannot allocate " | 131 | dev_err(&dev->dev, "BAR %d: can't " |
132 | "resource region %d " | 132 | "allocate resource\n", idx); |
133 | "of bridge %s\n", | ||
134 | idx, pci_name(dev)); | ||
135 | /* | 133 | /* |
136 | * Something is wrong with the region. | 134 | * Something is wrong with the region. |
137 | * Invalidate the resource to prevent | 135 | * Invalidate the resource to prevent |
@@ -166,15 +164,15 @@ static void __init pcibios_allocate_resources(int pass) | |||
166 | else | 164 | else |
167 | disabled = !(command & PCI_COMMAND_MEMORY); | 165 | disabled = !(command & PCI_COMMAND_MEMORY); |
168 | if (pass == disabled) { | 166 | if (pass == disabled) { |
169 | DBG("PCI: Resource %08lx-%08lx " | 167 | dev_dbg(&dev->dev, "resource %#08llx-%#08llx " |
170 | "(f=%lx, d=%d, p=%d)\n", | 168 | "(f=%lx, d=%d, p=%d)\n", |
171 | r->start, r->end, r->flags, disabled, pass); | 169 | (unsigned long long) r->start, |
170 | (unsigned long long) r->end, | ||
171 | r->flags, disabled, pass); | ||
172 | pr = pci_find_parent_resource(dev, r); | 172 | pr = pci_find_parent_resource(dev, r); |
173 | if (!pr || request_resource(pr, r) < 0) { | 173 | if (!pr || request_resource(pr, r) < 0) { |
174 | printk(KERN_ERR "PCI: Cannot allocate " | 174 | dev_err(&dev->dev, "BAR %d: can't " |
175 | "resource region %d " | 175 | "allocate resource\n", idx); |
176 | "of device %s\n", | ||
177 | idx, pci_name(dev)); | ||
178 | /* We'll assign a new address later */ | 176 | /* We'll assign a new address later */ |
179 | r->end -= r->start; | 177 | r->end -= r->start; |
180 | r->start = 0; | 178 | r->start = 0; |
@@ -187,8 +185,7 @@ static void __init pcibios_allocate_resources(int pass) | |||
187 | /* Turn the ROM off, leave the resource region, | 185 | /* Turn the ROM off, leave the resource region, |
188 | * but keep it unregistered. */ | 186 | * but keep it unregistered. */ |
189 | u32 reg; | 187 | u32 reg; |
190 | DBG("PCI: Switching off ROM of %s\n", | 188 | dev_dbg(&dev->dev, "disabling ROM\n"); |
191 | pci_name(dev)); | ||
192 | r->flags &= ~IORESOURCE_ROM_ENABLE; | 189 | r->flags &= ~IORESOURCE_ROM_ENABLE; |
193 | pci_read_config_dword(dev, | 190 | pci_read_config_dword(dev, |
194 | dev->rom_base_reg, ®); | 191 | dev->rom_base_reg, ®); |
@@ -257,8 +254,7 @@ void pcibios_set_master(struct pci_dev *dev) | |||
257 | lat = pcibios_max_latency; | 254 | lat = pcibios_max_latency; |
258 | else | 255 | else |
259 | return; | 256 | return; |
260 | printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", | 257 | dev_printk(KERN_DEBUG, &dev->dev, "setting latency timer to %d\n", lat); |
261 | pci_name(dev), lat); | ||
262 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | 258 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); |
263 | } | 259 | } |
264 | 260 | ||
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 6a06a2eb0597..fec0123b33a9 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c | |||
@@ -436,7 +436,7 @@ static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq) | |||
436 | { | 436 | { |
437 | WARN_ON_ONCE(pirq >= 9); | 437 | WARN_ON_ONCE(pirq >= 9); |
438 | if (pirq > 8) { | 438 | if (pirq > 8) { |
439 | printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); | 439 | dev_info(&dev->dev, "VLSI router PIRQ escape (%d)\n", pirq); |
440 | return 0; | 440 | return 0; |
441 | } | 441 | } |
442 | return read_config_nybble(router, 0x74, pirq-1); | 442 | return read_config_nybble(router, 0x74, pirq-1); |
@@ -446,7 +446,7 @@ static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, | |||
446 | { | 446 | { |
447 | WARN_ON_ONCE(pirq >= 9); | 447 | WARN_ON_ONCE(pirq >= 9); |
448 | if (pirq > 8) { | 448 | if (pirq > 8) { |
449 | printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); | 449 | dev_info(&dev->dev, "VLSI router PIRQ escape (%d)\n", pirq); |
450 | return 0; | 450 | return 0; |
451 | } | 451 | } |
452 | write_config_nybble(router, 0x74, pirq-1, irq); | 452 | write_config_nybble(router, 0x74, pirq-1, irq); |
@@ -492,15 +492,17 @@ static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq | |||
492 | irq = 0; | 492 | irq = 0; |
493 | if (pirq <= 4) | 493 | if (pirq <= 4) |
494 | irq = read_config_nybble(router, 0x56, pirq - 1); | 494 | irq = read_config_nybble(router, 0x56, pirq - 1); |
495 | printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n", | 495 | dev_info(&dev->dev, |
496 | dev->vendor, dev->device, pirq, irq); | 496 | "AMD756: dev [%04x/%04x], router PIRQ %d get IRQ %d\n", |
497 | dev->vendor, dev->device, pirq, irq); | ||
497 | return irq; | 498 | return irq; |
498 | } | 499 | } |
499 | 500 | ||
500 | static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) | 501 | static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
501 | { | 502 | { |
502 | printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", | 503 | dev_info(&dev->dev, |
503 | dev->vendor, dev->device, pirq, irq); | 504 | "AMD756: dev [%04x/%04x], router PIRQ %d set IRQ %d\n", |
505 | dev->vendor, dev->device, pirq, irq); | ||
504 | if (pirq <= 4) | 506 | if (pirq <= 4) |
505 | write_config_nybble(router, 0x56, pirq - 1, irq); | 507 | write_config_nybble(router, 0x56, pirq - 1, irq); |
506 | return 1; | 508 | return 1; |
@@ -730,7 +732,6 @@ static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, | |||
730 | switch (device) { | 732 | switch (device) { |
731 | case PCI_DEVICE_ID_AL_M1533: | 733 | case PCI_DEVICE_ID_AL_M1533: |
732 | case PCI_DEVICE_ID_AL_M1563: | 734 | case PCI_DEVICE_ID_AL_M1563: |
733 | printk(KERN_DEBUG "PCI: Using ALI IRQ Router\n"); | ||
734 | r->name = "ALI"; | 735 | r->name = "ALI"; |
735 | r->get = pirq_ali_get; | 736 | r->get = pirq_ali_get; |
736 | r->set = pirq_ali_set; | 737 | r->set = pirq_ali_set; |
@@ -840,11 +841,9 @@ static void __init pirq_find_router(struct irq_router *r) | |||
840 | h->probe(r, pirq_router_dev, pirq_router_dev->device)) | 841 | h->probe(r, pirq_router_dev, pirq_router_dev->device)) |
841 | break; | 842 | break; |
842 | } | 843 | } |
843 | printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", | 844 | dev_info(&pirq_router_dev->dev, "%s IRQ router [%04x/%04x]\n", |
844 | pirq_router.name, | 845 | pirq_router.name, |
845 | pirq_router_dev->vendor, | 846 | pirq_router_dev->vendor, pirq_router_dev->device); |
846 | pirq_router_dev->device, | ||
847 | pci_name(pirq_router_dev)); | ||
848 | 847 | ||
849 | /* The device remains referenced for the kernel lifetime */ | 848 | /* The device remains referenced for the kernel lifetime */ |
850 | } | 849 | } |
@@ -877,7 +876,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) | |||
877 | /* Find IRQ pin */ | 876 | /* Find IRQ pin */ |
878 | pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); | 877 | pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); |
879 | if (!pin) { | 878 | if (!pin) { |
880 | DBG(KERN_DEBUG " -> no interrupt pin\n"); | 879 | dev_dbg(&dev->dev, "no interrupt pin\n"); |
881 | return 0; | 880 | return 0; |
882 | } | 881 | } |
883 | pin = pin - 1; | 882 | pin = pin - 1; |
@@ -887,20 +886,20 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) | |||
887 | if (!pirq_table) | 886 | if (!pirq_table) |
888 | return 0; | 887 | return 0; |
889 | 888 | ||
890 | DBG(KERN_DEBUG "IRQ for %s[%c]", pci_name(dev), 'A' + pin); | ||
891 | info = pirq_get_info(dev); | 889 | info = pirq_get_info(dev); |
892 | if (!info) { | 890 | if (!info) { |
893 | DBG(" -> not found in routing table\n" KERN_DEBUG); | 891 | dev_dbg(&dev->dev, "PCI INT %c not found in routing table\n", |
892 | 'A' + pin); | ||
894 | return 0; | 893 | return 0; |
895 | } | 894 | } |
896 | pirq = info->irq[pin].link; | 895 | pirq = info->irq[pin].link; |
897 | mask = info->irq[pin].bitmap; | 896 | mask = info->irq[pin].bitmap; |
898 | if (!pirq) { | 897 | if (!pirq) { |
899 | DBG(" -> not routed\n" KERN_DEBUG); | 898 | dev_dbg(&dev->dev, "PCI INT %c not routed\n", 'A' + pin); |
900 | return 0; | 899 | return 0; |
901 | } | 900 | } |
902 | DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, | 901 | dev_dbg(&dev->dev, "PCI INT %c -> PIRQ %02x, mask %04x, excl %04x", |
903 | pirq_table->exclusive_irqs); | 902 | 'A' + pin, pirq, mask, pirq_table->exclusive_irqs); |
904 | mask &= pcibios_irq_mask; | 903 | mask &= pcibios_irq_mask; |
905 | 904 | ||
906 | /* Work around broken HP Pavilion Notebooks which assign USB to | 905 | /* Work around broken HP Pavilion Notebooks which assign USB to |
@@ -930,10 +929,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) | |||
930 | if (pci_probe & PCI_USE_PIRQ_MASK) | 929 | if (pci_probe & PCI_USE_PIRQ_MASK) |
931 | newirq = 0; | 930 | newirq = 0; |
932 | else | 931 | else |
933 | printk("\n" KERN_WARNING | 932 | dev_warn(&dev->dev, "IRQ %d doesn't match PIRQ mask " |
934 | "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n" | 933 | "%#x; try pci=usepirqmask\n", newirq, mask); |
935 | KERN_DEBUG, newirq, | ||
936 | pci_name(dev)); | ||
937 | } | 934 | } |
938 | if (!newirq && assign) { | 935 | if (!newirq && assign) { |
939 | for (i = 0; i < 16; i++) { | 936 | for (i = 0; i < 16; i++) { |
@@ -944,39 +941,35 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) | |||
944 | newirq = i; | 941 | newirq = i; |
945 | } | 942 | } |
946 | } | 943 | } |
947 | DBG(" -> newirq=%d", newirq); | 944 | dev_dbg(&dev->dev, "PCI INT %c -> newirq %d", 'A' + pin, newirq); |
948 | 945 | ||
949 | /* Check if it is hardcoded */ | 946 | /* Check if it is hardcoded */ |
950 | if ((pirq & 0xf0) == 0xf0) { | 947 | if ((pirq & 0xf0) == 0xf0) { |
951 | irq = pirq & 0xf; | 948 | irq = pirq & 0xf; |
952 | DBG(" -> hardcoded IRQ %d\n", irq); | 949 | msg = "hardcoded"; |
953 | msg = "Hardcoded"; | ||
954 | } else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \ | 950 | } else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \ |
955 | ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask))) { | 951 | ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask))) { |
956 | DBG(" -> got IRQ %d\n", irq); | 952 | msg = "found"; |
957 | msg = "Found"; | ||
958 | eisa_set_level_irq(irq); | 953 | eisa_set_level_irq(irq); |
959 | } else if (newirq && r->set && | 954 | } else if (newirq && r->set && |
960 | (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { | 955 | (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { |
961 | DBG(" -> assigning IRQ %d", newirq); | ||
962 | if (r->set(pirq_router_dev, dev, pirq, newirq)) { | 956 | if (r->set(pirq_router_dev, dev, pirq, newirq)) { |
963 | eisa_set_level_irq(newirq); | 957 | eisa_set_level_irq(newirq); |
964 | DBG(" ... OK\n"); | 958 | msg = "assigned"; |
965 | msg = "Assigned"; | ||
966 | irq = newirq; | 959 | irq = newirq; |
967 | } | 960 | } |
968 | } | 961 | } |
969 | 962 | ||
970 | if (!irq) { | 963 | if (!irq) { |
971 | DBG(" ... failed\n"); | ||
972 | if (newirq && mask == (1 << newirq)) { | 964 | if (newirq && mask == (1 << newirq)) { |
973 | msg = "Guessed"; | 965 | msg = "guessed"; |
974 | irq = newirq; | 966 | irq = newirq; |
975 | } else | 967 | } else { |
968 | dev_dbg(&dev->dev, "can't route interrupt\n"); | ||
976 | return 0; | 969 | return 0; |
970 | } | ||
977 | } | 971 | } |
978 | printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, | 972 | dev_info(&dev->dev, "%s PCI INT %c -> IRQ %d\n", msg, 'A' + pin, irq); |
979 | pci_name(dev)); | ||
980 | 973 | ||
981 | /* Update IRQ for all devices with the same pirq value */ | 974 | /* Update IRQ for all devices with the same pirq value */ |
982 | while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { | 975 | while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { |
@@ -996,17 +989,17 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) | |||
996 | (!(pci_probe & PCI_USE_PIRQ_MASK) || \ | 989 | (!(pci_probe & PCI_USE_PIRQ_MASK) || \ |
997 | ((1 << dev2->irq) & mask))) { | 990 | ((1 << dev2->irq) & mask))) { |
998 | #ifndef CONFIG_PCI_MSI | 991 | #ifndef CONFIG_PCI_MSI |
999 | printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n", | 992 | dev_info(&dev2->dev, "IRQ routing conflict: " |
1000 | pci_name(dev2), dev2->irq, irq); | 993 | "have IRQ %d, want IRQ %d\n", |
994 | dev2->irq, irq); | ||
1001 | #endif | 995 | #endif |
1002 | continue; | 996 | continue; |
1003 | } | 997 | } |
1004 | dev2->irq = irq; | 998 | dev2->irq = irq; |
1005 | pirq_penalty[irq]++; | 999 | pirq_penalty[irq]++; |
1006 | if (dev != dev2) | 1000 | if (dev != dev2) |
1007 | printk(KERN_INFO | 1001 | dev_info(&dev->dev, "sharing IRQ %d with %s\n", |
1008 | "PCI: Sharing IRQ %d with %s\n", | 1002 | irq, pci_name(dev2)); |
1009 | irq, pci_name(dev2)); | ||
1010 | } | 1003 | } |
1011 | } | 1004 | } |
1012 | return 1; | 1005 | return 1; |
@@ -1025,8 +1018,7 @@ static void __init pcibios_fixup_irqs(void) | |||
1025 | * already in use. | 1018 | * already in use. |
1026 | */ | 1019 | */ |
1027 | if (dev->irq >= 16) { | 1020 | if (dev->irq >= 16) { |
1028 | DBG(KERN_DEBUG "%s: ignoring bogus IRQ %d\n", | 1021 | dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", dev->irq); |
1029 | pci_name(dev), dev->irq); | ||
1030 | dev->irq = 0; | 1022 | dev->irq = 0; |
1031 | } | 1023 | } |
1032 | /* | 1024 | /* |
@@ -1070,12 +1062,12 @@ static void __init pcibios_fixup_irqs(void) | |||
1070 | irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, | 1062 | irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, |
1071 | PCI_SLOT(bridge->devfn), pin); | 1063 | PCI_SLOT(bridge->devfn), pin); |
1072 | if (irq >= 0) | 1064 | if (irq >= 0) |
1073 | printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n", | 1065 | dev_warn(&dev->dev, "using bridge %s INT %c to get IRQ %d\n", |
1074 | pci_name(bridge), 'A' + pin, irq); | 1066 | pci_name(bridge), |
1067 | 'A' + pin, irq); | ||
1075 | } | 1068 | } |
1076 | if (irq >= 0) { | 1069 | if (irq >= 0) { |
1077 | printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", | 1070 | dev_info(&dev->dev, "PCI->APIC IRQ transform: INT %c -> IRQ %d\n", 'A' + pin, irq); |
1078 | pci_name(dev), 'A' + pin, irq); | ||
1079 | dev->irq = irq; | 1071 | dev->irq = irq; |
1080 | } | 1072 | } |
1081 | } | 1073 | } |
@@ -1231,25 +1223,24 @@ static int pirq_enable_irq(struct pci_dev *dev) | |||
1231 | irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, | 1223 | irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, |
1232 | PCI_SLOT(bridge->devfn), pin); | 1224 | PCI_SLOT(bridge->devfn), pin); |
1233 | if (irq >= 0) | 1225 | if (irq >= 0) |
1234 | printk(KERN_WARNING | 1226 | dev_warn(&dev->dev, "using bridge %s " |
1235 | "PCI: using PPB %s[%c] to get irq %d\n", | 1227 | "INT %c to get IRQ %d\n", |
1236 | pci_name(bridge), | 1228 | pci_name(bridge), 'A' + pin, |
1237 | 'A' + pin, irq); | 1229 | irq); |
1238 | dev = bridge; | 1230 | dev = bridge; |
1239 | } | 1231 | } |
1240 | dev = temp_dev; | 1232 | dev = temp_dev; |
1241 | if (irq >= 0) { | 1233 | if (irq >= 0) { |
1242 | printk(KERN_INFO | 1234 | dev_info(&dev->dev, "PCI->APIC IRQ transform: " |
1243 | "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", | 1235 | "INT %c -> IRQ %d\n", 'A' + pin, irq); |
1244 | pci_name(dev), 'A' + pin, irq); | ||
1245 | dev->irq = irq; | 1236 | dev->irq = irq; |
1246 | return 0; | 1237 | return 0; |
1247 | } else | 1238 | } else |
1248 | msg = " Probably buggy MP table."; | 1239 | msg = "; probably buggy MP table"; |
1249 | } else if (pci_probe & PCI_BIOS_IRQ_SCAN) | 1240 | } else if (pci_probe & PCI_BIOS_IRQ_SCAN) |
1250 | msg = ""; | 1241 | msg = ""; |
1251 | else | 1242 | else |
1252 | msg = " Please try using pci=biosirq."; | 1243 | msg = "; please try using pci=biosirq"; |
1253 | 1244 | ||
1254 | /* | 1245 | /* |
1255 | * With IDE legacy devices the IRQ lookup failure is not | 1246 | * With IDE legacy devices the IRQ lookup failure is not |
@@ -1259,9 +1250,8 @@ static int pirq_enable_irq(struct pci_dev *dev) | |||
1259 | !(dev->class & 0x5)) | 1250 | !(dev->class & 0x5)) |
1260 | return 0; | 1251 | return 0; |
1261 | 1252 | ||
1262 | printk(KERN_WARNING | 1253 | dev_warn(&dev->dev, "can't find IRQ for PCI INT %c%s\n", |
1263 | "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", | 1254 | 'A' + pin, msg); |
1264 | 'A' + pin, pci_name(dev), msg); | ||
1265 | } | 1255 | } |
1266 | return 0; | 1256 | return 0; |
1267 | } | 1257 | } |
diff --git a/arch/x86/pci/numaq_32.c b/arch/x86/pci/numaq_32.c index f4b16dc11dad..1177845d3186 100644 --- a/arch/x86/pci/numaq_32.c +++ b/arch/x86/pci/numaq_32.c | |||
@@ -131,13 +131,14 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) | |||
131 | u8 busno, suba, subb; | 131 | u8 busno, suba, subb; |
132 | int quad = BUS2QUAD(d->bus->number); | 132 | int quad = BUS2QUAD(d->bus->number); |
133 | 133 | ||
134 | printk("PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); | 134 | dev_info(&d->dev, "searching for i450NX host bridges\n"); |
135 | reg = 0xd0; | 135 | reg = 0xd0; |
136 | for(pxb=0; pxb<2; pxb++) { | 136 | for(pxb=0; pxb<2; pxb++) { |
137 | pci_read_config_byte(d, reg++, &busno); | 137 | pci_read_config_byte(d, reg++, &busno); |
138 | pci_read_config_byte(d, reg++, &suba); | 138 | pci_read_config_byte(d, reg++, &suba); |
139 | pci_read_config_byte(d, reg++, &subb); | 139 | pci_read_config_byte(d, reg++, &subb); |
140 | DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); | 140 | dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n", |
141 | pxb, busno, suba, subb); | ||
141 | if (busno) { | 142 | if (busno) { |
142 | /* Bus A */ | 143 | /* Bus A */ |
143 | pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno)); | 144 | pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno)); |
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index dd376f7ad090..d5b4ef898879 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c | |||
@@ -76,9 +76,9 @@ static struct acpi_pci_driver acpi_pci_slot_driver = { | |||
76 | }; | 76 | }; |
77 | 77 | ||
78 | static int | 78 | static int |
79 | check_slot(acpi_handle handle, int *device, unsigned long *sun) | 79 | check_slot(acpi_handle handle, unsigned long *sun) |
80 | { | 80 | { |
81 | int retval = 0; | 81 | int device = -1; |
82 | unsigned long adr, sta; | 82 | unsigned long adr, sta; |
83 | acpi_status status; | 83 | acpi_status status; |
84 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 84 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
@@ -89,32 +89,27 @@ check_slot(acpi_handle handle, int *device, unsigned long *sun) | |||
89 | if (check_sta_before_sun) { | 89 | if (check_sta_before_sun) { |
90 | /* If SxFy doesn't have _STA, we just assume it's there */ | 90 | /* If SxFy doesn't have _STA, we just assume it's there */ |
91 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | 91 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); |
92 | if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT)) { | 92 | if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT)) |
93 | retval = -1; | ||
94 | goto out; | 93 | goto out; |
95 | } | ||
96 | } | 94 | } |
97 | 95 | ||
98 | status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); | 96 | status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); |
99 | if (ACPI_FAILURE(status)) { | 97 | if (ACPI_FAILURE(status)) { |
100 | dbg("_ADR returned %d on %s\n", status, (char *)buffer.pointer); | 98 | dbg("_ADR returned %d on %s\n", status, (char *)buffer.pointer); |
101 | retval = -1; | ||
102 | goto out; | 99 | goto out; |
103 | } | 100 | } |
104 | 101 | ||
105 | *device = (adr >> 16) & 0xffff; | ||
106 | |||
107 | /* No _SUN == not a slot == bail */ | 102 | /* No _SUN == not a slot == bail */ |
108 | status = acpi_evaluate_integer(handle, "_SUN", NULL, sun); | 103 | status = acpi_evaluate_integer(handle, "_SUN", NULL, sun); |
109 | if (ACPI_FAILURE(status)) { | 104 | if (ACPI_FAILURE(status)) { |
110 | dbg("_SUN returned %d on %s\n", status, (char *)buffer.pointer); | 105 | dbg("_SUN returned %d on %s\n", status, (char *)buffer.pointer); |
111 | retval = -1; | ||
112 | goto out; | 106 | goto out; |
113 | } | 107 | } |
114 | 108 | ||
109 | device = (adr >> 16) & 0xffff; | ||
115 | out: | 110 | out: |
116 | kfree(buffer.pointer); | 111 | kfree(buffer.pointer); |
117 | return retval; | 112 | return device; |
118 | } | 113 | } |
119 | 114 | ||
120 | struct callback_args { | 115 | struct callback_args { |
@@ -144,7 +139,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
144 | struct callback_args *parent_context = context; | 139 | struct callback_args *parent_context = context; |
145 | struct pci_bus *pci_bus = parent_context->pci_bus; | 140 | struct pci_bus *pci_bus = parent_context->pci_bus; |
146 | 141 | ||
147 | if (check_slot(handle, &device, &sun)) | 142 | device = check_slot(handle, &sun); |
143 | if (device < 0) | ||
148 | return AE_OK; | 144 | return AE_OK; |
149 | 145 | ||
150 | slot = kmalloc(sizeof(*slot), GFP_KERNEL); | 146 | slot = kmalloc(sizeof(*slot), GFP_KERNEL); |
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index b4749969c6b4..0133af49cf06 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c | |||
@@ -64,7 +64,13 @@ static DEFINE_MUTEX(performance_mutex); | |||
64 | * policy is adjusted accordingly. | 64 | * policy is adjusted accordingly. |
65 | */ | 65 | */ |
66 | 66 | ||
67 | static unsigned int ignore_ppc = 0; | 67 | /* ignore_ppc: |
68 | * -1 -> cpufreq low level drivers not initialized -> _PSS, etc. not called yet | ||
69 | * ignore _PPC | ||
70 | * 0 -> cpufreq low level drivers initialized -> consider _PPC values | ||
71 | * 1 -> ignore _PPC totally -> forced by user through boot param | ||
72 | */ | ||
73 | static unsigned int ignore_ppc = -1; | ||
68 | module_param(ignore_ppc, uint, 0644); | 74 | module_param(ignore_ppc, uint, 0644); |
69 | MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ | 75 | MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ |
70 | "limited by BIOS, this should help"); | 76 | "limited by BIOS, this should help"); |
@@ -72,7 +78,7 @@ MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ | |||
72 | #define PPC_REGISTERED 1 | 78 | #define PPC_REGISTERED 1 |
73 | #define PPC_IN_USE 2 | 79 | #define PPC_IN_USE 2 |
74 | 80 | ||
75 | static int acpi_processor_ppc_status = 0; | 81 | static int acpi_processor_ppc_status; |
76 | 82 | ||
77 | static int acpi_processor_ppc_notifier(struct notifier_block *nb, | 83 | static int acpi_processor_ppc_notifier(struct notifier_block *nb, |
78 | unsigned long event, void *data) | 84 | unsigned long event, void *data) |
@@ -81,13 +87,18 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb, | |||
81 | struct acpi_processor *pr; | 87 | struct acpi_processor *pr; |
82 | unsigned int ppc = 0; | 88 | unsigned int ppc = 0; |
83 | 89 | ||
84 | if (ignore_ppc) | 90 | if (event == CPUFREQ_START && ignore_ppc <= 0) { |
91 | ignore_ppc = 0; | ||
85 | return 0; | 92 | return 0; |
93 | } | ||
86 | 94 | ||
87 | mutex_lock(&performance_mutex); | 95 | if (ignore_ppc) |
96 | return 0; | ||
88 | 97 | ||
89 | if (event != CPUFREQ_INCOMPATIBLE) | 98 | if (event != CPUFREQ_INCOMPATIBLE) |
90 | goto out; | 99 | return 0; |
100 | |||
101 | mutex_lock(&performance_mutex); | ||
91 | 102 | ||
92 | pr = per_cpu(processors, policy->cpu); | 103 | pr = per_cpu(processors, policy->cpu); |
93 | if (!pr || !pr->performance) | 104 | if (!pr || !pr->performance) |
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index a2c3f9cfa549..a56fc6c4394b 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c | |||
@@ -827,7 +827,6 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) | |||
827 | static int acpi_processor_get_throttling(struct acpi_processor *pr) | 827 | static int acpi_processor_get_throttling(struct acpi_processor *pr) |
828 | { | 828 | { |
829 | cpumask_t saved_mask; | 829 | cpumask_t saved_mask; |
830 | cpumask_of_cpu_ptr_declare(new_mask); | ||
831 | int ret; | 830 | int ret; |
832 | 831 | ||
833 | if (!pr) | 832 | if (!pr) |
@@ -839,8 +838,7 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr) | |||
839 | * Migrate task to the cpu pointed by pr. | 838 | * Migrate task to the cpu pointed by pr. |
840 | */ | 839 | */ |
841 | saved_mask = current->cpus_allowed; | 840 | saved_mask = current->cpus_allowed; |
842 | cpumask_of_cpu_ptr_next(new_mask, pr->id); | 841 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(pr->id)); |
843 | set_cpus_allowed_ptr(current, new_mask); | ||
844 | ret = pr->throttling.acpi_processor_get_throttling(pr); | 842 | ret = pr->throttling.acpi_processor_get_throttling(pr); |
845 | /* restore the previous state */ | 843 | /* restore the previous state */ |
846 | set_cpus_allowed_ptr(current, &saved_mask); | 844 | set_cpus_allowed_ptr(current, &saved_mask); |
@@ -989,7 +987,6 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr, | |||
989 | int acpi_processor_set_throttling(struct acpi_processor *pr, int state) | 987 | int acpi_processor_set_throttling(struct acpi_processor *pr, int state) |
990 | { | 988 | { |
991 | cpumask_t saved_mask; | 989 | cpumask_t saved_mask; |
992 | cpumask_of_cpu_ptr_declare(new_mask); | ||
993 | int ret = 0; | 990 | int ret = 0; |
994 | unsigned int i; | 991 | unsigned int i; |
995 | struct acpi_processor *match_pr; | 992 | struct acpi_processor *match_pr; |
@@ -1028,8 +1025,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) | |||
1028 | * it can be called only for the cpu pointed by pr. | 1025 | * it can be called only for the cpu pointed by pr. |
1029 | */ | 1026 | */ |
1030 | if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { | 1027 | if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { |
1031 | cpumask_of_cpu_ptr_next(new_mask, pr->id); | 1028 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(pr->id)); |
1032 | set_cpus_allowed_ptr(current, new_mask); | ||
1033 | ret = p_throttling->acpi_processor_set_throttling(pr, | 1029 | ret = p_throttling->acpi_processor_set_throttling(pr, |
1034 | t_state.target_state); | 1030 | t_state.target_state); |
1035 | } else { | 1031 | } else { |
@@ -1060,8 +1056,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) | |||
1060 | continue; | 1056 | continue; |
1061 | } | 1057 | } |
1062 | t_state.cpu = i; | 1058 | t_state.cpu = i; |
1063 | cpumask_of_cpu_ptr_next(new_mask, i); | 1059 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(i)); |
1064 | set_cpus_allowed_ptr(current, new_mask); | ||
1065 | ret = match_pr->throttling. | 1060 | ret = match_pr->throttling. |
1066 | acpi_processor_set_throttling( | 1061 | acpi_processor_set_throttling( |
1067 | match_pr, t_state.target_state); | 1062 | match_pr, t_state.target_state); |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 192688344ed2..f52931e1c16e 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -66,8 +66,8 @@ | |||
66 | #include <linux/ctype.h> | 66 | #include <linux/ctype.h> |
67 | 67 | ||
68 | #ifdef CONFIG_PPC_OF | 68 | #ifdef CONFIG_PPC_OF |
69 | #include <asm/of_device.h> | 69 | #include <linux/of_device.h> |
70 | #include <asm/of_platform.h> | 70 | #include <linux/of_platform.h> |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | #define PFX "ipmi_si: " | 73 | #define PFX "ipmi_si: " |
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index e30575e87648..b638403e8e9c 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c | |||
@@ -1612,8 +1612,10 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) | |||
1612 | 1612 | ||
1613 | switch (cmd) { | 1613 | switch (cmd) { |
1614 | case MOXA_GET_MAJOR: | 1614 | case MOXA_GET_MAJOR: |
1615 | printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl %x, fix " | 1615 | if (printk_ratelimit()) |
1616 | "your userspace\n", current->comm, cmd); | 1616 | printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl " |
1617 | "%x (GET_MAJOR), fix your userspace\n", | ||
1618 | current->comm, cmd); | ||
1617 | return put_user(ttymajor, (int __user *)argp); | 1619 | return put_user(ttymajor, (int __user *)argp); |
1618 | 1620 | ||
1619 | case MOXA_CHKPORTENABLE: | 1621 | case MOXA_CHKPORTENABLE: |
diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 7d500f82195a..4c1820cad712 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c | |||
@@ -568,7 +568,7 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, | |||
568 | list_del(&packet->queue); | 568 | list_del(&packet->queue); |
569 | } else { | 569 | } else { |
570 | const int min_capacity = | 570 | const int min_capacity = |
571 | ipwireless_ppp_mru(hw->network + 2); | 571 | ipwireless_ppp_mru(hw->network) + 2; |
572 | int new_capacity; | 572 | int new_capacity; |
573 | 573 | ||
574 | spin_unlock_irqrestore(&hw->lock, flags); | 574 | spin_unlock_irqrestore(&hw->lock, flags); |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8d6a3ff02672..8a67f16987db 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -825,6 +825,9 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) | |||
825 | policy->user_policy.min = policy->cpuinfo.min_freq; | 825 | policy->user_policy.min = policy->cpuinfo.min_freq; |
826 | policy->user_policy.max = policy->cpuinfo.max_freq; | 826 | policy->user_policy.max = policy->cpuinfo.max_freq; |
827 | 827 | ||
828 | blocking_notifier_call_chain(&cpufreq_policy_notifier_list, | ||
829 | CPUFREQ_START, policy); | ||
830 | |||
828 | #ifdef CONFIG_SMP | 831 | #ifdef CONFIG_SMP |
829 | 832 | ||
830 | #ifdef CONFIG_HOTPLUG_CPU | 833 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index c66817e7717b..50a071f1c945 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c | |||
@@ -245,7 +245,6 @@ static ssize_t host_control_on_shutdown_store(struct device *dev, | |||
245 | static int smi_request(struct smi_cmd *smi_cmd) | 245 | static int smi_request(struct smi_cmd *smi_cmd) |
246 | { | 246 | { |
247 | cpumask_t old_mask; | 247 | cpumask_t old_mask; |
248 | cpumask_of_cpu_ptr(new_mask, 0); | ||
249 | int ret = 0; | 248 | int ret = 0; |
250 | 249 | ||
251 | if (smi_cmd->magic != SMI_CMD_MAGIC) { | 250 | if (smi_cmd->magic != SMI_CMD_MAGIC) { |
@@ -256,7 +255,7 @@ static int smi_request(struct smi_cmd *smi_cmd) | |||
256 | 255 | ||
257 | /* SMI requires CPU 0 */ | 256 | /* SMI requires CPU 0 */ |
258 | old_mask = current->cpus_allowed; | 257 | old_mask = current->cpus_allowed; |
259 | set_cpus_allowed_ptr(current, new_mask); | 258 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(0)); |
260 | if (smp_processor_id() != 0) { | 259 | if (smp_processor_id() != 0) { |
261 | dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n", | 260 | dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n", |
262 | __func__); | 261 | __func__); |
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index 11f17440fea6..d53fbbfefa3e 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c | |||
@@ -81,4 +81,3 @@ void __init reserve_ibft_region(void) | |||
81 | if (ibft_addr) | 81 | if (ibft_addr) |
82 | reserve_bootmem(pos, PAGE_ALIGN(len), BOOTMEM_DEFAULT); | 82 | reserve_bootmem(pos, PAGE_ALIGN(len), BOOTMEM_DEFAULT); |
83 | } | 83 | } |
84 | EXPORT_SYMBOL_GPL(reserve_ibft_region); | ||
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index c521bf6e1bf2..fa2be26272d5 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c | |||
@@ -1086,6 +1086,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) | |||
1086 | /* Make sure we have sane timings */ | 1086 | /* Make sure we have sane timings */ |
1087 | sanitize_timings(pmif); | 1087 | sanitize_timings(pmif); |
1088 | 1088 | ||
1089 | host = ide_host_alloc(&d, hws); | ||
1090 | if (host == NULL) | ||
1091 | return -ENOMEM; | ||
1092 | hwif = host->ports[0]; | ||
1093 | |||
1089 | #ifndef CONFIG_PPC64 | 1094 | #ifndef CONFIG_PPC64 |
1090 | /* XXX FIXME: Media bay stuff need re-organizing */ | 1095 | /* XXX FIXME: Media bay stuff need re-organizing */ |
1091 | if (np->parent && np->parent->name | 1096 | if (np->parent && np->parent->name |
@@ -1119,11 +1124,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) | |||
1119 | pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, | 1124 | pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, |
1120 | pmif->mediabay ? " (mediabay)" : "", hw->irq); | 1125 | pmif->mediabay ? " (mediabay)" : "", hw->irq); |
1121 | 1126 | ||
1122 | rc = ide_host_add(&d, hws, &host); | 1127 | rc = ide_host_register(host, &d, hws); |
1123 | if (rc) | 1128 | if (rc) { |
1129 | ide_host_free(host); | ||
1124 | return rc; | 1130 | return rc; |
1125 | 1131 | } | |
1126 | hwif = host->ports[0]; | ||
1127 | 1132 | ||
1128 | return 0; | 1133 | return 0; |
1129 | } | 1134 | } |
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 5eea4356d703..90663e01a56e 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c | |||
@@ -135,6 +135,7 @@ static void unmap_switcher(void) | |||
135 | /* Now we just need to free the pages we copied the switcher into */ | 135 | /* Now we just need to free the pages we copied the switcher into */ |
136 | for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) | 136 | for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) |
137 | __free_pages(switcher_page[i], 0); | 137 | __free_pages(switcher_page[i], 0); |
138 | kfree(switcher_page); | ||
138 | } | 139 | } |
139 | 140 | ||
140 | /*H:032 | 141 | /*H:032 |
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 0414ddf87587..a1039068f95c 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
@@ -406,7 +406,8 @@ void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int num, u32 lo, u32 hi) | |||
406 | * deliver_trap() to bounce it back into the Guest. */ | 406 | * deliver_trap() to bounce it back into the Guest. */ |
407 | static void default_idt_entry(struct desc_struct *idt, | 407 | static void default_idt_entry(struct desc_struct *idt, |
408 | int trap, | 408 | int trap, |
409 | const unsigned long handler) | 409 | const unsigned long handler, |
410 | const struct desc_struct *base) | ||
410 | { | 411 | { |
411 | /* A present interrupt gate. */ | 412 | /* A present interrupt gate. */ |
412 | u32 flags = 0x8e00; | 413 | u32 flags = 0x8e00; |
@@ -415,6 +416,10 @@ static void default_idt_entry(struct desc_struct *idt, | |||
415 | * the Guest to use the "int" instruction to trigger it. */ | 416 | * the Guest to use the "int" instruction to trigger it. */ |
416 | if (trap == LGUEST_TRAP_ENTRY) | 417 | if (trap == LGUEST_TRAP_ENTRY) |
417 | flags |= (GUEST_PL << 13); | 418 | flags |= (GUEST_PL << 13); |
419 | else if (base) | ||
420 | /* Copy priv. level from what Guest asked for. This allows | ||
421 | * debug (int 3) traps from Guest userspace, for example. */ | ||
422 | flags |= (base->b & 0x6000); | ||
418 | 423 | ||
419 | /* Now pack it into the IDT entry in its weird format. */ | 424 | /* Now pack it into the IDT entry in its weird format. */ |
420 | idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF); | 425 | idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF); |
@@ -428,7 +433,7 @@ void setup_default_idt_entries(struct lguest_ro_state *state, | |||
428 | unsigned int i; | 433 | unsigned int i; |
429 | 434 | ||
430 | for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++) | 435 | for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++) |
431 | default_idt_entry(&state->guest_idt[i], i, def[i]); | 436 | default_idt_entry(&state->guest_idt[i], i, def[i], NULL); |
432 | } | 437 | } |
433 | 438 | ||
434 | /*H:240 We don't use the IDT entries in the "struct lguest" directly, instead | 439 | /*H:240 We don't use the IDT entries in the "struct lguest" directly, instead |
@@ -442,6 +447,8 @@ void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, | |||
442 | /* We can simply copy the direct traps, otherwise we use the default | 447 | /* We can simply copy the direct traps, otherwise we use the default |
443 | * ones in the Switcher: they will return to the Host. */ | 448 | * ones in the Switcher: they will return to the Host. */ |
444 | for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) { | 449 | for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) { |
450 | const struct desc_struct *gidt = &cpu->arch.idt[i]; | ||
451 | |||
445 | /* If no Guest can ever override this trap, leave it alone. */ | 452 | /* If no Guest can ever override this trap, leave it alone. */ |
446 | if (!direct_trap(i)) | 453 | if (!direct_trap(i)) |
447 | continue; | 454 | continue; |
@@ -449,12 +456,15 @@ void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, | |||
449 | /* Only trap gates (type 15) can go direct to the Guest. | 456 | /* Only trap gates (type 15) can go direct to the Guest. |
450 | * Interrupt gates (type 14) disable interrupts as they are | 457 | * Interrupt gates (type 14) disable interrupts as they are |
451 | * entered, which we never let the Guest do. Not present | 458 | * entered, which we never let the Guest do. Not present |
452 | * entries (type 0x0) also can't go direct, of course. */ | 459 | * entries (type 0x0) also can't go direct, of course. |
453 | if (idt_type(cpu->arch.idt[i].a, cpu->arch.idt[i].b) == 0xF) | 460 | * |
454 | idt[i] = cpu->arch.idt[i]; | 461 | * If it can't go direct, we still need to copy the priv. level: |
462 | * they might want to give userspace access to a software | ||
463 | * interrupt. */ | ||
464 | if (idt_type(gidt->a, gidt->b) == 0xF) | ||
465 | idt[i] = *gidt; | ||
455 | else | 466 | else |
456 | /* Reset it to the default. */ | 467 | default_idt_entry(&idt[i], i, def[i], gidt); |
457 | default_idt_entry(&idt[i], i, def[i]); | ||
458 | } | 468 | } |
459 | } | 469 | } |
460 | 470 | ||
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index 95dfda52b4f9..bf7942327bda 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c | |||
@@ -480,7 +480,7 @@ void __init lguest_arch_host_init(void) | |||
480 | * bit on its CPU, depending on the argument (0 == unset). */ | 480 | * bit on its CPU, depending on the argument (0 == unset). */ |
481 | on_each_cpu(adjust_pge, (void *)0, 1); | 481 | on_each_cpu(adjust_pge, (void *)0, 1); |
482 | /* Turn off the feature in the global feature set. */ | 482 | /* Turn off the feature in the global feature set. */ |
483 | clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); | 483 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_PGE); |
484 | } | 484 | } |
485 | put_online_cpus(); | 485 | put_online_cpus(); |
486 | }; | 486 | }; |
@@ -491,7 +491,7 @@ void __exit lguest_arch_host_fini(void) | |||
491 | /* If we had PGE before we started, turn it back on now. */ | 491 | /* If we had PGE before we started, turn it back on now. */ |
492 | get_online_cpus(); | 492 | get_online_cpus(); |
493 | if (cpu_had_pge) { | 493 | if (cpu_had_pge) { |
494 | set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); | 494 | set_cpu_cap(&boot_cpu_data, X86_FEATURE_PGE); |
495 | /* adjust_pge's argument "1" means set PGE. */ | 495 | /* adjust_pge's argument "1" means set PGE. */ |
496 | on_each_cpu(adjust_pge, (void *)1, 1); | 496 | on_each_cpu(adjust_pge, (void *)1, 1); |
497 | } | 497 | } |
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 0454be4266c1..9c9c126ed334 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -15,24 +15,24 @@ | |||
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/mfd/core.h> | 16 | #include <linux/mfd/core.h> |
17 | 17 | ||
18 | static int mfd_add_device(struct platform_device *parent, | 18 | static int mfd_add_device(struct device *parent, int id, |
19 | const struct mfd_cell *cell, | 19 | const struct mfd_cell *cell, |
20 | struct resource *mem_base, | 20 | struct resource *mem_base, |
21 | int irq_base) | 21 | int irq_base) |
22 | { | 22 | { |
23 | struct resource res[cell->num_resources]; | 23 | struct resource res[cell->num_resources]; |
24 | struct platform_device *pdev; | 24 | struct platform_device *pdev; |
25 | int ret = -ENOMEM; | 25 | int ret = -ENOMEM; |
26 | int r; | 26 | int r; |
27 | 27 | ||
28 | pdev = platform_device_alloc(cell->name, parent->id); | 28 | pdev = platform_device_alloc(cell->name, id); |
29 | if (!pdev) | 29 | if (!pdev) |
30 | goto fail_alloc; | 30 | goto fail_alloc; |
31 | 31 | ||
32 | pdev->dev.parent = &parent->dev; | 32 | pdev->dev.parent = parent; |
33 | 33 | ||
34 | ret = platform_device_add_data(pdev, | 34 | ret = platform_device_add_data(pdev, |
35 | cell, sizeof(struct mfd_cell)); | 35 | cell->platform_data, cell->data_size); |
36 | if (ret) | 36 | if (ret) |
37 | goto fail_device; | 37 | goto fail_device; |
38 | 38 | ||
@@ -75,17 +75,16 @@ fail_alloc: | |||
75 | return ret; | 75 | return ret; |
76 | } | 76 | } |
77 | 77 | ||
78 | int mfd_add_devices( | 78 | int mfd_add_devices(struct device *parent, int id, |
79 | struct platform_device *parent, | 79 | const struct mfd_cell *cells, int n_devs, |
80 | const struct mfd_cell *cells, int n_devs, | 80 | struct resource *mem_base, |
81 | struct resource *mem_base, | 81 | int irq_base) |
82 | int irq_base) | ||
83 | { | 82 | { |
84 | int i; | 83 | int i; |
85 | int ret = 0; | 84 | int ret = 0; |
86 | 85 | ||
87 | for (i = 0; i < n_devs; i++) { | 86 | for (i = 0; i < n_devs; i++) { |
88 | ret = mfd_add_device(parent, cells + i, mem_base, irq_base); | 87 | ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); |
89 | if (ret) | 88 | if (ret) |
90 | break; | 89 | break; |
91 | } | 90 | } |
@@ -99,14 +98,13 @@ EXPORT_SYMBOL(mfd_add_devices); | |||
99 | 98 | ||
100 | static int mfd_remove_devices_fn(struct device *dev, void *unused) | 99 | static int mfd_remove_devices_fn(struct device *dev, void *unused) |
101 | { | 100 | { |
102 | platform_device_unregister( | 101 | platform_device_unregister(to_platform_device(dev)); |
103 | container_of(dev, struct platform_device, dev)); | ||
104 | return 0; | 102 | return 0; |
105 | } | 103 | } |
106 | 104 | ||
107 | void mfd_remove_devices(struct platform_device *parent) | 105 | void mfd_remove_devices(struct device *parent) |
108 | { | 106 | { |
109 | device_for_each_child(&parent->dev, NULL, mfd_remove_devices_fn); | 107 | device_for_each_child(parent, NULL, mfd_remove_devices_fn); |
110 | } | 108 | } |
111 | EXPORT_SYMBOL(mfd_remove_devices); | 109 | EXPORT_SYMBOL(mfd_remove_devices); |
112 | 110 | ||
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 94e55e8e7ce6..f4fd797c1590 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
@@ -466,8 +466,12 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
466 | tc6393xb_attach_irq(dev); | 466 | tc6393xb_attach_irq(dev); |
467 | 467 | ||
468 | tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; | 468 | tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; |
469 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = | ||
470 | &tc6393xb_cells[TC6393XB_CELL_NAND]; | ||
471 | tc6393xb_cells[TC6393XB_CELL_NAND].data_size = | ||
472 | sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); | ||
469 | 473 | ||
470 | retval = mfd_add_devices(dev, | 474 | retval = mfd_add_devices(&dev->dev, dev->id, |
471 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), | 475 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), |
472 | iomem, tcpd->irq_base); | 476 | iomem, tcpd->irq_base); |
473 | 477 | ||
@@ -501,7 +505,7 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) | |||
501 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | 505 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
502 | int ret; | 506 | int ret; |
503 | 507 | ||
504 | mfd_remove_devices(dev); | 508 | mfd_remove_devices(&dev->dev); |
505 | 509 | ||
506 | if (tc6393xb->irq) | 510 | if (tc6393xb->irq) |
507 | tc6393xb_detach_irq(dev); | 511 | tc6393xb_detach_irq(dev); |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index f5ade1904aad..fa50e9ede0e6 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -426,7 +426,7 @@ config ENCLOSURE_SERVICES | |||
426 | 426 | ||
427 | config SGI_XP | 427 | config SGI_XP |
428 | tristate "Support communication between SGI SSIs" | 428 | tristate "Support communication between SGI SSIs" |
429 | depends on IA64_GENERIC || IA64_SGI_SN2 | 429 | depends on IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || (X86_64 && SMP) |
430 | select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 | 430 | select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 |
431 | select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 | 431 | select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 |
432 | ---help--- | 432 | ---help--- |
@@ -450,4 +450,27 @@ config HP_ILO | |||
450 | To compile this driver as a module, choose M here: the | 450 | To compile this driver as a module, choose M here: the |
451 | module will be called hpilo. | 451 | module will be called hpilo. |
452 | 452 | ||
453 | config SGI_GRU | ||
454 | tristate "SGI GRU driver" | ||
455 | depends on (X86_64 || IA64_SGI_UV || IA64_GENERIC) && SMP | ||
456 | default n | ||
457 | select MMU_NOTIFIER | ||
458 | ---help--- | ||
459 | The GRU is a hardware resource located in the system chipset. The GRU | ||
460 | contains memory that can be mmapped into the user address space. This memory is | ||
461 | used to communicate with the GRU to perform functions such as load/store, | ||
462 | scatter/gather, bcopy, AMOs, etc. The GRU is directly accessed by user | ||
463 | instructions using user virtual addresses. GRU instructions (ex., bcopy) use | ||
464 | user virtual addresses for operands. | ||
465 | |||
466 | If you are not running on a SGI UV system, say N. | ||
467 | |||
468 | config SGI_GRU_DEBUG | ||
469 | bool "SGI GRU driver debug" | ||
470 | depends on SGI_GRU | ||
471 | default n | ||
472 | ---help--- | ||
473 | This option enables addition debugging code for the SGI GRU driver. If | ||
474 | you are unsure, say N. | ||
475 | |||
453 | endif # MISC_DEVICES | 476 | endif # MISC_DEVICES |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index f5e273420c09..c6c13f60b452 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -28,4 +28,5 @@ obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o | |||
28 | obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o | 28 | obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o |
29 | obj-$(CONFIG_KGDB_TESTS) += kgdbts.o | 29 | obj-$(CONFIG_KGDB_TESTS) += kgdbts.o |
30 | obj-$(CONFIG_SGI_XP) += sgi-xp/ | 30 | obj-$(CONFIG_SGI_XP) += sgi-xp/ |
31 | obj-$(CONFIG_SGI_GRU) += sgi-gru/ | ||
31 | obj-$(CONFIG_HP_ILO) += hpilo.o | 32 | obj-$(CONFIG_HP_ILO) += hpilo.o |
diff --git a/drivers/misc/sgi-gru/Makefile b/drivers/misc/sgi-gru/Makefile new file mode 100644 index 000000000000..d03597a521b0 --- /dev/null +++ b/drivers/misc/sgi-gru/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | obj-$(CONFIG_SGI_GRU) := gru.o | ||
2 | gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o | ||
3 | |||
diff --git a/drivers/misc/sgi-gru/gru.h b/drivers/misc/sgi-gru/gru.h new file mode 100644 index 000000000000..40df7cb3f0a5 --- /dev/null +++ b/drivers/misc/sgi-gru/gru.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU Lesser General Public License as published by | ||
6 | * the Free Software Foundation; either version 2.1 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU Lesser General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef __GRU_H__ | ||
20 | #define __GRU_H__ | ||
21 | |||
22 | /* | ||
23 | * GRU architectural definitions | ||
24 | */ | ||
25 | #define GRU_CACHE_LINE_BYTES 64 | ||
26 | #define GRU_HANDLE_STRIDE 256 | ||
27 | #define GRU_CB_BASE 0 | ||
28 | #define GRU_DS_BASE 0x20000 | ||
29 | |||
30 | /* | ||
31 | * Size used to map GRU GSeg | ||
32 | */ | ||
33 | #if defined CONFIG_IA64 | ||
34 | #define GRU_GSEG_PAGESIZE (256 * 1024UL) | ||
35 | #elif defined CONFIG_X86_64 | ||
36 | #define GRU_GSEG_PAGESIZE (256 * 1024UL) /* ZZZ 2MB ??? */ | ||
37 | #else | ||
38 | #error "Unsupported architecture" | ||
39 | #endif | ||
40 | |||
41 | /* | ||
42 | * Structure for obtaining GRU resource information | ||
43 | */ | ||
44 | struct gru_chiplet_info { | ||
45 | int node; | ||
46 | int chiplet; | ||
47 | int blade; | ||
48 | int total_dsr_bytes; | ||
49 | int total_cbr; | ||
50 | int total_user_dsr_bytes; | ||
51 | int total_user_cbr; | ||
52 | int free_user_dsr_bytes; | ||
53 | int free_user_cbr; | ||
54 | }; | ||
55 | |||
56 | /* Flags for GRU options on the gru_create_context() call */ | ||
57 | /* Select one of the follow 4 options to specify how TLB misses are handled */ | ||
58 | #define GRU_OPT_MISS_DEFAULT 0x0000 /* Use default mode */ | ||
59 | #define GRU_OPT_MISS_USER_POLL 0x0001 /* User will poll CB for faults */ | ||
60 | #define GRU_OPT_MISS_FMM_INTR 0x0002 /* Send interrupt to cpu to | ||
61 | handle fault */ | ||
62 | #define GRU_OPT_MISS_FMM_POLL 0x0003 /* Use system polling thread */ | ||
63 | #define GRU_OPT_MISS_MASK 0x0003 /* Mask for TLB MISS option */ | ||
64 | |||
65 | |||
66 | |||
67 | #endif /* __GRU_H__ */ | ||
diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h new file mode 100644 index 000000000000..0dc36225c7c6 --- /dev/null +++ b/drivers/misc/sgi-gru/gru_instructions.h | |||
@@ -0,0 +1,669 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU Lesser General Public License as published by | ||
6 | * the Free Software Foundation; either version 2.1 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU Lesser General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef __GRU_INSTRUCTIONS_H__ | ||
20 | #define __GRU_INSTRUCTIONS_H__ | ||
21 | |||
22 | #define gru_flush_cache_hook(p) | ||
23 | #define gru_emulator_wait_hook(p, w) | ||
24 | |||
25 | /* | ||
26 | * Architecture dependent functions | ||
27 | */ | ||
28 | |||
29 | #if defined CONFIG_IA64 | ||
30 | #include <linux/compiler.h> | ||
31 | #include <asm/intrinsics.h> | ||
32 | #define __flush_cache(p) ia64_fc(p) | ||
33 | /* Use volatile on IA64 to ensure ordering via st4.rel */ | ||
34 | #define gru_ordered_store_int(p,v) \ | ||
35 | do { \ | ||
36 | barrier(); \ | ||
37 | *((volatile int *)(p)) = v; /* force st.rel */ \ | ||
38 | } while (0) | ||
39 | #elif defined CONFIG_X86_64 | ||
40 | #define __flush_cache(p) clflush(p) | ||
41 | #define gru_ordered_store_int(p,v) \ | ||
42 | do { \ | ||
43 | barrier(); \ | ||
44 | *(int *)p = v; \ | ||
45 | } while (0) | ||
46 | #else | ||
47 | #error "Unsupported architecture" | ||
48 | #endif | ||
49 | |||
50 | /* | ||
51 | * Control block status and exception codes | ||
52 | */ | ||
53 | #define CBS_IDLE 0 | ||
54 | #define CBS_EXCEPTION 1 | ||
55 | #define CBS_ACTIVE 2 | ||
56 | #define CBS_CALL_OS 3 | ||
57 | |||
58 | /* CB substatus bitmasks */ | ||
59 | #define CBSS_MSG_QUEUE_MASK 7 | ||
60 | #define CBSS_IMPLICIT_ABORT_ACTIVE_MASK 8 | ||
61 | |||
62 | /* CB substatus message queue values (low 3 bits of substatus) */ | ||
63 | #define CBSS_NO_ERROR 0 | ||
64 | #define CBSS_LB_OVERFLOWED 1 | ||
65 | #define CBSS_QLIMIT_REACHED 2 | ||
66 | #define CBSS_PAGE_OVERFLOW 3 | ||
67 | #define CBSS_AMO_NACKED 4 | ||
68 | #define CBSS_PUT_NACKED 5 | ||
69 | |||
70 | /* | ||
71 | * Structure used to fetch exception detail for CBs that terminate with | ||
72 | * CBS_EXCEPTION | ||
73 | */ | ||
74 | struct control_block_extended_exc_detail { | ||
75 | unsigned long cb; | ||
76 | int opc; | ||
77 | int ecause; | ||
78 | int exopc; | ||
79 | long exceptdet0; | ||
80 | int exceptdet1; | ||
81 | }; | ||
82 | |||
83 | /* | ||
84 | * Instruction formats | ||
85 | */ | ||
86 | |||
87 | /* | ||
88 | * Generic instruction format. | ||
89 | * This definition has precise bit field definitions. | ||
90 | */ | ||
91 | struct gru_instruction_bits { | ||
92 | /* DW 0 - low */ | ||
93 | unsigned int icmd: 1; | ||
94 | unsigned char ima: 3; /* CB_DelRep, unmapped mode */ | ||
95 | unsigned char reserved0: 4; | ||
96 | unsigned int xtype: 3; | ||
97 | unsigned int iaa0: 2; | ||
98 | unsigned int iaa1: 2; | ||
99 | unsigned char reserved1: 1; | ||
100 | unsigned char opc: 8; /* opcode */ | ||
101 | unsigned char exopc: 8; /* extended opcode */ | ||
102 | /* DW 0 - high */ | ||
103 | unsigned int idef2: 22; /* TRi0 */ | ||
104 | unsigned char reserved2: 2; | ||
105 | unsigned char istatus: 2; | ||
106 | unsigned char isubstatus:4; | ||
107 | unsigned char reserved3: 2; | ||
108 | /* DW 1 */ | ||
109 | unsigned long idef4; /* 42 bits: TRi1, BufSize */ | ||
110 | /* DW 2-6 */ | ||
111 | unsigned long idef1; /* BAddr0 */ | ||
112 | unsigned long idef5; /* Nelem */ | ||
113 | unsigned long idef6; /* Stride, Operand1 */ | ||
114 | unsigned long idef3; /* BAddr1, Value, Operand2 */ | ||
115 | unsigned long reserved4; | ||
116 | /* DW 7 */ | ||
117 | unsigned long avalue; /* AValue */ | ||
118 | }; | ||
119 | |||
120 | /* | ||
121 | * Generic instruction with friendlier names. This format is used | ||
122 | * for inline instructions. | ||
123 | */ | ||
124 | struct gru_instruction { | ||
125 | /* DW 0 */ | ||
126 | unsigned int op32; /* icmd,xtype,iaa0,ima,opc */ | ||
127 | unsigned int tri0; | ||
128 | unsigned long tri1_bufsize; /* DW 1 */ | ||
129 | unsigned long baddr0; /* DW 2 */ | ||
130 | unsigned long nelem; /* DW 3 */ | ||
131 | unsigned long op1_stride; /* DW 4 */ | ||
132 | unsigned long op2_value_baddr1; /* DW 5 */ | ||
133 | unsigned long reserved0; /* DW 6 */ | ||
134 | unsigned long avalue; /* DW 7 */ | ||
135 | }; | ||
136 | |||
137 | /* Some shifts and masks for the low 32 bits of a GRU command */ | ||
138 | #define GRU_CB_ICMD_SHFT 0 | ||
139 | #define GRU_CB_ICMD_MASK 0x1 | ||
140 | #define GRU_CB_XTYPE_SHFT 8 | ||
141 | #define GRU_CB_XTYPE_MASK 0x7 | ||
142 | #define GRU_CB_IAA0_SHFT 11 | ||
143 | #define GRU_CB_IAA0_MASK 0x3 | ||
144 | #define GRU_CB_IAA1_SHFT 13 | ||
145 | #define GRU_CB_IAA1_MASK 0x3 | ||
146 | #define GRU_CB_IMA_SHFT 1 | ||
147 | #define GRU_CB_IMA_MASK 0x3 | ||
148 | #define GRU_CB_OPC_SHFT 16 | ||
149 | #define GRU_CB_OPC_MASK 0xff | ||
150 | #define GRU_CB_EXOPC_SHFT 24 | ||
151 | #define GRU_CB_EXOPC_MASK 0xff | ||
152 | |||
153 | /* GRU instruction opcodes (opc field) */ | ||
154 | #define OP_NOP 0x00 | ||
155 | #define OP_BCOPY 0x01 | ||
156 | #define OP_VLOAD 0x02 | ||
157 | #define OP_IVLOAD 0x03 | ||
158 | #define OP_VSTORE 0x04 | ||
159 | #define OP_IVSTORE 0x05 | ||
160 | #define OP_VSET 0x06 | ||
161 | #define OP_IVSET 0x07 | ||
162 | #define OP_MESQ 0x08 | ||
163 | #define OP_GAMXR 0x09 | ||
164 | #define OP_GAMIR 0x0a | ||
165 | #define OP_GAMIRR 0x0b | ||
166 | #define OP_GAMER 0x0c | ||
167 | #define OP_GAMERR 0x0d | ||
168 | #define OP_BSTORE 0x0e | ||
169 | #define OP_VFLUSH 0x0f | ||
170 | |||
171 | |||
172 | /* Extended opcodes values (exopc field) */ | ||
173 | |||
174 | /* GAMIR - AMOs with implicit operands */ | ||
175 | #define EOP_IR_FETCH 0x01 /* Plain fetch of memory */ | ||
176 | #define EOP_IR_CLR 0x02 /* Fetch and clear */ | ||
177 | #define EOP_IR_INC 0x05 /* Fetch and increment */ | ||
178 | #define EOP_IR_DEC 0x07 /* Fetch and decrement */ | ||
179 | #define EOP_IR_QCHK1 0x0d /* Queue check, 64 byte msg */ | ||
180 | #define EOP_IR_QCHK2 0x0e /* Queue check, 128 byte msg */ | ||
181 | |||
182 | /* GAMIRR - Registered AMOs with implicit operands */ | ||
183 | #define EOP_IRR_FETCH 0x01 /* Registered fetch of memory */ | ||
184 | #define EOP_IRR_CLR 0x02 /* Registered fetch and clear */ | ||
185 | #define EOP_IRR_INC 0x05 /* Registered fetch and increment */ | ||
186 | #define EOP_IRR_DEC 0x07 /* Registered fetch and decrement */ | ||
187 | #define EOP_IRR_DECZ 0x0f /* Registered fetch and decrement, update on zero*/ | ||
188 | |||
189 | /* GAMER - AMOs with explicit operands */ | ||
190 | #define EOP_ER_SWAP 0x00 /* Exchange argument and memory */ | ||
191 | #define EOP_ER_OR 0x01 /* Logical OR with memory */ | ||
192 | #define EOP_ER_AND 0x02 /* Logical AND with memory */ | ||
193 | #define EOP_ER_XOR 0x03 /* Logical XOR with memory */ | ||
194 | #define EOP_ER_ADD 0x04 /* Add value to memory */ | ||
195 | #define EOP_ER_CSWAP 0x08 /* Compare with operand2, write operand1 if match*/ | ||
196 | #define EOP_ER_CADD 0x0c /* Queue check, operand1*64 byte msg */ | ||
197 | |||
198 | /* GAMERR - Registered AMOs with explicit operands */ | ||
199 | #define EOP_ERR_SWAP 0x00 /* Exchange argument and memory */ | ||
200 | #define EOP_ERR_OR 0x01 /* Logical OR with memory */ | ||
201 | #define EOP_ERR_AND 0x02 /* Logical AND with memory */ | ||
202 | #define EOP_ERR_XOR 0x03 /* Logical XOR with memory */ | ||
203 | #define EOP_ERR_ADD 0x04 /* Add value to memory */ | ||
204 | #define EOP_ERR_CSWAP 0x08 /* Compare with operand2, write operand1 if match*/ | ||
205 | #define EOP_ERR_EPOLL 0x09 /* Poll for equality */ | ||
206 | #define EOP_ERR_NPOLL 0x0a /* Poll for inequality */ | ||
207 | |||
208 | /* GAMXR - SGI Arithmetic unit */ | ||
209 | #define EOP_XR_CSWAP 0x0b /* Masked compare exchange */ | ||
210 | |||
211 | |||
212 | /* Transfer types (xtype field) */ | ||
213 | #define XTYPE_B 0x0 /* byte */ | ||
214 | #define XTYPE_S 0x1 /* short (2-byte) */ | ||
215 | #define XTYPE_W 0x2 /* word (4-byte) */ | ||
216 | #define XTYPE_DW 0x3 /* doubleword (8-byte) */ | ||
217 | #define XTYPE_CL 0x6 /* cacheline (64-byte) */ | ||
218 | |||
219 | |||
220 | /* Instruction access attributes (iaa0, iaa1 fields) */ | ||
221 | #define IAA_RAM 0x0 /* normal cached RAM access */ | ||
222 | #define IAA_NCRAM 0x2 /* noncoherent RAM access */ | ||
223 | #define IAA_MMIO 0x1 /* noncoherent memory-mapped I/O space */ | ||
224 | #define IAA_REGISTER 0x3 /* memory-mapped registers, etc. */ | ||
225 | |||
226 | |||
227 | /* Instruction mode attributes (ima field) */ | ||
228 | #define IMA_MAPPED 0x0 /* Virtual mode */ | ||
229 | #define IMA_CB_DELAY 0x1 /* hold read responses until status changes */ | ||
230 | #define IMA_UNMAPPED 0x2 /* bypass the TLBs (OS only) */ | ||
231 | #define IMA_INTERRUPT 0x4 /* Interrupt when instruction completes */ | ||
232 | |||
233 | /* CBE ecause bits */ | ||
234 | #define CBE_CAUSE_RI (1 << 0) | ||
235 | #define CBE_CAUSE_INVALID_INSTRUCTION (1 << 1) | ||
236 | #define CBE_CAUSE_UNMAPPED_MODE_FORBIDDEN (1 << 2) | ||
237 | #define CBE_CAUSE_PE_CHECK_DATA_ERROR (1 << 3) | ||
238 | #define CBE_CAUSE_IAA_GAA_MISMATCH (1 << 4) | ||
239 | #define CBE_CAUSE_DATA_SEGMENT_LIMIT_EXCEPTION (1 << 5) | ||
240 | #define CBE_CAUSE_OS_FATAL_TLB_FAULT (1 << 6) | ||
241 | #define CBE_CAUSE_EXECUTION_HW_ERROR (1 << 7) | ||
242 | #define CBE_CAUSE_TLBHW_ERROR (1 << 8) | ||
243 | #define CBE_CAUSE_RA_REQUEST_TIMEOUT (1 << 9) | ||
244 | #define CBE_CAUSE_HA_REQUEST_TIMEOUT (1 << 10) | ||
245 | #define CBE_CAUSE_RA_RESPONSE_FATAL (1 << 11) | ||
246 | #define CBE_CAUSE_RA_RESPONSE_NON_FATAL (1 << 12) | ||
247 | #define CBE_CAUSE_HA_RESPONSE_FATAL (1 << 13) | ||
248 | #define CBE_CAUSE_HA_RESPONSE_NON_FATAL (1 << 14) | ||
249 | #define CBE_CAUSE_ADDRESS_SPACE_DECODE_ERROR (1 << 15) | ||
250 | #define CBE_CAUSE_RESPONSE_DATA_ERROR (1 << 16) | ||
251 | #define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR (1 << 17) | ||
252 | |||
253 | /* | ||
254 | * Exceptions are retried for the following cases. If any OTHER bits are set | ||
255 | * in ecause, the exception is not retryable. | ||
256 | */ | ||
257 | #define EXCEPTION_RETRY_BITS (CBE_CAUSE_RESPONSE_DATA_ERROR | \ | ||
258 | CBE_CAUSE_RA_REQUEST_TIMEOUT | \ | ||
259 | CBE_CAUSE_TLBHW_ERROR | \ | ||
260 | CBE_CAUSE_HA_REQUEST_TIMEOUT) | ||
261 | |||
262 | /* Message queue head structure */ | ||
263 | union gru_mesqhead { | ||
264 | unsigned long val; | ||
265 | struct { | ||
266 | unsigned int head; | ||
267 | unsigned int limit; | ||
268 | }; | ||
269 | }; | ||
270 | |||
271 | |||
272 | /* Generate the low word of a GRU instruction */ | ||
273 | static inline unsigned int | ||
274 | __opword(unsigned char opcode, unsigned char exopc, unsigned char xtype, | ||
275 | unsigned char iaa0, unsigned char iaa1, | ||
276 | unsigned char ima) | ||
277 | { | ||
278 | return (1 << GRU_CB_ICMD_SHFT) | | ||
279 | (iaa0 << GRU_CB_IAA0_SHFT) | | ||
280 | (iaa1 << GRU_CB_IAA1_SHFT) | | ||
281 | (ima << GRU_CB_IMA_SHFT) | | ||
282 | (xtype << GRU_CB_XTYPE_SHFT) | | ||
283 | (opcode << GRU_CB_OPC_SHFT) | | ||
284 | (exopc << GRU_CB_EXOPC_SHFT); | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Architecture specific intrinsics | ||
289 | */ | ||
290 | static inline void gru_flush_cache(void *p) | ||
291 | { | ||
292 | __flush_cache(p); | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Store the lower 32 bits of the command including the "start" bit. Then | ||
297 | * start the instruction executing. | ||
298 | */ | ||
299 | static inline void gru_start_instruction(struct gru_instruction *ins, int op32) | ||
300 | { | ||
301 | gru_ordered_store_int(ins, op32); | ||
302 | } | ||
303 | |||
304 | |||
305 | /* Convert "hints" to IMA */ | ||
306 | #define CB_IMA(h) ((h) | IMA_UNMAPPED) | ||
307 | |||
308 | /* Convert data segment cache line index into TRI0 / TRI1 value */ | ||
309 | #define GRU_DINDEX(i) ((i) * GRU_CACHE_LINE_BYTES) | ||
310 | |||
311 | /* Inline functions for GRU instructions. | ||
312 | * Note: | ||
313 | * - nelem and stride are in elements | ||
314 | * - tri0/tri1 is in bytes for the beginning of the data segment. | ||
315 | */ | ||
316 | static inline void gru_vload(void *cb, unsigned long mem_addr, | ||
317 | unsigned int tri0, unsigned char xtype, unsigned long nelem, | ||
318 | unsigned long stride, unsigned long hints) | ||
319 | { | ||
320 | struct gru_instruction *ins = (struct gru_instruction *)cb; | ||
321 | |||
322 | ins->baddr0 = (long)mem_addr; | ||
323 | ins->nelem = nelem; | ||
324 | ins->tri0 = tri0; | ||
325 | ins->op1_stride = stride; | ||
326 | gru_start_instruction(ins, __opword(OP_VLOAD, 0, xtype, IAA_RAM, 0, | ||
327 | CB_IMA(hints))); | ||
328 | } | ||
329 | |||
330 | static inline void gru_vstore(void *cb, unsigned long mem_addr, | ||
331 | unsigned int tri0, unsigned char xtype, unsigned long nelem, | ||
332 | unsigned long stride, unsigned long hints) | ||
333 | { | ||
334 | struct gru_instruction *ins = (void *)cb; | ||
335 | |||
336 | ins->baddr0 = (long)mem_addr; | ||
337 | ins->nelem = nelem; | ||
338 | ins->tri0 = tri0; | ||
339 | ins->op1_stride = stride; | ||
340 | gru_start_instruction(ins, __opword(OP_VSTORE, 0, xtype, IAA_RAM, 0, | ||
341 | CB_IMA(hints))); | ||
342 | } | ||
343 | |||
344 | static inline void gru_ivload(void *cb, unsigned long mem_addr, | ||
345 | unsigned int tri0, unsigned int tri1, unsigned char xtype, | ||
346 | unsigned long nelem, unsigned long hints) | ||
347 | { | ||
348 | struct gru_instruction *ins = (void *)cb; | ||
349 | |||
350 | ins->baddr0 = (long)mem_addr; | ||
351 | ins->nelem = nelem; | ||
352 | ins->tri0 = tri0; | ||
353 | ins->tri1_bufsize = tri1; | ||
354 | gru_start_instruction(ins, __opword(OP_IVLOAD, 0, xtype, IAA_RAM, 0, | ||
355 | CB_IMA(hints))); | ||
356 | } | ||
357 | |||
358 | static inline void gru_ivstore(void *cb, unsigned long mem_addr, | ||
359 | unsigned int tri0, unsigned int tri1, | ||
360 | unsigned char xtype, unsigned long nelem, unsigned long hints) | ||
361 | { | ||
362 | struct gru_instruction *ins = (void *)cb; | ||
363 | |||
364 | ins->baddr0 = (long)mem_addr; | ||
365 | ins->nelem = nelem; | ||
366 | ins->tri0 = tri0; | ||
367 | ins->tri1_bufsize = tri1; | ||
368 | gru_start_instruction(ins, __opword(OP_IVSTORE, 0, xtype, IAA_RAM, 0, | ||
369 | CB_IMA(hints))); | ||
370 | } | ||
371 | |||
372 | static inline void gru_vset(void *cb, unsigned long mem_addr, | ||
373 | unsigned long value, unsigned char xtype, unsigned long nelem, | ||
374 | unsigned long stride, unsigned long hints) | ||
375 | { | ||
376 | struct gru_instruction *ins = (void *)cb; | ||
377 | |||
378 | ins->baddr0 = (long)mem_addr; | ||
379 | ins->op2_value_baddr1 = value; | ||
380 | ins->nelem = nelem; | ||
381 | ins->op1_stride = stride; | ||
382 | gru_start_instruction(ins, __opword(OP_VSET, 0, xtype, IAA_RAM, 0, | ||
383 | CB_IMA(hints))); | ||
384 | } | ||
385 | |||
386 | static inline void gru_ivset(void *cb, unsigned long mem_addr, | ||
387 | unsigned int tri1, unsigned long value, unsigned char xtype, | ||
388 | unsigned long nelem, unsigned long hints) | ||
389 | { | ||
390 | struct gru_instruction *ins = (void *)cb; | ||
391 | |||
392 | ins->baddr0 = (long)mem_addr; | ||
393 | ins->op2_value_baddr1 = value; | ||
394 | ins->nelem = nelem; | ||
395 | ins->tri1_bufsize = tri1; | ||
396 | gru_start_instruction(ins, __opword(OP_IVSET, 0, xtype, IAA_RAM, 0, | ||
397 | CB_IMA(hints))); | ||
398 | } | ||
399 | |||
400 | static inline void gru_vflush(void *cb, unsigned long mem_addr, | ||
401 | unsigned long nelem, unsigned char xtype, unsigned long stride, | ||
402 | unsigned long hints) | ||
403 | { | ||
404 | struct gru_instruction *ins = (void *)cb; | ||
405 | |||
406 | ins->baddr0 = (long)mem_addr; | ||
407 | ins->op1_stride = stride; | ||
408 | ins->nelem = nelem; | ||
409 | gru_start_instruction(ins, __opword(OP_VFLUSH, 0, xtype, IAA_RAM, 0, | ||
410 | CB_IMA(hints))); | ||
411 | } | ||
412 | |||
413 | static inline void gru_nop(void *cb, int hints) | ||
414 | { | ||
415 | struct gru_instruction *ins = (void *)cb; | ||
416 | |||
417 | gru_start_instruction(ins, __opword(OP_NOP, 0, 0, 0, 0, CB_IMA(hints))); | ||
418 | } | ||
419 | |||
420 | |||
421 | static inline void gru_bcopy(void *cb, const unsigned long src, | ||
422 | unsigned long dest, | ||
423 | unsigned int tri0, unsigned int xtype, unsigned long nelem, | ||
424 | unsigned int bufsize, unsigned long hints) | ||
425 | { | ||
426 | struct gru_instruction *ins = (void *)cb; | ||
427 | |||
428 | ins->baddr0 = (long)src; | ||
429 | ins->op2_value_baddr1 = (long)dest; | ||
430 | ins->nelem = nelem; | ||
431 | ins->tri0 = tri0; | ||
432 | ins->tri1_bufsize = bufsize; | ||
433 | gru_start_instruction(ins, __opword(OP_BCOPY, 0, xtype, IAA_RAM, | ||
434 | IAA_RAM, CB_IMA(hints))); | ||
435 | } | ||
436 | |||
437 | static inline void gru_bstore(void *cb, const unsigned long src, | ||
438 | unsigned long dest, unsigned int tri0, unsigned int xtype, | ||
439 | unsigned long nelem, unsigned long hints) | ||
440 | { | ||
441 | struct gru_instruction *ins = (void *)cb; | ||
442 | |||
443 | ins->baddr0 = (long)src; | ||
444 | ins->op2_value_baddr1 = (long)dest; | ||
445 | ins->nelem = nelem; | ||
446 | ins->tri0 = tri0; | ||
447 | gru_start_instruction(ins, __opword(OP_BSTORE, 0, xtype, 0, IAA_RAM, | ||
448 | CB_IMA(hints))); | ||
449 | } | ||
450 | |||
451 | static inline void gru_gamir(void *cb, int exopc, unsigned long src, | ||
452 | unsigned int xtype, unsigned long hints) | ||
453 | { | ||
454 | struct gru_instruction *ins = (void *)cb; | ||
455 | |||
456 | ins->baddr0 = (long)src; | ||
457 | gru_start_instruction(ins, __opword(OP_GAMIR, exopc, xtype, IAA_RAM, 0, | ||
458 | CB_IMA(hints))); | ||
459 | } | ||
460 | |||
461 | static inline void gru_gamirr(void *cb, int exopc, unsigned long src, | ||
462 | unsigned int xtype, unsigned long hints) | ||
463 | { | ||
464 | struct gru_instruction *ins = (void *)cb; | ||
465 | |||
466 | ins->baddr0 = (long)src; | ||
467 | gru_start_instruction(ins, __opword(OP_GAMIRR, exopc, xtype, IAA_RAM, 0, | ||
468 | CB_IMA(hints))); | ||
469 | } | ||
470 | |||
471 | static inline void gru_gamer(void *cb, int exopc, unsigned long src, | ||
472 | unsigned int xtype, | ||
473 | unsigned long operand1, unsigned long operand2, | ||
474 | unsigned long hints) | ||
475 | { | ||
476 | struct gru_instruction *ins = (void *)cb; | ||
477 | |||
478 | ins->baddr0 = (long)src; | ||
479 | ins->op1_stride = operand1; | ||
480 | ins->op2_value_baddr1 = operand2; | ||
481 | gru_start_instruction(ins, __opword(OP_GAMER, exopc, xtype, IAA_RAM, 0, | ||
482 | CB_IMA(hints))); | ||
483 | } | ||
484 | |||
485 | static inline void gru_gamerr(void *cb, int exopc, unsigned long src, | ||
486 | unsigned int xtype, unsigned long operand1, | ||
487 | unsigned long operand2, unsigned long hints) | ||
488 | { | ||
489 | struct gru_instruction *ins = (void *)cb; | ||
490 | |||
491 | ins->baddr0 = (long)src; | ||
492 | ins->op1_stride = operand1; | ||
493 | ins->op2_value_baddr1 = operand2; | ||
494 | gru_start_instruction(ins, __opword(OP_GAMERR, exopc, xtype, IAA_RAM, 0, | ||
495 | CB_IMA(hints))); | ||
496 | } | ||
497 | |||
498 | static inline void gru_gamxr(void *cb, unsigned long src, | ||
499 | unsigned int tri0, unsigned long hints) | ||
500 | { | ||
501 | struct gru_instruction *ins = (void *)cb; | ||
502 | |||
503 | ins->baddr0 = (long)src; | ||
504 | ins->nelem = 4; | ||
505 | gru_start_instruction(ins, __opword(OP_GAMXR, EOP_XR_CSWAP, XTYPE_DW, | ||
506 | IAA_RAM, 0, CB_IMA(hints))); | ||
507 | } | ||
508 | |||
509 | static inline void gru_mesq(void *cb, unsigned long queue, | ||
510 | unsigned long tri0, unsigned long nelem, | ||
511 | unsigned long hints) | ||
512 | { | ||
513 | struct gru_instruction *ins = (void *)cb; | ||
514 | |||
515 | ins->baddr0 = (long)queue; | ||
516 | ins->nelem = nelem; | ||
517 | ins->tri0 = tri0; | ||
518 | gru_start_instruction(ins, __opword(OP_MESQ, 0, XTYPE_CL, IAA_RAM, 0, | ||
519 | CB_IMA(hints))); | ||
520 | } | ||
521 | |||
522 | static inline unsigned long gru_get_amo_value(void *cb) | ||
523 | { | ||
524 | struct gru_instruction *ins = (void *)cb; | ||
525 | |||
526 | return ins->avalue; | ||
527 | } | ||
528 | |||
529 | static inline int gru_get_amo_value_head(void *cb) | ||
530 | { | ||
531 | struct gru_instruction *ins = (void *)cb; | ||
532 | |||
533 | return ins->avalue & 0xffffffff; | ||
534 | } | ||
535 | |||
536 | static inline int gru_get_amo_value_limit(void *cb) | ||
537 | { | ||
538 | struct gru_instruction *ins = (void *)cb; | ||
539 | |||
540 | return ins->avalue >> 32; | ||
541 | } | ||
542 | |||
543 | static inline union gru_mesqhead gru_mesq_head(int head, int limit) | ||
544 | { | ||
545 | union gru_mesqhead mqh; | ||
546 | |||
547 | mqh.head = head; | ||
548 | mqh.limit = limit; | ||
549 | return mqh; | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * Get struct control_block_extended_exc_detail for CB. | ||
554 | */ | ||
555 | extern int gru_get_cb_exception_detail(void *cb, | ||
556 | struct control_block_extended_exc_detail *excdet); | ||
557 | |||
558 | #define GRU_EXC_STR_SIZE 256 | ||
559 | |||
560 | extern int gru_check_status_proc(void *cb); | ||
561 | extern int gru_wait_proc(void *cb); | ||
562 | extern void gru_wait_abort_proc(void *cb); | ||
563 | |||
564 | /* | ||
565 | * Control block definition for checking status | ||
566 | */ | ||
567 | struct gru_control_block_status { | ||
568 | unsigned int icmd :1; | ||
569 | unsigned int unused1 :31; | ||
570 | unsigned int unused2 :24; | ||
571 | unsigned int istatus :2; | ||
572 | unsigned int isubstatus :4; | ||
573 | unsigned int inused3 :2; | ||
574 | }; | ||
575 | |||
576 | /* Get CB status */ | ||
577 | static inline int gru_get_cb_status(void *cb) | ||
578 | { | ||
579 | struct gru_control_block_status *cbs = (void *)cb; | ||
580 | |||
581 | return cbs->istatus; | ||
582 | } | ||
583 | |||
584 | /* Get CB message queue substatus */ | ||
585 | static inline int gru_get_cb_message_queue_substatus(void *cb) | ||
586 | { | ||
587 | struct gru_control_block_status *cbs = (void *)cb; | ||
588 | |||
589 | return cbs->isubstatus & CBSS_MSG_QUEUE_MASK; | ||
590 | } | ||
591 | |||
592 | /* Get CB substatus */ | ||
593 | static inline int gru_get_cb_substatus(void *cb) | ||
594 | { | ||
595 | struct gru_control_block_status *cbs = (void *)cb; | ||
596 | |||
597 | return cbs->isubstatus; | ||
598 | } | ||
599 | |||
600 | /* Check the status of a CB. If the CB is in UPM mode, call the | ||
601 | * OS to handle the UPM status. | ||
602 | * Returns the CB status field value (0 for normal completion) | ||
603 | */ | ||
604 | static inline int gru_check_status(void *cb) | ||
605 | { | ||
606 | struct gru_control_block_status *cbs = (void *)cb; | ||
607 | int ret = cbs->istatus; | ||
608 | |||
609 | if (ret == CBS_CALL_OS) | ||
610 | ret = gru_check_status_proc(cb); | ||
611 | return ret; | ||
612 | } | ||
613 | |||
614 | /* Wait for CB to complete. | ||
615 | * Returns the CB status field value (0 for normal completion) | ||
616 | */ | ||
617 | static inline int gru_wait(void *cb) | ||
618 | { | ||
619 | struct gru_control_block_status *cbs = (void *)cb; | ||
620 | int ret = cbs->istatus;; | ||
621 | |||
622 | if (ret != CBS_IDLE) | ||
623 | ret = gru_wait_proc(cb); | ||
624 | return ret; | ||
625 | } | ||
626 | |||
627 | /* Wait for CB to complete. Aborts program if error. (Note: error does NOT | ||
628 | * mean TLB mis - only fatal errors such as memory parity error or user | ||
629 | * bugs will cause termination. | ||
630 | */ | ||
631 | static inline void gru_wait_abort(void *cb) | ||
632 | { | ||
633 | struct gru_control_block_status *cbs = (void *)cb; | ||
634 | |||
635 | if (cbs->istatus != CBS_IDLE) | ||
636 | gru_wait_abort_proc(cb); | ||
637 | } | ||
638 | |||
639 | |||
640 | /* | ||
641 | * Get a pointer to a control block | ||
642 | * gseg - GSeg address returned from gru_get_thread_gru_segment() | ||
643 | * index - index of desired CB | ||
644 | */ | ||
645 | static inline void *gru_get_cb_pointer(void *gseg, | ||
646 | int index) | ||
647 | { | ||
648 | return gseg + GRU_CB_BASE + index * GRU_HANDLE_STRIDE; | ||
649 | } | ||
650 | |||
651 | /* | ||
652 | * Get a pointer to a cacheline in the data segment portion of a GSeg | ||
653 | * gseg - GSeg address returned from gru_get_thread_gru_segment() | ||
654 | * index - index of desired cache line | ||
655 | */ | ||
656 | static inline void *gru_get_data_pointer(void *gseg, int index) | ||
657 | { | ||
658 | return gseg + GRU_DS_BASE + index * GRU_CACHE_LINE_BYTES; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * Convert a vaddr into the tri index within the GSEG | ||
663 | * vaddr - virtual address of within gseg | ||
664 | */ | ||
665 | static inline int gru_get_tri(void *vaddr) | ||
666 | { | ||
667 | return ((unsigned long)vaddr & (GRU_GSEG_PAGESIZE - 1)) - GRU_DS_BASE; | ||
668 | } | ||
669 | #endif /* __GRU_INSTRUCTIONS_H__ */ | ||
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c new file mode 100644 index 000000000000..3d33015bbf31 --- /dev/null +++ b/drivers/misc/sgi-gru/grufault.c | |||
@@ -0,0 +1,633 @@ | |||
1 | /* | ||
2 | * SN Platform GRU Driver | ||
3 | * | ||
4 | * FAULT HANDLER FOR GRU DETECTED TLB MISSES | ||
5 | * | ||
6 | * This file contains code that handles TLB misses within the GRU. | ||
7 | * These misses are reported either via interrupts or user polling of | ||
8 | * the user CB. | ||
9 | * | ||
10 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/hugetlb.h> | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/io.h> | ||
34 | #include <linux/uaccess.h> | ||
35 | #include <asm/pgtable.h> | ||
36 | #include "gru.h" | ||
37 | #include "grutables.h" | ||
38 | #include "grulib.h" | ||
39 | #include "gru_instructions.h" | ||
40 | #include <asm/uv/uv_hub.h> | ||
41 | |||
42 | /* | ||
43 | * Test if a physical address is a valid GRU GSEG address | ||
44 | */ | ||
45 | static inline int is_gru_paddr(unsigned long paddr) | ||
46 | { | ||
47 | return paddr >= gru_start_paddr && paddr < gru_end_paddr; | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * Find the vma of a GRU segment. Caller must hold mmap_sem. | ||
52 | */ | ||
53 | struct vm_area_struct *gru_find_vma(unsigned long vaddr) | ||
54 | { | ||
55 | struct vm_area_struct *vma; | ||
56 | |||
57 | vma = find_vma(current->mm, vaddr); | ||
58 | if (vma && vma->vm_start <= vaddr && vma->vm_ops == &gru_vm_ops) | ||
59 | return vma; | ||
60 | return NULL; | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * Find and lock the gts that contains the specified user vaddr. | ||
65 | * | ||
66 | * Returns: | ||
67 | * - *gts with the mmap_sem locked for read and the GTS locked. | ||
68 | * - NULL if vaddr invalid OR is not a valid GSEG vaddr. | ||
69 | */ | ||
70 | |||
71 | static struct gru_thread_state *gru_find_lock_gts(unsigned long vaddr) | ||
72 | { | ||
73 | struct mm_struct *mm = current->mm; | ||
74 | struct vm_area_struct *vma; | ||
75 | struct gru_thread_state *gts = NULL; | ||
76 | |||
77 | down_read(&mm->mmap_sem); | ||
78 | vma = gru_find_vma(vaddr); | ||
79 | if (vma) | ||
80 | gts = gru_find_thread_state(vma, TSID(vaddr, vma)); | ||
81 | if (gts) | ||
82 | mutex_lock(>s->ts_ctxlock); | ||
83 | else | ||
84 | up_read(&mm->mmap_sem); | ||
85 | return gts; | ||
86 | } | ||
87 | |||
88 | static struct gru_thread_state *gru_alloc_locked_gts(unsigned long vaddr) | ||
89 | { | ||
90 | struct mm_struct *mm = current->mm; | ||
91 | struct vm_area_struct *vma; | ||
92 | struct gru_thread_state *gts = NULL; | ||
93 | |||
94 | down_write(&mm->mmap_sem); | ||
95 | vma = gru_find_vma(vaddr); | ||
96 | if (vma) | ||
97 | gts = gru_alloc_thread_state(vma, TSID(vaddr, vma)); | ||
98 | if (gts) { | ||
99 | mutex_lock(>s->ts_ctxlock); | ||
100 | downgrade_write(&mm->mmap_sem); | ||
101 | } else { | ||
102 | up_write(&mm->mmap_sem); | ||
103 | } | ||
104 | |||
105 | return gts; | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * Unlock a GTS that was previously locked with gru_find_lock_gts(). | ||
110 | */ | ||
111 | static void gru_unlock_gts(struct gru_thread_state *gts) | ||
112 | { | ||
113 | mutex_unlock(>s->ts_ctxlock); | ||
114 | up_read(¤t->mm->mmap_sem); | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Set a CB.istatus to active using a user virtual address. This must be done | ||
119 | * just prior to a TFH RESTART. The new cb.istatus is an in-cache status ONLY. | ||
120 | * If the line is evicted, the status may be lost. The in-cache update | ||
121 | * is necessary to prevent the user from seeing a stale cb.istatus that will | ||
122 | * change as soon as the TFH restart is complete. Races may cause an | ||
123 | * occasional failure to clear the cb.istatus, but that is ok. | ||
124 | * | ||
125 | * If the cb address is not valid (should not happen, but...), nothing | ||
126 | * bad will happen.. The get_user()/put_user() will fail but there | ||
127 | * are no bad side-effects. | ||
128 | */ | ||
129 | static void gru_cb_set_istatus_active(unsigned long __user *cb) | ||
130 | { | ||
131 | union { | ||
132 | struct gru_instruction_bits bits; | ||
133 | unsigned long dw; | ||
134 | } u; | ||
135 | |||
136 | if (cb) { | ||
137 | get_user(u.dw, cb); | ||
138 | u.bits.istatus = CBS_ACTIVE; | ||
139 | put_user(u.dw, cb); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Convert a interrupt IRQ to a pointer to the GRU GTS that caused the | ||
145 | * interrupt. Interrupts are always sent to a cpu on the blade that contains the | ||
146 | * GRU (except for headless blades which are not currently supported). A blade | ||
147 | * has N grus; a block of N consecutive IRQs is assigned to the GRUs. The IRQ | ||
148 | * number uniquely identifies the GRU chiplet on the local blade that caused the | ||
149 | * interrupt. Always called in interrupt context. | ||
150 | */ | ||
151 | static inline struct gru_state *irq_to_gru(int irq) | ||
152 | { | ||
153 | return &gru_base[uv_numa_blade_id()]->bs_grus[irq - IRQ_GRU]; | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * Read & clear a TFM | ||
158 | * | ||
159 | * The GRU has an array of fault maps. A map is private to a cpu | ||
160 | * Only one cpu will be accessing a cpu's fault map. | ||
161 | * | ||
162 | * This function scans the cpu-private fault map & clears all bits that | ||
163 | * are set. The function returns a bitmap that indicates the bits that | ||
164 | * were cleared. Note that sense the maps may be updated asynchronously by | ||
165 | * the GRU, atomic operations must be used to clear bits. | ||
166 | */ | ||
167 | static void get_clear_fault_map(struct gru_state *gru, | ||
168 | struct gru_tlb_fault_map *map) | ||
169 | { | ||
170 | unsigned long i, k; | ||
171 | struct gru_tlb_fault_map *tfm; | ||
172 | |||
173 | tfm = get_tfm_for_cpu(gru, gru_cpu_fault_map_id()); | ||
174 | prefetchw(tfm); /* Helps on hardware, required for emulator */ | ||
175 | for (i = 0; i < BITS_TO_LONGS(GRU_NUM_CBE); i++) { | ||
176 | k = tfm->fault_bits[i]; | ||
177 | if (k) | ||
178 | k = xchg(&tfm->fault_bits[i], 0UL); | ||
179 | map->fault_bits[i] = k; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Not functionally required but helps performance. (Required | ||
184 | * on emulator) | ||
185 | */ | ||
186 | gru_flush_cache(tfm); | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Atomic (interrupt context) & non-atomic (user context) functions to | ||
191 | * convert a vaddr into a physical address. The size of the page | ||
192 | * is returned in pageshift. | ||
193 | * returns: | ||
194 | * 0 - successful | ||
195 | * < 0 - error code | ||
196 | * 1 - (atomic only) try again in non-atomic context | ||
197 | */ | ||
198 | static int non_atomic_pte_lookup(struct vm_area_struct *vma, | ||
199 | unsigned long vaddr, int write, | ||
200 | unsigned long *paddr, int *pageshift) | ||
201 | { | ||
202 | struct page *page; | ||
203 | |||
204 | /* ZZZ Need to handle HUGE pages */ | ||
205 | if (is_vm_hugetlb_page(vma)) | ||
206 | return -EFAULT; | ||
207 | *pageshift = PAGE_SHIFT; | ||
208 | if (get_user_pages | ||
209 | (current, current->mm, vaddr, 1, write, 0, &page, NULL) <= 0) | ||
210 | return -EFAULT; | ||
211 | *paddr = page_to_phys(page); | ||
212 | put_page(page); | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * | ||
218 | * atomic_pte_lookup | ||
219 | * | ||
220 | * Convert a user virtual address to a physical address | ||
221 | * Only supports Intel large pages (2MB only) on x86_64. | ||
222 | * ZZZ - hugepage support is incomplete | ||
223 | */ | ||
224 | static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr, | ||
225 | int write, unsigned long *paddr, int *pageshift) | ||
226 | { | ||
227 | pgd_t *pgdp; | ||
228 | pmd_t *pmdp; | ||
229 | pud_t *pudp; | ||
230 | pte_t pte; | ||
231 | |||
232 | WARN_ON(irqs_disabled()); /* ZZZ debug */ | ||
233 | |||
234 | local_irq_disable(); | ||
235 | pgdp = pgd_offset(vma->vm_mm, vaddr); | ||
236 | if (unlikely(pgd_none(*pgdp))) | ||
237 | goto err; | ||
238 | |||
239 | pudp = pud_offset(pgdp, vaddr); | ||
240 | if (unlikely(pud_none(*pudp))) | ||
241 | goto err; | ||
242 | |||
243 | pmdp = pmd_offset(pudp, vaddr); | ||
244 | if (unlikely(pmd_none(*pmdp))) | ||
245 | goto err; | ||
246 | #ifdef CONFIG_X86_64 | ||
247 | if (unlikely(pmd_large(*pmdp))) | ||
248 | pte = *(pte_t *) pmdp; | ||
249 | else | ||
250 | #endif | ||
251 | pte = *pte_offset_kernel(pmdp, vaddr); | ||
252 | |||
253 | local_irq_enable(); | ||
254 | |||
255 | if (unlikely(!pte_present(pte) || | ||
256 | (write && (!pte_write(pte) || !pte_dirty(pte))))) | ||
257 | return 1; | ||
258 | |||
259 | *paddr = pte_pfn(pte) << PAGE_SHIFT; | ||
260 | *pageshift = is_vm_hugetlb_page(vma) ? HPAGE_SHIFT : PAGE_SHIFT; | ||
261 | return 0; | ||
262 | |||
263 | err: | ||
264 | local_irq_enable(); | ||
265 | return 1; | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * Drop a TLB entry into the GRU. The fault is described by info in an TFH. | ||
270 | * Input: | ||
271 | * cb Address of user CBR. Null if not running in user context | ||
272 | * Return: | ||
273 | * 0 = dropin, exception, or switch to UPM successful | ||
274 | * 1 = range invalidate active | ||
275 | * < 0 = error code | ||
276 | * | ||
277 | */ | ||
278 | static int gru_try_dropin(struct gru_thread_state *gts, | ||
279 | struct gru_tlb_fault_handle *tfh, | ||
280 | unsigned long __user *cb) | ||
281 | { | ||
282 | struct mm_struct *mm = gts->ts_mm; | ||
283 | struct vm_area_struct *vma; | ||
284 | int pageshift, asid, write, ret; | ||
285 | unsigned long paddr, gpa, vaddr; | ||
286 | |||
287 | /* | ||
288 | * NOTE: The GRU contains magic hardware that eliminates races between | ||
289 | * TLB invalidates and TLB dropins. If an invalidate occurs | ||
290 | * in the window between reading the TFH and the subsequent TLB dropin, | ||
291 | * the dropin is ignored. This eliminates the need for additional locks. | ||
292 | */ | ||
293 | |||
294 | /* | ||
295 | * Error if TFH state is IDLE or FMM mode & the user issuing a UPM call. | ||
296 | * Might be a hardware race OR a stupid user. Ignore FMM because FMM | ||
297 | * is a transient state. | ||
298 | */ | ||
299 | if (tfh->state == TFHSTATE_IDLE) | ||
300 | goto failidle; | ||
301 | if (tfh->state == TFHSTATE_MISS_FMM && cb) | ||
302 | goto failfmm; | ||
303 | |||
304 | write = (tfh->cause & TFHCAUSE_TLB_MOD) != 0; | ||
305 | vaddr = tfh->missvaddr; | ||
306 | asid = tfh->missasid; | ||
307 | if (asid == 0) | ||
308 | goto failnoasid; | ||
309 | |||
310 | rmb(); /* TFH must be cache resident before reading ms_range_active */ | ||
311 | |||
312 | /* | ||
313 | * TFH is cache resident - at least briefly. Fail the dropin | ||
314 | * if a range invalidate is active. | ||
315 | */ | ||
316 | if (atomic_read(>s->ts_gms->ms_range_active)) | ||
317 | goto failactive; | ||
318 | |||
319 | vma = find_vma(mm, vaddr); | ||
320 | if (!vma) | ||
321 | goto failinval; | ||
322 | |||
323 | /* | ||
324 | * Atomic lookup is faster & usually works even if called in non-atomic | ||
325 | * context. | ||
326 | */ | ||
327 | ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &pageshift); | ||
328 | if (ret) { | ||
329 | if (!cb) | ||
330 | goto failupm; | ||
331 | if (non_atomic_pte_lookup(vma, vaddr, write, &paddr, | ||
332 | &pageshift)) | ||
333 | goto failinval; | ||
334 | } | ||
335 | if (is_gru_paddr(paddr)) | ||
336 | goto failinval; | ||
337 | |||
338 | paddr = paddr & ~((1UL << pageshift) - 1); | ||
339 | gpa = uv_soc_phys_ram_to_gpa(paddr); | ||
340 | gru_cb_set_istatus_active(cb); | ||
341 | tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write, | ||
342 | GRU_PAGESIZE(pageshift)); | ||
343 | STAT(tlb_dropin); | ||
344 | gru_dbg(grudev, | ||
345 | "%s: tfh 0x%p, vaddr 0x%lx, asid 0x%x, ps %d, gpa 0x%lx\n", | ||
346 | ret ? "non-atomic" : "atomic", tfh, vaddr, asid, | ||
347 | pageshift, gpa); | ||
348 | return 0; | ||
349 | |||
350 | failnoasid: | ||
351 | /* No asid (delayed unload). */ | ||
352 | STAT(tlb_dropin_fail_no_asid); | ||
353 | gru_dbg(grudev, "FAILED no_asid tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); | ||
354 | if (!cb) | ||
355 | tfh_user_polling_mode(tfh); | ||
356 | else | ||
357 | gru_flush_cache(tfh); | ||
358 | return -EAGAIN; | ||
359 | |||
360 | failupm: | ||
361 | /* Atomic failure switch CBR to UPM */ | ||
362 | tfh_user_polling_mode(tfh); | ||
363 | STAT(tlb_dropin_fail_upm); | ||
364 | gru_dbg(grudev, "FAILED upm tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); | ||
365 | return 1; | ||
366 | |||
367 | failfmm: | ||
368 | /* FMM state on UPM call */ | ||
369 | STAT(tlb_dropin_fail_fmm); | ||
370 | gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state); | ||
371 | return 0; | ||
372 | |||
373 | failidle: | ||
374 | /* TFH was idle - no miss pending */ | ||
375 | gru_flush_cache(tfh); | ||
376 | if (cb) | ||
377 | gru_flush_cache(cb); | ||
378 | STAT(tlb_dropin_fail_idle); | ||
379 | gru_dbg(grudev, "FAILED idle tfh: 0x%p, state %d\n", tfh, tfh->state); | ||
380 | return 0; | ||
381 | |||
382 | failinval: | ||
383 | /* All errors (atomic & non-atomic) switch CBR to EXCEPTION state */ | ||
384 | tfh_exception(tfh); | ||
385 | STAT(tlb_dropin_fail_invalid); | ||
386 | gru_dbg(grudev, "FAILED inval tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); | ||
387 | return -EFAULT; | ||
388 | |||
389 | failactive: | ||
390 | /* Range invalidate active. Switch to UPM iff atomic */ | ||
391 | if (!cb) | ||
392 | tfh_user_polling_mode(tfh); | ||
393 | else | ||
394 | gru_flush_cache(tfh); | ||
395 | STAT(tlb_dropin_fail_range_active); | ||
396 | gru_dbg(grudev, "FAILED range active: tfh 0x%p, vaddr 0x%lx\n", | ||
397 | tfh, vaddr); | ||
398 | return 1; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Process an external interrupt from the GRU. This interrupt is | ||
403 | * caused by a TLB miss. | ||
404 | * Note that this is the interrupt handler that is registered with linux | ||
405 | * interrupt handlers. | ||
406 | */ | ||
407 | irqreturn_t gru_intr(int irq, void *dev_id) | ||
408 | { | ||
409 | struct gru_state *gru; | ||
410 | struct gru_tlb_fault_map map; | ||
411 | struct gru_thread_state *gts; | ||
412 | struct gru_tlb_fault_handle *tfh = NULL; | ||
413 | int cbrnum, ctxnum; | ||
414 | |||
415 | STAT(intr); | ||
416 | |||
417 | gru = irq_to_gru(irq); | ||
418 | if (!gru) { | ||
419 | dev_err(grudev, "GRU: invalid interrupt: cpu %d, irq %d\n", | ||
420 | raw_smp_processor_id(), irq); | ||
421 | return IRQ_NONE; | ||
422 | } | ||
423 | get_clear_fault_map(gru, &map); | ||
424 | gru_dbg(grudev, "irq %d, gru %x, map 0x%lx\n", irq, gru->gs_gid, | ||
425 | map.fault_bits[0]); | ||
426 | |||
427 | for_each_cbr_in_tfm(cbrnum, map.fault_bits) { | ||
428 | tfh = get_tfh_by_index(gru, cbrnum); | ||
429 | prefetchw(tfh); /* Helps on hdw, required for emulator */ | ||
430 | |||
431 | /* | ||
432 | * When hardware sets a bit in the faultmap, it implicitly | ||
433 | * locks the GRU context so that it cannot be unloaded. | ||
434 | * The gts cannot change until a TFH start/writestart command | ||
435 | * is issued. | ||
436 | */ | ||
437 | ctxnum = tfh->ctxnum; | ||
438 | gts = gru->gs_gts[ctxnum]; | ||
439 | |||
440 | /* | ||
441 | * This is running in interrupt context. Trylock the mmap_sem. | ||
442 | * If it fails, retry the fault in user context. | ||
443 | */ | ||
444 | if (down_read_trylock(>s->ts_mm->mmap_sem)) { | ||
445 | gru_try_dropin(gts, tfh, NULL); | ||
446 | up_read(>s->ts_mm->mmap_sem); | ||
447 | } else { | ||
448 | tfh_user_polling_mode(tfh); | ||
449 | } | ||
450 | } | ||
451 | return IRQ_HANDLED; | ||
452 | } | ||
453 | |||
454 | |||
455 | static int gru_user_dropin(struct gru_thread_state *gts, | ||
456 | struct gru_tlb_fault_handle *tfh, | ||
457 | unsigned long __user *cb) | ||
458 | { | ||
459 | struct gru_mm_struct *gms = gts->ts_gms; | ||
460 | int ret; | ||
461 | |||
462 | while (1) { | ||
463 | wait_event(gms->ms_wait_queue, | ||
464 | atomic_read(&gms->ms_range_active) == 0); | ||
465 | prefetchw(tfh); /* Helps on hdw, required for emulator */ | ||
466 | ret = gru_try_dropin(gts, tfh, cb); | ||
467 | if (ret <= 0) | ||
468 | return ret; | ||
469 | STAT(call_os_wait_queue); | ||
470 | } | ||
471 | } | ||
472 | |||
473 | /* | ||
474 | * This interface is called as a result of a user detecting a "call OS" bit | ||
475 | * in a user CB. Normally means that a TLB fault has occurred. | ||
476 | * cb - user virtual address of the CB | ||
477 | */ | ||
478 | int gru_handle_user_call_os(unsigned long cb) | ||
479 | { | ||
480 | struct gru_tlb_fault_handle *tfh; | ||
481 | struct gru_thread_state *gts; | ||
482 | unsigned long __user *cbp; | ||
483 | int ucbnum, cbrnum, ret = -EINVAL; | ||
484 | |||
485 | STAT(call_os); | ||
486 | gru_dbg(grudev, "address 0x%lx\n", cb); | ||
487 | |||
488 | /* sanity check the cb pointer */ | ||
489 | ucbnum = get_cb_number((void *)cb); | ||
490 | if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB) | ||
491 | return -EINVAL; | ||
492 | cbp = (unsigned long *)cb; | ||
493 | |||
494 | gts = gru_find_lock_gts(cb); | ||
495 | if (!gts) | ||
496 | return -EINVAL; | ||
497 | |||
498 | if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) { | ||
499 | ret = -EINVAL; | ||
500 | goto exit; | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * If force_unload is set, the UPM TLB fault is phony. The task | ||
505 | * has migrated to another node and the GSEG must be moved. Just | ||
506 | * unload the context. The task will page fault and assign a new | ||
507 | * context. | ||
508 | */ | ||
509 | ret = -EAGAIN; | ||
510 | cbrnum = thread_cbr_number(gts, ucbnum); | ||
511 | if (gts->ts_force_unload) { | ||
512 | gru_unload_context(gts, 1); | ||
513 | } else if (gts->ts_gru) { | ||
514 | tfh = get_tfh_by_index(gts->ts_gru, cbrnum); | ||
515 | ret = gru_user_dropin(gts, tfh, cbp); | ||
516 | } | ||
517 | exit: | ||
518 | gru_unlock_gts(gts); | ||
519 | return ret; | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * Fetch the exception detail information for a CB that terminated with | ||
524 | * an exception. | ||
525 | */ | ||
526 | int gru_get_exception_detail(unsigned long arg) | ||
527 | { | ||
528 | struct control_block_extended_exc_detail excdet; | ||
529 | struct gru_control_block_extended *cbe; | ||
530 | struct gru_thread_state *gts; | ||
531 | int ucbnum, cbrnum, ret; | ||
532 | |||
533 | STAT(user_exception); | ||
534 | if (copy_from_user(&excdet, (void __user *)arg, sizeof(excdet))) | ||
535 | return -EFAULT; | ||
536 | |||
537 | gru_dbg(grudev, "address 0x%lx\n", excdet.cb); | ||
538 | gts = gru_find_lock_gts(excdet.cb); | ||
539 | if (!gts) | ||
540 | return -EINVAL; | ||
541 | |||
542 | if (gts->ts_gru) { | ||
543 | ucbnum = get_cb_number((void *)excdet.cb); | ||
544 | cbrnum = thread_cbr_number(gts, ucbnum); | ||
545 | cbe = get_cbe_by_index(gts->ts_gru, cbrnum); | ||
546 | excdet.opc = cbe->opccpy; | ||
547 | excdet.exopc = cbe->exopccpy; | ||
548 | excdet.ecause = cbe->ecause; | ||
549 | excdet.exceptdet0 = cbe->idef1upd; | ||
550 | excdet.exceptdet1 = cbe->idef3upd; | ||
551 | ret = 0; | ||
552 | } else { | ||
553 | ret = -EAGAIN; | ||
554 | } | ||
555 | gru_unlock_gts(gts); | ||
556 | |||
557 | gru_dbg(grudev, "address 0x%lx, ecause 0x%x\n", excdet.cb, | ||
558 | excdet.ecause); | ||
559 | if (!ret && copy_to_user((void __user *)arg, &excdet, sizeof(excdet))) | ||
560 | ret = -EFAULT; | ||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * User request to unload a context. Content is saved for possible reload. | ||
566 | */ | ||
567 | int gru_user_unload_context(unsigned long arg) | ||
568 | { | ||
569 | struct gru_thread_state *gts; | ||
570 | struct gru_unload_context_req req; | ||
571 | |||
572 | STAT(user_unload_context); | ||
573 | if (copy_from_user(&req, (void __user *)arg, sizeof(req))) | ||
574 | return -EFAULT; | ||
575 | |||
576 | gru_dbg(grudev, "gseg 0x%lx\n", req.gseg); | ||
577 | |||
578 | gts = gru_find_lock_gts(req.gseg); | ||
579 | if (!gts) | ||
580 | return -EINVAL; | ||
581 | |||
582 | if (gts->ts_gru) | ||
583 | gru_unload_context(gts, 1); | ||
584 | gru_unlock_gts(gts); | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | /* | ||
590 | * User request to flush a range of virtual addresses from the GRU TLB | ||
591 | * (Mainly for testing). | ||
592 | */ | ||
593 | int gru_user_flush_tlb(unsigned long arg) | ||
594 | { | ||
595 | struct gru_thread_state *gts; | ||
596 | struct gru_flush_tlb_req req; | ||
597 | |||
598 | STAT(user_flush_tlb); | ||
599 | if (copy_from_user(&req, (void __user *)arg, sizeof(req))) | ||
600 | return -EFAULT; | ||
601 | |||
602 | gru_dbg(grudev, "gseg 0x%lx, vaddr 0x%lx, len 0x%lx\n", req.gseg, | ||
603 | req.vaddr, req.len); | ||
604 | |||
605 | gts = gru_find_lock_gts(req.gseg); | ||
606 | if (!gts) | ||
607 | return -EINVAL; | ||
608 | |||
609 | gru_flush_tlb_range(gts->ts_gms, req.vaddr, req.vaddr + req.len); | ||
610 | gru_unlock_gts(gts); | ||
611 | |||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | /* | ||
616 | * Register the current task as the user of the GSEG slice. | ||
617 | * Needed for TLB fault interrupt targeting. | ||
618 | */ | ||
619 | int gru_set_task_slice(long address) | ||
620 | { | ||
621 | struct gru_thread_state *gts; | ||
622 | |||
623 | STAT(set_task_slice); | ||
624 | gru_dbg(grudev, "address 0x%lx\n", address); | ||
625 | gts = gru_alloc_locked_gts(address); | ||
626 | if (!gts) | ||
627 | return -EINVAL; | ||
628 | |||
629 | gts->ts_tgid_owner = current->tgid; | ||
630 | gru_unlock_gts(gts); | ||
631 | |||
632 | return 0; | ||
633 | } | ||
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c new file mode 100644 index 000000000000..23c91f5f6b61 --- /dev/null +++ b/drivers/misc/sgi-gru/grufile.c | |||
@@ -0,0 +1,485 @@ | |||
1 | /* | ||
2 | * SN Platform GRU Driver | ||
3 | * | ||
4 | * FILE OPERATIONS & DRIVER INITIALIZATION | ||
5 | * | ||
6 | * This file supports the user system call for file open, close, mmap, etc. | ||
7 | * This also incudes the driver initialization code. | ||
8 | * | ||
9 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/io.h> | ||
32 | #include <linux/smp_lock.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/device.h> | ||
35 | #include <linux/miscdevice.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/proc_fs.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | #include "gru.h" | ||
40 | #include "grulib.h" | ||
41 | #include "grutables.h" | ||
42 | |||
43 | #if defined CONFIG_X86_64 | ||
44 | #include <asm/genapic.h> | ||
45 | #include <asm/irq.h> | ||
46 | #define IS_UV() is_uv_system() | ||
47 | #elif defined CONFIG_IA64 | ||
48 | #include <asm/system.h> | ||
49 | #include <asm/sn/simulator.h> | ||
50 | /* temp support for running on hardware simulator */ | ||
51 | #define IS_UV() IS_MEDUSA() || ia64_platform_is("uv") | ||
52 | #else | ||
53 | #define IS_UV() 0 | ||
54 | #endif | ||
55 | |||
56 | #include <asm/uv/uv_hub.h> | ||
57 | #include <asm/uv/uv_mmrs.h> | ||
58 | |||
59 | struct gru_blade_state *gru_base[GRU_MAX_BLADES] __read_mostly; | ||
60 | unsigned long gru_start_paddr, gru_end_paddr __read_mostly; | ||
61 | struct gru_stats_s gru_stats; | ||
62 | |||
63 | /* Guaranteed user available resources on each node */ | ||
64 | static int max_user_cbrs, max_user_dsr_bytes; | ||
65 | |||
66 | static struct file_operations gru_fops; | ||
67 | static struct miscdevice gru_miscdev; | ||
68 | |||
69 | |||
70 | /* | ||
71 | * gru_vma_close | ||
72 | * | ||
73 | * Called when unmapping a device mapping. Frees all gru resources | ||
74 | * and tables belonging to the vma. | ||
75 | */ | ||
76 | static void gru_vma_close(struct vm_area_struct *vma) | ||
77 | { | ||
78 | struct gru_vma_data *vdata; | ||
79 | struct gru_thread_state *gts; | ||
80 | struct list_head *entry, *next; | ||
81 | |||
82 | if (!vma->vm_private_data) | ||
83 | return; | ||
84 | |||
85 | vdata = vma->vm_private_data; | ||
86 | vma->vm_private_data = NULL; | ||
87 | gru_dbg(grudev, "vma %p, file %p, vdata %p\n", vma, vma->vm_file, | ||
88 | vdata); | ||
89 | list_for_each_safe(entry, next, &vdata->vd_head) { | ||
90 | gts = | ||
91 | list_entry(entry, struct gru_thread_state, ts_next); | ||
92 | list_del(>s->ts_next); | ||
93 | mutex_lock(>s->ts_ctxlock); | ||
94 | if (gts->ts_gru) | ||
95 | gru_unload_context(gts, 0); | ||
96 | mutex_unlock(>s->ts_ctxlock); | ||
97 | gts_drop(gts); | ||
98 | } | ||
99 | kfree(vdata); | ||
100 | STAT(vdata_free); | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * gru_file_mmap | ||
105 | * | ||
106 | * Called when mmaping the device. Initializes the vma with a fault handler | ||
107 | * and private data structure necessary to allocate, track, and free the | ||
108 | * underlying pages. | ||
109 | */ | ||
110 | static int gru_file_mmap(struct file *file, struct vm_area_struct *vma) | ||
111 | { | ||
112 | if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) != (VM_SHARED | VM_WRITE)) | ||
113 | return -EPERM; | ||
114 | |||
115 | if (vma->vm_start & (GRU_GSEG_PAGESIZE - 1) || | ||
116 | vma->vm_end & (GRU_GSEG_PAGESIZE - 1)) | ||
117 | return -EINVAL; | ||
118 | |||
119 | vma->vm_flags |= | ||
120 | (VM_IO | VM_DONTCOPY | VM_LOCKED | VM_DONTEXPAND | VM_PFNMAP | | ||
121 | VM_RESERVED); | ||
122 | vma->vm_page_prot = PAGE_SHARED; | ||
123 | vma->vm_ops = &gru_vm_ops; | ||
124 | |||
125 | vma->vm_private_data = gru_alloc_vma_data(vma, 0); | ||
126 | if (!vma->vm_private_data) | ||
127 | return -ENOMEM; | ||
128 | |||
129 | gru_dbg(grudev, "file %p, vaddr 0x%lx, vma %p, vdata %p\n", | ||
130 | file, vma->vm_start, vma, vma->vm_private_data); | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * Create a new GRU context | ||
136 | */ | ||
137 | static int gru_create_new_context(unsigned long arg) | ||
138 | { | ||
139 | struct gru_create_context_req req; | ||
140 | struct vm_area_struct *vma; | ||
141 | struct gru_vma_data *vdata; | ||
142 | int ret = -EINVAL; | ||
143 | |||
144 | |||
145 | if (copy_from_user(&req, (void __user *)arg, sizeof(req))) | ||
146 | return -EFAULT; | ||
147 | |||
148 | if (req.data_segment_bytes == 0 || | ||
149 | req.data_segment_bytes > max_user_dsr_bytes) | ||
150 | return -EINVAL; | ||
151 | if (!req.control_blocks || !req.maximum_thread_count || | ||
152 | req.control_blocks > max_user_cbrs) | ||
153 | return -EINVAL; | ||
154 | |||
155 | if (!(req.options & GRU_OPT_MISS_MASK)) | ||
156 | req.options |= GRU_OPT_MISS_FMM_INTR; | ||
157 | |||
158 | down_write(¤t->mm->mmap_sem); | ||
159 | vma = gru_find_vma(req.gseg); | ||
160 | if (vma) { | ||
161 | vdata = vma->vm_private_data; | ||
162 | vdata->vd_user_options = req.options; | ||
163 | vdata->vd_dsr_au_count = | ||
164 | GRU_DS_BYTES_TO_AU(req.data_segment_bytes); | ||
165 | vdata->vd_cbr_au_count = GRU_CB_COUNT_TO_AU(req.control_blocks); | ||
166 | ret = 0; | ||
167 | } | ||
168 | up_write(¤t->mm->mmap_sem); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Get GRU configuration info (temp - for emulator testing) | ||
175 | */ | ||
176 | static long gru_get_config_info(unsigned long arg) | ||
177 | { | ||
178 | struct gru_config_info info; | ||
179 | int nodesperblade; | ||
180 | |||
181 | if (num_online_nodes() > 1 && | ||
182 | (uv_node_to_blade_id(1) == uv_node_to_blade_id(0))) | ||
183 | nodesperblade = 2; | ||
184 | else | ||
185 | nodesperblade = 1; | ||
186 | info.cpus = num_online_cpus(); | ||
187 | info.nodes = num_online_nodes(); | ||
188 | info.blades = info.nodes / nodesperblade; | ||
189 | info.chiplets = GRU_CHIPLETS_PER_BLADE * info.blades; | ||
190 | |||
191 | if (copy_to_user((void __user *)arg, &info, sizeof(info))) | ||
192 | return -EFAULT; | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * Get GRU chiplet status | ||
198 | */ | ||
199 | static long gru_get_chiplet_status(unsigned long arg) | ||
200 | { | ||
201 | struct gru_state *gru; | ||
202 | struct gru_chiplet_info info; | ||
203 | |||
204 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) | ||
205 | return -EFAULT; | ||
206 | |||
207 | if (info.node == -1) | ||
208 | info.node = numa_node_id(); | ||
209 | if (info.node >= num_possible_nodes() || | ||
210 | info.chiplet >= GRU_CHIPLETS_PER_HUB || | ||
211 | info.node < 0 || info.chiplet < 0) | ||
212 | return -EINVAL; | ||
213 | |||
214 | info.blade = uv_node_to_blade_id(info.node); | ||
215 | gru = get_gru(info.blade, info.chiplet); | ||
216 | |||
217 | info.total_dsr_bytes = GRU_NUM_DSR_BYTES; | ||
218 | info.total_cbr = GRU_NUM_CB; | ||
219 | info.total_user_dsr_bytes = GRU_NUM_DSR_BYTES - | ||
220 | gru->gs_reserved_dsr_bytes; | ||
221 | info.total_user_cbr = GRU_NUM_CB - gru->gs_reserved_cbrs; | ||
222 | info.free_user_dsr_bytes = hweight64(gru->gs_dsr_map) * | ||
223 | GRU_DSR_AU_BYTES; | ||
224 | info.free_user_cbr = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; | ||
225 | |||
226 | if (copy_to_user((void __user *)arg, &info, sizeof(info))) | ||
227 | return -EFAULT; | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * gru_file_unlocked_ioctl | ||
233 | * | ||
234 | * Called to update file attributes via IOCTL calls. | ||
235 | */ | ||
236 | static long gru_file_unlocked_ioctl(struct file *file, unsigned int req, | ||
237 | unsigned long arg) | ||
238 | { | ||
239 | int err = -EBADRQC; | ||
240 | |||
241 | gru_dbg(grudev, "file %p\n", file); | ||
242 | |||
243 | switch (req) { | ||
244 | case GRU_CREATE_CONTEXT: | ||
245 | err = gru_create_new_context(arg); | ||
246 | break; | ||
247 | case GRU_SET_TASK_SLICE: | ||
248 | err = gru_set_task_slice(arg); | ||
249 | break; | ||
250 | case GRU_USER_GET_EXCEPTION_DETAIL: | ||
251 | err = gru_get_exception_detail(arg); | ||
252 | break; | ||
253 | case GRU_USER_UNLOAD_CONTEXT: | ||
254 | err = gru_user_unload_context(arg); | ||
255 | break; | ||
256 | case GRU_GET_CHIPLET_STATUS: | ||
257 | err = gru_get_chiplet_status(arg); | ||
258 | break; | ||
259 | case GRU_USER_FLUSH_TLB: | ||
260 | err = gru_user_flush_tlb(arg); | ||
261 | break; | ||
262 | case GRU_USER_CALL_OS: | ||
263 | err = gru_handle_user_call_os(arg); | ||
264 | break; | ||
265 | case GRU_GET_CONFIG_INFO: | ||
266 | err = gru_get_config_info(arg); | ||
267 | break; | ||
268 | } | ||
269 | return err; | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Called at init time to build tables for all GRUs that are present in the | ||
274 | * system. | ||
275 | */ | ||
276 | static void gru_init_chiplet(struct gru_state *gru, unsigned long paddr, | ||
277 | void *vaddr, int nid, int bid, int grunum) | ||
278 | { | ||
279 | spin_lock_init(&gru->gs_lock); | ||
280 | spin_lock_init(&gru->gs_asid_lock); | ||
281 | gru->gs_gru_base_paddr = paddr; | ||
282 | gru->gs_gru_base_vaddr = vaddr; | ||
283 | gru->gs_gid = bid * GRU_CHIPLETS_PER_BLADE + grunum; | ||
284 | gru->gs_blade = gru_base[bid]; | ||
285 | gru->gs_blade_id = bid; | ||
286 | gru->gs_cbr_map = (GRU_CBR_AU == 64) ? ~0 : (1UL << GRU_CBR_AU) - 1; | ||
287 | gru->gs_dsr_map = (1UL << GRU_DSR_AU) - 1; | ||
288 | gru_tgh_flush_init(gru); | ||
289 | gru_dbg(grudev, "bid %d, nid %d, gru %x, vaddr %p (0x%lx)\n", | ||
290 | bid, nid, gru->gs_gid, gru->gs_gru_base_vaddr, | ||
291 | gru->gs_gru_base_paddr); | ||
292 | gru_kservices_init(gru); | ||
293 | } | ||
294 | |||
295 | static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) | ||
296 | { | ||
297 | int pnode, nid, bid, chip; | ||
298 | int cbrs, dsrbytes, n; | ||
299 | int order = get_order(sizeof(struct gru_blade_state)); | ||
300 | struct page *page; | ||
301 | struct gru_state *gru; | ||
302 | unsigned long paddr; | ||
303 | void *vaddr; | ||
304 | |||
305 | max_user_cbrs = GRU_NUM_CB; | ||
306 | max_user_dsr_bytes = GRU_NUM_DSR_BYTES; | ||
307 | for_each_online_node(nid) { | ||
308 | bid = uv_node_to_blade_id(nid); | ||
309 | pnode = uv_node_to_pnode(nid); | ||
310 | if (gru_base[bid]) | ||
311 | continue; | ||
312 | page = alloc_pages_node(nid, GFP_KERNEL, order); | ||
313 | if (!page) | ||
314 | goto fail; | ||
315 | gru_base[bid] = page_address(page); | ||
316 | memset(gru_base[bid], 0, sizeof(struct gru_blade_state)); | ||
317 | gru_base[bid]->bs_lru_gru = &gru_base[bid]->bs_grus[0]; | ||
318 | spin_lock_init(&gru_base[bid]->bs_lock); | ||
319 | |||
320 | dsrbytes = 0; | ||
321 | cbrs = 0; | ||
322 | for (gru = gru_base[bid]->bs_grus, chip = 0; | ||
323 | chip < GRU_CHIPLETS_PER_BLADE; | ||
324 | chip++, gru++) { | ||
325 | paddr = gru_chiplet_paddr(gru_base_paddr, pnode, chip); | ||
326 | vaddr = gru_chiplet_vaddr(gru_base_vaddr, pnode, chip); | ||
327 | gru_init_chiplet(gru, paddr, vaddr, bid, nid, chip); | ||
328 | n = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; | ||
329 | cbrs = max(cbrs, n); | ||
330 | n = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES; | ||
331 | dsrbytes = max(dsrbytes, n); | ||
332 | } | ||
333 | max_user_cbrs = min(max_user_cbrs, cbrs); | ||
334 | max_user_dsr_bytes = min(max_user_dsr_bytes, dsrbytes); | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | |||
339 | fail: | ||
340 | for (nid--; nid >= 0; nid--) | ||
341 | free_pages((unsigned long)gru_base[nid], order); | ||
342 | return -ENOMEM; | ||
343 | } | ||
344 | |||
345 | #ifdef CONFIG_IA64 | ||
346 | |||
347 | static int get_base_irq(void) | ||
348 | { | ||
349 | return IRQ_GRU; | ||
350 | } | ||
351 | |||
352 | #elif defined CONFIG_X86_64 | ||
353 | |||
354 | static void noop(unsigned int irq) | ||
355 | { | ||
356 | } | ||
357 | |||
358 | static struct irq_chip gru_chip = { | ||
359 | .name = "gru", | ||
360 | .mask = noop, | ||
361 | .unmask = noop, | ||
362 | .ack = noop, | ||
363 | }; | ||
364 | |||
365 | static int get_base_irq(void) | ||
366 | { | ||
367 | set_irq_chip(IRQ_GRU, &gru_chip); | ||
368 | set_irq_chip(IRQ_GRU + 1, &gru_chip); | ||
369 | return IRQ_GRU; | ||
370 | } | ||
371 | #endif | ||
372 | |||
373 | /* | ||
374 | * gru_init | ||
375 | * | ||
376 | * Called at boot or module load time to initialize the GRUs. | ||
377 | */ | ||
378 | static int __init gru_init(void) | ||
379 | { | ||
380 | int ret, irq, chip; | ||
381 | char id[10]; | ||
382 | void *gru_start_vaddr; | ||
383 | |||
384 | if (!IS_UV()) | ||
385 | return 0; | ||
386 | |||
387 | #if defined CONFIG_IA64 | ||
388 | gru_start_paddr = 0xd000000000UL; /* ZZZZZZZZZZZZZZZZZZZ fixme */ | ||
389 | #else | ||
390 | gru_start_paddr = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR) & | ||
391 | 0x7fffffffffffUL; | ||
392 | |||
393 | #endif | ||
394 | gru_start_vaddr = __va(gru_start_paddr); | ||
395 | gru_end_paddr = gru_start_paddr + MAX_NUMNODES * GRU_SIZE; | ||
396 | printk(KERN_INFO "GRU space: 0x%lx - 0x%lx\n", | ||
397 | gru_start_paddr, gru_end_paddr); | ||
398 | irq = get_base_irq(); | ||
399 | for (chip = 0; chip < GRU_CHIPLETS_PER_BLADE; chip++) { | ||
400 | ret = request_irq(irq + chip, gru_intr, 0, id, NULL); | ||
401 | if (ret) { | ||
402 | printk(KERN_ERR "%s: request_irq failed\n", | ||
403 | GRU_DRIVER_ID_STR); | ||
404 | goto exit1; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | ret = misc_register(&gru_miscdev); | ||
409 | if (ret) { | ||
410 | printk(KERN_ERR "%s: misc_register failed\n", | ||
411 | GRU_DRIVER_ID_STR); | ||
412 | goto exit1; | ||
413 | } | ||
414 | |||
415 | ret = gru_proc_init(); | ||
416 | if (ret) { | ||
417 | printk(KERN_ERR "%s: proc init failed\n", GRU_DRIVER_ID_STR); | ||
418 | goto exit2; | ||
419 | } | ||
420 | |||
421 | ret = gru_init_tables(gru_start_paddr, gru_start_vaddr); | ||
422 | if (ret) { | ||
423 | printk(KERN_ERR "%s: init tables failed\n", GRU_DRIVER_ID_STR); | ||
424 | goto exit3; | ||
425 | } | ||
426 | |||
427 | printk(KERN_INFO "%s: v%s\n", GRU_DRIVER_ID_STR, | ||
428 | GRU_DRIVER_VERSION_STR); | ||
429 | return 0; | ||
430 | |||
431 | exit3: | ||
432 | gru_proc_exit(); | ||
433 | exit2: | ||
434 | misc_deregister(&gru_miscdev); | ||
435 | exit1: | ||
436 | for (--chip; chip >= 0; chip--) | ||
437 | free_irq(irq + chip, NULL); | ||
438 | return ret; | ||
439 | |||
440 | } | ||
441 | |||
442 | static void __exit gru_exit(void) | ||
443 | { | ||
444 | int i, bid; | ||
445 | int order = get_order(sizeof(struct gru_state) * | ||
446 | GRU_CHIPLETS_PER_BLADE); | ||
447 | |||
448 | for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++) | ||
449 | free_irq(IRQ_GRU + i, NULL); | ||
450 | |||
451 | for (bid = 0; bid < GRU_MAX_BLADES; bid++) | ||
452 | free_pages((unsigned long)gru_base[bid], order); | ||
453 | |||
454 | misc_deregister(&gru_miscdev); | ||
455 | gru_proc_exit(); | ||
456 | } | ||
457 | |||
458 | static struct file_operations gru_fops = { | ||
459 | .owner = THIS_MODULE, | ||
460 | .unlocked_ioctl = gru_file_unlocked_ioctl, | ||
461 | .mmap = gru_file_mmap, | ||
462 | }; | ||
463 | |||
464 | static struct miscdevice gru_miscdev = { | ||
465 | .minor = MISC_DYNAMIC_MINOR, | ||
466 | .name = "gru", | ||
467 | .fops = &gru_fops, | ||
468 | }; | ||
469 | |||
470 | struct vm_operations_struct gru_vm_ops = { | ||
471 | .close = gru_vma_close, | ||
472 | .fault = gru_fault, | ||
473 | }; | ||
474 | |||
475 | module_init(gru_init); | ||
476 | module_exit(gru_exit); | ||
477 | |||
478 | module_param(gru_options, ulong, 0644); | ||
479 | MODULE_PARM_DESC(gru_options, "Various debug options"); | ||
480 | |||
481 | MODULE_AUTHOR("Silicon Graphics, Inc."); | ||
482 | MODULE_LICENSE("GPL"); | ||
483 | MODULE_DESCRIPTION(GRU_DRIVER_ID_STR GRU_DRIVER_VERSION_STR); | ||
484 | MODULE_VERSION(GRU_DRIVER_VERSION_STR); | ||
485 | |||
diff --git a/drivers/misc/sgi-gru/gruhandles.h b/drivers/misc/sgi-gru/gruhandles.h new file mode 100644 index 000000000000..d16031d62673 --- /dev/null +++ b/drivers/misc/sgi-gru/gruhandles.h | |||
@@ -0,0 +1,663 @@ | |||
1 | /* | ||
2 | * SN Platform GRU Driver | ||
3 | * | ||
4 | * GRU HANDLE DEFINITION | ||
5 | * | ||
6 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #ifndef __GRUHANDLES_H__ | ||
24 | #define __GRUHANDLES_H__ | ||
25 | #include "gru_instructions.h" | ||
26 | |||
27 | /* | ||
28 | * Manifest constants for GRU Memory Map | ||
29 | */ | ||
30 | #define GRU_GSEG0_BASE 0 | ||
31 | #define GRU_MCS_BASE (64 * 1024 * 1024) | ||
32 | #define GRU_SIZE (128UL * 1024 * 1024) | ||
33 | |||
34 | /* Handle & resource counts */ | ||
35 | #define GRU_NUM_CB 128 | ||
36 | #define GRU_NUM_DSR_BYTES (32 * 1024) | ||
37 | #define GRU_NUM_TFM 16 | ||
38 | #define GRU_NUM_TGH 24 | ||
39 | #define GRU_NUM_CBE 128 | ||
40 | #define GRU_NUM_TFH 128 | ||
41 | #define GRU_NUM_CCH 16 | ||
42 | #define GRU_NUM_GSH 1 | ||
43 | |||
44 | /* Maximum resource counts that can be reserved by user programs */ | ||
45 | #define GRU_NUM_USER_CBR GRU_NUM_CBE | ||
46 | #define GRU_NUM_USER_DSR_BYTES GRU_NUM_DSR_BYTES | ||
47 | |||
48 | /* Bytes per handle & handle stride. Code assumes all cb, tfh, cbe handles | ||
49 | * are the same */ | ||
50 | #define GRU_HANDLE_BYTES 64 | ||
51 | #define GRU_HANDLE_STRIDE 256 | ||
52 | |||
53 | /* Base addresses of handles */ | ||
54 | #define GRU_TFM_BASE (GRU_MCS_BASE + 0x00000) | ||
55 | #define GRU_TGH_BASE (GRU_MCS_BASE + 0x08000) | ||
56 | #define GRU_CBE_BASE (GRU_MCS_BASE + 0x10000) | ||
57 | #define GRU_TFH_BASE (GRU_MCS_BASE + 0x18000) | ||
58 | #define GRU_CCH_BASE (GRU_MCS_BASE + 0x20000) | ||
59 | #define GRU_GSH_BASE (GRU_MCS_BASE + 0x30000) | ||
60 | |||
61 | /* User gseg constants */ | ||
62 | #define GRU_GSEG_STRIDE (4 * 1024 * 1024) | ||
63 | #define GSEG_BASE(a) ((a) & ~(GRU_GSEG_PAGESIZE - 1)) | ||
64 | |||
65 | /* Data segment constants */ | ||
66 | #define GRU_DSR_AU_BYTES 1024 | ||
67 | #define GRU_DSR_CL (GRU_NUM_DSR_BYTES / GRU_CACHE_LINE_BYTES) | ||
68 | #define GRU_DSR_AU_CL (GRU_DSR_AU_BYTES / GRU_CACHE_LINE_BYTES) | ||
69 | #define GRU_DSR_AU (GRU_NUM_DSR_BYTES / GRU_DSR_AU_BYTES) | ||
70 | |||
71 | /* Control block constants */ | ||
72 | #define GRU_CBR_AU_SIZE 2 | ||
73 | #define GRU_CBR_AU (GRU_NUM_CBE / GRU_CBR_AU_SIZE) | ||
74 | |||
75 | /* Convert resource counts to the number of AU */ | ||
76 | #define GRU_DS_BYTES_TO_AU(n) DIV_ROUND_UP(n, GRU_DSR_AU_BYTES) | ||
77 | #define GRU_CB_COUNT_TO_AU(n) DIV_ROUND_UP(n, GRU_CBR_AU_SIZE) | ||
78 | |||
79 | /* UV limits */ | ||
80 | #define GRU_CHIPLETS_PER_HUB 2 | ||
81 | #define GRU_HUBS_PER_BLADE 1 | ||
82 | #define GRU_CHIPLETS_PER_BLADE (GRU_HUBS_PER_BLADE * GRU_CHIPLETS_PER_HUB) | ||
83 | |||
84 | /* User GRU Gseg offsets */ | ||
85 | #define GRU_CB_BASE 0 | ||
86 | #define GRU_CB_LIMIT (GRU_CB_BASE + GRU_HANDLE_STRIDE * GRU_NUM_CBE) | ||
87 | #define GRU_DS_BASE 0x20000 | ||
88 | #define GRU_DS_LIMIT (GRU_DS_BASE + GRU_NUM_DSR_BYTES) | ||
89 | |||
90 | /* Convert a GRU physical address to the chiplet offset */ | ||
91 | #define GSEGPOFF(h) ((h) & (GRU_SIZE - 1)) | ||
92 | |||
93 | /* Convert an arbitrary handle address to the beginning of the GRU segment */ | ||
94 | #ifndef __PLUGIN__ | ||
95 | #define GRUBASE(h) ((void *)((unsigned long)(h) & ~(GRU_SIZE - 1))) | ||
96 | #else | ||
97 | extern void *gmu_grubase(void *h); | ||
98 | #define GRUBASE(h) gmu_grubase(h) | ||
99 | #endif | ||
100 | |||
101 | /* General addressing macros. */ | ||
102 | static inline void *get_gseg_base_address(void *base, int ctxnum) | ||
103 | { | ||
104 | return (void *)(base + GRU_GSEG0_BASE + GRU_GSEG_STRIDE * ctxnum); | ||
105 | } | ||
106 | |||
107 | static inline void *get_gseg_base_address_cb(void *base, int ctxnum, int line) | ||
108 | { | ||
109 | return (void *)(get_gseg_base_address(base, ctxnum) + | ||
110 | GRU_CB_BASE + GRU_HANDLE_STRIDE * line); | ||
111 | } | ||
112 | |||
113 | static inline void *get_gseg_base_address_ds(void *base, int ctxnum, int line) | ||
114 | { | ||
115 | return (void *)(get_gseg_base_address(base, ctxnum) + GRU_DS_BASE + | ||
116 | GRU_CACHE_LINE_BYTES * line); | ||
117 | } | ||
118 | |||
119 | static inline struct gru_tlb_fault_map *get_tfm(void *base, int ctxnum) | ||
120 | { | ||
121 | return (struct gru_tlb_fault_map *)(base + GRU_TFM_BASE + | ||
122 | ctxnum * GRU_HANDLE_STRIDE); | ||
123 | } | ||
124 | |||
125 | static inline struct gru_tlb_global_handle *get_tgh(void *base, int ctxnum) | ||
126 | { | ||
127 | return (struct gru_tlb_global_handle *)(base + GRU_TGH_BASE + | ||
128 | ctxnum * GRU_HANDLE_STRIDE); | ||
129 | } | ||
130 | |||
131 | static inline struct gru_control_block_extended *get_cbe(void *base, int ctxnum) | ||
132 | { | ||
133 | return (struct gru_control_block_extended *)(base + GRU_CBE_BASE + | ||
134 | ctxnum * GRU_HANDLE_STRIDE); | ||
135 | } | ||
136 | |||
137 | static inline struct gru_tlb_fault_handle *get_tfh(void *base, int ctxnum) | ||
138 | { | ||
139 | return (struct gru_tlb_fault_handle *)(base + GRU_TFH_BASE + | ||
140 | ctxnum * GRU_HANDLE_STRIDE); | ||
141 | } | ||
142 | |||
143 | static inline struct gru_context_configuration_handle *get_cch(void *base, | ||
144 | int ctxnum) | ||
145 | { | ||
146 | return (struct gru_context_configuration_handle *)(base + | ||
147 | GRU_CCH_BASE + ctxnum * GRU_HANDLE_STRIDE); | ||
148 | } | ||
149 | |||
150 | static inline unsigned long get_cb_number(void *cb) | ||
151 | { | ||
152 | return (((unsigned long)cb - GRU_CB_BASE) % GRU_GSEG_PAGESIZE) / | ||
153 | GRU_HANDLE_STRIDE; | ||
154 | } | ||
155 | |||
156 | /* byte offset to a specific GRU chiplet. (p=pnode, c=chiplet (0 or 1)*/ | ||
157 | static inline unsigned long gru_chiplet_paddr(unsigned long paddr, int pnode, | ||
158 | int chiplet) | ||
159 | { | ||
160 | return paddr + GRU_SIZE * (2 * pnode + chiplet); | ||
161 | } | ||
162 | |||
163 | static inline void *gru_chiplet_vaddr(void *vaddr, int pnode, int chiplet) | ||
164 | { | ||
165 | return vaddr + GRU_SIZE * (2 * pnode + chiplet); | ||
166 | } | ||
167 | |||
168 | |||
169 | |||
170 | /* | ||
171 | * Global TLB Fault Map | ||
172 | * Bitmap of outstanding TLB misses needing interrupt/polling service. | ||
173 | * | ||
174 | */ | ||
175 | struct gru_tlb_fault_map { | ||
176 | unsigned long fault_bits[BITS_TO_LONGS(GRU_NUM_CBE)]; | ||
177 | unsigned long fill0[2]; | ||
178 | unsigned long done_bits[BITS_TO_LONGS(GRU_NUM_CBE)]; | ||
179 | unsigned long fill1[2]; | ||
180 | }; | ||
181 | |||
182 | /* | ||
183 | * TGH - TLB Global Handle | ||
184 | * Used for TLB flushing. | ||
185 | * | ||
186 | */ | ||
187 | struct gru_tlb_global_handle { | ||
188 | unsigned int cmd:1; /* DW 0 */ | ||
189 | unsigned int delresp:1; | ||
190 | unsigned int opc:1; | ||
191 | unsigned int fill1:5; | ||
192 | |||
193 | unsigned int fill2:8; | ||
194 | |||
195 | unsigned int status:2; | ||
196 | unsigned long fill3:2; | ||
197 | unsigned int state:3; | ||
198 | unsigned long fill4:1; | ||
199 | |||
200 | unsigned int cause:3; | ||
201 | unsigned long fill5:37; | ||
202 | |||
203 | unsigned long vaddr:64; /* DW 1 */ | ||
204 | |||
205 | unsigned int asid:24; /* DW 2 */ | ||
206 | unsigned int fill6:8; | ||
207 | |||
208 | unsigned int pagesize:5; | ||
209 | unsigned int fill7:11; | ||
210 | |||
211 | unsigned int global:1; | ||
212 | unsigned int fill8:15; | ||
213 | |||
214 | unsigned long vaddrmask:39; /* DW 3 */ | ||
215 | unsigned int fill9:9; | ||
216 | unsigned int n:10; | ||
217 | unsigned int fill10:6; | ||
218 | |||
219 | unsigned int ctxbitmap:16; /* DW4 */ | ||
220 | unsigned long fill11[3]; | ||
221 | }; | ||
222 | |||
223 | enum gru_tgh_cmd { | ||
224 | TGHCMD_START | ||
225 | }; | ||
226 | |||
227 | enum gru_tgh_opc { | ||
228 | TGHOP_TLBNOP, | ||
229 | TGHOP_TLBINV | ||
230 | }; | ||
231 | |||
232 | enum gru_tgh_status { | ||
233 | TGHSTATUS_IDLE, | ||
234 | TGHSTATUS_EXCEPTION, | ||
235 | TGHSTATUS_ACTIVE | ||
236 | }; | ||
237 | |||
238 | enum gru_tgh_state { | ||
239 | TGHSTATE_IDLE, | ||
240 | TGHSTATE_PE_INVAL, | ||
241 | TGHSTATE_INTERRUPT_INVAL, | ||
242 | TGHSTATE_WAITDONE, | ||
243 | TGHSTATE_RESTART_CTX, | ||
244 | }; | ||
245 | |||
246 | /* | ||
247 | * TFH - TLB Global Handle | ||
248 | * Used for TLB dropins into the GRU TLB. | ||
249 | * | ||
250 | */ | ||
251 | struct gru_tlb_fault_handle { | ||
252 | unsigned int cmd:1; /* DW 0 - low 32*/ | ||
253 | unsigned int delresp:1; | ||
254 | unsigned int fill0:2; | ||
255 | unsigned int opc:3; | ||
256 | unsigned int fill1:9; | ||
257 | |||
258 | unsigned int status:2; | ||
259 | unsigned int fill2:1; | ||
260 | unsigned int color:1; | ||
261 | unsigned int state:3; | ||
262 | unsigned int fill3:1; | ||
263 | |||
264 | unsigned int cause:7; /* DW 0 - high 32 */ | ||
265 | unsigned int fill4:1; | ||
266 | |||
267 | unsigned int indexway:12; | ||
268 | unsigned int fill5:4; | ||
269 | |||
270 | unsigned int ctxnum:4; | ||
271 | unsigned int fill6:12; | ||
272 | |||
273 | unsigned long missvaddr:64; /* DW 1 */ | ||
274 | |||
275 | unsigned int missasid:24; /* DW 2 */ | ||
276 | unsigned int fill7:8; | ||
277 | unsigned int fillasid:24; | ||
278 | unsigned int dirty:1; | ||
279 | unsigned int gaa:2; | ||
280 | unsigned long fill8:5; | ||
281 | |||
282 | unsigned long pfn:41; /* DW 3 */ | ||
283 | unsigned int fill9:7; | ||
284 | unsigned int pagesize:5; | ||
285 | unsigned int fill10:11; | ||
286 | |||
287 | unsigned long fillvaddr:64; /* DW 4 */ | ||
288 | |||
289 | unsigned long fill11[3]; | ||
290 | }; | ||
291 | |||
292 | enum gru_tfh_opc { | ||
293 | TFHOP_NOOP, | ||
294 | TFHOP_RESTART, | ||
295 | TFHOP_WRITE_ONLY, | ||
296 | TFHOP_WRITE_RESTART, | ||
297 | TFHOP_EXCEPTION, | ||
298 | TFHOP_USER_POLLING_MODE = 7, | ||
299 | }; | ||
300 | |||
301 | enum tfh_status { | ||
302 | TFHSTATUS_IDLE, | ||
303 | TFHSTATUS_EXCEPTION, | ||
304 | TFHSTATUS_ACTIVE, | ||
305 | }; | ||
306 | |||
307 | enum tfh_state { | ||
308 | TFHSTATE_INACTIVE, | ||
309 | TFHSTATE_IDLE, | ||
310 | TFHSTATE_MISS_UPM, | ||
311 | TFHSTATE_MISS_FMM, | ||
312 | TFHSTATE_HW_ERR, | ||
313 | TFHSTATE_WRITE_TLB, | ||
314 | TFHSTATE_RESTART_CBR, | ||
315 | }; | ||
316 | |||
317 | /* TFH cause bits */ | ||
318 | enum tfh_cause { | ||
319 | TFHCAUSE_NONE, | ||
320 | TFHCAUSE_TLB_MISS, | ||
321 | TFHCAUSE_TLB_MOD, | ||
322 | TFHCAUSE_HW_ERROR_RR, | ||
323 | TFHCAUSE_HW_ERROR_MAIN_ARRAY, | ||
324 | TFHCAUSE_HW_ERROR_VALID, | ||
325 | TFHCAUSE_HW_ERROR_PAGESIZE, | ||
326 | TFHCAUSE_INSTRUCTION_EXCEPTION, | ||
327 | TFHCAUSE_UNCORRECTIBLE_ERROR, | ||
328 | }; | ||
329 | |||
330 | /* GAA values */ | ||
331 | #define GAA_RAM 0x0 | ||
332 | #define GAA_NCRAM 0x2 | ||
333 | #define GAA_MMIO 0x1 | ||
334 | #define GAA_REGISTER 0x3 | ||
335 | |||
336 | /* GRU paddr shift for pfn. (NOTE: shift is NOT by actual pagesize) */ | ||
337 | #define GRU_PADDR_SHIFT 12 | ||
338 | |||
339 | /* | ||
340 | * Context Configuration handle | ||
341 | * Used to allocate resources to a GSEG context. | ||
342 | * | ||
343 | */ | ||
344 | struct gru_context_configuration_handle { | ||
345 | unsigned int cmd:1; /* DW0 */ | ||
346 | unsigned int delresp:1; | ||
347 | unsigned int opc:3; | ||
348 | unsigned int unmap_enable:1; | ||
349 | unsigned int req_slice_set_enable:1; | ||
350 | unsigned int req_slice:2; | ||
351 | unsigned int cb_int_enable:1; | ||
352 | unsigned int tlb_int_enable:1; | ||
353 | unsigned int tfm_fault_bit_enable:1; | ||
354 | unsigned int tlb_int_select:4; | ||
355 | |||
356 | unsigned int status:2; | ||
357 | unsigned int state:2; | ||
358 | unsigned int reserved2:4; | ||
359 | |||
360 | unsigned int cause:4; | ||
361 | unsigned int tfm_done_bit_enable:1; | ||
362 | unsigned int unused:3; | ||
363 | |||
364 | unsigned int dsr_allocation_map; | ||
365 | |||
366 | unsigned long cbr_allocation_map; /* DW1 */ | ||
367 | |||
368 | unsigned int asid[8]; /* DW 2 - 5 */ | ||
369 | unsigned short sizeavail[8]; /* DW 6 - 7 */ | ||
370 | } __attribute__ ((packed)); | ||
371 | |||
372 | enum gru_cch_opc { | ||
373 | CCHOP_START = 1, | ||
374 | CCHOP_ALLOCATE, | ||
375 | CCHOP_INTERRUPT, | ||
376 | CCHOP_DEALLOCATE, | ||
377 | CCHOP_INTERRUPT_SYNC, | ||
378 | }; | ||
379 | |||
380 | enum gru_cch_status { | ||
381 | CCHSTATUS_IDLE, | ||
382 | CCHSTATUS_EXCEPTION, | ||
383 | CCHSTATUS_ACTIVE, | ||
384 | }; | ||
385 | |||
386 | enum gru_cch_state { | ||
387 | CCHSTATE_INACTIVE, | ||
388 | CCHSTATE_MAPPED, | ||
389 | CCHSTATE_ACTIVE, | ||
390 | CCHSTATE_INTERRUPTED, | ||
391 | }; | ||
392 | |||
393 | /* CCH Exception cause */ | ||
394 | enum gru_cch_cause { | ||
395 | CCHCAUSE_REGION_REGISTER_WRITE_ERROR = 1, | ||
396 | CCHCAUSE_ILLEGAL_OPCODE = 2, | ||
397 | CCHCAUSE_INVALID_START_REQUEST = 3, | ||
398 | CCHCAUSE_INVALID_ALLOCATION_REQUEST = 4, | ||
399 | CCHCAUSE_INVALID_DEALLOCATION_REQUEST = 5, | ||
400 | CCHCAUSE_INVALID_INTERRUPT_REQUEST = 6, | ||
401 | CCHCAUSE_CCH_BUSY = 7, | ||
402 | CCHCAUSE_NO_CBRS_TO_ALLOCATE = 8, | ||
403 | CCHCAUSE_BAD_TFM_CONFIG = 9, | ||
404 | CCHCAUSE_CBR_RESOURCES_OVERSUBSCRIPED = 10, | ||
405 | CCHCAUSE_DSR_RESOURCES_OVERSUBSCRIPED = 11, | ||
406 | CCHCAUSE_CBR_DEALLOCATION_ERROR = 12, | ||
407 | }; | ||
408 | /* | ||
409 | * CBE - Control Block Extended | ||
410 | * Maintains internal GRU state for active CBs. | ||
411 | * | ||
412 | */ | ||
413 | struct gru_control_block_extended { | ||
414 | unsigned int reserved0:1; /* DW 0 - low */ | ||
415 | unsigned int imacpy:3; | ||
416 | unsigned int reserved1:4; | ||
417 | unsigned int xtypecpy:3; | ||
418 | unsigned int iaa0cpy:2; | ||
419 | unsigned int iaa1cpy:2; | ||
420 | unsigned int reserved2:1; | ||
421 | unsigned int opccpy:8; | ||
422 | unsigned int exopccpy:8; | ||
423 | |||
424 | unsigned int idef2cpy:22; /* DW 0 - high */ | ||
425 | unsigned int reserved3:10; | ||
426 | |||
427 | unsigned int idef4cpy:22; /* DW 1 */ | ||
428 | unsigned int reserved4:10; | ||
429 | unsigned int idef4upd:22; | ||
430 | unsigned int reserved5:10; | ||
431 | |||
432 | unsigned long idef1upd:64; /* DW 2 */ | ||
433 | |||
434 | unsigned long idef5cpy:64; /* DW 3 */ | ||
435 | |||
436 | unsigned long idef6cpy:64; /* DW 4 */ | ||
437 | |||
438 | unsigned long idef3upd:64; /* DW 5 */ | ||
439 | |||
440 | unsigned long idef5upd:64; /* DW 6 */ | ||
441 | |||
442 | unsigned int idef2upd:22; /* DW 7 */ | ||
443 | unsigned int reserved6:10; | ||
444 | |||
445 | unsigned int ecause:20; | ||
446 | unsigned int cbrstate:4; | ||
447 | unsigned int cbrexecstatus:8; | ||
448 | }; | ||
449 | |||
450 | enum gru_cbr_state { | ||
451 | CBRSTATE_INACTIVE, | ||
452 | CBRSTATE_IDLE, | ||
453 | CBRSTATE_PE_CHECK, | ||
454 | CBRSTATE_QUEUED, | ||
455 | CBRSTATE_WAIT_RESPONSE, | ||
456 | CBRSTATE_INTERRUPTED, | ||
457 | CBRSTATE_INTERRUPTED_MISS_FMM, | ||
458 | CBRSTATE_BUSY_INTERRUPT_MISS_FMM, | ||
459 | CBRSTATE_INTERRUPTED_MISS_UPM, | ||
460 | CBRSTATE_BUSY_INTERRUPTED_MISS_UPM, | ||
461 | CBRSTATE_REQUEST_ISSUE, | ||
462 | CBRSTATE_BUSY_INTERRUPT, | ||
463 | }; | ||
464 | |||
465 | /* CBE cbrexecstatus bits */ | ||
466 | #define CBR_EXS_ABORT_OCC_BIT 0 | ||
467 | #define CBR_EXS_INT_OCC_BIT 1 | ||
468 | #define CBR_EXS_PENDING_BIT 2 | ||
469 | #define CBR_EXS_QUEUED_BIT 3 | ||
470 | #define CBR_EXS_TLBHW_BIT 4 | ||
471 | #define CBR_EXS_EXCEPTION_BIT 5 | ||
472 | |||
473 | #define CBR_EXS_ABORT_OCC (1 << CBR_EXS_ABORT_OCC_BIT) | ||
474 | #define CBR_EXS_INT_OCC (1 << CBR_EXS_INT_OCC_BIT) | ||
475 | #define CBR_EXS_PENDING (1 << CBR_EXS_PENDING_BIT) | ||
476 | #define CBR_EXS_QUEUED (1 << CBR_EXS_QUEUED_BIT) | ||
477 | #define CBR_EXS_TLBHW (1 << CBR_EXS_TLBHW_BIT) | ||
478 | #define CBR_EXS_EXCEPTION (1 << CBR_EXS_EXCEPTION_BIT) | ||
479 | |||
480 | /* CBE ecause bits - defined in gru_instructions.h */ | ||
481 | |||
482 | /* | ||
483 | * Convert a processor pagesize into the strange encoded pagesize used by the | ||
484 | * GRU. Processor pagesize is encoded as log of bytes per page. (or PAGE_SHIFT) | ||
485 | * pagesize log pagesize grupagesize | ||
486 | * 4k 12 0 | ||
487 | * 16k 14 1 | ||
488 | * 64k 16 2 | ||
489 | * 256k 18 3 | ||
490 | * 1m 20 4 | ||
491 | * 2m 21 5 | ||
492 | * 4m 22 6 | ||
493 | * 16m 24 7 | ||
494 | * 64m 26 8 | ||
495 | * ... | ||
496 | */ | ||
497 | #define GRU_PAGESIZE(sh) ((((sh) > 20 ? (sh) + 2: (sh)) >> 1) - 6) | ||
498 | #define GRU_SIZEAVAIL(sh) (1UL << GRU_PAGESIZE(sh)) | ||
499 | |||
500 | /* minimum TLB purge count to ensure a full purge */ | ||
501 | #define GRUMAXINVAL 1024UL | ||
502 | |||
503 | |||
504 | /* Extract the status field from a kernel handle */ | ||
505 | #define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3) | ||
506 | |||
507 | static inline void start_instruction(void *h) | ||
508 | { | ||
509 | unsigned long *w0 = h; | ||
510 | |||
511 | wmb(); /* setting CMD bit must be last */ | ||
512 | *w0 = *w0 | 1; | ||
513 | gru_flush_cache(h); | ||
514 | } | ||
515 | |||
516 | static inline int wait_instruction_complete(void *h) | ||
517 | { | ||
518 | int status; | ||
519 | |||
520 | do { | ||
521 | cpu_relax(); | ||
522 | barrier(); | ||
523 | status = GET_MSEG_HANDLE_STATUS(h); | ||
524 | } while (status == CCHSTATUS_ACTIVE); | ||
525 | return status; | ||
526 | } | ||
527 | |||
528 | #if defined CONFIG_IA64 | ||
529 | static inline void cch_allocate_set_asids( | ||
530 | struct gru_context_configuration_handle *cch, int asidval) | ||
531 | { | ||
532 | int i; | ||
533 | |||
534 | for (i = 0; i <= RGN_HPAGE; i++) { /* assume HPAGE is last region */ | ||
535 | cch->asid[i] = (asidval++); | ||
536 | #if 0 | ||
537 | /* ZZZ hugepages not supported yet */ | ||
538 | if (i == RGN_HPAGE) | ||
539 | cch->sizeavail[i] = GRU_SIZEAVAIL(hpage_shift); | ||
540 | else | ||
541 | #endif | ||
542 | cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT); | ||
543 | } | ||
544 | } | ||
545 | #elif defined CONFIG_X86_64 | ||
546 | static inline void cch_allocate_set_asids( | ||
547 | struct gru_context_configuration_handle *cch, int asidval) | ||
548 | { | ||
549 | int i; | ||
550 | |||
551 | for (i = 0; i < 8; i++) { | ||
552 | cch->asid[i] = asidval++; | ||
553 | cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT) | | ||
554 | GRU_SIZEAVAIL(21); | ||
555 | } | ||
556 | } | ||
557 | #endif | ||
558 | |||
559 | static inline int cch_allocate(struct gru_context_configuration_handle *cch, | ||
560 | int asidval, unsigned long cbrmap, | ||
561 | unsigned long dsrmap) | ||
562 | { | ||
563 | cch_allocate_set_asids(cch, asidval); | ||
564 | cch->dsr_allocation_map = dsrmap; | ||
565 | cch->cbr_allocation_map = cbrmap; | ||
566 | cch->opc = CCHOP_ALLOCATE; | ||
567 | start_instruction(cch); | ||
568 | return wait_instruction_complete(cch); | ||
569 | } | ||
570 | |||
571 | static inline int cch_start(struct gru_context_configuration_handle *cch) | ||
572 | { | ||
573 | cch->opc = CCHOP_START; | ||
574 | start_instruction(cch); | ||
575 | return wait_instruction_complete(cch); | ||
576 | } | ||
577 | |||
578 | static inline int cch_interrupt(struct gru_context_configuration_handle *cch) | ||
579 | { | ||
580 | cch->opc = CCHOP_INTERRUPT; | ||
581 | start_instruction(cch); | ||
582 | return wait_instruction_complete(cch); | ||
583 | } | ||
584 | |||
585 | static inline int cch_deallocate(struct gru_context_configuration_handle *cch) | ||
586 | { | ||
587 | cch->opc = CCHOP_DEALLOCATE; | ||
588 | start_instruction(cch); | ||
589 | return wait_instruction_complete(cch); | ||
590 | } | ||
591 | |||
592 | static inline int cch_interrupt_sync(struct gru_context_configuration_handle | ||
593 | *cch) | ||
594 | { | ||
595 | cch->opc = CCHOP_INTERRUPT_SYNC; | ||
596 | start_instruction(cch); | ||
597 | return wait_instruction_complete(cch); | ||
598 | } | ||
599 | |||
600 | static inline int tgh_invalidate(struct gru_tlb_global_handle *tgh, | ||
601 | unsigned long vaddr, unsigned long vaddrmask, | ||
602 | int asid, int pagesize, int global, int n, | ||
603 | unsigned short ctxbitmap) | ||
604 | { | ||
605 | tgh->vaddr = vaddr; | ||
606 | tgh->asid = asid; | ||
607 | tgh->pagesize = pagesize; | ||
608 | tgh->n = n; | ||
609 | tgh->global = global; | ||
610 | tgh->vaddrmask = vaddrmask; | ||
611 | tgh->ctxbitmap = ctxbitmap; | ||
612 | tgh->opc = TGHOP_TLBINV; | ||
613 | start_instruction(tgh); | ||
614 | return wait_instruction_complete(tgh); | ||
615 | } | ||
616 | |||
617 | static inline void tfh_write_only(struct gru_tlb_fault_handle *tfh, | ||
618 | unsigned long pfn, unsigned long vaddr, | ||
619 | int asid, int dirty, int pagesize) | ||
620 | { | ||
621 | tfh->fillasid = asid; | ||
622 | tfh->fillvaddr = vaddr; | ||
623 | tfh->pfn = pfn; | ||
624 | tfh->dirty = dirty; | ||
625 | tfh->pagesize = pagesize; | ||
626 | tfh->opc = TFHOP_WRITE_ONLY; | ||
627 | start_instruction(tfh); | ||
628 | } | ||
629 | |||
630 | static inline void tfh_write_restart(struct gru_tlb_fault_handle *tfh, | ||
631 | unsigned long paddr, int gaa, | ||
632 | unsigned long vaddr, int asid, int dirty, | ||
633 | int pagesize) | ||
634 | { | ||
635 | tfh->fillasid = asid; | ||
636 | tfh->fillvaddr = vaddr; | ||
637 | tfh->pfn = paddr >> GRU_PADDR_SHIFT; | ||
638 | tfh->gaa = gaa; | ||
639 | tfh->dirty = dirty; | ||
640 | tfh->pagesize = pagesize; | ||
641 | tfh->opc = TFHOP_WRITE_RESTART; | ||
642 | start_instruction(tfh); | ||
643 | } | ||
644 | |||
645 | static inline void tfh_restart(struct gru_tlb_fault_handle *tfh) | ||
646 | { | ||
647 | tfh->opc = TFHOP_RESTART; | ||
648 | start_instruction(tfh); | ||
649 | } | ||
650 | |||
651 | static inline void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh) | ||
652 | { | ||
653 | tfh->opc = TFHOP_USER_POLLING_MODE; | ||
654 | start_instruction(tfh); | ||
655 | } | ||
656 | |||
657 | static inline void tfh_exception(struct gru_tlb_fault_handle *tfh) | ||
658 | { | ||
659 | tfh->opc = TFHOP_EXCEPTION; | ||
660 | start_instruction(tfh); | ||
661 | } | ||
662 | |||
663 | #endif /* __GRUHANDLES_H__ */ | ||
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c new file mode 100644 index 000000000000..dfd49af0fe18 --- /dev/null +++ b/drivers/misc/sgi-gru/grukservices.c | |||
@@ -0,0 +1,679 @@ | |||
1 | /* | ||
2 | * SN Platform GRU Driver | ||
3 | * | ||
4 | * KERNEL SERVICES THAT USE THE GRU | ||
5 | * | ||
6 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/smp_lock.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/miscdevice.h> | ||
31 | #include <linux/proc_fs.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/uaccess.h> | ||
34 | #include "gru.h" | ||
35 | #include "grulib.h" | ||
36 | #include "grutables.h" | ||
37 | #include "grukservices.h" | ||
38 | #include "gru_instructions.h" | ||
39 | #include <asm/uv/uv_hub.h> | ||
40 | |||
41 | /* | ||
42 | * Kernel GRU Usage | ||
43 | * | ||
44 | * The following is an interim algorithm for management of kernel GRU | ||
45 | * resources. This will likely be replaced when we better understand the | ||
46 | * kernel/user requirements. | ||
47 | * | ||
48 | * At boot time, the kernel permanently reserves a fixed number of | ||
49 | * CBRs/DSRs for each cpu to use. The resources are all taken from | ||
50 | * the GRU chiplet 1 on the blade. This leaves the full set of resources | ||
51 | * of chiplet 0 available to be allocated to a single user. | ||
52 | */ | ||
53 | |||
54 | /* Blade percpu resources PERMANENTLY reserved for kernel use */ | ||
55 | #define GRU_NUM_KERNEL_CBR 1 | ||
56 | #define GRU_NUM_KERNEL_DSR_BYTES 256 | ||
57 | #define KERNEL_CTXNUM 15 | ||
58 | |||
59 | /* GRU instruction attributes for all instructions */ | ||
60 | #define IMA IMA_CB_DELAY | ||
61 | |||
62 | /* GRU cacheline size is always 64 bytes - even on arches with 128 byte lines */ | ||
63 | #define __gru_cacheline_aligned__ \ | ||
64 | __attribute__((__aligned__(GRU_CACHE_LINE_BYTES))) | ||
65 | |||
66 | #define MAGIC 0x1234567887654321UL | ||
67 | |||
68 | /* Default retry count for GRU errors on kernel instructions */ | ||
69 | #define EXCEPTION_RETRY_LIMIT 3 | ||
70 | |||
71 | /* Status of message queue sections */ | ||
72 | #define MQS_EMPTY 0 | ||
73 | #define MQS_FULL 1 | ||
74 | #define MQS_NOOP 2 | ||
75 | |||
76 | /*----------------- RESOURCE MANAGEMENT -------------------------------------*/ | ||
77 | /* optimized for x86_64 */ | ||
78 | struct message_queue { | ||
79 | union gru_mesqhead head __gru_cacheline_aligned__; /* CL 0 */ | ||
80 | int qlines; /* DW 1 */ | ||
81 | long hstatus[2]; | ||
82 | void *next __gru_cacheline_aligned__;/* CL 1 */ | ||
83 | void *limit; | ||
84 | void *start; | ||
85 | void *start2; | ||
86 | char data ____cacheline_aligned; /* CL 2 */ | ||
87 | }; | ||
88 | |||
89 | /* First word in every message - used by mesq interface */ | ||
90 | struct message_header { | ||
91 | char present; | ||
92 | char present2; | ||
93 | char lines; | ||
94 | char fill; | ||
95 | }; | ||
96 | |||
97 | #define QLINES(mq) ((mq) + offsetof(struct message_queue, qlines)) | ||
98 | #define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h])) | ||
99 | |||
100 | static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr) | ||
101 | { | ||
102 | struct gru_blade_state *bs; | ||
103 | int lcpu; | ||
104 | |||
105 | BUG_ON(dsr_bytes > GRU_NUM_KERNEL_DSR_BYTES); | ||
106 | preempt_disable(); | ||
107 | bs = gru_base[uv_numa_blade_id()]; | ||
108 | lcpu = uv_blade_processor_id(); | ||
109 | *cb = bs->kernel_cb + lcpu * GRU_HANDLE_STRIDE; | ||
110 | *dsr = bs->kernel_dsr + lcpu * GRU_NUM_KERNEL_DSR_BYTES; | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static void gru_free_cpu_resources(void *cb, void *dsr) | ||
115 | { | ||
116 | preempt_enable(); | ||
117 | } | ||
118 | |||
119 | int gru_get_cb_exception_detail(void *cb, | ||
120 | struct control_block_extended_exc_detail *excdet) | ||
121 | { | ||
122 | struct gru_control_block_extended *cbe; | ||
123 | |||
124 | cbe = get_cbe(GRUBASE(cb), get_cb_number(cb)); | ||
125 | excdet->opc = cbe->opccpy; | ||
126 | excdet->exopc = cbe->exopccpy; | ||
127 | excdet->ecause = cbe->ecause; | ||
128 | excdet->exceptdet0 = cbe->idef1upd; | ||
129 | excdet->exceptdet1 = cbe->idef3upd; | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | char *gru_get_cb_exception_detail_str(int ret, void *cb, | ||
134 | char *buf, int size) | ||
135 | { | ||
136 | struct gru_control_block_status *gen = (void *)cb; | ||
137 | struct control_block_extended_exc_detail excdet; | ||
138 | |||
139 | if (ret > 0 && gen->istatus == CBS_EXCEPTION) { | ||
140 | gru_get_cb_exception_detail(cb, &excdet); | ||
141 | snprintf(buf, size, | ||
142 | "GRU exception: cb %p, opc %d, exopc %d, ecause 0x%x," | ||
143 | "excdet0 0x%lx, excdet1 0x%x", | ||
144 | gen, excdet.opc, excdet.exopc, excdet.ecause, | ||
145 | excdet.exceptdet0, excdet.exceptdet1); | ||
146 | } else { | ||
147 | snprintf(buf, size, "No exception"); | ||
148 | } | ||
149 | return buf; | ||
150 | } | ||
151 | |||
152 | static int gru_wait_idle_or_exception(struct gru_control_block_status *gen) | ||
153 | { | ||
154 | while (gen->istatus >= CBS_ACTIVE) { | ||
155 | cpu_relax(); | ||
156 | barrier(); | ||
157 | } | ||
158 | return gen->istatus; | ||
159 | } | ||
160 | |||
161 | static int gru_retry_exception(void *cb) | ||
162 | { | ||
163 | struct gru_control_block_status *gen = (void *)cb; | ||
164 | struct control_block_extended_exc_detail excdet; | ||
165 | int retry = EXCEPTION_RETRY_LIMIT; | ||
166 | |||
167 | while (1) { | ||
168 | if (gru_get_cb_message_queue_substatus(cb)) | ||
169 | break; | ||
170 | if (gru_wait_idle_or_exception(gen) == CBS_IDLE) | ||
171 | return CBS_IDLE; | ||
172 | |||
173 | gru_get_cb_exception_detail(cb, &excdet); | ||
174 | if (excdet.ecause & ~EXCEPTION_RETRY_BITS) | ||
175 | break; | ||
176 | if (retry-- == 0) | ||
177 | break; | ||
178 | gen->icmd = 1; | ||
179 | gru_flush_cache(gen); | ||
180 | } | ||
181 | return CBS_EXCEPTION; | ||
182 | } | ||
183 | |||
184 | int gru_check_status_proc(void *cb) | ||
185 | { | ||
186 | struct gru_control_block_status *gen = (void *)cb; | ||
187 | int ret; | ||
188 | |||
189 | ret = gen->istatus; | ||
190 | if (ret != CBS_EXCEPTION) | ||
191 | return ret; | ||
192 | return gru_retry_exception(cb); | ||
193 | |||
194 | } | ||
195 | |||
196 | int gru_wait_proc(void *cb) | ||
197 | { | ||
198 | struct gru_control_block_status *gen = (void *)cb; | ||
199 | int ret; | ||
200 | |||
201 | ret = gru_wait_idle_or_exception(gen); | ||
202 | if (ret == CBS_EXCEPTION) | ||
203 | ret = gru_retry_exception(cb); | ||
204 | |||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | void gru_abort(int ret, void *cb, char *str) | ||
209 | { | ||
210 | char buf[GRU_EXC_STR_SIZE]; | ||
211 | |||
212 | panic("GRU FATAL ERROR: %s - %s\n", str, | ||
213 | gru_get_cb_exception_detail_str(ret, cb, buf, sizeof(buf))); | ||
214 | } | ||
215 | |||
216 | void gru_wait_abort_proc(void *cb) | ||
217 | { | ||
218 | int ret; | ||
219 | |||
220 | ret = gru_wait_proc(cb); | ||
221 | if (ret) | ||
222 | gru_abort(ret, cb, "gru_wait_abort"); | ||
223 | } | ||
224 | |||
225 | |||
226 | /*------------------------------ MESSAGE QUEUES -----------------------------*/ | ||
227 | |||
228 | /* Internal status . These are NOT returned to the user. */ | ||
229 | #define MQIE_AGAIN -1 /* try again */ | ||
230 | |||
231 | |||
232 | /* | ||
233 | * Save/restore the "present" flag that is in the second line of 2-line | ||
234 | * messages | ||
235 | */ | ||
236 | static inline int get_present2(void *p) | ||
237 | { | ||
238 | struct message_header *mhdr = p + GRU_CACHE_LINE_BYTES; | ||
239 | return mhdr->present; | ||
240 | } | ||
241 | |||
242 | static inline void restore_present2(void *p, int val) | ||
243 | { | ||
244 | struct message_header *mhdr = p + GRU_CACHE_LINE_BYTES; | ||
245 | mhdr->present = val; | ||
246 | } | ||
247 | |||
248 | /* | ||
249 | * Create a message queue. | ||
250 | * qlines - message queue size in cache lines. Includes 2-line header. | ||
251 | */ | ||
252 | int gru_create_message_queue(void *p, unsigned int bytes) | ||
253 | { | ||
254 | struct message_queue *mq = p; | ||
255 | unsigned int qlines; | ||
256 | |||
257 | qlines = bytes / GRU_CACHE_LINE_BYTES - 2; | ||
258 | memset(mq, 0, bytes); | ||
259 | mq->start = &mq->data; | ||
260 | mq->start2 = &mq->data + (qlines / 2 - 1) * GRU_CACHE_LINE_BYTES; | ||
261 | mq->next = &mq->data; | ||
262 | mq->limit = &mq->data + (qlines - 2) * GRU_CACHE_LINE_BYTES; | ||
263 | mq->qlines = qlines; | ||
264 | mq->hstatus[0] = 0; | ||
265 | mq->hstatus[1] = 1; | ||
266 | mq->head = gru_mesq_head(2, qlines / 2 + 1); | ||
267 | return 0; | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(gru_create_message_queue); | ||
270 | |||
271 | /* | ||
272 | * Send a NOOP message to a message queue | ||
273 | * Returns: | ||
274 | * 0 - if queue is full after the send. This is the normal case | ||
275 | * but various races can change this. | ||
276 | * -1 - if mesq sent successfully but queue not full | ||
277 | * >0 - unexpected error. MQE_xxx returned | ||
278 | */ | ||
279 | static int send_noop_message(void *cb, | ||
280 | unsigned long mq, void *mesg) | ||
281 | { | ||
282 | const struct message_header noop_header = { | ||
283 | .present = MQS_NOOP, .lines = 1}; | ||
284 | unsigned long m; | ||
285 | int substatus, ret; | ||
286 | struct message_header save_mhdr, *mhdr = mesg; | ||
287 | |||
288 | STAT(mesq_noop); | ||
289 | save_mhdr = *mhdr; | ||
290 | *mhdr = noop_header; | ||
291 | gru_mesq(cb, mq, gru_get_tri(mhdr), 1, IMA); | ||
292 | ret = gru_wait(cb); | ||
293 | |||
294 | if (ret) { | ||
295 | substatus = gru_get_cb_message_queue_substatus(cb); | ||
296 | switch (substatus) { | ||
297 | case CBSS_NO_ERROR: | ||
298 | STAT(mesq_noop_unexpected_error); | ||
299 | ret = MQE_UNEXPECTED_CB_ERR; | ||
300 | break; | ||
301 | case CBSS_LB_OVERFLOWED: | ||
302 | STAT(mesq_noop_lb_overflow); | ||
303 | ret = MQE_CONGESTION; | ||
304 | break; | ||
305 | case CBSS_QLIMIT_REACHED: | ||
306 | STAT(mesq_noop_qlimit_reached); | ||
307 | ret = 0; | ||
308 | break; | ||
309 | case CBSS_AMO_NACKED: | ||
310 | STAT(mesq_noop_amo_nacked); | ||
311 | ret = MQE_CONGESTION; | ||
312 | break; | ||
313 | case CBSS_PUT_NACKED: | ||
314 | STAT(mesq_noop_put_nacked); | ||
315 | m = mq + (gru_get_amo_value_head(cb) << 6); | ||
316 | gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, 1, 1, | ||
317 | IMA); | ||
318 | if (gru_wait(cb) == CBS_IDLE) | ||
319 | ret = MQIE_AGAIN; | ||
320 | else | ||
321 | ret = MQE_UNEXPECTED_CB_ERR; | ||
322 | break; | ||
323 | case CBSS_PAGE_OVERFLOW: | ||
324 | default: | ||
325 | BUG(); | ||
326 | } | ||
327 | } | ||
328 | *mhdr = save_mhdr; | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Handle a gru_mesq full. | ||
334 | */ | ||
335 | static int send_message_queue_full(void *cb, | ||
336 | unsigned long mq, void *mesg, int lines) | ||
337 | { | ||
338 | union gru_mesqhead mqh; | ||
339 | unsigned int limit, head; | ||
340 | unsigned long avalue; | ||
341 | int half, qlines, save; | ||
342 | |||
343 | /* Determine if switching to first/second half of q */ | ||
344 | avalue = gru_get_amo_value(cb); | ||
345 | head = gru_get_amo_value_head(cb); | ||
346 | limit = gru_get_amo_value_limit(cb); | ||
347 | |||
348 | /* | ||
349 | * Fetch "qlines" from the queue header. Since the queue may be | ||
350 | * in memory that can't be accessed using socket addresses, use | ||
351 | * the GRU to access the data. Use DSR space from the message. | ||
352 | */ | ||
353 | save = *(int *)mesg; | ||
354 | gru_vload(cb, QLINES(mq), gru_get_tri(mesg), XTYPE_W, 1, 1, IMA); | ||
355 | if (gru_wait(cb) != CBS_IDLE) | ||
356 | goto cberr; | ||
357 | qlines = *(int *)mesg; | ||
358 | *(int *)mesg = save; | ||
359 | half = (limit != qlines); | ||
360 | |||
361 | if (half) | ||
362 | mqh = gru_mesq_head(qlines / 2 + 1, qlines); | ||
363 | else | ||
364 | mqh = gru_mesq_head(2, qlines / 2 + 1); | ||
365 | |||
366 | /* Try to get lock for switching head pointer */ | ||
367 | gru_gamir(cb, EOP_IR_CLR, HSTATUS(mq, half), XTYPE_DW, IMA); | ||
368 | if (gru_wait(cb) != CBS_IDLE) | ||
369 | goto cberr; | ||
370 | if (!gru_get_amo_value(cb)) { | ||
371 | STAT(mesq_qf_locked); | ||
372 | return MQE_QUEUE_FULL; | ||
373 | } | ||
374 | |||
375 | /* Got the lock. Send optional NOP if queue not full, */ | ||
376 | if (head != limit) { | ||
377 | if (send_noop_message(cb, mq, mesg)) { | ||
378 | gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), | ||
379 | XTYPE_DW, IMA); | ||
380 | if (gru_wait(cb) != CBS_IDLE) | ||
381 | goto cberr; | ||
382 | STAT(mesq_qf_noop_not_full); | ||
383 | return MQIE_AGAIN; | ||
384 | } | ||
385 | avalue++; | ||
386 | } | ||
387 | |||
388 | /* Then flip queuehead to other half of queue. */ | ||
389 | gru_gamer(cb, EOP_ERR_CSWAP, mq, XTYPE_DW, mqh.val, avalue, IMA); | ||
390 | if (gru_wait(cb) != CBS_IDLE) | ||
391 | goto cberr; | ||
392 | |||
393 | /* If not successfully in swapping queue head, clear the hstatus lock */ | ||
394 | if (gru_get_amo_value(cb) != avalue) { | ||
395 | STAT(mesq_qf_switch_head_failed); | ||
396 | gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), XTYPE_DW, IMA); | ||
397 | if (gru_wait(cb) != CBS_IDLE) | ||
398 | goto cberr; | ||
399 | } | ||
400 | return MQIE_AGAIN; | ||
401 | cberr: | ||
402 | STAT(mesq_qf_unexpected_error); | ||
403 | return MQE_UNEXPECTED_CB_ERR; | ||
404 | } | ||
405 | |||
406 | |||
407 | /* | ||
408 | * Handle a gru_mesq failure. Some of these failures are software recoverable | ||
409 | * or retryable. | ||
410 | */ | ||
411 | static int send_message_failure(void *cb, | ||
412 | unsigned long mq, | ||
413 | void *mesg, | ||
414 | int lines) | ||
415 | { | ||
416 | int substatus, ret = 0; | ||
417 | unsigned long m; | ||
418 | |||
419 | substatus = gru_get_cb_message_queue_substatus(cb); | ||
420 | switch (substatus) { | ||
421 | case CBSS_NO_ERROR: | ||
422 | STAT(mesq_send_unexpected_error); | ||
423 | ret = MQE_UNEXPECTED_CB_ERR; | ||
424 | break; | ||
425 | case CBSS_LB_OVERFLOWED: | ||
426 | STAT(mesq_send_lb_overflow); | ||
427 | ret = MQE_CONGESTION; | ||
428 | break; | ||
429 | case CBSS_QLIMIT_REACHED: | ||
430 | STAT(mesq_send_qlimit_reached); | ||
431 | ret = send_message_queue_full(cb, mq, mesg, lines); | ||
432 | break; | ||
433 | case CBSS_AMO_NACKED: | ||
434 | STAT(mesq_send_amo_nacked); | ||
435 | ret = MQE_CONGESTION; | ||
436 | break; | ||
437 | case CBSS_PUT_NACKED: | ||
438 | STAT(mesq_send_put_nacked); | ||
439 | m =mq + (gru_get_amo_value_head(cb) << 6); | ||
440 | gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA); | ||
441 | if (gru_wait(cb) == CBS_IDLE) | ||
442 | ret = MQE_OK; | ||
443 | else | ||
444 | ret = MQE_UNEXPECTED_CB_ERR; | ||
445 | break; | ||
446 | default: | ||
447 | BUG(); | ||
448 | } | ||
449 | return ret; | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * Send a message to a message queue | ||
454 | * cb GRU control block to use to send message | ||
455 | * mq message queue | ||
456 | * mesg message. ust be vaddr within a GSEG | ||
457 | * bytes message size (<= 2 CL) | ||
458 | */ | ||
459 | int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes) | ||
460 | { | ||
461 | struct message_header *mhdr; | ||
462 | void *cb; | ||
463 | void *dsr; | ||
464 | int istatus, clines, ret; | ||
465 | |||
466 | STAT(mesq_send); | ||
467 | BUG_ON(bytes < sizeof(int) || bytes > 2 * GRU_CACHE_LINE_BYTES); | ||
468 | |||
469 | clines = (bytes + GRU_CACHE_LINE_BYTES - 1) / GRU_CACHE_LINE_BYTES; | ||
470 | if (gru_get_cpu_resources(bytes, &cb, &dsr)) | ||
471 | return MQE_BUG_NO_RESOURCES; | ||
472 | memcpy(dsr, mesg, bytes); | ||
473 | mhdr = dsr; | ||
474 | mhdr->present = MQS_FULL; | ||
475 | mhdr->lines = clines; | ||
476 | if (clines == 2) { | ||
477 | mhdr->present2 = get_present2(mhdr); | ||
478 | restore_present2(mhdr, MQS_FULL); | ||
479 | } | ||
480 | |||
481 | do { | ||
482 | ret = MQE_OK; | ||
483 | gru_mesq(cb, mq, gru_get_tri(mhdr), clines, IMA); | ||
484 | istatus = gru_wait(cb); | ||
485 | if (istatus != CBS_IDLE) | ||
486 | ret = send_message_failure(cb, mq, dsr, clines); | ||
487 | } while (ret == MQIE_AGAIN); | ||
488 | gru_free_cpu_resources(cb, dsr); | ||
489 | |||
490 | if (ret) | ||
491 | STAT(mesq_send_failed); | ||
492 | return ret; | ||
493 | } | ||
494 | EXPORT_SYMBOL_GPL(gru_send_message_gpa); | ||
495 | |||
496 | /* | ||
497 | * Advance the receive pointer for the queue to the next message. | ||
498 | */ | ||
499 | void gru_free_message(void *rmq, void *mesg) | ||
500 | { | ||
501 | struct message_queue *mq = rmq; | ||
502 | struct message_header *mhdr = mq->next; | ||
503 | void *next, *pnext; | ||
504 | int half = -1; | ||
505 | int lines = mhdr->lines; | ||
506 | |||
507 | if (lines == 2) | ||
508 | restore_present2(mhdr, MQS_EMPTY); | ||
509 | mhdr->present = MQS_EMPTY; | ||
510 | |||
511 | pnext = mq->next; | ||
512 | next = pnext + GRU_CACHE_LINE_BYTES * lines; | ||
513 | if (next == mq->limit) { | ||
514 | next = mq->start; | ||
515 | half = 1; | ||
516 | } else if (pnext < mq->start2 && next >= mq->start2) { | ||
517 | half = 0; | ||
518 | } | ||
519 | |||
520 | if (half >= 0) | ||
521 | mq->hstatus[half] = 1; | ||
522 | mq->next = next; | ||
523 | } | ||
524 | EXPORT_SYMBOL_GPL(gru_free_message); | ||
525 | |||
526 | /* | ||
527 | * Get next message from message queue. Return NULL if no message | ||
528 | * present. User must call next_message() to move to next message. | ||
529 | * rmq message queue | ||
530 | */ | ||
531 | void *gru_get_next_message(void *rmq) | ||
532 | { | ||
533 | struct message_queue *mq = rmq; | ||
534 | struct message_header *mhdr = mq->next; | ||
535 | int present = mhdr->present; | ||
536 | |||
537 | /* skip NOOP messages */ | ||
538 | STAT(mesq_receive); | ||
539 | while (present == MQS_NOOP) { | ||
540 | gru_free_message(rmq, mhdr); | ||
541 | mhdr = mq->next; | ||
542 | present = mhdr->present; | ||
543 | } | ||
544 | |||
545 | /* Wait for both halves of 2 line messages */ | ||
546 | if (present == MQS_FULL && mhdr->lines == 2 && | ||
547 | get_present2(mhdr) == MQS_EMPTY) | ||
548 | present = MQS_EMPTY; | ||
549 | |||
550 | if (!present) { | ||
551 | STAT(mesq_receive_none); | ||
552 | return NULL; | ||
553 | } | ||
554 | |||
555 | if (mhdr->lines == 2) | ||
556 | restore_present2(mhdr, mhdr->present2); | ||
557 | |||
558 | return mhdr; | ||
559 | } | ||
560 | EXPORT_SYMBOL_GPL(gru_get_next_message); | ||
561 | |||
562 | /* ---------------------- GRU DATA COPY FUNCTIONS ---------------------------*/ | ||
563 | |||
564 | /* | ||
565 | * Copy a block of data using the GRU resources | ||
566 | */ | ||
567 | int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa, | ||
568 | unsigned int bytes) | ||
569 | { | ||
570 | void *cb; | ||
571 | void *dsr; | ||
572 | int ret; | ||
573 | |||
574 | STAT(copy_gpa); | ||
575 | if (gru_get_cpu_resources(GRU_NUM_KERNEL_DSR_BYTES, &cb, &dsr)) | ||
576 | return MQE_BUG_NO_RESOURCES; | ||
577 | gru_bcopy(cb, src_gpa, dest_gpa, gru_get_tri(dsr), | ||
578 | XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_BYTES, IMA); | ||
579 | ret = gru_wait(cb); | ||
580 | gru_free_cpu_resources(cb, dsr); | ||
581 | return ret; | ||
582 | } | ||
583 | EXPORT_SYMBOL_GPL(gru_copy_gpa); | ||
584 | |||
585 | /* ------------------- KERNEL QUICKTESTS RUN AT STARTUP ----------------*/ | ||
586 | /* Temp - will delete after we gain confidence in the GRU */ | ||
587 | static __cacheline_aligned unsigned long word0; | ||
588 | static __cacheline_aligned unsigned long word1; | ||
589 | |||
590 | static int quicktest(struct gru_state *gru) | ||
591 | { | ||
592 | void *cb; | ||
593 | void *ds; | ||
594 | unsigned long *p; | ||
595 | |||
596 | cb = get_gseg_base_address_cb(gru->gs_gru_base_vaddr, KERNEL_CTXNUM, 0); | ||
597 | ds = get_gseg_base_address_ds(gru->gs_gru_base_vaddr, KERNEL_CTXNUM, 0); | ||
598 | p = ds; | ||
599 | word0 = MAGIC; | ||
600 | |||
601 | gru_vload(cb, uv_gpa(&word0), 0, XTYPE_DW, 1, 1, IMA); | ||
602 | if (gru_wait(cb) != CBS_IDLE) | ||
603 | BUG(); | ||
604 | |||
605 | if (*(unsigned long *)ds != MAGIC) | ||
606 | BUG(); | ||
607 | gru_vstore(cb, uv_gpa(&word1), 0, XTYPE_DW, 1, 1, IMA); | ||
608 | if (gru_wait(cb) != CBS_IDLE) | ||
609 | BUG(); | ||
610 | |||
611 | if (word0 != word1 || word0 != MAGIC) { | ||
612 | printk | ||
613 | ("GRU quicktest err: gru %d, found 0x%lx, expected 0x%lx\n", | ||
614 | gru->gs_gid, word1, MAGIC); | ||
615 | BUG(); /* ZZZ should not be fatal */ | ||
616 | } | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | |||
622 | int gru_kservices_init(struct gru_state *gru) | ||
623 | { | ||
624 | struct gru_blade_state *bs; | ||
625 | struct gru_context_configuration_handle *cch; | ||
626 | unsigned long cbr_map, dsr_map; | ||
627 | int err, num, cpus_possible; | ||
628 | |||
629 | /* | ||
630 | * Currently, resources are reserved ONLY on the second chiplet | ||
631 | * on each blade. This leaves ALL resources on chiplet 0 available | ||
632 | * for user code. | ||
633 | */ | ||
634 | bs = gru->gs_blade; | ||
635 | if (gru != &bs->bs_grus[1]) | ||
636 | return 0; | ||
637 | |||
638 | cpus_possible = uv_blade_nr_possible_cpus(gru->gs_blade_id); | ||
639 | |||
640 | num = GRU_NUM_KERNEL_CBR * cpus_possible; | ||
641 | cbr_map = gru_reserve_cb_resources(gru, GRU_CB_COUNT_TO_AU(num), NULL); | ||
642 | gru->gs_reserved_cbrs += num; | ||
643 | |||
644 | num = GRU_NUM_KERNEL_DSR_BYTES * cpus_possible; | ||
645 | dsr_map = gru_reserve_ds_resources(gru, GRU_DS_BYTES_TO_AU(num), NULL); | ||
646 | gru->gs_reserved_dsr_bytes += num; | ||
647 | |||
648 | gru->gs_active_contexts++; | ||
649 | __set_bit(KERNEL_CTXNUM, &gru->gs_context_map); | ||
650 | cch = get_cch(gru->gs_gru_base_vaddr, KERNEL_CTXNUM); | ||
651 | |||
652 | bs->kernel_cb = get_gseg_base_address_cb(gru->gs_gru_base_vaddr, | ||
653 | KERNEL_CTXNUM, 0); | ||
654 | bs->kernel_dsr = get_gseg_base_address_ds(gru->gs_gru_base_vaddr, | ||
655 | KERNEL_CTXNUM, 0); | ||
656 | |||
657 | lock_cch_handle(cch); | ||
658 | cch->tfm_fault_bit_enable = 0; | ||
659 | cch->tlb_int_enable = 0; | ||
660 | cch->tfm_done_bit_enable = 0; | ||
661 | cch->unmap_enable = 1; | ||
662 | err = cch_allocate(cch, 0, cbr_map, dsr_map); | ||
663 | if (err) { | ||
664 | gru_dbg(grudev, | ||
665 | "Unable to allocate kernel CCH: gru %d, err %d\n", | ||
666 | gru->gs_gid, err); | ||
667 | BUG(); | ||
668 | } | ||
669 | if (cch_start(cch)) { | ||
670 | gru_dbg(grudev, "Unable to start kernel CCH: gru %d, err %d\n", | ||
671 | gru->gs_gid, err); | ||
672 | BUG(); | ||
673 | } | ||
674 | unlock_cch_handle(cch); | ||
675 | |||
676 | if (gru_options & GRU_QUICKLOOK) | ||
677 | quicktest(gru); | ||
678 | return 0; | ||
679 | } | ||
diff --git a/drivers/misc/sgi-gru/grukservices.h b/drivers/misc/sgi-gru/grukservices.h new file mode 100644 index 000000000000..eb17e0a3ac61 --- /dev/null +++ b/drivers/misc/sgi-gru/grukservices.h | |||
@@ -0,0 +1,134 @@ | |||
1 | |||
2 | /* | ||
3 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | #ifndef __GRU_KSERVICES_H_ | ||
20 | #define __GRU_KSERVICES_H_ | ||
21 | |||
22 | |||
23 | /* | ||
24 | * Message queues using the GRU to send/receive messages. | ||
25 | * | ||
26 | * These function allow the user to create a message queue for | ||
27 | * sending/receiving 1 or 2 cacheline messages using the GRU. | ||
28 | * | ||
29 | * Processes SENDING messages will use a kernel CBR/DSR to send | ||
30 | * the message. This is transparent to the caller. | ||
31 | * | ||
32 | * The receiver does not use any GRU resources. | ||
33 | * | ||
34 | * The functions support: | ||
35 | * - single receiver | ||
36 | * - multiple senders | ||
37 | * - cross partition message | ||
38 | * | ||
39 | * Missing features ZZZ: | ||
40 | * - user options for dealing with timeouts, queue full, etc. | ||
41 | * - gru_create_message_queue() needs interrupt vector info | ||
42 | */ | ||
43 | |||
44 | /* | ||
45 | * Initialize a user allocated chunk of memory to be used as | ||
46 | * a message queue. The caller must ensure that the queue is | ||
47 | * in contiguous physical memory and is cacheline aligned. | ||
48 | * | ||
49 | * Message queue size is the total number of bytes allocated | ||
50 | * to the queue including a 2 cacheline header that is used | ||
51 | * to manage the queue. | ||
52 | * | ||
53 | * Input: | ||
54 | * p pointer to user allocated memory. | ||
55 | * bytes size of message queue in bytes | ||
56 | * | ||
57 | * Errors: | ||
58 | * 0 OK | ||
59 | * >0 error | ||
60 | */ | ||
61 | extern int gru_create_message_queue(void *p, unsigned int bytes); | ||
62 | |||
63 | /* | ||
64 | * Send a message to a message queue. | ||
65 | * | ||
66 | * Note: The message queue transport mechanism uses the first 32 | ||
67 | * bits of the message. Users should avoid using these bits. | ||
68 | * | ||
69 | * | ||
70 | * Input: | ||
71 | * xmq message queue - must be a UV global physical address | ||
72 | * mesg pointer to message. Must be 64-bit aligned | ||
73 | * bytes size of message in bytes | ||
74 | * | ||
75 | * Output: | ||
76 | * 0 message sent | ||
77 | * >0 Send failure - see error codes below | ||
78 | * | ||
79 | */ | ||
80 | extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg, | ||
81 | unsigned int bytes); | ||
82 | |||
83 | /* Status values for gru_send_message() */ | ||
84 | #define MQE_OK 0 /* message sent successfully */ | ||
85 | #define MQE_CONGESTION 1 /* temporary congestion, try again */ | ||
86 | #define MQE_QUEUE_FULL 2 /* queue is full */ | ||
87 | #define MQE_UNEXPECTED_CB_ERR 3 /* unexpected CB error */ | ||
88 | #define MQE_PAGE_OVERFLOW 10 /* BUG - queue overflowed a page */ | ||
89 | #define MQE_BUG_NO_RESOURCES 11 /* BUG - could not alloc GRU cb/dsr */ | ||
90 | |||
91 | /* | ||
92 | * Advance the receive pointer for the message queue to the next message. | ||
93 | * Note: current API requires messages to be gotten & freed in order. Future | ||
94 | * API extensions may allow for out-of-order freeing. | ||
95 | * | ||
96 | * Input | ||
97 | * mq message queue | ||
98 | * mesq message being freed | ||
99 | */ | ||
100 | extern void gru_free_message(void *mq, void *mesq); | ||
101 | |||
102 | /* | ||
103 | * Get next message from message queue. Returns pointer to | ||
104 | * message OR NULL if no message present. | ||
105 | * User must call gru_free_message() after message is processed | ||
106 | * in order to move the queue pointers to next message. | ||
107 | * | ||
108 | * Input | ||
109 | * mq message queue | ||
110 | * | ||
111 | * Output: | ||
112 | * p pointer to message | ||
113 | * NULL no message available | ||
114 | */ | ||
115 | extern void *gru_get_next_message(void *mq); | ||
116 | |||
117 | |||
118 | /* | ||
119 | * Copy data using the GRU. Source or destination can be located in a remote | ||
120 | * partition. | ||
121 | * | ||
122 | * Input: | ||
123 | * dest_gpa destination global physical address | ||
124 | * src_gpa source global physical address | ||
125 | * bytes number of bytes to copy | ||
126 | * | ||
127 | * Output: | ||
128 | * 0 OK | ||
129 | * >0 error | ||
130 | */ | ||
131 | extern int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa, | ||
132 | unsigned int bytes); | ||
133 | |||
134 | #endif /* __GRU_KSERVICES_H_ */ | ||
diff --git a/drivers/misc/sgi-gru/grulib.h b/drivers/misc/sgi-gru/grulib.h new file mode 100644 index 000000000000..e56e196a6998 --- /dev/null +++ b/drivers/misc/sgi-gru/grulib.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU Lesser General Public License as published by | ||
6 | * the Free Software Foundation; either version 2.1 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU Lesser General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef __GRULIB_H__ | ||
20 | #define __GRULIB_H__ | ||
21 | |||
22 | #define GRU_BASENAME "gru" | ||
23 | #define GRU_FULLNAME "/dev/gru" | ||
24 | #define GRU_IOCTL_NUM 'G' | ||
25 | |||
26 | /* | ||
27 | * Maximum number of GRU segments that a user can have open | ||
28 | * ZZZ temp - set high for testing. Revisit. | ||
29 | */ | ||
30 | #define GRU_MAX_OPEN_CONTEXTS 32 | ||
31 | |||
32 | /* Set Number of Request Blocks */ | ||
33 | #define GRU_CREATE_CONTEXT _IOWR(GRU_IOCTL_NUM, 1, void *) | ||
34 | |||
35 | /* Register task as using the slice */ | ||
36 | #define GRU_SET_TASK_SLICE _IOWR(GRU_IOCTL_NUM, 5, void *) | ||
37 | |||
38 | /* Fetch exception detail */ | ||
39 | #define GRU_USER_GET_EXCEPTION_DETAIL _IOWR(GRU_IOCTL_NUM, 6, void *) | ||
40 | |||
41 | /* For user call_os handling - normally a TLB fault */ | ||
42 | #define GRU_USER_CALL_OS _IOWR(GRU_IOCTL_NUM, 8, void *) | ||
43 | |||
44 | /* For user unload context */ | ||
45 | #define GRU_USER_UNLOAD_CONTEXT _IOWR(GRU_IOCTL_NUM, 9, void *) | ||
46 | |||
47 | /* For fetching GRU chiplet status */ | ||
48 | #define GRU_GET_CHIPLET_STATUS _IOWR(GRU_IOCTL_NUM, 10, void *) | ||
49 | |||
50 | /* For user TLB flushing (primarily for tests) */ | ||
51 | #define GRU_USER_FLUSH_TLB _IOWR(GRU_IOCTL_NUM, 50, void *) | ||
52 | |||
53 | /* Get some config options (primarily for tests & emulator) */ | ||
54 | #define GRU_GET_CONFIG_INFO _IOWR(GRU_IOCTL_NUM, 51, void *) | ||
55 | |||
56 | #define CONTEXT_WINDOW_BYTES(th) (GRU_GSEG_PAGESIZE * (th)) | ||
57 | #define THREAD_POINTER(p, th) (p + GRU_GSEG_PAGESIZE * (th)) | ||
58 | |||
59 | /* | ||
60 | * Structure used to pass TLB flush parameters to the driver | ||
61 | */ | ||
62 | struct gru_create_context_req { | ||
63 | unsigned long gseg; | ||
64 | unsigned int data_segment_bytes; | ||
65 | unsigned int control_blocks; | ||
66 | unsigned int maximum_thread_count; | ||
67 | unsigned int options; | ||
68 | }; | ||
69 | |||
70 | /* | ||
71 | * Structure used to pass unload context parameters to the driver | ||
72 | */ | ||
73 | struct gru_unload_context_req { | ||
74 | unsigned long gseg; | ||
75 | }; | ||
76 | |||
77 | /* | ||
78 | * Structure used to pass TLB flush parameters to the driver | ||
79 | */ | ||
80 | struct gru_flush_tlb_req { | ||
81 | unsigned long gseg; | ||
82 | unsigned long vaddr; | ||
83 | size_t len; | ||
84 | }; | ||
85 | |||
86 | /* | ||
87 | * GRU configuration info (temp - for testing) | ||
88 | */ | ||
89 | struct gru_config_info { | ||
90 | int cpus; | ||
91 | int blades; | ||
92 | int nodes; | ||
93 | int chiplets; | ||
94 | int fill[16]; | ||
95 | }; | ||
96 | |||
97 | #endif /* __GRULIB_H__ */ | ||
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c new file mode 100644 index 000000000000..0eeb8dddd2f5 --- /dev/null +++ b/drivers/misc/sgi-gru/grumain.c | |||
@@ -0,0 +1,802 @@ | |||
1 | /* | ||
2 | * SN Platform GRU Driver | ||
3 | * | ||
4 | * DRIVER TABLE MANAGER + GRU CONTEXT LOAD/UNLOAD | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | * | ||
10 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <asm/uv/uv_hub.h> | ||
21 | #include "gru.h" | ||
22 | #include "grutables.h" | ||
23 | #include "gruhandles.h" | ||
24 | |||
25 | unsigned long gru_options __read_mostly; | ||
26 | |||
27 | static struct device_driver gru_driver = { | ||
28 | .name = "gru" | ||
29 | }; | ||
30 | |||
31 | static struct device gru_device = { | ||
32 | .bus_id = {0}, | ||
33 | .driver = &gru_driver, | ||
34 | }; | ||
35 | |||
36 | struct device *grudev = &gru_device; | ||
37 | |||
38 | /* | ||
39 | * Select a gru fault map to be used by the current cpu. Note that | ||
40 | * multiple cpus may be using the same map. | ||
41 | * ZZZ should "shift" be used?? Depends on HT cpu numbering | ||
42 | * ZZZ should be inline but did not work on emulator | ||
43 | */ | ||
44 | int gru_cpu_fault_map_id(void) | ||
45 | { | ||
46 | return uv_blade_processor_id() % GRU_NUM_TFM; | ||
47 | } | ||
48 | |||
49 | /*--------- ASID Management ------------------------------------------- | ||
50 | * | ||
51 | * Initially, assign asids sequentially from MIN_ASID .. MAX_ASID. | ||
52 | * Once MAX is reached, flush the TLB & start over. However, | ||
53 | * some asids may still be in use. There won't be many (percentage wise) still | ||
54 | * in use. Search active contexts & determine the value of the first | ||
55 | * asid in use ("x"s below). Set "limit" to this value. | ||
56 | * This defines a block of assignable asids. | ||
57 | * | ||
58 | * When "limit" is reached, search forward from limit+1 and determine the | ||
59 | * next block of assignable asids. | ||
60 | * | ||
61 | * Repeat until MAX_ASID is reached, then start over again. | ||
62 | * | ||
63 | * Each time MAX_ASID is reached, increment the asid generation. Since | ||
64 | * the search for in-use asids only checks contexts with GRUs currently | ||
65 | * assigned, asids in some contexts will be missed. Prior to loading | ||
66 | * a context, the asid generation of the GTS asid is rechecked. If it | ||
67 | * doesn't match the current generation, a new asid will be assigned. | ||
68 | * | ||
69 | * 0---------------x------------x---------------------x----| | ||
70 | * ^-next ^-limit ^-MAX_ASID | ||
71 | * | ||
72 | * All asid manipulation & context loading/unloading is protected by the | ||
73 | * gs_lock. | ||
74 | */ | ||
75 | |||
76 | /* Hit the asid limit. Start over */ | ||
77 | static int gru_wrap_asid(struct gru_state *gru) | ||
78 | { | ||
79 | gru_dbg(grudev, "gru %p\n", gru); | ||
80 | STAT(asid_wrap); | ||
81 | gru->gs_asid_gen++; | ||
82 | gru_flush_all_tlb(gru); | ||
83 | return MIN_ASID; | ||
84 | } | ||
85 | |||
86 | /* Find the next chunk of unused asids */ | ||
87 | static int gru_reset_asid_limit(struct gru_state *gru, int asid) | ||
88 | { | ||
89 | int i, gid, inuse_asid, limit; | ||
90 | |||
91 | gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); | ||
92 | STAT(asid_next); | ||
93 | limit = MAX_ASID; | ||
94 | if (asid >= limit) | ||
95 | asid = gru_wrap_asid(gru); | ||
96 | gid = gru->gs_gid; | ||
97 | again: | ||
98 | for (i = 0; i < GRU_NUM_CCH; i++) { | ||
99 | if (!gru->gs_gts[i]) | ||
100 | continue; | ||
101 | inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid; | ||
102 | gru_dbg(grudev, "gru %p, inuse_asid 0x%x, cxtnum %d, gts %p\n", | ||
103 | gru, inuse_asid, i, gru->gs_gts[i]); | ||
104 | if (inuse_asid == asid) { | ||
105 | asid += ASID_INC; | ||
106 | if (asid >= limit) { | ||
107 | /* | ||
108 | * empty range: reset the range limit and | ||
109 | * start over | ||
110 | */ | ||
111 | limit = MAX_ASID; | ||
112 | if (asid >= MAX_ASID) | ||
113 | asid = gru_wrap_asid(gru); | ||
114 | goto again; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | if ((inuse_asid > asid) && (inuse_asid < limit)) | ||
119 | limit = inuse_asid; | ||
120 | } | ||
121 | gru->gs_asid_limit = limit; | ||
122 | gru->gs_asid = asid; | ||
123 | gru_dbg(grudev, "gru %p, new asid 0x%x, new_limit 0x%x\n", gru, asid, | ||
124 | limit); | ||
125 | return asid; | ||
126 | } | ||
127 | |||
128 | /* Assign a new ASID to a thread context. */ | ||
129 | static int gru_assign_asid(struct gru_state *gru) | ||
130 | { | ||
131 | int asid; | ||
132 | |||
133 | spin_lock(&gru->gs_asid_lock); | ||
134 | gru->gs_asid += ASID_INC; | ||
135 | asid = gru->gs_asid; | ||
136 | if (asid >= gru->gs_asid_limit) | ||
137 | asid = gru_reset_asid_limit(gru, asid); | ||
138 | spin_unlock(&gru->gs_asid_lock); | ||
139 | |||
140 | gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); | ||
141 | return asid; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Clear n bits in a word. Return a word indicating the bits that were cleared. | ||
146 | * Optionally, build an array of chars that contain the bit numbers allocated. | ||
147 | */ | ||
148 | static unsigned long reserve_resources(unsigned long *p, int n, int mmax, | ||
149 | char *idx) | ||
150 | { | ||
151 | unsigned long bits = 0; | ||
152 | int i; | ||
153 | |||
154 | do { | ||
155 | i = find_first_bit(p, mmax); | ||
156 | if (i == mmax) | ||
157 | BUG(); | ||
158 | __clear_bit(i, p); | ||
159 | __set_bit(i, &bits); | ||
160 | if (idx) | ||
161 | *idx++ = i; | ||
162 | } while (--n); | ||
163 | return bits; | ||
164 | } | ||
165 | |||
166 | unsigned long gru_reserve_cb_resources(struct gru_state *gru, int cbr_au_count, | ||
167 | char *cbmap) | ||
168 | { | ||
169 | return reserve_resources(&gru->gs_cbr_map, cbr_au_count, GRU_CBR_AU, | ||
170 | cbmap); | ||
171 | } | ||
172 | |||
173 | unsigned long gru_reserve_ds_resources(struct gru_state *gru, int dsr_au_count, | ||
174 | char *dsmap) | ||
175 | { | ||
176 | return reserve_resources(&gru->gs_dsr_map, dsr_au_count, GRU_DSR_AU, | ||
177 | dsmap); | ||
178 | } | ||
179 | |||
180 | static void reserve_gru_resources(struct gru_state *gru, | ||
181 | struct gru_thread_state *gts) | ||
182 | { | ||
183 | gru->gs_active_contexts++; | ||
184 | gts->ts_cbr_map = | ||
185 | gru_reserve_cb_resources(gru, gts->ts_cbr_au_count, | ||
186 | gts->ts_cbr_idx); | ||
187 | gts->ts_dsr_map = | ||
188 | gru_reserve_ds_resources(gru, gts->ts_dsr_au_count, NULL); | ||
189 | } | ||
190 | |||
191 | static void free_gru_resources(struct gru_state *gru, | ||
192 | struct gru_thread_state *gts) | ||
193 | { | ||
194 | gru->gs_active_contexts--; | ||
195 | gru->gs_cbr_map |= gts->ts_cbr_map; | ||
196 | gru->gs_dsr_map |= gts->ts_dsr_map; | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Check if a GRU has sufficient free resources to satisfy an allocation | ||
201 | * request. Note: GRU locks may or may not be held when this is called. If | ||
202 | * not held, recheck after acquiring the appropriate locks. | ||
203 | * | ||
204 | * Returns 1 if sufficient resources, 0 if not | ||
205 | */ | ||
206 | static int check_gru_resources(struct gru_state *gru, int cbr_au_count, | ||
207 | int dsr_au_count, int max_active_contexts) | ||
208 | { | ||
209 | return hweight64(gru->gs_cbr_map) >= cbr_au_count | ||
210 | && hweight64(gru->gs_dsr_map) >= dsr_au_count | ||
211 | && gru->gs_active_contexts < max_active_contexts; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * TLB manangment requires tracking all GRU chiplets that have loaded a GSEG | ||
216 | * context. | ||
217 | */ | ||
218 | static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms, | ||
219 | int ctxnum) | ||
220 | { | ||
221 | struct gru_mm_tracker *asids = &gms->ms_asids[gru->gs_gid]; | ||
222 | unsigned short ctxbitmap = (1 << ctxnum); | ||
223 | int asid; | ||
224 | |||
225 | spin_lock(&gms->ms_asid_lock); | ||
226 | asid = asids->mt_asid; | ||
227 | |||
228 | if (asid == 0 || asids->mt_asid_gen != gru->gs_asid_gen) { | ||
229 | asid = gru_assign_asid(gru); | ||
230 | asids->mt_asid = asid; | ||
231 | asids->mt_asid_gen = gru->gs_asid_gen; | ||
232 | STAT(asid_new); | ||
233 | } else { | ||
234 | STAT(asid_reuse); | ||
235 | } | ||
236 | |||
237 | BUG_ON(asids->mt_ctxbitmap & ctxbitmap); | ||
238 | asids->mt_ctxbitmap |= ctxbitmap; | ||
239 | if (!test_bit(gru->gs_gid, gms->ms_asidmap)) | ||
240 | __set_bit(gru->gs_gid, gms->ms_asidmap); | ||
241 | spin_unlock(&gms->ms_asid_lock); | ||
242 | |||
243 | gru_dbg(grudev, | ||
244 | "gru %x, gms %p, ctxnum 0x%d, asid 0x%x, asidmap 0x%lx\n", | ||
245 | gru->gs_gid, gms, ctxnum, asid, gms->ms_asidmap[0]); | ||
246 | return asid; | ||
247 | } | ||
248 | |||
249 | static void gru_unload_mm_tracker(struct gru_state *gru, | ||
250 | struct gru_mm_struct *gms, int ctxnum) | ||
251 | { | ||
252 | struct gru_mm_tracker *asids; | ||
253 | unsigned short ctxbitmap; | ||
254 | |||
255 | asids = &gms->ms_asids[gru->gs_gid]; | ||
256 | ctxbitmap = (1 << ctxnum); | ||
257 | spin_lock(&gms->ms_asid_lock); | ||
258 | BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap); | ||
259 | asids->mt_ctxbitmap ^= ctxbitmap; | ||
260 | gru_dbg(grudev, "gru %x, gms %p, ctxnum 0x%d, asidmap 0x%lx\n", | ||
261 | gru->gs_gid, gms, ctxnum, gms->ms_asidmap[0]); | ||
262 | spin_unlock(&gms->ms_asid_lock); | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Decrement the reference count on a GTS structure. Free the structure | ||
267 | * if the reference count goes to zero. | ||
268 | */ | ||
269 | void gts_drop(struct gru_thread_state *gts) | ||
270 | { | ||
271 | if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { | ||
272 | gru_drop_mmu_notifier(gts->ts_gms); | ||
273 | kfree(gts); | ||
274 | STAT(gts_free); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * Locate the GTS structure for the current thread. | ||
280 | */ | ||
281 | static struct gru_thread_state *gru_find_current_gts_nolock(struct gru_vma_data | ||
282 | *vdata, int tsid) | ||
283 | { | ||
284 | struct gru_thread_state *gts; | ||
285 | |||
286 | list_for_each_entry(gts, &vdata->vd_head, ts_next) | ||
287 | if (gts->ts_tsid == tsid) | ||
288 | return gts; | ||
289 | return NULL; | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * Allocate a thread state structure. | ||
294 | */ | ||
295 | static struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | ||
296 | struct gru_vma_data *vdata, | ||
297 | int tsid) | ||
298 | { | ||
299 | struct gru_thread_state *gts; | ||
300 | int bytes; | ||
301 | |||
302 | bytes = DSR_BYTES(vdata->vd_dsr_au_count) + | ||
303 | CBR_BYTES(vdata->vd_cbr_au_count); | ||
304 | bytes += sizeof(struct gru_thread_state); | ||
305 | gts = kzalloc(bytes, GFP_KERNEL); | ||
306 | if (!gts) | ||
307 | return NULL; | ||
308 | |||
309 | STAT(gts_alloc); | ||
310 | atomic_set(>s->ts_refcnt, 1); | ||
311 | mutex_init(>s->ts_ctxlock); | ||
312 | gts->ts_cbr_au_count = vdata->vd_cbr_au_count; | ||
313 | gts->ts_dsr_au_count = vdata->vd_dsr_au_count; | ||
314 | gts->ts_user_options = vdata->vd_user_options; | ||
315 | gts->ts_tsid = tsid; | ||
316 | gts->ts_user_options = vdata->vd_user_options; | ||
317 | gts->ts_ctxnum = NULLCTX; | ||
318 | gts->ts_mm = current->mm; | ||
319 | gts->ts_vma = vma; | ||
320 | gts->ts_tlb_int_select = -1; | ||
321 | gts->ts_gms = gru_register_mmu_notifier(); | ||
322 | if (!gts->ts_gms) | ||
323 | goto err; | ||
324 | |||
325 | gru_dbg(grudev, "alloc vdata %p, new gts %p\n", vdata, gts); | ||
326 | return gts; | ||
327 | |||
328 | err: | ||
329 | gts_drop(gts); | ||
330 | return NULL; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Allocate a vma private data structure. | ||
335 | */ | ||
336 | struct gru_vma_data *gru_alloc_vma_data(struct vm_area_struct *vma, int tsid) | ||
337 | { | ||
338 | struct gru_vma_data *vdata = NULL; | ||
339 | |||
340 | vdata = kmalloc(sizeof(*vdata), GFP_KERNEL); | ||
341 | if (!vdata) | ||
342 | return NULL; | ||
343 | |||
344 | INIT_LIST_HEAD(&vdata->vd_head); | ||
345 | spin_lock_init(&vdata->vd_lock); | ||
346 | gru_dbg(grudev, "alloc vdata %p\n", vdata); | ||
347 | return vdata; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * Find the thread state structure for the current thread. | ||
352 | */ | ||
353 | struct gru_thread_state *gru_find_thread_state(struct vm_area_struct *vma, | ||
354 | int tsid) | ||
355 | { | ||
356 | struct gru_vma_data *vdata = vma->vm_private_data; | ||
357 | struct gru_thread_state *gts; | ||
358 | |||
359 | spin_lock(&vdata->vd_lock); | ||
360 | gts = gru_find_current_gts_nolock(vdata, tsid); | ||
361 | spin_unlock(&vdata->vd_lock); | ||
362 | gru_dbg(grudev, "vma %p, gts %p\n", vma, gts); | ||
363 | return gts; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * Allocate a new thread state for a GSEG. Note that races may allow | ||
368 | * another thread to race to create a gts. | ||
369 | */ | ||
370 | struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, | ||
371 | int tsid) | ||
372 | { | ||
373 | struct gru_vma_data *vdata = vma->vm_private_data; | ||
374 | struct gru_thread_state *gts, *ngts; | ||
375 | |||
376 | gts = gru_alloc_gts(vma, vdata, tsid); | ||
377 | if (!gts) | ||
378 | return NULL; | ||
379 | |||
380 | spin_lock(&vdata->vd_lock); | ||
381 | ngts = gru_find_current_gts_nolock(vdata, tsid); | ||
382 | if (ngts) { | ||
383 | gts_drop(gts); | ||
384 | gts = ngts; | ||
385 | STAT(gts_double_allocate); | ||
386 | } else { | ||
387 | list_add(>s->ts_next, &vdata->vd_head); | ||
388 | } | ||
389 | spin_unlock(&vdata->vd_lock); | ||
390 | gru_dbg(grudev, "vma %p, gts %p\n", vma, gts); | ||
391 | return gts; | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * Free the GRU context assigned to the thread state. | ||
396 | */ | ||
397 | static void gru_free_gru_context(struct gru_thread_state *gts) | ||
398 | { | ||
399 | struct gru_state *gru; | ||
400 | |||
401 | gru = gts->ts_gru; | ||
402 | gru_dbg(grudev, "gts %p, gru %p\n", gts, gru); | ||
403 | |||
404 | spin_lock(&gru->gs_lock); | ||
405 | gru->gs_gts[gts->ts_ctxnum] = NULL; | ||
406 | free_gru_resources(gru, gts); | ||
407 | BUG_ON(test_bit(gts->ts_ctxnum, &gru->gs_context_map) == 0); | ||
408 | __clear_bit(gts->ts_ctxnum, &gru->gs_context_map); | ||
409 | gts->ts_ctxnum = NULLCTX; | ||
410 | gts->ts_gru = NULL; | ||
411 | spin_unlock(&gru->gs_lock); | ||
412 | |||
413 | gts_drop(gts); | ||
414 | STAT(free_context); | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * Prefetching cachelines help hardware performance. | ||
419 | * (Strictly a performance enhancement. Not functionally required). | ||
420 | */ | ||
421 | static void prefetch_data(void *p, int num, int stride) | ||
422 | { | ||
423 | while (num-- > 0) { | ||
424 | prefetchw(p); | ||
425 | p += stride; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | static inline long gru_copy_handle(void *d, void *s) | ||
430 | { | ||
431 | memcpy(d, s, GRU_HANDLE_BYTES); | ||
432 | return GRU_HANDLE_BYTES; | ||
433 | } | ||
434 | |||
435 | /* rewrite in assembly & use lots of prefetch */ | ||
436 | static void gru_load_context_data(void *save, void *grubase, int ctxnum, | ||
437 | unsigned long cbrmap, unsigned long dsrmap) | ||
438 | { | ||
439 | void *gseg, *cb, *cbe; | ||
440 | unsigned long length; | ||
441 | int i, scr; | ||
442 | |||
443 | gseg = grubase + ctxnum * GRU_GSEG_STRIDE; | ||
444 | length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; | ||
445 | prefetch_data(gseg + GRU_DS_BASE, length / GRU_CACHE_LINE_BYTES, | ||
446 | GRU_CACHE_LINE_BYTES); | ||
447 | |||
448 | cb = gseg + GRU_CB_BASE; | ||
449 | cbe = grubase + GRU_CBE_BASE; | ||
450 | for_each_cbr_in_allocation_map(i, &cbrmap, scr) { | ||
451 | prefetch_data(cb, 1, GRU_CACHE_LINE_BYTES); | ||
452 | prefetch_data(cbe + i * GRU_HANDLE_STRIDE, 1, | ||
453 | GRU_CACHE_LINE_BYTES); | ||
454 | cb += GRU_HANDLE_STRIDE; | ||
455 | } | ||
456 | |||
457 | cb = gseg + GRU_CB_BASE; | ||
458 | for_each_cbr_in_allocation_map(i, &cbrmap, scr) { | ||
459 | save += gru_copy_handle(cb, save); | ||
460 | save += gru_copy_handle(cbe + i * GRU_HANDLE_STRIDE, save); | ||
461 | cb += GRU_HANDLE_STRIDE; | ||
462 | } | ||
463 | |||
464 | memcpy(gseg + GRU_DS_BASE, save, length); | ||
465 | } | ||
466 | |||
467 | static void gru_unload_context_data(void *save, void *grubase, int ctxnum, | ||
468 | unsigned long cbrmap, unsigned long dsrmap) | ||
469 | { | ||
470 | void *gseg, *cb, *cbe; | ||
471 | unsigned long length; | ||
472 | int i, scr; | ||
473 | |||
474 | gseg = grubase + ctxnum * GRU_GSEG_STRIDE; | ||
475 | |||
476 | cb = gseg + GRU_CB_BASE; | ||
477 | cbe = grubase + GRU_CBE_BASE; | ||
478 | for_each_cbr_in_allocation_map(i, &cbrmap, scr) { | ||
479 | save += gru_copy_handle(save, cb); | ||
480 | save += gru_copy_handle(save, cbe + i * GRU_HANDLE_STRIDE); | ||
481 | cb += GRU_HANDLE_STRIDE; | ||
482 | } | ||
483 | length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; | ||
484 | memcpy(save, gseg + GRU_DS_BASE, length); | ||
485 | } | ||
486 | |||
487 | void gru_unload_context(struct gru_thread_state *gts, int savestate) | ||
488 | { | ||
489 | struct gru_state *gru = gts->ts_gru; | ||
490 | struct gru_context_configuration_handle *cch; | ||
491 | int ctxnum = gts->ts_ctxnum; | ||
492 | |||
493 | zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); | ||
494 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); | ||
495 | |||
496 | lock_cch_handle(cch); | ||
497 | if (cch_interrupt_sync(cch)) | ||
498 | BUG(); | ||
499 | gru_dbg(grudev, "gts %p\n", gts); | ||
500 | |||
501 | gru_unload_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); | ||
502 | if (savestate) | ||
503 | gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, | ||
504 | ctxnum, gts->ts_cbr_map, | ||
505 | gts->ts_dsr_map); | ||
506 | |||
507 | if (cch_deallocate(cch)) | ||
508 | BUG(); | ||
509 | gts->ts_force_unload = 0; /* ts_force_unload locked by CCH lock */ | ||
510 | unlock_cch_handle(cch); | ||
511 | |||
512 | gru_free_gru_context(gts); | ||
513 | STAT(unload_context); | ||
514 | } | ||
515 | |||
516 | /* | ||
517 | * Load a GRU context by copying it from the thread data structure in memory | ||
518 | * to the GRU. | ||
519 | */ | ||
520 | static void gru_load_context(struct gru_thread_state *gts) | ||
521 | { | ||
522 | struct gru_state *gru = gts->ts_gru; | ||
523 | struct gru_context_configuration_handle *cch; | ||
524 | int err, asid, ctxnum = gts->ts_ctxnum; | ||
525 | |||
526 | gru_dbg(grudev, "gts %p\n", gts); | ||
527 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); | ||
528 | |||
529 | lock_cch_handle(cch); | ||
530 | asid = gru_load_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); | ||
531 | cch->tfm_fault_bit_enable = | ||
532 | (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL | ||
533 | || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); | ||
534 | cch->tlb_int_enable = (gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); | ||
535 | if (cch->tlb_int_enable) { | ||
536 | gts->ts_tlb_int_select = gru_cpu_fault_map_id(); | ||
537 | cch->tlb_int_select = gts->ts_tlb_int_select; | ||
538 | } | ||
539 | cch->tfm_done_bit_enable = 0; | ||
540 | err = cch_allocate(cch, asid, gts->ts_cbr_map, gts->ts_dsr_map); | ||
541 | if (err) { | ||
542 | gru_dbg(grudev, | ||
543 | "err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n", | ||
544 | err, cch, gts, gts->ts_cbr_map, gts->ts_dsr_map); | ||
545 | BUG(); | ||
546 | } | ||
547 | |||
548 | gru_load_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, ctxnum, | ||
549 | gts->ts_cbr_map, gts->ts_dsr_map); | ||
550 | |||
551 | if (cch_start(cch)) | ||
552 | BUG(); | ||
553 | unlock_cch_handle(cch); | ||
554 | |||
555 | STAT(load_context); | ||
556 | } | ||
557 | |||
558 | /* | ||
559 | * Update fields in an active CCH: | ||
560 | * - retarget interrupts on local blade | ||
561 | * - force a delayed context unload by clearing the CCH asids. This | ||
562 | * forces TLB misses for new GRU instructions. The context is unloaded | ||
563 | * when the next TLB miss occurs. | ||
564 | */ | ||
565 | static int gru_update_cch(struct gru_thread_state *gts, int int_select) | ||
566 | { | ||
567 | struct gru_context_configuration_handle *cch; | ||
568 | struct gru_state *gru = gts->ts_gru; | ||
569 | int i, ctxnum = gts->ts_ctxnum, ret = 0; | ||
570 | |||
571 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); | ||
572 | |||
573 | lock_cch_handle(cch); | ||
574 | if (cch->state == CCHSTATE_ACTIVE) { | ||
575 | if (gru->gs_gts[gts->ts_ctxnum] != gts) | ||
576 | goto exit; | ||
577 | if (cch_interrupt(cch)) | ||
578 | BUG(); | ||
579 | if (int_select >= 0) { | ||
580 | gts->ts_tlb_int_select = int_select; | ||
581 | cch->tlb_int_select = int_select; | ||
582 | } else { | ||
583 | for (i = 0; i < 8; i++) | ||
584 | cch->asid[i] = 0; | ||
585 | cch->tfm_fault_bit_enable = 0; | ||
586 | cch->tlb_int_enable = 0; | ||
587 | gts->ts_force_unload = 1; | ||
588 | } | ||
589 | if (cch_start(cch)) | ||
590 | BUG(); | ||
591 | ret = 1; | ||
592 | } | ||
593 | exit: | ||
594 | unlock_cch_handle(cch); | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * Update CCH tlb interrupt select. Required when all the following is true: | ||
600 | * - task's GRU context is loaded into a GRU | ||
601 | * - task is using interrupt notification for TLB faults | ||
602 | * - task has migrated to a different cpu on the same blade where | ||
603 | * it was previously running. | ||
604 | */ | ||
605 | static int gru_retarget_intr(struct gru_thread_state *gts) | ||
606 | { | ||
607 | if (gts->ts_tlb_int_select < 0 | ||
608 | || gts->ts_tlb_int_select == gru_cpu_fault_map_id()) | ||
609 | return 0; | ||
610 | |||
611 | gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select, | ||
612 | gru_cpu_fault_map_id()); | ||
613 | return gru_update_cch(gts, gru_cpu_fault_map_id()); | ||
614 | } | ||
615 | |||
616 | |||
617 | /* | ||
618 | * Insufficient GRU resources available on the local blade. Steal a context from | ||
619 | * a process. This is a hack until a _real_ resource scheduler is written.... | ||
620 | */ | ||
621 | #define next_ctxnum(n) ((n) < GRU_NUM_CCH - 2 ? (n) + 1 : 0) | ||
622 | #define next_gru(b, g) (((g) < &(b)->bs_grus[GRU_CHIPLETS_PER_BLADE - 1]) ? \ | ||
623 | ((g)+1) : &(b)->bs_grus[0]) | ||
624 | |||
625 | static void gru_steal_context(struct gru_thread_state *gts) | ||
626 | { | ||
627 | struct gru_blade_state *blade; | ||
628 | struct gru_state *gru, *gru0; | ||
629 | struct gru_thread_state *ngts = NULL; | ||
630 | int ctxnum, ctxnum0, flag = 0, cbr, dsr; | ||
631 | |||
632 | cbr = gts->ts_cbr_au_count; | ||
633 | dsr = gts->ts_dsr_au_count; | ||
634 | |||
635 | preempt_disable(); | ||
636 | blade = gru_base[uv_numa_blade_id()]; | ||
637 | spin_lock(&blade->bs_lock); | ||
638 | |||
639 | ctxnum = next_ctxnum(blade->bs_lru_ctxnum); | ||
640 | gru = blade->bs_lru_gru; | ||
641 | if (ctxnum == 0) | ||
642 | gru = next_gru(blade, gru); | ||
643 | ctxnum0 = ctxnum; | ||
644 | gru0 = gru; | ||
645 | while (1) { | ||
646 | if (check_gru_resources(gru, cbr, dsr, GRU_NUM_CCH)) | ||
647 | break; | ||
648 | spin_lock(&gru->gs_lock); | ||
649 | for (; ctxnum < GRU_NUM_CCH; ctxnum++) { | ||
650 | if (flag && gru == gru0 && ctxnum == ctxnum0) | ||
651 | break; | ||
652 | ngts = gru->gs_gts[ctxnum]; | ||
653 | /* | ||
654 | * We are grabbing locks out of order, so trylock is | ||
655 | * needed. GTSs are usually not locked, so the odds of | ||
656 | * success are high. If trylock fails, try to steal a | ||
657 | * different GSEG. | ||
658 | */ | ||
659 | if (ngts && mutex_trylock(&ngts->ts_ctxlock)) | ||
660 | break; | ||
661 | ngts = NULL; | ||
662 | flag = 1; | ||
663 | } | ||
664 | spin_unlock(&gru->gs_lock); | ||
665 | if (ngts || (flag && gru == gru0 && ctxnum == ctxnum0)) | ||
666 | break; | ||
667 | ctxnum = 0; | ||
668 | gru = next_gru(blade, gru); | ||
669 | } | ||
670 | blade->bs_lru_gru = gru; | ||
671 | blade->bs_lru_ctxnum = ctxnum; | ||
672 | spin_unlock(&blade->bs_lock); | ||
673 | preempt_enable(); | ||
674 | |||
675 | if (ngts) { | ||
676 | STAT(steal_context); | ||
677 | ngts->ts_steal_jiffies = jiffies; | ||
678 | gru_unload_context(ngts, 1); | ||
679 | mutex_unlock(&ngts->ts_ctxlock); | ||
680 | } else { | ||
681 | STAT(steal_context_failed); | ||
682 | } | ||
683 | gru_dbg(grudev, | ||
684 | "stole gru %x, ctxnum %d from gts %p. Need cb %d, ds %d;" | ||
685 | " avail cb %ld, ds %ld\n", | ||
686 | gru->gs_gid, ctxnum, ngts, cbr, dsr, hweight64(gru->gs_cbr_map), | ||
687 | hweight64(gru->gs_dsr_map)); | ||
688 | } | ||
689 | |||
690 | /* | ||
691 | * Scan the GRUs on the local blade & assign a GRU context. | ||
692 | */ | ||
693 | static struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts) | ||
694 | { | ||
695 | struct gru_state *gru, *grux; | ||
696 | int i, max_active_contexts; | ||
697 | |||
698 | preempt_disable(); | ||
699 | |||
700 | again: | ||
701 | gru = NULL; | ||
702 | max_active_contexts = GRU_NUM_CCH; | ||
703 | for_each_gru_on_blade(grux, uv_numa_blade_id(), i) { | ||
704 | if (check_gru_resources(grux, gts->ts_cbr_au_count, | ||
705 | gts->ts_dsr_au_count, | ||
706 | max_active_contexts)) { | ||
707 | gru = grux; | ||
708 | max_active_contexts = grux->gs_active_contexts; | ||
709 | if (max_active_contexts == 0) | ||
710 | break; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | if (gru) { | ||
715 | spin_lock(&gru->gs_lock); | ||
716 | if (!check_gru_resources(gru, gts->ts_cbr_au_count, | ||
717 | gts->ts_dsr_au_count, GRU_NUM_CCH)) { | ||
718 | spin_unlock(&gru->gs_lock); | ||
719 | goto again; | ||
720 | } | ||
721 | reserve_gru_resources(gru, gts); | ||
722 | gts->ts_gru = gru; | ||
723 | gts->ts_ctxnum = | ||
724 | find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH); | ||
725 | BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH); | ||
726 | atomic_inc(>s->ts_refcnt); | ||
727 | gru->gs_gts[gts->ts_ctxnum] = gts; | ||
728 | __set_bit(gts->ts_ctxnum, &gru->gs_context_map); | ||
729 | spin_unlock(&gru->gs_lock); | ||
730 | |||
731 | STAT(assign_context); | ||
732 | gru_dbg(grudev, | ||
733 | "gseg %p, gts %p, gru %x, ctx %d, cbr %d, dsr %d\n", | ||
734 | gseg_virtual_address(gts->ts_gru, gts->ts_ctxnum), gts, | ||
735 | gts->ts_gru->gs_gid, gts->ts_ctxnum, | ||
736 | gts->ts_cbr_au_count, gts->ts_dsr_au_count); | ||
737 | } else { | ||
738 | gru_dbg(grudev, "failed to allocate a GTS %s\n", ""); | ||
739 | STAT(assign_context_failed); | ||
740 | } | ||
741 | |||
742 | preempt_enable(); | ||
743 | return gru; | ||
744 | } | ||
745 | |||
746 | /* | ||
747 | * gru_nopage | ||
748 | * | ||
749 | * Map the user's GRU segment | ||
750 | * | ||
751 | * Note: gru segments alway mmaped on GRU_GSEG_PAGESIZE boundaries. | ||
752 | */ | ||
753 | int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
754 | { | ||
755 | struct gru_thread_state *gts; | ||
756 | unsigned long paddr, vaddr; | ||
757 | |||
758 | vaddr = (unsigned long)vmf->virtual_address; | ||
759 | gru_dbg(grudev, "vma %p, vaddr 0x%lx (0x%lx)\n", | ||
760 | vma, vaddr, GSEG_BASE(vaddr)); | ||
761 | STAT(nopfn); | ||
762 | |||
763 | /* The following check ensures vaddr is a valid address in the VMA */ | ||
764 | gts = gru_find_thread_state(vma, TSID(vaddr, vma)); | ||
765 | if (!gts) | ||
766 | return VM_FAULT_SIGBUS; | ||
767 | |||
768 | again: | ||
769 | preempt_disable(); | ||
770 | mutex_lock(>s->ts_ctxlock); | ||
771 | if (gts->ts_gru) { | ||
772 | if (gts->ts_gru->gs_blade_id != uv_numa_blade_id()) { | ||
773 | STAT(migrated_nopfn_unload); | ||
774 | gru_unload_context(gts, 1); | ||
775 | } else { | ||
776 | if (gru_retarget_intr(gts)) | ||
777 | STAT(migrated_nopfn_retarget); | ||
778 | } | ||
779 | } | ||
780 | |||
781 | if (!gts->ts_gru) { | ||
782 | if (!gru_assign_gru_context(gts)) { | ||
783 | mutex_unlock(>s->ts_ctxlock); | ||
784 | preempt_enable(); | ||
785 | schedule_timeout(GRU_ASSIGN_DELAY); /* true hack ZZZ */ | ||
786 | if (gts->ts_steal_jiffies + GRU_STEAL_DELAY < jiffies) | ||
787 | gru_steal_context(gts); | ||
788 | goto again; | ||
789 | } | ||
790 | gru_load_context(gts); | ||
791 | paddr = gseg_physical_address(gts->ts_gru, gts->ts_ctxnum); | ||
792 | remap_pfn_range(vma, vaddr & ~(GRU_GSEG_PAGESIZE - 1), | ||
793 | paddr >> PAGE_SHIFT, GRU_GSEG_PAGESIZE, | ||
794 | vma->vm_page_prot); | ||
795 | } | ||
796 | |||
797 | mutex_unlock(>s->ts_ctxlock); | ||
798 | preempt_enable(); | ||
799 | |||
800 | return VM_FAULT_NOPAGE; | ||
801 | } | ||
802 | |||
diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c new file mode 100644 index 000000000000..533923f83f1a --- /dev/null +++ b/drivers/misc/sgi-gru/gruprocfs.c | |||
@@ -0,0 +1,336 @@ | |||
1 | /* | ||
2 | * SN Platform GRU Driver | ||
3 | * | ||
4 | * PROC INTERFACES | ||
5 | * | ||
6 | * This file supports the /proc interfaces for the GRU driver | ||
7 | * | ||
8 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | #include <linux/proc_fs.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | #include <linux/uaccess.h> | ||
29 | #include "gru.h" | ||
30 | #include "grulib.h" | ||
31 | #include "grutables.h" | ||
32 | |||
33 | #define printstat(s, f) printstat_val(s, &gru_stats.f, #f) | ||
34 | |||
35 | static void printstat_val(struct seq_file *s, atomic_long_t *v, char *id) | ||
36 | { | ||
37 | unsigned long val = atomic_long_read(v); | ||
38 | |||
39 | if (val) | ||
40 | seq_printf(s, "%16lu %s\n", val, id); | ||
41 | } | ||
42 | |||
43 | static int statistics_show(struct seq_file *s, void *p) | ||
44 | { | ||
45 | printstat(s, vdata_alloc); | ||
46 | printstat(s, vdata_free); | ||
47 | printstat(s, gts_alloc); | ||
48 | printstat(s, gts_free); | ||
49 | printstat(s, vdata_double_alloc); | ||
50 | printstat(s, gts_double_allocate); | ||
51 | printstat(s, assign_context); | ||
52 | printstat(s, assign_context_failed); | ||
53 | printstat(s, free_context); | ||
54 | printstat(s, load_context); | ||
55 | printstat(s, unload_context); | ||
56 | printstat(s, steal_context); | ||
57 | printstat(s, steal_context_failed); | ||
58 | printstat(s, nopfn); | ||
59 | printstat(s, break_cow); | ||
60 | printstat(s, asid_new); | ||
61 | printstat(s, asid_next); | ||
62 | printstat(s, asid_wrap); | ||
63 | printstat(s, asid_reuse); | ||
64 | printstat(s, intr); | ||
65 | printstat(s, call_os); | ||
66 | printstat(s, call_os_check_for_bug); | ||
67 | printstat(s, call_os_wait_queue); | ||
68 | printstat(s, user_flush_tlb); | ||
69 | printstat(s, user_unload_context); | ||
70 | printstat(s, user_exception); | ||
71 | printstat(s, set_task_slice); | ||
72 | printstat(s, migrate_check); | ||
73 | printstat(s, migrated_retarget); | ||
74 | printstat(s, migrated_unload); | ||
75 | printstat(s, migrated_unload_delay); | ||
76 | printstat(s, migrated_nopfn_retarget); | ||
77 | printstat(s, migrated_nopfn_unload); | ||
78 | printstat(s, tlb_dropin); | ||
79 | printstat(s, tlb_dropin_fail_no_asid); | ||
80 | printstat(s, tlb_dropin_fail_upm); | ||
81 | printstat(s, tlb_dropin_fail_invalid); | ||
82 | printstat(s, tlb_dropin_fail_range_active); | ||
83 | printstat(s, tlb_dropin_fail_idle); | ||
84 | printstat(s, tlb_dropin_fail_fmm); | ||
85 | printstat(s, mmu_invalidate_range); | ||
86 | printstat(s, mmu_invalidate_page); | ||
87 | printstat(s, mmu_clear_flush_young); | ||
88 | printstat(s, flush_tlb); | ||
89 | printstat(s, flush_tlb_gru); | ||
90 | printstat(s, flush_tlb_gru_tgh); | ||
91 | printstat(s, flush_tlb_gru_zero_asid); | ||
92 | printstat(s, copy_gpa); | ||
93 | printstat(s, mesq_receive); | ||
94 | printstat(s, mesq_receive_none); | ||
95 | printstat(s, mesq_send); | ||
96 | printstat(s, mesq_send_failed); | ||
97 | printstat(s, mesq_noop); | ||
98 | printstat(s, mesq_send_unexpected_error); | ||
99 | printstat(s, mesq_send_lb_overflow); | ||
100 | printstat(s, mesq_send_qlimit_reached); | ||
101 | printstat(s, mesq_send_amo_nacked); | ||
102 | printstat(s, mesq_send_put_nacked); | ||
103 | printstat(s, mesq_qf_not_full); | ||
104 | printstat(s, mesq_qf_locked); | ||
105 | printstat(s, mesq_qf_noop_not_full); | ||
106 | printstat(s, mesq_qf_switch_head_failed); | ||
107 | printstat(s, mesq_qf_unexpected_error); | ||
108 | printstat(s, mesq_noop_unexpected_error); | ||
109 | printstat(s, mesq_noop_lb_overflow); | ||
110 | printstat(s, mesq_noop_qlimit_reached); | ||
111 | printstat(s, mesq_noop_amo_nacked); | ||
112 | printstat(s, mesq_noop_put_nacked); | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static ssize_t statistics_write(struct file *file, const char __user *userbuf, | ||
117 | size_t count, loff_t *data) | ||
118 | { | ||
119 | memset(&gru_stats, 0, sizeof(gru_stats)); | ||
120 | return count; | ||
121 | } | ||
122 | |||
123 | static int options_show(struct seq_file *s, void *p) | ||
124 | { | ||
125 | seq_printf(s, "0x%lx\n", gru_options); | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static ssize_t options_write(struct file *file, const char __user *userbuf, | ||
130 | size_t count, loff_t *data) | ||
131 | { | ||
132 | unsigned long val; | ||
133 | char buf[80]; | ||
134 | |||
135 | if (copy_from_user | ||
136 | (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf))) | ||
137 | return -EFAULT; | ||
138 | if (!strict_strtoul(buf, 10, &val)) | ||
139 | gru_options = val; | ||
140 | |||
141 | return count; | ||
142 | } | ||
143 | |||
144 | static int cch_seq_show(struct seq_file *file, void *data) | ||
145 | { | ||
146 | long gid = *(long *)data; | ||
147 | int i; | ||
148 | struct gru_state *gru = GID_TO_GRU(gid); | ||
149 | struct gru_thread_state *ts; | ||
150 | const char *mode[] = { "??", "UPM", "INTR", "OS_POLL" }; | ||
151 | |||
152 | if (gid == 0) | ||
153 | seq_printf(file, "#%5s%5s%6s%9s%6s%8s%8s\n", "gid", "bid", | ||
154 | "ctx#", "pid", "cbrs", "dsbytes", "mode"); | ||
155 | if (gru) | ||
156 | for (i = 0; i < GRU_NUM_CCH; i++) { | ||
157 | ts = gru->gs_gts[i]; | ||
158 | if (!ts) | ||
159 | continue; | ||
160 | seq_printf(file, " %5d%5d%6d%9d%6d%8d%8s\n", | ||
161 | gru->gs_gid, gru->gs_blade_id, i, | ||
162 | ts->ts_tgid_owner, | ||
163 | ts->ts_cbr_au_count * GRU_CBR_AU_SIZE, | ||
164 | ts->ts_cbr_au_count * GRU_DSR_AU_BYTES, | ||
165 | mode[ts->ts_user_options & | ||
166 | GRU_OPT_MISS_MASK]); | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int gru_seq_show(struct seq_file *file, void *data) | ||
173 | { | ||
174 | long gid = *(long *)data, ctxfree, cbrfree, dsrfree; | ||
175 | struct gru_state *gru = GID_TO_GRU(gid); | ||
176 | |||
177 | if (gid == 0) { | ||
178 | seq_printf(file, "#%5s%5s%7s%6s%6s%8s%6s%6s\n", "gid", "nid", | ||
179 | "ctx", "cbr", "dsr", "ctx", "cbr", "dsr"); | ||
180 | seq_printf(file, "#%5s%5s%7s%6s%6s%8s%6s%6s\n", "", "", "busy", | ||
181 | "busy", "busy", "free", "free", "free"); | ||
182 | } | ||
183 | if (gru) { | ||
184 | ctxfree = GRU_NUM_CCH - gru->gs_active_contexts; | ||
185 | cbrfree = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; | ||
186 | dsrfree = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES; | ||
187 | seq_printf(file, " %5d%5d%7ld%6ld%6ld%8ld%6ld%6ld\n", | ||
188 | gru->gs_gid, gru->gs_blade_id, GRU_NUM_CCH - ctxfree, | ||
189 | GRU_NUM_CBE - cbrfree, GRU_NUM_DSR_BYTES - dsrfree, | ||
190 | ctxfree, cbrfree, dsrfree); | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static void seq_stop(struct seq_file *file, void *data) | ||
197 | { | ||
198 | } | ||
199 | |||
200 | static void *seq_start(struct seq_file *file, loff_t *gid) | ||
201 | { | ||
202 | if (*gid < GRU_MAX_GRUS) | ||
203 | return gid; | ||
204 | return NULL; | ||
205 | } | ||
206 | |||
207 | static void *seq_next(struct seq_file *file, void *data, loff_t *gid) | ||
208 | { | ||
209 | (*gid)++; | ||
210 | if (*gid < GRU_MAX_GRUS) | ||
211 | return gid; | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | static const struct seq_operations cch_seq_ops = { | ||
216 | .start = seq_start, | ||
217 | .next = seq_next, | ||
218 | .stop = seq_stop, | ||
219 | .show = cch_seq_show | ||
220 | }; | ||
221 | |||
222 | static const struct seq_operations gru_seq_ops = { | ||
223 | .start = seq_start, | ||
224 | .next = seq_next, | ||
225 | .stop = seq_stop, | ||
226 | .show = gru_seq_show | ||
227 | }; | ||
228 | |||
229 | static int statistics_open(struct inode *inode, struct file *file) | ||
230 | { | ||
231 | return single_open(file, statistics_show, NULL); | ||
232 | } | ||
233 | |||
234 | static int options_open(struct inode *inode, struct file *file) | ||
235 | { | ||
236 | return single_open(file, options_show, NULL); | ||
237 | } | ||
238 | |||
239 | static int cch_open(struct inode *inode, struct file *file) | ||
240 | { | ||
241 | return seq_open(file, &cch_seq_ops); | ||
242 | } | ||
243 | |||
244 | static int gru_open(struct inode *inode, struct file *file) | ||
245 | { | ||
246 | return seq_open(file, &gru_seq_ops); | ||
247 | } | ||
248 | |||
249 | /* *INDENT-OFF* */ | ||
250 | static const struct file_operations statistics_fops = { | ||
251 | .open = statistics_open, | ||
252 | .read = seq_read, | ||
253 | .write = statistics_write, | ||
254 | .llseek = seq_lseek, | ||
255 | .release = single_release, | ||
256 | }; | ||
257 | |||
258 | static const struct file_operations options_fops = { | ||
259 | .open = options_open, | ||
260 | .read = seq_read, | ||
261 | .write = options_write, | ||
262 | .llseek = seq_lseek, | ||
263 | .release = single_release, | ||
264 | }; | ||
265 | |||
266 | static const struct file_operations cch_fops = { | ||
267 | .open = cch_open, | ||
268 | .read = seq_read, | ||
269 | .llseek = seq_lseek, | ||
270 | .release = seq_release, | ||
271 | }; | ||
272 | static const struct file_operations gru_fops = { | ||
273 | .open = gru_open, | ||
274 | .read = seq_read, | ||
275 | .llseek = seq_lseek, | ||
276 | .release = seq_release, | ||
277 | }; | ||
278 | |||
279 | static struct proc_entry { | ||
280 | char *name; | ||
281 | int mode; | ||
282 | const struct file_operations *fops; | ||
283 | struct proc_dir_entry *entry; | ||
284 | } proc_files[] = { | ||
285 | {"statistics", 0644, &statistics_fops}, | ||
286 | {"debug_options", 0644, &options_fops}, | ||
287 | {"cch_status", 0444, &cch_fops}, | ||
288 | {"gru_status", 0444, &gru_fops}, | ||
289 | {NULL} | ||
290 | }; | ||
291 | /* *INDENT-ON* */ | ||
292 | |||
293 | static struct proc_dir_entry *proc_gru __read_mostly; | ||
294 | |||
295 | static int create_proc_file(struct proc_entry *p) | ||
296 | { | ||
297 | p->entry = create_proc_entry(p->name, p->mode, proc_gru); | ||
298 | if (!p->entry) | ||
299 | return -1; | ||
300 | p->entry->proc_fops = p->fops; | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static void delete_proc_files(void) | ||
305 | { | ||
306 | struct proc_entry *p; | ||
307 | |||
308 | if (proc_gru) { | ||
309 | for (p = proc_files; p->name; p++) | ||
310 | if (p->entry) | ||
311 | remove_proc_entry(p->name, proc_gru); | ||
312 | remove_proc_entry("gru", NULL); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | int gru_proc_init(void) | ||
317 | { | ||
318 | struct proc_entry *p; | ||
319 | |||
320 | proc_mkdir("sgi_uv", NULL); | ||
321 | proc_gru = proc_mkdir("sgi_uv/gru", NULL); | ||
322 | |||
323 | for (p = proc_files; p->name; p++) | ||
324 | if (create_proc_file(p)) | ||
325 | goto err; | ||
326 | return 0; | ||
327 | |||
328 | err: | ||
329 | delete_proc_files(); | ||
330 | return -1; | ||
331 | } | ||
332 | |||
333 | void gru_proc_exit(void) | ||
334 | { | ||
335 | delete_proc_files(); | ||
336 | } | ||
diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h new file mode 100644 index 000000000000..4251018f70ff --- /dev/null +++ b/drivers/misc/sgi-gru/grutables.h | |||
@@ -0,0 +1,609 @@ | |||
1 | /* | ||
2 | * SN Platform GRU Driver | ||
3 | * | ||
4 | * GRU DRIVER TABLES, MACROS, externs, etc | ||
5 | * | ||
6 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #ifndef __GRUTABLES_H__ | ||
24 | #define __GRUTABLES_H__ | ||
25 | |||
26 | /* | ||
27 | * GRU Chiplet: | ||
28 | * The GRU is a user addressible memory accelerator. It provides | ||
29 | * several forms of load, store, memset, bcopy instructions. In addition, it | ||
30 | * contains special instructions for AMOs, sending messages to message | ||
31 | * queues, etc. | ||
32 | * | ||
33 | * The GRU is an integral part of the node controller. It connects | ||
34 | * directly to the cpu socket. In its current implementation, there are 2 | ||
35 | * GRU chiplets in the node controller on each blade (~node). | ||
36 | * | ||
37 | * The entire GRU memory space is fully coherent and cacheable by the cpus. | ||
38 | * | ||
39 | * Each GRU chiplet has a physical memory map that looks like the following: | ||
40 | * | ||
41 | * +-----------------+ | ||
42 | * |/////////////////| | ||
43 | * |/////////////////| | ||
44 | * |/////////////////| | ||
45 | * |/////////////////| | ||
46 | * |/////////////////| | ||
47 | * |/////////////////| | ||
48 | * |/////////////////| | ||
49 | * |/////////////////| | ||
50 | * +-----------------+ | ||
51 | * | system control | | ||
52 | * +-----------------+ _______ +-------------+ | ||
53 | * |/////////////////| / | | | ||
54 | * |/////////////////| / | | | ||
55 | * |/////////////////| / | instructions| | ||
56 | * |/////////////////| / | | | ||
57 | * |/////////////////| / | | | ||
58 | * |/////////////////| / |-------------| | ||
59 | * |/////////////////| / | | | ||
60 | * +-----------------+ | | | ||
61 | * | context 15 | | data | | ||
62 | * +-----------------+ | | | ||
63 | * | ...... | \ | | | ||
64 | * +-----------------+ \____________ +-------------+ | ||
65 | * | context 1 | | ||
66 | * +-----------------+ | ||
67 | * | context 0 | | ||
68 | * +-----------------+ | ||
69 | * | ||
70 | * Each of the "contexts" is a chunk of memory that can be mmaped into user | ||
71 | * space. The context consists of 2 parts: | ||
72 | * | ||
73 | * - an instruction space that can be directly accessed by the user | ||
74 | * to issue GRU instructions and to check instruction status. | ||
75 | * | ||
76 | * - a data area that acts as normal RAM. | ||
77 | * | ||
78 | * User instructions contain virtual addresses of data to be accessed by the | ||
79 | * GRU. The GRU contains a TLB that is used to convert these user virtual | ||
80 | * addresses to physical addresses. | ||
81 | * | ||
82 | * The "system control" area of the GRU chiplet is used by the kernel driver | ||
83 | * to manage user contexts and to perform functions such as TLB dropin and | ||
84 | * purging. | ||
85 | * | ||
86 | * One context may be reserved for the kernel and used for cross-partition | ||
87 | * communication. The GRU will also be used to asynchronously zero out | ||
88 | * large blocks of memory (not currently implemented). | ||
89 | * | ||
90 | * | ||
91 | * Tables: | ||
92 | * | ||
93 | * VDATA-VMA Data - Holds a few parameters. Head of linked list of | ||
94 | * GTS tables for threads using the GSEG | ||
95 | * GTS - Gru Thread State - contains info for managing a GSEG context. A | ||
96 | * GTS is allocated for each thread accessing a | ||
97 | * GSEG. | ||
98 | * GTD - GRU Thread Data - contains shadow copy of GRU data when GSEG is | ||
99 | * not loaded into a GRU | ||
100 | * GMS - GRU Memory Struct - Used to manage TLB shootdowns. Tracks GRUs | ||
101 | * where a GSEG has been loaded. Similar to | ||
102 | * an mm_struct but for GRU. | ||
103 | * | ||
104 | * GS - GRU State - Used to manage the state of a GRU chiplet | ||
105 | * BS - Blade State - Used to manage state of all GRU chiplets | ||
106 | * on a blade | ||
107 | * | ||
108 | * | ||
109 | * Normal task tables for task using GRU. | ||
110 | * - 2 threads in process | ||
111 | * - 2 GSEGs open in process | ||
112 | * - GSEG1 is being used by both threads | ||
113 | * - GSEG2 is used only by thread 2 | ||
114 | * | ||
115 | * task -->| | ||
116 | * task ---+---> mm ->------ (notifier) -------+-> gms | ||
117 | * | | | ||
118 | * |--> vma -> vdata ---> gts--->| GSEG1 (thread1) | ||
119 | * | | | | ||
120 | * | +-> gts--->| GSEG1 (thread2) | ||
121 | * | | | ||
122 | * |--> vma -> vdata ---> gts--->| GSEG2 (thread2) | ||
123 | * . | ||
124 | * . | ||
125 | * | ||
126 | * GSEGs are marked DONTCOPY on fork | ||
127 | * | ||
128 | * At open | ||
129 | * file.private_data -> NULL | ||
130 | * | ||
131 | * At mmap, | ||
132 | * vma -> vdata | ||
133 | * | ||
134 | * After gseg reference | ||
135 | * vma -> vdata ->gts | ||
136 | * | ||
137 | * After fork | ||
138 | * parent | ||
139 | * vma -> vdata -> gts | ||
140 | * child | ||
141 | * (vma is not copied) | ||
142 | * | ||
143 | */ | ||
144 | |||
145 | #include <linux/rmap.h> | ||
146 | #include <linux/interrupt.h> | ||
147 | #include <linux/mutex.h> | ||
148 | #include <linux/wait.h> | ||
149 | #include <linux/mmu_notifier.h> | ||
150 | #include "gru.h" | ||
151 | #include "gruhandles.h" | ||
152 | |||
153 | extern struct gru_stats_s gru_stats; | ||
154 | extern struct gru_blade_state *gru_base[]; | ||
155 | extern unsigned long gru_start_paddr, gru_end_paddr; | ||
156 | |||
157 | #define GRU_MAX_BLADES MAX_NUMNODES | ||
158 | #define GRU_MAX_GRUS (GRU_MAX_BLADES * GRU_CHIPLETS_PER_BLADE) | ||
159 | |||
160 | #define GRU_DRIVER_ID_STR "SGI GRU Device Driver" | ||
161 | #define GRU_DRIVER_VERSION_STR "0.80" | ||
162 | |||
163 | /* | ||
164 | * GRU statistics. | ||
165 | */ | ||
166 | struct gru_stats_s { | ||
167 | atomic_long_t vdata_alloc; | ||
168 | atomic_long_t vdata_free; | ||
169 | atomic_long_t gts_alloc; | ||
170 | atomic_long_t gts_free; | ||
171 | atomic_long_t vdata_double_alloc; | ||
172 | atomic_long_t gts_double_allocate; | ||
173 | atomic_long_t assign_context; | ||
174 | atomic_long_t assign_context_failed; | ||
175 | atomic_long_t free_context; | ||
176 | atomic_long_t load_context; | ||
177 | atomic_long_t unload_context; | ||
178 | atomic_long_t steal_context; | ||
179 | atomic_long_t steal_context_failed; | ||
180 | atomic_long_t nopfn; | ||
181 | atomic_long_t break_cow; | ||
182 | atomic_long_t asid_new; | ||
183 | atomic_long_t asid_next; | ||
184 | atomic_long_t asid_wrap; | ||
185 | atomic_long_t asid_reuse; | ||
186 | atomic_long_t intr; | ||
187 | atomic_long_t call_os; | ||
188 | atomic_long_t call_os_check_for_bug; | ||
189 | atomic_long_t call_os_wait_queue; | ||
190 | atomic_long_t user_flush_tlb; | ||
191 | atomic_long_t user_unload_context; | ||
192 | atomic_long_t user_exception; | ||
193 | atomic_long_t set_task_slice; | ||
194 | atomic_long_t migrate_check; | ||
195 | atomic_long_t migrated_retarget; | ||
196 | atomic_long_t migrated_unload; | ||
197 | atomic_long_t migrated_unload_delay; | ||
198 | atomic_long_t migrated_nopfn_retarget; | ||
199 | atomic_long_t migrated_nopfn_unload; | ||
200 | atomic_long_t tlb_dropin; | ||
201 | atomic_long_t tlb_dropin_fail_no_asid; | ||
202 | atomic_long_t tlb_dropin_fail_upm; | ||
203 | atomic_long_t tlb_dropin_fail_invalid; | ||
204 | atomic_long_t tlb_dropin_fail_range_active; | ||
205 | atomic_long_t tlb_dropin_fail_idle; | ||
206 | atomic_long_t tlb_dropin_fail_fmm; | ||
207 | atomic_long_t mmu_invalidate_range; | ||
208 | atomic_long_t mmu_invalidate_page; | ||
209 | atomic_long_t mmu_clear_flush_young; | ||
210 | atomic_long_t flush_tlb; | ||
211 | atomic_long_t flush_tlb_gru; | ||
212 | atomic_long_t flush_tlb_gru_tgh; | ||
213 | atomic_long_t flush_tlb_gru_zero_asid; | ||
214 | |||
215 | atomic_long_t copy_gpa; | ||
216 | |||
217 | atomic_long_t mesq_receive; | ||
218 | atomic_long_t mesq_receive_none; | ||
219 | atomic_long_t mesq_send; | ||
220 | atomic_long_t mesq_send_failed; | ||
221 | atomic_long_t mesq_noop; | ||
222 | atomic_long_t mesq_send_unexpected_error; | ||
223 | atomic_long_t mesq_send_lb_overflow; | ||
224 | atomic_long_t mesq_send_qlimit_reached; | ||
225 | atomic_long_t mesq_send_amo_nacked; | ||
226 | atomic_long_t mesq_send_put_nacked; | ||
227 | atomic_long_t mesq_qf_not_full; | ||
228 | atomic_long_t mesq_qf_locked; | ||
229 | atomic_long_t mesq_qf_noop_not_full; | ||
230 | atomic_long_t mesq_qf_switch_head_failed; | ||
231 | atomic_long_t mesq_qf_unexpected_error; | ||
232 | atomic_long_t mesq_noop_unexpected_error; | ||
233 | atomic_long_t mesq_noop_lb_overflow; | ||
234 | atomic_long_t mesq_noop_qlimit_reached; | ||
235 | atomic_long_t mesq_noop_amo_nacked; | ||
236 | atomic_long_t mesq_noop_put_nacked; | ||
237 | |||
238 | }; | ||
239 | |||
240 | #define OPT_DPRINT 1 | ||
241 | #define OPT_STATS 2 | ||
242 | #define GRU_QUICKLOOK 4 | ||
243 | |||
244 | |||
245 | #define IRQ_GRU 110 /* Starting IRQ number for interrupts */ | ||
246 | |||
247 | /* Delay in jiffies between attempts to assign a GRU context */ | ||
248 | #define GRU_ASSIGN_DELAY ((HZ * 20) / 1000) | ||
249 | |||
250 | /* | ||
251 | * If a process has it's context stolen, min delay in jiffies before trying to | ||
252 | * steal a context from another process. | ||
253 | */ | ||
254 | #define GRU_STEAL_DELAY ((HZ * 200) / 1000) | ||
255 | |||
256 | #define STAT(id) do { \ | ||
257 | if (gru_options & OPT_STATS) \ | ||
258 | atomic_long_inc(&gru_stats.id); \ | ||
259 | } while (0) | ||
260 | |||
261 | #ifdef CONFIG_SGI_GRU_DEBUG | ||
262 | #define gru_dbg(dev, fmt, x...) \ | ||
263 | do { \ | ||
264 | if (gru_options & OPT_DPRINT) \ | ||
265 | dev_dbg(dev, "%s: " fmt, __func__, x); \ | ||
266 | } while (0) | ||
267 | #else | ||
268 | #define gru_dbg(x...) | ||
269 | #endif | ||
270 | |||
271 | /*----------------------------------------------------------------------------- | ||
272 | * ASID management | ||
273 | */ | ||
274 | #define MAX_ASID 0xfffff0 | ||
275 | #define MIN_ASID 8 | ||
276 | #define ASID_INC 8 /* number of regions */ | ||
277 | |||
278 | /* Generate a GRU asid value from a GRU base asid & a virtual address. */ | ||
279 | #if defined CONFIG_IA64 | ||
280 | #define VADDR_HI_BIT 64 | ||
281 | #define GRUREGION(addr) ((addr) >> (VADDR_HI_BIT - 3) & 3) | ||
282 | #elif defined __x86_64 | ||
283 | #define VADDR_HI_BIT 48 | ||
284 | #define GRUREGION(addr) (0) /* ZZZ could do better */ | ||
285 | #else | ||
286 | #error "Unsupported architecture" | ||
287 | #endif | ||
288 | #define GRUASID(asid, addr) ((asid) + GRUREGION(addr)) | ||
289 | |||
290 | /*------------------------------------------------------------------------------ | ||
291 | * File & VMS Tables | ||
292 | */ | ||
293 | |||
294 | struct gru_state; | ||
295 | |||
296 | /* | ||
297 | * This structure is pointed to from the mmstruct via the notifier pointer. | ||
298 | * There is one of these per address space. | ||
299 | */ | ||
300 | struct gru_mm_tracker { | ||
301 | unsigned int mt_asid_gen; /* ASID wrap count */ | ||
302 | int mt_asid; /* current base ASID for gru */ | ||
303 | unsigned short mt_ctxbitmap; /* bitmap of contexts using | ||
304 | asid */ | ||
305 | }; | ||
306 | |||
307 | struct gru_mm_struct { | ||
308 | struct mmu_notifier ms_notifier; | ||
309 | atomic_t ms_refcnt; | ||
310 | spinlock_t ms_asid_lock; /* protects ASID assignment */ | ||
311 | atomic_t ms_range_active;/* num range_invals active */ | ||
312 | char ms_released; | ||
313 | wait_queue_head_t ms_wait_queue; | ||
314 | DECLARE_BITMAP(ms_asidmap, GRU_MAX_GRUS); | ||
315 | struct gru_mm_tracker ms_asids[GRU_MAX_GRUS]; | ||
316 | }; | ||
317 | |||
318 | /* | ||
319 | * One of these structures is allocated when a GSEG is mmaped. The | ||
320 | * structure is pointed to by the vma->vm_private_data field in the vma struct. | ||
321 | */ | ||
322 | struct gru_vma_data { | ||
323 | spinlock_t vd_lock; /* Serialize access to vma */ | ||
324 | struct list_head vd_head; /* head of linked list of gts */ | ||
325 | long vd_user_options;/* misc user option flags */ | ||
326 | int vd_cbr_au_count; | ||
327 | int vd_dsr_au_count; | ||
328 | }; | ||
329 | |||
330 | /* | ||
331 | * One of these is allocated for each thread accessing a mmaped GRU. A linked | ||
332 | * list of these structure is hung off the struct gru_vma_data in the mm_struct. | ||
333 | */ | ||
334 | struct gru_thread_state { | ||
335 | struct list_head ts_next; /* list - head at vma-private */ | ||
336 | struct mutex ts_ctxlock; /* load/unload CTX lock */ | ||
337 | struct mm_struct *ts_mm; /* mm currently mapped to | ||
338 | context */ | ||
339 | struct vm_area_struct *ts_vma; /* vma of GRU context */ | ||
340 | struct gru_state *ts_gru; /* GRU where the context is | ||
341 | loaded */ | ||
342 | struct gru_mm_struct *ts_gms; /* asid & ioproc struct */ | ||
343 | unsigned long ts_cbr_map; /* map of allocated CBRs */ | ||
344 | unsigned long ts_dsr_map; /* map of allocated DATA | ||
345 | resources */ | ||
346 | unsigned long ts_steal_jiffies;/* jiffies when context last | ||
347 | stolen */ | ||
348 | long ts_user_options;/* misc user option flags */ | ||
349 | pid_t ts_tgid_owner; /* task that is using the | ||
350 | context - for migration */ | ||
351 | int ts_tsid; /* thread that owns the | ||
352 | structure */ | ||
353 | int ts_tlb_int_select;/* target cpu if interrupts | ||
354 | enabled */ | ||
355 | int ts_ctxnum; /* context number where the | ||
356 | context is loaded */ | ||
357 | atomic_t ts_refcnt; /* reference count GTS */ | ||
358 | unsigned char ts_dsr_au_count;/* Number of DSR resources | ||
359 | required for contest */ | ||
360 | unsigned char ts_cbr_au_count;/* Number of CBR resources | ||
361 | required for contest */ | ||
362 | char ts_force_unload;/* force context to be unloaded | ||
363 | after migration */ | ||
364 | char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each | ||
365 | allocated CB */ | ||
366 | unsigned long ts_gdata[0]; /* save area for GRU data (CB, | ||
367 | DS, CBE) */ | ||
368 | }; | ||
369 | |||
370 | /* | ||
371 | * Threaded programs actually allocate an array of GSEGs when a context is | ||
372 | * created. Each thread uses a separate GSEG. TSID is the index into the GSEG | ||
373 | * array. | ||
374 | */ | ||
375 | #define TSID(a, v) (((a) - (v)->vm_start) / GRU_GSEG_PAGESIZE) | ||
376 | #define UGRUADDR(gts) ((gts)->ts_vma->vm_start + \ | ||
377 | (gts)->ts_tsid * GRU_GSEG_PAGESIZE) | ||
378 | |||
379 | #define NULLCTX (-1) /* if context not loaded into GRU */ | ||
380 | |||
381 | /*----------------------------------------------------------------------------- | ||
382 | * GRU State Tables | ||
383 | */ | ||
384 | |||
385 | /* | ||
386 | * One of these exists for each GRU chiplet. | ||
387 | */ | ||
388 | struct gru_state { | ||
389 | struct gru_blade_state *gs_blade; /* GRU state for entire | ||
390 | blade */ | ||
391 | unsigned long gs_gru_base_paddr; /* Physical address of | ||
392 | gru segments (64) */ | ||
393 | void *gs_gru_base_vaddr; /* Virtual address of | ||
394 | gru segments (64) */ | ||
395 | unsigned char gs_gid; /* unique GRU number */ | ||
396 | unsigned char gs_tgh_local_shift; /* used to pick TGH for | ||
397 | local flush */ | ||
398 | unsigned char gs_tgh_first_remote; /* starting TGH# for | ||
399 | remote flush */ | ||
400 | unsigned short gs_blade_id; /* blade of GRU */ | ||
401 | spinlock_t gs_asid_lock; /* lock used for | ||
402 | assigning asids */ | ||
403 | spinlock_t gs_lock; /* lock used for | ||
404 | assigning contexts */ | ||
405 | |||
406 | /* -- the following are protected by the gs_asid_lock spinlock ---- */ | ||
407 | unsigned int gs_asid; /* Next availe ASID */ | ||
408 | unsigned int gs_asid_limit; /* Limit of available | ||
409 | ASIDs */ | ||
410 | unsigned int gs_asid_gen; /* asid generation. | ||
411 | Inc on wrap */ | ||
412 | |||
413 | /* --- the following fields are protected by the gs_lock spinlock --- */ | ||
414 | unsigned long gs_context_map; /* bitmap to manage | ||
415 | contexts in use */ | ||
416 | unsigned long gs_cbr_map; /* bitmap to manage CB | ||
417 | resources */ | ||
418 | unsigned long gs_dsr_map; /* bitmap used to manage | ||
419 | DATA resources */ | ||
420 | unsigned int gs_reserved_cbrs; /* Number of kernel- | ||
421 | reserved cbrs */ | ||
422 | unsigned int gs_reserved_dsr_bytes; /* Bytes of kernel- | ||
423 | reserved dsrs */ | ||
424 | unsigned short gs_active_contexts; /* number of contexts | ||
425 | in use */ | ||
426 | struct gru_thread_state *gs_gts[GRU_NUM_CCH]; /* GTS currently using | ||
427 | the context */ | ||
428 | }; | ||
429 | |||
430 | /* | ||
431 | * This structure contains the GRU state for all the GRUs on a blade. | ||
432 | */ | ||
433 | struct gru_blade_state { | ||
434 | void *kernel_cb; /* First kernel | ||
435 | reserved cb */ | ||
436 | void *kernel_dsr; /* First kernel | ||
437 | reserved DSR */ | ||
438 | /* ---- the following are protected by the bs_lock spinlock ---- */ | ||
439 | spinlock_t bs_lock; /* lock used for | ||
440 | stealing contexts */ | ||
441 | int bs_lru_ctxnum; /* STEAL - last context | ||
442 | stolen */ | ||
443 | struct gru_state *bs_lru_gru; /* STEAL - last gru | ||
444 | stolen */ | ||
445 | |||
446 | struct gru_state bs_grus[GRU_CHIPLETS_PER_BLADE]; | ||
447 | }; | ||
448 | |||
449 | /*----------------------------------------------------------------------------- | ||
450 | * Address Primitives | ||
451 | */ | ||
452 | #define get_tfm_for_cpu(g, c) \ | ||
453 | ((struct gru_tlb_fault_map *)get_tfm((g)->gs_gru_base_vaddr, (c))) | ||
454 | #define get_tfh_by_index(g, i) \ | ||
455 | ((struct gru_tlb_fault_handle *)get_tfh((g)->gs_gru_base_vaddr, (i))) | ||
456 | #define get_tgh_by_index(g, i) \ | ||
457 | ((struct gru_tlb_global_handle *)get_tgh((g)->gs_gru_base_vaddr, (i))) | ||
458 | #define get_cbe_by_index(g, i) \ | ||
459 | ((struct gru_control_block_extended *)get_cbe((g)->gs_gru_base_vaddr,\ | ||
460 | (i))) | ||
461 | |||
462 | /*----------------------------------------------------------------------------- | ||
463 | * Useful Macros | ||
464 | */ | ||
465 | |||
466 | /* Given a blade# & chiplet#, get a pointer to the GRU */ | ||
467 | #define get_gru(b, c) (&gru_base[b]->bs_grus[c]) | ||
468 | |||
469 | /* Number of bytes to save/restore when unloading/loading GRU contexts */ | ||
470 | #define DSR_BYTES(dsr) ((dsr) * GRU_DSR_AU_BYTES) | ||
471 | #define CBR_BYTES(cbr) ((cbr) * GRU_HANDLE_BYTES * GRU_CBR_AU_SIZE * 2) | ||
472 | |||
473 | /* Convert a user CB number to the actual CBRNUM */ | ||
474 | #define thread_cbr_number(gts, n) ((gts)->ts_cbr_idx[(n) / GRU_CBR_AU_SIZE] \ | ||
475 | * GRU_CBR_AU_SIZE + (n) % GRU_CBR_AU_SIZE) | ||
476 | |||
477 | /* Convert a gid to a pointer to the GRU */ | ||
478 | #define GID_TO_GRU(gid) \ | ||
479 | (gru_base[(gid) / GRU_CHIPLETS_PER_BLADE] ? \ | ||
480 | (&gru_base[(gid) / GRU_CHIPLETS_PER_BLADE]-> \ | ||
481 | bs_grus[(gid) % GRU_CHIPLETS_PER_BLADE]) : \ | ||
482 | NULL) | ||
483 | |||
484 | /* Scan all active GRUs in a GRU bitmap */ | ||
485 | #define for_each_gru_in_bitmap(gid, map) \ | ||
486 | for ((gid) = find_first_bit((map), GRU_MAX_GRUS); (gid) < GRU_MAX_GRUS;\ | ||
487 | (gid)++, (gid) = find_next_bit((map), GRU_MAX_GRUS, (gid))) | ||
488 | |||
489 | /* Scan all active GRUs on a specific blade */ | ||
490 | #define for_each_gru_on_blade(gru, nid, i) \ | ||
491 | for ((gru) = gru_base[nid]->bs_grus, (i) = 0; \ | ||
492 | (i) < GRU_CHIPLETS_PER_BLADE; \ | ||
493 | (i)++, (gru)++) | ||
494 | |||
495 | /* Scan all active GTSs on a gru. Note: must hold ss_lock to use this macro. */ | ||
496 | #define for_each_gts_on_gru(gts, gru, ctxnum) \ | ||
497 | for ((ctxnum) = 0; (ctxnum) < GRU_NUM_CCH; (ctxnum)++) \ | ||
498 | if (((gts) = (gru)->gs_gts[ctxnum])) | ||
499 | |||
500 | /* Scan each CBR whose bit is set in a TFM (or copy of) */ | ||
501 | #define for_each_cbr_in_tfm(i, map) \ | ||
502 | for ((i) = find_first_bit(map, GRU_NUM_CBE); \ | ||
503 | (i) < GRU_NUM_CBE; \ | ||
504 | (i)++, (i) = find_next_bit(map, GRU_NUM_CBE, i)) | ||
505 | |||
506 | /* Scan each CBR in a CBR bitmap. Note: multiple CBRs in an allocation unit */ | ||
507 | #define for_each_cbr_in_allocation_map(i, map, k) \ | ||
508 | for ((k) = find_first_bit(map, GRU_CBR_AU); (k) < GRU_CBR_AU; \ | ||
509 | (k) = find_next_bit(map, GRU_CBR_AU, (k) + 1)) \ | ||
510 | for ((i) = (k)*GRU_CBR_AU_SIZE; \ | ||
511 | (i) < ((k) + 1) * GRU_CBR_AU_SIZE; (i)++) | ||
512 | |||
513 | /* Scan each DSR in a DSR bitmap. Note: multiple DSRs in an allocation unit */ | ||
514 | #define for_each_dsr_in_allocation_map(i, map, k) \ | ||
515 | for ((k) = find_first_bit((const unsigned long *)map, GRU_DSR_AU);\ | ||
516 | (k) < GRU_DSR_AU; \ | ||
517 | (k) = find_next_bit((const unsigned long *)map, \ | ||
518 | GRU_DSR_AU, (k) + 1)) \ | ||
519 | for ((i) = (k) * GRU_DSR_AU_CL; \ | ||
520 | (i) < ((k) + 1) * GRU_DSR_AU_CL; (i)++) | ||
521 | |||
522 | #define gseg_physical_address(gru, ctxnum) \ | ||
523 | ((gru)->gs_gru_base_paddr + ctxnum * GRU_GSEG_STRIDE) | ||
524 | #define gseg_virtual_address(gru, ctxnum) \ | ||
525 | ((gru)->gs_gru_base_vaddr + ctxnum * GRU_GSEG_STRIDE) | ||
526 | |||
527 | /*----------------------------------------------------------------------------- | ||
528 | * Lock / Unlock GRU handles | ||
529 | * Use the "delresp" bit in the handle as a "lock" bit. | ||
530 | */ | ||
531 | |||
532 | /* Lock hierarchy checking enabled only in emulator */ | ||
533 | |||
534 | static inline void __lock_handle(void *h) | ||
535 | { | ||
536 | while (test_and_set_bit(1, h)) | ||
537 | cpu_relax(); | ||
538 | } | ||
539 | |||
540 | static inline void __unlock_handle(void *h) | ||
541 | { | ||
542 | clear_bit(1, h); | ||
543 | } | ||
544 | |||
545 | static inline void lock_cch_handle(struct gru_context_configuration_handle *cch) | ||
546 | { | ||
547 | __lock_handle(cch); | ||
548 | } | ||
549 | |||
550 | static inline void unlock_cch_handle(struct gru_context_configuration_handle | ||
551 | *cch) | ||
552 | { | ||
553 | __unlock_handle(cch); | ||
554 | } | ||
555 | |||
556 | static inline void lock_tgh_handle(struct gru_tlb_global_handle *tgh) | ||
557 | { | ||
558 | __lock_handle(tgh); | ||
559 | } | ||
560 | |||
561 | static inline void unlock_tgh_handle(struct gru_tlb_global_handle *tgh) | ||
562 | { | ||
563 | __unlock_handle(tgh); | ||
564 | } | ||
565 | |||
566 | /*----------------------------------------------------------------------------- | ||
567 | * Function prototypes & externs | ||
568 | */ | ||
569 | struct gru_unload_context_req; | ||
570 | |||
571 | extern struct vm_operations_struct gru_vm_ops; | ||
572 | extern struct device *grudev; | ||
573 | |||
574 | extern struct gru_vma_data *gru_alloc_vma_data(struct vm_area_struct *vma, | ||
575 | int tsid); | ||
576 | extern struct gru_thread_state *gru_find_thread_state(struct vm_area_struct | ||
577 | *vma, int tsid); | ||
578 | extern struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct | ||
579 | *vma, int tsid); | ||
580 | extern void gru_unload_context(struct gru_thread_state *gts, int savestate); | ||
581 | extern void gts_drop(struct gru_thread_state *gts); | ||
582 | extern void gru_tgh_flush_init(struct gru_state *gru); | ||
583 | extern int gru_kservices_init(struct gru_state *gru); | ||
584 | extern irqreturn_t gru_intr(int irq, void *dev_id); | ||
585 | extern int gru_handle_user_call_os(unsigned long address); | ||
586 | extern int gru_user_flush_tlb(unsigned long arg); | ||
587 | extern int gru_user_unload_context(unsigned long arg); | ||
588 | extern int gru_get_exception_detail(unsigned long arg); | ||
589 | extern int gru_set_task_slice(long address); | ||
590 | extern int gru_cpu_fault_map_id(void); | ||
591 | extern struct vm_area_struct *gru_find_vma(unsigned long vaddr); | ||
592 | extern void gru_flush_all_tlb(struct gru_state *gru); | ||
593 | extern int gru_proc_init(void); | ||
594 | extern void gru_proc_exit(void); | ||
595 | |||
596 | extern unsigned long gru_reserve_cb_resources(struct gru_state *gru, | ||
597 | int cbr_au_count, char *cbmap); | ||
598 | extern unsigned long gru_reserve_ds_resources(struct gru_state *gru, | ||
599 | int dsr_au_count, char *dsmap); | ||
600 | extern int gru_fault(struct vm_area_struct *, struct vm_fault *vmf); | ||
601 | extern struct gru_mm_struct *gru_register_mmu_notifier(void); | ||
602 | extern void gru_drop_mmu_notifier(struct gru_mm_struct *gms); | ||
603 | |||
604 | extern void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start, | ||
605 | unsigned long len); | ||
606 | |||
607 | extern unsigned long gru_options; | ||
608 | |||
609 | #endif /* __GRUTABLES_H__ */ | ||
diff --git a/drivers/misc/sgi-gru/grutlbpurge.c b/drivers/misc/sgi-gru/grutlbpurge.c new file mode 100644 index 000000000000..bcfd5425e2e6 --- /dev/null +++ b/drivers/misc/sgi-gru/grutlbpurge.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * SN Platform GRU Driver | ||
3 | * | ||
4 | * MMUOPS callbacks + TLB flushing | ||
5 | * | ||
6 | * This file handles emu notifier callbacks from the core kernel. The callbacks | ||
7 | * are used to update the TLB in the GRU as a result of changes in the | ||
8 | * state of a process address space. This file also handles TLB invalidates | ||
9 | * from the GRU driver. | ||
10 | * | ||
11 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | */ | ||
27 | |||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/list.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/device.h> | ||
34 | #include <linux/hugetlb.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/timex.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/srcu.h> | ||
39 | #include <asm/processor.h> | ||
40 | #include "gru.h" | ||
41 | #include "grutables.h" | ||
42 | #include <asm/uv/uv_hub.h> | ||
43 | |||
44 | #define gru_random() get_cycles() | ||
45 | |||
46 | /* ---------------------------------- TLB Invalidation functions -------- | ||
47 | * get_tgh_handle | ||
48 | * | ||
49 | * Find a TGH to use for issuing a TLB invalidate. For GRUs that are on the | ||
50 | * local blade, use a fixed TGH that is a function of the blade-local cpu | ||
51 | * number. Normally, this TGH is private to the cpu & no contention occurs for | ||
52 | * the TGH. For offblade GRUs, select a random TGH in the range above the | ||
53 | * private TGHs. A spinlock is required to access this TGH & the lock must be | ||
54 | * released when the invalidate is completes. This sucks, but it is the best we | ||
55 | * can do. | ||
56 | * | ||
57 | * Note that the spinlock is IN the TGH handle so locking does not involve | ||
58 | * additional cache lines. | ||
59 | * | ||
60 | */ | ||
61 | static inline int get_off_blade_tgh(struct gru_state *gru) | ||
62 | { | ||
63 | int n; | ||
64 | |||
65 | n = GRU_NUM_TGH - gru->gs_tgh_first_remote; | ||
66 | n = gru_random() % n; | ||
67 | n += gru->gs_tgh_first_remote; | ||
68 | return n; | ||
69 | } | ||
70 | |||
71 | static inline int get_on_blade_tgh(struct gru_state *gru) | ||
72 | { | ||
73 | return uv_blade_processor_id() >> gru->gs_tgh_local_shift; | ||
74 | } | ||
75 | |||
76 | static struct gru_tlb_global_handle *get_lock_tgh_handle(struct gru_state | ||
77 | *gru) | ||
78 | { | ||
79 | struct gru_tlb_global_handle *tgh; | ||
80 | int n; | ||
81 | |||
82 | preempt_disable(); | ||
83 | if (uv_numa_blade_id() == gru->gs_blade_id) | ||
84 | n = get_on_blade_tgh(gru); | ||
85 | else | ||
86 | n = get_off_blade_tgh(gru); | ||
87 | tgh = get_tgh_by_index(gru, n); | ||
88 | lock_tgh_handle(tgh); | ||
89 | |||
90 | return tgh; | ||
91 | } | ||
92 | |||
93 | static void get_unlock_tgh_handle(struct gru_tlb_global_handle *tgh) | ||
94 | { | ||
95 | unlock_tgh_handle(tgh); | ||
96 | preempt_enable(); | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * gru_flush_tlb_range | ||
101 | * | ||
102 | * General purpose TLB invalidation function. This function scans every GRU in | ||
103 | * the ENTIRE system (partition) looking for GRUs where the specified MM has | ||
104 | * been accessed by the GRU. For each GRU found, the TLB must be invalidated OR | ||
105 | * the ASID invalidated. Invalidating an ASID causes a new ASID to be assigned | ||
106 | * on the next fault. This effectively flushes the ENTIRE TLB for the MM at the | ||
107 | * cost of (possibly) a large number of future TLBmisses. | ||
108 | * | ||
109 | * The current algorithm is optimized based on the following (somewhat true) | ||
110 | * assumptions: | ||
111 | * - GRU contexts are not loaded into a GRU unless a reference is made to | ||
112 | * the data segment or control block (this is true, not an assumption). | ||
113 | * If a DS/CB is referenced, the user will also issue instructions that | ||
114 | * cause TLBmisses. It is not necessary to optimize for the case where | ||
115 | * contexts are loaded but no instructions cause TLB misses. (I know | ||
116 | * this will happen but I'm not optimizing for it). | ||
117 | * - GRU instructions to invalidate TLB entries are SLOOOOWWW - normally | ||
118 | * a few usec but in unusual cases, it could be longer. Avoid if | ||
119 | * possible. | ||
120 | * - intrablade process migration between cpus is not frequent but is | ||
121 | * common. | ||
122 | * - a GRU context is not typically migrated to a different GRU on the | ||
123 | * blade because of intrablade migration | ||
124 | * - interblade migration is rare. Processes migrate their GRU context to | ||
125 | * the new blade. | ||
126 | * - if interblade migration occurs, migration back to the original blade | ||
127 | * is very very rare (ie., no optimization for this case) | ||
128 | * - most GRU instruction operate on a subset of the user REGIONS. Code | ||
129 | * & shared library regions are not likely targets of GRU instructions. | ||
130 | * | ||
131 | * To help improve the efficiency of TLB invalidation, the GMS data | ||
132 | * structure is maintained for EACH address space (MM struct). The GMS is | ||
133 | * also the structure that contains the pointer to the mmu callout | ||
134 | * functions. This structure is linked to the mm_struct for the address space | ||
135 | * using the mmu "register" function. The mmu interfaces are used to | ||
136 | * provide the callbacks for TLB invalidation. The GMS contains: | ||
137 | * | ||
138 | * - asid[maxgrus] array. ASIDs are assigned to a GRU when a context is | ||
139 | * loaded into the GRU. | ||
140 | * - asidmap[maxgrus]. bitmap to make it easier to find non-zero asids in | ||
141 | * the above array | ||
142 | * - ctxbitmap[maxgrus]. Indicates the contexts that are currently active | ||
143 | * in the GRU for the address space. This bitmap must be passed to the | ||
144 | * GRU to do an invalidate. | ||
145 | * | ||
146 | * The current algorithm for invalidating TLBs is: | ||
147 | * - scan the asidmap for GRUs where the context has been loaded, ie, | ||
148 | * asid is non-zero. | ||
149 | * - for each gru found: | ||
150 | * - if the ctxtmap is non-zero, there are active contexts in the | ||
151 | * GRU. TLB invalidate instructions must be issued to the GRU. | ||
152 | * - if the ctxtmap is zero, no context is active. Set the ASID to | ||
153 | * zero to force a full TLB invalidation. This is fast but will | ||
154 | * cause a lot of TLB misses if the context is reloaded onto the | ||
155 | * GRU | ||
156 | * | ||
157 | */ | ||
158 | |||
159 | void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start, | ||
160 | unsigned long len) | ||
161 | { | ||
162 | struct gru_state *gru; | ||
163 | struct gru_mm_tracker *asids; | ||
164 | struct gru_tlb_global_handle *tgh; | ||
165 | unsigned long num; | ||
166 | int grupagesize, pagesize, pageshift, gid, asid; | ||
167 | |||
168 | /* ZZZ TODO - handle huge pages */ | ||
169 | pageshift = PAGE_SHIFT; | ||
170 | pagesize = (1UL << pageshift); | ||
171 | grupagesize = GRU_PAGESIZE(pageshift); | ||
172 | num = min(((len + pagesize - 1) >> pageshift), GRUMAXINVAL); | ||
173 | |||
174 | STAT(flush_tlb); | ||
175 | gru_dbg(grudev, "gms %p, start 0x%lx, len 0x%lx, asidmap 0x%lx\n", gms, | ||
176 | start, len, gms->ms_asidmap[0]); | ||
177 | |||
178 | spin_lock(&gms->ms_asid_lock); | ||
179 | for_each_gru_in_bitmap(gid, gms->ms_asidmap) { | ||
180 | STAT(flush_tlb_gru); | ||
181 | gru = GID_TO_GRU(gid); | ||
182 | asids = gms->ms_asids + gid; | ||
183 | asid = asids->mt_asid; | ||
184 | if (asids->mt_ctxbitmap && asid) { | ||
185 | STAT(flush_tlb_gru_tgh); | ||
186 | asid = GRUASID(asid, start); | ||
187 | gru_dbg(grudev, | ||
188 | " FLUSH gruid %d, asid 0x%x, num %ld, cbmap 0x%x\n", | ||
189 | gid, asid, num, asids->mt_ctxbitmap); | ||
190 | tgh = get_lock_tgh_handle(gru); | ||
191 | tgh_invalidate(tgh, start, 0, asid, grupagesize, 0, | ||
192 | num - 1, asids->mt_ctxbitmap); | ||
193 | get_unlock_tgh_handle(tgh); | ||
194 | } else { | ||
195 | STAT(flush_tlb_gru_zero_asid); | ||
196 | asids->mt_asid = 0; | ||
197 | __clear_bit(gru->gs_gid, gms->ms_asidmap); | ||
198 | gru_dbg(grudev, | ||
199 | " CLEARASID gruid %d, asid 0x%x, cbtmap 0x%x, asidmap 0x%lx\n", | ||
200 | gid, asid, asids->mt_ctxbitmap, | ||
201 | gms->ms_asidmap[0]); | ||
202 | } | ||
203 | } | ||
204 | spin_unlock(&gms->ms_asid_lock); | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * Flush the entire TLB on a chiplet. | ||
209 | */ | ||
210 | void gru_flush_all_tlb(struct gru_state *gru) | ||
211 | { | ||
212 | struct gru_tlb_global_handle *tgh; | ||
213 | |||
214 | gru_dbg(grudev, "gru %p, gid %d\n", gru, gru->gs_gid); | ||
215 | tgh = get_lock_tgh_handle(gru); | ||
216 | tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0); | ||
217 | get_unlock_tgh_handle(tgh); | ||
218 | preempt_enable(); | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | * MMUOPS notifier callout functions | ||
223 | */ | ||
224 | static void gru_invalidate_range_start(struct mmu_notifier *mn, | ||
225 | struct mm_struct *mm, | ||
226 | unsigned long start, unsigned long end) | ||
227 | { | ||
228 | struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, | ||
229 | ms_notifier); | ||
230 | |||
231 | STAT(mmu_invalidate_range); | ||
232 | atomic_inc(&gms->ms_range_active); | ||
233 | gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx, act %d\n", gms, | ||
234 | start, end, atomic_read(&gms->ms_range_active)); | ||
235 | gru_flush_tlb_range(gms, start, end - start); | ||
236 | } | ||
237 | |||
238 | static void gru_invalidate_range_end(struct mmu_notifier *mn, | ||
239 | struct mm_struct *mm, unsigned long start, | ||
240 | unsigned long end) | ||
241 | { | ||
242 | struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, | ||
243 | ms_notifier); | ||
244 | |||
245 | /* ..._and_test() provides needed barrier */ | ||
246 | (void)atomic_dec_and_test(&gms->ms_range_active); | ||
247 | |||
248 | wake_up_all(&gms->ms_wait_queue); | ||
249 | gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx\n", gms, start, end); | ||
250 | } | ||
251 | |||
252 | static void gru_invalidate_page(struct mmu_notifier *mn, struct mm_struct *mm, | ||
253 | unsigned long address) | ||
254 | { | ||
255 | struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, | ||
256 | ms_notifier); | ||
257 | |||
258 | STAT(mmu_invalidate_page); | ||
259 | gru_flush_tlb_range(gms, address, PAGE_SIZE); | ||
260 | gru_dbg(grudev, "gms %p, address 0x%lx\n", gms, address); | ||
261 | } | ||
262 | |||
263 | static void gru_release(struct mmu_notifier *mn, struct mm_struct *mm) | ||
264 | { | ||
265 | struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, | ||
266 | ms_notifier); | ||
267 | |||
268 | gms->ms_released = 1; | ||
269 | gru_dbg(grudev, "gms %p\n", gms); | ||
270 | } | ||
271 | |||
272 | |||
273 | static const struct mmu_notifier_ops gru_mmuops = { | ||
274 | .invalidate_page = gru_invalidate_page, | ||
275 | .invalidate_range_start = gru_invalidate_range_start, | ||
276 | .invalidate_range_end = gru_invalidate_range_end, | ||
277 | .release = gru_release, | ||
278 | }; | ||
279 | |||
280 | /* Move this to the basic mmu_notifier file. But for now... */ | ||
281 | static struct mmu_notifier *mmu_find_ops(struct mm_struct *mm, | ||
282 | const struct mmu_notifier_ops *ops) | ||
283 | { | ||
284 | struct mmu_notifier *mn, *gru_mn = NULL; | ||
285 | struct hlist_node *n; | ||
286 | |||
287 | if (mm->mmu_notifier_mm) { | ||
288 | rcu_read_lock(); | ||
289 | hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, | ||
290 | hlist) | ||
291 | if (mn->ops == ops) { | ||
292 | gru_mn = mn; | ||
293 | break; | ||
294 | } | ||
295 | rcu_read_unlock(); | ||
296 | } | ||
297 | return gru_mn; | ||
298 | } | ||
299 | |||
300 | struct gru_mm_struct *gru_register_mmu_notifier(void) | ||
301 | { | ||
302 | struct gru_mm_struct *gms; | ||
303 | struct mmu_notifier *mn; | ||
304 | |||
305 | mn = mmu_find_ops(current->mm, &gru_mmuops); | ||
306 | if (mn) { | ||
307 | gms = container_of(mn, struct gru_mm_struct, ms_notifier); | ||
308 | atomic_inc(&gms->ms_refcnt); | ||
309 | } else { | ||
310 | gms = kzalloc(sizeof(*gms), GFP_KERNEL); | ||
311 | if (gms) { | ||
312 | spin_lock_init(&gms->ms_asid_lock); | ||
313 | gms->ms_notifier.ops = &gru_mmuops; | ||
314 | atomic_set(&gms->ms_refcnt, 1); | ||
315 | init_waitqueue_head(&gms->ms_wait_queue); | ||
316 | __mmu_notifier_register(&gms->ms_notifier, current->mm); | ||
317 | } | ||
318 | } | ||
319 | gru_dbg(grudev, "gms %p, refcnt %d\n", gms, | ||
320 | atomic_read(&gms->ms_refcnt)); | ||
321 | return gms; | ||
322 | } | ||
323 | |||
324 | void gru_drop_mmu_notifier(struct gru_mm_struct *gms) | ||
325 | { | ||
326 | gru_dbg(grudev, "gms %p, refcnt %d, released %d\n", gms, | ||
327 | atomic_read(&gms->ms_refcnt), gms->ms_released); | ||
328 | if (atomic_dec_return(&gms->ms_refcnt) == 0) { | ||
329 | if (!gms->ms_released) | ||
330 | mmu_notifier_unregister(&gms->ms_notifier, current->mm); | ||
331 | kfree(gms); | ||
332 | } | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * Setup TGH parameters. There are: | ||
337 | * - 24 TGH handles per GRU chiplet | ||
338 | * - a portion (MAX_LOCAL_TGH) of the handles are reserved for | ||
339 | * use by blade-local cpus | ||
340 | * - the rest are used by off-blade cpus. This usage is | ||
341 | * less frequent than blade-local usage. | ||
342 | * | ||
343 | * For now, use 16 handles for local flushes, 8 for remote flushes. If the blade | ||
344 | * has less tan or equal to 16 cpus, each cpu has a unique handle that it can | ||
345 | * use. | ||
346 | */ | ||
347 | #define MAX_LOCAL_TGH 16 | ||
348 | |||
349 | void gru_tgh_flush_init(struct gru_state *gru) | ||
350 | { | ||
351 | int cpus, shift = 0, n; | ||
352 | |||
353 | cpus = uv_blade_nr_possible_cpus(gru->gs_blade_id); | ||
354 | |||
355 | /* n = cpus rounded up to next power of 2 */ | ||
356 | if (cpus) { | ||
357 | n = 1 << fls(cpus - 1); | ||
358 | |||
359 | /* | ||
360 | * shift count for converting local cpu# to TGH index | ||
361 | * 0 if cpus <= MAX_LOCAL_TGH, | ||
362 | * 1 if cpus <= 2*MAX_LOCAL_TGH, | ||
363 | * etc | ||
364 | */ | ||
365 | shift = max(0, fls(n - 1) - fls(MAX_LOCAL_TGH - 1)); | ||
366 | } | ||
367 | gru->gs_tgh_local_shift = shift; | ||
368 | |||
369 | /* first starting TGH index to use for remote purges */ | ||
370 | gru->gs_tgh_first_remote = (cpus + (1 << shift) - 1) >> shift; | ||
371 | |||
372 | } | ||
diff --git a/drivers/misc/sgi-xp/Makefile b/drivers/misc/sgi-xp/Makefile index b6e40a7958ce..35ce28578075 100644 --- a/drivers/misc/sgi-xp/Makefile +++ b/drivers/misc/sgi-xp/Makefile | |||
@@ -3,9 +3,17 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_SGI_XP) += xp.o | 5 | obj-$(CONFIG_SGI_XP) += xp.o |
6 | xp-y := xp_main.o xp_nofault.o | 6 | xp-y := xp_main.o |
7 | xp-$(CONFIG_IA64_SGI_SN2) += xp_sn2.o xp_nofault.o | ||
8 | xp-$(CONFIG_IA64_GENERIC) += xp_sn2.o xp_nofault.o xp_uv.o | ||
9 | xp-$(CONFIG_IA64_SGI_UV) += xp_uv.o | ||
10 | xp-$(CONFIG_X86_64) += xp_uv.o | ||
7 | 11 | ||
8 | obj-$(CONFIG_SGI_XP) += xpc.o | 12 | obj-$(CONFIG_SGI_XP) += xpc.o |
9 | xpc-y := xpc_main.o xpc_channel.o xpc_partition.o | 13 | xpc-y := xpc_main.o xpc_channel.o xpc_partition.o |
14 | xpc-$(CONFIG_IA64_SGI_SN2) += xpc_sn2.o | ||
15 | xpc-$(CONFIG_IA64_GENERIC) += xpc_sn2.o xpc_uv.o | ||
16 | xpc-$(CONFIG_IA64_SGI_UV) += xpc_uv.o | ||
17 | xpc-$(CONFIG_X86_64) += xpc_uv.o | ||
10 | 18 | ||
11 | obj-$(CONFIG_SGI_XP) += xpnet.o | 19 | obj-$(CONFIG_SGI_XP) += xpnet.o |
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 03a87a307e32..859a5281c61b 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h | |||
@@ -13,11 +13,34 @@ | |||
13 | #ifndef _DRIVERS_MISC_SGIXP_XP_H | 13 | #ifndef _DRIVERS_MISC_SGIXP_XP_H |
14 | #define _DRIVERS_MISC_SGIXP_XP_H | 14 | #define _DRIVERS_MISC_SGIXP_XP_H |
15 | 15 | ||
16 | #include <linux/cache.h> | ||
17 | #include <linux/hardirq.h> | ||
18 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
19 | #include <asm/sn/types.h> | 17 | |
20 | #include <asm/sn/bte.h> | 18 | #ifdef CONFIG_IA64 |
19 | #include <asm/system.h> | ||
20 | #include <asm/sn/arch.h> /* defines is_shub1() and is_shub2() */ | ||
21 | #define is_shub() ia64_platform_is("sn2") | ||
22 | #define is_uv() ia64_platform_is("uv") | ||
23 | #endif | ||
24 | #ifdef CONFIG_X86_64 | ||
25 | #include <asm/genapic.h> | ||
26 | #define is_uv() is_uv_system() | ||
27 | #endif | ||
28 | |||
29 | #ifndef is_shub1 | ||
30 | #define is_shub1() 0 | ||
31 | #endif | ||
32 | |||
33 | #ifndef is_shub2 | ||
34 | #define is_shub2() 0 | ||
35 | #endif | ||
36 | |||
37 | #ifndef is_shub | ||
38 | #define is_shub() 0 | ||
39 | #endif | ||
40 | |||
41 | #ifndef is_uv | ||
42 | #define is_uv() 0 | ||
43 | #endif | ||
21 | 44 | ||
22 | #ifdef USE_DBUG_ON | 45 | #ifdef USE_DBUG_ON |
23 | #define DBUG_ON(condition) BUG_ON(condition) | 46 | #define DBUG_ON(condition) BUG_ON(condition) |
@@ -26,133 +49,56 @@ | |||
26 | #endif | 49 | #endif |
27 | 50 | ||
28 | /* | 51 | /* |
29 | * Define the maximum number of logically defined partitions the system | 52 | * Define the maximum number of partitions the system can possibly support. |
30 | * can support. It is constrained by the maximum number of hardware | 53 | * It is based on the maximum number of hardware partitionable regions. The |
31 | * partitionable regions. The term 'region' in this context refers to the | 54 | * term 'region' in this context refers to the minimum number of nodes that |
32 | * minimum number of nodes that can comprise an access protection grouping. | 55 | * can comprise an access protection grouping. The access protection is in |
33 | * The access protection is in regards to memory, IPI and IOI. | 56 | * regards to memory, IPI and IOI. |
34 | * | 57 | * |
35 | * The maximum number of hardware partitionable regions is equal to the | 58 | * The maximum number of hardware partitionable regions is equal to the |
36 | * maximum number of nodes in the entire system divided by the minimum number | 59 | * maximum number of nodes in the entire system divided by the minimum number |
37 | * of nodes that comprise an access protection grouping. | 60 | * of nodes that comprise an access protection grouping. |
38 | */ | 61 | */ |
39 | #define XP_MAX_PARTITIONS 64 | 62 | #define XP_MAX_NPARTITIONS_SN2 64 |
40 | 63 | #define XP_MAX_NPARTITIONS_UV 256 | |
41 | /* | ||
42 | * Define the number of u64s required to represent all the C-brick nasids | ||
43 | * as a bitmap. The cross-partition kernel modules deal only with | ||
44 | * C-brick nasids, thus the need for bitmaps which don't account for | ||
45 | * odd-numbered (non C-brick) nasids. | ||
46 | */ | ||
47 | #define XP_MAX_PHYSNODE_ID (MAX_NUMALINK_NODES / 2) | ||
48 | #define XP_NASID_MASK_BYTES ((XP_MAX_PHYSNODE_ID + 7) / 8) | ||
49 | #define XP_NASID_MASK_WORDS ((XP_MAX_PHYSNODE_ID + 63) / 64) | ||
50 | |||
51 | /* | ||
52 | * Wrapper for bte_copy() that should it return a failure status will retry | ||
53 | * the bte_copy() once in the hope that the failure was due to a temporary | ||
54 | * aberration (i.e., the link going down temporarily). | ||
55 | * | ||
56 | * src - physical address of the source of the transfer. | ||
57 | * vdst - virtual address of the destination of the transfer. | ||
58 | * len - number of bytes to transfer from source to destination. | ||
59 | * mode - see bte_copy() for definition. | ||
60 | * notification - see bte_copy() for definition. | ||
61 | * | ||
62 | * Note: xp_bte_copy() should never be called while holding a spinlock. | ||
63 | */ | ||
64 | static inline bte_result_t | ||
65 | xp_bte_copy(u64 src, u64 vdst, u64 len, u64 mode, void *notification) | ||
66 | { | ||
67 | bte_result_t ret; | ||
68 | u64 pdst = ia64_tpa(vdst); | ||
69 | |||
70 | /* | ||
71 | * Ensure that the physically mapped memory is contiguous. | ||
72 | * | ||
73 | * We do this by ensuring that the memory is from region 7 only. | ||
74 | * If the need should arise to use memory from one of the other | ||
75 | * regions, then modify the BUG_ON() statement to ensure that the | ||
76 | * memory from that region is always physically contiguous. | ||
77 | */ | ||
78 | BUG_ON(REGION_NUMBER(vdst) != RGN_KERNEL); | ||
79 | |||
80 | ret = bte_copy(src, pdst, len, mode, notification); | ||
81 | if ((ret != BTE_SUCCESS) && BTE_ERROR_RETRY(ret)) { | ||
82 | if (!in_interrupt()) | ||
83 | cond_resched(); | ||
84 | |||
85 | ret = bte_copy(src, pdst, len, mode, notification); | ||
86 | } | ||
87 | |||
88 | return ret; | ||
89 | } | ||
90 | 64 | ||
91 | /* | 65 | /* |
92 | * XPC establishes channel connections between the local partition and any | 66 | * XPC establishes channel connections between the local partition and any |
93 | * other partition that is currently up. Over these channels, kernel-level | 67 | * other partition that is currently up. Over these channels, kernel-level |
94 | * `users' can communicate with their counterparts on the other partitions. | 68 | * `users' can communicate with their counterparts on the other partitions. |
95 | * | 69 | * |
96 | * The maxinum number of channels is limited to eight. For performance reasons, | ||
97 | * the internal cross partition structures require sixteen bytes per channel, | ||
98 | * and eight allows all of this interface-shared info to fit in one cache line. | ||
99 | * | ||
100 | * XPC_NCHANNELS reflects the total number of channels currently defined. | ||
101 | * If the need for additional channels arises, one can simply increase | 70 | * If the need for additional channels arises, one can simply increase |
102 | * XPC_NCHANNELS accordingly. If the day should come where that number | 71 | * XPC_MAX_NCHANNELS accordingly. If the day should come where that number |
103 | * exceeds the MAXIMUM number of channels allowed (eight), then one will need | 72 | * exceeds the absolute MAXIMUM number of channels possible (eight), then one |
104 | * to make changes to the XPC code to allow for this. | 73 | * will need to make changes to the XPC code to accommodate for this. |
74 | * | ||
75 | * The absolute maximum number of channels possible is limited to eight for | ||
76 | * performance reasons on sn2 hardware. The internal cross partition structures | ||
77 | * require sixteen bytes per channel, and eight allows all of this | ||
78 | * interface-shared info to fit in one 128-byte cacheline. | ||
105 | */ | 79 | */ |
106 | #define XPC_MEM_CHANNEL 0 /* memory channel number */ | 80 | #define XPC_MEM_CHANNEL 0 /* memory channel number */ |
107 | #define XPC_NET_CHANNEL 1 /* network channel number */ | 81 | #define XPC_NET_CHANNEL 1 /* network channel number */ |
108 | 82 | ||
109 | #define XPC_NCHANNELS 2 /* #of defined channels */ | 83 | #define XPC_MAX_NCHANNELS 2 /* max #of channels allowed */ |
110 | #define XPC_MAX_NCHANNELS 8 /* max #of channels allowed */ | ||
111 | 84 | ||
112 | #if XPC_NCHANNELS > XPC_MAX_NCHANNELS | 85 | #if XPC_MAX_NCHANNELS > 8 |
113 | #error XPC_NCHANNELS exceeds MAXIMUM allowed. | 86 | #error XPC_MAX_NCHANNELS exceeds absolute MAXIMUM possible. |
114 | #endif | 87 | #endif |
115 | 88 | ||
116 | /* | 89 | /* |
117 | * The format of an XPC message is as follows: | 90 | * Define macro, XPC_MSG_SIZE(), is provided for the user |
118 | * | ||
119 | * +-------+--------------------------------+ | ||
120 | * | flags |////////////////////////////////| | ||
121 | * +-------+--------------------------------+ | ||
122 | * | message # | | ||
123 | * +----------------------------------------+ | ||
124 | * | payload (user-defined message) | | ||
125 | * | | | ||
126 | * : | ||
127 | * | | | ||
128 | * +----------------------------------------+ | ||
129 | * | ||
130 | * The size of the payload is defined by the user via xpc_connect(). A user- | ||
131 | * defined message resides in the payload area. | ||
132 | * | ||
133 | * The user should have no dealings with the message header, but only the | ||
134 | * message's payload. When a message entry is allocated (via xpc_allocate()) | ||
135 | * a pointer to the payload area is returned and not the actual beginning of | ||
136 | * the XPC message. The user then constructs a message in the payload area | ||
137 | * and passes that pointer as an argument on xpc_send() or xpc_send_notify(). | ||
138 | * | ||
139 | * The size of a message entry (within a message queue) must be a cacheline | ||
140 | * sized multiple in order to facilitate the BTE transfer of messages from one | ||
141 | * message queue to another. A macro, XPC_MSG_SIZE(), is provided for the user | ||
142 | * that wants to fit as many msg entries as possible in a given memory size | 91 | * that wants to fit as many msg entries as possible in a given memory size |
143 | * (e.g. a memory page). | 92 | * (e.g. a memory page). |
144 | */ | 93 | */ |
145 | struct xpc_msg { | 94 | #define XPC_MSG_MAX_SIZE 128 |
146 | u8 flags; /* FOR XPC INTERNAL USE ONLY */ | 95 | #define XPC_MSG_HDR_MAX_SIZE 16 |
147 | u8 reserved[7]; /* FOR XPC INTERNAL USE ONLY */ | 96 | #define XPC_MSG_PAYLOAD_MAX_SIZE (XPC_MSG_MAX_SIZE - XPC_MSG_HDR_MAX_SIZE) |
148 | s64 number; /* FOR XPC INTERNAL USE ONLY */ | ||
149 | |||
150 | u64 payload; /* user defined portion of message */ | ||
151 | }; | ||
152 | 97 | ||
153 | #define XPC_MSG_PAYLOAD_OFFSET (u64) (&((struct xpc_msg *)0)->payload) | ||
154 | #define XPC_MSG_SIZE(_payload_size) \ | 98 | #define XPC_MSG_SIZE(_payload_size) \ |
155 | L1_CACHE_ALIGN(XPC_MSG_PAYLOAD_OFFSET + (_payload_size)) | 99 | ALIGN(XPC_MSG_HDR_MAX_SIZE + (_payload_size), \ |
100 | is_uv() ? 64 : 128) | ||
101 | |||
156 | 102 | ||
157 | /* | 103 | /* |
158 | * Define the return values and values passed to user's callout functions. | 104 | * Define the return values and values passed to user's callout functions. |
@@ -233,8 +179,20 @@ enum xp_retval { | |||
233 | xpDisconnected, /* 51: channel disconnected (closed) */ | 179 | xpDisconnected, /* 51: channel disconnected (closed) */ |
234 | 180 | ||
235 | xpBteCopyError, /* 52: bte_copy() returned error */ | 181 | xpBteCopyError, /* 52: bte_copy() returned error */ |
182 | xpSalError, /* 53: sn SAL error */ | ||
183 | xpRsvdPageNotSet, /* 54: the reserved page is not set up */ | ||
184 | xpPayloadTooBig, /* 55: payload too large for message slot */ | ||
185 | |||
186 | xpUnsupported, /* 56: unsupported functionality or resource */ | ||
187 | xpNeedMoreInfo, /* 57: more info is needed by SAL */ | ||
236 | 188 | ||
237 | xpUnknownReason /* 53: unknown reason - must be last in enum */ | 189 | xpGruCopyError, /* 58: gru_copy_gru() returned error */ |
190 | xpGruSendMqError, /* 59: gru send message queue related error */ | ||
191 | |||
192 | xpBadChannelNumber, /* 60: invalid channel number */ | ||
193 | xpBadMsgType, /* 60: invalid message type */ | ||
194 | |||
195 | xpUnknownReason /* 61: unknown reason - must be last in enum */ | ||
238 | }; | 196 | }; |
239 | 197 | ||
240 | /* | 198 | /* |
@@ -285,6 +243,9 @@ typedef void (*xpc_channel_func) (enum xp_retval reason, short partid, | |||
285 | * calling xpc_received(). | 243 | * calling xpc_received(). |
286 | * | 244 | * |
287 | * All other reason codes indicate failure. | 245 | * All other reason codes indicate failure. |
246 | * | ||
247 | * NOTE: The user defined function must be callable by an interrupt handler | ||
248 | * and thus cannot block. | ||
288 | */ | 249 | */ |
289 | typedef void (*xpc_notify_func) (enum xp_retval reason, short partid, | 250 | typedef void (*xpc_notify_func) (enum xp_retval reason, short partid, |
290 | int ch_number, void *key); | 251 | int ch_number, void *key); |
@@ -308,23 +269,22 @@ struct xpc_registration { | |||
308 | xpc_channel_func func; /* function to call */ | 269 | xpc_channel_func func; /* function to call */ |
309 | void *key; /* pointer to user's key */ | 270 | void *key; /* pointer to user's key */ |
310 | u16 nentries; /* #of msg entries in local msg queue */ | 271 | u16 nentries; /* #of msg entries in local msg queue */ |
311 | u16 msg_size; /* message queue's message size */ | 272 | u16 entry_size; /* message queue's message entry size */ |
312 | u32 assigned_limit; /* limit on #of assigned kthreads */ | 273 | u32 assigned_limit; /* limit on #of assigned kthreads */ |
313 | u32 idle_limit; /* limit on #of idle kthreads */ | 274 | u32 idle_limit; /* limit on #of idle kthreads */ |
314 | } ____cacheline_aligned; | 275 | } ____cacheline_aligned; |
315 | 276 | ||
316 | #define XPC_CHANNEL_REGISTERED(_c) (xpc_registrations[_c].func != NULL) | 277 | #define XPC_CHANNEL_REGISTERED(_c) (xpc_registrations[_c].func != NULL) |
317 | 278 | ||
318 | /* the following are valid xpc_allocate() flags */ | 279 | /* the following are valid xpc_send() or xpc_send_notify() flags */ |
319 | #define XPC_WAIT 0 /* wait flag */ | 280 | #define XPC_WAIT 0 /* wait flag */ |
320 | #define XPC_NOWAIT 1 /* no wait flag */ | 281 | #define XPC_NOWAIT 1 /* no wait flag */ |
321 | 282 | ||
322 | struct xpc_interface { | 283 | struct xpc_interface { |
323 | void (*connect) (int); | 284 | void (*connect) (int); |
324 | void (*disconnect) (int); | 285 | void (*disconnect) (int); |
325 | enum xp_retval (*allocate) (short, int, u32, void **); | 286 | enum xp_retval (*send) (short, int, u32, void *, u16); |
326 | enum xp_retval (*send) (short, int, void *); | 287 | enum xp_retval (*send_notify) (short, int, u32, void *, u16, |
327 | enum xp_retval (*send_notify) (short, int, void *, | ||
328 | xpc_notify_func, void *); | 288 | xpc_notify_func, void *); |
329 | void (*received) (short, int, void *); | 289 | void (*received) (short, int, void *); |
330 | enum xp_retval (*partid_to_nasids) (short, void *); | 290 | enum xp_retval (*partid_to_nasids) (short, void *); |
@@ -334,10 +294,9 @@ extern struct xpc_interface xpc_interface; | |||
334 | 294 | ||
335 | extern void xpc_set_interface(void (*)(int), | 295 | extern void xpc_set_interface(void (*)(int), |
336 | void (*)(int), | 296 | void (*)(int), |
337 | enum xp_retval (*)(short, int, u32, void **), | 297 | enum xp_retval (*)(short, int, u32, void *, u16), |
338 | enum xp_retval (*)(short, int, void *), | 298 | enum xp_retval (*)(short, int, u32, void *, u16, |
339 | enum xp_retval (*)(short, int, void *, | 299 | xpc_notify_func, void *), |
340 | xpc_notify_func, void *), | ||
341 | void (*)(short, int, void *), | 300 | void (*)(short, int, void *), |
342 | enum xp_retval (*)(short, void *)); | 301 | enum xp_retval (*)(short, void *)); |
343 | extern void xpc_clear_interface(void); | 302 | extern void xpc_clear_interface(void); |
@@ -347,22 +306,19 @@ extern enum xp_retval xpc_connect(int, xpc_channel_func, void *, u16, | |||
347 | extern void xpc_disconnect(int); | 306 | extern void xpc_disconnect(int); |
348 | 307 | ||
349 | static inline enum xp_retval | 308 | static inline enum xp_retval |
350 | xpc_allocate(short partid, int ch_number, u32 flags, void **payload) | 309 | xpc_send(short partid, int ch_number, u32 flags, void *payload, |
351 | { | 310 | u16 payload_size) |
352 | return xpc_interface.allocate(partid, ch_number, flags, payload); | ||
353 | } | ||
354 | |||
355 | static inline enum xp_retval | ||
356 | xpc_send(short partid, int ch_number, void *payload) | ||
357 | { | 311 | { |
358 | return xpc_interface.send(partid, ch_number, payload); | 312 | return xpc_interface.send(partid, ch_number, flags, payload, |
313 | payload_size); | ||
359 | } | 314 | } |
360 | 315 | ||
361 | static inline enum xp_retval | 316 | static inline enum xp_retval |
362 | xpc_send_notify(short partid, int ch_number, void *payload, | 317 | xpc_send_notify(short partid, int ch_number, u32 flags, void *payload, |
363 | xpc_notify_func func, void *key) | 318 | u16 payload_size, xpc_notify_func func, void *key) |
364 | { | 319 | { |
365 | return xpc_interface.send_notify(partid, ch_number, payload, func, key); | 320 | return xpc_interface.send_notify(partid, ch_number, flags, payload, |
321 | payload_size, func, key); | ||
366 | } | 322 | } |
367 | 323 | ||
368 | static inline void | 324 | static inline void |
@@ -377,8 +333,23 @@ xpc_partid_to_nasids(short partid, void *nasids) | |||
377 | return xpc_interface.partid_to_nasids(partid, nasids); | 333 | return xpc_interface.partid_to_nasids(partid, nasids); |
378 | } | 334 | } |
379 | 335 | ||
336 | extern short xp_max_npartitions; | ||
337 | extern short xp_partition_id; | ||
338 | extern u8 xp_region_size; | ||
339 | |||
340 | extern unsigned long (*xp_pa) (void *); | ||
341 | extern enum xp_retval (*xp_remote_memcpy) (unsigned long, const unsigned long, | ||
342 | size_t); | ||
343 | extern int (*xp_cpu_to_nasid) (int); | ||
344 | |||
380 | extern u64 xp_nofault_PIOR_target; | 345 | extern u64 xp_nofault_PIOR_target; |
381 | extern int xp_nofault_PIOR(void *); | 346 | extern int xp_nofault_PIOR(void *); |
382 | extern int xp_error_PIOR(void); | 347 | extern int xp_error_PIOR(void); |
383 | 348 | ||
349 | extern struct device *xp; | ||
350 | extern enum xp_retval xp_init_sn2(void); | ||
351 | extern enum xp_retval xp_init_uv(void); | ||
352 | extern void xp_exit_sn2(void); | ||
353 | extern void xp_exit_uv(void); | ||
354 | |||
384 | #endif /* _DRIVERS_MISC_SGIXP_XP_H */ | 355 | #endif /* _DRIVERS_MISC_SGIXP_XP_H */ |
diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index 196480b691a1..66a1d19e08ad 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c | |||
@@ -14,29 +14,48 @@ | |||
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/module.h> | 17 | #include <linux/module.h> |
20 | #include <linux/mutex.h> | 18 | #include <linux/device.h> |
21 | #include <asm/sn/intr.h> | ||
22 | #include <asm/sn/sn_sal.h> | ||
23 | #include "xp.h" | 19 | #include "xp.h" |
24 | 20 | ||
25 | /* | 21 | /* define the XP debug device structures to be used with dev_dbg() et al */ |
26 | * The export of xp_nofault_PIOR needs to happen here since it is defined | 22 | |
27 | * in drivers/misc/sgi-xp/xp_nofault.S. The target of the nofault read is | 23 | struct device_driver xp_dbg_name = { |
28 | * defined here. | 24 | .name = "xp" |
29 | */ | 25 | }; |
30 | EXPORT_SYMBOL_GPL(xp_nofault_PIOR); | 26 | |
27 | struct device xp_dbg_subname = { | ||
28 | .bus_id = {0}, /* set to "" */ | ||
29 | .driver = &xp_dbg_name | ||
30 | }; | ||
31 | |||
32 | struct device *xp = &xp_dbg_subname; | ||
33 | |||
34 | /* max #of partitions possible */ | ||
35 | short xp_max_npartitions; | ||
36 | EXPORT_SYMBOL_GPL(xp_max_npartitions); | ||
37 | |||
38 | short xp_partition_id; | ||
39 | EXPORT_SYMBOL_GPL(xp_partition_id); | ||
40 | |||
41 | u8 xp_region_size; | ||
42 | EXPORT_SYMBOL_GPL(xp_region_size); | ||
43 | |||
44 | unsigned long (*xp_pa) (void *addr); | ||
45 | EXPORT_SYMBOL_GPL(xp_pa); | ||
46 | |||
47 | enum xp_retval (*xp_remote_memcpy) (unsigned long dst_gpa, | ||
48 | const unsigned long src_gpa, size_t len); | ||
49 | EXPORT_SYMBOL_GPL(xp_remote_memcpy); | ||
31 | 50 | ||
32 | u64 xp_nofault_PIOR_target; | 51 | int (*xp_cpu_to_nasid) (int cpuid); |
33 | EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target); | 52 | EXPORT_SYMBOL_GPL(xp_cpu_to_nasid); |
34 | 53 | ||
35 | /* | 54 | /* |
36 | * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level | 55 | * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level |
37 | * users of XPC. | 56 | * users of XPC. |
38 | */ | 57 | */ |
39 | struct xpc_registration xpc_registrations[XPC_NCHANNELS]; | 58 | struct xpc_registration xpc_registrations[XPC_MAX_NCHANNELS]; |
40 | EXPORT_SYMBOL_GPL(xpc_registrations); | 59 | EXPORT_SYMBOL_GPL(xpc_registrations); |
41 | 60 | ||
42 | /* | 61 | /* |
@@ -51,10 +70,9 @@ xpc_notloaded(void) | |||
51 | struct xpc_interface xpc_interface = { | 70 | struct xpc_interface xpc_interface = { |
52 | (void (*)(int))xpc_notloaded, | 71 | (void (*)(int))xpc_notloaded, |
53 | (void (*)(int))xpc_notloaded, | 72 | (void (*)(int))xpc_notloaded, |
54 | (enum xp_retval(*)(short, int, u32, void **))xpc_notloaded, | 73 | (enum xp_retval(*)(short, int, u32, void *, u16))xpc_notloaded, |
55 | (enum xp_retval(*)(short, int, void *))xpc_notloaded, | 74 | (enum xp_retval(*)(short, int, u32, void *, u16, xpc_notify_func, |
56 | (enum xp_retval(*)(short, int, void *, xpc_notify_func, void *)) | 75 | void *))xpc_notloaded, |
57 | xpc_notloaded, | ||
58 | (void (*)(short, int, void *))xpc_notloaded, | 76 | (void (*)(short, int, void *))xpc_notloaded, |
59 | (enum xp_retval(*)(short, void *))xpc_notloaded | 77 | (enum xp_retval(*)(short, void *))xpc_notloaded |
60 | }; | 78 | }; |
@@ -66,16 +84,14 @@ EXPORT_SYMBOL_GPL(xpc_interface); | |||
66 | void | 84 | void |
67 | xpc_set_interface(void (*connect) (int), | 85 | xpc_set_interface(void (*connect) (int), |
68 | void (*disconnect) (int), | 86 | void (*disconnect) (int), |
69 | enum xp_retval (*allocate) (short, int, u32, void **), | 87 | enum xp_retval (*send) (short, int, u32, void *, u16), |
70 | enum xp_retval (*send) (short, int, void *), | 88 | enum xp_retval (*send_notify) (short, int, u32, void *, u16, |
71 | enum xp_retval (*send_notify) (short, int, void *, | ||
72 | xpc_notify_func, void *), | 89 | xpc_notify_func, void *), |
73 | void (*received) (short, int, void *), | 90 | void (*received) (short, int, void *), |
74 | enum xp_retval (*partid_to_nasids) (short, void *)) | 91 | enum xp_retval (*partid_to_nasids) (short, void *)) |
75 | { | 92 | { |
76 | xpc_interface.connect = connect; | 93 | xpc_interface.connect = connect; |
77 | xpc_interface.disconnect = disconnect; | 94 | xpc_interface.disconnect = disconnect; |
78 | xpc_interface.allocate = allocate; | ||
79 | xpc_interface.send = send; | 95 | xpc_interface.send = send; |
80 | xpc_interface.send_notify = send_notify; | 96 | xpc_interface.send_notify = send_notify; |
81 | xpc_interface.received = received; | 97 | xpc_interface.received = received; |
@@ -91,13 +107,11 @@ xpc_clear_interface(void) | |||
91 | { | 107 | { |
92 | xpc_interface.connect = (void (*)(int))xpc_notloaded; | 108 | xpc_interface.connect = (void (*)(int))xpc_notloaded; |
93 | xpc_interface.disconnect = (void (*)(int))xpc_notloaded; | 109 | xpc_interface.disconnect = (void (*)(int))xpc_notloaded; |
94 | xpc_interface.allocate = (enum xp_retval(*)(short, int, u32, | 110 | xpc_interface.send = (enum xp_retval(*)(short, int, u32, void *, u16)) |
95 | void **))xpc_notloaded; | ||
96 | xpc_interface.send = (enum xp_retval(*)(short, int, void *)) | ||
97 | xpc_notloaded; | 111 | xpc_notloaded; |
98 | xpc_interface.send_notify = (enum xp_retval(*)(short, int, void *, | 112 | xpc_interface.send_notify = (enum xp_retval(*)(short, int, u32, void *, |
99 | xpc_notify_func, | 113 | u16, xpc_notify_func, |
100 | void *))xpc_notloaded; | 114 | void *))xpc_notloaded; |
101 | xpc_interface.received = (void (*)(short, int, void *)) | 115 | xpc_interface.received = (void (*)(short, int, void *)) |
102 | xpc_notloaded; | 116 | xpc_notloaded; |
103 | xpc_interface.partid_to_nasids = (enum xp_retval(*)(short, void *)) | 117 | xpc_interface.partid_to_nasids = (enum xp_retval(*)(short, void *)) |
@@ -135,11 +149,14 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, | |||
135 | { | 149 | { |
136 | struct xpc_registration *registration; | 150 | struct xpc_registration *registration; |
137 | 151 | ||
138 | DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); | 152 | DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS); |
139 | DBUG_ON(payload_size == 0 || nentries == 0); | 153 | DBUG_ON(payload_size == 0 || nentries == 0); |
140 | DBUG_ON(func == NULL); | 154 | DBUG_ON(func == NULL); |
141 | DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit); | 155 | DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit); |
142 | 156 | ||
157 | if (XPC_MSG_SIZE(payload_size) > XPC_MSG_MAX_SIZE) | ||
158 | return xpPayloadTooBig; | ||
159 | |||
143 | registration = &xpc_registrations[ch_number]; | 160 | registration = &xpc_registrations[ch_number]; |
144 | 161 | ||
145 | if (mutex_lock_interruptible(®istration->mutex) != 0) | 162 | if (mutex_lock_interruptible(®istration->mutex) != 0) |
@@ -152,7 +169,7 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, | |||
152 | } | 169 | } |
153 | 170 | ||
154 | /* register the channel for connection */ | 171 | /* register the channel for connection */ |
155 | registration->msg_size = XPC_MSG_SIZE(payload_size); | 172 | registration->entry_size = XPC_MSG_SIZE(payload_size); |
156 | registration->nentries = nentries; | 173 | registration->nentries = nentries; |
157 | registration->assigned_limit = assigned_limit; | 174 | registration->assigned_limit = assigned_limit; |
158 | registration->idle_limit = idle_limit; | 175 | registration->idle_limit = idle_limit; |
@@ -185,7 +202,7 @@ xpc_disconnect(int ch_number) | |||
185 | { | 202 | { |
186 | struct xpc_registration *registration; | 203 | struct xpc_registration *registration; |
187 | 204 | ||
188 | DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); | 205 | DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS); |
189 | 206 | ||
190 | registration = &xpc_registrations[ch_number]; | 207 | registration = &xpc_registrations[ch_number]; |
191 | 208 | ||
@@ -206,7 +223,7 @@ xpc_disconnect(int ch_number) | |||
206 | registration->func = NULL; | 223 | registration->func = NULL; |
207 | registration->key = NULL; | 224 | registration->key = NULL; |
208 | registration->nentries = 0; | 225 | registration->nentries = 0; |
209 | registration->msg_size = 0; | 226 | registration->entry_size = 0; |
210 | registration->assigned_limit = 0; | 227 | registration->assigned_limit = 0; |
211 | registration->idle_limit = 0; | 228 | registration->idle_limit = 0; |
212 | 229 | ||
@@ -221,39 +238,21 @@ EXPORT_SYMBOL_GPL(xpc_disconnect); | |||
221 | int __init | 238 | int __init |
222 | xp_init(void) | 239 | xp_init(void) |
223 | { | 240 | { |
224 | int ret, ch_number; | 241 | enum xp_retval ret; |
225 | u64 func_addr = *(u64 *)xp_nofault_PIOR; | 242 | int ch_number; |
226 | u64 err_func_addr = *(u64 *)xp_error_PIOR; | ||
227 | |||
228 | if (!ia64_platform_is("sn2")) | ||
229 | return -ENODEV; | ||
230 | 243 | ||
231 | /* | 244 | if (is_shub()) |
232 | * Register a nofault code region which performs a cross-partition | 245 | ret = xp_init_sn2(); |
233 | * PIO read. If the PIO read times out, the MCA handler will consume | 246 | else if (is_uv()) |
234 | * the error and return to a kernel-provided instruction to indicate | 247 | ret = xp_init_uv(); |
235 | * an error. This PIO read exists because it is guaranteed to timeout | ||
236 | * if the destination is down (AMO operations do not timeout on at | ||
237 | * least some CPUs on Shubs <= v1.2, which unfortunately we have to | ||
238 | * work around). | ||
239 | */ | ||
240 | ret = sn_register_nofault_code(func_addr, err_func_addr, err_func_addr, | ||
241 | 1, 1); | ||
242 | if (ret != 0) { | ||
243 | printk(KERN_ERR "XP: can't register nofault code, error=%d\n", | ||
244 | ret); | ||
245 | } | ||
246 | /* | ||
247 | * Setup the nofault PIO read target. (There is no special reason why | ||
248 | * SH_IPI_ACCESS was selected.) | ||
249 | */ | ||
250 | if (is_shub2()) | ||
251 | xp_nofault_PIOR_target = SH2_IPI_ACCESS0; | ||
252 | else | 248 | else |
253 | xp_nofault_PIOR_target = SH1_IPI_ACCESS; | 249 | ret = xpUnsupported; |
250 | |||
251 | if (ret != xpSuccess) | ||
252 | return -ENODEV; | ||
254 | 253 | ||
255 | /* initialize the connection registration mutex */ | 254 | /* initialize the connection registration mutex */ |
256 | for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) | 255 | for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) |
257 | mutex_init(&xpc_registrations[ch_number].mutex); | 256 | mutex_init(&xpc_registrations[ch_number].mutex); |
258 | 257 | ||
259 | return 0; | 258 | return 0; |
@@ -264,12 +263,10 @@ module_init(xp_init); | |||
264 | void __exit | 263 | void __exit |
265 | xp_exit(void) | 264 | xp_exit(void) |
266 | { | 265 | { |
267 | u64 func_addr = *(u64 *)xp_nofault_PIOR; | 266 | if (is_shub()) |
268 | u64 err_func_addr = *(u64 *)xp_error_PIOR; | 267 | xp_exit_sn2(); |
269 | 268 | else if (is_uv()) | |
270 | /* unregister the PIO read nofault code region */ | 269 | xp_exit_uv(); |
271 | (void)sn_register_nofault_code(func_addr, err_func_addr, | ||
272 | err_func_addr, 1, 0); | ||
273 | } | 270 | } |
274 | 271 | ||
275 | module_exit(xp_exit); | 272 | module_exit(xp_exit); |
diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c new file mode 100644 index 000000000000..1440134caf31 --- /dev/null +++ b/drivers/misc/sgi-xp/xp_sn2.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Cross Partition (XP) sn2-based functions. | ||
11 | * | ||
12 | * Architecture specific implementation of common functions. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <asm/sn/bte.h> | ||
18 | #include <asm/sn/sn_sal.h> | ||
19 | #include "xp.h" | ||
20 | |||
21 | /* | ||
22 | * The export of xp_nofault_PIOR needs to happen here since it is defined | ||
23 | * in drivers/misc/sgi-xp/xp_nofault.S. The target of the nofault read is | ||
24 | * defined here. | ||
25 | */ | ||
26 | EXPORT_SYMBOL_GPL(xp_nofault_PIOR); | ||
27 | |||
28 | u64 xp_nofault_PIOR_target; | ||
29 | EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target); | ||
30 | |||
31 | /* | ||
32 | * Register a nofault code region which performs a cross-partition PIO read. | ||
33 | * If the PIO read times out, the MCA handler will consume the error and | ||
34 | * return to a kernel-provided instruction to indicate an error. This PIO read | ||
35 | * exists because it is guaranteed to timeout if the destination is down | ||
36 | * (amo operations do not timeout on at least some CPUs on Shubs <= v1.2, | ||
37 | * which unfortunately we have to work around). | ||
38 | */ | ||
39 | static enum xp_retval | ||
40 | xp_register_nofault_code_sn2(void) | ||
41 | { | ||
42 | int ret; | ||
43 | u64 func_addr; | ||
44 | u64 err_func_addr; | ||
45 | |||
46 | func_addr = *(u64 *)xp_nofault_PIOR; | ||
47 | err_func_addr = *(u64 *)xp_error_PIOR; | ||
48 | ret = sn_register_nofault_code(func_addr, err_func_addr, err_func_addr, | ||
49 | 1, 1); | ||
50 | if (ret != 0) { | ||
51 | dev_err(xp, "can't register nofault code, error=%d\n", ret); | ||
52 | return xpSalError; | ||
53 | } | ||
54 | /* | ||
55 | * Setup the nofault PIO read target. (There is no special reason why | ||
56 | * SH_IPI_ACCESS was selected.) | ||
57 | */ | ||
58 | if (is_shub1()) | ||
59 | xp_nofault_PIOR_target = SH1_IPI_ACCESS; | ||
60 | else if (is_shub2()) | ||
61 | xp_nofault_PIOR_target = SH2_IPI_ACCESS0; | ||
62 | |||
63 | return xpSuccess; | ||
64 | } | ||
65 | |||
66 | static void | ||
67 | xp_unregister_nofault_code_sn2(void) | ||
68 | { | ||
69 | u64 func_addr = *(u64 *)xp_nofault_PIOR; | ||
70 | u64 err_func_addr = *(u64 *)xp_error_PIOR; | ||
71 | |||
72 | /* unregister the PIO read nofault code region */ | ||
73 | (void)sn_register_nofault_code(func_addr, err_func_addr, | ||
74 | err_func_addr, 1, 0); | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Convert a virtual memory address to a physical memory address. | ||
79 | */ | ||
80 | static unsigned long | ||
81 | xp_pa_sn2(void *addr) | ||
82 | { | ||
83 | return __pa(addr); | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Wrapper for bte_copy(). | ||
88 | * | ||
89 | * dst_pa - physical address of the destination of the transfer. | ||
90 | * src_pa - physical address of the source of the transfer. | ||
91 | * len - number of bytes to transfer from source to destination. | ||
92 | * | ||
93 | * Note: xp_remote_memcpy_sn2() should never be called while holding a spinlock. | ||
94 | */ | ||
95 | static enum xp_retval | ||
96 | xp_remote_memcpy_sn2(unsigned long dst_pa, const unsigned long src_pa, | ||
97 | size_t len) | ||
98 | { | ||
99 | bte_result_t ret; | ||
100 | |||
101 | ret = bte_copy(src_pa, dst_pa, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL); | ||
102 | if (ret == BTE_SUCCESS) | ||
103 | return xpSuccess; | ||
104 | |||
105 | if (is_shub2()) { | ||
106 | dev_err(xp, "bte_copy() on shub2 failed, error=0x%x dst_pa=" | ||
107 | "0x%016lx src_pa=0x%016lx len=%ld\\n", ret, dst_pa, | ||
108 | src_pa, len); | ||
109 | } else { | ||
110 | dev_err(xp, "bte_copy() failed, error=%d dst_pa=0x%016lx " | ||
111 | "src_pa=0x%016lx len=%ld\\n", ret, dst_pa, src_pa, len); | ||
112 | } | ||
113 | |||
114 | return xpBteCopyError; | ||
115 | } | ||
116 | |||
117 | static int | ||
118 | xp_cpu_to_nasid_sn2(int cpuid) | ||
119 | { | ||
120 | return cpuid_to_nasid(cpuid); | ||
121 | } | ||
122 | |||
123 | enum xp_retval | ||
124 | xp_init_sn2(void) | ||
125 | { | ||
126 | BUG_ON(!is_shub()); | ||
127 | |||
128 | xp_max_npartitions = XP_MAX_NPARTITIONS_SN2; | ||
129 | xp_partition_id = sn_partition_id; | ||
130 | xp_region_size = sn_region_size; | ||
131 | |||
132 | xp_pa = xp_pa_sn2; | ||
133 | xp_remote_memcpy = xp_remote_memcpy_sn2; | ||
134 | xp_cpu_to_nasid = xp_cpu_to_nasid_sn2; | ||
135 | |||
136 | return xp_register_nofault_code_sn2(); | ||
137 | } | ||
138 | |||
139 | void | ||
140 | xp_exit_sn2(void) | ||
141 | { | ||
142 | BUG_ON(!is_shub()); | ||
143 | |||
144 | xp_unregister_nofault_code_sn2(); | ||
145 | } | ||
146 | |||
diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c new file mode 100644 index 000000000000..d9f7ce2510bc --- /dev/null +++ b/drivers/misc/sgi-xp/xp_uv.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Cross Partition (XP) uv-based functions. | ||
11 | * | ||
12 | * Architecture specific implementation of common functions. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/device.h> | ||
17 | #include <asm/uv/uv_hub.h> | ||
18 | #include "../sgi-gru/grukservices.h" | ||
19 | #include "xp.h" | ||
20 | |||
21 | /* | ||
22 | * Convert a virtual memory address to a physical memory address. | ||
23 | */ | ||
24 | static unsigned long | ||
25 | xp_pa_uv(void *addr) | ||
26 | { | ||
27 | return uv_gpa(addr); | ||
28 | } | ||
29 | |||
30 | static enum xp_retval | ||
31 | xp_remote_memcpy_uv(unsigned long dst_gpa, const unsigned long src_gpa, | ||
32 | size_t len) | ||
33 | { | ||
34 | int ret; | ||
35 | |||
36 | ret = gru_copy_gpa(dst_gpa, src_gpa, len); | ||
37 | if (ret == 0) | ||
38 | return xpSuccess; | ||
39 | |||
40 | dev_err(xp, "gru_copy_gpa() failed, dst_gpa=0x%016lx src_gpa=0x%016lx " | ||
41 | "len=%ld\n", dst_gpa, src_gpa, len); | ||
42 | return xpGruCopyError; | ||
43 | } | ||
44 | |||
45 | static int | ||
46 | xp_cpu_to_nasid_uv(int cpuid) | ||
47 | { | ||
48 | /* ??? Is this same as sn2 nasid in mach/part bitmaps set up by SAL? */ | ||
49 | return UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpuid)); | ||
50 | } | ||
51 | |||
52 | enum xp_retval | ||
53 | xp_init_uv(void) | ||
54 | { | ||
55 | BUG_ON(!is_uv()); | ||
56 | |||
57 | xp_max_npartitions = XP_MAX_NPARTITIONS_UV; | ||
58 | xp_partition_id = 0; /* !!! not correct value */ | ||
59 | xp_region_size = 0; /* !!! not correct value */ | ||
60 | |||
61 | xp_pa = xp_pa_uv; | ||
62 | xp_remote_memcpy = xp_remote_memcpy_uv; | ||
63 | xp_cpu_to_nasid = xp_cpu_to_nasid_uv; | ||
64 | |||
65 | return xpSuccess; | ||
66 | } | ||
67 | |||
68 | void | ||
69 | xp_exit_uv(void) | ||
70 | { | ||
71 | BUG_ON(!is_uv()); | ||
72 | } | ||
diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 11ac267ed68f..619208d61862 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h | |||
@@ -13,18 +13,10 @@ | |||
13 | #ifndef _DRIVERS_MISC_SGIXP_XPC_H | 13 | #ifndef _DRIVERS_MISC_SGIXP_XPC_H |
14 | #define _DRIVERS_MISC_SGIXP_XPC_H | 14 | #define _DRIVERS_MISC_SGIXP_XPC_H |
15 | 15 | ||
16 | #include <linux/interrupt.h> | 16 | #include <linux/wait.h> |
17 | #include <linux/sysctl.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/completion.h> | 17 | #include <linux/completion.h> |
21 | #include <asm/pgtable.h> | 18 | #include <linux/timer.h> |
22 | #include <asm/processor.h> | 19 | #include <linux/sched.h> |
23 | #include <asm/sn/bte.h> | ||
24 | #include <asm/sn/clksupport.h> | ||
25 | #include <asm/sn/addrs.h> | ||
26 | #include <asm/sn/mspec.h> | ||
27 | #include <asm/sn/shub_mmr.h> | ||
28 | #include "xp.h" | 20 | #include "xp.h" |
29 | 21 | ||
30 | /* | 22 | /* |
@@ -36,23 +28,7 @@ | |||
36 | #define XPC_VERSION_MAJOR(_v) ((_v) >> 4) | 28 | #define XPC_VERSION_MAJOR(_v) ((_v) >> 4) |
37 | #define XPC_VERSION_MINOR(_v) ((_v) & 0xf) | 29 | #define XPC_VERSION_MINOR(_v) ((_v) & 0xf) |
38 | 30 | ||
39 | /* | 31 | /* define frequency of the heartbeat and frequency how often it's checked */ |
40 | * The next macros define word or bit representations for given | ||
41 | * C-brick nasid in either the SAL provided bit array representing | ||
42 | * nasids in the partition/machine or the AMO_t array used for | ||
43 | * inter-partition initiation communications. | ||
44 | * | ||
45 | * For SN2 machines, C-Bricks are alway even numbered NASIDs. As | ||
46 | * such, some space will be saved by insisting that nasid information | ||
47 | * passed from SAL always be packed for C-Bricks and the | ||
48 | * cross-partition interrupts use the same packing scheme. | ||
49 | */ | ||
50 | #define XPC_NASID_W_INDEX(_n) (((_n) / 64) / 2) | ||
51 | #define XPC_NASID_B_INDEX(_n) (((_n) / 2) & (64 - 1)) | ||
52 | #define XPC_NASID_IN_ARRAY(_n, _p) ((_p)[XPC_NASID_W_INDEX(_n)] & \ | ||
53 | (1UL << XPC_NASID_B_INDEX(_n))) | ||
54 | #define XPC_NASID_FROM_W_B(_w, _b) (((_w) * 64 + (_b)) * 2) | ||
55 | |||
56 | #define XPC_HB_DEFAULT_INTERVAL 5 /* incr HB every x secs */ | 32 | #define XPC_HB_DEFAULT_INTERVAL 5 /* incr HB every x secs */ |
57 | #define XPC_HB_CHECK_DEFAULT_INTERVAL 20 /* check HB every x secs */ | 33 | #define XPC_HB_CHECK_DEFAULT_INTERVAL 20 /* check HB every x secs */ |
58 | 34 | ||
@@ -72,11 +48,11 @@ | |||
72 | * | 48 | * |
73 | * reserved page header | 49 | * reserved page header |
74 | * | 50 | * |
75 | * The first cacheline of the reserved page contains the header | 51 | * The first two 64-byte cachelines of the reserved page contain the |
76 | * (struct xpc_rsvd_page). Before SAL initialization has completed, | 52 | * header (struct xpc_rsvd_page). Before SAL initialization has completed, |
77 | * SAL has set up the following fields of the reserved page header: | 53 | * SAL has set up the following fields of the reserved page header: |
78 | * SAL_signature, SAL_version, partid, and nasids_size. The other | 54 | * SAL_signature, SAL_version, SAL_partid, and SAL_nasids_size. The |
79 | * fields are set up by XPC. (xpc_rsvd_page points to the local | 55 | * other fields are set up by XPC. (xpc_rsvd_page points to the local |
80 | * partition's reserved page.) | 56 | * partition's reserved page.) |
81 | * | 57 | * |
82 | * part_nasids mask | 58 | * part_nasids mask |
@@ -87,14 +63,16 @@ | |||
87 | * the actual nasids in the entire machine (mach_nasids). We're only | 63 | * the actual nasids in the entire machine (mach_nasids). We're only |
88 | * interested in the even numbered nasids (which contain the processors | 64 | * interested in the even numbered nasids (which contain the processors |
89 | * and/or memory), so we only need half as many bits to represent the | 65 | * and/or memory), so we only need half as many bits to represent the |
90 | * nasids. The part_nasids mask is located starting at the first cacheline | 66 | * nasids. When mapping nasid to bit in a mask (or bit to nasid) be sure |
91 | * following the reserved page header. The mach_nasids mask follows right | 67 | * to either divide or multiply by 2. The part_nasids mask is located |
92 | * after the part_nasids mask. The size in bytes of each mask is reflected | 68 | * starting at the first cacheline following the reserved page header. The |
93 | * by the reserved page header field 'nasids_size'. (Local partition's | 69 | * mach_nasids mask follows right after the part_nasids mask. The size in |
94 | * mask pointers are xpc_part_nasids and xpc_mach_nasids.) | 70 | * bytes of each mask is reflected by the reserved page header field |
71 | * 'SAL_nasids_size'. (Local partition's mask pointers are xpc_part_nasids | ||
72 | * and xpc_mach_nasids.) | ||
95 | * | 73 | * |
96 | * vars | 74 | * vars (ia64-sn2 only) |
97 | * vars part | 75 | * vars part (ia64-sn2 only) |
98 | * | 76 | * |
99 | * Immediately following the mach_nasids mask are the XPC variables | 77 | * Immediately following the mach_nasids mask are the XPC variables |
100 | * required by other partitions. First are those that are generic to all | 78 | * required by other partitions. First are those that are generic to all |
@@ -102,43 +80,26 @@ | |||
102 | * which are partition specific (vars part). These are setup by XPC. | 80 | * which are partition specific (vars part). These are setup by XPC. |
103 | * (Local partition's vars pointers are xpc_vars and xpc_vars_part.) | 81 | * (Local partition's vars pointers are xpc_vars and xpc_vars_part.) |
104 | * | 82 | * |
105 | * Note: Until vars_pa is set, the partition XPC code has not been initialized. | 83 | * Note: Until 'ts_jiffies' is set non-zero, the partition XPC code has not been |
84 | * initialized. | ||
106 | */ | 85 | */ |
107 | struct xpc_rsvd_page { | 86 | struct xpc_rsvd_page { |
108 | u64 SAL_signature; /* SAL: unique signature */ | 87 | u64 SAL_signature; /* SAL: unique signature */ |
109 | u64 SAL_version; /* SAL: version */ | 88 | u64 SAL_version; /* SAL: version */ |
110 | u8 partid; /* SAL: partition ID */ | 89 | short SAL_partid; /* SAL: partition ID */ |
90 | short max_npartitions; /* value of XPC_MAX_PARTITIONS */ | ||
111 | u8 version; | 91 | u8 version; |
112 | u8 pad1[6]; /* align to next u64 in cacheline */ | 92 | u8 pad1[3]; /* align to next u64 in 1st 64-byte cacheline */ |
113 | u64 vars_pa; /* physical address of struct xpc_vars */ | 93 | union { |
114 | struct timespec stamp; /* time when reserved page was setup by XPC */ | 94 | unsigned long vars_pa; /* phys address of struct xpc_vars */ |
115 | u64 pad2[9]; /* align to last u64 in cacheline */ | 95 | unsigned long activate_mq_gpa; /* gru phy addr of activate_mq */ |
116 | u64 nasids_size; /* SAL: size of each nasid mask in bytes */ | 96 | } sn; |
97 | unsigned long ts_jiffies; /* timestamp when rsvd pg was setup by XPC */ | ||
98 | u64 pad2[10]; /* align to last u64 in 2nd 64-byte cacheline */ | ||
99 | u64 SAL_nasids_size; /* SAL: size of each nasid mask in bytes */ | ||
117 | }; | 100 | }; |
118 | 101 | ||
119 | #define XPC_RP_VERSION _XPC_VERSION(1, 1) /* version 1.1 of the reserved page */ | 102 | #define XPC_RP_VERSION _XPC_VERSION(2, 0) /* version 2.0 of the reserved page */ |
120 | |||
121 | #define XPC_SUPPORTS_RP_STAMP(_version) \ | ||
122 | (_version >= _XPC_VERSION(1, 1)) | ||
123 | |||
124 | /* | ||
125 | * compare stamps - the return value is: | ||
126 | * | ||
127 | * < 0, if stamp1 < stamp2 | ||
128 | * = 0, if stamp1 == stamp2 | ||
129 | * > 0, if stamp1 > stamp2 | ||
130 | */ | ||
131 | static inline int | ||
132 | xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2) | ||
133 | { | ||
134 | int ret; | ||
135 | |||
136 | ret = stamp1->tv_sec - stamp2->tv_sec; | ||
137 | if (ret == 0) | ||
138 | ret = stamp1->tv_nsec - stamp2->tv_nsec; | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | 103 | ||
143 | /* | 104 | /* |
144 | * Define the structures by which XPC variables can be exported to other | 105 | * Define the structures by which XPC variables can be exported to other |
@@ -154,85 +115,40 @@ xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2) | |||
154 | * reflected by incrementing either the major or minor version numbers | 115 | * reflected by incrementing either the major or minor version numbers |
155 | * of struct xpc_vars. | 116 | * of struct xpc_vars. |
156 | */ | 117 | */ |
157 | struct xpc_vars { | 118 | struct xpc_vars_sn2 { |
158 | u8 version; | 119 | u8 version; |
159 | u64 heartbeat; | 120 | u64 heartbeat; |
160 | u64 heartbeating_to_mask; | 121 | DECLARE_BITMAP(heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2); |
161 | u64 heartbeat_offline; /* if 0, heartbeat should be changing */ | 122 | u64 heartbeat_offline; /* if 0, heartbeat should be changing */ |
162 | int act_nasid; | 123 | int activate_IRQ_nasid; |
163 | int act_phys_cpuid; | 124 | int activate_IRQ_phys_cpuid; |
164 | u64 vars_part_pa; | 125 | unsigned long vars_part_pa; |
165 | u64 amos_page_pa; /* paddr of page of AMOs from MSPEC driver */ | 126 | unsigned long amos_page_pa;/* paddr of page of amos from MSPEC driver */ |
166 | AMO_t *amos_page; /* vaddr of page of AMOs from MSPEC driver */ | 127 | struct amo *amos_page; /* vaddr of page of amos from MSPEC driver */ |
167 | }; | 128 | }; |
168 | 129 | ||
169 | #define XPC_V_VERSION _XPC_VERSION(3, 1) /* version 3.1 of the cross vars */ | 130 | #define XPC_V_VERSION _XPC_VERSION(3, 1) /* version 3.1 of the cross vars */ |
170 | 131 | ||
171 | #define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \ | ||
172 | (_version >= _XPC_VERSION(3, 1)) | ||
173 | |||
174 | static inline int | ||
175 | xpc_hb_allowed(short partid, struct xpc_vars *vars) | ||
176 | { | ||
177 | return ((vars->heartbeating_to_mask & (1UL << partid)) != 0); | ||
178 | } | ||
179 | |||
180 | static inline void | ||
181 | xpc_allow_hb(short partid, struct xpc_vars *vars) | ||
182 | { | ||
183 | u64 old_mask, new_mask; | ||
184 | |||
185 | do { | ||
186 | old_mask = vars->heartbeating_to_mask; | ||
187 | new_mask = (old_mask | (1UL << partid)); | ||
188 | } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != | ||
189 | old_mask); | ||
190 | } | ||
191 | |||
192 | static inline void | ||
193 | xpc_disallow_hb(short partid, struct xpc_vars *vars) | ||
194 | { | ||
195 | u64 old_mask, new_mask; | ||
196 | |||
197 | do { | ||
198 | old_mask = vars->heartbeating_to_mask; | ||
199 | new_mask = (old_mask & ~(1UL << partid)); | ||
200 | } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != | ||
201 | old_mask); | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * The AMOs page consists of a number of AMO variables which are divided into | ||
206 | * four groups, The first two groups are used to identify an IRQ's sender. | ||
207 | * These two groups consist of 64 and 128 AMO variables respectively. The last | ||
208 | * two groups, consisting of just one AMO variable each, are used to identify | ||
209 | * the remote partitions that are currently engaged (from the viewpoint of | ||
210 | * the XPC running on the remote partition). | ||
211 | */ | ||
212 | #define XPC_NOTIFY_IRQ_AMOS 0 | ||
213 | #define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_PARTITIONS) | ||
214 | #define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS) | ||
215 | #define XPC_DISENGAGE_REQUEST_AMO (XPC_ENGAGED_PARTITIONS_AMO + 1) | ||
216 | |||
217 | /* | 132 | /* |
218 | * The following structure describes the per partition specific variables. | 133 | * The following structure describes the per partition specific variables. |
219 | * | 134 | * |
220 | * An array of these structures, one per partition, will be defined. As a | 135 | * An array of these structures, one per partition, will be defined. As a |
221 | * partition becomes active XPC will copy the array entry corresponding to | 136 | * partition becomes active XPC will copy the array entry corresponding to |
222 | * itself from that partition. It is desirable that the size of this | 137 | * itself from that partition. It is desirable that the size of this structure |
223 | * structure evenly divide into a cacheline, such that none of the entries | 138 | * evenly divides into a 128-byte cacheline, such that none of the entries in |
224 | * in this array crosses a cacheline boundary. As it is now, each entry | 139 | * this array crosses a 128-byte cacheline boundary. As it is now, each entry |
225 | * occupies half a cacheline. | 140 | * occupies 64-bytes. |
226 | */ | 141 | */ |
227 | struct xpc_vars_part { | 142 | struct xpc_vars_part_sn2 { |
228 | u64 magic; | 143 | u64 magic; |
229 | 144 | ||
230 | u64 openclose_args_pa; /* physical address of open and close args */ | 145 | unsigned long openclose_args_pa; /* phys addr of open and close args */ |
231 | u64 GPs_pa; /* physical address of Get/Put values */ | 146 | unsigned long GPs_pa; /* physical address of Get/Put values */ |
147 | |||
148 | unsigned long chctl_amo_pa; /* physical address of chctl flags' amo */ | ||
232 | 149 | ||
233 | u64 IPI_amo_pa; /* physical address of IPI AMO_t structure */ | 150 | int notify_IRQ_nasid; /* nasid of where to send notify IRQs */ |
234 | int IPI_nasid; /* nasid of where to send IPIs */ | 151 | int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */ |
235 | int IPI_phys_cpuid; /* physical CPU ID of where to send IPIs */ | ||
236 | 152 | ||
237 | u8 nchannels; /* #of defined channels supported */ | 153 | u8 nchannels; /* #of defined channels supported */ |
238 | 154 | ||
@@ -248,20 +164,95 @@ struct xpc_vars_part { | |||
248 | * MAGIC2 indicates that this partition has pulled the remote partititions | 164 | * MAGIC2 indicates that this partition has pulled the remote partititions |
249 | * per partition variables that pertain to this partition. | 165 | * per partition variables that pertain to this partition. |
250 | */ | 166 | */ |
251 | #define XPC_VP_MAGIC1 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */ | 167 | #define XPC_VP_MAGIC1_SN2 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */ |
252 | #define XPC_VP_MAGIC2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */ | 168 | #define XPC_VP_MAGIC2_SN2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */ |
253 | 169 | ||
254 | /* the reserved page sizes and offsets */ | 170 | /* the reserved page sizes and offsets */ |
255 | 171 | ||
256 | #define XPC_RP_HEADER_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page)) | 172 | #define XPC_RP_HEADER_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page)) |
257 | #define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars)) | 173 | #define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars_sn2)) |
258 | 174 | ||
259 | #define XPC_RP_PART_NASIDS(_rp) ((u64 *)((u8 *)(_rp) + XPC_RP_HEADER_SIZE)) | 175 | #define XPC_RP_PART_NASIDS(_rp) ((unsigned long *)((u8 *)(_rp) + \ |
260 | #define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words) | 176 | XPC_RP_HEADER_SIZE)) |
261 | #define XPC_RP_VARS(_rp) ((struct xpc_vars *)(XPC_RP_MACH_NASIDS(_rp) + \ | 177 | #define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + \ |
262 | xp_nasid_mask_words)) | 178 | xpc_nasid_mask_nlongs) |
263 | #define XPC_RP_VARS_PART(_rp) ((struct xpc_vars_part *) \ | 179 | #define XPC_RP_VARS(_rp) ((struct xpc_vars_sn2 *) \ |
264 | ((u8 *)XPC_RP_VARS(_rp) + XPC_RP_VARS_SIZE)) | 180 | (XPC_RP_MACH_NASIDS(_rp) + \ |
181 | xpc_nasid_mask_nlongs)) | ||
182 | |||
183 | /* | ||
184 | * The activate_mq is used to send/receive GRU messages that affect XPC's | ||
185 | * heartbeat, partition active state, and channel state. This is UV only. | ||
186 | */ | ||
187 | struct xpc_activate_mq_msghdr_uv { | ||
188 | short partid; /* sender's partid */ | ||
189 | u8 act_state; /* sender's act_state at time msg sent */ | ||
190 | u8 type; /* message's type */ | ||
191 | unsigned long rp_ts_jiffies; /* timestamp of sender's rp setup by XPC */ | ||
192 | }; | ||
193 | |||
194 | /* activate_mq defined message types */ | ||
195 | #define XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV 0 | ||
196 | #define XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV 1 | ||
197 | #define XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV 2 | ||
198 | #define XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV 3 | ||
199 | |||
200 | #define XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV 4 | ||
201 | #define XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV 5 | ||
202 | |||
203 | #define XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV 6 | ||
204 | #define XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV 7 | ||
205 | #define XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV 8 | ||
206 | #define XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV 9 | ||
207 | |||
208 | #define XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV 10 | ||
209 | #define XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV 11 | ||
210 | |||
211 | struct xpc_activate_mq_msg_uv { | ||
212 | struct xpc_activate_mq_msghdr_uv hdr; | ||
213 | }; | ||
214 | |||
215 | struct xpc_activate_mq_msg_heartbeat_req_uv { | ||
216 | struct xpc_activate_mq_msghdr_uv hdr; | ||
217 | u64 heartbeat; | ||
218 | }; | ||
219 | |||
220 | struct xpc_activate_mq_msg_activate_req_uv { | ||
221 | struct xpc_activate_mq_msghdr_uv hdr; | ||
222 | unsigned long rp_gpa; | ||
223 | unsigned long activate_mq_gpa; | ||
224 | }; | ||
225 | |||
226 | struct xpc_activate_mq_msg_deactivate_req_uv { | ||
227 | struct xpc_activate_mq_msghdr_uv hdr; | ||
228 | enum xp_retval reason; | ||
229 | }; | ||
230 | |||
231 | struct xpc_activate_mq_msg_chctl_closerequest_uv { | ||
232 | struct xpc_activate_mq_msghdr_uv hdr; | ||
233 | short ch_number; | ||
234 | enum xp_retval reason; | ||
235 | }; | ||
236 | |||
237 | struct xpc_activate_mq_msg_chctl_closereply_uv { | ||
238 | struct xpc_activate_mq_msghdr_uv hdr; | ||
239 | short ch_number; | ||
240 | }; | ||
241 | |||
242 | struct xpc_activate_mq_msg_chctl_openrequest_uv { | ||
243 | struct xpc_activate_mq_msghdr_uv hdr; | ||
244 | short ch_number; | ||
245 | short entry_size; /* size of notify_mq's GRU messages */ | ||
246 | short local_nentries; /* ??? Is this needed? What is? */ | ||
247 | }; | ||
248 | |||
249 | struct xpc_activate_mq_msg_chctl_openreply_uv { | ||
250 | struct xpc_activate_mq_msghdr_uv hdr; | ||
251 | short ch_number; | ||
252 | short remote_nentries; /* ??? Is this needed? What is? */ | ||
253 | short local_nentries; /* ??? Is this needed? What is? */ | ||
254 | unsigned long local_notify_mq_gpa; | ||
255 | }; | ||
265 | 256 | ||
266 | /* | 257 | /* |
267 | * Functions registered by add_timer() or called by kernel_thread() only | 258 | * Functions registered by add_timer() or called by kernel_thread() only |
@@ -270,22 +261,22 @@ struct xpc_vars_part { | |||
270 | * the passed argument. | 261 | * the passed argument. |
271 | */ | 262 | */ |
272 | #define XPC_PACK_ARGS(_arg1, _arg2) \ | 263 | #define XPC_PACK_ARGS(_arg1, _arg2) \ |
273 | ((((u64) _arg1) & 0xffffffff) | \ | 264 | ((((u64)_arg1) & 0xffffffff) | \ |
274 | ((((u64) _arg2) & 0xffffffff) << 32)) | 265 | ((((u64)_arg2) & 0xffffffff) << 32)) |
275 | 266 | ||
276 | #define XPC_UNPACK_ARG1(_args) (((u64) _args) & 0xffffffff) | 267 | #define XPC_UNPACK_ARG1(_args) (((u64)_args) & 0xffffffff) |
277 | #define XPC_UNPACK_ARG2(_args) ((((u64) _args) >> 32) & 0xffffffff) | 268 | #define XPC_UNPACK_ARG2(_args) ((((u64)_args) >> 32) & 0xffffffff) |
278 | 269 | ||
279 | /* | 270 | /* |
280 | * Define a Get/Put value pair (pointers) used with a message queue. | 271 | * Define a Get/Put value pair (pointers) used with a message queue. |
281 | */ | 272 | */ |
282 | struct xpc_gp { | 273 | struct xpc_gp_sn2 { |
283 | s64 get; /* Get value */ | 274 | s64 get; /* Get value */ |
284 | s64 put; /* Put value */ | 275 | s64 put; /* Put value */ |
285 | }; | 276 | }; |
286 | 277 | ||
287 | #define XPC_GP_SIZE \ | 278 | #define XPC_GP_SIZE \ |
288 | L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_NCHANNELS) | 279 | L1_CACHE_ALIGN(sizeof(struct xpc_gp_sn2) * XPC_MAX_NCHANNELS) |
289 | 280 | ||
290 | /* | 281 | /* |
291 | * Define a structure that contains arguments associated with opening and | 282 | * Define a structure that contains arguments associated with opening and |
@@ -293,31 +284,89 @@ struct xpc_gp { | |||
293 | */ | 284 | */ |
294 | struct xpc_openclose_args { | 285 | struct xpc_openclose_args { |
295 | u16 reason; /* reason why channel is closing */ | 286 | u16 reason; /* reason why channel is closing */ |
296 | u16 msg_size; /* sizeof each message entry */ | 287 | u16 entry_size; /* sizeof each message entry */ |
297 | u16 remote_nentries; /* #of message entries in remote msg queue */ | 288 | u16 remote_nentries; /* #of message entries in remote msg queue */ |
298 | u16 local_nentries; /* #of message entries in local msg queue */ | 289 | u16 local_nentries; /* #of message entries in local msg queue */ |
299 | u64 local_msgqueue_pa; /* physical address of local message queue */ | 290 | unsigned long local_msgqueue_pa; /* phys addr of local message queue */ |
300 | }; | 291 | }; |
301 | 292 | ||
302 | #define XPC_OPENCLOSE_ARGS_SIZE \ | 293 | #define XPC_OPENCLOSE_ARGS_SIZE \ |
303 | L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * XPC_NCHANNELS) | 294 | L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * \ |
295 | XPC_MAX_NCHANNELS) | ||
304 | 296 | ||
305 | /* struct xpc_msg flags */ | ||
306 | 297 | ||
307 | #define XPC_M_DONE 0x01 /* msg has been received/consumed */ | 298 | /* |
308 | #define XPC_M_READY 0x02 /* msg is ready to be sent */ | 299 | * Structures to define a fifo singly-linked list. |
309 | #define XPC_M_INTERRUPT 0x04 /* send interrupt when msg consumed */ | 300 | */ |
310 | 301 | ||
311 | #define XPC_MSG_ADDRESS(_payload) \ | 302 | struct xpc_fifo_entry_uv { |
312 | ((struct xpc_msg *)((u8 *)(_payload) - XPC_MSG_PAYLOAD_OFFSET)) | 303 | struct xpc_fifo_entry_uv *next; |
304 | }; | ||
305 | |||
306 | struct xpc_fifo_head_uv { | ||
307 | struct xpc_fifo_entry_uv *first; | ||
308 | struct xpc_fifo_entry_uv *last; | ||
309 | spinlock_t lock; | ||
310 | int n_entries; | ||
311 | }; | ||
313 | 312 | ||
314 | /* | 313 | /* |
315 | * Defines notify entry. | 314 | * Define a sn2 styled message. |
315 | * | ||
316 | * A user-defined message resides in the payload area. The max size of the | ||
317 | * payload is defined by the user via xpc_connect(). | ||
318 | * | ||
319 | * The size of a message entry (within a message queue) must be a 128-byte | ||
320 | * cacheline sized multiple in order to facilitate the BTE transfer of messages | ||
321 | * from one message queue to another. | ||
322 | */ | ||
323 | struct xpc_msg_sn2 { | ||
324 | u8 flags; /* FOR XPC INTERNAL USE ONLY */ | ||
325 | u8 reserved[7]; /* FOR XPC INTERNAL USE ONLY */ | ||
326 | s64 number; /* FOR XPC INTERNAL USE ONLY */ | ||
327 | |||
328 | u64 payload; /* user defined portion of message */ | ||
329 | }; | ||
330 | |||
331 | /* struct xpc_msg_sn2 flags */ | ||
332 | |||
333 | #define XPC_M_SN2_DONE 0x01 /* msg has been received/consumed */ | ||
334 | #define XPC_M_SN2_READY 0x02 /* msg is ready to be sent */ | ||
335 | #define XPC_M_SN2_INTERRUPT 0x04 /* send interrupt when msg consumed */ | ||
336 | |||
337 | /* | ||
338 | * The format of a uv XPC notify_mq GRU message is as follows: | ||
339 | * | ||
340 | * A user-defined message resides in the payload area. The max size of the | ||
341 | * payload is defined by the user via xpc_connect(). | ||
342 | * | ||
343 | * The size of a message (payload and header) sent via the GRU must be either 1 | ||
344 | * or 2 GRU_CACHE_LINE_BYTES in length. | ||
345 | */ | ||
346 | |||
347 | struct xpc_notify_mq_msghdr_uv { | ||
348 | union { | ||
349 | unsigned int gru_msg_hdr; /* FOR GRU INTERNAL USE ONLY */ | ||
350 | struct xpc_fifo_entry_uv next; /* FOR XPC INTERNAL USE ONLY */ | ||
351 | } u; | ||
352 | short partid; /* FOR XPC INTERNAL USE ONLY */ | ||
353 | u8 ch_number; /* FOR XPC INTERNAL USE ONLY */ | ||
354 | u8 size; /* FOR XPC INTERNAL USE ONLY */ | ||
355 | unsigned int msg_slot_number; /* FOR XPC INTERNAL USE ONLY */ | ||
356 | }; | ||
357 | |||
358 | struct xpc_notify_mq_msg_uv { | ||
359 | struct xpc_notify_mq_msghdr_uv hdr; | ||
360 | unsigned long payload; | ||
361 | }; | ||
362 | |||
363 | /* | ||
364 | * Define sn2's notify entry. | ||
316 | * | 365 | * |
317 | * This is used to notify a message's sender that their message was received | 366 | * This is used to notify a message's sender that their message was received |
318 | * and consumed by the intended recipient. | 367 | * and consumed by the intended recipient. |
319 | */ | 368 | */ |
320 | struct xpc_notify { | 369 | struct xpc_notify_sn2 { |
321 | u8 type; /* type of notification */ | 370 | u8 type; /* type of notification */ |
322 | 371 | ||
323 | /* the following two fields are only used if type == XPC_N_CALL */ | 372 | /* the following two fields are only used if type == XPC_N_CALL */ |
@@ -325,9 +374,20 @@ struct xpc_notify { | |||
325 | void *key; /* pointer to user's key */ | 374 | void *key; /* pointer to user's key */ |
326 | }; | 375 | }; |
327 | 376 | ||
328 | /* struct xpc_notify type of notification */ | 377 | /* struct xpc_notify_sn2 type of notification */ |
378 | |||
379 | #define XPC_N_CALL 0x01 /* notify function provided by user */ | ||
329 | 380 | ||
330 | #define XPC_N_CALL 0x01 /* notify function provided by user */ | 381 | /* |
382 | * Define uv's version of the notify entry. It additionally is used to allocate | ||
383 | * a msg slot on the remote partition into which is copied a sent message. | ||
384 | */ | ||
385 | struct xpc_send_msg_slot_uv { | ||
386 | struct xpc_fifo_entry_uv next; | ||
387 | unsigned int msg_slot_number; | ||
388 | xpc_notify_func func; /* user's notify function */ | ||
389 | void *key; /* pointer to user's key */ | ||
390 | }; | ||
331 | 391 | ||
332 | /* | 392 | /* |
333 | * Define the structure that manages all the stuff required by a channel. In | 393 | * Define the structure that manages all the stuff required by a channel. In |
@@ -339,8 +399,12 @@ struct xpc_notify { | |||
339 | * There is an array of these structures for each remote partition. It is | 399 | * There is an array of these structures for each remote partition. It is |
340 | * allocated at the time a partition becomes active. The array contains one | 400 | * allocated at the time a partition becomes active. The array contains one |
341 | * of these structures for each potential channel connection to that partition. | 401 | * of these structures for each potential channel connection to that partition. |
402 | */ | ||
403 | |||
404 | /* | ||
405 | * The following is sn2 only. | ||
342 | * | 406 | * |
343 | * Each of these structures manages two message queues (circular buffers). | 407 | * Each channel structure manages two message queues (circular buffers). |
344 | * They are allocated at the time a channel connection is made. One of | 408 | * They are allocated at the time a channel connection is made. One of |
345 | * these message queues (local_msgqueue) holds the locally created messages | 409 | * these message queues (local_msgqueue) holds the locally created messages |
346 | * that are destined for the remote partition. The other of these message | 410 | * that are destined for the remote partition. The other of these message |
@@ -407,58 +471,72 @@ struct xpc_notify { | |||
407 | * new messages, by the clearing of the message flags of the acknowledged | 471 | * new messages, by the clearing of the message flags of the acknowledged |
408 | * messages. | 472 | * messages. |
409 | */ | 473 | */ |
474 | |||
475 | struct xpc_channel_sn2 { | ||
476 | struct xpc_openclose_args *local_openclose_args; /* args passed on */ | ||
477 | /* opening or closing of channel */ | ||
478 | |||
479 | void *local_msgqueue_base; /* base address of kmalloc'd space */ | ||
480 | struct xpc_msg_sn2 *local_msgqueue; /* local message queue */ | ||
481 | void *remote_msgqueue_base; /* base address of kmalloc'd space */ | ||
482 | struct xpc_msg_sn2 *remote_msgqueue; /* cached copy of remote */ | ||
483 | /* partition's local message queue */ | ||
484 | unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */ | ||
485 | /* local message queue */ | ||
486 | |||
487 | struct xpc_notify_sn2 *notify_queue;/* notify queue for messages sent */ | ||
488 | |||
489 | /* various flavors of local and remote Get/Put values */ | ||
490 | |||
491 | struct xpc_gp_sn2 *local_GP; /* local Get/Put values */ | ||
492 | struct xpc_gp_sn2 remote_GP; /* remote Get/Put values */ | ||
493 | struct xpc_gp_sn2 w_local_GP; /* working local Get/Put values */ | ||
494 | struct xpc_gp_sn2 w_remote_GP; /* working remote Get/Put values */ | ||
495 | s64 next_msg_to_pull; /* Put value of next msg to pull */ | ||
496 | |||
497 | struct mutex msg_to_pull_mutex; /* next msg to pull serialization */ | ||
498 | }; | ||
499 | |||
500 | struct xpc_channel_uv { | ||
501 | unsigned long remote_notify_mq_gpa; /* gru phys address of remote */ | ||
502 | /* partition's notify mq */ | ||
503 | |||
504 | struct xpc_send_msg_slot_uv *send_msg_slots; | ||
505 | struct xpc_notify_mq_msg_uv *recv_msg_slots; | ||
506 | |||
507 | struct xpc_fifo_head_uv msg_slot_free_list; | ||
508 | struct xpc_fifo_head_uv recv_msg_list; /* deliverable payloads */ | ||
509 | }; | ||
510 | |||
410 | struct xpc_channel { | 511 | struct xpc_channel { |
411 | short partid; /* ID of remote partition connected */ | 512 | short partid; /* ID of remote partition connected */ |
412 | spinlock_t lock; /* lock for updating this structure */ | 513 | spinlock_t lock; /* lock for updating this structure */ |
413 | u32 flags; /* general flags */ | 514 | unsigned int flags; /* general flags */ |
414 | 515 | ||
415 | enum xp_retval reason; /* reason why channel is disconnect'g */ | 516 | enum xp_retval reason; /* reason why channel is disconnect'g */ |
416 | int reason_line; /* line# disconnect initiated from */ | 517 | int reason_line; /* line# disconnect initiated from */ |
417 | 518 | ||
418 | u16 number; /* channel # */ | 519 | u16 number; /* channel # */ |
419 | 520 | ||
420 | u16 msg_size; /* sizeof each msg entry */ | 521 | u16 entry_size; /* sizeof each msg entry */ |
421 | u16 local_nentries; /* #of msg entries in local msg queue */ | 522 | u16 local_nentries; /* #of msg entries in local msg queue */ |
422 | u16 remote_nentries; /* #of msg entries in remote msg queue */ | 523 | u16 remote_nentries; /* #of msg entries in remote msg queue */ |
423 | 524 | ||
424 | void *local_msgqueue_base; /* base address of kmalloc'd space */ | ||
425 | struct xpc_msg *local_msgqueue; /* local message queue */ | ||
426 | void *remote_msgqueue_base; /* base address of kmalloc'd space */ | ||
427 | struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */ | ||
428 | /* local message queue */ | ||
429 | u64 remote_msgqueue_pa; /* phys addr of remote partition's */ | ||
430 | /* local message queue */ | ||
431 | |||
432 | atomic_t references; /* #of external references to queues */ | 525 | atomic_t references; /* #of external references to queues */ |
433 | 526 | ||
434 | atomic_t n_on_msg_allocate_wq; /* #on msg allocation wait queue */ | 527 | atomic_t n_on_msg_allocate_wq; /* #on msg allocation wait queue */ |
435 | wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */ | 528 | wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */ |
436 | 529 | ||
437 | u8 delayed_IPI_flags; /* IPI flags received, but delayed */ | 530 | u8 delayed_chctl_flags; /* chctl flags received, but delayed */ |
438 | /* action until channel disconnected */ | 531 | /* action until channel disconnected */ |
439 | 532 | ||
440 | /* queue of msg senders who want to be notified when msg received */ | ||
441 | |||
442 | atomic_t n_to_notify; /* #of msg senders to notify */ | 533 | atomic_t n_to_notify; /* #of msg senders to notify */ |
443 | struct xpc_notify *notify_queue; /* notify queue for messages sent */ | ||
444 | 534 | ||
445 | xpc_channel_func func; /* user's channel function */ | 535 | xpc_channel_func func; /* user's channel function */ |
446 | void *key; /* pointer to user's key */ | 536 | void *key; /* pointer to user's key */ |
447 | 537 | ||
448 | struct mutex msg_to_pull_mutex; /* next msg to pull serialization */ | ||
449 | struct completion wdisconnect_wait; /* wait for channel disconnect */ | 538 | struct completion wdisconnect_wait; /* wait for channel disconnect */ |
450 | 539 | ||
451 | struct xpc_openclose_args *local_openclose_args; /* args passed on */ | ||
452 | /* opening or closing of channel */ | ||
453 | |||
454 | /* various flavors of local and remote Get/Put values */ | ||
455 | |||
456 | struct xpc_gp *local_GP; /* local Get/Put values */ | ||
457 | struct xpc_gp remote_GP; /* remote Get/Put values */ | ||
458 | struct xpc_gp w_local_GP; /* working local Get/Put values */ | ||
459 | struct xpc_gp w_remote_GP; /* working remote Get/Put values */ | ||
460 | s64 next_msg_to_pull; /* Put value of next msg to pull */ | ||
461 | |||
462 | /* kthread management related fields */ | 540 | /* kthread management related fields */ |
463 | 541 | ||
464 | atomic_t kthreads_assigned; /* #of kthreads assigned to channel */ | 542 | atomic_t kthreads_assigned; /* #of kthreads assigned to channel */ |
@@ -469,6 +547,11 @@ struct xpc_channel { | |||
469 | 547 | ||
470 | wait_queue_head_t idle_wq; /* idle kthread wait queue */ | 548 | wait_queue_head_t idle_wq; /* idle kthread wait queue */ |
471 | 549 | ||
550 | union { | ||
551 | struct xpc_channel_sn2 sn2; | ||
552 | struct xpc_channel_uv uv; | ||
553 | } sn; | ||
554 | |||
472 | } ____cacheline_aligned; | 555 | } ____cacheline_aligned; |
473 | 556 | ||
474 | /* struct xpc_channel flags */ | 557 | /* struct xpc_channel flags */ |
@@ -501,33 +584,128 @@ struct xpc_channel { | |||
501 | #define XPC_C_WDISCONNECT 0x00040000 /* waiting for channel disconnect */ | 584 | #define XPC_C_WDISCONNECT 0x00040000 /* waiting for channel disconnect */ |
502 | 585 | ||
503 | /* | 586 | /* |
504 | * Manages channels on a partition basis. There is one of these structures | 587 | * The channel control flags (chctl) union consists of a 64-bit variable which |
588 | * is divided up into eight bytes, ordered from right to left. Byte zero | ||
589 | * pertains to channel 0, byte one to channel 1, and so on. Each channel's byte | ||
590 | * can have one or more of the chctl flags set in it. | ||
591 | */ | ||
592 | |||
593 | union xpc_channel_ctl_flags { | ||
594 | u64 all_flags; | ||
595 | u8 flags[XPC_MAX_NCHANNELS]; | ||
596 | }; | ||
597 | |||
598 | /* chctl flags */ | ||
599 | #define XPC_CHCTL_CLOSEREQUEST 0x01 | ||
600 | #define XPC_CHCTL_CLOSEREPLY 0x02 | ||
601 | #define XPC_CHCTL_OPENREQUEST 0x04 | ||
602 | #define XPC_CHCTL_OPENREPLY 0x08 | ||
603 | #define XPC_CHCTL_MSGREQUEST 0x10 | ||
604 | |||
605 | #define XPC_OPENCLOSE_CHCTL_FLAGS \ | ||
606 | (XPC_CHCTL_CLOSEREQUEST | XPC_CHCTL_CLOSEREPLY | \ | ||
607 | XPC_CHCTL_OPENREQUEST | XPC_CHCTL_OPENREPLY) | ||
608 | #define XPC_MSG_CHCTL_FLAGS XPC_CHCTL_MSGREQUEST | ||
609 | |||
610 | static inline int | ||
611 | xpc_any_openclose_chctl_flags_set(union xpc_channel_ctl_flags *chctl) | ||
612 | { | ||
613 | int ch_number; | ||
614 | |||
615 | for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) { | ||
616 | if (chctl->flags[ch_number] & XPC_OPENCLOSE_CHCTL_FLAGS) | ||
617 | return 1; | ||
618 | } | ||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static inline int | ||
623 | xpc_any_msg_chctl_flags_set(union xpc_channel_ctl_flags *chctl) | ||
624 | { | ||
625 | int ch_number; | ||
626 | |||
627 | for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) { | ||
628 | if (chctl->flags[ch_number] & XPC_MSG_CHCTL_FLAGS) | ||
629 | return 1; | ||
630 | } | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * Manage channels on a partition basis. There is one of these structures | ||
505 | * for each partition (a partition will never utilize the structure that | 636 | * for each partition (a partition will never utilize the structure that |
506 | * represents itself). | 637 | * represents itself). |
507 | */ | 638 | */ |
639 | |||
640 | struct xpc_partition_sn2 { | ||
641 | unsigned long remote_amos_page_pa; /* paddr of partition's amos page */ | ||
642 | int activate_IRQ_nasid; /* active partition's act/deact nasid */ | ||
643 | int activate_IRQ_phys_cpuid; /* active part's act/deact phys cpuid */ | ||
644 | |||
645 | unsigned long remote_vars_pa; /* phys addr of partition's vars */ | ||
646 | unsigned long remote_vars_part_pa; /* paddr of partition's vars part */ | ||
647 | u8 remote_vars_version; /* version# of partition's vars */ | ||
648 | |||
649 | void *local_GPs_base; /* base address of kmalloc'd space */ | ||
650 | struct xpc_gp_sn2 *local_GPs; /* local Get/Put values */ | ||
651 | void *remote_GPs_base; /* base address of kmalloc'd space */ | ||
652 | struct xpc_gp_sn2 *remote_GPs; /* copy of remote partition's local */ | ||
653 | /* Get/Put values */ | ||
654 | unsigned long remote_GPs_pa; /* phys addr of remote partition's local */ | ||
655 | /* Get/Put values */ | ||
656 | |||
657 | void *local_openclose_args_base; /* base address of kmalloc'd space */ | ||
658 | struct xpc_openclose_args *local_openclose_args; /* local's args */ | ||
659 | unsigned long remote_openclose_args_pa; /* phys addr of remote's args */ | ||
660 | |||
661 | int notify_IRQ_nasid; /* nasid of where to send notify IRQs */ | ||
662 | int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */ | ||
663 | char notify_IRQ_owner[8]; /* notify IRQ's owner's name */ | ||
664 | |||
665 | struct amo *remote_chctl_amo_va; /* addr of remote chctl flags' amo */ | ||
666 | struct amo *local_chctl_amo_va; /* address of chctl flags' amo */ | ||
667 | |||
668 | struct timer_list dropped_notify_IRQ_timer; /* dropped IRQ timer */ | ||
669 | }; | ||
670 | |||
671 | struct xpc_partition_uv { | ||
672 | unsigned long remote_activate_mq_gpa; /* gru phys address of remote */ | ||
673 | /* partition's activate mq */ | ||
674 | spinlock_t flags_lock; /* protect updating of flags */ | ||
675 | unsigned int flags; /* general flags */ | ||
676 | u8 remote_act_state; /* remote partition's act_state */ | ||
677 | u8 act_state_req; /* act_state request from remote partition */ | ||
678 | enum xp_retval reason; /* reason for deactivate act_state request */ | ||
679 | u64 heartbeat; /* incremented by remote partition */ | ||
680 | }; | ||
681 | |||
682 | /* struct xpc_partition_uv flags */ | ||
683 | |||
684 | #define XPC_P_HEARTBEAT_OFFLINE_UV 0x00000001 | ||
685 | #define XPC_P_ENGAGED_UV 0x00000002 | ||
686 | |||
687 | /* struct xpc_partition_uv act_state change requests */ | ||
688 | |||
689 | #define XPC_P_ASR_ACTIVATE_UV 0x01 | ||
690 | #define XPC_P_ASR_REACTIVATE_UV 0x02 | ||
691 | #define XPC_P_ASR_DEACTIVATE_UV 0x03 | ||
692 | |||
508 | struct xpc_partition { | 693 | struct xpc_partition { |
509 | 694 | ||
510 | /* XPC HB infrastructure */ | 695 | /* XPC HB infrastructure */ |
511 | 696 | ||
512 | u8 remote_rp_version; /* version# of partition's rsvd pg */ | 697 | u8 remote_rp_version; /* version# of partition's rsvd pg */ |
513 | struct timespec remote_rp_stamp; /* time when rsvd pg was initialized */ | 698 | unsigned long remote_rp_ts_jiffies; /* timestamp when rsvd pg setup */ |
514 | u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ | 699 | unsigned long remote_rp_pa; /* phys addr of partition's rsvd pg */ |
515 | u64 remote_vars_pa; /* phys addr of partition's vars */ | ||
516 | u64 remote_vars_part_pa; /* phys addr of partition's vars part */ | ||
517 | u64 last_heartbeat; /* HB at last read */ | 700 | u64 last_heartbeat; /* HB at last read */ |
518 | u64 remote_amos_page_pa; /* phys addr of partition's amos page */ | 701 | u32 activate_IRQ_rcvd; /* IRQs since activation */ |
519 | int remote_act_nasid; /* active part's act/deact nasid */ | ||
520 | int remote_act_phys_cpuid; /* active part's act/deact phys cpuid */ | ||
521 | u32 act_IRQ_rcvd; /* IRQs since activation */ | ||
522 | spinlock_t act_lock; /* protect updating of act_state */ | 702 | spinlock_t act_lock; /* protect updating of act_state */ |
523 | u8 act_state; /* from XPC HB viewpoint */ | 703 | u8 act_state; /* from XPC HB viewpoint */ |
524 | u8 remote_vars_version; /* version# of partition's vars */ | ||
525 | enum xp_retval reason; /* reason partition is deactivating */ | 704 | enum xp_retval reason; /* reason partition is deactivating */ |
526 | int reason_line; /* line# deactivation initiated from */ | 705 | int reason_line; /* line# deactivation initiated from */ |
527 | int reactivate_nasid; /* nasid in partition to reactivate */ | ||
528 | 706 | ||
529 | unsigned long disengage_request_timeout; /* timeout in jiffies */ | 707 | unsigned long disengage_timeout; /* timeout in jiffies */ |
530 | struct timer_list disengage_request_timer; | 708 | struct timer_list disengage_timer; |
531 | 709 | ||
532 | /* XPC infrastructure referencing and teardown control */ | 710 | /* XPC infrastructure referencing and teardown control */ |
533 | 711 | ||
@@ -535,85 +713,63 @@ struct xpc_partition { | |||
535 | wait_queue_head_t teardown_wq; /* kthread waiting to teardown infra */ | 713 | wait_queue_head_t teardown_wq; /* kthread waiting to teardown infra */ |
536 | atomic_t references; /* #of references to infrastructure */ | 714 | atomic_t references; /* #of references to infrastructure */ |
537 | 715 | ||
538 | /* | ||
539 | * NONE OF THE PRECEDING FIELDS OF THIS STRUCTURE WILL BE CLEARED WHEN | ||
540 | * XPC SETS UP THE NECESSARY INFRASTRUCTURE TO SUPPORT CROSS PARTITION | ||
541 | * COMMUNICATION. ALL OF THE FOLLOWING FIELDS WILL BE CLEARED. (THE | ||
542 | * 'nchannels' FIELD MUST BE THE FIRST OF THE FIELDS TO BE CLEARED.) | ||
543 | */ | ||
544 | |||
545 | u8 nchannels; /* #of defined channels supported */ | 716 | u8 nchannels; /* #of defined channels supported */ |
546 | atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */ | 717 | atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */ |
547 | atomic_t nchannels_engaged; /* #of channels engaged with remote part */ | 718 | atomic_t nchannels_engaged; /* #of channels engaged with remote part */ |
548 | struct xpc_channel *channels; /* array of channel structures */ | 719 | struct xpc_channel *channels; /* array of channel structures */ |
549 | 720 | ||
550 | void *local_GPs_base; /* base address of kmalloc'd space */ | 721 | /* fields used for managing channel avialability and activity */ |
551 | struct xpc_gp *local_GPs; /* local Get/Put values */ | ||
552 | void *remote_GPs_base; /* base address of kmalloc'd space */ | ||
553 | struct xpc_gp *remote_GPs; /* copy of remote partition's local */ | ||
554 | /* Get/Put values */ | ||
555 | u64 remote_GPs_pa; /* phys address of remote partition's local */ | ||
556 | /* Get/Put values */ | ||
557 | 722 | ||
558 | /* fields used to pass args when opening or closing a channel */ | 723 | union xpc_channel_ctl_flags chctl; /* chctl flags yet to be processed */ |
724 | spinlock_t chctl_lock; /* chctl flags lock */ | ||
559 | 725 | ||
560 | void *local_openclose_args_base; /* base address of kmalloc'd space */ | ||
561 | struct xpc_openclose_args *local_openclose_args; /* local's args */ | ||
562 | void *remote_openclose_args_base; /* base address of kmalloc'd space */ | 726 | void *remote_openclose_args_base; /* base address of kmalloc'd space */ |
563 | struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */ | 727 | struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */ |
564 | /* args */ | 728 | /* args */ |
565 | u64 remote_openclose_args_pa; /* phys addr of remote's args */ | ||
566 | |||
567 | /* IPI sending, receiving and handling related fields */ | ||
568 | |||
569 | int remote_IPI_nasid; /* nasid of where to send IPIs */ | ||
570 | int remote_IPI_phys_cpuid; /* phys CPU ID of where to send IPIs */ | ||
571 | AMO_t *remote_IPI_amo_va; /* address of remote IPI AMO_t structure */ | ||
572 | |||
573 | AMO_t *local_IPI_amo_va; /* address of IPI AMO_t structure */ | ||
574 | u64 local_IPI_amo; /* IPI amo flags yet to be handled */ | ||
575 | char IPI_owner[8]; /* IPI owner's name */ | ||
576 | struct timer_list dropped_IPI_timer; /* dropped IPI timer */ | ||
577 | |||
578 | spinlock_t IPI_lock; /* IPI handler lock */ | ||
579 | 729 | ||
580 | /* channel manager related fields */ | 730 | /* channel manager related fields */ |
581 | 731 | ||
582 | atomic_t channel_mgr_requests; /* #of requests to activate chan mgr */ | 732 | atomic_t channel_mgr_requests; /* #of requests to activate chan mgr */ |
583 | wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */ | 733 | wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */ |
584 | 734 | ||
735 | union { | ||
736 | struct xpc_partition_sn2 sn2; | ||
737 | struct xpc_partition_uv uv; | ||
738 | } sn; | ||
739 | |||
585 | } ____cacheline_aligned; | 740 | } ____cacheline_aligned; |
586 | 741 | ||
587 | /* struct xpc_partition act_state values (for XPC HB) */ | 742 | /* struct xpc_partition act_state values (for XPC HB) */ |
588 | 743 | ||
589 | #define XPC_P_INACTIVE 0x00 /* partition is not active */ | 744 | #define XPC_P_AS_INACTIVE 0x00 /* partition is not active */ |
590 | #define XPC_P_ACTIVATION_REQ 0x01 /* created thread to activate */ | 745 | #define XPC_P_AS_ACTIVATION_REQ 0x01 /* created thread to activate */ |
591 | #define XPC_P_ACTIVATING 0x02 /* activation thread started */ | 746 | #define XPC_P_AS_ACTIVATING 0x02 /* activation thread started */ |
592 | #define XPC_P_ACTIVE 0x03 /* xpc_partition_up() was called */ | 747 | #define XPC_P_AS_ACTIVE 0x03 /* xpc_partition_up() was called */ |
593 | #define XPC_P_DEACTIVATING 0x04 /* partition deactivation initiated */ | 748 | #define XPC_P_AS_DEACTIVATING 0x04 /* partition deactivation initiated */ |
594 | 749 | ||
595 | #define XPC_DEACTIVATE_PARTITION(_p, _reason) \ | 750 | #define XPC_DEACTIVATE_PARTITION(_p, _reason) \ |
596 | xpc_deactivate_partition(__LINE__, (_p), (_reason)) | 751 | xpc_deactivate_partition(__LINE__, (_p), (_reason)) |
597 | 752 | ||
598 | /* struct xpc_partition setup_state values */ | 753 | /* struct xpc_partition setup_state values */ |
599 | 754 | ||
600 | #define XPC_P_UNSET 0x00 /* infrastructure was never setup */ | 755 | #define XPC_P_SS_UNSET 0x00 /* infrastructure was never setup */ |
601 | #define XPC_P_SETUP 0x01 /* infrastructure is setup */ | 756 | #define XPC_P_SS_SETUP 0x01 /* infrastructure is setup */ |
602 | #define XPC_P_WTEARDOWN 0x02 /* waiting to teardown infrastructure */ | 757 | #define XPC_P_SS_WTEARDOWN 0x02 /* waiting to teardown infrastructure */ |
603 | #define XPC_P_TORNDOWN 0x03 /* infrastructure is torndown */ | 758 | #define XPC_P_SS_TORNDOWN 0x03 /* infrastructure is torndown */ |
604 | 759 | ||
605 | /* | 760 | /* |
606 | * struct xpc_partition IPI_timer #of seconds to wait before checking for | 761 | * struct xpc_partition_sn2's dropped notify IRQ timer is set to wait the |
607 | * dropped IPIs. These occur whenever an IPI amo write doesn't complete until | 762 | * following interval #of seconds before checking for dropped notify IRQs. |
608 | * after the IPI was received. | 763 | * These can occur whenever an IRQ's associated amo write doesn't complete |
764 | * until after the IRQ was received. | ||
609 | */ | 765 | */ |
610 | #define XPC_P_DROPPED_IPI_WAIT (0.25 * HZ) | 766 | #define XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL (0.25 * HZ) |
611 | 767 | ||
612 | /* number of seconds to wait for other partitions to disengage */ | 768 | /* number of seconds to wait for other partitions to disengage */ |
613 | #define XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT 90 | 769 | #define XPC_DISENGAGE_DEFAULT_TIMELIMIT 90 |
614 | 770 | ||
615 | /* interval in seconds to print 'waiting disengagement' messages */ | 771 | /* interval in seconds to print 'waiting deactivation' messages */ |
616 | #define XPC_DISENGAGE_PRINTMSG_INTERVAL 10 | 772 | #define XPC_DEACTIVATE_PRINTMSG_INTERVAL 10 |
617 | 773 | ||
618 | #define XPC_PARTID(_p) ((short)((_p) - &xpc_partitions[0])) | 774 | #define XPC_PARTID(_p) ((short)((_p) - &xpc_partitions[0])) |
619 | 775 | ||
@@ -623,33 +779,92 @@ extern struct xpc_registration xpc_registrations[]; | |||
623 | /* found in xpc_main.c */ | 779 | /* found in xpc_main.c */ |
624 | extern struct device *xpc_part; | 780 | extern struct device *xpc_part; |
625 | extern struct device *xpc_chan; | 781 | extern struct device *xpc_chan; |
626 | extern int xpc_disengage_request_timelimit; | 782 | extern int xpc_disengage_timelimit; |
627 | extern int xpc_disengage_request_timedout; | 783 | extern int xpc_disengage_timedout; |
628 | extern irqreturn_t xpc_notify_IRQ_handler(int, void *); | 784 | extern int xpc_activate_IRQ_rcvd; |
629 | extern void xpc_dropped_IPI_check(struct xpc_partition *); | 785 | extern spinlock_t xpc_activate_IRQ_rcvd_lock; |
786 | extern wait_queue_head_t xpc_activate_IRQ_wq; | ||
787 | extern void *xpc_heartbeating_to_mask; | ||
788 | extern void *xpc_kzalloc_cacheline_aligned(size_t, gfp_t, void **); | ||
630 | extern void xpc_activate_partition(struct xpc_partition *); | 789 | extern void xpc_activate_partition(struct xpc_partition *); |
631 | extern void xpc_activate_kthreads(struct xpc_channel *, int); | 790 | extern void xpc_activate_kthreads(struct xpc_channel *, int); |
632 | extern void xpc_create_kthreads(struct xpc_channel *, int, int); | 791 | extern void xpc_create_kthreads(struct xpc_channel *, int, int); |
633 | extern void xpc_disconnect_wait(int); | 792 | extern void xpc_disconnect_wait(int); |
793 | extern int (*xpc_setup_partitions_sn) (void); | ||
794 | extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *, u64 *, | ||
795 | unsigned long *, | ||
796 | size_t *); | ||
797 | extern int (*xpc_setup_rsvd_page_sn) (struct xpc_rsvd_page *); | ||
798 | extern void (*xpc_heartbeat_init) (void); | ||
799 | extern void (*xpc_heartbeat_exit) (void); | ||
800 | extern void (*xpc_increment_heartbeat) (void); | ||
801 | extern void (*xpc_offline_heartbeat) (void); | ||
802 | extern void (*xpc_online_heartbeat) (void); | ||
803 | extern enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *); | ||
804 | extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *); | ||
805 | extern u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *); | ||
806 | extern enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *); | ||
807 | extern void (*xpc_teardown_msg_structures) (struct xpc_channel *); | ||
808 | extern void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *); | ||
809 | extern void (*xpc_process_msg_chctl_flags) (struct xpc_partition *, int); | ||
810 | extern int (*xpc_n_of_deliverable_payloads) (struct xpc_channel *); | ||
811 | extern void *(*xpc_get_deliverable_payload) (struct xpc_channel *); | ||
812 | extern void (*xpc_request_partition_activation) (struct xpc_rsvd_page *, | ||
813 | unsigned long, int); | ||
814 | extern void (*xpc_request_partition_reactivation) (struct xpc_partition *); | ||
815 | extern void (*xpc_request_partition_deactivation) (struct xpc_partition *); | ||
816 | extern void (*xpc_cancel_partition_deactivation_request) ( | ||
817 | struct xpc_partition *); | ||
818 | extern void (*xpc_process_activate_IRQ_rcvd) (void); | ||
819 | extern enum xp_retval (*xpc_setup_ch_structures_sn) (struct xpc_partition *); | ||
820 | extern void (*xpc_teardown_ch_structures_sn) (struct xpc_partition *); | ||
821 | |||
822 | extern void (*xpc_indicate_partition_engaged) (struct xpc_partition *); | ||
823 | extern int (*xpc_partition_engaged) (short); | ||
824 | extern int (*xpc_any_partition_engaged) (void); | ||
825 | extern void (*xpc_indicate_partition_disengaged) (struct xpc_partition *); | ||
826 | extern void (*xpc_assume_partition_disengaged) (short); | ||
827 | |||
828 | extern void (*xpc_send_chctl_closerequest) (struct xpc_channel *, | ||
829 | unsigned long *); | ||
830 | extern void (*xpc_send_chctl_closereply) (struct xpc_channel *, | ||
831 | unsigned long *); | ||
832 | extern void (*xpc_send_chctl_openrequest) (struct xpc_channel *, | ||
833 | unsigned long *); | ||
834 | extern void (*xpc_send_chctl_openreply) (struct xpc_channel *, unsigned long *); | ||
835 | |||
836 | extern void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *, | ||
837 | unsigned long); | ||
838 | |||
839 | extern enum xp_retval (*xpc_send_payload) (struct xpc_channel *, u32, void *, | ||
840 | u16, u8, xpc_notify_func, void *); | ||
841 | extern void (*xpc_received_payload) (struct xpc_channel *, void *); | ||
842 | |||
843 | /* found in xpc_sn2.c */ | ||
844 | extern int xpc_init_sn2(void); | ||
845 | extern void xpc_exit_sn2(void); | ||
846 | |||
847 | /* found in xpc_uv.c */ | ||
848 | extern int xpc_init_uv(void); | ||
849 | extern void xpc_exit_uv(void); | ||
634 | 850 | ||
635 | /* found in xpc_partition.c */ | 851 | /* found in xpc_partition.c */ |
636 | extern int xpc_exiting; | 852 | extern int xpc_exiting; |
637 | extern struct xpc_vars *xpc_vars; | 853 | extern int xpc_nasid_mask_nlongs; |
638 | extern struct xpc_rsvd_page *xpc_rsvd_page; | 854 | extern struct xpc_rsvd_page *xpc_rsvd_page; |
639 | extern struct xpc_vars_part *xpc_vars_part; | 855 | extern unsigned long *xpc_mach_nasids; |
640 | extern struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1]; | 856 | extern struct xpc_partition *xpc_partitions; |
641 | extern char *xpc_remote_copy_buffer; | ||
642 | extern void *xpc_remote_copy_buffer_base; | ||
643 | extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); | 857 | extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); |
644 | extern struct xpc_rsvd_page *xpc_rsvd_page_init(void); | 858 | extern int xpc_setup_rsvd_page(void); |
645 | extern void xpc_allow_IPI_ops(void); | 859 | extern void xpc_teardown_rsvd_page(void); |
646 | extern void xpc_restrict_IPI_ops(void); | 860 | extern int xpc_identify_activate_IRQ_sender(void); |
647 | extern int xpc_identify_act_IRQ_sender(void); | ||
648 | extern int xpc_partition_disengaged(struct xpc_partition *); | 861 | extern int xpc_partition_disengaged(struct xpc_partition *); |
649 | extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); | 862 | extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); |
650 | extern void xpc_mark_partition_inactive(struct xpc_partition *); | 863 | extern void xpc_mark_partition_inactive(struct xpc_partition *); |
651 | extern void xpc_discovery(void); | 864 | extern void xpc_discovery(void); |
652 | extern void xpc_check_remote_hb(void); | 865 | extern enum xp_retval xpc_get_remote_rp(int, unsigned long *, |
866 | struct xpc_rsvd_page *, | ||
867 | unsigned long *); | ||
653 | extern void xpc_deactivate_partition(const int, struct xpc_partition *, | 868 | extern void xpc_deactivate_partition(const int, struct xpc_partition *, |
654 | enum xp_retval); | 869 | enum xp_retval); |
655 | extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *); | 870 | extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *); |
@@ -657,21 +872,52 @@ extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *); | |||
657 | /* found in xpc_channel.c */ | 872 | /* found in xpc_channel.c */ |
658 | extern void xpc_initiate_connect(int); | 873 | extern void xpc_initiate_connect(int); |
659 | extern void xpc_initiate_disconnect(int); | 874 | extern void xpc_initiate_disconnect(int); |
660 | extern enum xp_retval xpc_initiate_allocate(short, int, u32, void **); | 875 | extern enum xp_retval xpc_allocate_msg_wait(struct xpc_channel *); |
661 | extern enum xp_retval xpc_initiate_send(short, int, void *); | 876 | extern enum xp_retval xpc_initiate_send(short, int, u32, void *, u16); |
662 | extern enum xp_retval xpc_initiate_send_notify(short, int, void *, | 877 | extern enum xp_retval xpc_initiate_send_notify(short, int, u32, void *, u16, |
663 | xpc_notify_func, void *); | 878 | xpc_notify_func, void *); |
664 | extern void xpc_initiate_received(short, int, void *); | 879 | extern void xpc_initiate_received(short, int, void *); |
665 | extern enum xp_retval xpc_setup_infrastructure(struct xpc_partition *); | 880 | extern void xpc_process_sent_chctl_flags(struct xpc_partition *); |
666 | extern enum xp_retval xpc_pull_remote_vars_part(struct xpc_partition *); | ||
667 | extern void xpc_process_channel_activity(struct xpc_partition *); | ||
668 | extern void xpc_connected_callout(struct xpc_channel *); | 881 | extern void xpc_connected_callout(struct xpc_channel *); |
669 | extern void xpc_deliver_msg(struct xpc_channel *); | 882 | extern void xpc_deliver_payload(struct xpc_channel *); |
670 | extern void xpc_disconnect_channel(const int, struct xpc_channel *, | 883 | extern void xpc_disconnect_channel(const int, struct xpc_channel *, |
671 | enum xp_retval, unsigned long *); | 884 | enum xp_retval, unsigned long *); |
672 | extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval); | 885 | extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval); |
673 | extern void xpc_partition_going_down(struct xpc_partition *, enum xp_retval); | 886 | extern void xpc_partition_going_down(struct xpc_partition *, enum xp_retval); |
674 | extern void xpc_teardown_infrastructure(struct xpc_partition *); | 887 | |
888 | static inline int | ||
889 | xpc_hb_allowed(short partid, void *heartbeating_to_mask) | ||
890 | { | ||
891 | return test_bit(partid, heartbeating_to_mask); | ||
892 | } | ||
893 | |||
894 | static inline int | ||
895 | xpc_any_hbs_allowed(void) | ||
896 | { | ||
897 | DBUG_ON(xpc_heartbeating_to_mask == NULL); | ||
898 | return !bitmap_empty(xpc_heartbeating_to_mask, xp_max_npartitions); | ||
899 | } | ||
900 | |||
901 | static inline void | ||
902 | xpc_allow_hb(short partid) | ||
903 | { | ||
904 | DBUG_ON(xpc_heartbeating_to_mask == NULL); | ||
905 | set_bit(partid, xpc_heartbeating_to_mask); | ||
906 | } | ||
907 | |||
908 | static inline void | ||
909 | xpc_disallow_hb(short partid) | ||
910 | { | ||
911 | DBUG_ON(xpc_heartbeating_to_mask == NULL); | ||
912 | clear_bit(partid, xpc_heartbeating_to_mask); | ||
913 | } | ||
914 | |||
915 | static inline void | ||
916 | xpc_disallow_all_hbs(void) | ||
917 | { | ||
918 | DBUG_ON(xpc_heartbeating_to_mask == NULL); | ||
919 | bitmap_zero(xpc_heartbeating_to_mask, xp_max_npartitions); | ||
920 | } | ||
675 | 921 | ||
676 | static inline void | 922 | static inline void |
677 | xpc_wakeup_channel_mgr(struct xpc_partition *part) | 923 | xpc_wakeup_channel_mgr(struct xpc_partition *part) |
@@ -713,7 +959,7 @@ xpc_part_deref(struct xpc_partition *part) | |||
713 | s32 refs = atomic_dec_return(&part->references); | 959 | s32 refs = atomic_dec_return(&part->references); |
714 | 960 | ||
715 | DBUG_ON(refs < 0); | 961 | DBUG_ON(refs < 0); |
716 | if (refs == 0 && part->setup_state == XPC_P_WTEARDOWN) | 962 | if (refs == 0 && part->setup_state == XPC_P_SS_WTEARDOWN) |
717 | wake_up(&part->teardown_wq); | 963 | wake_up(&part->teardown_wq); |
718 | } | 964 | } |
719 | 965 | ||
@@ -723,7 +969,7 @@ xpc_part_ref(struct xpc_partition *part) | |||
723 | int setup; | 969 | int setup; |
724 | 970 | ||
725 | atomic_inc(&part->references); | 971 | atomic_inc(&part->references); |
726 | setup = (part->setup_state == XPC_P_SETUP); | 972 | setup = (part->setup_state == XPC_P_SS_SETUP); |
727 | if (!setup) | 973 | if (!setup) |
728 | xpc_part_deref(part); | 974 | xpc_part_deref(part); |
729 | 975 | ||
@@ -741,416 +987,4 @@ xpc_part_ref(struct xpc_partition *part) | |||
741 | (_p)->reason_line = _line; \ | 987 | (_p)->reason_line = _line; \ |
742 | } | 988 | } |
743 | 989 | ||
744 | /* | ||
745 | * This next set of inlines are used to keep track of when a partition is | ||
746 | * potentially engaged in accessing memory belonging to another partition. | ||
747 | */ | ||
748 | |||
749 | static inline void | ||
750 | xpc_mark_partition_engaged(struct xpc_partition *part) | ||
751 | { | ||
752 | unsigned long irq_flags; | ||
753 | AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + | ||
754 | (XPC_ENGAGED_PARTITIONS_AMO * | ||
755 | sizeof(AMO_t))); | ||
756 | |||
757 | local_irq_save(irq_flags); | ||
758 | |||
759 | /* set bit corresponding to our partid in remote partition's AMO */ | ||
760 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, | ||
761 | (1UL << sn_partition_id)); | ||
762 | /* | ||
763 | * We must always use the nofault function regardless of whether we | ||
764 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
765 | * didn't, we'd never know that the other partition is down and would | ||
766 | * keep sending IPIs and AMOs to it until the heartbeat times out. | ||
767 | */ | ||
768 | (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> | ||
769 | variable), | ||
770 | xp_nofault_PIOR_target)); | ||
771 | |||
772 | local_irq_restore(irq_flags); | ||
773 | } | ||
774 | |||
775 | static inline void | ||
776 | xpc_mark_partition_disengaged(struct xpc_partition *part) | ||
777 | { | ||
778 | unsigned long irq_flags; | ||
779 | AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + | ||
780 | (XPC_ENGAGED_PARTITIONS_AMO * | ||
781 | sizeof(AMO_t))); | ||
782 | |||
783 | local_irq_save(irq_flags); | ||
784 | |||
785 | /* clear bit corresponding to our partid in remote partition's AMO */ | ||
786 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, | ||
787 | ~(1UL << sn_partition_id)); | ||
788 | /* | ||
789 | * We must always use the nofault function regardless of whether we | ||
790 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
791 | * didn't, we'd never know that the other partition is down and would | ||
792 | * keep sending IPIs and AMOs to it until the heartbeat times out. | ||
793 | */ | ||
794 | (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> | ||
795 | variable), | ||
796 | xp_nofault_PIOR_target)); | ||
797 | |||
798 | local_irq_restore(irq_flags); | ||
799 | } | ||
800 | |||
801 | static inline void | ||
802 | xpc_request_partition_disengage(struct xpc_partition *part) | ||
803 | { | ||
804 | unsigned long irq_flags; | ||
805 | AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + | ||
806 | (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); | ||
807 | |||
808 | local_irq_save(irq_flags); | ||
809 | |||
810 | /* set bit corresponding to our partid in remote partition's AMO */ | ||
811 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, | ||
812 | (1UL << sn_partition_id)); | ||
813 | /* | ||
814 | * We must always use the nofault function regardless of whether we | ||
815 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
816 | * didn't, we'd never know that the other partition is down and would | ||
817 | * keep sending IPIs and AMOs to it until the heartbeat times out. | ||
818 | */ | ||
819 | (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> | ||
820 | variable), | ||
821 | xp_nofault_PIOR_target)); | ||
822 | |||
823 | local_irq_restore(irq_flags); | ||
824 | } | ||
825 | |||
826 | static inline void | ||
827 | xpc_cancel_partition_disengage_request(struct xpc_partition *part) | ||
828 | { | ||
829 | unsigned long irq_flags; | ||
830 | AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + | ||
831 | (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); | ||
832 | |||
833 | local_irq_save(irq_flags); | ||
834 | |||
835 | /* clear bit corresponding to our partid in remote partition's AMO */ | ||
836 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, | ||
837 | ~(1UL << sn_partition_id)); | ||
838 | /* | ||
839 | * We must always use the nofault function regardless of whether we | ||
840 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
841 | * didn't, we'd never know that the other partition is down and would | ||
842 | * keep sending IPIs and AMOs to it until the heartbeat times out. | ||
843 | */ | ||
844 | (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> | ||
845 | variable), | ||
846 | xp_nofault_PIOR_target)); | ||
847 | |||
848 | local_irq_restore(irq_flags); | ||
849 | } | ||
850 | |||
851 | static inline u64 | ||
852 | xpc_partition_engaged(u64 partid_mask) | ||
853 | { | ||
854 | AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; | ||
855 | |||
856 | /* return our partition's AMO variable ANDed with partid_mask */ | ||
857 | return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & | ||
858 | partid_mask); | ||
859 | } | ||
860 | |||
861 | static inline u64 | ||
862 | xpc_partition_disengage_requested(u64 partid_mask) | ||
863 | { | ||
864 | AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; | ||
865 | |||
866 | /* return our partition's AMO variable ANDed with partid_mask */ | ||
867 | return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & | ||
868 | partid_mask); | ||
869 | } | ||
870 | |||
871 | static inline void | ||
872 | xpc_clear_partition_engaged(u64 partid_mask) | ||
873 | { | ||
874 | AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; | ||
875 | |||
876 | /* clear bit(s) based on partid_mask in our partition's AMO */ | ||
877 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, | ||
878 | ~partid_mask); | ||
879 | } | ||
880 | |||
881 | static inline void | ||
882 | xpc_clear_partition_disengage_request(u64 partid_mask) | ||
883 | { | ||
884 | AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; | ||
885 | |||
886 | /* clear bit(s) based on partid_mask in our partition's AMO */ | ||
887 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, | ||
888 | ~partid_mask); | ||
889 | } | ||
890 | |||
891 | /* | ||
892 | * The following set of macros and inlines are used for the sending and | ||
893 | * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, | ||
894 | * one that is associated with partition activity (SGI_XPC_ACTIVATE) and | ||
895 | * the other that is associated with channel activity (SGI_XPC_NOTIFY). | ||
896 | */ | ||
897 | |||
898 | static inline u64 | ||
899 | xpc_IPI_receive(AMO_t *amo) | ||
900 | { | ||
901 | return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR); | ||
902 | } | ||
903 | |||
904 | static inline enum xp_retval | ||
905 | xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) | ||
906 | { | ||
907 | int ret = 0; | ||
908 | unsigned long irq_flags; | ||
909 | |||
910 | local_irq_save(irq_flags); | ||
911 | |||
912 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, flag); | ||
913 | sn_send_IPI_phys(nasid, phys_cpuid, vector, 0); | ||
914 | |||
915 | /* | ||
916 | * We must always use the nofault function regardless of whether we | ||
917 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
918 | * didn't, we'd never know that the other partition is down and would | ||
919 | * keep sending IPIs and AMOs to it until the heartbeat times out. | ||
920 | */ | ||
921 | ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable), | ||
922 | xp_nofault_PIOR_target)); | ||
923 | |||
924 | local_irq_restore(irq_flags); | ||
925 | |||
926 | return ((ret == 0) ? xpSuccess : xpPioReadError); | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | * IPIs associated with SGI_XPC_ACTIVATE IRQ. | ||
931 | */ | ||
932 | |||
933 | /* | ||
934 | * Flag the appropriate AMO variable and send an IPI to the specified node. | ||
935 | */ | ||
936 | static inline void | ||
937 | xpc_activate_IRQ_send(u64 amos_page_pa, int from_nasid, int to_nasid, | ||
938 | int to_phys_cpuid) | ||
939 | { | ||
940 | int w_index = XPC_NASID_W_INDEX(from_nasid); | ||
941 | int b_index = XPC_NASID_B_INDEX(from_nasid); | ||
942 | AMO_t *amos = (AMO_t *)__va(amos_page_pa + | ||
943 | (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); | ||
944 | |||
945 | (void)xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid, | ||
946 | to_phys_cpuid, SGI_XPC_ACTIVATE); | ||
947 | } | ||
948 | |||
949 | static inline void | ||
950 | xpc_IPI_send_activate(struct xpc_vars *vars) | ||
951 | { | ||
952 | xpc_activate_IRQ_send(vars->amos_page_pa, cnodeid_to_nasid(0), | ||
953 | vars->act_nasid, vars->act_phys_cpuid); | ||
954 | } | ||
955 | |||
956 | static inline void | ||
957 | xpc_IPI_send_activated(struct xpc_partition *part) | ||
958 | { | ||
959 | xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0), | ||
960 | part->remote_act_nasid, | ||
961 | part->remote_act_phys_cpuid); | ||
962 | } | ||
963 | |||
964 | static inline void | ||
965 | xpc_IPI_send_reactivate(struct xpc_partition *part) | ||
966 | { | ||
967 | xpc_activate_IRQ_send(xpc_vars->amos_page_pa, part->reactivate_nasid, | ||
968 | xpc_vars->act_nasid, xpc_vars->act_phys_cpuid); | ||
969 | } | ||
970 | |||
971 | static inline void | ||
972 | xpc_IPI_send_disengage(struct xpc_partition *part) | ||
973 | { | ||
974 | xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0), | ||
975 | part->remote_act_nasid, | ||
976 | part->remote_act_phys_cpuid); | ||
977 | } | ||
978 | |||
979 | /* | ||
980 | * IPIs associated with SGI_XPC_NOTIFY IRQ. | ||
981 | */ | ||
982 | |||
983 | /* | ||
984 | * Send an IPI to the remote partition that is associated with the | ||
985 | * specified channel. | ||
986 | */ | ||
987 | #define XPC_NOTIFY_IRQ_SEND(_ch, _ipi_f, _irq_f) \ | ||
988 | xpc_notify_IRQ_send(_ch, _ipi_f, #_ipi_f, _irq_f) | ||
989 | |||
990 | static inline void | ||
991 | xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string, | ||
992 | unsigned long *irq_flags) | ||
993 | { | ||
994 | struct xpc_partition *part = &xpc_partitions[ch->partid]; | ||
995 | enum xp_retval ret; | ||
996 | |||
997 | if (likely(part->act_state != XPC_P_DEACTIVATING)) { | ||
998 | ret = xpc_IPI_send(part->remote_IPI_amo_va, | ||
999 | (u64)ipi_flag << (ch->number * 8), | ||
1000 | part->remote_IPI_nasid, | ||
1001 | part->remote_IPI_phys_cpuid, SGI_XPC_NOTIFY); | ||
1002 | dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n", | ||
1003 | ipi_flag_string, ch->partid, ch->number, ret); | ||
1004 | if (unlikely(ret != xpSuccess)) { | ||
1005 | if (irq_flags != NULL) | ||
1006 | spin_unlock_irqrestore(&ch->lock, *irq_flags); | ||
1007 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
1008 | if (irq_flags != NULL) | ||
1009 | spin_lock_irqsave(&ch->lock, *irq_flags); | ||
1010 | } | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | /* | ||
1015 | * Make it look like the remote partition, which is associated with the | ||
1016 | * specified channel, sent us an IPI. This faked IPI will be handled | ||
1017 | * by xpc_dropped_IPI_check(). | ||
1018 | */ | ||
1019 | #define XPC_NOTIFY_IRQ_SEND_LOCAL(_ch, _ipi_f) \ | ||
1020 | xpc_notify_IRQ_send_local(_ch, _ipi_f, #_ipi_f) | ||
1021 | |||
1022 | static inline void | ||
1023 | xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag, | ||
1024 | char *ipi_flag_string) | ||
1025 | { | ||
1026 | struct xpc_partition *part = &xpc_partitions[ch->partid]; | ||
1027 | |||
1028 | FETCHOP_STORE_OP(TO_AMO((u64)&part->local_IPI_amo_va->variable), | ||
1029 | FETCHOP_OR, ((u64)ipi_flag << (ch->number * 8))); | ||
1030 | dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n", | ||
1031 | ipi_flag_string, ch->partid, ch->number); | ||
1032 | } | ||
1033 | |||
1034 | /* | ||
1035 | * The sending and receiving of IPIs includes the setting of an AMO variable | ||
1036 | * to indicate the reason the IPI was sent. The 64-bit variable is divided | ||
1037 | * up into eight bytes, ordered from right to left. Byte zero pertains to | ||
1038 | * channel 0, byte one to channel 1, and so on. Each byte is described by | ||
1039 | * the following IPI flags. | ||
1040 | */ | ||
1041 | |||
1042 | #define XPC_IPI_CLOSEREQUEST 0x01 | ||
1043 | #define XPC_IPI_CLOSEREPLY 0x02 | ||
1044 | #define XPC_IPI_OPENREQUEST 0x04 | ||
1045 | #define XPC_IPI_OPENREPLY 0x08 | ||
1046 | #define XPC_IPI_MSGREQUEST 0x10 | ||
1047 | |||
1048 | /* given an AMO variable and a channel#, get its associated IPI flags */ | ||
1049 | #define XPC_GET_IPI_FLAGS(_amo, _c) ((u8) (((_amo) >> ((_c) * 8)) & 0xff)) | ||
1050 | #define XPC_SET_IPI_FLAGS(_amo, _c, _f) (_amo) |= ((u64) (_f) << ((_c) * 8)) | ||
1051 | |||
1052 | #define XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & 0x0f0f0f0f0f0f0f0fUL) | ||
1053 | #define XPC_ANY_MSG_IPI_FLAGS_SET(_amo) ((_amo) & 0x1010101010101010UL) | ||
1054 | |||
1055 | static inline void | ||
1056 | xpc_IPI_send_closerequest(struct xpc_channel *ch, unsigned long *irq_flags) | ||
1057 | { | ||
1058 | struct xpc_openclose_args *args = ch->local_openclose_args; | ||
1059 | |||
1060 | args->reason = ch->reason; | ||
1061 | |||
1062 | XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREQUEST, irq_flags); | ||
1063 | } | ||
1064 | |||
1065 | static inline void | ||
1066 | xpc_IPI_send_closereply(struct xpc_channel *ch, unsigned long *irq_flags) | ||
1067 | { | ||
1068 | XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREPLY, irq_flags); | ||
1069 | } | ||
1070 | |||
1071 | static inline void | ||
1072 | xpc_IPI_send_openrequest(struct xpc_channel *ch, unsigned long *irq_flags) | ||
1073 | { | ||
1074 | struct xpc_openclose_args *args = ch->local_openclose_args; | ||
1075 | |||
1076 | args->msg_size = ch->msg_size; | ||
1077 | args->local_nentries = ch->local_nentries; | ||
1078 | |||
1079 | XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREQUEST, irq_flags); | ||
1080 | } | ||
1081 | |||
1082 | static inline void | ||
1083 | xpc_IPI_send_openreply(struct xpc_channel *ch, unsigned long *irq_flags) | ||
1084 | { | ||
1085 | struct xpc_openclose_args *args = ch->local_openclose_args; | ||
1086 | |||
1087 | args->remote_nentries = ch->remote_nentries; | ||
1088 | args->local_nentries = ch->local_nentries; | ||
1089 | args->local_msgqueue_pa = __pa(ch->local_msgqueue); | ||
1090 | |||
1091 | XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREPLY, irq_flags); | ||
1092 | } | ||
1093 | |||
1094 | static inline void | ||
1095 | xpc_IPI_send_msgrequest(struct xpc_channel *ch) | ||
1096 | { | ||
1097 | XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_MSGREQUEST, NULL); | ||
1098 | } | ||
1099 | |||
1100 | static inline void | ||
1101 | xpc_IPI_send_local_msgrequest(struct xpc_channel *ch) | ||
1102 | { | ||
1103 | XPC_NOTIFY_IRQ_SEND_LOCAL(ch, XPC_IPI_MSGREQUEST); | ||
1104 | } | ||
1105 | |||
1106 | /* | ||
1107 | * Memory for XPC's AMO variables is allocated by the MSPEC driver. These | ||
1108 | * pages are located in the lowest granule. The lowest granule uses 4k pages | ||
1109 | * for cached references and an alternate TLB handler to never provide a | ||
1110 | * cacheable mapping for the entire region. This will prevent speculative | ||
1111 | * reading of cached copies of our lines from being issued which will cause | ||
1112 | * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 | ||
1113 | * AMO variables (based on XP_MAX_PARTITIONS) for message notification and an | ||
1114 | * additional 128 AMO variables (based on XP_NASID_MASK_WORDS) for partition | ||
1115 | * activation and 2 AMO variables for partition deactivation. | ||
1116 | */ | ||
1117 | static inline AMO_t * | ||
1118 | xpc_IPI_init(int index) | ||
1119 | { | ||
1120 | AMO_t *amo = xpc_vars->amos_page + index; | ||
1121 | |||
1122 | (void)xpc_IPI_receive(amo); /* clear AMO variable */ | ||
1123 | return amo; | ||
1124 | } | ||
1125 | |||
1126 | static inline enum xp_retval | ||
1127 | xpc_map_bte_errors(bte_result_t error) | ||
1128 | { | ||
1129 | return ((error == BTE_SUCCESS) ? xpSuccess : xpBteCopyError); | ||
1130 | } | ||
1131 | |||
1132 | /* | ||
1133 | * Check to see if there is any channel activity to/from the specified | ||
1134 | * partition. | ||
1135 | */ | ||
1136 | static inline void | ||
1137 | xpc_check_for_channel_activity(struct xpc_partition *part) | ||
1138 | { | ||
1139 | u64 IPI_amo; | ||
1140 | unsigned long irq_flags; | ||
1141 | |||
1142 | IPI_amo = xpc_IPI_receive(part->local_IPI_amo_va); | ||
1143 | if (IPI_amo == 0) | ||
1144 | return; | ||
1145 | |||
1146 | spin_lock_irqsave(&part->IPI_lock, irq_flags); | ||
1147 | part->local_IPI_amo |= IPI_amo; | ||
1148 | spin_unlock_irqrestore(&part->IPI_lock, irq_flags); | ||
1149 | |||
1150 | dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n", | ||
1151 | XPC_PARTID(part), IPI_amo); | ||
1152 | |||
1153 | xpc_wakeup_channel_mgr(part); | ||
1154 | } | ||
1155 | |||
1156 | #endif /* _DRIVERS_MISC_SGIXP_XPC_H */ | 990 | #endif /* _DRIVERS_MISC_SGIXP_XPC_H */ |
diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 9c90c2d55c08..9cd2ebe2a3b6 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c | |||
@@ -14,536 +14,10 @@ | |||
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/kernel.h> | 17 | #include <linux/device.h> |
18 | #include <linux/init.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/cache.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/completion.h> | ||
24 | #include <asm/sn/bte.h> | ||
25 | #include <asm/sn/sn_sal.h> | ||
26 | #include "xpc.h" | 18 | #include "xpc.h" |
27 | 19 | ||
28 | /* | 20 | /* |
29 | * Guarantee that the kzalloc'd memory is cacheline aligned. | ||
30 | */ | ||
31 | static void * | ||
32 | xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) | ||
33 | { | ||
34 | /* see if kzalloc will give us cachline aligned memory by default */ | ||
35 | *base = kzalloc(size, flags); | ||
36 | if (*base == NULL) | ||
37 | return NULL; | ||
38 | |||
39 | if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) | ||
40 | return *base; | ||
41 | |||
42 | kfree(*base); | ||
43 | |||
44 | /* nope, we'll have to do it ourselves */ | ||
45 | *base = kzalloc(size + L1_CACHE_BYTES, flags); | ||
46 | if (*base == NULL) | ||
47 | return NULL; | ||
48 | |||
49 | return (void *)L1_CACHE_ALIGN((u64)*base); | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * Set up the initial values for the XPartition Communication channels. | ||
54 | */ | ||
55 | static void | ||
56 | xpc_initialize_channels(struct xpc_partition *part, short partid) | ||
57 | { | ||
58 | int ch_number; | ||
59 | struct xpc_channel *ch; | ||
60 | |||
61 | for (ch_number = 0; ch_number < part->nchannels; ch_number++) { | ||
62 | ch = &part->channels[ch_number]; | ||
63 | |||
64 | ch->partid = partid; | ||
65 | ch->number = ch_number; | ||
66 | ch->flags = XPC_C_DISCONNECTED; | ||
67 | |||
68 | ch->local_GP = &part->local_GPs[ch_number]; | ||
69 | ch->local_openclose_args = | ||
70 | &part->local_openclose_args[ch_number]; | ||
71 | |||
72 | atomic_set(&ch->kthreads_assigned, 0); | ||
73 | atomic_set(&ch->kthreads_idle, 0); | ||
74 | atomic_set(&ch->kthreads_active, 0); | ||
75 | |||
76 | atomic_set(&ch->references, 0); | ||
77 | atomic_set(&ch->n_to_notify, 0); | ||
78 | |||
79 | spin_lock_init(&ch->lock); | ||
80 | mutex_init(&ch->msg_to_pull_mutex); | ||
81 | init_completion(&ch->wdisconnect_wait); | ||
82 | |||
83 | atomic_set(&ch->n_on_msg_allocate_wq, 0); | ||
84 | init_waitqueue_head(&ch->msg_allocate_wq); | ||
85 | init_waitqueue_head(&ch->idle_wq); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Setup the infrastructure necessary to support XPartition Communication | ||
91 | * between the specified remote partition and the local one. | ||
92 | */ | ||
93 | enum xp_retval | ||
94 | xpc_setup_infrastructure(struct xpc_partition *part) | ||
95 | { | ||
96 | int ret, cpuid; | ||
97 | struct timer_list *timer; | ||
98 | short partid = XPC_PARTID(part); | ||
99 | |||
100 | /* | ||
101 | * Zero out MOST of the entry for this partition. Only the fields | ||
102 | * starting with `nchannels' will be zeroed. The preceding fields must | ||
103 | * remain `viable' across partition ups and downs, since they may be | ||
104 | * referenced during this memset() operation. | ||
105 | */ | ||
106 | memset(&part->nchannels, 0, sizeof(struct xpc_partition) - | ||
107 | offsetof(struct xpc_partition, nchannels)); | ||
108 | |||
109 | /* | ||
110 | * Allocate all of the channel structures as a contiguous chunk of | ||
111 | * memory. | ||
112 | */ | ||
113 | part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_NCHANNELS, | ||
114 | GFP_KERNEL); | ||
115 | if (part->channels == NULL) { | ||
116 | dev_err(xpc_chan, "can't get memory for channels\n"); | ||
117 | return xpNoMemory; | ||
118 | } | ||
119 | |||
120 | part->nchannels = XPC_NCHANNELS; | ||
121 | |||
122 | /* allocate all the required GET/PUT values */ | ||
123 | |||
124 | part->local_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, | ||
125 | GFP_KERNEL, | ||
126 | &part->local_GPs_base); | ||
127 | if (part->local_GPs == NULL) { | ||
128 | kfree(part->channels); | ||
129 | part->channels = NULL; | ||
130 | dev_err(xpc_chan, "can't get memory for local get/put " | ||
131 | "values\n"); | ||
132 | return xpNoMemory; | ||
133 | } | ||
134 | |||
135 | part->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, | ||
136 | GFP_KERNEL, | ||
137 | &part-> | ||
138 | remote_GPs_base); | ||
139 | if (part->remote_GPs == NULL) { | ||
140 | dev_err(xpc_chan, "can't get memory for remote get/put " | ||
141 | "values\n"); | ||
142 | kfree(part->local_GPs_base); | ||
143 | part->local_GPs = NULL; | ||
144 | kfree(part->channels); | ||
145 | part->channels = NULL; | ||
146 | return xpNoMemory; | ||
147 | } | ||
148 | |||
149 | /* allocate all the required open and close args */ | ||
150 | |||
151 | part->local_openclose_args = | ||
152 | xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, | ||
153 | &part->local_openclose_args_base); | ||
154 | if (part->local_openclose_args == NULL) { | ||
155 | dev_err(xpc_chan, "can't get memory for local connect args\n"); | ||
156 | kfree(part->remote_GPs_base); | ||
157 | part->remote_GPs = NULL; | ||
158 | kfree(part->local_GPs_base); | ||
159 | part->local_GPs = NULL; | ||
160 | kfree(part->channels); | ||
161 | part->channels = NULL; | ||
162 | return xpNoMemory; | ||
163 | } | ||
164 | |||
165 | part->remote_openclose_args = | ||
166 | xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, | ||
167 | &part->remote_openclose_args_base); | ||
168 | if (part->remote_openclose_args == NULL) { | ||
169 | dev_err(xpc_chan, "can't get memory for remote connect args\n"); | ||
170 | kfree(part->local_openclose_args_base); | ||
171 | part->local_openclose_args = NULL; | ||
172 | kfree(part->remote_GPs_base); | ||
173 | part->remote_GPs = NULL; | ||
174 | kfree(part->local_GPs_base); | ||
175 | part->local_GPs = NULL; | ||
176 | kfree(part->channels); | ||
177 | part->channels = NULL; | ||
178 | return xpNoMemory; | ||
179 | } | ||
180 | |||
181 | xpc_initialize_channels(part, partid); | ||
182 | |||
183 | atomic_set(&part->nchannels_active, 0); | ||
184 | atomic_set(&part->nchannels_engaged, 0); | ||
185 | |||
186 | /* local_IPI_amo were set to 0 by an earlier memset() */ | ||
187 | |||
188 | /* Initialize this partitions AMO_t structure */ | ||
189 | part->local_IPI_amo_va = xpc_IPI_init(partid); | ||
190 | |||
191 | spin_lock_init(&part->IPI_lock); | ||
192 | |||
193 | atomic_set(&part->channel_mgr_requests, 1); | ||
194 | init_waitqueue_head(&part->channel_mgr_wq); | ||
195 | |||
196 | sprintf(part->IPI_owner, "xpc%02d", partid); | ||
197 | ret = request_irq(SGI_XPC_NOTIFY, xpc_notify_IRQ_handler, IRQF_SHARED, | ||
198 | part->IPI_owner, (void *)(u64)partid); | ||
199 | if (ret != 0) { | ||
200 | dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " | ||
201 | "errno=%d\n", -ret); | ||
202 | kfree(part->remote_openclose_args_base); | ||
203 | part->remote_openclose_args = NULL; | ||
204 | kfree(part->local_openclose_args_base); | ||
205 | part->local_openclose_args = NULL; | ||
206 | kfree(part->remote_GPs_base); | ||
207 | part->remote_GPs = NULL; | ||
208 | kfree(part->local_GPs_base); | ||
209 | part->local_GPs = NULL; | ||
210 | kfree(part->channels); | ||
211 | part->channels = NULL; | ||
212 | return xpLackOfResources; | ||
213 | } | ||
214 | |||
215 | /* Setup a timer to check for dropped IPIs */ | ||
216 | timer = &part->dropped_IPI_timer; | ||
217 | init_timer(timer); | ||
218 | timer->function = (void (*)(unsigned long))xpc_dropped_IPI_check; | ||
219 | timer->data = (unsigned long)part; | ||
220 | timer->expires = jiffies + XPC_P_DROPPED_IPI_WAIT; | ||
221 | add_timer(timer); | ||
222 | |||
223 | /* | ||
224 | * With the setting of the partition setup_state to XPC_P_SETUP, we're | ||
225 | * declaring that this partition is ready to go. | ||
226 | */ | ||
227 | part->setup_state = XPC_P_SETUP; | ||
228 | |||
229 | /* | ||
230 | * Setup the per partition specific variables required by the | ||
231 | * remote partition to establish channel connections with us. | ||
232 | * | ||
233 | * The setting of the magic # indicates that these per partition | ||
234 | * specific variables are ready to be used. | ||
235 | */ | ||
236 | xpc_vars_part[partid].GPs_pa = __pa(part->local_GPs); | ||
237 | xpc_vars_part[partid].openclose_args_pa = | ||
238 | __pa(part->local_openclose_args); | ||
239 | xpc_vars_part[partid].IPI_amo_pa = __pa(part->local_IPI_amo_va); | ||
240 | cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ | ||
241 | xpc_vars_part[partid].IPI_nasid = cpuid_to_nasid(cpuid); | ||
242 | xpc_vars_part[partid].IPI_phys_cpuid = cpu_physical_id(cpuid); | ||
243 | xpc_vars_part[partid].nchannels = part->nchannels; | ||
244 | xpc_vars_part[partid].magic = XPC_VP_MAGIC1; | ||
245 | |||
246 | return xpSuccess; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * Create a wrapper that hides the underlying mechanism for pulling a cacheline | ||
251 | * (or multiple cachelines) from a remote partition. | ||
252 | * | ||
253 | * src must be a cacheline aligned physical address on the remote partition. | ||
254 | * dst must be a cacheline aligned virtual address on this partition. | ||
255 | * cnt must be an cacheline sized | ||
256 | */ | ||
257 | static enum xp_retval | ||
258 | xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst, | ||
259 | const void *src, size_t cnt) | ||
260 | { | ||
261 | bte_result_t bte_ret; | ||
262 | |||
263 | DBUG_ON((u64)src != L1_CACHE_ALIGN((u64)src)); | ||
264 | DBUG_ON((u64)dst != L1_CACHE_ALIGN((u64)dst)); | ||
265 | DBUG_ON(cnt != L1_CACHE_ALIGN(cnt)); | ||
266 | |||
267 | if (part->act_state == XPC_P_DEACTIVATING) | ||
268 | return part->reason; | ||
269 | |||
270 | bte_ret = xp_bte_copy((u64)src, (u64)dst, (u64)cnt, | ||
271 | (BTE_NORMAL | BTE_WACQUIRE), NULL); | ||
272 | if (bte_ret == BTE_SUCCESS) | ||
273 | return xpSuccess; | ||
274 | |||
275 | dev_dbg(xpc_chan, "xp_bte_copy() from partition %d failed, ret=%d\n", | ||
276 | XPC_PARTID(part), bte_ret); | ||
277 | |||
278 | return xpc_map_bte_errors(bte_ret); | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Pull the remote per partition specific variables from the specified | ||
283 | * partition. | ||
284 | */ | ||
285 | enum xp_retval | ||
286 | xpc_pull_remote_vars_part(struct xpc_partition *part) | ||
287 | { | ||
288 | u8 buffer[L1_CACHE_BYTES * 2]; | ||
289 | struct xpc_vars_part *pulled_entry_cacheline = | ||
290 | (struct xpc_vars_part *)L1_CACHE_ALIGN((u64)buffer); | ||
291 | struct xpc_vars_part *pulled_entry; | ||
292 | u64 remote_entry_cacheline_pa, remote_entry_pa; | ||
293 | short partid = XPC_PARTID(part); | ||
294 | enum xp_retval ret; | ||
295 | |||
296 | /* pull the cacheline that contains the variables we're interested in */ | ||
297 | |||
298 | DBUG_ON(part->remote_vars_part_pa != | ||
299 | L1_CACHE_ALIGN(part->remote_vars_part_pa)); | ||
300 | DBUG_ON(sizeof(struct xpc_vars_part) != L1_CACHE_BYTES / 2); | ||
301 | |||
302 | remote_entry_pa = part->remote_vars_part_pa + | ||
303 | sn_partition_id * sizeof(struct xpc_vars_part); | ||
304 | |||
305 | remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1)); | ||
306 | |||
307 | pulled_entry = (struct xpc_vars_part *)((u64)pulled_entry_cacheline + | ||
308 | (remote_entry_pa & | ||
309 | (L1_CACHE_BYTES - 1))); | ||
310 | |||
311 | ret = xpc_pull_remote_cachelines(part, pulled_entry_cacheline, | ||
312 | (void *)remote_entry_cacheline_pa, | ||
313 | L1_CACHE_BYTES); | ||
314 | if (ret != xpSuccess) { | ||
315 | dev_dbg(xpc_chan, "failed to pull XPC vars_part from " | ||
316 | "partition %d, ret=%d\n", partid, ret); | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | /* see if they've been set up yet */ | ||
321 | |||
322 | if (pulled_entry->magic != XPC_VP_MAGIC1 && | ||
323 | pulled_entry->magic != XPC_VP_MAGIC2) { | ||
324 | |||
325 | if (pulled_entry->magic != 0) { | ||
326 | dev_dbg(xpc_chan, "partition %d's XPC vars_part for " | ||
327 | "partition %d has bad magic value (=0x%lx)\n", | ||
328 | partid, sn_partition_id, pulled_entry->magic); | ||
329 | return xpBadMagic; | ||
330 | } | ||
331 | |||
332 | /* they've not been initialized yet */ | ||
333 | return xpRetry; | ||
334 | } | ||
335 | |||
336 | if (xpc_vars_part[partid].magic == XPC_VP_MAGIC1) { | ||
337 | |||
338 | /* validate the variables */ | ||
339 | |||
340 | if (pulled_entry->GPs_pa == 0 || | ||
341 | pulled_entry->openclose_args_pa == 0 || | ||
342 | pulled_entry->IPI_amo_pa == 0) { | ||
343 | |||
344 | dev_err(xpc_chan, "partition %d's XPC vars_part for " | ||
345 | "partition %d are not valid\n", partid, | ||
346 | sn_partition_id); | ||
347 | return xpInvalidAddress; | ||
348 | } | ||
349 | |||
350 | /* the variables we imported look to be valid */ | ||
351 | |||
352 | part->remote_GPs_pa = pulled_entry->GPs_pa; | ||
353 | part->remote_openclose_args_pa = | ||
354 | pulled_entry->openclose_args_pa; | ||
355 | part->remote_IPI_amo_va = | ||
356 | (AMO_t *)__va(pulled_entry->IPI_amo_pa); | ||
357 | part->remote_IPI_nasid = pulled_entry->IPI_nasid; | ||
358 | part->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid; | ||
359 | |||
360 | if (part->nchannels > pulled_entry->nchannels) | ||
361 | part->nchannels = pulled_entry->nchannels; | ||
362 | |||
363 | /* let the other side know that we've pulled their variables */ | ||
364 | |||
365 | xpc_vars_part[partid].magic = XPC_VP_MAGIC2; | ||
366 | } | ||
367 | |||
368 | if (pulled_entry->magic == XPC_VP_MAGIC1) | ||
369 | return xpRetry; | ||
370 | |||
371 | return xpSuccess; | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * Get the IPI flags and pull the openclose args and/or remote GPs as needed. | ||
376 | */ | ||
377 | static u64 | ||
378 | xpc_get_IPI_flags(struct xpc_partition *part) | ||
379 | { | ||
380 | unsigned long irq_flags; | ||
381 | u64 IPI_amo; | ||
382 | enum xp_retval ret; | ||
383 | |||
384 | /* | ||
385 | * See if there are any IPI flags to be handled. | ||
386 | */ | ||
387 | |||
388 | spin_lock_irqsave(&part->IPI_lock, irq_flags); | ||
389 | IPI_amo = part->local_IPI_amo; | ||
390 | if (IPI_amo != 0) | ||
391 | part->local_IPI_amo = 0; | ||
392 | |||
393 | spin_unlock_irqrestore(&part->IPI_lock, irq_flags); | ||
394 | |||
395 | if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_amo)) { | ||
396 | ret = xpc_pull_remote_cachelines(part, | ||
397 | part->remote_openclose_args, | ||
398 | (void *)part-> | ||
399 | remote_openclose_args_pa, | ||
400 | XPC_OPENCLOSE_ARGS_SIZE); | ||
401 | if (ret != xpSuccess) { | ||
402 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
403 | |||
404 | dev_dbg(xpc_chan, "failed to pull openclose args from " | ||
405 | "partition %d, ret=%d\n", XPC_PARTID(part), | ||
406 | ret); | ||
407 | |||
408 | /* don't bother processing IPIs anymore */ | ||
409 | IPI_amo = 0; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_amo)) { | ||
414 | ret = xpc_pull_remote_cachelines(part, part->remote_GPs, | ||
415 | (void *)part->remote_GPs_pa, | ||
416 | XPC_GP_SIZE); | ||
417 | if (ret != xpSuccess) { | ||
418 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
419 | |||
420 | dev_dbg(xpc_chan, "failed to pull GPs from partition " | ||
421 | "%d, ret=%d\n", XPC_PARTID(part), ret); | ||
422 | |||
423 | /* don't bother processing IPIs anymore */ | ||
424 | IPI_amo = 0; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | return IPI_amo; | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | * Allocate the local message queue and the notify queue. | ||
433 | */ | ||
434 | static enum xp_retval | ||
435 | xpc_allocate_local_msgqueue(struct xpc_channel *ch) | ||
436 | { | ||
437 | unsigned long irq_flags; | ||
438 | int nentries; | ||
439 | size_t nbytes; | ||
440 | |||
441 | for (nentries = ch->local_nentries; nentries > 0; nentries--) { | ||
442 | |||
443 | nbytes = nentries * ch->msg_size; | ||
444 | ch->local_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, | ||
445 | GFP_KERNEL, | ||
446 | &ch->local_msgqueue_base); | ||
447 | if (ch->local_msgqueue == NULL) | ||
448 | continue; | ||
449 | |||
450 | nbytes = nentries * sizeof(struct xpc_notify); | ||
451 | ch->notify_queue = kzalloc(nbytes, GFP_KERNEL); | ||
452 | if (ch->notify_queue == NULL) { | ||
453 | kfree(ch->local_msgqueue_base); | ||
454 | ch->local_msgqueue = NULL; | ||
455 | continue; | ||
456 | } | ||
457 | |||
458 | spin_lock_irqsave(&ch->lock, irq_flags); | ||
459 | if (nentries < ch->local_nentries) { | ||
460 | dev_dbg(xpc_chan, "nentries=%d local_nentries=%d, " | ||
461 | "partid=%d, channel=%d\n", nentries, | ||
462 | ch->local_nentries, ch->partid, ch->number); | ||
463 | |||
464 | ch->local_nentries = nentries; | ||
465 | } | ||
466 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
467 | return xpSuccess; | ||
468 | } | ||
469 | |||
470 | dev_dbg(xpc_chan, "can't get memory for local message queue and notify " | ||
471 | "queue, partid=%d, channel=%d\n", ch->partid, ch->number); | ||
472 | return xpNoMemory; | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * Allocate the cached remote message queue. | ||
477 | */ | ||
478 | static enum xp_retval | ||
479 | xpc_allocate_remote_msgqueue(struct xpc_channel *ch) | ||
480 | { | ||
481 | unsigned long irq_flags; | ||
482 | int nentries; | ||
483 | size_t nbytes; | ||
484 | |||
485 | DBUG_ON(ch->remote_nentries <= 0); | ||
486 | |||
487 | for (nentries = ch->remote_nentries; nentries > 0; nentries--) { | ||
488 | |||
489 | nbytes = nentries * ch->msg_size; | ||
490 | ch->remote_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, | ||
491 | GFP_KERNEL, | ||
492 | &ch->remote_msgqueue_base); | ||
493 | if (ch->remote_msgqueue == NULL) | ||
494 | continue; | ||
495 | |||
496 | spin_lock_irqsave(&ch->lock, irq_flags); | ||
497 | if (nentries < ch->remote_nentries) { | ||
498 | dev_dbg(xpc_chan, "nentries=%d remote_nentries=%d, " | ||
499 | "partid=%d, channel=%d\n", nentries, | ||
500 | ch->remote_nentries, ch->partid, ch->number); | ||
501 | |||
502 | ch->remote_nentries = nentries; | ||
503 | } | ||
504 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
505 | return xpSuccess; | ||
506 | } | ||
507 | |||
508 | dev_dbg(xpc_chan, "can't get memory for cached remote message queue, " | ||
509 | "partid=%d, channel=%d\n", ch->partid, ch->number); | ||
510 | return xpNoMemory; | ||
511 | } | ||
512 | |||
513 | /* | ||
514 | * Allocate message queues and other stuff associated with a channel. | ||
515 | * | ||
516 | * Note: Assumes all of the channel sizes are filled in. | ||
517 | */ | ||
518 | static enum xp_retval | ||
519 | xpc_allocate_msgqueues(struct xpc_channel *ch) | ||
520 | { | ||
521 | unsigned long irq_flags; | ||
522 | enum xp_retval ret; | ||
523 | |||
524 | DBUG_ON(ch->flags & XPC_C_SETUP); | ||
525 | |||
526 | ret = xpc_allocate_local_msgqueue(ch); | ||
527 | if (ret != xpSuccess) | ||
528 | return ret; | ||
529 | |||
530 | ret = xpc_allocate_remote_msgqueue(ch); | ||
531 | if (ret != xpSuccess) { | ||
532 | kfree(ch->local_msgqueue_base); | ||
533 | ch->local_msgqueue = NULL; | ||
534 | kfree(ch->notify_queue); | ||
535 | ch->notify_queue = NULL; | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | spin_lock_irqsave(&ch->lock, irq_flags); | ||
540 | ch->flags |= XPC_C_SETUP; | ||
541 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
542 | |||
543 | return xpSuccess; | ||
544 | } | ||
545 | |||
546 | /* | ||
547 | * Process a connect message from a remote partition. | 21 | * Process a connect message from a remote partition. |
548 | * | 22 | * |
549 | * Note: xpc_process_connect() is expecting to be called with the | 23 | * Note: xpc_process_connect() is expecting to be called with the |
@@ -565,30 +39,29 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
565 | 39 | ||
566 | if (!(ch->flags & XPC_C_SETUP)) { | 40 | if (!(ch->flags & XPC_C_SETUP)) { |
567 | spin_unlock_irqrestore(&ch->lock, *irq_flags); | 41 | spin_unlock_irqrestore(&ch->lock, *irq_flags); |
568 | ret = xpc_allocate_msgqueues(ch); | 42 | ret = xpc_setup_msg_structures(ch); |
569 | spin_lock_irqsave(&ch->lock, *irq_flags); | 43 | spin_lock_irqsave(&ch->lock, *irq_flags); |
570 | 44 | ||
571 | if (ret != xpSuccess) | 45 | if (ret != xpSuccess) |
572 | XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags); | 46 | XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags); |
573 | 47 | ||
48 | ch->flags |= XPC_C_SETUP; | ||
49 | |||
574 | if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING)) | 50 | if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING)) |
575 | return; | 51 | return; |
576 | 52 | ||
577 | DBUG_ON(!(ch->flags & XPC_C_SETUP)); | ||
578 | DBUG_ON(ch->local_msgqueue == NULL); | 53 | DBUG_ON(ch->local_msgqueue == NULL); |
579 | DBUG_ON(ch->remote_msgqueue == NULL); | 54 | DBUG_ON(ch->remote_msgqueue == NULL); |
580 | } | 55 | } |
581 | 56 | ||
582 | if (!(ch->flags & XPC_C_OPENREPLY)) { | 57 | if (!(ch->flags & XPC_C_OPENREPLY)) { |
583 | ch->flags |= XPC_C_OPENREPLY; | 58 | ch->flags |= XPC_C_OPENREPLY; |
584 | xpc_IPI_send_openreply(ch, irq_flags); | 59 | xpc_send_chctl_openreply(ch, irq_flags); |
585 | } | 60 | } |
586 | 61 | ||
587 | if (!(ch->flags & XPC_C_ROPENREPLY)) | 62 | if (!(ch->flags & XPC_C_ROPENREPLY)) |
588 | return; | 63 | return; |
589 | 64 | ||
590 | DBUG_ON(ch->remote_msgqueue_pa == 0); | ||
591 | |||
592 | ch->flags = (XPC_C_CONNECTED | XPC_C_SETUP); /* clear all else */ | 65 | ch->flags = (XPC_C_CONNECTED | XPC_C_SETUP); /* clear all else */ |
593 | 66 | ||
594 | dev_info(xpc_chan, "channel %d to partition %d connected\n", | 67 | dev_info(xpc_chan, "channel %d to partition %d connected\n", |
@@ -600,99 +73,6 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
600 | } | 73 | } |
601 | 74 | ||
602 | /* | 75 | /* |
603 | * Notify those who wanted to be notified upon delivery of their message. | ||
604 | */ | ||
605 | static void | ||
606 | xpc_notify_senders(struct xpc_channel *ch, enum xp_retval reason, s64 put) | ||
607 | { | ||
608 | struct xpc_notify *notify; | ||
609 | u8 notify_type; | ||
610 | s64 get = ch->w_remote_GP.get - 1; | ||
611 | |||
612 | while (++get < put && atomic_read(&ch->n_to_notify) > 0) { | ||
613 | |||
614 | notify = &ch->notify_queue[get % ch->local_nentries]; | ||
615 | |||
616 | /* | ||
617 | * See if the notify entry indicates it was associated with | ||
618 | * a message who's sender wants to be notified. It is possible | ||
619 | * that it is, but someone else is doing or has done the | ||
620 | * notification. | ||
621 | */ | ||
622 | notify_type = notify->type; | ||
623 | if (notify_type == 0 || | ||
624 | cmpxchg(¬ify->type, notify_type, 0) != notify_type) { | ||
625 | continue; | ||
626 | } | ||
627 | |||
628 | DBUG_ON(notify_type != XPC_N_CALL); | ||
629 | |||
630 | atomic_dec(&ch->n_to_notify); | ||
631 | |||
632 | if (notify->func != NULL) { | ||
633 | dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, " | ||
634 | "msg_number=%ld, partid=%d, channel=%d\n", | ||
635 | (void *)notify, get, ch->partid, ch->number); | ||
636 | |||
637 | notify->func(reason, ch->partid, ch->number, | ||
638 | notify->key); | ||
639 | |||
640 | dev_dbg(xpc_chan, "notify->func() returned, " | ||
641 | "notify=0x%p, msg_number=%ld, partid=%d, " | ||
642 | "channel=%d\n", (void *)notify, get, | ||
643 | ch->partid, ch->number); | ||
644 | } | ||
645 | } | ||
646 | } | ||
647 | |||
648 | /* | ||
649 | * Free up message queues and other stuff that were allocated for the specified | ||
650 | * channel. | ||
651 | * | ||
652 | * Note: ch->reason and ch->reason_line are left set for debugging purposes, | ||
653 | * they're cleared when XPC_C_DISCONNECTED is cleared. | ||
654 | */ | ||
655 | static void | ||
656 | xpc_free_msgqueues(struct xpc_channel *ch) | ||
657 | { | ||
658 | DBUG_ON(!spin_is_locked(&ch->lock)); | ||
659 | DBUG_ON(atomic_read(&ch->n_to_notify) != 0); | ||
660 | |||
661 | ch->remote_msgqueue_pa = 0; | ||
662 | ch->func = NULL; | ||
663 | ch->key = NULL; | ||
664 | ch->msg_size = 0; | ||
665 | ch->local_nentries = 0; | ||
666 | ch->remote_nentries = 0; | ||
667 | ch->kthreads_assigned_limit = 0; | ||
668 | ch->kthreads_idle_limit = 0; | ||
669 | |||
670 | ch->local_GP->get = 0; | ||
671 | ch->local_GP->put = 0; | ||
672 | ch->remote_GP.get = 0; | ||
673 | ch->remote_GP.put = 0; | ||
674 | ch->w_local_GP.get = 0; | ||
675 | ch->w_local_GP.put = 0; | ||
676 | ch->w_remote_GP.get = 0; | ||
677 | ch->w_remote_GP.put = 0; | ||
678 | ch->next_msg_to_pull = 0; | ||
679 | |||
680 | if (ch->flags & XPC_C_SETUP) { | ||
681 | ch->flags &= ~XPC_C_SETUP; | ||
682 | |||
683 | dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n", | ||
684 | ch->flags, ch->partid, ch->number); | ||
685 | |||
686 | kfree(ch->local_msgqueue_base); | ||
687 | ch->local_msgqueue = NULL; | ||
688 | kfree(ch->remote_msgqueue_base); | ||
689 | ch->remote_msgqueue = NULL; | ||
690 | kfree(ch->notify_queue); | ||
691 | ch->notify_queue = NULL; | ||
692 | } | ||
693 | } | ||
694 | |||
695 | /* | ||
696 | * spin_lock_irqsave() is expected to be held on entry. | 76 | * spin_lock_irqsave() is expected to be held on entry. |
697 | */ | 77 | */ |
698 | static void | 78 | static void |
@@ -717,9 +97,9 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
717 | DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && | 97 | DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && |
718 | !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE)); | 98 | !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE)); |
719 | 99 | ||
720 | if (part->act_state == XPC_P_DEACTIVATING) { | 100 | if (part->act_state == XPC_P_AS_DEACTIVATING) { |
721 | /* can't proceed until the other side disengages from us */ | 101 | /* can't proceed until the other side disengages from us */ |
722 | if (xpc_partition_engaged(1UL << ch->partid)) | 102 | if (xpc_partition_engaged(ch->partid)) |
723 | return; | 103 | return; |
724 | 104 | ||
725 | } else { | 105 | } else { |
@@ -731,7 +111,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
731 | 111 | ||
732 | if (!(ch->flags & XPC_C_CLOSEREPLY)) { | 112 | if (!(ch->flags & XPC_C_CLOSEREPLY)) { |
733 | ch->flags |= XPC_C_CLOSEREPLY; | 113 | ch->flags |= XPC_C_CLOSEREPLY; |
734 | xpc_IPI_send_closereply(ch, irq_flags); | 114 | xpc_send_chctl_closereply(ch, irq_flags); |
735 | } | 115 | } |
736 | 116 | ||
737 | if (!(ch->flags & XPC_C_RCLOSEREPLY)) | 117 | if (!(ch->flags & XPC_C_RCLOSEREPLY)) |
@@ -740,8 +120,8 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
740 | 120 | ||
741 | /* wake those waiting for notify completion */ | 121 | /* wake those waiting for notify completion */ |
742 | if (atomic_read(&ch->n_to_notify) > 0) { | 122 | if (atomic_read(&ch->n_to_notify) > 0) { |
743 | /* >>> we do callout while holding ch->lock */ | 123 | /* we do callout while holding ch->lock, callout can't block */ |
744 | xpc_notify_senders(ch, ch->reason, ch->w_local_GP.put); | 124 | xpc_notify_senders_of_disconnect(ch); |
745 | } | 125 | } |
746 | 126 | ||
747 | /* both sides are disconnected now */ | 127 | /* both sides are disconnected now */ |
@@ -752,10 +132,24 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
752 | spin_lock_irqsave(&ch->lock, *irq_flags); | 132 | spin_lock_irqsave(&ch->lock, *irq_flags); |
753 | } | 133 | } |
754 | 134 | ||
135 | DBUG_ON(atomic_read(&ch->n_to_notify) != 0); | ||
136 | |||
755 | /* it's now safe to free the channel's message queues */ | 137 | /* it's now safe to free the channel's message queues */ |
756 | xpc_free_msgqueues(ch); | 138 | xpc_teardown_msg_structures(ch); |
757 | 139 | ||
758 | /* mark disconnected, clear all other flags except XPC_C_WDISCONNECT */ | 140 | ch->func = NULL; |
141 | ch->key = NULL; | ||
142 | ch->entry_size = 0; | ||
143 | ch->local_nentries = 0; | ||
144 | ch->remote_nentries = 0; | ||
145 | ch->kthreads_assigned_limit = 0; | ||
146 | ch->kthreads_idle_limit = 0; | ||
147 | |||
148 | /* | ||
149 | * Mark the channel disconnected and clear all other flags, including | ||
150 | * XPC_C_SETUP (because of call to xpc_teardown_msg_structures()) but | ||
151 | * not including XPC_C_WDISCONNECT (if it was set). | ||
152 | */ | ||
759 | ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT)); | 153 | ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT)); |
760 | 154 | ||
761 | atomic_dec(&part->nchannels_active); | 155 | atomic_dec(&part->nchannels_active); |
@@ -768,15 +162,15 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
768 | if (ch->flags & XPC_C_WDISCONNECT) { | 162 | if (ch->flags & XPC_C_WDISCONNECT) { |
769 | /* we won't lose the CPU since we're holding ch->lock */ | 163 | /* we won't lose the CPU since we're holding ch->lock */ |
770 | complete(&ch->wdisconnect_wait); | 164 | complete(&ch->wdisconnect_wait); |
771 | } else if (ch->delayed_IPI_flags) { | 165 | } else if (ch->delayed_chctl_flags) { |
772 | if (part->act_state != XPC_P_DEACTIVATING) { | 166 | if (part->act_state != XPC_P_AS_DEACTIVATING) { |
773 | /* time to take action on any delayed IPI flags */ | 167 | /* time to take action on any delayed chctl flags */ |
774 | spin_lock(&part->IPI_lock); | 168 | spin_lock(&part->chctl_lock); |
775 | XPC_SET_IPI_FLAGS(part->local_IPI_amo, ch->number, | 169 | part->chctl.flags[ch->number] |= |
776 | ch->delayed_IPI_flags); | 170 | ch->delayed_chctl_flags; |
777 | spin_unlock(&part->IPI_lock); | 171 | spin_unlock(&part->chctl_lock); |
778 | } | 172 | } |
779 | ch->delayed_IPI_flags = 0; | 173 | ch->delayed_chctl_flags = 0; |
780 | } | 174 | } |
781 | } | 175 | } |
782 | 176 | ||
@@ -784,8 +178,8 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
784 | * Process a change in the channel's remote connection state. | 178 | * Process a change in the channel's remote connection state. |
785 | */ | 179 | */ |
786 | static void | 180 | static void |
787 | xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, | 181 | xpc_process_openclose_chctl_flags(struct xpc_partition *part, int ch_number, |
788 | u8 IPI_flags) | 182 | u8 chctl_flags) |
789 | { | 183 | { |
790 | unsigned long irq_flags; | 184 | unsigned long irq_flags; |
791 | struct xpc_openclose_args *args = | 185 | struct xpc_openclose_args *args = |
@@ -800,24 +194,24 @@ again: | |||
800 | if ((ch->flags & XPC_C_DISCONNECTED) && | 194 | if ((ch->flags & XPC_C_DISCONNECTED) && |
801 | (ch->flags & XPC_C_WDISCONNECT)) { | 195 | (ch->flags & XPC_C_WDISCONNECT)) { |
802 | /* | 196 | /* |
803 | * Delay processing IPI flags until thread waiting disconnect | 197 | * Delay processing chctl flags until thread waiting disconnect |
804 | * has had a chance to see that the channel is disconnected. | 198 | * has had a chance to see that the channel is disconnected. |
805 | */ | 199 | */ |
806 | ch->delayed_IPI_flags |= IPI_flags; | 200 | ch->delayed_chctl_flags |= chctl_flags; |
807 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 201 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
808 | return; | 202 | return; |
809 | } | 203 | } |
810 | 204 | ||
811 | if (IPI_flags & XPC_IPI_CLOSEREQUEST) { | 205 | if (chctl_flags & XPC_CHCTL_CLOSEREQUEST) { |
812 | 206 | ||
813 | dev_dbg(xpc_chan, "XPC_IPI_CLOSEREQUEST (reason=%d) received " | 207 | dev_dbg(xpc_chan, "XPC_CHCTL_CLOSEREQUEST (reason=%d) received " |
814 | "from partid=%d, channel=%d\n", args->reason, | 208 | "from partid=%d, channel=%d\n", args->reason, |
815 | ch->partid, ch->number); | 209 | ch->partid, ch->number); |
816 | 210 | ||
817 | /* | 211 | /* |
818 | * If RCLOSEREQUEST is set, we're probably waiting for | 212 | * If RCLOSEREQUEST is set, we're probably waiting for |
819 | * RCLOSEREPLY. We should find it and a ROPENREQUEST packed | 213 | * RCLOSEREPLY. We should find it and a ROPENREQUEST packed |
820 | * with this RCLOSEREQUEST in the IPI_flags. | 214 | * with this RCLOSEREQUEST in the chctl_flags. |
821 | */ | 215 | */ |
822 | 216 | ||
823 | if (ch->flags & XPC_C_RCLOSEREQUEST) { | 217 | if (ch->flags & XPC_C_RCLOSEREQUEST) { |
@@ -826,8 +220,8 @@ again: | |||
826 | DBUG_ON(!(ch->flags & XPC_C_CLOSEREPLY)); | 220 | DBUG_ON(!(ch->flags & XPC_C_CLOSEREPLY)); |
827 | DBUG_ON(ch->flags & XPC_C_RCLOSEREPLY); | 221 | DBUG_ON(ch->flags & XPC_C_RCLOSEREPLY); |
828 | 222 | ||
829 | DBUG_ON(!(IPI_flags & XPC_IPI_CLOSEREPLY)); | 223 | DBUG_ON(!(chctl_flags & XPC_CHCTL_CLOSEREPLY)); |
830 | IPI_flags &= ~XPC_IPI_CLOSEREPLY; | 224 | chctl_flags &= ~XPC_CHCTL_CLOSEREPLY; |
831 | ch->flags |= XPC_C_RCLOSEREPLY; | 225 | ch->flags |= XPC_C_RCLOSEREPLY; |
832 | 226 | ||
833 | /* both sides have finished disconnecting */ | 227 | /* both sides have finished disconnecting */ |
@@ -837,17 +231,15 @@ again: | |||
837 | } | 231 | } |
838 | 232 | ||
839 | if (ch->flags & XPC_C_DISCONNECTED) { | 233 | if (ch->flags & XPC_C_DISCONNECTED) { |
840 | if (!(IPI_flags & XPC_IPI_OPENREQUEST)) { | 234 | if (!(chctl_flags & XPC_CHCTL_OPENREQUEST)) { |
841 | if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, | 235 | if (part->chctl.flags[ch_number] & |
842 | ch_number) & | 236 | XPC_CHCTL_OPENREQUEST) { |
843 | XPC_IPI_OPENREQUEST)) { | 237 | |
844 | 238 | DBUG_ON(ch->delayed_chctl_flags != 0); | |
845 | DBUG_ON(ch->delayed_IPI_flags != 0); | 239 | spin_lock(&part->chctl_lock); |
846 | spin_lock(&part->IPI_lock); | 240 | part->chctl.flags[ch_number] |= |
847 | XPC_SET_IPI_FLAGS(part->local_IPI_amo, | 241 | XPC_CHCTL_CLOSEREQUEST; |
848 | ch_number, | 242 | spin_unlock(&part->chctl_lock); |
849 | XPC_IPI_CLOSEREQUEST); | ||
850 | spin_unlock(&part->IPI_lock); | ||
851 | } | 243 | } |
852 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 244 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
853 | return; | 245 | return; |
@@ -860,7 +252,7 @@ again: | |||
860 | ch->flags |= (XPC_C_CONNECTING | XPC_C_ROPENREQUEST); | 252 | ch->flags |= (XPC_C_CONNECTING | XPC_C_ROPENREQUEST); |
861 | } | 253 | } |
862 | 254 | ||
863 | IPI_flags &= ~(XPC_IPI_OPENREQUEST | XPC_IPI_OPENREPLY); | 255 | chctl_flags &= ~(XPC_CHCTL_OPENREQUEST | XPC_CHCTL_OPENREPLY); |
864 | 256 | ||
865 | /* | 257 | /* |
866 | * The meaningful CLOSEREQUEST connection state fields are: | 258 | * The meaningful CLOSEREQUEST connection state fields are: |
@@ -878,7 +270,7 @@ again: | |||
878 | 270 | ||
879 | XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); | 271 | XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); |
880 | 272 | ||
881 | DBUG_ON(IPI_flags & XPC_IPI_CLOSEREPLY); | 273 | DBUG_ON(chctl_flags & XPC_CHCTL_CLOSEREPLY); |
882 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 274 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
883 | return; | 275 | return; |
884 | } | 276 | } |
@@ -886,13 +278,13 @@ again: | |||
886 | xpc_process_disconnect(ch, &irq_flags); | 278 | xpc_process_disconnect(ch, &irq_flags); |
887 | } | 279 | } |
888 | 280 | ||
889 | if (IPI_flags & XPC_IPI_CLOSEREPLY) { | 281 | if (chctl_flags & XPC_CHCTL_CLOSEREPLY) { |
890 | 282 | ||
891 | dev_dbg(xpc_chan, "XPC_IPI_CLOSEREPLY received from partid=%d," | 283 | dev_dbg(xpc_chan, "XPC_CHCTL_CLOSEREPLY received from partid=" |
892 | " channel=%d\n", ch->partid, ch->number); | 284 | "%d, channel=%d\n", ch->partid, ch->number); |
893 | 285 | ||
894 | if (ch->flags & XPC_C_DISCONNECTED) { | 286 | if (ch->flags & XPC_C_DISCONNECTED) { |
895 | DBUG_ON(part->act_state != XPC_P_DEACTIVATING); | 287 | DBUG_ON(part->act_state != XPC_P_AS_DEACTIVATING); |
896 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 288 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
897 | return; | 289 | return; |
898 | } | 290 | } |
@@ -900,15 +292,14 @@ again: | |||
900 | DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); | 292 | DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); |
901 | 293 | ||
902 | if (!(ch->flags & XPC_C_RCLOSEREQUEST)) { | 294 | if (!(ch->flags & XPC_C_RCLOSEREQUEST)) { |
903 | if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, ch_number) | 295 | if (part->chctl.flags[ch_number] & |
904 | & XPC_IPI_CLOSEREQUEST)) { | 296 | XPC_CHCTL_CLOSEREQUEST) { |
905 | 297 | ||
906 | DBUG_ON(ch->delayed_IPI_flags != 0); | 298 | DBUG_ON(ch->delayed_chctl_flags != 0); |
907 | spin_lock(&part->IPI_lock); | 299 | spin_lock(&part->chctl_lock); |
908 | XPC_SET_IPI_FLAGS(part->local_IPI_amo, | 300 | part->chctl.flags[ch_number] |= |
909 | ch_number, | 301 | XPC_CHCTL_CLOSEREPLY; |
910 | XPC_IPI_CLOSEREPLY); | 302 | spin_unlock(&part->chctl_lock); |
911 | spin_unlock(&part->IPI_lock); | ||
912 | } | 303 | } |
913 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 304 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
914 | return; | 305 | return; |
@@ -922,21 +313,21 @@ again: | |||
922 | } | 313 | } |
923 | } | 314 | } |
924 | 315 | ||
925 | if (IPI_flags & XPC_IPI_OPENREQUEST) { | 316 | if (chctl_flags & XPC_CHCTL_OPENREQUEST) { |
926 | 317 | ||
927 | dev_dbg(xpc_chan, "XPC_IPI_OPENREQUEST (msg_size=%d, " | 318 | dev_dbg(xpc_chan, "XPC_CHCTL_OPENREQUEST (entry_size=%d, " |
928 | "local_nentries=%d) received from partid=%d, " | 319 | "local_nentries=%d) received from partid=%d, " |
929 | "channel=%d\n", args->msg_size, args->local_nentries, | 320 | "channel=%d\n", args->entry_size, args->local_nentries, |
930 | ch->partid, ch->number); | 321 | ch->partid, ch->number); |
931 | 322 | ||
932 | if (part->act_state == XPC_P_DEACTIVATING || | 323 | if (part->act_state == XPC_P_AS_DEACTIVATING || |
933 | (ch->flags & XPC_C_ROPENREQUEST)) { | 324 | (ch->flags & XPC_C_ROPENREQUEST)) { |
934 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 325 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
935 | return; | 326 | return; |
936 | } | 327 | } |
937 | 328 | ||
938 | if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_WDISCONNECT)) { | 329 | if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_WDISCONNECT)) { |
939 | ch->delayed_IPI_flags |= XPC_IPI_OPENREQUEST; | 330 | ch->delayed_chctl_flags |= XPC_CHCTL_OPENREQUEST; |
940 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 331 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
941 | return; | 332 | return; |
942 | } | 333 | } |
@@ -947,10 +338,10 @@ again: | |||
947 | 338 | ||
948 | /* | 339 | /* |
949 | * The meaningful OPENREQUEST connection state fields are: | 340 | * The meaningful OPENREQUEST connection state fields are: |
950 | * msg_size = size of channel's messages in bytes | 341 | * entry_size = size of channel's messages in bytes |
951 | * local_nentries = remote partition's local_nentries | 342 | * local_nentries = remote partition's local_nentries |
952 | */ | 343 | */ |
953 | if (args->msg_size == 0 || args->local_nentries == 0) { | 344 | if (args->entry_size == 0 || args->local_nentries == 0) { |
954 | /* assume OPENREQUEST was delayed by mistake */ | 345 | /* assume OPENREQUEST was delayed by mistake */ |
955 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 346 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
956 | return; | 347 | return; |
@@ -960,14 +351,14 @@ again: | |||
960 | ch->remote_nentries = args->local_nentries; | 351 | ch->remote_nentries = args->local_nentries; |
961 | 352 | ||
962 | if (ch->flags & XPC_C_OPENREQUEST) { | 353 | if (ch->flags & XPC_C_OPENREQUEST) { |
963 | if (args->msg_size != ch->msg_size) { | 354 | if (args->entry_size != ch->entry_size) { |
964 | XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes, | 355 | XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes, |
965 | &irq_flags); | 356 | &irq_flags); |
966 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 357 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
967 | return; | 358 | return; |
968 | } | 359 | } |
969 | } else { | 360 | } else { |
970 | ch->msg_size = args->msg_size; | 361 | ch->entry_size = args->entry_size; |
971 | 362 | ||
972 | XPC_SET_REASON(ch, 0, 0); | 363 | XPC_SET_REASON(ch, 0, 0); |
973 | ch->flags &= ~XPC_C_DISCONNECTED; | 364 | ch->flags &= ~XPC_C_DISCONNECTED; |
@@ -978,13 +369,13 @@ again: | |||
978 | xpc_process_connect(ch, &irq_flags); | 369 | xpc_process_connect(ch, &irq_flags); |
979 | } | 370 | } |
980 | 371 | ||
981 | if (IPI_flags & XPC_IPI_OPENREPLY) { | 372 | if (chctl_flags & XPC_CHCTL_OPENREPLY) { |
982 | 373 | ||
983 | dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY (local_msgqueue_pa=0x%lx, " | 374 | dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY (local_msgqueue_pa=" |
984 | "local_nentries=%d, remote_nentries=%d) received from " | 375 | "0x%lx, local_nentries=%d, remote_nentries=%d) " |
985 | "partid=%d, channel=%d\n", args->local_msgqueue_pa, | 376 | "received from partid=%d, channel=%d\n", |
986 | args->local_nentries, args->remote_nentries, | 377 | args->local_msgqueue_pa, args->local_nentries, |
987 | ch->partid, ch->number); | 378 | args->remote_nentries, ch->partid, ch->number); |
988 | 379 | ||
989 | if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) { | 380 | if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) { |
990 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 381 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
@@ -1012,10 +403,10 @@ again: | |||
1012 | DBUG_ON(args->remote_nentries == 0); | 403 | DBUG_ON(args->remote_nentries == 0); |
1013 | 404 | ||
1014 | ch->flags |= XPC_C_ROPENREPLY; | 405 | ch->flags |= XPC_C_ROPENREPLY; |
1015 | ch->remote_msgqueue_pa = args->local_msgqueue_pa; | 406 | xpc_save_remote_msgqueue_pa(ch, args->local_msgqueue_pa); |
1016 | 407 | ||
1017 | if (args->local_nentries < ch->remote_nentries) { | 408 | if (args->local_nentries < ch->remote_nentries) { |
1018 | dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY: new " | 409 | dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new " |
1019 | "remote_nentries=%d, old remote_nentries=%d, " | 410 | "remote_nentries=%d, old remote_nentries=%d, " |
1020 | "partid=%d, channel=%d\n", | 411 | "partid=%d, channel=%d\n", |
1021 | args->local_nentries, ch->remote_nentries, | 412 | args->local_nentries, ch->remote_nentries, |
@@ -1024,7 +415,7 @@ again: | |||
1024 | ch->remote_nentries = args->local_nentries; | 415 | ch->remote_nentries = args->local_nentries; |
1025 | } | 416 | } |
1026 | if (args->remote_nentries < ch->local_nentries) { | 417 | if (args->remote_nentries < ch->local_nentries) { |
1027 | dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY: new " | 418 | dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new " |
1028 | "local_nentries=%d, old local_nentries=%d, " | 419 | "local_nentries=%d, old local_nentries=%d, " |
1029 | "partid=%d, channel=%d\n", | 420 | "partid=%d, channel=%d\n", |
1030 | args->remote_nentries, ch->local_nentries, | 421 | args->remote_nentries, ch->local_nentries, |
@@ -1082,7 +473,7 @@ xpc_connect_channel(struct xpc_channel *ch) | |||
1082 | ch->local_nentries = registration->nentries; | 473 | ch->local_nentries = registration->nentries; |
1083 | 474 | ||
1084 | if (ch->flags & XPC_C_ROPENREQUEST) { | 475 | if (ch->flags & XPC_C_ROPENREQUEST) { |
1085 | if (registration->msg_size != ch->msg_size) { | 476 | if (registration->entry_size != ch->entry_size) { |
1086 | /* the local and remote sides aren't the same */ | 477 | /* the local and remote sides aren't the same */ |
1087 | 478 | ||
1088 | /* | 479 | /* |
@@ -1101,7 +492,7 @@ xpc_connect_channel(struct xpc_channel *ch) | |||
1101 | return xpUnequalMsgSizes; | 492 | return xpUnequalMsgSizes; |
1102 | } | 493 | } |
1103 | } else { | 494 | } else { |
1104 | ch->msg_size = registration->msg_size; | 495 | ch->entry_size = registration->entry_size; |
1105 | 496 | ||
1106 | XPC_SET_REASON(ch, 0, 0); | 497 | XPC_SET_REASON(ch, 0, 0); |
1107 | ch->flags &= ~XPC_C_DISCONNECTED; | 498 | ch->flags &= ~XPC_C_DISCONNECTED; |
@@ -1114,7 +505,7 @@ xpc_connect_channel(struct xpc_channel *ch) | |||
1114 | /* initiate the connection */ | 505 | /* initiate the connection */ |
1115 | 506 | ||
1116 | ch->flags |= (XPC_C_OPENREQUEST | XPC_C_CONNECTING); | 507 | ch->flags |= (XPC_C_OPENREQUEST | XPC_C_CONNECTING); |
1117 | xpc_IPI_send_openrequest(ch, &irq_flags); | 508 | xpc_send_chctl_openrequest(ch, &irq_flags); |
1118 | 509 | ||
1119 | xpc_process_connect(ch, &irq_flags); | 510 | xpc_process_connect(ch, &irq_flags); |
1120 | 511 | ||
@@ -1123,152 +514,16 @@ xpc_connect_channel(struct xpc_channel *ch) | |||
1123 | return xpSuccess; | 514 | return xpSuccess; |
1124 | } | 515 | } |
1125 | 516 | ||
1126 | /* | ||
1127 | * Clear some of the msg flags in the local message queue. | ||
1128 | */ | ||
1129 | static inline void | ||
1130 | xpc_clear_local_msgqueue_flags(struct xpc_channel *ch) | ||
1131 | { | ||
1132 | struct xpc_msg *msg; | ||
1133 | s64 get; | ||
1134 | |||
1135 | get = ch->w_remote_GP.get; | ||
1136 | do { | ||
1137 | msg = (struct xpc_msg *)((u64)ch->local_msgqueue + | ||
1138 | (get % ch->local_nentries) * | ||
1139 | ch->msg_size); | ||
1140 | msg->flags = 0; | ||
1141 | } while (++get < ch->remote_GP.get); | ||
1142 | } | ||
1143 | |||
1144 | /* | ||
1145 | * Clear some of the msg flags in the remote message queue. | ||
1146 | */ | ||
1147 | static inline void | ||
1148 | xpc_clear_remote_msgqueue_flags(struct xpc_channel *ch) | ||
1149 | { | ||
1150 | struct xpc_msg *msg; | ||
1151 | s64 put; | ||
1152 | |||
1153 | put = ch->w_remote_GP.put; | ||
1154 | do { | ||
1155 | msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + | ||
1156 | (put % ch->remote_nentries) * | ||
1157 | ch->msg_size); | ||
1158 | msg->flags = 0; | ||
1159 | } while (++put < ch->remote_GP.put); | ||
1160 | } | ||
1161 | |||
1162 | static void | ||
1163 | xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) | ||
1164 | { | ||
1165 | struct xpc_channel *ch = &part->channels[ch_number]; | ||
1166 | int nmsgs_sent; | ||
1167 | |||
1168 | ch->remote_GP = part->remote_GPs[ch_number]; | ||
1169 | |||
1170 | /* See what, if anything, has changed for each connected channel */ | ||
1171 | |||
1172 | xpc_msgqueue_ref(ch); | ||
1173 | |||
1174 | if (ch->w_remote_GP.get == ch->remote_GP.get && | ||
1175 | ch->w_remote_GP.put == ch->remote_GP.put) { | ||
1176 | /* nothing changed since GPs were last pulled */ | ||
1177 | xpc_msgqueue_deref(ch); | ||
1178 | return; | ||
1179 | } | ||
1180 | |||
1181 | if (!(ch->flags & XPC_C_CONNECTED)) { | ||
1182 | xpc_msgqueue_deref(ch); | ||
1183 | return; | ||
1184 | } | ||
1185 | |||
1186 | /* | ||
1187 | * First check to see if messages recently sent by us have been | ||
1188 | * received by the other side. (The remote GET value will have | ||
1189 | * changed since we last looked at it.) | ||
1190 | */ | ||
1191 | |||
1192 | if (ch->w_remote_GP.get != ch->remote_GP.get) { | ||
1193 | |||
1194 | /* | ||
1195 | * We need to notify any senders that want to be notified | ||
1196 | * that their sent messages have been received by their | ||
1197 | * intended recipients. We need to do this before updating | ||
1198 | * w_remote_GP.get so that we don't allocate the same message | ||
1199 | * queue entries prematurely (see xpc_allocate_msg()). | ||
1200 | */ | ||
1201 | if (atomic_read(&ch->n_to_notify) > 0) { | ||
1202 | /* | ||
1203 | * Notify senders that messages sent have been | ||
1204 | * received and delivered by the other side. | ||
1205 | */ | ||
1206 | xpc_notify_senders(ch, xpMsgDelivered, | ||
1207 | ch->remote_GP.get); | ||
1208 | } | ||
1209 | |||
1210 | /* | ||
1211 | * Clear msg->flags in previously sent messages, so that | ||
1212 | * they're ready for xpc_allocate_msg(). | ||
1213 | */ | ||
1214 | xpc_clear_local_msgqueue_flags(ch); | ||
1215 | |||
1216 | ch->w_remote_GP.get = ch->remote_GP.get; | ||
1217 | |||
1218 | dev_dbg(xpc_chan, "w_remote_GP.get changed to %ld, partid=%d, " | ||
1219 | "channel=%d\n", ch->w_remote_GP.get, ch->partid, | ||
1220 | ch->number); | ||
1221 | |||
1222 | /* | ||
1223 | * If anyone was waiting for message queue entries to become | ||
1224 | * available, wake them up. | ||
1225 | */ | ||
1226 | if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) | ||
1227 | wake_up(&ch->msg_allocate_wq); | ||
1228 | } | ||
1229 | |||
1230 | /* | ||
1231 | * Now check for newly sent messages by the other side. (The remote | ||
1232 | * PUT value will have changed since we last looked at it.) | ||
1233 | */ | ||
1234 | |||
1235 | if (ch->w_remote_GP.put != ch->remote_GP.put) { | ||
1236 | /* | ||
1237 | * Clear msg->flags in previously received messages, so that | ||
1238 | * they're ready for xpc_get_deliverable_msg(). | ||
1239 | */ | ||
1240 | xpc_clear_remote_msgqueue_flags(ch); | ||
1241 | |||
1242 | ch->w_remote_GP.put = ch->remote_GP.put; | ||
1243 | |||
1244 | dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, " | ||
1245 | "channel=%d\n", ch->w_remote_GP.put, ch->partid, | ||
1246 | ch->number); | ||
1247 | |||
1248 | nmsgs_sent = ch->w_remote_GP.put - ch->w_local_GP.get; | ||
1249 | if (nmsgs_sent > 0) { | ||
1250 | dev_dbg(xpc_chan, "msgs waiting to be copied and " | ||
1251 | "delivered=%d, partid=%d, channel=%d\n", | ||
1252 | nmsgs_sent, ch->partid, ch->number); | ||
1253 | |||
1254 | if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) | ||
1255 | xpc_activate_kthreads(ch, nmsgs_sent); | ||
1256 | } | ||
1257 | } | ||
1258 | |||
1259 | xpc_msgqueue_deref(ch); | ||
1260 | } | ||
1261 | |||
1262 | void | 517 | void |
1263 | xpc_process_channel_activity(struct xpc_partition *part) | 518 | xpc_process_sent_chctl_flags(struct xpc_partition *part) |
1264 | { | 519 | { |
1265 | unsigned long irq_flags; | 520 | unsigned long irq_flags; |
1266 | u64 IPI_amo, IPI_flags; | 521 | union xpc_channel_ctl_flags chctl; |
1267 | struct xpc_channel *ch; | 522 | struct xpc_channel *ch; |
1268 | int ch_number; | 523 | int ch_number; |
1269 | u32 ch_flags; | 524 | u32 ch_flags; |
1270 | 525 | ||
1271 | IPI_amo = xpc_get_IPI_flags(part); | 526 | chctl.all_flags = xpc_get_chctl_all_flags(part); |
1272 | 527 | ||
1273 | /* | 528 | /* |
1274 | * Initiate channel connections for registered channels. | 529 | * Initiate channel connections for registered channels. |
@@ -1281,14 +536,14 @@ xpc_process_channel_activity(struct xpc_partition *part) | |||
1281 | ch = &part->channels[ch_number]; | 536 | ch = &part->channels[ch_number]; |
1282 | 537 | ||
1283 | /* | 538 | /* |
1284 | * Process any open or close related IPI flags, and then deal | 539 | * Process any open or close related chctl flags, and then deal |
1285 | * with connecting or disconnecting the channel as required. | 540 | * with connecting or disconnecting the channel as required. |
1286 | */ | 541 | */ |
1287 | 542 | ||
1288 | IPI_flags = XPC_GET_IPI_FLAGS(IPI_amo, ch_number); | 543 | if (chctl.flags[ch_number] & XPC_OPENCLOSE_CHCTL_FLAGS) { |
1289 | 544 | xpc_process_openclose_chctl_flags(part, ch_number, | |
1290 | if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_flags)) | 545 | chctl.flags[ch_number]); |
1291 | xpc_process_openclose_IPI(part, ch_number, IPI_flags); | 546 | } |
1292 | 547 | ||
1293 | ch_flags = ch->flags; /* need an atomic snapshot of flags */ | 548 | ch_flags = ch->flags; /* need an atomic snapshot of flags */ |
1294 | 549 | ||
@@ -1299,7 +554,7 @@ xpc_process_channel_activity(struct xpc_partition *part) | |||
1299 | continue; | 554 | continue; |
1300 | } | 555 | } |
1301 | 556 | ||
1302 | if (part->act_state == XPC_P_DEACTIVATING) | 557 | if (part->act_state == XPC_P_AS_DEACTIVATING) |
1303 | continue; | 558 | continue; |
1304 | 559 | ||
1305 | if (!(ch_flags & XPC_C_CONNECTED)) { | 560 | if (!(ch_flags & XPC_C_CONNECTED)) { |
@@ -1315,13 +570,13 @@ xpc_process_channel_activity(struct xpc_partition *part) | |||
1315 | } | 570 | } |
1316 | 571 | ||
1317 | /* | 572 | /* |
1318 | * Process any message related IPI flags, this may involve the | 573 | * Process any message related chctl flags, this may involve |
1319 | * activation of kthreads to deliver any pending messages sent | 574 | * the activation of kthreads to deliver any pending messages |
1320 | * from the other partition. | 575 | * sent from the other partition. |
1321 | */ | 576 | */ |
1322 | 577 | ||
1323 | if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_flags)) | 578 | if (chctl.flags[ch_number] & XPC_MSG_CHCTL_FLAGS) |
1324 | xpc_process_msg_IPI(part, ch_number); | 579 | xpc_process_msg_chctl_flags(part, ch_number); |
1325 | } | 580 | } |
1326 | } | 581 | } |
1327 | 582 | ||
@@ -1369,59 +624,6 @@ xpc_partition_going_down(struct xpc_partition *part, enum xp_retval reason) | |||
1369 | } | 624 | } |
1370 | 625 | ||
1371 | /* | 626 | /* |
1372 | * Teardown the infrastructure necessary to support XPartition Communication | ||
1373 | * between the specified remote partition and the local one. | ||
1374 | */ | ||
1375 | void | ||
1376 | xpc_teardown_infrastructure(struct xpc_partition *part) | ||
1377 | { | ||
1378 | short partid = XPC_PARTID(part); | ||
1379 | |||
1380 | /* | ||
1381 | * We start off by making this partition inaccessible to local | ||
1382 | * processes by marking it as no longer setup. Then we make it | ||
1383 | * inaccessible to remote processes by clearing the XPC per partition | ||
1384 | * specific variable's magic # (which indicates that these variables | ||
1385 | * are no longer valid) and by ignoring all XPC notify IPIs sent to | ||
1386 | * this partition. | ||
1387 | */ | ||
1388 | |||
1389 | DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); | ||
1390 | DBUG_ON(atomic_read(&part->nchannels_active) != 0); | ||
1391 | DBUG_ON(part->setup_state != XPC_P_SETUP); | ||
1392 | part->setup_state = XPC_P_WTEARDOWN; | ||
1393 | |||
1394 | xpc_vars_part[partid].magic = 0; | ||
1395 | |||
1396 | free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid); | ||
1397 | |||
1398 | /* | ||
1399 | * Before proceeding with the teardown we have to wait until all | ||
1400 | * existing references cease. | ||
1401 | */ | ||
1402 | wait_event(part->teardown_wq, (atomic_read(&part->references) == 0)); | ||
1403 | |||
1404 | /* now we can begin tearing down the infrastructure */ | ||
1405 | |||
1406 | part->setup_state = XPC_P_TORNDOWN; | ||
1407 | |||
1408 | /* in case we've still got outstanding timers registered... */ | ||
1409 | del_timer_sync(&part->dropped_IPI_timer); | ||
1410 | |||
1411 | kfree(part->remote_openclose_args_base); | ||
1412 | part->remote_openclose_args = NULL; | ||
1413 | kfree(part->local_openclose_args_base); | ||
1414 | part->local_openclose_args = NULL; | ||
1415 | kfree(part->remote_GPs_base); | ||
1416 | part->remote_GPs = NULL; | ||
1417 | kfree(part->local_GPs_base); | ||
1418 | part->local_GPs = NULL; | ||
1419 | kfree(part->channels); | ||
1420 | part->channels = NULL; | ||
1421 | part->local_IPI_amo_va = NULL; | ||
1422 | } | ||
1423 | |||
1424 | /* | ||
1425 | * Called by XP at the time of channel connection registration to cause | 627 | * Called by XP at the time of channel connection registration to cause |
1426 | * XPC to establish connections to all currently active partitions. | 628 | * XPC to establish connections to all currently active partitions. |
1427 | */ | 629 | */ |
@@ -1432,9 +634,9 @@ xpc_initiate_connect(int ch_number) | |||
1432 | struct xpc_partition *part; | 634 | struct xpc_partition *part; |
1433 | struct xpc_channel *ch; | 635 | struct xpc_channel *ch; |
1434 | 636 | ||
1435 | DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); | 637 | DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS); |
1436 | 638 | ||
1437 | for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { | 639 | for (partid = 0; partid < xp_max_npartitions; partid++) { |
1438 | part = &xpc_partitions[partid]; | 640 | part = &xpc_partitions[partid]; |
1439 | 641 | ||
1440 | if (xpc_part_ref(part)) { | 642 | if (xpc_part_ref(part)) { |
@@ -1488,10 +690,10 @@ xpc_initiate_disconnect(int ch_number) | |||
1488 | struct xpc_partition *part; | 690 | struct xpc_partition *part; |
1489 | struct xpc_channel *ch; | 691 | struct xpc_channel *ch; |
1490 | 692 | ||
1491 | DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); | 693 | DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS); |
1492 | 694 | ||
1493 | /* initiate the channel disconnect for every active partition */ | 695 | /* initiate the channel disconnect for every active partition */ |
1494 | for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { | 696 | for (partid = 0; partid < xp_max_npartitions; partid++) { |
1495 | part = &xpc_partitions[partid]; | 697 | part = &xpc_partitions[partid]; |
1496 | 698 | ||
1497 | if (xpc_part_ref(part)) { | 699 | if (xpc_part_ref(part)) { |
@@ -1550,7 +752,7 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, | |||
1550 | XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | | 752 | XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | |
1551 | XPC_C_CONNECTING | XPC_C_CONNECTED); | 753 | XPC_C_CONNECTING | XPC_C_CONNECTED); |
1552 | 754 | ||
1553 | xpc_IPI_send_closerequest(ch, irq_flags); | 755 | xpc_send_chctl_closerequest(ch, irq_flags); |
1554 | 756 | ||
1555 | if (channel_was_connected) | 757 | if (channel_was_connected) |
1556 | ch->flags |= XPC_C_WASCONNECTED; | 758 | ch->flags |= XPC_C_WASCONNECTED; |
@@ -1598,7 +800,7 @@ xpc_disconnect_callout(struct xpc_channel *ch, enum xp_retval reason) | |||
1598 | * Wait for a message entry to become available for the specified channel, | 800 | * Wait for a message entry to become available for the specified channel, |
1599 | * but don't wait any longer than 1 jiffy. | 801 | * but don't wait any longer than 1 jiffy. |
1600 | */ | 802 | */ |
1601 | static enum xp_retval | 803 | enum xp_retval |
1602 | xpc_allocate_msg_wait(struct xpc_channel *ch) | 804 | xpc_allocate_msg_wait(struct xpc_channel *ch) |
1603 | { | 805 | { |
1604 | enum xp_retval ret; | 806 | enum xp_retval ret; |
@@ -1625,315 +827,54 @@ xpc_allocate_msg_wait(struct xpc_channel *ch) | |||
1625 | } | 827 | } |
1626 | 828 | ||
1627 | /* | 829 | /* |
1628 | * Allocate an entry for a message from the message queue associated with the | 830 | * Send a message that contains the user's payload on the specified channel |
1629 | * specified channel. | 831 | * connected to the specified partition. |
1630 | */ | ||
1631 | static enum xp_retval | ||
1632 | xpc_allocate_msg(struct xpc_channel *ch, u32 flags, | ||
1633 | struct xpc_msg **address_of_msg) | ||
1634 | { | ||
1635 | struct xpc_msg *msg; | ||
1636 | enum xp_retval ret; | ||
1637 | s64 put; | ||
1638 | |||
1639 | /* this reference will be dropped in xpc_send_msg() */ | ||
1640 | xpc_msgqueue_ref(ch); | ||
1641 | |||
1642 | if (ch->flags & XPC_C_DISCONNECTING) { | ||
1643 | xpc_msgqueue_deref(ch); | ||
1644 | return ch->reason; | ||
1645 | } | ||
1646 | if (!(ch->flags & XPC_C_CONNECTED)) { | ||
1647 | xpc_msgqueue_deref(ch); | ||
1648 | return xpNotConnected; | ||
1649 | } | ||
1650 | |||
1651 | /* | ||
1652 | * Get the next available message entry from the local message queue. | ||
1653 | * If none are available, we'll make sure that we grab the latest | ||
1654 | * GP values. | ||
1655 | */ | ||
1656 | ret = xpTimeout; | ||
1657 | |||
1658 | while (1) { | ||
1659 | |||
1660 | put = ch->w_local_GP.put; | ||
1661 | rmb(); /* guarantee that .put loads before .get */ | ||
1662 | if (put - ch->w_remote_GP.get < ch->local_nentries) { | ||
1663 | |||
1664 | /* There are available message entries. We need to try | ||
1665 | * to secure one for ourselves. We'll do this by trying | ||
1666 | * to increment w_local_GP.put as long as someone else | ||
1667 | * doesn't beat us to it. If they do, we'll have to | ||
1668 | * try again. | ||
1669 | */ | ||
1670 | if (cmpxchg(&ch->w_local_GP.put, put, put + 1) == put) { | ||
1671 | /* we got the entry referenced by put */ | ||
1672 | break; | ||
1673 | } | ||
1674 | continue; /* try again */ | ||
1675 | } | ||
1676 | |||
1677 | /* | ||
1678 | * There aren't any available msg entries at this time. | ||
1679 | * | ||
1680 | * In waiting for a message entry to become available, | ||
1681 | * we set a timeout in case the other side is not | ||
1682 | * sending completion IPIs. This lets us fake an IPI | ||
1683 | * that will cause the IPI handler to fetch the latest | ||
1684 | * GP values as if an IPI was sent by the other side. | ||
1685 | */ | ||
1686 | if (ret == xpTimeout) | ||
1687 | xpc_IPI_send_local_msgrequest(ch); | ||
1688 | |||
1689 | if (flags & XPC_NOWAIT) { | ||
1690 | xpc_msgqueue_deref(ch); | ||
1691 | return xpNoWait; | ||
1692 | } | ||
1693 | |||
1694 | ret = xpc_allocate_msg_wait(ch); | ||
1695 | if (ret != xpInterrupted && ret != xpTimeout) { | ||
1696 | xpc_msgqueue_deref(ch); | ||
1697 | return ret; | ||
1698 | } | ||
1699 | } | ||
1700 | |||
1701 | /* get the message's address and initialize it */ | ||
1702 | msg = (struct xpc_msg *)((u64)ch->local_msgqueue + | ||
1703 | (put % ch->local_nentries) * ch->msg_size); | ||
1704 | |||
1705 | DBUG_ON(msg->flags != 0); | ||
1706 | msg->number = put; | ||
1707 | |||
1708 | dev_dbg(xpc_chan, "w_local_GP.put changed to %ld; msg=0x%p, " | ||
1709 | "msg_number=%ld, partid=%d, channel=%d\n", put + 1, | ||
1710 | (void *)msg, msg->number, ch->partid, ch->number); | ||
1711 | |||
1712 | *address_of_msg = msg; | ||
1713 | |||
1714 | return xpSuccess; | ||
1715 | } | ||
1716 | |||
1717 | /* | ||
1718 | * Allocate an entry for a message from the message queue associated with the | ||
1719 | * specified channel. NOTE that this routine can sleep waiting for a message | ||
1720 | * entry to become available. To not sleep, pass in the XPC_NOWAIT flag. | ||
1721 | * | 832 | * |
1722 | * Arguments: | 833 | * NOTE that this routine can sleep waiting for a message entry to become |
834 | * available. To not sleep, pass in the XPC_NOWAIT flag. | ||
1723 | * | 835 | * |
1724 | * partid - ID of partition to which the channel is connected. | 836 | * Once sent, this routine will not wait for the message to be received, nor |
1725 | * ch_number - channel #. | 837 | * will notification be given when it does happen. |
1726 | * flags - see xpc.h for valid flags. | ||
1727 | * payload - address of the allocated payload area pointer (filled in on | ||
1728 | * return) in which the user-defined message is constructed. | ||
1729 | */ | ||
1730 | enum xp_retval | ||
1731 | xpc_initiate_allocate(short partid, int ch_number, u32 flags, void **payload) | ||
1732 | { | ||
1733 | struct xpc_partition *part = &xpc_partitions[partid]; | ||
1734 | enum xp_retval ret = xpUnknownReason; | ||
1735 | struct xpc_msg *msg = NULL; | ||
1736 | |||
1737 | DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); | ||
1738 | DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); | ||
1739 | |||
1740 | *payload = NULL; | ||
1741 | |||
1742 | if (xpc_part_ref(part)) { | ||
1743 | ret = xpc_allocate_msg(&part->channels[ch_number], flags, &msg); | ||
1744 | xpc_part_deref(part); | ||
1745 | |||
1746 | if (msg != NULL) | ||
1747 | *payload = &msg->payload; | ||
1748 | } | ||
1749 | |||
1750 | return ret; | ||
1751 | } | ||
1752 | |||
1753 | /* | ||
1754 | * Now we actually send the messages that are ready to be sent by advancing | ||
1755 | * the local message queue's Put value and then send an IPI to the recipient | ||
1756 | * partition. | ||
1757 | */ | ||
1758 | static void | ||
1759 | xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) | ||
1760 | { | ||
1761 | struct xpc_msg *msg; | ||
1762 | s64 put = initial_put + 1; | ||
1763 | int send_IPI = 0; | ||
1764 | |||
1765 | while (1) { | ||
1766 | |||
1767 | while (1) { | ||
1768 | if (put == ch->w_local_GP.put) | ||
1769 | break; | ||
1770 | |||
1771 | msg = (struct xpc_msg *)((u64)ch->local_msgqueue + | ||
1772 | (put % ch->local_nentries) * | ||
1773 | ch->msg_size); | ||
1774 | |||
1775 | if (!(msg->flags & XPC_M_READY)) | ||
1776 | break; | ||
1777 | |||
1778 | put++; | ||
1779 | } | ||
1780 | |||
1781 | if (put == initial_put) { | ||
1782 | /* nothing's changed */ | ||
1783 | break; | ||
1784 | } | ||
1785 | |||
1786 | if (cmpxchg_rel(&ch->local_GP->put, initial_put, put) != | ||
1787 | initial_put) { | ||
1788 | /* someone else beat us to it */ | ||
1789 | DBUG_ON(ch->local_GP->put < initial_put); | ||
1790 | break; | ||
1791 | } | ||
1792 | |||
1793 | /* we just set the new value of local_GP->put */ | ||
1794 | |||
1795 | dev_dbg(xpc_chan, "local_GP->put changed to %ld, partid=%d, " | ||
1796 | "channel=%d\n", put, ch->partid, ch->number); | ||
1797 | |||
1798 | send_IPI = 1; | ||
1799 | |||
1800 | /* | ||
1801 | * We need to ensure that the message referenced by | ||
1802 | * local_GP->put is not XPC_M_READY or that local_GP->put | ||
1803 | * equals w_local_GP.put, so we'll go have a look. | ||
1804 | */ | ||
1805 | initial_put = put; | ||
1806 | } | ||
1807 | |||
1808 | if (send_IPI) | ||
1809 | xpc_IPI_send_msgrequest(ch); | ||
1810 | } | ||
1811 | |||
1812 | /* | ||
1813 | * Common code that does the actual sending of the message by advancing the | ||
1814 | * local message queue's Put value and sends an IPI to the partition the | ||
1815 | * message is being sent to. | ||
1816 | */ | ||
1817 | static enum xp_retval | ||
1818 | xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, | ||
1819 | xpc_notify_func func, void *key) | ||
1820 | { | ||
1821 | enum xp_retval ret = xpSuccess; | ||
1822 | struct xpc_notify *notify = notify; | ||
1823 | s64 put, msg_number = msg->number; | ||
1824 | |||
1825 | DBUG_ON(notify_type == XPC_N_CALL && func == NULL); | ||
1826 | DBUG_ON((((u64)msg - (u64)ch->local_msgqueue) / ch->msg_size) != | ||
1827 | msg_number % ch->local_nentries); | ||
1828 | DBUG_ON(msg->flags & XPC_M_READY); | ||
1829 | |||
1830 | if (ch->flags & XPC_C_DISCONNECTING) { | ||
1831 | /* drop the reference grabbed in xpc_allocate_msg() */ | ||
1832 | xpc_msgqueue_deref(ch); | ||
1833 | return ch->reason; | ||
1834 | } | ||
1835 | |||
1836 | if (notify_type != 0) { | ||
1837 | /* | ||
1838 | * Tell the remote side to send an ACK interrupt when the | ||
1839 | * message has been delivered. | ||
1840 | */ | ||
1841 | msg->flags |= XPC_M_INTERRUPT; | ||
1842 | |||
1843 | atomic_inc(&ch->n_to_notify); | ||
1844 | |||
1845 | notify = &ch->notify_queue[msg_number % ch->local_nentries]; | ||
1846 | notify->func = func; | ||
1847 | notify->key = key; | ||
1848 | notify->type = notify_type; | ||
1849 | |||
1850 | /* >>> is a mb() needed here? */ | ||
1851 | |||
1852 | if (ch->flags & XPC_C_DISCONNECTING) { | ||
1853 | /* | ||
1854 | * An error occurred between our last error check and | ||
1855 | * this one. We will try to clear the type field from | ||
1856 | * the notify entry. If we succeed then | ||
1857 | * xpc_disconnect_channel() didn't already process | ||
1858 | * the notify entry. | ||
1859 | */ | ||
1860 | if (cmpxchg(¬ify->type, notify_type, 0) == | ||
1861 | notify_type) { | ||
1862 | atomic_dec(&ch->n_to_notify); | ||
1863 | ret = ch->reason; | ||
1864 | } | ||
1865 | |||
1866 | /* drop the reference grabbed in xpc_allocate_msg() */ | ||
1867 | xpc_msgqueue_deref(ch); | ||
1868 | return ret; | ||
1869 | } | ||
1870 | } | ||
1871 | |||
1872 | msg->flags |= XPC_M_READY; | ||
1873 | |||
1874 | /* | ||
1875 | * The preceding store of msg->flags must occur before the following | ||
1876 | * load of ch->local_GP->put. | ||
1877 | */ | ||
1878 | mb(); | ||
1879 | |||
1880 | /* see if the message is next in line to be sent, if so send it */ | ||
1881 | |||
1882 | put = ch->local_GP->put; | ||
1883 | if (put == msg_number) | ||
1884 | xpc_send_msgs(ch, put); | ||
1885 | |||
1886 | /* drop the reference grabbed in xpc_allocate_msg() */ | ||
1887 | xpc_msgqueue_deref(ch); | ||
1888 | return ret; | ||
1889 | } | ||
1890 | |||
1891 | /* | ||
1892 | * Send a message previously allocated using xpc_initiate_allocate() on the | ||
1893 | * specified channel connected to the specified partition. | ||
1894 | * | ||
1895 | * This routine will not wait for the message to be received, nor will | ||
1896 | * notification be given when it does happen. Once this routine has returned | ||
1897 | * the message entry allocated via xpc_initiate_allocate() is no longer | ||
1898 | * accessable to the caller. | ||
1899 | * | ||
1900 | * This routine, although called by users, does not call xpc_part_ref() to | ||
1901 | * ensure that the partition infrastructure is in place. It relies on the | ||
1902 | * fact that we called xpc_msgqueue_ref() in xpc_allocate_msg(). | ||
1903 | * | 838 | * |
1904 | * Arguments: | 839 | * Arguments: |
1905 | * | 840 | * |
1906 | * partid - ID of partition to which the channel is connected. | 841 | * partid - ID of partition to which the channel is connected. |
1907 | * ch_number - channel # to send message on. | 842 | * ch_number - channel # to send message on. |
1908 | * payload - pointer to the payload area allocated via | 843 | * flags - see xp.h for valid flags. |
1909 | * xpc_initiate_allocate(). | 844 | * payload - pointer to the payload which is to be sent. |
845 | * payload_size - size of the payload in bytes. | ||
1910 | */ | 846 | */ |
1911 | enum xp_retval | 847 | enum xp_retval |
1912 | xpc_initiate_send(short partid, int ch_number, void *payload) | 848 | xpc_initiate_send(short partid, int ch_number, u32 flags, void *payload, |
849 | u16 payload_size) | ||
1913 | { | 850 | { |
1914 | struct xpc_partition *part = &xpc_partitions[partid]; | 851 | struct xpc_partition *part = &xpc_partitions[partid]; |
1915 | struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); | 852 | enum xp_retval ret = xpUnknownReason; |
1916 | enum xp_retval ret; | ||
1917 | 853 | ||
1918 | dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg, | 854 | dev_dbg(xpc_chan, "payload=0x%p, partid=%d, channel=%d\n", payload, |
1919 | partid, ch_number); | 855 | partid, ch_number); |
1920 | 856 | ||
1921 | DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); | 857 | DBUG_ON(partid < 0 || partid >= xp_max_npartitions); |
1922 | DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); | 858 | DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); |
1923 | DBUG_ON(msg == NULL); | 859 | DBUG_ON(payload == NULL); |
1924 | 860 | ||
1925 | ret = xpc_send_msg(&part->channels[ch_number], msg, 0, NULL, NULL); | 861 | if (xpc_part_ref(part)) { |
862 | ret = xpc_send_payload(&part->channels[ch_number], flags, | ||
863 | payload, payload_size, 0, NULL, NULL); | ||
864 | xpc_part_deref(part); | ||
865 | } | ||
1926 | 866 | ||
1927 | return ret; | 867 | return ret; |
1928 | } | 868 | } |
1929 | 869 | ||
1930 | /* | 870 | /* |
1931 | * Send a message previously allocated using xpc_initiate_allocate on the | 871 | * Send a message that contains the user's payload on the specified channel |
1932 | * specified channel connected to the specified partition. | 872 | * connected to the specified partition. |
1933 | * | 873 | * |
1934 | * This routine will not wait for the message to be sent. Once this routine | 874 | * NOTE that this routine can sleep waiting for a message entry to become |
1935 | * has returned the message entry allocated via xpc_initiate_allocate() is no | 875 | * available. To not sleep, pass in the XPC_NOWAIT flag. |
1936 | * longer accessable to the caller. | 876 | * |
877 | * This routine will not wait for the message to be sent or received. | ||
1937 | * | 878 | * |
1938 | * Once the remote end of the channel has received the message, the function | 879 | * Once the remote end of the channel has received the message, the function |
1939 | * passed as an argument to xpc_initiate_send_notify() will be called. This | 880 | * passed as an argument to xpc_initiate_send_notify() will be called. This |
@@ -1943,158 +884,51 @@ xpc_initiate_send(short partid, int ch_number, void *payload) | |||
1943 | * | 884 | * |
1944 | * If this routine returns an error, the caller's function will NOT be called. | 885 | * If this routine returns an error, the caller's function will NOT be called. |
1945 | * | 886 | * |
1946 | * This routine, although called by users, does not call xpc_part_ref() to | ||
1947 | * ensure that the partition infrastructure is in place. It relies on the | ||
1948 | * fact that we called xpc_msgqueue_ref() in xpc_allocate_msg(). | ||
1949 | * | ||
1950 | * Arguments: | 887 | * Arguments: |
1951 | * | 888 | * |
1952 | * partid - ID of partition to which the channel is connected. | 889 | * partid - ID of partition to which the channel is connected. |
1953 | * ch_number - channel # to send message on. | 890 | * ch_number - channel # to send message on. |
1954 | * payload - pointer to the payload area allocated via | 891 | * flags - see xp.h for valid flags. |
1955 | * xpc_initiate_allocate(). | 892 | * payload - pointer to the payload which is to be sent. |
893 | * payload_size - size of the payload in bytes. | ||
1956 | * func - function to call with asynchronous notification of message | 894 | * func - function to call with asynchronous notification of message |
1957 | * receipt. THIS FUNCTION MUST BE NON-BLOCKING. | 895 | * receipt. THIS FUNCTION MUST BE NON-BLOCKING. |
1958 | * key - user-defined key to be passed to the function when it's called. | 896 | * key - user-defined key to be passed to the function when it's called. |
1959 | */ | 897 | */ |
1960 | enum xp_retval | 898 | enum xp_retval |
1961 | xpc_initiate_send_notify(short partid, int ch_number, void *payload, | 899 | xpc_initiate_send_notify(short partid, int ch_number, u32 flags, void *payload, |
1962 | xpc_notify_func func, void *key) | 900 | u16 payload_size, xpc_notify_func func, void *key) |
1963 | { | 901 | { |
1964 | struct xpc_partition *part = &xpc_partitions[partid]; | 902 | struct xpc_partition *part = &xpc_partitions[partid]; |
1965 | struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); | 903 | enum xp_retval ret = xpUnknownReason; |
1966 | enum xp_retval ret; | ||
1967 | 904 | ||
1968 | dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg, | 905 | dev_dbg(xpc_chan, "payload=0x%p, partid=%d, channel=%d\n", payload, |
1969 | partid, ch_number); | 906 | partid, ch_number); |
1970 | 907 | ||
1971 | DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); | 908 | DBUG_ON(partid < 0 || partid >= xp_max_npartitions); |
1972 | DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); | 909 | DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); |
1973 | DBUG_ON(msg == NULL); | 910 | DBUG_ON(payload == NULL); |
1974 | DBUG_ON(func == NULL); | 911 | DBUG_ON(func == NULL); |
1975 | 912 | ||
1976 | ret = xpc_send_msg(&part->channels[ch_number], msg, XPC_N_CALL, | 913 | if (xpc_part_ref(part)) { |
1977 | func, key); | 914 | ret = xpc_send_payload(&part->channels[ch_number], flags, |
1978 | return ret; | 915 | payload, payload_size, XPC_N_CALL, func, |
1979 | } | 916 | key); |
1980 | 917 | xpc_part_deref(part); | |
1981 | static struct xpc_msg * | ||
1982 | xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) | ||
1983 | { | ||
1984 | struct xpc_partition *part = &xpc_partitions[ch->partid]; | ||
1985 | struct xpc_msg *remote_msg, *msg; | ||
1986 | u32 msg_index, nmsgs; | ||
1987 | u64 msg_offset; | ||
1988 | enum xp_retval ret; | ||
1989 | |||
1990 | if (mutex_lock_interruptible(&ch->msg_to_pull_mutex) != 0) { | ||
1991 | /* we were interrupted by a signal */ | ||
1992 | return NULL; | ||
1993 | } | ||
1994 | |||
1995 | while (get >= ch->next_msg_to_pull) { | ||
1996 | |||
1997 | /* pull as many messages as are ready and able to be pulled */ | ||
1998 | |||
1999 | msg_index = ch->next_msg_to_pull % ch->remote_nentries; | ||
2000 | |||
2001 | DBUG_ON(ch->next_msg_to_pull >= ch->w_remote_GP.put); | ||
2002 | nmsgs = ch->w_remote_GP.put - ch->next_msg_to_pull; | ||
2003 | if (msg_index + nmsgs > ch->remote_nentries) { | ||
2004 | /* ignore the ones that wrap the msg queue for now */ | ||
2005 | nmsgs = ch->remote_nentries - msg_index; | ||
2006 | } | ||
2007 | |||
2008 | msg_offset = msg_index * ch->msg_size; | ||
2009 | msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); | ||
2010 | remote_msg = (struct xpc_msg *)(ch->remote_msgqueue_pa + | ||
2011 | msg_offset); | ||
2012 | |||
2013 | ret = xpc_pull_remote_cachelines(part, msg, remote_msg, | ||
2014 | nmsgs * ch->msg_size); | ||
2015 | if (ret != xpSuccess) { | ||
2016 | |||
2017 | dev_dbg(xpc_chan, "failed to pull %d msgs starting with" | ||
2018 | " msg %ld from partition %d, channel=%d, " | ||
2019 | "ret=%d\n", nmsgs, ch->next_msg_to_pull, | ||
2020 | ch->partid, ch->number, ret); | ||
2021 | |||
2022 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
2023 | |||
2024 | mutex_unlock(&ch->msg_to_pull_mutex); | ||
2025 | return NULL; | ||
2026 | } | ||
2027 | |||
2028 | ch->next_msg_to_pull += nmsgs; | ||
2029 | } | 918 | } |
2030 | 919 | return ret; | |
2031 | mutex_unlock(&ch->msg_to_pull_mutex); | ||
2032 | |||
2033 | /* return the message we were looking for */ | ||
2034 | msg_offset = (get % ch->remote_nentries) * ch->msg_size; | ||
2035 | msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); | ||
2036 | |||
2037 | return msg; | ||
2038 | } | ||
2039 | |||
2040 | /* | ||
2041 | * Get a message to be delivered. | ||
2042 | */ | ||
2043 | static struct xpc_msg * | ||
2044 | xpc_get_deliverable_msg(struct xpc_channel *ch) | ||
2045 | { | ||
2046 | struct xpc_msg *msg = NULL; | ||
2047 | s64 get; | ||
2048 | |||
2049 | do { | ||
2050 | if (ch->flags & XPC_C_DISCONNECTING) | ||
2051 | break; | ||
2052 | |||
2053 | get = ch->w_local_GP.get; | ||
2054 | rmb(); /* guarantee that .get loads before .put */ | ||
2055 | if (get == ch->w_remote_GP.put) | ||
2056 | break; | ||
2057 | |||
2058 | /* There are messages waiting to be pulled and delivered. | ||
2059 | * We need to try to secure one for ourselves. We'll do this | ||
2060 | * by trying to increment w_local_GP.get and hope that no one | ||
2061 | * else beats us to it. If they do, we'll we'll simply have | ||
2062 | * to try again for the next one. | ||
2063 | */ | ||
2064 | |||
2065 | if (cmpxchg(&ch->w_local_GP.get, get, get + 1) == get) { | ||
2066 | /* we got the entry referenced by get */ | ||
2067 | |||
2068 | dev_dbg(xpc_chan, "w_local_GP.get changed to %ld, " | ||
2069 | "partid=%d, channel=%d\n", get + 1, | ||
2070 | ch->partid, ch->number); | ||
2071 | |||
2072 | /* pull the message from the remote partition */ | ||
2073 | |||
2074 | msg = xpc_pull_remote_msg(ch, get); | ||
2075 | |||
2076 | DBUG_ON(msg != NULL && msg->number != get); | ||
2077 | DBUG_ON(msg != NULL && (msg->flags & XPC_M_DONE)); | ||
2078 | DBUG_ON(msg != NULL && !(msg->flags & XPC_M_READY)); | ||
2079 | |||
2080 | break; | ||
2081 | } | ||
2082 | |||
2083 | } while (1); | ||
2084 | |||
2085 | return msg; | ||
2086 | } | 920 | } |
2087 | 921 | ||
2088 | /* | 922 | /* |
2089 | * Deliver a message to its intended recipient. | 923 | * Deliver a message's payload to its intended recipient. |
2090 | */ | 924 | */ |
2091 | void | 925 | void |
2092 | xpc_deliver_msg(struct xpc_channel *ch) | 926 | xpc_deliver_payload(struct xpc_channel *ch) |
2093 | { | 927 | { |
2094 | struct xpc_msg *msg; | 928 | void *payload; |
2095 | 929 | ||
2096 | msg = xpc_get_deliverable_msg(ch); | 930 | payload = xpc_get_deliverable_payload(ch); |
2097 | if (msg != NULL) { | 931 | if (payload != NULL) { |
2098 | 932 | ||
2099 | /* | 933 | /* |
2100 | * This ref is taken to protect the payload itself from being | 934 | * This ref is taken to protect the payload itself from being |
@@ -2106,18 +940,16 @@ xpc_deliver_msg(struct xpc_channel *ch) | |||
2106 | atomic_inc(&ch->kthreads_active); | 940 | atomic_inc(&ch->kthreads_active); |
2107 | 941 | ||
2108 | if (ch->func != NULL) { | 942 | if (ch->func != NULL) { |
2109 | dev_dbg(xpc_chan, "ch->func() called, msg=0x%p, " | 943 | dev_dbg(xpc_chan, "ch->func() called, payload=0x%p " |
2110 | "msg_number=%ld, partid=%d, channel=%d\n", | 944 | "partid=%d channel=%d\n", payload, ch->partid, |
2111 | (void *)msg, msg->number, ch->partid, | ||
2112 | ch->number); | 945 | ch->number); |
2113 | 946 | ||
2114 | /* deliver the message to its intended recipient */ | 947 | /* deliver the message to its intended recipient */ |
2115 | ch->func(xpMsgReceived, ch->partid, ch->number, | 948 | ch->func(xpMsgReceived, ch->partid, ch->number, payload, |
2116 | &msg->payload, ch->key); | 949 | ch->key); |
2117 | 950 | ||
2118 | dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, " | 951 | dev_dbg(xpc_chan, "ch->func() returned, payload=0x%p " |
2119 | "msg_number=%ld, partid=%d, channel=%d\n", | 952 | "partid=%d channel=%d\n", payload, ch->partid, |
2120 | (void *)msg, msg->number, ch->partid, | ||
2121 | ch->number); | 953 | ch->number); |
2122 | } | 954 | } |
2123 | 955 | ||
@@ -2126,118 +958,31 @@ xpc_deliver_msg(struct xpc_channel *ch) | |||
2126 | } | 958 | } |
2127 | 959 | ||
2128 | /* | 960 | /* |
2129 | * Now we actually acknowledge the messages that have been delivered and ack'd | 961 | * Acknowledge receipt of a delivered message's payload. |
2130 | * by advancing the cached remote message queue's Get value and if requested | ||
2131 | * send an IPI to the message sender's partition. | ||
2132 | */ | ||
2133 | static void | ||
2134 | xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) | ||
2135 | { | ||
2136 | struct xpc_msg *msg; | ||
2137 | s64 get = initial_get + 1; | ||
2138 | int send_IPI = 0; | ||
2139 | |||
2140 | while (1) { | ||
2141 | |||
2142 | while (1) { | ||
2143 | if (get == ch->w_local_GP.get) | ||
2144 | break; | ||
2145 | |||
2146 | msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + | ||
2147 | (get % ch->remote_nentries) * | ||
2148 | ch->msg_size); | ||
2149 | |||
2150 | if (!(msg->flags & XPC_M_DONE)) | ||
2151 | break; | ||
2152 | |||
2153 | msg_flags |= msg->flags; | ||
2154 | get++; | ||
2155 | } | ||
2156 | |||
2157 | if (get == initial_get) { | ||
2158 | /* nothing's changed */ | ||
2159 | break; | ||
2160 | } | ||
2161 | |||
2162 | if (cmpxchg_rel(&ch->local_GP->get, initial_get, get) != | ||
2163 | initial_get) { | ||
2164 | /* someone else beat us to it */ | ||
2165 | DBUG_ON(ch->local_GP->get <= initial_get); | ||
2166 | break; | ||
2167 | } | ||
2168 | |||
2169 | /* we just set the new value of local_GP->get */ | ||
2170 | |||
2171 | dev_dbg(xpc_chan, "local_GP->get changed to %ld, partid=%d, " | ||
2172 | "channel=%d\n", get, ch->partid, ch->number); | ||
2173 | |||
2174 | send_IPI = (msg_flags & XPC_M_INTERRUPT); | ||
2175 | |||
2176 | /* | ||
2177 | * We need to ensure that the message referenced by | ||
2178 | * local_GP->get is not XPC_M_DONE or that local_GP->get | ||
2179 | * equals w_local_GP.get, so we'll go have a look. | ||
2180 | */ | ||
2181 | initial_get = get; | ||
2182 | } | ||
2183 | |||
2184 | if (send_IPI) | ||
2185 | xpc_IPI_send_msgrequest(ch); | ||
2186 | } | ||
2187 | |||
2188 | /* | ||
2189 | * Acknowledge receipt of a delivered message. | ||
2190 | * | ||
2191 | * If a message has XPC_M_INTERRUPT set, send an interrupt to the partition | ||
2192 | * that sent the message. | ||
2193 | * | 962 | * |
2194 | * This function, although called by users, does not call xpc_part_ref() to | 963 | * This function, although called by users, does not call xpc_part_ref() to |
2195 | * ensure that the partition infrastructure is in place. It relies on the | 964 | * ensure that the partition infrastructure is in place. It relies on the |
2196 | * fact that we called xpc_msgqueue_ref() in xpc_deliver_msg(). | 965 | * fact that we called xpc_msgqueue_ref() in xpc_deliver_payload(). |
2197 | * | 966 | * |
2198 | * Arguments: | 967 | * Arguments: |
2199 | * | 968 | * |
2200 | * partid - ID of partition to which the channel is connected. | 969 | * partid - ID of partition to which the channel is connected. |
2201 | * ch_number - channel # message received on. | 970 | * ch_number - channel # message received on. |
2202 | * payload - pointer to the payload area allocated via | 971 | * payload - pointer to the payload area allocated via |
2203 | * xpc_initiate_allocate(). | 972 | * xpc_initiate_send() or xpc_initiate_send_notify(). |
2204 | */ | 973 | */ |
2205 | void | 974 | void |
2206 | xpc_initiate_received(short partid, int ch_number, void *payload) | 975 | xpc_initiate_received(short partid, int ch_number, void *payload) |
2207 | { | 976 | { |
2208 | struct xpc_partition *part = &xpc_partitions[partid]; | 977 | struct xpc_partition *part = &xpc_partitions[partid]; |
2209 | struct xpc_channel *ch; | 978 | struct xpc_channel *ch; |
2210 | struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); | ||
2211 | s64 get, msg_number = msg->number; | ||
2212 | 979 | ||
2213 | DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); | 980 | DBUG_ON(partid < 0 || partid >= xp_max_npartitions); |
2214 | DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); | 981 | DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); |
2215 | 982 | ||
2216 | ch = &part->channels[ch_number]; | 983 | ch = &part->channels[ch_number]; |
984 | xpc_received_payload(ch, payload); | ||
2217 | 985 | ||
2218 | dev_dbg(xpc_chan, "msg=0x%p, msg_number=%ld, partid=%d, channel=%d\n", | 986 | /* the call to xpc_msgqueue_ref() was done by xpc_deliver_payload() */ |
2219 | (void *)msg, msg_number, ch->partid, ch->number); | ||
2220 | |||
2221 | DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->msg_size) != | ||
2222 | msg_number % ch->remote_nentries); | ||
2223 | DBUG_ON(msg->flags & XPC_M_DONE); | ||
2224 | |||
2225 | msg->flags |= XPC_M_DONE; | ||
2226 | |||
2227 | /* | ||
2228 | * The preceding store of msg->flags must occur before the following | ||
2229 | * load of ch->local_GP->get. | ||
2230 | */ | ||
2231 | mb(); | ||
2232 | |||
2233 | /* | ||
2234 | * See if this message is next in line to be acknowledged as having | ||
2235 | * been delivered. | ||
2236 | */ | ||
2237 | get = ch->local_GP->get; | ||
2238 | if (get == msg_number) | ||
2239 | xpc_acknowledge_msgs(ch, get, msg->flags); | ||
2240 | |||
2241 | /* the call to xpc_msgqueue_ref() was done by xpc_deliver_msg() */ | ||
2242 | xpc_msgqueue_deref(ch); | 987 | xpc_msgqueue_deref(ch); |
2243 | } | 988 | } |
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 579b01ff82d4..46325fc84811 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c | |||
@@ -25,37 +25,31 @@ | |||
25 | * | 25 | * |
26 | * Caveats: | 26 | * Caveats: |
27 | * | 27 | * |
28 | * . We currently have no way to determine which nasid an IPI came | 28 | * . Currently on sn2, we have no way to determine which nasid an IRQ |
29 | * from. Thus, xpc_IPI_send() does a remote AMO write followed by | 29 | * came from. Thus, xpc_send_IRQ_sn2() does a remote amo write |
30 | * an IPI. The AMO indicates where data is to be pulled from, so | 30 | * followed by an IPI. The amo indicates where data is to be pulled |
31 | * after the IPI arrives, the remote partition checks the AMO word. | 31 | * from, so after the IPI arrives, the remote partition checks the amo |
32 | * The IPI can actually arrive before the AMO however, so other code | 32 | * word. The IPI can actually arrive before the amo however, so other |
33 | * must periodically check for this case. Also, remote AMO operations | 33 | * code must periodically check for this case. Also, remote amo |
34 | * do not reliably time out. Thus we do a remote PIO read solely to | 34 | * operations do not reliably time out. Thus we do a remote PIO read |
35 | * know whether the remote partition is down and whether we should | 35 | * solely to know whether the remote partition is down and whether we |
36 | * stop sending IPIs to it. This remote PIO read operation is set up | 36 | * should stop sending IPIs to it. This remote PIO read operation is |
37 | * in a special nofault region so SAL knows to ignore (and cleanup) | 37 | * set up in a special nofault region so SAL knows to ignore (and |
38 | * any errors due to the remote AMO write, PIO read, and/or PIO | 38 | * cleanup) any errors due to the remote amo write, PIO read, and/or |
39 | * write operations. | 39 | * PIO write operations. |
40 | * | 40 | * |
41 | * If/when new hardware solves this IPI problem, we should abandon | 41 | * If/when new hardware solves this IPI problem, we should abandon |
42 | * the current approach. | 42 | * the current approach. |
43 | * | 43 | * |
44 | */ | 44 | */ |
45 | 45 | ||
46 | #include <linux/kernel.h> | ||
47 | #include <linux/module.h> | 46 | #include <linux/module.h> |
48 | #include <linux/init.h> | 47 | #include <linux/sysctl.h> |
49 | #include <linux/cache.h> | 48 | #include <linux/device.h> |
50 | #include <linux/interrupt.h> | ||
51 | #include <linux/delay.h> | 49 | #include <linux/delay.h> |
52 | #include <linux/reboot.h> | 50 | #include <linux/reboot.h> |
53 | #include <linux/completion.h> | ||
54 | #include <linux/kdebug.h> | 51 | #include <linux/kdebug.h> |
55 | #include <linux/kthread.h> | 52 | #include <linux/kthread.h> |
56 | #include <linux/uaccess.h> | ||
57 | #include <asm/sn/intr.h> | ||
58 | #include <asm/sn/sn_sal.h> | ||
59 | #include "xpc.h" | 53 | #include "xpc.h" |
60 | 54 | ||
61 | /* define two XPC debug device structures to be used with dev_dbg() et al */ | 55 | /* define two XPC debug device structures to be used with dev_dbg() et al */ |
@@ -89,9 +83,9 @@ static int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_INTERVAL; | |||
89 | static int xpc_hb_check_min_interval = 10; | 83 | static int xpc_hb_check_min_interval = 10; |
90 | static int xpc_hb_check_max_interval = 120; | 84 | static int xpc_hb_check_max_interval = 120; |
91 | 85 | ||
92 | int xpc_disengage_request_timelimit = XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT; | 86 | int xpc_disengage_timelimit = XPC_DISENGAGE_DEFAULT_TIMELIMIT; |
93 | static int xpc_disengage_request_min_timelimit; /* = 0 */ | 87 | static int xpc_disengage_min_timelimit; /* = 0 */ |
94 | static int xpc_disengage_request_max_timelimit = 120; | 88 | static int xpc_disengage_max_timelimit = 120; |
95 | 89 | ||
96 | static ctl_table xpc_sys_xpc_hb_dir[] = { | 90 | static ctl_table xpc_sys_xpc_hb_dir[] = { |
97 | { | 91 | { |
@@ -124,14 +118,14 @@ static ctl_table xpc_sys_xpc_dir[] = { | |||
124 | .child = xpc_sys_xpc_hb_dir}, | 118 | .child = xpc_sys_xpc_hb_dir}, |
125 | { | 119 | { |
126 | .ctl_name = CTL_UNNUMBERED, | 120 | .ctl_name = CTL_UNNUMBERED, |
127 | .procname = "disengage_request_timelimit", | 121 | .procname = "disengage_timelimit", |
128 | .data = &xpc_disengage_request_timelimit, | 122 | .data = &xpc_disengage_timelimit, |
129 | .maxlen = sizeof(int), | 123 | .maxlen = sizeof(int), |
130 | .mode = 0644, | 124 | .mode = 0644, |
131 | .proc_handler = &proc_dointvec_minmax, | 125 | .proc_handler = &proc_dointvec_minmax, |
132 | .strategy = &sysctl_intvec, | 126 | .strategy = &sysctl_intvec, |
133 | .extra1 = &xpc_disengage_request_min_timelimit, | 127 | .extra1 = &xpc_disengage_min_timelimit, |
134 | .extra2 = &xpc_disengage_request_max_timelimit}, | 128 | .extra2 = &xpc_disengage_max_timelimit}, |
135 | {} | 129 | {} |
136 | }; | 130 | }; |
137 | static ctl_table xpc_sys_dir[] = { | 131 | static ctl_table xpc_sys_dir[] = { |
@@ -144,16 +138,19 @@ static ctl_table xpc_sys_dir[] = { | |||
144 | }; | 138 | }; |
145 | static struct ctl_table_header *xpc_sysctl; | 139 | static struct ctl_table_header *xpc_sysctl; |
146 | 140 | ||
147 | /* non-zero if any remote partition disengage request was timed out */ | 141 | /* non-zero if any remote partition disengage was timed out */ |
148 | int xpc_disengage_request_timedout; | 142 | int xpc_disengage_timedout; |
149 | 143 | ||
150 | /* #of IRQs received */ | 144 | /* #of activate IRQs received and not yet processed */ |
151 | static atomic_t xpc_act_IRQ_rcvd; | 145 | int xpc_activate_IRQ_rcvd; |
146 | DEFINE_SPINLOCK(xpc_activate_IRQ_rcvd_lock); | ||
152 | 147 | ||
153 | /* IRQ handler notifies this wait queue on receipt of an IRQ */ | 148 | /* IRQ handler notifies this wait queue on receipt of an IRQ */ |
154 | static DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq); | 149 | DECLARE_WAIT_QUEUE_HEAD(xpc_activate_IRQ_wq); |
155 | 150 | ||
156 | static unsigned long xpc_hb_check_timeout; | 151 | static unsigned long xpc_hb_check_timeout; |
152 | static struct timer_list xpc_hb_timer; | ||
153 | void *xpc_heartbeating_to_mask; | ||
157 | 154 | ||
158 | /* notification that the xpc_hb_checker thread has exited */ | 155 | /* notification that the xpc_hb_checker thread has exited */ |
159 | static DECLARE_COMPLETION(xpc_hb_checker_exited); | 156 | static DECLARE_COMPLETION(xpc_hb_checker_exited); |
@@ -161,8 +158,6 @@ static DECLARE_COMPLETION(xpc_hb_checker_exited); | |||
161 | /* notification that the xpc_discovery thread has exited */ | 158 | /* notification that the xpc_discovery thread has exited */ |
162 | static DECLARE_COMPLETION(xpc_discovery_exited); | 159 | static DECLARE_COMPLETION(xpc_discovery_exited); |
163 | 160 | ||
164 | static struct timer_list xpc_hb_timer; | ||
165 | |||
166 | static void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *); | 161 | static void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *); |
167 | 162 | ||
168 | static int xpc_system_reboot(struct notifier_block *, unsigned long, void *); | 163 | static int xpc_system_reboot(struct notifier_block *, unsigned long, void *); |
@@ -175,31 +170,76 @@ static struct notifier_block xpc_die_notifier = { | |||
175 | .notifier_call = xpc_system_die, | 170 | .notifier_call = xpc_system_die, |
176 | }; | 171 | }; |
177 | 172 | ||
173 | int (*xpc_setup_partitions_sn) (void); | ||
174 | enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie, | ||
175 | unsigned long *rp_pa, | ||
176 | size_t *len); | ||
177 | int (*xpc_setup_rsvd_page_sn) (struct xpc_rsvd_page *rp); | ||
178 | void (*xpc_heartbeat_init) (void); | ||
179 | void (*xpc_heartbeat_exit) (void); | ||
180 | void (*xpc_increment_heartbeat) (void); | ||
181 | void (*xpc_offline_heartbeat) (void); | ||
182 | void (*xpc_online_heartbeat) (void); | ||
183 | enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *part); | ||
184 | |||
185 | enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); | ||
186 | void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch); | ||
187 | u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *part); | ||
188 | enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *ch); | ||
189 | void (*xpc_teardown_msg_structures) (struct xpc_channel *ch); | ||
190 | void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number); | ||
191 | int (*xpc_n_of_deliverable_payloads) (struct xpc_channel *ch); | ||
192 | void *(*xpc_get_deliverable_payload) (struct xpc_channel *ch); | ||
193 | |||
194 | void (*xpc_request_partition_activation) (struct xpc_rsvd_page *remote_rp, | ||
195 | unsigned long remote_rp_pa, | ||
196 | int nasid); | ||
197 | void (*xpc_request_partition_reactivation) (struct xpc_partition *part); | ||
198 | void (*xpc_request_partition_deactivation) (struct xpc_partition *part); | ||
199 | void (*xpc_cancel_partition_deactivation_request) (struct xpc_partition *part); | ||
200 | |||
201 | void (*xpc_process_activate_IRQ_rcvd) (void); | ||
202 | enum xp_retval (*xpc_setup_ch_structures_sn) (struct xpc_partition *part); | ||
203 | void (*xpc_teardown_ch_structures_sn) (struct xpc_partition *part); | ||
204 | |||
205 | void (*xpc_indicate_partition_engaged) (struct xpc_partition *part); | ||
206 | int (*xpc_partition_engaged) (short partid); | ||
207 | int (*xpc_any_partition_engaged) (void); | ||
208 | void (*xpc_indicate_partition_disengaged) (struct xpc_partition *part); | ||
209 | void (*xpc_assume_partition_disengaged) (short partid); | ||
210 | |||
211 | void (*xpc_send_chctl_closerequest) (struct xpc_channel *ch, | ||
212 | unsigned long *irq_flags); | ||
213 | void (*xpc_send_chctl_closereply) (struct xpc_channel *ch, | ||
214 | unsigned long *irq_flags); | ||
215 | void (*xpc_send_chctl_openrequest) (struct xpc_channel *ch, | ||
216 | unsigned long *irq_flags); | ||
217 | void (*xpc_send_chctl_openreply) (struct xpc_channel *ch, | ||
218 | unsigned long *irq_flags); | ||
219 | |||
220 | void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch, | ||
221 | unsigned long msgqueue_pa); | ||
222 | |||
223 | enum xp_retval (*xpc_send_payload) (struct xpc_channel *ch, u32 flags, | ||
224 | void *payload, u16 payload_size, | ||
225 | u8 notify_type, xpc_notify_func func, | ||
226 | void *key); | ||
227 | void (*xpc_received_payload) (struct xpc_channel *ch, void *payload); | ||
228 | |||
178 | /* | 229 | /* |
179 | * Timer function to enforce the timelimit on the partition disengage request. | 230 | * Timer function to enforce the timelimit on the partition disengage. |
180 | */ | 231 | */ |
181 | static void | 232 | static void |
182 | xpc_timeout_partition_disengage_request(unsigned long data) | 233 | xpc_timeout_partition_disengage(unsigned long data) |
183 | { | 234 | { |
184 | struct xpc_partition *part = (struct xpc_partition *)data; | 235 | struct xpc_partition *part = (struct xpc_partition *)data; |
185 | 236 | ||
186 | DBUG_ON(time_before(jiffies, part->disengage_request_timeout)); | 237 | DBUG_ON(time_is_after_jiffies(part->disengage_timeout)); |
187 | 238 | ||
188 | (void)xpc_partition_disengaged(part); | 239 | (void)xpc_partition_disengaged(part); |
189 | 240 | ||
190 | DBUG_ON(part->disengage_request_timeout != 0); | 241 | DBUG_ON(part->disengage_timeout != 0); |
191 | DBUG_ON(xpc_partition_engaged(1UL << XPC_PARTID(part)) != 0); | 242 | DBUG_ON(xpc_partition_engaged(XPC_PARTID(part))); |
192 | } | ||
193 | |||
194 | /* | ||
195 | * Notify the heartbeat check thread that an IRQ has been received. | ||
196 | */ | ||
197 | static irqreturn_t | ||
198 | xpc_act_IRQ_handler(int irq, void *dev_id) | ||
199 | { | ||
200 | atomic_inc(&xpc_act_IRQ_rcvd); | ||
201 | wake_up_interruptible(&xpc_act_IRQ_wq); | ||
202 | return IRQ_HANDLED; | ||
203 | } | 243 | } |
204 | 244 | ||
205 | /* | 245 | /* |
@@ -210,15 +250,63 @@ xpc_act_IRQ_handler(int irq, void *dev_id) | |||
210 | static void | 250 | static void |
211 | xpc_hb_beater(unsigned long dummy) | 251 | xpc_hb_beater(unsigned long dummy) |
212 | { | 252 | { |
213 | xpc_vars->heartbeat++; | 253 | xpc_increment_heartbeat(); |
214 | 254 | ||
215 | if (time_after_eq(jiffies, xpc_hb_check_timeout)) | 255 | if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) |
216 | wake_up_interruptible(&xpc_act_IRQ_wq); | 256 | wake_up_interruptible(&xpc_activate_IRQ_wq); |
217 | 257 | ||
218 | xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ); | 258 | xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ); |
219 | add_timer(&xpc_hb_timer); | 259 | add_timer(&xpc_hb_timer); |
220 | } | 260 | } |
221 | 261 | ||
262 | static void | ||
263 | xpc_start_hb_beater(void) | ||
264 | { | ||
265 | xpc_heartbeat_init(); | ||
266 | init_timer(&xpc_hb_timer); | ||
267 | xpc_hb_timer.function = xpc_hb_beater; | ||
268 | xpc_hb_beater(0); | ||
269 | } | ||
270 | |||
271 | static void | ||
272 | xpc_stop_hb_beater(void) | ||
273 | { | ||
274 | del_timer_sync(&xpc_hb_timer); | ||
275 | xpc_heartbeat_exit(); | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * At periodic intervals, scan through all active partitions and ensure | ||
280 | * their heartbeat is still active. If not, the partition is deactivated. | ||
281 | */ | ||
282 | static void | ||
283 | xpc_check_remote_hb(void) | ||
284 | { | ||
285 | struct xpc_partition *part; | ||
286 | short partid; | ||
287 | enum xp_retval ret; | ||
288 | |||
289 | for (partid = 0; partid < xp_max_npartitions; partid++) { | ||
290 | |||
291 | if (xpc_exiting) | ||
292 | break; | ||
293 | |||
294 | if (partid == xp_partition_id) | ||
295 | continue; | ||
296 | |||
297 | part = &xpc_partitions[partid]; | ||
298 | |||
299 | if (part->act_state == XPC_P_AS_INACTIVE || | ||
300 | part->act_state == XPC_P_AS_DEACTIVATING) { | ||
301 | continue; | ||
302 | } | ||
303 | |||
304 | ret = xpc_get_remote_heartbeat(part); | ||
305 | if (ret != xpSuccess) | ||
306 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
307 | } | ||
308 | } | ||
309 | |||
222 | /* | 310 | /* |
223 | * This thread is responsible for nearly all of the partition | 311 | * This thread is responsible for nearly all of the partition |
224 | * activation/deactivation. | 312 | * activation/deactivation. |
@@ -226,67 +314,57 @@ xpc_hb_beater(unsigned long dummy) | |||
226 | static int | 314 | static int |
227 | xpc_hb_checker(void *ignore) | 315 | xpc_hb_checker(void *ignore) |
228 | { | 316 | { |
229 | int last_IRQ_count = 0; | ||
230 | int new_IRQ_count; | ||
231 | int force_IRQ = 0; | 317 | int force_IRQ = 0; |
232 | cpumask_of_cpu_ptr(cpumask, XPC_HB_CHECK_CPU); | ||
233 | 318 | ||
234 | /* this thread was marked active by xpc_hb_init() */ | 319 | /* this thread was marked active by xpc_hb_init() */ |
235 | 320 | ||
236 | set_cpus_allowed_ptr(current, cpumask); | 321 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(XPC_HB_CHECK_CPU)); |
237 | 322 | ||
238 | /* set our heartbeating to other partitions into motion */ | 323 | /* set our heartbeating to other partitions into motion */ |
239 | xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); | 324 | xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); |
240 | xpc_hb_beater(0); | 325 | xpc_start_hb_beater(); |
241 | 326 | ||
242 | while (!xpc_exiting) { | 327 | while (!xpc_exiting) { |
243 | 328 | ||
244 | dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " | 329 | dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " |
245 | "been received\n", | 330 | "been received\n", |
246 | (int)(xpc_hb_check_timeout - jiffies), | 331 | (int)(xpc_hb_check_timeout - jiffies), |
247 | atomic_read(&xpc_act_IRQ_rcvd) - last_IRQ_count); | 332 | xpc_activate_IRQ_rcvd); |
248 | 333 | ||
249 | /* checking of remote heartbeats is skewed by IRQ handling */ | 334 | /* checking of remote heartbeats is skewed by IRQ handling */ |
250 | if (time_after_eq(jiffies, xpc_hb_check_timeout)) { | 335 | if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) { |
336 | xpc_hb_check_timeout = jiffies + | ||
337 | (xpc_hb_check_interval * HZ); | ||
338 | |||
251 | dev_dbg(xpc_part, "checking remote heartbeats\n"); | 339 | dev_dbg(xpc_part, "checking remote heartbeats\n"); |
252 | xpc_check_remote_hb(); | 340 | xpc_check_remote_hb(); |
253 | 341 | ||
254 | /* | 342 | /* |
255 | * We need to periodically recheck to ensure no | 343 | * On sn2 we need to periodically recheck to ensure no |
256 | * IPI/AMO pairs have been missed. That check | 344 | * IRQ/amo pairs have been missed. |
257 | * must always reset xpc_hb_check_timeout. | ||
258 | */ | 345 | */ |
259 | force_IRQ = 1; | 346 | if (is_shub()) |
347 | force_IRQ = 1; | ||
260 | } | 348 | } |
261 | 349 | ||
262 | /* check for outstanding IRQs */ | 350 | /* check for outstanding IRQs */ |
263 | new_IRQ_count = atomic_read(&xpc_act_IRQ_rcvd); | 351 | if (xpc_activate_IRQ_rcvd > 0 || force_IRQ != 0) { |
264 | if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) { | ||
265 | force_IRQ = 0; | 352 | force_IRQ = 0; |
266 | 353 | dev_dbg(xpc_part, "processing activate IRQs " | |
267 | dev_dbg(xpc_part, "found an IRQ to process; will be " | 354 | "received\n"); |
268 | "resetting xpc_hb_check_timeout\n"); | 355 | xpc_process_activate_IRQ_rcvd(); |
269 | |||
270 | last_IRQ_count += xpc_identify_act_IRQ_sender(); | ||
271 | if (last_IRQ_count < new_IRQ_count) { | ||
272 | /* retry once to help avoid missing AMO */ | ||
273 | (void)xpc_identify_act_IRQ_sender(); | ||
274 | } | ||
275 | last_IRQ_count = new_IRQ_count; | ||
276 | |||
277 | xpc_hb_check_timeout = jiffies + | ||
278 | (xpc_hb_check_interval * HZ); | ||
279 | } | 356 | } |
280 | 357 | ||
281 | /* wait for IRQ or timeout */ | 358 | /* wait for IRQ or timeout */ |
282 | (void)wait_event_interruptible(xpc_act_IRQ_wq, | 359 | (void)wait_event_interruptible(xpc_activate_IRQ_wq, |
283 | (last_IRQ_count < | 360 | (time_is_before_eq_jiffies( |
284 | atomic_read(&xpc_act_IRQ_rcvd) | 361 | xpc_hb_check_timeout) || |
285 | || time_after_eq(jiffies, | 362 | xpc_activate_IRQ_rcvd > 0 || |
286 | xpc_hb_check_timeout) || | ||
287 | xpc_exiting)); | 363 | xpc_exiting)); |
288 | } | 364 | } |
289 | 365 | ||
366 | xpc_stop_hb_beater(); | ||
367 | |||
290 | dev_dbg(xpc_part, "heartbeat checker is exiting\n"); | 368 | dev_dbg(xpc_part, "heartbeat checker is exiting\n"); |
291 | 369 | ||
292 | /* mark this thread as having exited */ | 370 | /* mark this thread as having exited */ |
@@ -312,37 +390,8 @@ xpc_initiate_discovery(void *ignore) | |||
312 | } | 390 | } |
313 | 391 | ||
314 | /* | 392 | /* |
315 | * Establish first contact with the remote partititon. This involves pulling | ||
316 | * the XPC per partition variables from the remote partition and waiting for | ||
317 | * the remote partition to pull ours. | ||
318 | */ | ||
319 | static enum xp_retval | ||
320 | xpc_make_first_contact(struct xpc_partition *part) | ||
321 | { | ||
322 | enum xp_retval ret; | ||
323 | |||
324 | while ((ret = xpc_pull_remote_vars_part(part)) != xpSuccess) { | ||
325 | if (ret != xpRetry) { | ||
326 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | dev_dbg(xpc_chan, "waiting to make first contact with " | ||
331 | "partition %d\n", XPC_PARTID(part)); | ||
332 | |||
333 | /* wait a 1/4 of a second or so */ | ||
334 | (void)msleep_interruptible(250); | ||
335 | |||
336 | if (part->act_state == XPC_P_DEACTIVATING) | ||
337 | return part->reason; | ||
338 | } | ||
339 | |||
340 | return xpc_mark_partition_active(part); | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * The first kthread assigned to a newly activated partition is the one | 393 | * The first kthread assigned to a newly activated partition is the one |
345 | * created by XPC HB with which it calls xpc_partition_up(). XPC hangs on to | 394 | * created by XPC HB with which it calls xpc_activating(). XPC hangs on to |
346 | * that kthread until the partition is brought down, at which time that kthread | 395 | * that kthread until the partition is brought down, at which time that kthread |
347 | * returns back to XPC HB. (The return of that kthread will signify to XPC HB | 396 | * returns back to XPC HB. (The return of that kthread will signify to XPC HB |
348 | * that XPC has dismantled all communication infrastructure for the associated | 397 | * that XPC has dismantled all communication infrastructure for the associated |
@@ -355,11 +404,11 @@ xpc_make_first_contact(struct xpc_partition *part) | |||
355 | static void | 404 | static void |
356 | xpc_channel_mgr(struct xpc_partition *part) | 405 | xpc_channel_mgr(struct xpc_partition *part) |
357 | { | 406 | { |
358 | while (part->act_state != XPC_P_DEACTIVATING || | 407 | while (part->act_state != XPC_P_AS_DEACTIVATING || |
359 | atomic_read(&part->nchannels_active) > 0 || | 408 | atomic_read(&part->nchannels_active) > 0 || |
360 | !xpc_partition_disengaged(part)) { | 409 | !xpc_partition_disengaged(part)) { |
361 | 410 | ||
362 | xpc_process_channel_activity(part); | 411 | xpc_process_sent_chctl_flags(part); |
363 | 412 | ||
364 | /* | 413 | /* |
365 | * Wait until we've been requested to activate kthreads or | 414 | * Wait until we've been requested to activate kthreads or |
@@ -377,8 +426,8 @@ xpc_channel_mgr(struct xpc_partition *part) | |||
377 | atomic_dec(&part->channel_mgr_requests); | 426 | atomic_dec(&part->channel_mgr_requests); |
378 | (void)wait_event_interruptible(part->channel_mgr_wq, | 427 | (void)wait_event_interruptible(part->channel_mgr_wq, |
379 | (atomic_read(&part->channel_mgr_requests) > 0 || | 428 | (atomic_read(&part->channel_mgr_requests) > 0 || |
380 | part->local_IPI_amo != 0 || | 429 | part->chctl.all_flags != 0 || |
381 | (part->act_state == XPC_P_DEACTIVATING && | 430 | (part->act_state == XPC_P_AS_DEACTIVATING && |
382 | atomic_read(&part->nchannels_active) == 0 && | 431 | atomic_read(&part->nchannels_active) == 0 && |
383 | xpc_partition_disengaged(part)))); | 432 | xpc_partition_disengaged(part)))); |
384 | atomic_set(&part->channel_mgr_requests, 1); | 433 | atomic_set(&part->channel_mgr_requests, 1); |
@@ -386,47 +435,163 @@ xpc_channel_mgr(struct xpc_partition *part) | |||
386 | } | 435 | } |
387 | 436 | ||
388 | /* | 437 | /* |
389 | * When XPC HB determines that a partition has come up, it will create a new | 438 | * Guarantee that the kzalloc'd memory is cacheline aligned. |
390 | * kthread and that kthread will call this function to attempt to set up the | ||
391 | * basic infrastructure used for Cross Partition Communication with the newly | ||
392 | * upped partition. | ||
393 | * | ||
394 | * The kthread that was created by XPC HB and which setup the XPC | ||
395 | * infrastructure will remain assigned to the partition until the partition | ||
396 | * goes down. At which time the kthread will teardown the XPC infrastructure | ||
397 | * and then exit. | ||
398 | * | ||
399 | * XPC HB will put the remote partition's XPC per partition specific variables | ||
400 | * physical address into xpc_partitions[partid].remote_vars_part_pa prior to | ||
401 | * calling xpc_partition_up(). | ||
402 | */ | 439 | */ |
403 | static void | 440 | void * |
404 | xpc_partition_up(struct xpc_partition *part) | 441 | xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) |
442 | { | ||
443 | /* see if kzalloc will give us cachline aligned memory by default */ | ||
444 | *base = kzalloc(size, flags); | ||
445 | if (*base == NULL) | ||
446 | return NULL; | ||
447 | |||
448 | if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) | ||
449 | return *base; | ||
450 | |||
451 | kfree(*base); | ||
452 | |||
453 | /* nope, we'll have to do it ourselves */ | ||
454 | *base = kzalloc(size + L1_CACHE_BYTES, flags); | ||
455 | if (*base == NULL) | ||
456 | return NULL; | ||
457 | |||
458 | return (void *)L1_CACHE_ALIGN((u64)*base); | ||
459 | } | ||
460 | |||
461 | /* | ||
462 | * Setup the channel structures necessary to support XPartition Communication | ||
463 | * between the specified remote partition and the local one. | ||
464 | */ | ||
465 | static enum xp_retval | ||
466 | xpc_setup_ch_structures(struct xpc_partition *part) | ||
405 | { | 467 | { |
468 | enum xp_retval ret; | ||
469 | int ch_number; | ||
470 | struct xpc_channel *ch; | ||
471 | short partid = XPC_PARTID(part); | ||
472 | |||
473 | /* | ||
474 | * Allocate all of the channel structures as a contiguous chunk of | ||
475 | * memory. | ||
476 | */ | ||
406 | DBUG_ON(part->channels != NULL); | 477 | DBUG_ON(part->channels != NULL); |
478 | part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS, | ||
479 | GFP_KERNEL); | ||
480 | if (part->channels == NULL) { | ||
481 | dev_err(xpc_chan, "can't get memory for channels\n"); | ||
482 | return xpNoMemory; | ||
483 | } | ||
407 | 484 | ||
408 | dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part)); | 485 | /* allocate the remote open and close args */ |
409 | 486 | ||
410 | if (xpc_setup_infrastructure(part) != xpSuccess) | 487 | part->remote_openclose_args = |
411 | return; | 488 | xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, |
489 | GFP_KERNEL, &part-> | ||
490 | remote_openclose_args_base); | ||
491 | if (part->remote_openclose_args == NULL) { | ||
492 | dev_err(xpc_chan, "can't get memory for remote connect args\n"); | ||
493 | ret = xpNoMemory; | ||
494 | goto out_1; | ||
495 | } | ||
496 | |||
497 | part->chctl.all_flags = 0; | ||
498 | spin_lock_init(&part->chctl_lock); | ||
499 | |||
500 | atomic_set(&part->channel_mgr_requests, 1); | ||
501 | init_waitqueue_head(&part->channel_mgr_wq); | ||
502 | |||
503 | part->nchannels = XPC_MAX_NCHANNELS; | ||
504 | |||
505 | atomic_set(&part->nchannels_active, 0); | ||
506 | atomic_set(&part->nchannels_engaged, 0); | ||
507 | |||
508 | for (ch_number = 0; ch_number < part->nchannels; ch_number++) { | ||
509 | ch = &part->channels[ch_number]; | ||
510 | |||
511 | ch->partid = partid; | ||
512 | ch->number = ch_number; | ||
513 | ch->flags = XPC_C_DISCONNECTED; | ||
514 | |||
515 | atomic_set(&ch->kthreads_assigned, 0); | ||
516 | atomic_set(&ch->kthreads_idle, 0); | ||
517 | atomic_set(&ch->kthreads_active, 0); | ||
518 | |||
519 | atomic_set(&ch->references, 0); | ||
520 | atomic_set(&ch->n_to_notify, 0); | ||
521 | |||
522 | spin_lock_init(&ch->lock); | ||
523 | init_completion(&ch->wdisconnect_wait); | ||
524 | |||
525 | atomic_set(&ch->n_on_msg_allocate_wq, 0); | ||
526 | init_waitqueue_head(&ch->msg_allocate_wq); | ||
527 | init_waitqueue_head(&ch->idle_wq); | ||
528 | } | ||
529 | |||
530 | ret = xpc_setup_ch_structures_sn(part); | ||
531 | if (ret != xpSuccess) | ||
532 | goto out_2; | ||
533 | |||
534 | /* | ||
535 | * With the setting of the partition setup_state to XPC_P_SS_SETUP, | ||
536 | * we're declaring that this partition is ready to go. | ||
537 | */ | ||
538 | part->setup_state = XPC_P_SS_SETUP; | ||
539 | |||
540 | return xpSuccess; | ||
541 | |||
542 | /* setup of ch structures failed */ | ||
543 | out_2: | ||
544 | kfree(part->remote_openclose_args_base); | ||
545 | part->remote_openclose_args = NULL; | ||
546 | out_1: | ||
547 | kfree(part->channels); | ||
548 | part->channels = NULL; | ||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * Teardown the channel structures necessary to support XPartition Communication | ||
554 | * between the specified remote partition and the local one. | ||
555 | */ | ||
556 | static void | ||
557 | xpc_teardown_ch_structures(struct xpc_partition *part) | ||
558 | { | ||
559 | DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); | ||
560 | DBUG_ON(atomic_read(&part->nchannels_active) != 0); | ||
412 | 561 | ||
413 | /* | 562 | /* |
414 | * The kthread that XPC HB called us with will become the | 563 | * Make this partition inaccessible to local processes by marking it |
415 | * channel manager for this partition. It will not return | 564 | * as no longer setup. Then wait before proceeding with the teardown |
416 | * back to XPC HB until the partition's XPC infrastructure | 565 | * until all existing references cease. |
417 | * has been dismantled. | ||
418 | */ | 566 | */ |
567 | DBUG_ON(part->setup_state != XPC_P_SS_SETUP); | ||
568 | part->setup_state = XPC_P_SS_WTEARDOWN; | ||
419 | 569 | ||
420 | (void)xpc_part_ref(part); /* this will always succeed */ | 570 | wait_event(part->teardown_wq, (atomic_read(&part->references) == 0)); |
421 | 571 | ||
422 | if (xpc_make_first_contact(part) == xpSuccess) | 572 | /* now we can begin tearing down the infrastructure */ |
423 | xpc_channel_mgr(part); | ||
424 | 573 | ||
425 | xpc_part_deref(part); | 574 | xpc_teardown_ch_structures_sn(part); |
426 | 575 | ||
427 | xpc_teardown_infrastructure(part); | 576 | kfree(part->remote_openclose_args_base); |
577 | part->remote_openclose_args = NULL; | ||
578 | kfree(part->channels); | ||
579 | part->channels = NULL; | ||
580 | |||
581 | part->setup_state = XPC_P_SS_TORNDOWN; | ||
428 | } | 582 | } |
429 | 583 | ||
584 | /* | ||
585 | * When XPC HB determines that a partition has come up, it will create a new | ||
586 | * kthread and that kthread will call this function to attempt to set up the | ||
587 | * basic infrastructure used for Cross Partition Communication with the newly | ||
588 | * upped partition. | ||
589 | * | ||
590 | * The kthread that was created by XPC HB and which setup the XPC | ||
591 | * infrastructure will remain assigned to the partition becoming the channel | ||
592 | * manager for that partition until the partition is deactivating, at which | ||
593 | * time the kthread will teardown the XPC infrastructure and then exit. | ||
594 | */ | ||
430 | static int | 595 | static int |
431 | xpc_activating(void *__partid) | 596 | xpc_activating(void *__partid) |
432 | { | 597 | { |
@@ -434,64 +599,47 @@ xpc_activating(void *__partid) | |||
434 | struct xpc_partition *part = &xpc_partitions[partid]; | 599 | struct xpc_partition *part = &xpc_partitions[partid]; |
435 | unsigned long irq_flags; | 600 | unsigned long irq_flags; |
436 | 601 | ||
437 | DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); | 602 | DBUG_ON(partid < 0 || partid >= xp_max_npartitions); |
438 | 603 | ||
439 | spin_lock_irqsave(&part->act_lock, irq_flags); | 604 | spin_lock_irqsave(&part->act_lock, irq_flags); |
440 | 605 | ||
441 | if (part->act_state == XPC_P_DEACTIVATING) { | 606 | if (part->act_state == XPC_P_AS_DEACTIVATING) { |
442 | part->act_state = XPC_P_INACTIVE; | 607 | part->act_state = XPC_P_AS_INACTIVE; |
443 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | 608 | spin_unlock_irqrestore(&part->act_lock, irq_flags); |
444 | part->remote_rp_pa = 0; | 609 | part->remote_rp_pa = 0; |
445 | return 0; | 610 | return 0; |
446 | } | 611 | } |
447 | 612 | ||
448 | /* indicate the thread is activating */ | 613 | /* indicate the thread is activating */ |
449 | DBUG_ON(part->act_state != XPC_P_ACTIVATION_REQ); | 614 | DBUG_ON(part->act_state != XPC_P_AS_ACTIVATION_REQ); |
450 | part->act_state = XPC_P_ACTIVATING; | 615 | part->act_state = XPC_P_AS_ACTIVATING; |
451 | 616 | ||
452 | XPC_SET_REASON(part, 0, 0); | 617 | XPC_SET_REASON(part, 0, 0); |
453 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | 618 | spin_unlock_irqrestore(&part->act_lock, irq_flags); |
454 | 619 | ||
455 | dev_dbg(xpc_part, "bringing partition %d up\n", partid); | 620 | dev_dbg(xpc_part, "activating partition %d\n", partid); |
456 | 621 | ||
457 | /* | 622 | xpc_allow_hb(partid); |
458 | * Register the remote partition's AMOs with SAL so it can handle | ||
459 | * and cleanup errors within that address range should the remote | ||
460 | * partition go down. We don't unregister this range because it is | ||
461 | * difficult to tell when outstanding writes to the remote partition | ||
462 | * are finished and thus when it is safe to unregister. This should | ||
463 | * not result in wasted space in the SAL xp_addr_region table because | ||
464 | * we should get the same page for remote_amos_page_pa after module | ||
465 | * reloads and system reboots. | ||
466 | */ | ||
467 | if (sn_register_xp_addr_region(part->remote_amos_page_pa, | ||
468 | PAGE_SIZE, 1) < 0) { | ||
469 | dev_warn(xpc_part, "xpc_partition_up(%d) failed to register " | ||
470 | "xp_addr region\n", partid); | ||
471 | 623 | ||
472 | spin_lock_irqsave(&part->act_lock, irq_flags); | 624 | if (xpc_setup_ch_structures(part) == xpSuccess) { |
473 | part->act_state = XPC_P_INACTIVE; | 625 | (void)xpc_part_ref(part); /* this will always succeed */ |
474 | XPC_SET_REASON(part, xpPhysAddrRegFailed, __LINE__); | ||
475 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | ||
476 | part->remote_rp_pa = 0; | ||
477 | return 0; | ||
478 | } | ||
479 | 626 | ||
480 | xpc_allow_hb(partid, xpc_vars); | 627 | if (xpc_make_first_contact(part) == xpSuccess) { |
481 | xpc_IPI_send_activated(part); | 628 | xpc_mark_partition_active(part); |
629 | xpc_channel_mgr(part); | ||
630 | /* won't return until partition is deactivating */ | ||
631 | } | ||
482 | 632 | ||
483 | /* | 633 | xpc_part_deref(part); |
484 | * xpc_partition_up() holds this thread and marks this partition as | 634 | xpc_teardown_ch_structures(part); |
485 | * XPC_P_ACTIVE by calling xpc_hb_mark_active(). | 635 | } |
486 | */ | ||
487 | (void)xpc_partition_up(part); | ||
488 | 636 | ||
489 | xpc_disallow_hb(partid, xpc_vars); | 637 | xpc_disallow_hb(partid); |
490 | xpc_mark_partition_inactive(part); | 638 | xpc_mark_partition_inactive(part); |
491 | 639 | ||
492 | if (part->reason == xpReactivating) { | 640 | if (part->reason == xpReactivating) { |
493 | /* interrupting ourselves results in activating partition */ | 641 | /* interrupting ourselves results in activating partition */ |
494 | xpc_IPI_send_reactivate(part); | 642 | xpc_request_partition_reactivation(part); |
495 | } | 643 | } |
496 | 644 | ||
497 | return 0; | 645 | return 0; |
@@ -506,9 +654,9 @@ xpc_activate_partition(struct xpc_partition *part) | |||
506 | 654 | ||
507 | spin_lock_irqsave(&part->act_lock, irq_flags); | 655 | spin_lock_irqsave(&part->act_lock, irq_flags); |
508 | 656 | ||
509 | DBUG_ON(part->act_state != XPC_P_INACTIVE); | 657 | DBUG_ON(part->act_state != XPC_P_AS_INACTIVE); |
510 | 658 | ||
511 | part->act_state = XPC_P_ACTIVATION_REQ; | 659 | part->act_state = XPC_P_AS_ACTIVATION_REQ; |
512 | XPC_SET_REASON(part, xpCloneKThread, __LINE__); | 660 | XPC_SET_REASON(part, xpCloneKThread, __LINE__); |
513 | 661 | ||
514 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | 662 | spin_unlock_irqrestore(&part->act_lock, irq_flags); |
@@ -517,62 +665,12 @@ xpc_activate_partition(struct xpc_partition *part) | |||
517 | partid); | 665 | partid); |
518 | if (IS_ERR(kthread)) { | 666 | if (IS_ERR(kthread)) { |
519 | spin_lock_irqsave(&part->act_lock, irq_flags); | 667 | spin_lock_irqsave(&part->act_lock, irq_flags); |
520 | part->act_state = XPC_P_INACTIVE; | 668 | part->act_state = XPC_P_AS_INACTIVE; |
521 | XPC_SET_REASON(part, xpCloneKThreadFailed, __LINE__); | 669 | XPC_SET_REASON(part, xpCloneKThreadFailed, __LINE__); |
522 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | 670 | spin_unlock_irqrestore(&part->act_lock, irq_flags); |
523 | } | 671 | } |
524 | } | 672 | } |
525 | 673 | ||
526 | /* | ||
527 | * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified | ||
528 | * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more | ||
529 | * than one partition, we use an AMO_t structure per partition to indicate | ||
530 | * whether a partition has sent an IPI or not. If it has, then wake up the | ||
531 | * associated kthread to handle it. | ||
532 | * | ||
533 | * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IPIs sent by XPC | ||
534 | * running on other partitions. | ||
535 | * | ||
536 | * Noteworthy Arguments: | ||
537 | * | ||
538 | * irq - Interrupt ReQuest number. NOT USED. | ||
539 | * | ||
540 | * dev_id - partid of IPI's potential sender. | ||
541 | */ | ||
542 | irqreturn_t | ||
543 | xpc_notify_IRQ_handler(int irq, void *dev_id) | ||
544 | { | ||
545 | short partid = (short)(u64)dev_id; | ||
546 | struct xpc_partition *part = &xpc_partitions[partid]; | ||
547 | |||
548 | DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); | ||
549 | |||
550 | if (xpc_part_ref(part)) { | ||
551 | xpc_check_for_channel_activity(part); | ||
552 | |||
553 | xpc_part_deref(part); | ||
554 | } | ||
555 | return IRQ_HANDLED; | ||
556 | } | ||
557 | |||
558 | /* | ||
559 | * Check to see if xpc_notify_IRQ_handler() dropped any IPIs on the floor | ||
560 | * because the write to their associated IPI amo completed after the IRQ/IPI | ||
561 | * was received. | ||
562 | */ | ||
563 | void | ||
564 | xpc_dropped_IPI_check(struct xpc_partition *part) | ||
565 | { | ||
566 | if (xpc_part_ref(part)) { | ||
567 | xpc_check_for_channel_activity(part); | ||
568 | |||
569 | part->dropped_IPI_timer.expires = jiffies + | ||
570 | XPC_P_DROPPED_IPI_WAIT; | ||
571 | add_timer(&part->dropped_IPI_timer); | ||
572 | xpc_part_deref(part); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | void | 674 | void |
577 | xpc_activate_kthreads(struct xpc_channel *ch, int needed) | 675 | xpc_activate_kthreads(struct xpc_channel *ch, int needed) |
578 | { | 676 | { |
@@ -617,9 +715,9 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) | |||
617 | do { | 715 | do { |
618 | /* deliver messages to their intended recipients */ | 716 | /* deliver messages to their intended recipients */ |
619 | 717 | ||
620 | while (ch->w_local_GP.get < ch->w_remote_GP.put && | 718 | while (xpc_n_of_deliverable_payloads(ch) > 0 && |
621 | !(ch->flags & XPC_C_DISCONNECTING)) { | 719 | !(ch->flags & XPC_C_DISCONNECTING)) { |
622 | xpc_deliver_msg(ch); | 720 | xpc_deliver_payload(ch); |
623 | } | 721 | } |
624 | 722 | ||
625 | if (atomic_inc_return(&ch->kthreads_idle) > | 723 | if (atomic_inc_return(&ch->kthreads_idle) > |
@@ -633,7 +731,7 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) | |||
633 | "wait_event_interruptible_exclusive()\n"); | 731 | "wait_event_interruptible_exclusive()\n"); |
634 | 732 | ||
635 | (void)wait_event_interruptible_exclusive(ch->idle_wq, | 733 | (void)wait_event_interruptible_exclusive(ch->idle_wq, |
636 | (ch->w_local_GP.get < ch->w_remote_GP.put || | 734 | (xpc_n_of_deliverable_payloads(ch) > 0 || |
637 | (ch->flags & XPC_C_DISCONNECTING))); | 735 | (ch->flags & XPC_C_DISCONNECTING))); |
638 | 736 | ||
639 | atomic_dec(&ch->kthreads_idle); | 737 | atomic_dec(&ch->kthreads_idle); |
@@ -678,7 +776,7 @@ xpc_kthread_start(void *args) | |||
678 | * additional kthreads to help deliver them. We only | 776 | * additional kthreads to help deliver them. We only |
679 | * need one less than total #of messages to deliver. | 777 | * need one less than total #of messages to deliver. |
680 | */ | 778 | */ |
681 | n_needed = ch->w_remote_GP.put - ch->w_local_GP.get - 1; | 779 | n_needed = xpc_n_of_deliverable_payloads(ch) - 1; |
682 | if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING)) | 780 | if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING)) |
683 | xpc_activate_kthreads(ch, n_needed); | 781 | xpc_activate_kthreads(ch, n_needed); |
684 | 782 | ||
@@ -704,11 +802,9 @@ xpc_kthread_start(void *args) | |||
704 | } | 802 | } |
705 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 803 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
706 | 804 | ||
707 | if (atomic_dec_return(&ch->kthreads_assigned) == 0) { | 805 | if (atomic_dec_return(&ch->kthreads_assigned) == 0 && |
708 | if (atomic_dec_return(&part->nchannels_engaged) == 0) { | 806 | atomic_dec_return(&part->nchannels_engaged) == 0) { |
709 | xpc_mark_partition_disengaged(part); | 807 | xpc_indicate_partition_disengaged(part); |
710 | xpc_IPI_send_disengage(part); | ||
711 | } | ||
712 | } | 808 | } |
713 | 809 | ||
714 | xpc_msgqueue_deref(ch); | 810 | xpc_msgqueue_deref(ch); |
@@ -759,9 +855,9 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, | |||
759 | } else if (ch->flags & XPC_C_DISCONNECTING) { | 855 | } else if (ch->flags & XPC_C_DISCONNECTING) { |
760 | break; | 856 | break; |
761 | 857 | ||
762 | } else if (atomic_inc_return(&ch->kthreads_assigned) == 1) { | 858 | } else if (atomic_inc_return(&ch->kthreads_assigned) == 1 && |
763 | if (atomic_inc_return(&part->nchannels_engaged) == 1) | 859 | atomic_inc_return(&part->nchannels_engaged) == 1) { |
764 | xpc_mark_partition_engaged(part); | 860 | xpc_indicate_partition_engaged(part); |
765 | } | 861 | } |
766 | (void)xpc_part_ref(part); | 862 | (void)xpc_part_ref(part); |
767 | xpc_msgqueue_ref(ch); | 863 | xpc_msgqueue_ref(ch); |
@@ -783,8 +879,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, | |||
783 | 879 | ||
784 | if (atomic_dec_return(&ch->kthreads_assigned) == 0 && | 880 | if (atomic_dec_return(&ch->kthreads_assigned) == 0 && |
785 | atomic_dec_return(&part->nchannels_engaged) == 0) { | 881 | atomic_dec_return(&part->nchannels_engaged) == 0) { |
786 | xpc_mark_partition_disengaged(part); | 882 | xpc_indicate_partition_disengaged(part); |
787 | xpc_IPI_send_disengage(part); | ||
788 | } | 883 | } |
789 | xpc_msgqueue_deref(ch); | 884 | xpc_msgqueue_deref(ch); |
790 | xpc_part_deref(part); | 885 | xpc_part_deref(part); |
@@ -816,7 +911,7 @@ xpc_disconnect_wait(int ch_number) | |||
816 | int wakeup_channel_mgr; | 911 | int wakeup_channel_mgr; |
817 | 912 | ||
818 | /* now wait for all callouts to the caller's function to cease */ | 913 | /* now wait for all callouts to the caller's function to cease */ |
819 | for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { | 914 | for (partid = 0; partid < xp_max_npartitions; partid++) { |
820 | part = &xpc_partitions[partid]; | 915 | part = &xpc_partitions[partid]; |
821 | 916 | ||
822 | if (!xpc_part_ref(part)) | 917 | if (!xpc_part_ref(part)) |
@@ -835,16 +930,15 @@ xpc_disconnect_wait(int ch_number) | |||
835 | DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED)); | 930 | DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED)); |
836 | wakeup_channel_mgr = 0; | 931 | wakeup_channel_mgr = 0; |
837 | 932 | ||
838 | if (ch->delayed_IPI_flags) { | 933 | if (ch->delayed_chctl_flags) { |
839 | if (part->act_state != XPC_P_DEACTIVATING) { | 934 | if (part->act_state != XPC_P_AS_DEACTIVATING) { |
840 | spin_lock(&part->IPI_lock); | 935 | spin_lock(&part->chctl_lock); |
841 | XPC_SET_IPI_FLAGS(part->local_IPI_amo, | 936 | part->chctl.flags[ch->number] |= |
842 | ch->number, | 937 | ch->delayed_chctl_flags; |
843 | ch->delayed_IPI_flags); | 938 | spin_unlock(&part->chctl_lock); |
844 | spin_unlock(&part->IPI_lock); | ||
845 | wakeup_channel_mgr = 1; | 939 | wakeup_channel_mgr = 1; |
846 | } | 940 | } |
847 | ch->delayed_IPI_flags = 0; | 941 | ch->delayed_chctl_flags = 0; |
848 | } | 942 | } |
849 | 943 | ||
850 | ch->flags &= ~XPC_C_WDISCONNECT; | 944 | ch->flags &= ~XPC_C_WDISCONNECT; |
@@ -857,13 +951,63 @@ xpc_disconnect_wait(int ch_number) | |||
857 | } | 951 | } |
858 | } | 952 | } |
859 | 953 | ||
954 | static int | ||
955 | xpc_setup_partitions(void) | ||
956 | { | ||
957 | short partid; | ||
958 | struct xpc_partition *part; | ||
959 | |||
960 | xpc_partitions = kzalloc(sizeof(struct xpc_partition) * | ||
961 | xp_max_npartitions, GFP_KERNEL); | ||
962 | if (xpc_partitions == NULL) { | ||
963 | dev_err(xpc_part, "can't get memory for partition structure\n"); | ||
964 | return -ENOMEM; | ||
965 | } | ||
966 | |||
967 | /* | ||
968 | * The first few fields of each entry of xpc_partitions[] need to | ||
969 | * be initialized now so that calls to xpc_connect() and | ||
970 | * xpc_disconnect() can be made prior to the activation of any remote | ||
971 | * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE | ||
972 | * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING | ||
973 | * PARTITION HAS BEEN ACTIVATED. | ||
974 | */ | ||
975 | for (partid = 0; partid < xp_max_npartitions; partid++) { | ||
976 | part = &xpc_partitions[partid]; | ||
977 | |||
978 | DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); | ||
979 | |||
980 | part->activate_IRQ_rcvd = 0; | ||
981 | spin_lock_init(&part->act_lock); | ||
982 | part->act_state = XPC_P_AS_INACTIVE; | ||
983 | XPC_SET_REASON(part, 0, 0); | ||
984 | |||
985 | init_timer(&part->disengage_timer); | ||
986 | part->disengage_timer.function = | ||
987 | xpc_timeout_partition_disengage; | ||
988 | part->disengage_timer.data = (unsigned long)part; | ||
989 | |||
990 | part->setup_state = XPC_P_SS_UNSET; | ||
991 | init_waitqueue_head(&part->teardown_wq); | ||
992 | atomic_set(&part->references, 0); | ||
993 | } | ||
994 | |||
995 | return xpc_setup_partitions_sn(); | ||
996 | } | ||
997 | |||
998 | static void | ||
999 | xpc_teardown_partitions(void) | ||
1000 | { | ||
1001 | kfree(xpc_partitions); | ||
1002 | } | ||
1003 | |||
860 | static void | 1004 | static void |
861 | xpc_do_exit(enum xp_retval reason) | 1005 | xpc_do_exit(enum xp_retval reason) |
862 | { | 1006 | { |
863 | short partid; | 1007 | short partid; |
864 | int active_part_count, printed_waiting_msg = 0; | 1008 | int active_part_count, printed_waiting_msg = 0; |
865 | struct xpc_partition *part; | 1009 | struct xpc_partition *part; |
866 | unsigned long printmsg_time, disengage_request_timeout = 0; | 1010 | unsigned long printmsg_time, disengage_timeout = 0; |
867 | 1011 | ||
868 | /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ | 1012 | /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ |
869 | DBUG_ON(xpc_exiting == 1); | 1013 | DBUG_ON(xpc_exiting == 1); |
@@ -874,10 +1018,7 @@ xpc_do_exit(enum xp_retval reason) | |||
874 | * the heartbeat checker thread in case it's sleeping. | 1018 | * the heartbeat checker thread in case it's sleeping. |
875 | */ | 1019 | */ |
876 | xpc_exiting = 1; | 1020 | xpc_exiting = 1; |
877 | wake_up_interruptible(&xpc_act_IRQ_wq); | 1021 | wake_up_interruptible(&xpc_activate_IRQ_wq); |
878 | |||
879 | /* ignore all incoming interrupts */ | ||
880 | free_irq(SGI_XPC_ACTIVATE, NULL); | ||
881 | 1022 | ||
882 | /* wait for the discovery thread to exit */ | 1023 | /* wait for the discovery thread to exit */ |
883 | wait_for_completion(&xpc_discovery_exited); | 1024 | wait_for_completion(&xpc_discovery_exited); |
@@ -890,17 +1031,17 @@ xpc_do_exit(enum xp_retval reason) | |||
890 | 1031 | ||
891 | /* wait for all partitions to become inactive */ | 1032 | /* wait for all partitions to become inactive */ |
892 | 1033 | ||
893 | printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); | 1034 | printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); |
894 | xpc_disengage_request_timedout = 0; | 1035 | xpc_disengage_timedout = 0; |
895 | 1036 | ||
896 | do { | 1037 | do { |
897 | active_part_count = 0; | 1038 | active_part_count = 0; |
898 | 1039 | ||
899 | for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { | 1040 | for (partid = 0; partid < xp_max_npartitions; partid++) { |
900 | part = &xpc_partitions[partid]; | 1041 | part = &xpc_partitions[partid]; |
901 | 1042 | ||
902 | if (xpc_partition_disengaged(part) && | 1043 | if (xpc_partition_disengaged(part) && |
903 | part->act_state == XPC_P_INACTIVE) { | 1044 | part->act_state == XPC_P_AS_INACTIVE) { |
904 | continue; | 1045 | continue; |
905 | } | 1046 | } |
906 | 1047 | ||
@@ -908,36 +1049,32 @@ xpc_do_exit(enum xp_retval reason) | |||
908 | 1049 | ||
909 | XPC_DEACTIVATE_PARTITION(part, reason); | 1050 | XPC_DEACTIVATE_PARTITION(part, reason); |
910 | 1051 | ||
911 | if (part->disengage_request_timeout > | 1052 | if (part->disengage_timeout > disengage_timeout) |
912 | disengage_request_timeout) { | 1053 | disengage_timeout = part->disengage_timeout; |
913 | disengage_request_timeout = | ||
914 | part->disengage_request_timeout; | ||
915 | } | ||
916 | } | 1054 | } |
917 | 1055 | ||
918 | if (xpc_partition_engaged(-1UL)) { | 1056 | if (xpc_any_partition_engaged()) { |
919 | if (time_after(jiffies, printmsg_time)) { | 1057 | if (time_is_before_jiffies(printmsg_time)) { |
920 | dev_info(xpc_part, "waiting for remote " | 1058 | dev_info(xpc_part, "waiting for remote " |
921 | "partitions to disengage, timeout in " | 1059 | "partitions to deactivate, timeout in " |
922 | "%ld seconds\n", | 1060 | "%ld seconds\n", (disengage_timeout - |
923 | (disengage_request_timeout - jiffies) | 1061 | jiffies) / HZ); |
924 | / HZ); | ||
925 | printmsg_time = jiffies + | 1062 | printmsg_time = jiffies + |
926 | (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); | 1063 | (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); |
927 | printed_waiting_msg = 1; | 1064 | printed_waiting_msg = 1; |
928 | } | 1065 | } |
929 | 1066 | ||
930 | } else if (active_part_count > 0) { | 1067 | } else if (active_part_count > 0) { |
931 | if (printed_waiting_msg) { | 1068 | if (printed_waiting_msg) { |
932 | dev_info(xpc_part, "waiting for local partition" | 1069 | dev_info(xpc_part, "waiting for local partition" |
933 | " to disengage\n"); | 1070 | " to deactivate\n"); |
934 | printed_waiting_msg = 0; | 1071 | printed_waiting_msg = 0; |
935 | } | 1072 | } |
936 | 1073 | ||
937 | } else { | 1074 | } else { |
938 | if (!xpc_disengage_request_timedout) { | 1075 | if (!xpc_disengage_timedout) { |
939 | dev_info(xpc_part, "all partitions have " | 1076 | dev_info(xpc_part, "all partitions have " |
940 | "disengaged\n"); | 1077 | "deactivated\n"); |
941 | } | 1078 | } |
942 | break; | 1079 | break; |
943 | } | 1080 | } |
@@ -947,33 +1084,28 @@ xpc_do_exit(enum xp_retval reason) | |||
947 | 1084 | ||
948 | } while (1); | 1085 | } while (1); |
949 | 1086 | ||
950 | DBUG_ON(xpc_partition_engaged(-1UL)); | 1087 | DBUG_ON(xpc_any_partition_engaged()); |
1088 | DBUG_ON(xpc_any_hbs_allowed() != 0); | ||
951 | 1089 | ||
952 | /* indicate to others that our reserved page is uninitialized */ | 1090 | xpc_teardown_rsvd_page(); |
953 | xpc_rsvd_page->vars_pa = 0; | ||
954 | |||
955 | /* now it's time to eliminate our heartbeat */ | ||
956 | del_timer_sync(&xpc_hb_timer); | ||
957 | DBUG_ON(xpc_vars->heartbeating_to_mask != 0); | ||
958 | 1091 | ||
959 | if (reason == xpUnloading) { | 1092 | if (reason == xpUnloading) { |
960 | /* take ourselves off of the reboot_notifier_list */ | ||
961 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); | ||
962 | |||
963 | /* take ourselves off of the die_notifier list */ | ||
964 | (void)unregister_die_notifier(&xpc_die_notifier); | 1093 | (void)unregister_die_notifier(&xpc_die_notifier); |
1094 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); | ||
965 | } | 1095 | } |
966 | 1096 | ||
967 | /* close down protections for IPI operations */ | ||
968 | xpc_restrict_IPI_ops(); | ||
969 | |||
970 | /* clear the interface to XPC's functions */ | 1097 | /* clear the interface to XPC's functions */ |
971 | xpc_clear_interface(); | 1098 | xpc_clear_interface(); |
972 | 1099 | ||
973 | if (xpc_sysctl) | 1100 | if (xpc_sysctl) |
974 | unregister_sysctl_table(xpc_sysctl); | 1101 | unregister_sysctl_table(xpc_sysctl); |
975 | 1102 | ||
976 | kfree(xpc_remote_copy_buffer_base); | 1103 | xpc_teardown_partitions(); |
1104 | |||
1105 | if (is_shub()) | ||
1106 | xpc_exit_sn2(); | ||
1107 | else | ||
1108 | xpc_exit_uv(); | ||
977 | } | 1109 | } |
978 | 1110 | ||
979 | /* | 1111 | /* |
@@ -1003,60 +1135,57 @@ xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused) | |||
1003 | } | 1135 | } |
1004 | 1136 | ||
1005 | /* | 1137 | /* |
1006 | * Notify other partitions to disengage from all references to our memory. | 1138 | * Notify other partitions to deactivate from us by first disengaging from all |
1139 | * references to our memory. | ||
1007 | */ | 1140 | */ |
1008 | static void | 1141 | static void |
1009 | xpc_die_disengage(void) | 1142 | xpc_die_deactivate(void) |
1010 | { | 1143 | { |
1011 | struct xpc_partition *part; | 1144 | struct xpc_partition *part; |
1012 | short partid; | 1145 | short partid; |
1013 | unsigned long engaged; | 1146 | int any_engaged; |
1014 | long time, printmsg_time, disengage_request_timeout; | 1147 | long keep_waiting; |
1148 | long wait_to_print; | ||
1015 | 1149 | ||
1016 | /* keep xpc_hb_checker thread from doing anything (just in case) */ | 1150 | /* keep xpc_hb_checker thread from doing anything (just in case) */ |
1017 | xpc_exiting = 1; | 1151 | xpc_exiting = 1; |
1018 | 1152 | ||
1019 | xpc_vars->heartbeating_to_mask = 0; /* indicate we're deactivated */ | 1153 | xpc_disallow_all_hbs(); /*indicate we're deactivated */ |
1020 | 1154 | ||
1021 | for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { | 1155 | for (partid = 0; partid < xp_max_npartitions; partid++) { |
1022 | part = &xpc_partitions[partid]; | 1156 | part = &xpc_partitions[partid]; |
1023 | 1157 | ||
1024 | if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part-> | 1158 | if (xpc_partition_engaged(partid) || |
1025 | remote_vars_version)) { | 1159 | part->act_state != XPC_P_AS_INACTIVE) { |
1026 | 1160 | xpc_request_partition_deactivation(part); | |
1027 | /* just in case it was left set by an earlier XPC */ | 1161 | xpc_indicate_partition_disengaged(part); |
1028 | xpc_clear_partition_engaged(1UL << partid); | ||
1029 | continue; | ||
1030 | } | ||
1031 | |||
1032 | if (xpc_partition_engaged(1UL << partid) || | ||
1033 | part->act_state != XPC_P_INACTIVE) { | ||
1034 | xpc_request_partition_disengage(part); | ||
1035 | xpc_mark_partition_disengaged(part); | ||
1036 | xpc_IPI_send_disengage(part); | ||
1037 | } | 1162 | } |
1038 | } | 1163 | } |
1039 | 1164 | ||
1040 | time = rtc_time(); | 1165 | /* |
1041 | printmsg_time = time + | 1166 | * Though we requested that all other partitions deactivate from us, |
1042 | (XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second); | 1167 | * we only wait until they've all disengaged or we've reached the |
1043 | disengage_request_timeout = time + | 1168 | * defined timelimit. |
1044 | (xpc_disengage_request_timelimit * sn_rtc_cycles_per_second); | 1169 | * |
1045 | 1170 | * Given that one iteration through the following while-loop takes | |
1046 | /* wait for all other partitions to disengage from us */ | 1171 | * approximately 200 microseconds, calculate the #of loops to take |
1172 | * before bailing and the #of loops before printing a waiting message. | ||
1173 | */ | ||
1174 | keep_waiting = xpc_disengage_timelimit * 1000 * 5; | ||
1175 | wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL * 1000 * 5; | ||
1047 | 1176 | ||
1048 | while (1) { | 1177 | while (1) { |
1049 | engaged = xpc_partition_engaged(-1UL); | 1178 | any_engaged = xpc_any_partition_engaged(); |
1050 | if (!engaged) { | 1179 | if (!any_engaged) { |
1051 | dev_info(xpc_part, "all partitions have disengaged\n"); | 1180 | dev_info(xpc_part, "all partitions have deactivated\n"); |
1052 | break; | 1181 | break; |
1053 | } | 1182 | } |
1054 | 1183 | ||
1055 | time = rtc_time(); | 1184 | if (!keep_waiting--) { |
1056 | if (time >= disengage_request_timeout) { | 1185 | for (partid = 0; partid < xp_max_npartitions; |
1057 | for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { | 1186 | partid++) { |
1058 | if (engaged & (1UL << partid)) { | 1187 | if (xpc_partition_engaged(partid)) { |
1059 | dev_info(xpc_part, "disengage from " | 1188 | dev_info(xpc_part, "deactivate from " |
1060 | "remote partition %d timed " | 1189 | "remote partition %d timed " |
1061 | "out\n", partid); | 1190 | "out\n", partid); |
1062 | } | 1191 | } |
@@ -1064,15 +1193,15 @@ xpc_die_disengage(void) | |||
1064 | break; | 1193 | break; |
1065 | } | 1194 | } |
1066 | 1195 | ||
1067 | if (time >= printmsg_time) { | 1196 | if (!wait_to_print--) { |
1068 | dev_info(xpc_part, "waiting for remote partitions to " | 1197 | dev_info(xpc_part, "waiting for remote partitions to " |
1069 | "disengage, timeout in %ld seconds\n", | 1198 | "deactivate, timeout in %ld seconds\n", |
1070 | (disengage_request_timeout - time) / | 1199 | keep_waiting / (1000 * 5)); |
1071 | sn_rtc_cycles_per_second); | 1200 | wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL * |
1072 | printmsg_time = time + | 1201 | 1000 * 5; |
1073 | (XPC_DISENGAGE_PRINTMSG_INTERVAL * | ||
1074 | sn_rtc_cycles_per_second); | ||
1075 | } | 1202 | } |
1203 | |||
1204 | udelay(200); | ||
1076 | } | 1205 | } |
1077 | } | 1206 | } |
1078 | 1207 | ||
@@ -1087,10 +1216,11 @@ xpc_die_disengage(void) | |||
1087 | static int | 1216 | static int |
1088 | xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) | 1217 | xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) |
1089 | { | 1218 | { |
1219 | #ifdef CONFIG_IA64 /* !!! temporary kludge */ | ||
1090 | switch (event) { | 1220 | switch (event) { |
1091 | case DIE_MACHINE_RESTART: | 1221 | case DIE_MACHINE_RESTART: |
1092 | case DIE_MACHINE_HALT: | 1222 | case DIE_MACHINE_HALT: |
1093 | xpc_die_disengage(); | 1223 | xpc_die_deactivate(); |
1094 | break; | 1224 | break; |
1095 | 1225 | ||
1096 | case DIE_KDEBUG_ENTER: | 1226 | case DIE_KDEBUG_ENTER: |
@@ -1101,8 +1231,7 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) | |||
1101 | /* fall through */ | 1231 | /* fall through */ |
1102 | case DIE_MCA_MONARCH_ENTER: | 1232 | case DIE_MCA_MONARCH_ENTER: |
1103 | case DIE_INIT_MONARCH_ENTER: | 1233 | case DIE_INIT_MONARCH_ENTER: |
1104 | xpc_vars->heartbeat++; | 1234 | xpc_offline_heartbeat(); |
1105 | xpc_vars->heartbeat_offline = 1; | ||
1106 | break; | 1235 | break; |
1107 | 1236 | ||
1108 | case DIE_KDEBUG_LEAVE: | 1237 | case DIE_KDEBUG_LEAVE: |
@@ -1113,10 +1242,12 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) | |||
1113 | /* fall through */ | 1242 | /* fall through */ |
1114 | case DIE_MCA_MONARCH_LEAVE: | 1243 | case DIE_MCA_MONARCH_LEAVE: |
1115 | case DIE_INIT_MONARCH_LEAVE: | 1244 | case DIE_INIT_MONARCH_LEAVE: |
1116 | xpc_vars->heartbeat++; | 1245 | xpc_online_heartbeat(); |
1117 | xpc_vars->heartbeat_offline = 0; | ||
1118 | break; | 1246 | break; |
1119 | } | 1247 | } |
1248 | #else | ||
1249 | xpc_die_deactivate(); | ||
1250 | #endif | ||
1120 | 1251 | ||
1121 | return NOTIFY_DONE; | 1252 | return NOTIFY_DONE; |
1122 | } | 1253 | } |
@@ -1125,105 +1256,52 @@ int __init | |||
1125 | xpc_init(void) | 1256 | xpc_init(void) |
1126 | { | 1257 | { |
1127 | int ret; | 1258 | int ret; |
1128 | short partid; | ||
1129 | struct xpc_partition *part; | ||
1130 | struct task_struct *kthread; | 1259 | struct task_struct *kthread; |
1131 | size_t buf_size; | ||
1132 | |||
1133 | if (!ia64_platform_is("sn2")) | ||
1134 | return -ENODEV; | ||
1135 | |||
1136 | buf_size = max(XPC_RP_VARS_SIZE, | ||
1137 | XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES); | ||
1138 | xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size, | ||
1139 | GFP_KERNEL, | ||
1140 | &xpc_remote_copy_buffer_base); | ||
1141 | if (xpc_remote_copy_buffer == NULL) | ||
1142 | return -ENOMEM; | ||
1143 | 1260 | ||
1144 | snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); | 1261 | snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); |
1145 | snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); | 1262 | snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); |
1146 | 1263 | ||
1147 | xpc_sysctl = register_sysctl_table(xpc_sys_dir); | 1264 | if (is_shub()) { |
1148 | 1265 | /* | |
1149 | /* | 1266 | * The ia64-sn2 architecture supports at most 64 partitions. |
1150 | * The first few fields of each entry of xpc_partitions[] need to | 1267 | * And the inability to unregister remote amos restricts us |
1151 | * be initialized now so that calls to xpc_connect() and | 1268 | * further to only support exactly 64 partitions on this |
1152 | * xpc_disconnect() can be made prior to the activation of any remote | 1269 | * architecture, no less. |
1153 | * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE | 1270 | */ |
1154 | * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING | 1271 | if (xp_max_npartitions != 64) { |
1155 | * PARTITION HAS BEEN ACTIVATED. | 1272 | dev_err(xpc_part, "max #of partitions not set to 64\n"); |
1156 | */ | 1273 | ret = -EINVAL; |
1157 | for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { | 1274 | } else { |
1158 | part = &xpc_partitions[partid]; | 1275 | ret = xpc_init_sn2(); |
1159 | 1276 | } | |
1160 | DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); | ||
1161 | |||
1162 | part->act_IRQ_rcvd = 0; | ||
1163 | spin_lock_init(&part->act_lock); | ||
1164 | part->act_state = XPC_P_INACTIVE; | ||
1165 | XPC_SET_REASON(part, 0, 0); | ||
1166 | 1277 | ||
1167 | init_timer(&part->disengage_request_timer); | 1278 | } else if (is_uv()) { |
1168 | part->disengage_request_timer.function = | 1279 | ret = xpc_init_uv(); |
1169 | xpc_timeout_partition_disengage_request; | ||
1170 | part->disengage_request_timer.data = (unsigned long)part; | ||
1171 | 1280 | ||
1172 | part->setup_state = XPC_P_UNSET; | 1281 | } else { |
1173 | init_waitqueue_head(&part->teardown_wq); | 1282 | ret = -ENODEV; |
1174 | atomic_set(&part->references, 0); | ||
1175 | } | 1283 | } |
1176 | 1284 | ||
1177 | /* | 1285 | if (ret != 0) |
1178 | * Open up protections for IPI operations (and AMO operations on | 1286 | return ret; |
1179 | * Shub 1.1 systems). | ||
1180 | */ | ||
1181 | xpc_allow_IPI_ops(); | ||
1182 | |||
1183 | /* | ||
1184 | * Interrupts being processed will increment this atomic variable and | ||
1185 | * awaken the heartbeat thread which will process the interrupts. | ||
1186 | */ | ||
1187 | atomic_set(&xpc_act_IRQ_rcvd, 0); | ||
1188 | 1287 | ||
1189 | /* | 1288 | ret = xpc_setup_partitions(); |
1190 | * This is safe to do before the xpc_hb_checker thread has started | ||
1191 | * because the handler releases a wait queue. If an interrupt is | ||
1192 | * received before the thread is waiting, it will not go to sleep, | ||
1193 | * but rather immediately process the interrupt. | ||
1194 | */ | ||
1195 | ret = request_irq(SGI_XPC_ACTIVATE, xpc_act_IRQ_handler, 0, | ||
1196 | "xpc hb", NULL); | ||
1197 | if (ret != 0) { | 1289 | if (ret != 0) { |
1198 | dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " | 1290 | dev_err(xpc_part, "can't get memory for partition structure\n"); |
1199 | "errno=%d\n", -ret); | 1291 | goto out_1; |
1200 | |||
1201 | xpc_restrict_IPI_ops(); | ||
1202 | |||
1203 | if (xpc_sysctl) | ||
1204 | unregister_sysctl_table(xpc_sysctl); | ||
1205 | |||
1206 | kfree(xpc_remote_copy_buffer_base); | ||
1207 | return -EBUSY; | ||
1208 | } | 1292 | } |
1209 | 1293 | ||
1294 | xpc_sysctl = register_sysctl_table(xpc_sys_dir); | ||
1295 | |||
1210 | /* | 1296 | /* |
1211 | * Fill the partition reserved page with the information needed by | 1297 | * Fill the partition reserved page with the information needed by |
1212 | * other partitions to discover we are alive and establish initial | 1298 | * other partitions to discover we are alive and establish initial |
1213 | * communications. | 1299 | * communications. |
1214 | */ | 1300 | */ |
1215 | xpc_rsvd_page = xpc_rsvd_page_init(); | 1301 | ret = xpc_setup_rsvd_page(); |
1216 | if (xpc_rsvd_page == NULL) { | 1302 | if (ret != 0) { |
1217 | dev_err(xpc_part, "could not setup our reserved page\n"); | 1303 | dev_err(xpc_part, "can't setup our reserved page\n"); |
1218 | 1304 | goto out_2; | |
1219 | free_irq(SGI_XPC_ACTIVATE, NULL); | ||
1220 | xpc_restrict_IPI_ops(); | ||
1221 | |||
1222 | if (xpc_sysctl) | ||
1223 | unregister_sysctl_table(xpc_sysctl); | ||
1224 | |||
1225 | kfree(xpc_remote_copy_buffer_base); | ||
1226 | return -EBUSY; | ||
1227 | } | 1305 | } |
1228 | 1306 | ||
1229 | /* add ourselves to the reboot_notifier_list */ | 1307 | /* add ourselves to the reboot_notifier_list */ |
@@ -1236,9 +1314,6 @@ xpc_init(void) | |||
1236 | if (ret != 0) | 1314 | if (ret != 0) |
1237 | dev_warn(xpc_part, "can't register die notifier\n"); | 1315 | dev_warn(xpc_part, "can't register die notifier\n"); |
1238 | 1316 | ||
1239 | init_timer(&xpc_hb_timer); | ||
1240 | xpc_hb_timer.function = xpc_hb_beater; | ||
1241 | |||
1242 | /* | 1317 | /* |
1243 | * The real work-horse behind xpc. This processes incoming | 1318 | * The real work-horse behind xpc. This processes incoming |
1244 | * interrupts and monitors remote heartbeats. | 1319 | * interrupts and monitors remote heartbeats. |
@@ -1246,25 +1321,8 @@ xpc_init(void) | |||
1246 | kthread = kthread_run(xpc_hb_checker, NULL, XPC_HB_CHECK_THREAD_NAME); | 1321 | kthread = kthread_run(xpc_hb_checker, NULL, XPC_HB_CHECK_THREAD_NAME); |
1247 | if (IS_ERR(kthread)) { | 1322 | if (IS_ERR(kthread)) { |
1248 | dev_err(xpc_part, "failed while forking hb check thread\n"); | 1323 | dev_err(xpc_part, "failed while forking hb check thread\n"); |
1249 | 1324 | ret = -EBUSY; | |
1250 | /* indicate to others that our reserved page is uninitialized */ | 1325 | goto out_3; |
1251 | xpc_rsvd_page->vars_pa = 0; | ||
1252 | |||
1253 | /* take ourselves off of the reboot_notifier_list */ | ||
1254 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); | ||
1255 | |||
1256 | /* take ourselves off of the die_notifier list */ | ||
1257 | (void)unregister_die_notifier(&xpc_die_notifier); | ||
1258 | |||
1259 | del_timer_sync(&xpc_hb_timer); | ||
1260 | free_irq(SGI_XPC_ACTIVATE, NULL); | ||
1261 | xpc_restrict_IPI_ops(); | ||
1262 | |||
1263 | if (xpc_sysctl) | ||
1264 | unregister_sysctl_table(xpc_sysctl); | ||
1265 | |||
1266 | kfree(xpc_remote_copy_buffer_base); | ||
1267 | return -EBUSY; | ||
1268 | } | 1326 | } |
1269 | 1327 | ||
1270 | /* | 1328 | /* |
@@ -1286,11 +1344,28 @@ xpc_init(void) | |||
1286 | 1344 | ||
1287 | /* set the interface to point at XPC's functions */ | 1345 | /* set the interface to point at XPC's functions */ |
1288 | xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect, | 1346 | xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect, |
1289 | xpc_initiate_allocate, xpc_initiate_send, | 1347 | xpc_initiate_send, xpc_initiate_send_notify, |
1290 | xpc_initiate_send_notify, xpc_initiate_received, | 1348 | xpc_initiate_received, xpc_initiate_partid_to_nasids); |
1291 | xpc_initiate_partid_to_nasids); | ||
1292 | 1349 | ||
1293 | return 0; | 1350 | return 0; |
1351 | |||
1352 | /* initialization was not successful */ | ||
1353 | out_3: | ||
1354 | xpc_teardown_rsvd_page(); | ||
1355 | |||
1356 | (void)unregister_die_notifier(&xpc_die_notifier); | ||
1357 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); | ||
1358 | out_2: | ||
1359 | if (xpc_sysctl) | ||
1360 | unregister_sysctl_table(xpc_sysctl); | ||
1361 | |||
1362 | xpc_teardown_partitions(); | ||
1363 | out_1: | ||
1364 | if (is_shub()) | ||
1365 | xpc_exit_sn2(); | ||
1366 | else | ||
1367 | xpc_exit_uv(); | ||
1368 | return ret; | ||
1294 | } | 1369 | } |
1295 | 1370 | ||
1296 | module_init(xpc_init); | 1371 | module_init(xpc_init); |
@@ -1315,9 +1390,9 @@ module_param(xpc_hb_check_interval, int, 0); | |||
1315 | MODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between " | 1390 | MODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between " |
1316 | "heartbeat checks."); | 1391 | "heartbeat checks."); |
1317 | 1392 | ||
1318 | module_param(xpc_disengage_request_timelimit, int, 0); | 1393 | module_param(xpc_disengage_timelimit, int, 0); |
1319 | MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait " | 1394 | MODULE_PARM_DESC(xpc_disengage_timelimit, "Number of seconds to wait " |
1320 | "for disengage request to complete."); | 1395 | "for disengage to complete."); |
1321 | 1396 | ||
1322 | module_param(xpc_kdebug_ignore, int, 0); | 1397 | module_param(xpc_kdebug_ignore, int, 0); |
1323 | MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by " | 1398 | MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by " |
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 7dd4b5812c42..6722f6fe4dc7 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c | |||
@@ -15,57 +15,22 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/kernel.h> | 18 | #include <linux/device.h> |
19 | #include <linux/sysctl.h> | 19 | #include <linux/hardirq.h> |
20 | #include <linux/cache.h> | ||
21 | #include <linux/mmzone.h> | ||
22 | #include <linux/nodemask.h> | ||
23 | #include <asm/uncached.h> | ||
24 | #include <asm/sn/bte.h> | ||
25 | #include <asm/sn/intr.h> | ||
26 | #include <asm/sn/sn_sal.h> | ||
27 | #include <asm/sn/nodepda.h> | ||
28 | #include <asm/sn/addrs.h> | ||
29 | #include "xpc.h" | 20 | #include "xpc.h" |
30 | 21 | ||
31 | /* XPC is exiting flag */ | 22 | /* XPC is exiting flag */ |
32 | int xpc_exiting; | 23 | int xpc_exiting; |
33 | 24 | ||
34 | /* SH_IPI_ACCESS shub register value on startup */ | ||
35 | static u64 xpc_sh1_IPI_access; | ||
36 | static u64 xpc_sh2_IPI_access0; | ||
37 | static u64 xpc_sh2_IPI_access1; | ||
38 | static u64 xpc_sh2_IPI_access2; | ||
39 | static u64 xpc_sh2_IPI_access3; | ||
40 | |||
41 | /* original protection values for each node */ | ||
42 | u64 xpc_prot_vec[MAX_NUMNODES]; | ||
43 | |||
44 | /* this partition's reserved page pointers */ | 25 | /* this partition's reserved page pointers */ |
45 | struct xpc_rsvd_page *xpc_rsvd_page; | 26 | struct xpc_rsvd_page *xpc_rsvd_page; |
46 | static u64 *xpc_part_nasids; | 27 | static unsigned long *xpc_part_nasids; |
47 | static u64 *xpc_mach_nasids; | 28 | unsigned long *xpc_mach_nasids; |
48 | struct xpc_vars *xpc_vars; | ||
49 | struct xpc_vars_part *xpc_vars_part; | ||
50 | 29 | ||
51 | static int xp_nasid_mask_bytes; /* actual size in bytes of nasid mask */ | 30 | static int xpc_nasid_mask_nbytes; /* #of bytes in nasid mask */ |
52 | static int xp_nasid_mask_words; /* actual size in words of nasid mask */ | 31 | int xpc_nasid_mask_nlongs; /* #of longs in nasid mask */ |
53 | |||
54 | /* | ||
55 | * For performance reasons, each entry of xpc_partitions[] is cacheline | ||
56 | * aligned. And xpc_partitions[] is padded with an additional entry at the | ||
57 | * end so that the last legitimate entry doesn't share its cacheline with | ||
58 | * another variable. | ||
59 | */ | ||
60 | struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1]; | ||
61 | 32 | ||
62 | /* | 33 | struct xpc_partition *xpc_partitions; |
63 | * Generic buffer used to store a local copy of portions of a remote | ||
64 | * partition's reserved page (either its header and part_nasids mask, | ||
65 | * or its vars). | ||
66 | */ | ||
67 | char *xpc_remote_copy_buffer; | ||
68 | void *xpc_remote_copy_buffer_base; | ||
69 | 34 | ||
70 | /* | 35 | /* |
71 | * Guarantee that the kmalloc'd memory is cacheline aligned. | 36 | * Guarantee that the kmalloc'd memory is cacheline aligned. |
@@ -95,56 +60,59 @@ xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) | |||
95 | * Given a nasid, get the physical address of the partition's reserved page | 60 | * Given a nasid, get the physical address of the partition's reserved page |
96 | * for that nasid. This function returns 0 on any error. | 61 | * for that nasid. This function returns 0 on any error. |
97 | */ | 62 | */ |
98 | static u64 | 63 | static unsigned long |
99 | xpc_get_rsvd_page_pa(int nasid) | 64 | xpc_get_rsvd_page_pa(int nasid) |
100 | { | 65 | { |
101 | bte_result_t bte_res; | 66 | enum xp_retval ret; |
102 | s64 status; | ||
103 | u64 cookie = 0; | 67 | u64 cookie = 0; |
104 | u64 rp_pa = nasid; /* seed with nasid */ | 68 | unsigned long rp_pa = nasid; /* seed with nasid */ |
105 | u64 len = 0; | 69 | size_t len = 0; |
106 | u64 buf = buf; | 70 | size_t buf_len = 0; |
107 | u64 buf_len = 0; | 71 | void *buf = buf; |
108 | void *buf_base = NULL; | 72 | void *buf_base = NULL; |
109 | 73 | ||
110 | while (1) { | 74 | while (1) { |
111 | 75 | ||
112 | status = sn_partition_reserved_page_pa(buf, &cookie, &rp_pa, | 76 | /* !!! rp_pa will need to be _gpa on UV. |
113 | &len); | 77 | * ??? So do we save it into the architecture specific parts |
78 | * ??? of the xpc_partition structure? Do we rename this | ||
79 | * ??? function or have two versions? Rename rp_pa for UV to | ||
80 | * ??? rp_gpa? | ||
81 | */ | ||
82 | ret = xpc_get_partition_rsvd_page_pa(buf, &cookie, &rp_pa, | ||
83 | &len); | ||
114 | 84 | ||
115 | dev_dbg(xpc_part, "SAL returned with status=%li, cookie=" | 85 | dev_dbg(xpc_part, "SAL returned with ret=%d, cookie=0x%016lx, " |
116 | "0x%016lx, address=0x%016lx, len=0x%016lx\n", | 86 | "address=0x%016lx, len=0x%016lx\n", ret, |
117 | status, cookie, rp_pa, len); | 87 | (unsigned long)cookie, rp_pa, len); |
118 | 88 | ||
119 | if (status != SALRET_MORE_PASSES) | 89 | if (ret != xpNeedMoreInfo) |
120 | break; | 90 | break; |
121 | 91 | ||
92 | /* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ | ||
122 | if (L1_CACHE_ALIGN(len) > buf_len) { | 93 | if (L1_CACHE_ALIGN(len) > buf_len) { |
123 | kfree(buf_base); | 94 | kfree(buf_base); |
124 | buf_len = L1_CACHE_ALIGN(len); | 95 | buf_len = L1_CACHE_ALIGN(len); |
125 | buf = (u64)xpc_kmalloc_cacheline_aligned(buf_len, | 96 | buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL, |
126 | GFP_KERNEL, | 97 | &buf_base); |
127 | &buf_base); | ||
128 | if (buf_base == NULL) { | 98 | if (buf_base == NULL) { |
129 | dev_err(xpc_part, "unable to kmalloc " | 99 | dev_err(xpc_part, "unable to kmalloc " |
130 | "len=0x%016lx\n", buf_len); | 100 | "len=0x%016lx\n", buf_len); |
131 | status = SALRET_ERROR; | 101 | ret = xpNoMemory; |
132 | break; | 102 | break; |
133 | } | 103 | } |
134 | } | 104 | } |
135 | 105 | ||
136 | bte_res = xp_bte_copy(rp_pa, buf, buf_len, | 106 | ret = xp_remote_memcpy(xp_pa(buf), rp_pa, buf_len); |
137 | (BTE_NOTIFY | BTE_WACQUIRE), NULL); | 107 | if (ret != xpSuccess) { |
138 | if (bte_res != BTE_SUCCESS) { | 108 | dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); |
139 | dev_dbg(xpc_part, "xp_bte_copy failed %i\n", bte_res); | ||
140 | status = SALRET_ERROR; | ||
141 | break; | 109 | break; |
142 | } | 110 | } |
143 | } | 111 | } |
144 | 112 | ||
145 | kfree(buf_base); | 113 | kfree(buf_base); |
146 | 114 | ||
147 | if (status != SALRET_OK) | 115 | if (ret != xpSuccess) |
148 | rp_pa = 0; | 116 | rp_pa = 0; |
149 | 117 | ||
150 | dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa); | 118 | dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa); |
@@ -156,300 +124,77 @@ xpc_get_rsvd_page_pa(int nasid) | |||
156 | * other partitions to discover we are alive and establish initial | 124 | * other partitions to discover we are alive and establish initial |
157 | * communications. | 125 | * communications. |
158 | */ | 126 | */ |
159 | struct xpc_rsvd_page * | 127 | int |
160 | xpc_rsvd_page_init(void) | 128 | xpc_setup_rsvd_page(void) |
161 | { | 129 | { |
130 | int ret; | ||
162 | struct xpc_rsvd_page *rp; | 131 | struct xpc_rsvd_page *rp; |
163 | AMO_t *amos_page; | 132 | unsigned long rp_pa; |
164 | u64 rp_pa, nasid_array = 0; | 133 | unsigned long new_ts_jiffies; |
165 | int i, ret; | ||
166 | 134 | ||
167 | /* get the local reserved page's address */ | 135 | /* get the local reserved page's address */ |
168 | 136 | ||
169 | preempt_disable(); | 137 | preempt_disable(); |
170 | rp_pa = xpc_get_rsvd_page_pa(cpuid_to_nasid(smp_processor_id())); | 138 | rp_pa = xpc_get_rsvd_page_pa(xp_cpu_to_nasid(smp_processor_id())); |
171 | preempt_enable(); | 139 | preempt_enable(); |
172 | if (rp_pa == 0) { | 140 | if (rp_pa == 0) { |
173 | dev_err(xpc_part, "SAL failed to locate the reserved page\n"); | 141 | dev_err(xpc_part, "SAL failed to locate the reserved page\n"); |
174 | return NULL; | 142 | return -ESRCH; |
175 | } | 143 | } |
176 | rp = (struct xpc_rsvd_page *)__va(rp_pa); | 144 | rp = (struct xpc_rsvd_page *)__va(rp_pa); |
177 | 145 | ||
178 | if (rp->partid != sn_partition_id) { | 146 | if (rp->SAL_version < 3) { |
179 | dev_err(xpc_part, "the reserved page's partid of %d should be " | 147 | /* SAL_versions < 3 had a SAL_partid defined as a u8 */ |
180 | "%d\n", rp->partid, sn_partition_id); | 148 | rp->SAL_partid &= 0xff; |
181 | return NULL; | 149 | } |
150 | BUG_ON(rp->SAL_partid != xp_partition_id); | ||
151 | |||
152 | if (rp->SAL_partid < 0 || rp->SAL_partid >= xp_max_npartitions) { | ||
153 | dev_err(xpc_part, "the reserved page's partid of %d is outside " | ||
154 | "supported range (< 0 || >= %d)\n", rp->SAL_partid, | ||
155 | xp_max_npartitions); | ||
156 | return -EINVAL; | ||
182 | } | 157 | } |
183 | 158 | ||
184 | rp->version = XPC_RP_VERSION; | 159 | rp->version = XPC_RP_VERSION; |
160 | rp->max_npartitions = xp_max_npartitions; | ||
185 | 161 | ||
186 | /* establish the actual sizes of the nasid masks */ | 162 | /* establish the actual sizes of the nasid masks */ |
187 | if (rp->SAL_version == 1) { | 163 | if (rp->SAL_version == 1) { |
188 | /* SAL_version 1 didn't set the nasids_size field */ | 164 | /* SAL_version 1 didn't set the nasids_size field */ |
189 | rp->nasids_size = 128; | 165 | rp->SAL_nasids_size = 128; |
190 | } | 166 | } |
191 | xp_nasid_mask_bytes = rp->nasids_size; | 167 | xpc_nasid_mask_nbytes = rp->SAL_nasids_size; |
192 | xp_nasid_mask_words = xp_nasid_mask_bytes / 8; | 168 | xpc_nasid_mask_nlongs = BITS_TO_LONGS(rp->SAL_nasids_size * |
169 | BITS_PER_BYTE); | ||
193 | 170 | ||
194 | /* setup the pointers to the various items in the reserved page */ | 171 | /* setup the pointers to the various items in the reserved page */ |
195 | xpc_part_nasids = XPC_RP_PART_NASIDS(rp); | 172 | xpc_part_nasids = XPC_RP_PART_NASIDS(rp); |
196 | xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); | 173 | xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); |
197 | xpc_vars = XPC_RP_VARS(rp); | ||
198 | xpc_vars_part = XPC_RP_VARS_PART(rp); | ||
199 | |||
200 | /* | ||
201 | * Before clearing xpc_vars, see if a page of AMOs had been previously | ||
202 | * allocated. If not we'll need to allocate one and set permissions | ||
203 | * so that cross-partition AMOs are allowed. | ||
204 | * | ||
205 | * The allocated AMO page needs MCA reporting to remain disabled after | ||
206 | * XPC has unloaded. To make this work, we keep a copy of the pointer | ||
207 | * to this page (i.e., amos_page) in the struct xpc_vars structure, | ||
208 | * which is pointed to by the reserved page, and re-use that saved copy | ||
209 | * on subsequent loads of XPC. This AMO page is never freed, and its | ||
210 | * memory protections are never restricted. | ||
211 | */ | ||
212 | amos_page = xpc_vars->amos_page; | ||
213 | if (amos_page == NULL) { | ||
214 | amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1)); | ||
215 | if (amos_page == NULL) { | ||
216 | dev_err(xpc_part, "can't allocate page of AMOs\n"); | ||
217 | return NULL; | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * Open up AMO-R/W to cpu. This is done for Shub 1.1 systems | ||
222 | * when xpc_allow_IPI_ops() is called via xpc_hb_init(). | ||
223 | */ | ||
224 | if (!enable_shub_wars_1_1()) { | ||
225 | ret = sn_change_memprotect(ia64_tpa((u64)amos_page), | ||
226 | PAGE_SIZE, | ||
227 | SN_MEMPROT_ACCESS_CLASS_1, | ||
228 | &nasid_array); | ||
229 | if (ret != 0) { | ||
230 | dev_err(xpc_part, "can't change memory " | ||
231 | "protections\n"); | ||
232 | uncached_free_page(__IA64_UNCACHED_OFFSET | | ||
233 | TO_PHYS((u64)amos_page), 1); | ||
234 | return NULL; | ||
235 | } | ||
236 | } | ||
237 | } else if (!IS_AMO_ADDRESS((u64)amos_page)) { | ||
238 | /* | ||
239 | * EFI's XPBOOT can also set amos_page in the reserved page, | ||
240 | * but it happens to leave it as an uncached physical address | ||
241 | * and we need it to be an uncached virtual, so we'll have to | ||
242 | * convert it. | ||
243 | */ | ||
244 | if (!IS_AMO_PHYS_ADDRESS((u64)amos_page)) { | ||
245 | dev_err(xpc_part, "previously used amos_page address " | ||
246 | "is bad = 0x%p\n", (void *)amos_page); | ||
247 | return NULL; | ||
248 | } | ||
249 | amos_page = (AMO_t *)TO_AMO((u64)amos_page); | ||
250 | } | ||
251 | |||
252 | /* clear xpc_vars */ | ||
253 | memset(xpc_vars, 0, sizeof(struct xpc_vars)); | ||
254 | |||
255 | xpc_vars->version = XPC_V_VERSION; | ||
256 | xpc_vars->act_nasid = cpuid_to_nasid(0); | ||
257 | xpc_vars->act_phys_cpuid = cpu_physical_id(0); | ||
258 | xpc_vars->vars_part_pa = __pa(xpc_vars_part); | ||
259 | xpc_vars->amos_page_pa = ia64_tpa((u64)amos_page); | ||
260 | xpc_vars->amos_page = amos_page; /* save for next load of XPC */ | ||
261 | |||
262 | /* clear xpc_vars_part */ | ||
263 | memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part) * | ||
264 | XP_MAX_PARTITIONS); | ||
265 | |||
266 | /* initialize the activate IRQ related AMO variables */ | ||
267 | for (i = 0; i < xp_nasid_mask_words; i++) | ||
268 | (void)xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); | ||
269 | |||
270 | /* initialize the engaged remote partitions related AMO variables */ | ||
271 | (void)xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); | ||
272 | (void)xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); | ||
273 | 174 | ||
274 | /* timestamp of when reserved page was setup by XPC */ | 175 | ret = xpc_setup_rsvd_page_sn(rp); |
275 | rp->stamp = CURRENT_TIME; | 176 | if (ret != 0) |
177 | return ret; | ||
276 | 178 | ||
277 | /* | 179 | /* |
180 | * Set timestamp of when reserved page was setup by XPC. | ||
278 | * This signifies to the remote partition that our reserved | 181 | * This signifies to the remote partition that our reserved |
279 | * page is initialized. | 182 | * page is initialized. |
280 | */ | 183 | */ |
281 | rp->vars_pa = __pa(xpc_vars); | 184 | new_ts_jiffies = jiffies; |
185 | if (new_ts_jiffies == 0 || new_ts_jiffies == rp->ts_jiffies) | ||
186 | new_ts_jiffies++; | ||
187 | rp->ts_jiffies = new_ts_jiffies; | ||
282 | 188 | ||
283 | return rp; | 189 | xpc_rsvd_page = rp; |
190 | return 0; | ||
284 | } | 191 | } |
285 | 192 | ||
286 | /* | ||
287 | * Change protections to allow IPI operations (and AMO operations on | ||
288 | * Shub 1.1 systems). | ||
289 | */ | ||
290 | void | 193 | void |
291 | xpc_allow_IPI_ops(void) | 194 | xpc_teardown_rsvd_page(void) |
292 | { | 195 | { |
293 | int node; | 196 | /* a zero timestamp indicates our rsvd page is not initialized */ |
294 | int nasid; | 197 | xpc_rsvd_page->ts_jiffies = 0; |
295 | |||
296 | /* >>> Change SH_IPI_ACCESS code to use SAL call once it is available */ | ||
297 | |||
298 | if (is_shub2()) { | ||
299 | xpc_sh2_IPI_access0 = | ||
300 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); | ||
301 | xpc_sh2_IPI_access1 = | ||
302 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); | ||
303 | xpc_sh2_IPI_access2 = | ||
304 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); | ||
305 | xpc_sh2_IPI_access3 = | ||
306 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); | ||
307 | |||
308 | for_each_online_node(node) { | ||
309 | nasid = cnodeid_to_nasid(node); | ||
310 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), | ||
311 | -1UL); | ||
312 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), | ||
313 | -1UL); | ||
314 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), | ||
315 | -1UL); | ||
316 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), | ||
317 | -1UL); | ||
318 | } | ||
319 | |||
320 | } else { | ||
321 | xpc_sh1_IPI_access = | ||
322 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); | ||
323 | |||
324 | for_each_online_node(node) { | ||
325 | nasid = cnodeid_to_nasid(node); | ||
326 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), | ||
327 | -1UL); | ||
328 | |||
329 | /* | ||
330 | * Since the BIST collides with memory operations on | ||
331 | * SHUB 1.1 sn_change_memprotect() cannot be used. | ||
332 | */ | ||
333 | if (enable_shub_wars_1_1()) { | ||
334 | /* open up everything */ | ||
335 | xpc_prot_vec[node] = (u64)HUB_L((u64 *) | ||
336 | GLOBAL_MMR_ADDR | ||
337 | (nasid, | ||
338 | SH1_MD_DQLP_MMR_DIR_PRIVEC0)); | ||
339 | HUB_S((u64 *) | ||
340 | GLOBAL_MMR_ADDR(nasid, | ||
341 | SH1_MD_DQLP_MMR_DIR_PRIVEC0), | ||
342 | -1UL); | ||
343 | HUB_S((u64 *) | ||
344 | GLOBAL_MMR_ADDR(nasid, | ||
345 | SH1_MD_DQRP_MMR_DIR_PRIVEC0), | ||
346 | -1UL); | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Restrict protections to disallow IPI operations (and AMO operations on | ||
354 | * Shub 1.1 systems). | ||
355 | */ | ||
356 | void | ||
357 | xpc_restrict_IPI_ops(void) | ||
358 | { | ||
359 | int node; | ||
360 | int nasid; | ||
361 | |||
362 | /* >>> Change SH_IPI_ACCESS code to use SAL call once it is available */ | ||
363 | |||
364 | if (is_shub2()) { | ||
365 | |||
366 | for_each_online_node(node) { | ||
367 | nasid = cnodeid_to_nasid(node); | ||
368 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), | ||
369 | xpc_sh2_IPI_access0); | ||
370 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), | ||
371 | xpc_sh2_IPI_access1); | ||
372 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), | ||
373 | xpc_sh2_IPI_access2); | ||
374 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), | ||
375 | xpc_sh2_IPI_access3); | ||
376 | } | ||
377 | |||
378 | } else { | ||
379 | |||
380 | for_each_online_node(node) { | ||
381 | nasid = cnodeid_to_nasid(node); | ||
382 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), | ||
383 | xpc_sh1_IPI_access); | ||
384 | |||
385 | if (enable_shub_wars_1_1()) { | ||
386 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
387 | SH1_MD_DQLP_MMR_DIR_PRIVEC0), | ||
388 | xpc_prot_vec[node]); | ||
389 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
390 | SH1_MD_DQRP_MMR_DIR_PRIVEC0), | ||
391 | xpc_prot_vec[node]); | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | |||
397 | /* | ||
398 | * At periodic intervals, scan through all active partitions and ensure | ||
399 | * their heartbeat is still active. If not, the partition is deactivated. | ||
400 | */ | ||
401 | void | ||
402 | xpc_check_remote_hb(void) | ||
403 | { | ||
404 | struct xpc_vars *remote_vars; | ||
405 | struct xpc_partition *part; | ||
406 | short partid; | ||
407 | bte_result_t bres; | ||
408 | |||
409 | remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer; | ||
410 | |||
411 | for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { | ||
412 | |||
413 | if (xpc_exiting) | ||
414 | break; | ||
415 | |||
416 | if (partid == sn_partition_id) | ||
417 | continue; | ||
418 | |||
419 | part = &xpc_partitions[partid]; | ||
420 | |||
421 | if (part->act_state == XPC_P_INACTIVE || | ||
422 | part->act_state == XPC_P_DEACTIVATING) { | ||
423 | continue; | ||
424 | } | ||
425 | |||
426 | /* pull the remote_hb cache line */ | ||
427 | bres = xp_bte_copy(part->remote_vars_pa, | ||
428 | (u64)remote_vars, | ||
429 | XPC_RP_VARS_SIZE, | ||
430 | (BTE_NOTIFY | BTE_WACQUIRE), NULL); | ||
431 | if (bres != BTE_SUCCESS) { | ||
432 | XPC_DEACTIVATE_PARTITION(part, | ||
433 | xpc_map_bte_errors(bres)); | ||
434 | continue; | ||
435 | } | ||
436 | |||
437 | dev_dbg(xpc_part, "partid = %d, heartbeat = %ld, last_heartbeat" | ||
438 | " = %ld, heartbeat_offline = %ld, HB_mask = 0x%lx\n", | ||
439 | partid, remote_vars->heartbeat, part->last_heartbeat, | ||
440 | remote_vars->heartbeat_offline, | ||
441 | remote_vars->heartbeating_to_mask); | ||
442 | |||
443 | if (((remote_vars->heartbeat == part->last_heartbeat) && | ||
444 | (remote_vars->heartbeat_offline == 0)) || | ||
445 | !xpc_hb_allowed(sn_partition_id, remote_vars)) { | ||
446 | |||
447 | XPC_DEACTIVATE_PARTITION(part, xpNoHeartbeat); | ||
448 | continue; | ||
449 | } | ||
450 | |||
451 | part->last_heartbeat = remote_vars->heartbeat; | ||
452 | } | ||
453 | } | 198 | } |
454 | 199 | ||
455 | /* | 200 | /* |
@@ -459,11 +204,12 @@ xpc_check_remote_hb(void) | |||
459 | * is large enough to contain a copy of their reserved page header and | 204 | * is large enough to contain a copy of their reserved page header and |
460 | * part_nasids mask. | 205 | * part_nasids mask. |
461 | */ | 206 | */ |
462 | static enum xp_retval | 207 | enum xp_retval |
463 | xpc_get_remote_rp(int nasid, u64 *discovered_nasids, | 208 | xpc_get_remote_rp(int nasid, unsigned long *discovered_nasids, |
464 | struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) | 209 | struct xpc_rsvd_page *remote_rp, unsigned long *remote_rp_pa) |
465 | { | 210 | { |
466 | int bres, i; | 211 | int l; |
212 | enum xp_retval ret; | ||
467 | 213 | ||
468 | /* get the reserved page's physical address */ | 214 | /* get the reserved page's physical address */ |
469 | 215 | ||
@@ -472,355 +218,45 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, | |||
472 | return xpNoRsvdPageAddr; | 218 | return xpNoRsvdPageAddr; |
473 | 219 | ||
474 | /* pull over the reserved page header and part_nasids mask */ | 220 | /* pull over the reserved page header and part_nasids mask */ |
475 | bres = xp_bte_copy(*remote_rp_pa, (u64)remote_rp, | 221 | ret = xp_remote_memcpy(xp_pa(remote_rp), *remote_rp_pa, |
476 | XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes, | 222 | XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes); |
477 | (BTE_NOTIFY | BTE_WACQUIRE), NULL); | 223 | if (ret != xpSuccess) |
478 | if (bres != BTE_SUCCESS) | 224 | return ret; |
479 | return xpc_map_bte_errors(bres); | ||
480 | 225 | ||
481 | if (discovered_nasids != NULL) { | 226 | if (discovered_nasids != NULL) { |
482 | u64 *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); | 227 | unsigned long *remote_part_nasids = |
483 | 228 | XPC_RP_PART_NASIDS(remote_rp); | |
484 | for (i = 0; i < xp_nasid_mask_words; i++) | ||
485 | discovered_nasids[i] |= remote_part_nasids[i]; | ||
486 | } | ||
487 | |||
488 | /* check that the partid is for another partition */ | ||
489 | 229 | ||
490 | if (remote_rp->partid < 1 || | 230 | for (l = 0; l < xpc_nasid_mask_nlongs; l++) |
491 | remote_rp->partid > (XP_MAX_PARTITIONS - 1)) { | 231 | discovered_nasids[l] |= remote_part_nasids[l]; |
492 | return xpInvalidPartid; | ||
493 | } | 232 | } |
494 | 233 | ||
495 | if (remote_rp->partid == sn_partition_id) | 234 | /* zero timestamp indicates the reserved page has not been setup */ |
496 | return xpLocalPartid; | 235 | if (remote_rp->ts_jiffies == 0) |
236 | return xpRsvdPageNotSet; | ||
497 | 237 | ||
498 | if (XPC_VERSION_MAJOR(remote_rp->version) != | 238 | if (XPC_VERSION_MAJOR(remote_rp->version) != |
499 | XPC_VERSION_MAJOR(XPC_RP_VERSION)) { | 239 | XPC_VERSION_MAJOR(XPC_RP_VERSION)) { |
500 | return xpBadVersion; | 240 | return xpBadVersion; |
501 | } | 241 | } |
502 | 242 | ||
503 | return xpSuccess; | 243 | /* check that both remote and local partids are valid for each side */ |
504 | } | 244 | if (remote_rp->SAL_partid < 0 || |
505 | 245 | remote_rp->SAL_partid >= xp_max_npartitions || | |
506 | /* | 246 | remote_rp->max_npartitions <= xp_partition_id) { |
507 | * Get a copy of the remote partition's XPC variables from the reserved page. | 247 | return xpInvalidPartid; |
508 | * | ||
509 | * remote_vars points to a buffer that is cacheline aligned for BTE copies and | ||
510 | * assumed to be of size XPC_RP_VARS_SIZE. | ||
511 | */ | ||
512 | static enum xp_retval | ||
513 | xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars) | ||
514 | { | ||
515 | int bres; | ||
516 | |||
517 | if (remote_vars_pa == 0) | ||
518 | return xpVarsNotSet; | ||
519 | |||
520 | /* pull over the cross partition variables */ | ||
521 | bres = xp_bte_copy(remote_vars_pa, (u64)remote_vars, XPC_RP_VARS_SIZE, | ||
522 | (BTE_NOTIFY | BTE_WACQUIRE), NULL); | ||
523 | if (bres != BTE_SUCCESS) | ||
524 | return xpc_map_bte_errors(bres); | ||
525 | |||
526 | if (XPC_VERSION_MAJOR(remote_vars->version) != | ||
527 | XPC_VERSION_MAJOR(XPC_V_VERSION)) { | ||
528 | return xpBadVersion; | ||
529 | } | ||
530 | |||
531 | return xpSuccess; | ||
532 | } | ||
533 | |||
534 | /* | ||
535 | * Update the remote partition's info. | ||
536 | */ | ||
537 | static void | ||
538 | xpc_update_partition_info(struct xpc_partition *part, u8 remote_rp_version, | ||
539 | struct timespec *remote_rp_stamp, u64 remote_rp_pa, | ||
540 | u64 remote_vars_pa, struct xpc_vars *remote_vars) | ||
541 | { | ||
542 | part->remote_rp_version = remote_rp_version; | ||
543 | dev_dbg(xpc_part, " remote_rp_version = 0x%016x\n", | ||
544 | part->remote_rp_version); | ||
545 | |||
546 | part->remote_rp_stamp = *remote_rp_stamp; | ||
547 | dev_dbg(xpc_part, " remote_rp_stamp (tv_sec = 0x%lx tv_nsec = 0x%lx\n", | ||
548 | part->remote_rp_stamp.tv_sec, part->remote_rp_stamp.tv_nsec); | ||
549 | |||
550 | part->remote_rp_pa = remote_rp_pa; | ||
551 | dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa); | ||
552 | |||
553 | part->remote_vars_pa = remote_vars_pa; | ||
554 | dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", | ||
555 | part->remote_vars_pa); | ||
556 | |||
557 | part->last_heartbeat = remote_vars->heartbeat; | ||
558 | dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", | ||
559 | part->last_heartbeat); | ||
560 | |||
561 | part->remote_vars_part_pa = remote_vars->vars_part_pa; | ||
562 | dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", | ||
563 | part->remote_vars_part_pa); | ||
564 | |||
565 | part->remote_act_nasid = remote_vars->act_nasid; | ||
566 | dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n", | ||
567 | part->remote_act_nasid); | ||
568 | |||
569 | part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid; | ||
570 | dev_dbg(xpc_part, " remote_act_phys_cpuid = 0x%x\n", | ||
571 | part->remote_act_phys_cpuid); | ||
572 | |||
573 | part->remote_amos_page_pa = remote_vars->amos_page_pa; | ||
574 | dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n", | ||
575 | part->remote_amos_page_pa); | ||
576 | |||
577 | part->remote_vars_version = remote_vars->version; | ||
578 | dev_dbg(xpc_part, " remote_vars_version = 0x%x\n", | ||
579 | part->remote_vars_version); | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | * Prior code has determined the nasid which generated an IPI. Inspect | ||
584 | * that nasid to determine if its partition needs to be activated or | ||
585 | * deactivated. | ||
586 | * | ||
587 | * A partition is consider "awaiting activation" if our partition | ||
588 | * flags indicate it is not active and it has a heartbeat. A | ||
589 | * partition is considered "awaiting deactivation" if our partition | ||
590 | * flags indicate it is active but it has no heartbeat or it is not | ||
591 | * sending its heartbeat to us. | ||
592 | * | ||
593 | * To determine the heartbeat, the remote nasid must have a properly | ||
594 | * initialized reserved page. | ||
595 | */ | ||
596 | static void | ||
597 | xpc_identify_act_IRQ_req(int nasid) | ||
598 | { | ||
599 | struct xpc_rsvd_page *remote_rp; | ||
600 | struct xpc_vars *remote_vars; | ||
601 | u64 remote_rp_pa; | ||
602 | u64 remote_vars_pa; | ||
603 | int remote_rp_version; | ||
604 | int reactivate = 0; | ||
605 | int stamp_diff; | ||
606 | struct timespec remote_rp_stamp = { 0, 0 }; | ||
607 | short partid; | ||
608 | struct xpc_partition *part; | ||
609 | enum xp_retval ret; | ||
610 | |||
611 | /* pull over the reserved page structure */ | ||
612 | |||
613 | remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer; | ||
614 | |||
615 | ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa); | ||
616 | if (ret != xpSuccess) { | ||
617 | dev_warn(xpc_part, "unable to get reserved page from nasid %d, " | ||
618 | "which sent interrupt, reason=%d\n", nasid, ret); | ||
619 | return; | ||
620 | } | ||
621 | |||
622 | remote_vars_pa = remote_rp->vars_pa; | ||
623 | remote_rp_version = remote_rp->version; | ||
624 | if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) | ||
625 | remote_rp_stamp = remote_rp->stamp; | ||
626 | |||
627 | partid = remote_rp->partid; | ||
628 | part = &xpc_partitions[partid]; | ||
629 | |||
630 | /* pull over the cross partition variables */ | ||
631 | |||
632 | remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer; | ||
633 | |||
634 | ret = xpc_get_remote_vars(remote_vars_pa, remote_vars); | ||
635 | if (ret != xpSuccess) { | ||
636 | |||
637 | dev_warn(xpc_part, "unable to get XPC variables from nasid %d, " | ||
638 | "which sent interrupt, reason=%d\n", nasid, ret); | ||
639 | |||
640 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
641 | return; | ||
642 | } | ||
643 | |||
644 | part->act_IRQ_rcvd++; | ||
645 | |||
646 | dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = " | ||
647 | "%ld:0x%lx\n", (int)nasid, (int)partid, part->act_IRQ_rcvd, | ||
648 | remote_vars->heartbeat, remote_vars->heartbeating_to_mask); | ||
649 | |||
650 | if (xpc_partition_disengaged(part) && | ||
651 | part->act_state == XPC_P_INACTIVE) { | ||
652 | |||
653 | xpc_update_partition_info(part, remote_rp_version, | ||
654 | &remote_rp_stamp, remote_rp_pa, | ||
655 | remote_vars_pa, remote_vars); | ||
656 | |||
657 | if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { | ||
658 | if (xpc_partition_disengage_requested(1UL << partid)) { | ||
659 | /* | ||
660 | * Other side is waiting on us to disengage, | ||
661 | * even though we already have. | ||
662 | */ | ||
663 | return; | ||
664 | } | ||
665 | } else { | ||
666 | /* other side doesn't support disengage requests */ | ||
667 | xpc_clear_partition_disengage_request(1UL << partid); | ||
668 | } | ||
669 | |||
670 | xpc_activate_partition(part); | ||
671 | return; | ||
672 | } | ||
673 | |||
674 | DBUG_ON(part->remote_rp_version == 0); | ||
675 | DBUG_ON(part->remote_vars_version == 0); | ||
676 | |||
677 | if (!XPC_SUPPORTS_RP_STAMP(part->remote_rp_version)) { | ||
678 | DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(part-> | ||
679 | remote_vars_version)); | ||
680 | |||
681 | if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { | ||
682 | DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> | ||
683 | version)); | ||
684 | /* see if the other side rebooted */ | ||
685 | if (part->remote_amos_page_pa == | ||
686 | remote_vars->amos_page_pa && | ||
687 | xpc_hb_allowed(sn_partition_id, remote_vars)) { | ||
688 | /* doesn't look that way, so ignore the IPI */ | ||
689 | return; | ||
690 | } | ||
691 | } | ||
692 | |||
693 | /* | ||
694 | * Other side rebooted and previous XPC didn't support the | ||
695 | * disengage request, so we don't need to do anything special. | ||
696 | */ | ||
697 | |||
698 | xpc_update_partition_info(part, remote_rp_version, | ||
699 | &remote_rp_stamp, remote_rp_pa, | ||
700 | remote_vars_pa, remote_vars); | ||
701 | part->reactivate_nasid = nasid; | ||
702 | XPC_DEACTIVATE_PARTITION(part, xpReactivating); | ||
703 | return; | ||
704 | } | ||
705 | |||
706 | DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)); | ||
707 | |||
708 | if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { | ||
709 | DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); | ||
710 | |||
711 | /* | ||
712 | * Other side rebooted and previous XPC did support the | ||
713 | * disengage request, but the new one doesn't. | ||
714 | */ | ||
715 | |||
716 | xpc_clear_partition_engaged(1UL << partid); | ||
717 | xpc_clear_partition_disengage_request(1UL << partid); | ||
718 | |||
719 | xpc_update_partition_info(part, remote_rp_version, | ||
720 | &remote_rp_stamp, remote_rp_pa, | ||
721 | remote_vars_pa, remote_vars); | ||
722 | reactivate = 1; | ||
723 | |||
724 | } else { | ||
725 | DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); | ||
726 | |||
727 | stamp_diff = xpc_compare_stamps(&part->remote_rp_stamp, | ||
728 | &remote_rp_stamp); | ||
729 | if (stamp_diff != 0) { | ||
730 | DBUG_ON(stamp_diff >= 0); | ||
731 | |||
732 | /* | ||
733 | * Other side rebooted and the previous XPC did support | ||
734 | * the disengage request, as does the new one. | ||
735 | */ | ||
736 | |||
737 | DBUG_ON(xpc_partition_engaged(1UL << partid)); | ||
738 | DBUG_ON(xpc_partition_disengage_requested(1UL << | ||
739 | partid)); | ||
740 | |||
741 | xpc_update_partition_info(part, remote_rp_version, | ||
742 | &remote_rp_stamp, | ||
743 | remote_rp_pa, remote_vars_pa, | ||
744 | remote_vars); | ||
745 | reactivate = 1; | ||
746 | } | ||
747 | } | ||
748 | |||
749 | if (part->disengage_request_timeout > 0 && | ||
750 | !xpc_partition_disengaged(part)) { | ||
751 | /* still waiting on other side to disengage from us */ | ||
752 | return; | ||
753 | } | ||
754 | |||
755 | if (reactivate) { | ||
756 | part->reactivate_nasid = nasid; | ||
757 | XPC_DEACTIVATE_PARTITION(part, xpReactivating); | ||
758 | |||
759 | } else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) && | ||
760 | xpc_partition_disengage_requested(1UL << partid)) { | ||
761 | XPC_DEACTIVATE_PARTITION(part, xpOtherGoingDown); | ||
762 | } | 248 | } |
763 | } | ||
764 | 249 | ||
765 | /* | 250 | if (remote_rp->SAL_partid == xp_partition_id) |
766 | * Loop through the activation AMO variables and process any bits | 251 | return xpLocalPartid; |
767 | * which are set. Each bit indicates a nasid sending a partition | ||
768 | * activation or deactivation request. | ||
769 | * | ||
770 | * Return #of IRQs detected. | ||
771 | */ | ||
772 | int | ||
773 | xpc_identify_act_IRQ_sender(void) | ||
774 | { | ||
775 | int word, bit; | ||
776 | u64 nasid_mask; | ||
777 | u64 nasid; /* remote nasid */ | ||
778 | int n_IRQs_detected = 0; | ||
779 | AMO_t *act_amos; | ||
780 | |||
781 | act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS; | ||
782 | |||
783 | /* scan through act AMO variable looking for non-zero entries */ | ||
784 | for (word = 0; word < xp_nasid_mask_words; word++) { | ||
785 | |||
786 | if (xpc_exiting) | ||
787 | break; | ||
788 | |||
789 | nasid_mask = xpc_IPI_receive(&act_amos[word]); | ||
790 | if (nasid_mask == 0) { | ||
791 | /* no IRQs from nasids in this variable */ | ||
792 | continue; | ||
793 | } | ||
794 | |||
795 | dev_dbg(xpc_part, "AMO[%d] gave back 0x%lx\n", word, | ||
796 | nasid_mask); | ||
797 | |||
798 | /* | ||
799 | * If this nasid has been added to the machine since | ||
800 | * our partition was reset, this will retain the | ||
801 | * remote nasid in our reserved pages machine mask. | ||
802 | * This is used in the event of module reload. | ||
803 | */ | ||
804 | xpc_mach_nasids[word] |= nasid_mask; | ||
805 | |||
806 | /* locate the nasid(s) which sent interrupts */ | ||
807 | 252 | ||
808 | for (bit = 0; bit < (8 * sizeof(u64)); bit++) { | 253 | return xpSuccess; |
809 | if (nasid_mask & (1UL << bit)) { | ||
810 | n_IRQs_detected++; | ||
811 | nasid = XPC_NASID_FROM_W_B(word, bit); | ||
812 | dev_dbg(xpc_part, "interrupt from nasid %ld\n", | ||
813 | nasid); | ||
814 | xpc_identify_act_IRQ_req(nasid); | ||
815 | } | ||
816 | } | ||
817 | } | ||
818 | return n_IRQs_detected; | ||
819 | } | 254 | } |
820 | 255 | ||
821 | /* | 256 | /* |
822 | * See if the other side has responded to a partition disengage request | 257 | * See if the other side has responded to a partition deactivate request |
823 | * from us. | 258 | * from us. Though we requested the remote partition to deactivate with regard |
259 | * to us, we really only need to wait for the other side to disengage from us. | ||
824 | */ | 260 | */ |
825 | int | 261 | int |
826 | xpc_partition_disengaged(struct xpc_partition *part) | 262 | xpc_partition_disengaged(struct xpc_partition *part) |
@@ -828,41 +264,37 @@ xpc_partition_disengaged(struct xpc_partition *part) | |||
828 | short partid = XPC_PARTID(part); | 264 | short partid = XPC_PARTID(part); |
829 | int disengaged; | 265 | int disengaged; |
830 | 266 | ||
831 | disengaged = (xpc_partition_engaged(1UL << partid) == 0); | 267 | disengaged = !xpc_partition_engaged(partid); |
832 | if (part->disengage_request_timeout) { | 268 | if (part->disengage_timeout) { |
833 | if (!disengaged) { | 269 | if (!disengaged) { |
834 | if (time_before(jiffies, | 270 | if (time_is_after_jiffies(part->disengage_timeout)) { |
835 | part->disengage_request_timeout)) { | ||
836 | /* timelimit hasn't been reached yet */ | 271 | /* timelimit hasn't been reached yet */ |
837 | return 0; | 272 | return 0; |
838 | } | 273 | } |
839 | 274 | ||
840 | /* | 275 | /* |
841 | * Other side hasn't responded to our disengage | 276 | * Other side hasn't responded to our deactivate |
842 | * request in a timely fashion, so assume it's dead. | 277 | * request in a timely fashion, so assume it's dead. |
843 | */ | 278 | */ |
844 | 279 | ||
845 | dev_info(xpc_part, "disengage from remote partition %d " | 280 | dev_info(xpc_part, "deactivate request to remote " |
846 | "timed out\n", partid); | 281 | "partition %d timed out\n", partid); |
847 | xpc_disengage_request_timedout = 1; | 282 | xpc_disengage_timedout = 1; |
848 | xpc_clear_partition_engaged(1UL << partid); | 283 | xpc_assume_partition_disengaged(partid); |
849 | disengaged = 1; | 284 | disengaged = 1; |
850 | } | 285 | } |
851 | part->disengage_request_timeout = 0; | 286 | part->disengage_timeout = 0; |
852 | 287 | ||
853 | /* cancel the timer function, provided it's not us */ | 288 | /* cancel the timer function, provided it's not us */ |
854 | if (!in_interrupt()) { | 289 | if (!in_interrupt()) |
855 | del_singleshot_timer_sync(&part-> | 290 | del_singleshot_timer_sync(&part->disengage_timer); |
856 | disengage_request_timer); | ||
857 | } | ||
858 | 291 | ||
859 | DBUG_ON(part->act_state != XPC_P_DEACTIVATING && | 292 | DBUG_ON(part->act_state != XPC_P_AS_DEACTIVATING && |
860 | part->act_state != XPC_P_INACTIVE); | 293 | part->act_state != XPC_P_AS_INACTIVE); |
861 | if (part->act_state != XPC_P_INACTIVE) | 294 | if (part->act_state != XPC_P_AS_INACTIVE) |
862 | xpc_wakeup_channel_mgr(part); | 295 | xpc_wakeup_channel_mgr(part); |
863 | 296 | ||
864 | if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) | 297 | xpc_cancel_partition_deactivation_request(part); |
865 | xpc_cancel_partition_disengage_request(part); | ||
866 | } | 298 | } |
867 | return disengaged; | 299 | return disengaged; |
868 | } | 300 | } |
@@ -879,8 +311,8 @@ xpc_mark_partition_active(struct xpc_partition *part) | |||
879 | dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part)); | 311 | dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part)); |
880 | 312 | ||
881 | spin_lock_irqsave(&part->act_lock, irq_flags); | 313 | spin_lock_irqsave(&part->act_lock, irq_flags); |
882 | if (part->act_state == XPC_P_ACTIVATING) { | 314 | if (part->act_state == XPC_P_AS_ACTIVATING) { |
883 | part->act_state = XPC_P_ACTIVE; | 315 | part->act_state = XPC_P_AS_ACTIVE; |
884 | ret = xpSuccess; | 316 | ret = xpSuccess; |
885 | } else { | 317 | } else { |
886 | DBUG_ON(part->reason == xpSuccess); | 318 | DBUG_ON(part->reason == xpSuccess); |
@@ -892,7 +324,7 @@ xpc_mark_partition_active(struct xpc_partition *part) | |||
892 | } | 324 | } |
893 | 325 | ||
894 | /* | 326 | /* |
895 | * Notify XPC that the partition is down. | 327 | * Start the process of deactivating the specified partition. |
896 | */ | 328 | */ |
897 | void | 329 | void |
898 | xpc_deactivate_partition(const int line, struct xpc_partition *part, | 330 | xpc_deactivate_partition(const int line, struct xpc_partition *part, |
@@ -902,16 +334,16 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, | |||
902 | 334 | ||
903 | spin_lock_irqsave(&part->act_lock, irq_flags); | 335 | spin_lock_irqsave(&part->act_lock, irq_flags); |
904 | 336 | ||
905 | if (part->act_state == XPC_P_INACTIVE) { | 337 | if (part->act_state == XPC_P_AS_INACTIVE) { |
906 | XPC_SET_REASON(part, reason, line); | 338 | XPC_SET_REASON(part, reason, line); |
907 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | 339 | spin_unlock_irqrestore(&part->act_lock, irq_flags); |
908 | if (reason == xpReactivating) { | 340 | if (reason == xpReactivating) { |
909 | /* we interrupt ourselves to reactivate partition */ | 341 | /* we interrupt ourselves to reactivate partition */ |
910 | xpc_IPI_send_reactivate(part); | 342 | xpc_request_partition_reactivation(part); |
911 | } | 343 | } |
912 | return; | 344 | return; |
913 | } | 345 | } |
914 | if (part->act_state == XPC_P_DEACTIVATING) { | 346 | if (part->act_state == XPC_P_AS_DEACTIVATING) { |
915 | if ((part->reason == xpUnloading && reason != xpUnloading) || | 347 | if ((part->reason == xpUnloading && reason != xpUnloading) || |
916 | reason == xpReactivating) { | 348 | reason == xpReactivating) { |
917 | XPC_SET_REASON(part, reason, line); | 349 | XPC_SET_REASON(part, reason, line); |
@@ -920,22 +352,18 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, | |||
920 | return; | 352 | return; |
921 | } | 353 | } |
922 | 354 | ||
923 | part->act_state = XPC_P_DEACTIVATING; | 355 | part->act_state = XPC_P_AS_DEACTIVATING; |
924 | XPC_SET_REASON(part, reason, line); | 356 | XPC_SET_REASON(part, reason, line); |
925 | 357 | ||
926 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | 358 | spin_unlock_irqrestore(&part->act_lock, irq_flags); |
927 | 359 | ||
928 | if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { | 360 | /* ask remote partition to deactivate with regard to us */ |
929 | xpc_request_partition_disengage(part); | 361 | xpc_request_partition_deactivation(part); |
930 | xpc_IPI_send_disengage(part); | ||
931 | 362 | ||
932 | /* set a timelimit on the disengage request */ | 363 | /* set a timelimit on the disengage phase of the deactivation request */ |
933 | part->disengage_request_timeout = jiffies + | 364 | part->disengage_timeout = jiffies + (xpc_disengage_timelimit * HZ); |
934 | (xpc_disengage_request_timelimit * HZ); | 365 | part->disengage_timer.expires = part->disengage_timeout; |
935 | part->disengage_request_timer.expires = | 366 | add_timer(&part->disengage_timer); |
936 | part->disengage_request_timeout; | ||
937 | add_timer(&part->disengage_request_timer); | ||
938 | } | ||
939 | 367 | ||
940 | dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", | 368 | dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", |
941 | XPC_PARTID(part), reason); | 369 | XPC_PARTID(part), reason); |
@@ -955,7 +383,7 @@ xpc_mark_partition_inactive(struct xpc_partition *part) | |||
955 | XPC_PARTID(part)); | 383 | XPC_PARTID(part)); |
956 | 384 | ||
957 | spin_lock_irqsave(&part->act_lock, irq_flags); | 385 | spin_lock_irqsave(&part->act_lock, irq_flags); |
958 | part->act_state = XPC_P_INACTIVE; | 386 | part->act_state = XPC_P_AS_INACTIVE; |
959 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | 387 | spin_unlock_irqrestore(&part->act_lock, irq_flags); |
960 | part->remote_rp_pa = 0; | 388 | part->remote_rp_pa = 0; |
961 | } | 389 | } |
@@ -974,28 +402,22 @@ xpc_discovery(void) | |||
974 | { | 402 | { |
975 | void *remote_rp_base; | 403 | void *remote_rp_base; |
976 | struct xpc_rsvd_page *remote_rp; | 404 | struct xpc_rsvd_page *remote_rp; |
977 | struct xpc_vars *remote_vars; | 405 | unsigned long remote_rp_pa; |
978 | u64 remote_rp_pa; | ||
979 | u64 remote_vars_pa; | ||
980 | int region; | 406 | int region; |
981 | int region_size; | 407 | int region_size; |
982 | int max_regions; | 408 | int max_regions; |
983 | int nasid; | 409 | int nasid; |
984 | struct xpc_rsvd_page *rp; | 410 | struct xpc_rsvd_page *rp; |
985 | short partid; | 411 | unsigned long *discovered_nasids; |
986 | struct xpc_partition *part; | ||
987 | u64 *discovered_nasids; | ||
988 | enum xp_retval ret; | 412 | enum xp_retval ret; |
989 | 413 | ||
990 | remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + | 414 | remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + |
991 | xp_nasid_mask_bytes, | 415 | xpc_nasid_mask_nbytes, |
992 | GFP_KERNEL, &remote_rp_base); | 416 | GFP_KERNEL, &remote_rp_base); |
993 | if (remote_rp == NULL) | 417 | if (remote_rp == NULL) |
994 | return; | 418 | return; |
995 | 419 | ||
996 | remote_vars = (struct xpc_vars *)remote_rp; | 420 | discovered_nasids = kzalloc(sizeof(long) * xpc_nasid_mask_nlongs, |
997 | |||
998 | discovered_nasids = kzalloc(sizeof(u64) * xp_nasid_mask_words, | ||
999 | GFP_KERNEL); | 421 | GFP_KERNEL); |
1000 | if (discovered_nasids == NULL) { | 422 | if (discovered_nasids == NULL) { |
1001 | kfree(remote_rp_base); | 423 | kfree(remote_rp_base); |
@@ -1010,7 +432,7 @@ xpc_discovery(void) | |||
1010 | * protection is in regards to memory, IOI and IPI. | 432 | * protection is in regards to memory, IOI and IPI. |
1011 | */ | 433 | */ |
1012 | max_regions = 64; | 434 | max_regions = 64; |
1013 | region_size = sn_region_size; | 435 | region_size = xp_region_size; |
1014 | 436 | ||
1015 | switch (region_size) { | 437 | switch (region_size) { |
1016 | case 128: | 438 | case 128: |
@@ -1038,28 +460,28 @@ xpc_discovery(void) | |||
1038 | 460 | ||
1039 | dev_dbg(xpc_part, "checking nasid %d\n", nasid); | 461 | dev_dbg(xpc_part, "checking nasid %d\n", nasid); |
1040 | 462 | ||
1041 | if (XPC_NASID_IN_ARRAY(nasid, xpc_part_nasids)) { | 463 | if (test_bit(nasid / 2, xpc_part_nasids)) { |
1042 | dev_dbg(xpc_part, "PROM indicates Nasid %d is " | 464 | dev_dbg(xpc_part, "PROM indicates Nasid %d is " |
1043 | "part of the local partition; skipping " | 465 | "part of the local partition; skipping " |
1044 | "region\n", nasid); | 466 | "region\n", nasid); |
1045 | break; | 467 | break; |
1046 | } | 468 | } |
1047 | 469 | ||
1048 | if (!(XPC_NASID_IN_ARRAY(nasid, xpc_mach_nasids))) { | 470 | if (!(test_bit(nasid / 2, xpc_mach_nasids))) { |
1049 | dev_dbg(xpc_part, "PROM indicates Nasid %d was " | 471 | dev_dbg(xpc_part, "PROM indicates Nasid %d was " |
1050 | "not on Numa-Link network at reset\n", | 472 | "not on Numa-Link network at reset\n", |
1051 | nasid); | 473 | nasid); |
1052 | continue; | 474 | continue; |
1053 | } | 475 | } |
1054 | 476 | ||
1055 | if (XPC_NASID_IN_ARRAY(nasid, discovered_nasids)) { | 477 | if (test_bit(nasid / 2, discovered_nasids)) { |
1056 | dev_dbg(xpc_part, "Nasid %d is part of a " | 478 | dev_dbg(xpc_part, "Nasid %d is part of a " |
1057 | "partition which was previously " | 479 | "partition which was previously " |
1058 | "discovered\n", nasid); | 480 | "discovered\n", nasid); |
1059 | continue; | 481 | continue; |
1060 | } | 482 | } |
1061 | 483 | ||
1062 | /* pull over the reserved page structure */ | 484 | /* pull over the rsvd page header & part_nasids mask */ |
1063 | 485 | ||
1064 | ret = xpc_get_remote_rp(nasid, discovered_nasids, | 486 | ret = xpc_get_remote_rp(nasid, discovered_nasids, |
1065 | remote_rp, &remote_rp_pa); | 487 | remote_rp, &remote_rp_pa); |
@@ -1074,72 +496,8 @@ xpc_discovery(void) | |||
1074 | continue; | 496 | continue; |
1075 | } | 497 | } |
1076 | 498 | ||
1077 | remote_vars_pa = remote_rp->vars_pa; | 499 | xpc_request_partition_activation(remote_rp, |
1078 | 500 | remote_rp_pa, nasid); | |
1079 | partid = remote_rp->partid; | ||
1080 | part = &xpc_partitions[partid]; | ||
1081 | |||
1082 | /* pull over the cross partition variables */ | ||
1083 | |||
1084 | ret = xpc_get_remote_vars(remote_vars_pa, remote_vars); | ||
1085 | if (ret != xpSuccess) { | ||
1086 | dev_dbg(xpc_part, "unable to get XPC variables " | ||
1087 | "from nasid %d, reason=%d\n", nasid, | ||
1088 | ret); | ||
1089 | |||
1090 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
1091 | continue; | ||
1092 | } | ||
1093 | |||
1094 | if (part->act_state != XPC_P_INACTIVE) { | ||
1095 | dev_dbg(xpc_part, "partition %d on nasid %d is " | ||
1096 | "already activating\n", partid, nasid); | ||
1097 | break; | ||
1098 | } | ||
1099 | |||
1100 | /* | ||
1101 | * Register the remote partition's AMOs with SAL so it | ||
1102 | * can handle and cleanup errors within that address | ||
1103 | * range should the remote partition go down. We don't | ||
1104 | * unregister this range because it is difficult to | ||
1105 | * tell when outstanding writes to the remote partition | ||
1106 | * are finished and thus when it is thus safe to | ||
1107 | * unregister. This should not result in wasted space | ||
1108 | * in the SAL xp_addr_region table because we should | ||
1109 | * get the same page for remote_act_amos_pa after | ||
1110 | * module reloads and system reboots. | ||
1111 | */ | ||
1112 | if (sn_register_xp_addr_region | ||
1113 | (remote_vars->amos_page_pa, PAGE_SIZE, 1) < 0) { | ||
1114 | dev_dbg(xpc_part, | ||
1115 | "partition %d failed to " | ||
1116 | "register xp_addr region 0x%016lx\n", | ||
1117 | partid, remote_vars->amos_page_pa); | ||
1118 | |||
1119 | XPC_SET_REASON(part, xpPhysAddrRegFailed, | ||
1120 | __LINE__); | ||
1121 | break; | ||
1122 | } | ||
1123 | |||
1124 | /* | ||
1125 | * The remote nasid is valid and available. | ||
1126 | * Send an interrupt to that nasid to notify | ||
1127 | * it that we are ready to begin activation. | ||
1128 | */ | ||
1129 | dev_dbg(xpc_part, "sending an interrupt to AMO 0x%lx, " | ||
1130 | "nasid %d, phys_cpuid 0x%x\n", | ||
1131 | remote_vars->amos_page_pa, | ||
1132 | remote_vars->act_nasid, | ||
1133 | remote_vars->act_phys_cpuid); | ||
1134 | |||
1135 | if (XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> | ||
1136 | version)) { | ||
1137 | part->remote_amos_page_pa = | ||
1138 | remote_vars->amos_page_pa; | ||
1139 | xpc_mark_partition_disengaged(part); | ||
1140 | xpc_cancel_partition_disengage_request(part); | ||
1141 | } | ||
1142 | xpc_IPI_send_activate(remote_vars); | ||
1143 | } | 501 | } |
1144 | } | 502 | } |
1145 | 503 | ||
@@ -1155,20 +513,16 @@ enum xp_retval | |||
1155 | xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) | 513 | xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) |
1156 | { | 514 | { |
1157 | struct xpc_partition *part; | 515 | struct xpc_partition *part; |
1158 | u64 part_nasid_pa; | 516 | unsigned long part_nasid_pa; |
1159 | int bte_res; | ||
1160 | 517 | ||
1161 | part = &xpc_partitions[partid]; | 518 | part = &xpc_partitions[partid]; |
1162 | if (part->remote_rp_pa == 0) | 519 | if (part->remote_rp_pa == 0) |
1163 | return xpPartitionDown; | 520 | return xpPartitionDown; |
1164 | 521 | ||
1165 | memset(nasid_mask, 0, XP_NASID_MASK_BYTES); | 522 | memset(nasid_mask, 0, xpc_nasid_mask_nbytes); |
1166 | |||
1167 | part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); | ||
1168 | 523 | ||
1169 | bte_res = xp_bte_copy(part_nasid_pa, (u64)nasid_mask, | 524 | part_nasid_pa = (unsigned long)XPC_RP_PART_NASIDS(part->remote_rp_pa); |
1170 | xp_nasid_mask_bytes, (BTE_NOTIFY | BTE_WACQUIRE), | ||
1171 | NULL); | ||
1172 | 525 | ||
1173 | return xpc_map_bte_errors(bte_res); | 526 | return xp_remote_memcpy(xp_pa(nasid_mask), part_nasid_pa, |
527 | xpc_nasid_mask_nbytes); | ||
1174 | } | 528 | } |
diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c new file mode 100644 index 000000000000..b4882ccf6344 --- /dev/null +++ b/drivers/misc/sgi-xp/xpc_sn2.c | |||
@@ -0,0 +1,2404 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Cross Partition Communication (XPC) sn2-based functions. | ||
11 | * | ||
12 | * Architecture specific implementation of common functions. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/delay.h> | ||
17 | #include <asm/uncached.h> | ||
18 | #include <asm/sn/mspec.h> | ||
19 | #include <asm/sn/sn_sal.h> | ||
20 | #include "xpc.h" | ||
21 | |||
22 | /* | ||
23 | * Define the number of u64s required to represent all the C-brick nasids | ||
24 | * as a bitmap. The cross-partition kernel modules deal only with | ||
25 | * C-brick nasids, thus the need for bitmaps which don't account for | ||
26 | * odd-numbered (non C-brick) nasids. | ||
27 | */ | ||
28 | #define XPC_MAX_PHYSNODES_SN2 (MAX_NUMALINK_NODES / 2) | ||
29 | #define XP_NASID_MASK_BYTES_SN2 ((XPC_MAX_PHYSNODES_SN2 + 7) / 8) | ||
30 | #define XP_NASID_MASK_WORDS_SN2 ((XPC_MAX_PHYSNODES_SN2 + 63) / 64) | ||
31 | |||
32 | /* | ||
33 | * Memory for XPC's amo variables is allocated by the MSPEC driver. These | ||
34 | * pages are located in the lowest granule. The lowest granule uses 4k pages | ||
35 | * for cached references and an alternate TLB handler to never provide a | ||
36 | * cacheable mapping for the entire region. This will prevent speculative | ||
37 | * reading of cached copies of our lines from being issued which will cause | ||
38 | * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 | ||
39 | * amo variables (based on XP_MAX_NPARTITIONS_SN2) to identify the senders of | ||
40 | * NOTIFY IRQs, 128 amo variables (based on XP_NASID_MASK_WORDS_SN2) to identify | ||
41 | * the senders of ACTIVATE IRQs, 1 amo variable to identify which remote | ||
42 | * partitions (i.e., XPCs) consider themselves currently engaged with the | ||
43 | * local XPC and 1 amo variable to request partition deactivation. | ||
44 | */ | ||
45 | #define XPC_NOTIFY_IRQ_AMOS_SN2 0 | ||
46 | #define XPC_ACTIVATE_IRQ_AMOS_SN2 (XPC_NOTIFY_IRQ_AMOS_SN2 + \ | ||
47 | XP_MAX_NPARTITIONS_SN2) | ||
48 | #define XPC_ENGAGED_PARTITIONS_AMO_SN2 (XPC_ACTIVATE_IRQ_AMOS_SN2 + \ | ||
49 | XP_NASID_MASK_WORDS_SN2) | ||
50 | #define XPC_DEACTIVATE_REQUEST_AMO_SN2 (XPC_ENGAGED_PARTITIONS_AMO_SN2 + 1) | ||
51 | |||
52 | /* | ||
53 | * Buffer used to store a local copy of portions of a remote partition's | ||
54 | * reserved page (either its header and part_nasids mask, or its vars). | ||
55 | */ | ||
56 | static void *xpc_remote_copy_buffer_base_sn2; | ||
57 | static char *xpc_remote_copy_buffer_sn2; | ||
58 | |||
59 | static struct xpc_vars_sn2 *xpc_vars_sn2; | ||
60 | static struct xpc_vars_part_sn2 *xpc_vars_part_sn2; | ||
61 | |||
62 | static int | ||
63 | xpc_setup_partitions_sn_sn2(void) | ||
64 | { | ||
65 | /* nothing needs to be done */ | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | /* SH_IPI_ACCESS shub register value on startup */ | ||
70 | static u64 xpc_sh1_IPI_access_sn2; | ||
71 | static u64 xpc_sh2_IPI_access0_sn2; | ||
72 | static u64 xpc_sh2_IPI_access1_sn2; | ||
73 | static u64 xpc_sh2_IPI_access2_sn2; | ||
74 | static u64 xpc_sh2_IPI_access3_sn2; | ||
75 | |||
76 | /* | ||
77 | * Change protections to allow IPI operations. | ||
78 | */ | ||
79 | static void | ||
80 | xpc_allow_IPI_ops_sn2(void) | ||
81 | { | ||
82 | int node; | ||
83 | int nasid; | ||
84 | |||
85 | /* !!! The following should get moved into SAL. */ | ||
86 | if (is_shub2()) { | ||
87 | xpc_sh2_IPI_access0_sn2 = | ||
88 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); | ||
89 | xpc_sh2_IPI_access1_sn2 = | ||
90 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); | ||
91 | xpc_sh2_IPI_access2_sn2 = | ||
92 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); | ||
93 | xpc_sh2_IPI_access3_sn2 = | ||
94 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); | ||
95 | |||
96 | for_each_online_node(node) { | ||
97 | nasid = cnodeid_to_nasid(node); | ||
98 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), | ||
99 | -1UL); | ||
100 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), | ||
101 | -1UL); | ||
102 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), | ||
103 | -1UL); | ||
104 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), | ||
105 | -1UL); | ||
106 | } | ||
107 | } else { | ||
108 | xpc_sh1_IPI_access_sn2 = | ||
109 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); | ||
110 | |||
111 | for_each_online_node(node) { | ||
112 | nasid = cnodeid_to_nasid(node); | ||
113 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), | ||
114 | -1UL); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Restrict protections to disallow IPI operations. | ||
121 | */ | ||
122 | static void | ||
123 | xpc_disallow_IPI_ops_sn2(void) | ||
124 | { | ||
125 | int node; | ||
126 | int nasid; | ||
127 | |||
128 | /* !!! The following should get moved into SAL. */ | ||
129 | if (is_shub2()) { | ||
130 | for_each_online_node(node) { | ||
131 | nasid = cnodeid_to_nasid(node); | ||
132 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), | ||
133 | xpc_sh2_IPI_access0_sn2); | ||
134 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), | ||
135 | xpc_sh2_IPI_access1_sn2); | ||
136 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), | ||
137 | xpc_sh2_IPI_access2_sn2); | ||
138 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), | ||
139 | xpc_sh2_IPI_access3_sn2); | ||
140 | } | ||
141 | } else { | ||
142 | for_each_online_node(node) { | ||
143 | nasid = cnodeid_to_nasid(node); | ||
144 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), | ||
145 | xpc_sh1_IPI_access_sn2); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * The following set of functions are used for the sending and receiving of | ||
152 | * IRQs (also known as IPIs). There are two flavors of IRQs, one that is | ||
153 | * associated with partition activity (SGI_XPC_ACTIVATE) and the other that | ||
154 | * is associated with channel activity (SGI_XPC_NOTIFY). | ||
155 | */ | ||
156 | |||
157 | static u64 | ||
158 | xpc_receive_IRQ_amo_sn2(struct amo *amo) | ||
159 | { | ||
160 | return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR); | ||
161 | } | ||
162 | |||
163 | static enum xp_retval | ||
164 | xpc_send_IRQ_sn2(struct amo *amo, u64 flag, int nasid, int phys_cpuid, | ||
165 | int vector) | ||
166 | { | ||
167 | int ret = 0; | ||
168 | unsigned long irq_flags; | ||
169 | |||
170 | local_irq_save(irq_flags); | ||
171 | |||
172 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, flag); | ||
173 | sn_send_IPI_phys(nasid, phys_cpuid, vector, 0); | ||
174 | |||
175 | /* | ||
176 | * We must always use the nofault function regardless of whether we | ||
177 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
178 | * didn't, we'd never know that the other partition is down and would | ||
179 | * keep sending IRQs and amos to it until the heartbeat times out. | ||
180 | */ | ||
181 | ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable), | ||
182 | xp_nofault_PIOR_target)); | ||
183 | |||
184 | local_irq_restore(irq_flags); | ||
185 | |||
186 | return (ret == 0) ? xpSuccess : xpPioReadError; | ||
187 | } | ||
188 | |||
189 | static struct amo * | ||
190 | xpc_init_IRQ_amo_sn2(int index) | ||
191 | { | ||
192 | struct amo *amo = xpc_vars_sn2->amos_page + index; | ||
193 | |||
194 | (void)xpc_receive_IRQ_amo_sn2(amo); /* clear amo variable */ | ||
195 | return amo; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Functions associated with SGI_XPC_ACTIVATE IRQ. | ||
200 | */ | ||
201 | |||
202 | /* | ||
203 | * Notify the heartbeat check thread that an activate IRQ has been received. | ||
204 | */ | ||
205 | static irqreturn_t | ||
206 | xpc_handle_activate_IRQ_sn2(int irq, void *dev_id) | ||
207 | { | ||
208 | unsigned long irq_flags; | ||
209 | |||
210 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
211 | xpc_activate_IRQ_rcvd++; | ||
212 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
213 | |||
214 | wake_up_interruptible(&xpc_activate_IRQ_wq); | ||
215 | return IRQ_HANDLED; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Flag the appropriate amo variable and send an IRQ to the specified node. | ||
220 | */ | ||
221 | static void | ||
222 | xpc_send_activate_IRQ_sn2(unsigned long amos_page_pa, int from_nasid, | ||
223 | int to_nasid, int to_phys_cpuid) | ||
224 | { | ||
225 | struct amo *amos = (struct amo *)__va(amos_page_pa + | ||
226 | (XPC_ACTIVATE_IRQ_AMOS_SN2 * | ||
227 | sizeof(struct amo))); | ||
228 | |||
229 | (void)xpc_send_IRQ_sn2(&amos[BIT_WORD(from_nasid / 2)], | ||
230 | BIT_MASK(from_nasid / 2), to_nasid, | ||
231 | to_phys_cpuid, SGI_XPC_ACTIVATE); | ||
232 | } | ||
233 | |||
234 | static void | ||
235 | xpc_send_local_activate_IRQ_sn2(int from_nasid) | ||
236 | { | ||
237 | unsigned long irq_flags; | ||
238 | struct amo *amos = (struct amo *)__va(xpc_vars_sn2->amos_page_pa + | ||
239 | (XPC_ACTIVATE_IRQ_AMOS_SN2 * | ||
240 | sizeof(struct amo))); | ||
241 | |||
242 | /* fake the sending and receipt of an activate IRQ from remote nasid */ | ||
243 | FETCHOP_STORE_OP(TO_AMO((u64)&amos[BIT_WORD(from_nasid / 2)].variable), | ||
244 | FETCHOP_OR, BIT_MASK(from_nasid / 2)); | ||
245 | |||
246 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
247 | xpc_activate_IRQ_rcvd++; | ||
248 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
249 | |||
250 | wake_up_interruptible(&xpc_activate_IRQ_wq); | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * Functions associated with SGI_XPC_NOTIFY IRQ. | ||
255 | */ | ||
256 | |||
257 | /* | ||
258 | * Check to see if any chctl flags were sent from the specified partition. | ||
259 | */ | ||
260 | static void | ||
261 | xpc_check_for_sent_chctl_flags_sn2(struct xpc_partition *part) | ||
262 | { | ||
263 | union xpc_channel_ctl_flags chctl; | ||
264 | unsigned long irq_flags; | ||
265 | |||
266 | chctl.all_flags = xpc_receive_IRQ_amo_sn2(part->sn.sn2. | ||
267 | local_chctl_amo_va); | ||
268 | if (chctl.all_flags == 0) | ||
269 | return; | ||
270 | |||
271 | spin_lock_irqsave(&part->chctl_lock, irq_flags); | ||
272 | part->chctl.all_flags |= chctl.all_flags; | ||
273 | spin_unlock_irqrestore(&part->chctl_lock, irq_flags); | ||
274 | |||
275 | dev_dbg(xpc_chan, "received notify IRQ from partid=%d, chctl.all_flags=" | ||
276 | "0x%lx\n", XPC_PARTID(part), chctl.all_flags); | ||
277 | |||
278 | xpc_wakeup_channel_mgr(part); | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified | ||
283 | * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more | ||
284 | * than one partition, we use an amo structure per partition to indicate | ||
285 | * whether a partition has sent an IRQ or not. If it has, then wake up the | ||
286 | * associated kthread to handle it. | ||
287 | * | ||
288 | * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IRQs sent by XPC | ||
289 | * running on other partitions. | ||
290 | * | ||
291 | * Noteworthy Arguments: | ||
292 | * | ||
293 | * irq - Interrupt ReQuest number. NOT USED. | ||
294 | * | ||
295 | * dev_id - partid of IRQ's potential sender. | ||
296 | */ | ||
297 | static irqreturn_t | ||
298 | xpc_handle_notify_IRQ_sn2(int irq, void *dev_id) | ||
299 | { | ||
300 | short partid = (short)(u64)dev_id; | ||
301 | struct xpc_partition *part = &xpc_partitions[partid]; | ||
302 | |||
303 | DBUG_ON(partid < 0 || partid >= XP_MAX_NPARTITIONS_SN2); | ||
304 | |||
305 | if (xpc_part_ref(part)) { | ||
306 | xpc_check_for_sent_chctl_flags_sn2(part); | ||
307 | |||
308 | xpc_part_deref(part); | ||
309 | } | ||
310 | return IRQ_HANDLED; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * Check to see if xpc_handle_notify_IRQ_sn2() dropped any IRQs on the floor | ||
315 | * because the write to their associated amo variable completed after the IRQ | ||
316 | * was received. | ||
317 | */ | ||
318 | static void | ||
319 | xpc_check_for_dropped_notify_IRQ_sn2(struct xpc_partition *part) | ||
320 | { | ||
321 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
322 | |||
323 | if (xpc_part_ref(part)) { | ||
324 | xpc_check_for_sent_chctl_flags_sn2(part); | ||
325 | |||
326 | part_sn2->dropped_notify_IRQ_timer.expires = jiffies + | ||
327 | XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL; | ||
328 | add_timer(&part_sn2->dropped_notify_IRQ_timer); | ||
329 | xpc_part_deref(part); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Send a notify IRQ to the remote partition that is associated with the | ||
335 | * specified channel. | ||
336 | */ | ||
337 | static void | ||
338 | xpc_send_notify_IRQ_sn2(struct xpc_channel *ch, u8 chctl_flag, | ||
339 | char *chctl_flag_string, unsigned long *irq_flags) | ||
340 | { | ||
341 | struct xpc_partition *part = &xpc_partitions[ch->partid]; | ||
342 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
343 | union xpc_channel_ctl_flags chctl = { 0 }; | ||
344 | enum xp_retval ret; | ||
345 | |||
346 | if (likely(part->act_state != XPC_P_AS_DEACTIVATING)) { | ||
347 | chctl.flags[ch->number] = chctl_flag; | ||
348 | ret = xpc_send_IRQ_sn2(part_sn2->remote_chctl_amo_va, | ||
349 | chctl.all_flags, | ||
350 | part_sn2->notify_IRQ_nasid, | ||
351 | part_sn2->notify_IRQ_phys_cpuid, | ||
352 | SGI_XPC_NOTIFY); | ||
353 | dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n", | ||
354 | chctl_flag_string, ch->partid, ch->number, ret); | ||
355 | if (unlikely(ret != xpSuccess)) { | ||
356 | if (irq_flags != NULL) | ||
357 | spin_unlock_irqrestore(&ch->lock, *irq_flags); | ||
358 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
359 | if (irq_flags != NULL) | ||
360 | spin_lock_irqsave(&ch->lock, *irq_flags); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | |||
365 | #define XPC_SEND_NOTIFY_IRQ_SN2(_ch, _ipi_f, _irq_f) \ | ||
366 | xpc_send_notify_IRQ_sn2(_ch, _ipi_f, #_ipi_f, _irq_f) | ||
367 | |||
368 | /* | ||
369 | * Make it look like the remote partition, which is associated with the | ||
370 | * specified channel, sent us a notify IRQ. This faked IRQ will be handled | ||
371 | * by xpc_check_for_dropped_notify_IRQ_sn2(). | ||
372 | */ | ||
373 | static void | ||
374 | xpc_send_local_notify_IRQ_sn2(struct xpc_channel *ch, u8 chctl_flag, | ||
375 | char *chctl_flag_string) | ||
376 | { | ||
377 | struct xpc_partition *part = &xpc_partitions[ch->partid]; | ||
378 | union xpc_channel_ctl_flags chctl = { 0 }; | ||
379 | |||
380 | chctl.flags[ch->number] = chctl_flag; | ||
381 | FETCHOP_STORE_OP(TO_AMO((u64)&part->sn.sn2.local_chctl_amo_va-> | ||
382 | variable), FETCHOP_OR, chctl.all_flags); | ||
383 | dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n", | ||
384 | chctl_flag_string, ch->partid, ch->number); | ||
385 | } | ||
386 | |||
387 | #define XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(_ch, _ipi_f) \ | ||
388 | xpc_send_local_notify_IRQ_sn2(_ch, _ipi_f, #_ipi_f) | ||
389 | |||
390 | static void | ||
391 | xpc_send_chctl_closerequest_sn2(struct xpc_channel *ch, | ||
392 | unsigned long *irq_flags) | ||
393 | { | ||
394 | struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args; | ||
395 | |||
396 | args->reason = ch->reason; | ||
397 | XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREQUEST, irq_flags); | ||
398 | } | ||
399 | |||
400 | static void | ||
401 | xpc_send_chctl_closereply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) | ||
402 | { | ||
403 | XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREPLY, irq_flags); | ||
404 | } | ||
405 | |||
406 | static void | ||
407 | xpc_send_chctl_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) | ||
408 | { | ||
409 | struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args; | ||
410 | |||
411 | args->entry_size = ch->entry_size; | ||
412 | args->local_nentries = ch->local_nentries; | ||
413 | XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREQUEST, irq_flags); | ||
414 | } | ||
415 | |||
416 | static void | ||
417 | xpc_send_chctl_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) | ||
418 | { | ||
419 | struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args; | ||
420 | |||
421 | args->remote_nentries = ch->remote_nentries; | ||
422 | args->local_nentries = ch->local_nentries; | ||
423 | args->local_msgqueue_pa = xp_pa(ch->sn.sn2.local_msgqueue); | ||
424 | XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREPLY, irq_flags); | ||
425 | } | ||
426 | |||
427 | static void | ||
428 | xpc_send_chctl_msgrequest_sn2(struct xpc_channel *ch) | ||
429 | { | ||
430 | XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST, NULL); | ||
431 | } | ||
432 | |||
433 | static void | ||
434 | xpc_send_chctl_local_msgrequest_sn2(struct xpc_channel *ch) | ||
435 | { | ||
436 | XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST); | ||
437 | } | ||
438 | |||
439 | static void | ||
440 | xpc_save_remote_msgqueue_pa_sn2(struct xpc_channel *ch, | ||
441 | unsigned long msgqueue_pa) | ||
442 | { | ||
443 | ch->sn.sn2.remote_msgqueue_pa = msgqueue_pa; | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * This next set of functions are used to keep track of when a partition is | ||
448 | * potentially engaged in accessing memory belonging to another partition. | ||
449 | */ | ||
450 | |||
451 | static void | ||
452 | xpc_indicate_partition_engaged_sn2(struct xpc_partition *part) | ||
453 | { | ||
454 | unsigned long irq_flags; | ||
455 | struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa + | ||
456 | (XPC_ENGAGED_PARTITIONS_AMO_SN2 * | ||
457 | sizeof(struct amo))); | ||
458 | |||
459 | local_irq_save(irq_flags); | ||
460 | |||
461 | /* set bit corresponding to our partid in remote partition's amo */ | ||
462 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, | ||
463 | BIT(sn_partition_id)); | ||
464 | |||
465 | /* | ||
466 | * We must always use the nofault function regardless of whether we | ||
467 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
468 | * didn't, we'd never know that the other partition is down and would | ||
469 | * keep sending IRQs and amos to it until the heartbeat times out. | ||
470 | */ | ||
471 | (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> | ||
472 | variable), | ||
473 | xp_nofault_PIOR_target)); | ||
474 | |||
475 | local_irq_restore(irq_flags); | ||
476 | } | ||
477 | |||
478 | static void | ||
479 | xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) | ||
480 | { | ||
481 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
482 | unsigned long irq_flags; | ||
483 | struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa + | ||
484 | (XPC_ENGAGED_PARTITIONS_AMO_SN2 * | ||
485 | sizeof(struct amo))); | ||
486 | |||
487 | local_irq_save(irq_flags); | ||
488 | |||
489 | /* clear bit corresponding to our partid in remote partition's amo */ | ||
490 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, | ||
491 | ~BIT(sn_partition_id)); | ||
492 | |||
493 | /* | ||
494 | * We must always use the nofault function regardless of whether we | ||
495 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
496 | * didn't, we'd never know that the other partition is down and would | ||
497 | * keep sending IRQs and amos to it until the heartbeat times out. | ||
498 | */ | ||
499 | (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> | ||
500 | variable), | ||
501 | xp_nofault_PIOR_target)); | ||
502 | |||
503 | local_irq_restore(irq_flags); | ||
504 | |||
505 | /* | ||
506 | * Send activate IRQ to get other side to see that we've cleared our | ||
507 | * bit in their engaged partitions amo. | ||
508 | */ | ||
509 | xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa, | ||
510 | cnodeid_to_nasid(0), | ||
511 | part_sn2->activate_IRQ_nasid, | ||
512 | part_sn2->activate_IRQ_phys_cpuid); | ||
513 | } | ||
514 | |||
515 | static void | ||
516 | xpc_assume_partition_disengaged_sn2(short partid) | ||
517 | { | ||
518 | struct amo *amo = xpc_vars_sn2->amos_page + | ||
519 | XPC_ENGAGED_PARTITIONS_AMO_SN2; | ||
520 | |||
521 | /* clear bit(s) based on partid mask in our partition's amo */ | ||
522 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, | ||
523 | ~BIT(partid)); | ||
524 | } | ||
525 | |||
526 | static int | ||
527 | xpc_partition_engaged_sn2(short partid) | ||
528 | { | ||
529 | struct amo *amo = xpc_vars_sn2->amos_page + | ||
530 | XPC_ENGAGED_PARTITIONS_AMO_SN2; | ||
531 | |||
532 | /* our partition's amo variable ANDed with partid mask */ | ||
533 | return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & | ||
534 | BIT(partid)) != 0; | ||
535 | } | ||
536 | |||
537 | static int | ||
538 | xpc_any_partition_engaged_sn2(void) | ||
539 | { | ||
540 | struct amo *amo = xpc_vars_sn2->amos_page + | ||
541 | XPC_ENGAGED_PARTITIONS_AMO_SN2; | ||
542 | |||
543 | /* our partition's amo variable */ | ||
544 | return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) != 0; | ||
545 | } | ||
546 | |||
547 | /* original protection values for each node */ | ||
548 | static u64 xpc_prot_vec_sn2[MAX_NUMNODES]; | ||
549 | |||
550 | /* | ||
551 | * Change protections to allow amo operations on non-Shub 1.1 systems. | ||
552 | */ | ||
553 | static enum xp_retval | ||
554 | xpc_allow_amo_ops_sn2(struct amo *amos_page) | ||
555 | { | ||
556 | u64 nasid_array = 0; | ||
557 | int ret; | ||
558 | |||
559 | /* | ||
560 | * On SHUB 1.1, we cannot call sn_change_memprotect() since the BIST | ||
561 | * collides with memory operations. On those systems we call | ||
562 | * xpc_allow_amo_ops_shub_wars_1_1_sn2() instead. | ||
563 | */ | ||
564 | if (!enable_shub_wars_1_1()) { | ||
565 | ret = sn_change_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE, | ||
566 | SN_MEMPROT_ACCESS_CLASS_1, | ||
567 | &nasid_array); | ||
568 | if (ret != 0) | ||
569 | return xpSalError; | ||
570 | } | ||
571 | return xpSuccess; | ||
572 | } | ||
573 | |||
574 | /* | ||
575 | * Change protections to allow amo operations on Shub 1.1 systems. | ||
576 | */ | ||
577 | static void | ||
578 | xpc_allow_amo_ops_shub_wars_1_1_sn2(void) | ||
579 | { | ||
580 | int node; | ||
581 | int nasid; | ||
582 | |||
583 | if (!enable_shub_wars_1_1()) | ||
584 | return; | ||
585 | |||
586 | for_each_online_node(node) { | ||
587 | nasid = cnodeid_to_nasid(node); | ||
588 | /* save current protection values */ | ||
589 | xpc_prot_vec_sn2[node] = | ||
590 | (u64)HUB_L((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
591 | SH1_MD_DQLP_MMR_DIR_PRIVEC0)); | ||
592 | /* open up everything */ | ||
593 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
594 | SH1_MD_DQLP_MMR_DIR_PRIVEC0), | ||
595 | -1UL); | ||
596 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
597 | SH1_MD_DQRP_MMR_DIR_PRIVEC0), | ||
598 | -1UL); | ||
599 | } | ||
600 | } | ||
601 | |||
602 | static enum xp_retval | ||
603 | xpc_get_partition_rsvd_page_pa_sn2(void *buf, u64 *cookie, unsigned long *rp_pa, | ||
604 | size_t *len) | ||
605 | { | ||
606 | s64 status; | ||
607 | enum xp_retval ret; | ||
608 | |||
609 | status = sn_partition_reserved_page_pa((u64)buf, cookie, rp_pa, len); | ||
610 | if (status == SALRET_OK) | ||
611 | ret = xpSuccess; | ||
612 | else if (status == SALRET_MORE_PASSES) | ||
613 | ret = xpNeedMoreInfo; | ||
614 | else | ||
615 | ret = xpSalError; | ||
616 | |||
617 | return ret; | ||
618 | } | ||
619 | |||
620 | |||
621 | static int | ||
622 | xpc_setup_rsvd_page_sn_sn2(struct xpc_rsvd_page *rp) | ||
623 | { | ||
624 | struct amo *amos_page; | ||
625 | int i; | ||
626 | int ret; | ||
627 | |||
628 | xpc_vars_sn2 = XPC_RP_VARS(rp); | ||
629 | |||
630 | rp->sn.vars_pa = xp_pa(xpc_vars_sn2); | ||
631 | |||
632 | /* vars_part array follows immediately after vars */ | ||
633 | xpc_vars_part_sn2 = (struct xpc_vars_part_sn2 *)((u8 *)XPC_RP_VARS(rp) + | ||
634 | XPC_RP_VARS_SIZE); | ||
635 | |||
636 | /* | ||
637 | * Before clearing xpc_vars_sn2, see if a page of amos had been | ||
638 | * previously allocated. If not we'll need to allocate one and set | ||
639 | * permissions so that cross-partition amos are allowed. | ||
640 | * | ||
641 | * The allocated amo page needs MCA reporting to remain disabled after | ||
642 | * XPC has unloaded. To make this work, we keep a copy of the pointer | ||
643 | * to this page (i.e., amos_page) in the struct xpc_vars_sn2 structure, | ||
644 | * which is pointed to by the reserved page, and re-use that saved copy | ||
645 | * on subsequent loads of XPC. This amo page is never freed, and its | ||
646 | * memory protections are never restricted. | ||
647 | */ | ||
648 | amos_page = xpc_vars_sn2->amos_page; | ||
649 | if (amos_page == NULL) { | ||
650 | amos_page = (struct amo *)TO_AMO(uncached_alloc_page(0, 1)); | ||
651 | if (amos_page == NULL) { | ||
652 | dev_err(xpc_part, "can't allocate page of amos\n"); | ||
653 | return -ENOMEM; | ||
654 | } | ||
655 | |||
656 | /* | ||
657 | * Open up amo-R/W to cpu. This is done on Shub 1.1 systems | ||
658 | * when xpc_allow_amo_ops_shub_wars_1_1_sn2() is called. | ||
659 | */ | ||
660 | ret = xpc_allow_amo_ops_sn2(amos_page); | ||
661 | if (ret != xpSuccess) { | ||
662 | dev_err(xpc_part, "can't allow amo operations\n"); | ||
663 | uncached_free_page(__IA64_UNCACHED_OFFSET | | ||
664 | TO_PHYS((u64)amos_page), 1); | ||
665 | return -EPERM; | ||
666 | } | ||
667 | } | ||
668 | |||
669 | /* clear xpc_vars_sn2 */ | ||
670 | memset(xpc_vars_sn2, 0, sizeof(struct xpc_vars_sn2)); | ||
671 | |||
672 | xpc_vars_sn2->version = XPC_V_VERSION; | ||
673 | xpc_vars_sn2->activate_IRQ_nasid = cpuid_to_nasid(0); | ||
674 | xpc_vars_sn2->activate_IRQ_phys_cpuid = cpu_physical_id(0); | ||
675 | xpc_vars_sn2->vars_part_pa = xp_pa(xpc_vars_part_sn2); | ||
676 | xpc_vars_sn2->amos_page_pa = ia64_tpa((u64)amos_page); | ||
677 | xpc_vars_sn2->amos_page = amos_page; /* save for next load of XPC */ | ||
678 | |||
679 | /* clear xpc_vars_part_sn2 */ | ||
680 | memset((u64 *)xpc_vars_part_sn2, 0, sizeof(struct xpc_vars_part_sn2) * | ||
681 | XP_MAX_NPARTITIONS_SN2); | ||
682 | |||
683 | /* initialize the activate IRQ related amo variables */ | ||
684 | for (i = 0; i < xpc_nasid_mask_nlongs; i++) | ||
685 | (void)xpc_init_IRQ_amo_sn2(XPC_ACTIVATE_IRQ_AMOS_SN2 + i); | ||
686 | |||
687 | /* initialize the engaged remote partitions related amo variables */ | ||
688 | (void)xpc_init_IRQ_amo_sn2(XPC_ENGAGED_PARTITIONS_AMO_SN2); | ||
689 | (void)xpc_init_IRQ_amo_sn2(XPC_DEACTIVATE_REQUEST_AMO_SN2); | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static void | ||
695 | xpc_increment_heartbeat_sn2(void) | ||
696 | { | ||
697 | xpc_vars_sn2->heartbeat++; | ||
698 | } | ||
699 | |||
700 | static void | ||
701 | xpc_offline_heartbeat_sn2(void) | ||
702 | { | ||
703 | xpc_increment_heartbeat_sn2(); | ||
704 | xpc_vars_sn2->heartbeat_offline = 1; | ||
705 | } | ||
706 | |||
707 | static void | ||
708 | xpc_online_heartbeat_sn2(void) | ||
709 | { | ||
710 | xpc_increment_heartbeat_sn2(); | ||
711 | xpc_vars_sn2->heartbeat_offline = 0; | ||
712 | } | ||
713 | |||
714 | static void | ||
715 | xpc_heartbeat_init_sn2(void) | ||
716 | { | ||
717 | DBUG_ON(xpc_vars_sn2 == NULL); | ||
718 | |||
719 | bitmap_zero(xpc_vars_sn2->heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2); | ||
720 | xpc_heartbeating_to_mask = &xpc_vars_sn2->heartbeating_to_mask[0]; | ||
721 | xpc_online_heartbeat_sn2(); | ||
722 | } | ||
723 | |||
724 | static void | ||
725 | xpc_heartbeat_exit_sn2(void) | ||
726 | { | ||
727 | xpc_offline_heartbeat_sn2(); | ||
728 | } | ||
729 | |||
730 | static enum xp_retval | ||
731 | xpc_get_remote_heartbeat_sn2(struct xpc_partition *part) | ||
732 | { | ||
733 | struct xpc_vars_sn2 *remote_vars; | ||
734 | enum xp_retval ret; | ||
735 | |||
736 | remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2; | ||
737 | |||
738 | /* pull the remote vars structure that contains the heartbeat */ | ||
739 | ret = xp_remote_memcpy(xp_pa(remote_vars), | ||
740 | part->sn.sn2.remote_vars_pa, | ||
741 | XPC_RP_VARS_SIZE); | ||
742 | if (ret != xpSuccess) | ||
743 | return ret; | ||
744 | |||
745 | dev_dbg(xpc_part, "partid=%d, heartbeat=%ld, last_heartbeat=%ld, " | ||
746 | "heartbeat_offline=%ld, HB_mask[0]=0x%lx\n", XPC_PARTID(part), | ||
747 | remote_vars->heartbeat, part->last_heartbeat, | ||
748 | remote_vars->heartbeat_offline, | ||
749 | remote_vars->heartbeating_to_mask[0]); | ||
750 | |||
751 | if ((remote_vars->heartbeat == part->last_heartbeat && | ||
752 | remote_vars->heartbeat_offline == 0) || | ||
753 | !xpc_hb_allowed(sn_partition_id, | ||
754 | &remote_vars->heartbeating_to_mask)) { | ||
755 | ret = xpNoHeartbeat; | ||
756 | } else { | ||
757 | part->last_heartbeat = remote_vars->heartbeat; | ||
758 | } | ||
759 | |||
760 | return ret; | ||
761 | } | ||
762 | |||
763 | /* | ||
764 | * Get a copy of the remote partition's XPC variables from the reserved page. | ||
765 | * | ||
766 | * remote_vars points to a buffer that is cacheline aligned for BTE copies and | ||
767 | * assumed to be of size XPC_RP_VARS_SIZE. | ||
768 | */ | ||
769 | static enum xp_retval | ||
770 | xpc_get_remote_vars_sn2(unsigned long remote_vars_pa, | ||
771 | struct xpc_vars_sn2 *remote_vars) | ||
772 | { | ||
773 | enum xp_retval ret; | ||
774 | |||
775 | if (remote_vars_pa == 0) | ||
776 | return xpVarsNotSet; | ||
777 | |||
778 | /* pull over the cross partition variables */ | ||
779 | ret = xp_remote_memcpy(xp_pa(remote_vars), remote_vars_pa, | ||
780 | XPC_RP_VARS_SIZE); | ||
781 | if (ret != xpSuccess) | ||
782 | return ret; | ||
783 | |||
784 | if (XPC_VERSION_MAJOR(remote_vars->version) != | ||
785 | XPC_VERSION_MAJOR(XPC_V_VERSION)) { | ||
786 | return xpBadVersion; | ||
787 | } | ||
788 | |||
789 | return xpSuccess; | ||
790 | } | ||
791 | |||
792 | static void | ||
793 | xpc_request_partition_activation_sn2(struct xpc_rsvd_page *remote_rp, | ||
794 | unsigned long remote_rp_pa, int nasid) | ||
795 | { | ||
796 | xpc_send_local_activate_IRQ_sn2(nasid); | ||
797 | } | ||
798 | |||
799 | static void | ||
800 | xpc_request_partition_reactivation_sn2(struct xpc_partition *part) | ||
801 | { | ||
802 | xpc_send_local_activate_IRQ_sn2(part->sn.sn2.activate_IRQ_nasid); | ||
803 | } | ||
804 | |||
805 | static void | ||
806 | xpc_request_partition_deactivation_sn2(struct xpc_partition *part) | ||
807 | { | ||
808 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
809 | unsigned long irq_flags; | ||
810 | struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa + | ||
811 | (XPC_DEACTIVATE_REQUEST_AMO_SN2 * | ||
812 | sizeof(struct amo))); | ||
813 | |||
814 | local_irq_save(irq_flags); | ||
815 | |||
816 | /* set bit corresponding to our partid in remote partition's amo */ | ||
817 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, | ||
818 | BIT(sn_partition_id)); | ||
819 | |||
820 | /* | ||
821 | * We must always use the nofault function regardless of whether we | ||
822 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
823 | * didn't, we'd never know that the other partition is down and would | ||
824 | * keep sending IRQs and amos to it until the heartbeat times out. | ||
825 | */ | ||
826 | (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> | ||
827 | variable), | ||
828 | xp_nofault_PIOR_target)); | ||
829 | |||
830 | local_irq_restore(irq_flags); | ||
831 | |||
832 | /* | ||
833 | * Send activate IRQ to get other side to see that we've set our | ||
834 | * bit in their deactivate request amo. | ||
835 | */ | ||
836 | xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa, | ||
837 | cnodeid_to_nasid(0), | ||
838 | part_sn2->activate_IRQ_nasid, | ||
839 | part_sn2->activate_IRQ_phys_cpuid); | ||
840 | } | ||
841 | |||
842 | static void | ||
843 | xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part) | ||
844 | { | ||
845 | unsigned long irq_flags; | ||
846 | struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa + | ||
847 | (XPC_DEACTIVATE_REQUEST_AMO_SN2 * | ||
848 | sizeof(struct amo))); | ||
849 | |||
850 | local_irq_save(irq_flags); | ||
851 | |||
852 | /* clear bit corresponding to our partid in remote partition's amo */ | ||
853 | FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, | ||
854 | ~BIT(sn_partition_id)); | ||
855 | |||
856 | /* | ||
857 | * We must always use the nofault function regardless of whether we | ||
858 | * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we | ||
859 | * didn't, we'd never know that the other partition is down and would | ||
860 | * keep sending IRQs and amos to it until the heartbeat times out. | ||
861 | */ | ||
862 | (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> | ||
863 | variable), | ||
864 | xp_nofault_PIOR_target)); | ||
865 | |||
866 | local_irq_restore(irq_flags); | ||
867 | } | ||
868 | |||
869 | static int | ||
870 | xpc_partition_deactivation_requested_sn2(short partid) | ||
871 | { | ||
872 | struct amo *amo = xpc_vars_sn2->amos_page + | ||
873 | XPC_DEACTIVATE_REQUEST_AMO_SN2; | ||
874 | |||
875 | /* our partition's amo variable ANDed with partid mask */ | ||
876 | return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & | ||
877 | BIT(partid)) != 0; | ||
878 | } | ||
879 | |||
880 | /* | ||
881 | * Update the remote partition's info. | ||
882 | */ | ||
883 | static void | ||
884 | xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, | ||
885 | unsigned long *remote_rp_ts_jiffies, | ||
886 | unsigned long remote_rp_pa, | ||
887 | unsigned long remote_vars_pa, | ||
888 | struct xpc_vars_sn2 *remote_vars) | ||
889 | { | ||
890 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
891 | |||
892 | part->remote_rp_version = remote_rp_version; | ||
893 | dev_dbg(xpc_part, " remote_rp_version = 0x%016x\n", | ||
894 | part->remote_rp_version); | ||
895 | |||
896 | part->remote_rp_ts_jiffies = *remote_rp_ts_jiffies; | ||
897 | dev_dbg(xpc_part, " remote_rp_ts_jiffies = 0x%016lx\n", | ||
898 | part->remote_rp_ts_jiffies); | ||
899 | |||
900 | part->remote_rp_pa = remote_rp_pa; | ||
901 | dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa); | ||
902 | |||
903 | part_sn2->remote_vars_pa = remote_vars_pa; | ||
904 | dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", | ||
905 | part_sn2->remote_vars_pa); | ||
906 | |||
907 | part->last_heartbeat = remote_vars->heartbeat; | ||
908 | dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", | ||
909 | part->last_heartbeat); | ||
910 | |||
911 | part_sn2->remote_vars_part_pa = remote_vars->vars_part_pa; | ||
912 | dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", | ||
913 | part_sn2->remote_vars_part_pa); | ||
914 | |||
915 | part_sn2->activate_IRQ_nasid = remote_vars->activate_IRQ_nasid; | ||
916 | dev_dbg(xpc_part, " activate_IRQ_nasid = 0x%x\n", | ||
917 | part_sn2->activate_IRQ_nasid); | ||
918 | |||
919 | part_sn2->activate_IRQ_phys_cpuid = | ||
920 | remote_vars->activate_IRQ_phys_cpuid; | ||
921 | dev_dbg(xpc_part, " activate_IRQ_phys_cpuid = 0x%x\n", | ||
922 | part_sn2->activate_IRQ_phys_cpuid); | ||
923 | |||
924 | part_sn2->remote_amos_page_pa = remote_vars->amos_page_pa; | ||
925 | dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n", | ||
926 | part_sn2->remote_amos_page_pa); | ||
927 | |||
928 | part_sn2->remote_vars_version = remote_vars->version; | ||
929 | dev_dbg(xpc_part, " remote_vars_version = 0x%x\n", | ||
930 | part_sn2->remote_vars_version); | ||
931 | } | ||
932 | |||
933 | /* | ||
934 | * Prior code has determined the nasid which generated a activate IRQ. | ||
935 | * Inspect that nasid to determine if its partition needs to be activated | ||
936 | * or deactivated. | ||
937 | * | ||
938 | * A partition is considered "awaiting activation" if our partition | ||
939 | * flags indicate it is not active and it has a heartbeat. A | ||
940 | * partition is considered "awaiting deactivation" if our partition | ||
941 | * flags indicate it is active but it has no heartbeat or it is not | ||
942 | * sending its heartbeat to us. | ||
943 | * | ||
944 | * To determine the heartbeat, the remote nasid must have a properly | ||
945 | * initialized reserved page. | ||
946 | */ | ||
947 | static void | ||
948 | xpc_identify_activate_IRQ_req_sn2(int nasid) | ||
949 | { | ||
950 | struct xpc_rsvd_page *remote_rp; | ||
951 | struct xpc_vars_sn2 *remote_vars; | ||
952 | unsigned long remote_rp_pa; | ||
953 | unsigned long remote_vars_pa; | ||
954 | int remote_rp_version; | ||
955 | int reactivate = 0; | ||
956 | unsigned long remote_rp_ts_jiffies = 0; | ||
957 | short partid; | ||
958 | struct xpc_partition *part; | ||
959 | struct xpc_partition_sn2 *part_sn2; | ||
960 | enum xp_retval ret; | ||
961 | |||
962 | /* pull over the reserved page structure */ | ||
963 | |||
964 | remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer_sn2; | ||
965 | |||
966 | ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa); | ||
967 | if (ret != xpSuccess) { | ||
968 | dev_warn(xpc_part, "unable to get reserved page from nasid %d, " | ||
969 | "which sent interrupt, reason=%d\n", nasid, ret); | ||
970 | return; | ||
971 | } | ||
972 | |||
973 | remote_vars_pa = remote_rp->sn.vars_pa; | ||
974 | remote_rp_version = remote_rp->version; | ||
975 | remote_rp_ts_jiffies = remote_rp->ts_jiffies; | ||
976 | |||
977 | partid = remote_rp->SAL_partid; | ||
978 | part = &xpc_partitions[partid]; | ||
979 | part_sn2 = &part->sn.sn2; | ||
980 | |||
981 | /* pull over the cross partition variables */ | ||
982 | |||
983 | remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2; | ||
984 | |||
985 | ret = xpc_get_remote_vars_sn2(remote_vars_pa, remote_vars); | ||
986 | if (ret != xpSuccess) { | ||
987 | dev_warn(xpc_part, "unable to get XPC variables from nasid %d, " | ||
988 | "which sent interrupt, reason=%d\n", nasid, ret); | ||
989 | |||
990 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
991 | return; | ||
992 | } | ||
993 | |||
994 | part->activate_IRQ_rcvd++; | ||
995 | |||
996 | dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = " | ||
997 | "%ld:0x%lx\n", (int)nasid, (int)partid, part->activate_IRQ_rcvd, | ||
998 | remote_vars->heartbeat, remote_vars->heartbeating_to_mask[0]); | ||
999 | |||
1000 | if (xpc_partition_disengaged(part) && | ||
1001 | part->act_state == XPC_P_AS_INACTIVE) { | ||
1002 | |||
1003 | xpc_update_partition_info_sn2(part, remote_rp_version, | ||
1004 | &remote_rp_ts_jiffies, | ||
1005 | remote_rp_pa, remote_vars_pa, | ||
1006 | remote_vars); | ||
1007 | |||
1008 | if (xpc_partition_deactivation_requested_sn2(partid)) { | ||
1009 | /* | ||
1010 | * Other side is waiting on us to deactivate even though | ||
1011 | * we already have. | ||
1012 | */ | ||
1013 | return; | ||
1014 | } | ||
1015 | |||
1016 | xpc_activate_partition(part); | ||
1017 | return; | ||
1018 | } | ||
1019 | |||
1020 | DBUG_ON(part->remote_rp_version == 0); | ||
1021 | DBUG_ON(part_sn2->remote_vars_version == 0); | ||
1022 | |||
1023 | if (remote_rp_ts_jiffies != part->remote_rp_ts_jiffies) { | ||
1024 | |||
1025 | /* the other side rebooted */ | ||
1026 | |||
1027 | DBUG_ON(xpc_partition_engaged_sn2(partid)); | ||
1028 | DBUG_ON(xpc_partition_deactivation_requested_sn2(partid)); | ||
1029 | |||
1030 | xpc_update_partition_info_sn2(part, remote_rp_version, | ||
1031 | &remote_rp_ts_jiffies, | ||
1032 | remote_rp_pa, remote_vars_pa, | ||
1033 | remote_vars); | ||
1034 | reactivate = 1; | ||
1035 | } | ||
1036 | |||
1037 | if (part->disengage_timeout > 0 && !xpc_partition_disengaged(part)) { | ||
1038 | /* still waiting on other side to disengage from us */ | ||
1039 | return; | ||
1040 | } | ||
1041 | |||
1042 | if (reactivate) | ||
1043 | XPC_DEACTIVATE_PARTITION(part, xpReactivating); | ||
1044 | else if (xpc_partition_deactivation_requested_sn2(partid)) | ||
1045 | XPC_DEACTIVATE_PARTITION(part, xpOtherGoingDown); | ||
1046 | } | ||
1047 | |||
1048 | /* | ||
1049 | * Loop through the activation amo variables and process any bits | ||
1050 | * which are set. Each bit indicates a nasid sending a partition | ||
1051 | * activation or deactivation request. | ||
1052 | * | ||
1053 | * Return #of IRQs detected. | ||
1054 | */ | ||
1055 | int | ||
1056 | xpc_identify_activate_IRQ_sender_sn2(void) | ||
1057 | { | ||
1058 | int l; | ||
1059 | int b; | ||
1060 | unsigned long nasid_mask_long; | ||
1061 | u64 nasid; /* remote nasid */ | ||
1062 | int n_IRQs_detected = 0; | ||
1063 | struct amo *act_amos; | ||
1064 | |||
1065 | act_amos = xpc_vars_sn2->amos_page + XPC_ACTIVATE_IRQ_AMOS_SN2; | ||
1066 | |||
1067 | /* scan through activate amo variables looking for non-zero entries */ | ||
1068 | for (l = 0; l < xpc_nasid_mask_nlongs; l++) { | ||
1069 | |||
1070 | if (xpc_exiting) | ||
1071 | break; | ||
1072 | |||
1073 | nasid_mask_long = xpc_receive_IRQ_amo_sn2(&act_amos[l]); | ||
1074 | |||
1075 | b = find_first_bit(&nasid_mask_long, BITS_PER_LONG); | ||
1076 | if (b >= BITS_PER_LONG) { | ||
1077 | /* no IRQs from nasids in this amo variable */ | ||
1078 | continue; | ||
1079 | } | ||
1080 | |||
1081 | dev_dbg(xpc_part, "amo[%d] gave back 0x%lx\n", l, | ||
1082 | nasid_mask_long); | ||
1083 | |||
1084 | /* | ||
1085 | * If this nasid has been added to the machine since | ||
1086 | * our partition was reset, this will retain the | ||
1087 | * remote nasid in our reserved pages machine mask. | ||
1088 | * This is used in the event of module reload. | ||
1089 | */ | ||
1090 | xpc_mach_nasids[l] |= nasid_mask_long; | ||
1091 | |||
1092 | /* locate the nasid(s) which sent interrupts */ | ||
1093 | |||
1094 | do { | ||
1095 | n_IRQs_detected++; | ||
1096 | nasid = (l * BITS_PER_LONG + b) * 2; | ||
1097 | dev_dbg(xpc_part, "interrupt from nasid %ld\n", nasid); | ||
1098 | xpc_identify_activate_IRQ_req_sn2(nasid); | ||
1099 | |||
1100 | b = find_next_bit(&nasid_mask_long, BITS_PER_LONG, | ||
1101 | b + 1); | ||
1102 | } while (b < BITS_PER_LONG); | ||
1103 | } | ||
1104 | return n_IRQs_detected; | ||
1105 | } | ||
1106 | |||
1107 | static void | ||
1108 | xpc_process_activate_IRQ_rcvd_sn2(void) | ||
1109 | { | ||
1110 | unsigned long irq_flags; | ||
1111 | int n_IRQs_expected; | ||
1112 | int n_IRQs_detected; | ||
1113 | |||
1114 | DBUG_ON(xpc_activate_IRQ_rcvd == 0); | ||
1115 | |||
1116 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
1117 | n_IRQs_expected = xpc_activate_IRQ_rcvd; | ||
1118 | xpc_activate_IRQ_rcvd = 0; | ||
1119 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
1120 | |||
1121 | n_IRQs_detected = xpc_identify_activate_IRQ_sender_sn2(); | ||
1122 | if (n_IRQs_detected < n_IRQs_expected) { | ||
1123 | /* retry once to help avoid missing amo */ | ||
1124 | (void)xpc_identify_activate_IRQ_sender_sn2(); | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | /* | ||
1129 | * Setup the channel structures that are sn2 specific. | ||
1130 | */ | ||
1131 | static enum xp_retval | ||
1132 | xpc_setup_ch_structures_sn_sn2(struct xpc_partition *part) | ||
1133 | { | ||
1134 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
1135 | struct xpc_channel_sn2 *ch_sn2; | ||
1136 | enum xp_retval retval; | ||
1137 | int ret; | ||
1138 | int cpuid; | ||
1139 | int ch_number; | ||
1140 | struct timer_list *timer; | ||
1141 | short partid = XPC_PARTID(part); | ||
1142 | |||
1143 | /* allocate all the required GET/PUT values */ | ||
1144 | |||
1145 | part_sn2->local_GPs = | ||
1146 | xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL, | ||
1147 | &part_sn2->local_GPs_base); | ||
1148 | if (part_sn2->local_GPs == NULL) { | ||
1149 | dev_err(xpc_chan, "can't get memory for local get/put " | ||
1150 | "values\n"); | ||
1151 | return xpNoMemory; | ||
1152 | } | ||
1153 | |||
1154 | part_sn2->remote_GPs = | ||
1155 | xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL, | ||
1156 | &part_sn2->remote_GPs_base); | ||
1157 | if (part_sn2->remote_GPs == NULL) { | ||
1158 | dev_err(xpc_chan, "can't get memory for remote get/put " | ||
1159 | "values\n"); | ||
1160 | retval = xpNoMemory; | ||
1161 | goto out_1; | ||
1162 | } | ||
1163 | |||
1164 | part_sn2->remote_GPs_pa = 0; | ||
1165 | |||
1166 | /* allocate all the required open and close args */ | ||
1167 | |||
1168 | part_sn2->local_openclose_args = | ||
1169 | xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, | ||
1170 | GFP_KERNEL, &part_sn2-> | ||
1171 | local_openclose_args_base); | ||
1172 | if (part_sn2->local_openclose_args == NULL) { | ||
1173 | dev_err(xpc_chan, "can't get memory for local connect args\n"); | ||
1174 | retval = xpNoMemory; | ||
1175 | goto out_2; | ||
1176 | } | ||
1177 | |||
1178 | part_sn2->remote_openclose_args_pa = 0; | ||
1179 | |||
1180 | part_sn2->local_chctl_amo_va = xpc_init_IRQ_amo_sn2(partid); | ||
1181 | |||
1182 | part_sn2->notify_IRQ_nasid = 0; | ||
1183 | part_sn2->notify_IRQ_phys_cpuid = 0; | ||
1184 | part_sn2->remote_chctl_amo_va = NULL; | ||
1185 | |||
1186 | sprintf(part_sn2->notify_IRQ_owner, "xpc%02d", partid); | ||
1187 | ret = request_irq(SGI_XPC_NOTIFY, xpc_handle_notify_IRQ_sn2, | ||
1188 | IRQF_SHARED, part_sn2->notify_IRQ_owner, | ||
1189 | (void *)(u64)partid); | ||
1190 | if (ret != 0) { | ||
1191 | dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " | ||
1192 | "errno=%d\n", -ret); | ||
1193 | retval = xpLackOfResources; | ||
1194 | goto out_3; | ||
1195 | } | ||
1196 | |||
1197 | /* Setup a timer to check for dropped notify IRQs */ | ||
1198 | timer = &part_sn2->dropped_notify_IRQ_timer; | ||
1199 | init_timer(timer); | ||
1200 | timer->function = | ||
1201 | (void (*)(unsigned long))xpc_check_for_dropped_notify_IRQ_sn2; | ||
1202 | timer->data = (unsigned long)part; | ||
1203 | timer->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL; | ||
1204 | add_timer(timer); | ||
1205 | |||
1206 | for (ch_number = 0; ch_number < part->nchannels; ch_number++) { | ||
1207 | ch_sn2 = &part->channels[ch_number].sn.sn2; | ||
1208 | |||
1209 | ch_sn2->local_GP = &part_sn2->local_GPs[ch_number]; | ||
1210 | ch_sn2->local_openclose_args = | ||
1211 | &part_sn2->local_openclose_args[ch_number]; | ||
1212 | |||
1213 | mutex_init(&ch_sn2->msg_to_pull_mutex); | ||
1214 | } | ||
1215 | |||
1216 | /* | ||
1217 | * Setup the per partition specific variables required by the | ||
1218 | * remote partition to establish channel connections with us. | ||
1219 | * | ||
1220 | * The setting of the magic # indicates that these per partition | ||
1221 | * specific variables are ready to be used. | ||
1222 | */ | ||
1223 | xpc_vars_part_sn2[partid].GPs_pa = xp_pa(part_sn2->local_GPs); | ||
1224 | xpc_vars_part_sn2[partid].openclose_args_pa = | ||
1225 | xp_pa(part_sn2->local_openclose_args); | ||
1226 | xpc_vars_part_sn2[partid].chctl_amo_pa = | ||
1227 | xp_pa(part_sn2->local_chctl_amo_va); | ||
1228 | cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ | ||
1229 | xpc_vars_part_sn2[partid].notify_IRQ_nasid = cpuid_to_nasid(cpuid); | ||
1230 | xpc_vars_part_sn2[partid].notify_IRQ_phys_cpuid = | ||
1231 | cpu_physical_id(cpuid); | ||
1232 | xpc_vars_part_sn2[partid].nchannels = part->nchannels; | ||
1233 | xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC1_SN2; | ||
1234 | |||
1235 | return xpSuccess; | ||
1236 | |||
1237 | /* setup of ch structures failed */ | ||
1238 | out_3: | ||
1239 | kfree(part_sn2->local_openclose_args_base); | ||
1240 | part_sn2->local_openclose_args = NULL; | ||
1241 | out_2: | ||
1242 | kfree(part_sn2->remote_GPs_base); | ||
1243 | part_sn2->remote_GPs = NULL; | ||
1244 | out_1: | ||
1245 | kfree(part_sn2->local_GPs_base); | ||
1246 | part_sn2->local_GPs = NULL; | ||
1247 | return retval; | ||
1248 | } | ||
1249 | |||
1250 | /* | ||
1251 | * Teardown the channel structures that are sn2 specific. | ||
1252 | */ | ||
1253 | static void | ||
1254 | xpc_teardown_ch_structures_sn_sn2(struct xpc_partition *part) | ||
1255 | { | ||
1256 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
1257 | short partid = XPC_PARTID(part); | ||
1258 | |||
1259 | /* | ||
1260 | * Indicate that the variables specific to the remote partition are no | ||
1261 | * longer available for its use. | ||
1262 | */ | ||
1263 | xpc_vars_part_sn2[partid].magic = 0; | ||
1264 | |||
1265 | /* in case we've still got outstanding timers registered... */ | ||
1266 | del_timer_sync(&part_sn2->dropped_notify_IRQ_timer); | ||
1267 | free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid); | ||
1268 | |||
1269 | kfree(part_sn2->local_openclose_args_base); | ||
1270 | part_sn2->local_openclose_args = NULL; | ||
1271 | kfree(part_sn2->remote_GPs_base); | ||
1272 | part_sn2->remote_GPs = NULL; | ||
1273 | kfree(part_sn2->local_GPs_base); | ||
1274 | part_sn2->local_GPs = NULL; | ||
1275 | part_sn2->local_chctl_amo_va = NULL; | ||
1276 | } | ||
1277 | |||
1278 | /* | ||
1279 | * Create a wrapper that hides the underlying mechanism for pulling a cacheline | ||
1280 | * (or multiple cachelines) from a remote partition. | ||
1281 | * | ||
1282 | * src_pa must be a cacheline aligned physical address on the remote partition. | ||
1283 | * dst must be a cacheline aligned virtual address on this partition. | ||
1284 | * cnt must be cacheline sized | ||
1285 | */ | ||
1286 | /* ??? Replace this function by call to xp_remote_memcpy() or bte_copy()? */ | ||
1287 | static enum xp_retval | ||
1288 | xpc_pull_remote_cachelines_sn2(struct xpc_partition *part, void *dst, | ||
1289 | const unsigned long src_pa, size_t cnt) | ||
1290 | { | ||
1291 | enum xp_retval ret; | ||
1292 | |||
1293 | DBUG_ON(src_pa != L1_CACHE_ALIGN(src_pa)); | ||
1294 | DBUG_ON((unsigned long)dst != L1_CACHE_ALIGN((unsigned long)dst)); | ||
1295 | DBUG_ON(cnt != L1_CACHE_ALIGN(cnt)); | ||
1296 | |||
1297 | if (part->act_state == XPC_P_AS_DEACTIVATING) | ||
1298 | return part->reason; | ||
1299 | |||
1300 | ret = xp_remote_memcpy(xp_pa(dst), src_pa, cnt); | ||
1301 | if (ret != xpSuccess) { | ||
1302 | dev_dbg(xpc_chan, "xp_remote_memcpy() from partition %d failed," | ||
1303 | " ret=%d\n", XPC_PARTID(part), ret); | ||
1304 | } | ||
1305 | return ret; | ||
1306 | } | ||
1307 | |||
1308 | /* | ||
1309 | * Pull the remote per partition specific variables from the specified | ||
1310 | * partition. | ||
1311 | */ | ||
1312 | static enum xp_retval | ||
1313 | xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) | ||
1314 | { | ||
1315 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
1316 | u8 buffer[L1_CACHE_BYTES * 2]; | ||
1317 | struct xpc_vars_part_sn2 *pulled_entry_cacheline = | ||
1318 | (struct xpc_vars_part_sn2 *)L1_CACHE_ALIGN((u64)buffer); | ||
1319 | struct xpc_vars_part_sn2 *pulled_entry; | ||
1320 | unsigned long remote_entry_cacheline_pa; | ||
1321 | unsigned long remote_entry_pa; | ||
1322 | short partid = XPC_PARTID(part); | ||
1323 | enum xp_retval ret; | ||
1324 | |||
1325 | /* pull the cacheline that contains the variables we're interested in */ | ||
1326 | |||
1327 | DBUG_ON(part_sn2->remote_vars_part_pa != | ||
1328 | L1_CACHE_ALIGN(part_sn2->remote_vars_part_pa)); | ||
1329 | DBUG_ON(sizeof(struct xpc_vars_part_sn2) != L1_CACHE_BYTES / 2); | ||
1330 | |||
1331 | remote_entry_pa = part_sn2->remote_vars_part_pa + | ||
1332 | sn_partition_id * sizeof(struct xpc_vars_part_sn2); | ||
1333 | |||
1334 | remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1)); | ||
1335 | |||
1336 | pulled_entry = (struct xpc_vars_part_sn2 *)((u64)pulled_entry_cacheline | ||
1337 | + (remote_entry_pa & | ||
1338 | (L1_CACHE_BYTES - 1))); | ||
1339 | |||
1340 | ret = xpc_pull_remote_cachelines_sn2(part, pulled_entry_cacheline, | ||
1341 | remote_entry_cacheline_pa, | ||
1342 | L1_CACHE_BYTES); | ||
1343 | if (ret != xpSuccess) { | ||
1344 | dev_dbg(xpc_chan, "failed to pull XPC vars_part from " | ||
1345 | "partition %d, ret=%d\n", partid, ret); | ||
1346 | return ret; | ||
1347 | } | ||
1348 | |||
1349 | /* see if they've been set up yet */ | ||
1350 | |||
1351 | if (pulled_entry->magic != XPC_VP_MAGIC1_SN2 && | ||
1352 | pulled_entry->magic != XPC_VP_MAGIC2_SN2) { | ||
1353 | |||
1354 | if (pulled_entry->magic != 0) { | ||
1355 | dev_dbg(xpc_chan, "partition %d's XPC vars_part for " | ||
1356 | "partition %d has bad magic value (=0x%lx)\n", | ||
1357 | partid, sn_partition_id, pulled_entry->magic); | ||
1358 | return xpBadMagic; | ||
1359 | } | ||
1360 | |||
1361 | /* they've not been initialized yet */ | ||
1362 | return xpRetry; | ||
1363 | } | ||
1364 | |||
1365 | if (xpc_vars_part_sn2[partid].magic == XPC_VP_MAGIC1_SN2) { | ||
1366 | |||
1367 | /* validate the variables */ | ||
1368 | |||
1369 | if (pulled_entry->GPs_pa == 0 || | ||
1370 | pulled_entry->openclose_args_pa == 0 || | ||
1371 | pulled_entry->chctl_amo_pa == 0) { | ||
1372 | |||
1373 | dev_err(xpc_chan, "partition %d's XPC vars_part for " | ||
1374 | "partition %d are not valid\n", partid, | ||
1375 | sn_partition_id); | ||
1376 | return xpInvalidAddress; | ||
1377 | } | ||
1378 | |||
1379 | /* the variables we imported look to be valid */ | ||
1380 | |||
1381 | part_sn2->remote_GPs_pa = pulled_entry->GPs_pa; | ||
1382 | part_sn2->remote_openclose_args_pa = | ||
1383 | pulled_entry->openclose_args_pa; | ||
1384 | part_sn2->remote_chctl_amo_va = | ||
1385 | (struct amo *)__va(pulled_entry->chctl_amo_pa); | ||
1386 | part_sn2->notify_IRQ_nasid = pulled_entry->notify_IRQ_nasid; | ||
1387 | part_sn2->notify_IRQ_phys_cpuid = | ||
1388 | pulled_entry->notify_IRQ_phys_cpuid; | ||
1389 | |||
1390 | if (part->nchannels > pulled_entry->nchannels) | ||
1391 | part->nchannels = pulled_entry->nchannels; | ||
1392 | |||
1393 | /* let the other side know that we've pulled their variables */ | ||
1394 | |||
1395 | xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC2_SN2; | ||
1396 | } | ||
1397 | |||
1398 | if (pulled_entry->magic == XPC_VP_MAGIC1_SN2) | ||
1399 | return xpRetry; | ||
1400 | |||
1401 | return xpSuccess; | ||
1402 | } | ||
1403 | |||
1404 | /* | ||
1405 | * Establish first contact with the remote partititon. This involves pulling | ||
1406 | * the XPC per partition variables from the remote partition and waiting for | ||
1407 | * the remote partition to pull ours. | ||
1408 | */ | ||
1409 | static enum xp_retval | ||
1410 | xpc_make_first_contact_sn2(struct xpc_partition *part) | ||
1411 | { | ||
1412 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
1413 | enum xp_retval ret; | ||
1414 | |||
1415 | /* | ||
1416 | * Register the remote partition's amos with SAL so it can handle | ||
1417 | * and cleanup errors within that address range should the remote | ||
1418 | * partition go down. We don't unregister this range because it is | ||
1419 | * difficult to tell when outstanding writes to the remote partition | ||
1420 | * are finished and thus when it is safe to unregister. This should | ||
1421 | * not result in wasted space in the SAL xp_addr_region table because | ||
1422 | * we should get the same page for remote_amos_page_pa after module | ||
1423 | * reloads and system reboots. | ||
1424 | */ | ||
1425 | if (sn_register_xp_addr_region(part_sn2->remote_amos_page_pa, | ||
1426 | PAGE_SIZE, 1) < 0) { | ||
1427 | dev_warn(xpc_part, "xpc_activating(%d) failed to register " | ||
1428 | "xp_addr region\n", XPC_PARTID(part)); | ||
1429 | |||
1430 | ret = xpPhysAddrRegFailed; | ||
1431 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
1432 | return ret; | ||
1433 | } | ||
1434 | |||
1435 | /* | ||
1436 | * Send activate IRQ to get other side to activate if they've not | ||
1437 | * already begun to do so. | ||
1438 | */ | ||
1439 | xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa, | ||
1440 | cnodeid_to_nasid(0), | ||
1441 | part_sn2->activate_IRQ_nasid, | ||
1442 | part_sn2->activate_IRQ_phys_cpuid); | ||
1443 | |||
1444 | while ((ret = xpc_pull_remote_vars_part_sn2(part)) != xpSuccess) { | ||
1445 | if (ret != xpRetry) { | ||
1446 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
1447 | return ret; | ||
1448 | } | ||
1449 | |||
1450 | dev_dbg(xpc_part, "waiting to make first contact with " | ||
1451 | "partition %d\n", XPC_PARTID(part)); | ||
1452 | |||
1453 | /* wait a 1/4 of a second or so */ | ||
1454 | (void)msleep_interruptible(250); | ||
1455 | |||
1456 | if (part->act_state == XPC_P_AS_DEACTIVATING) | ||
1457 | return part->reason; | ||
1458 | } | ||
1459 | |||
1460 | return xpSuccess; | ||
1461 | } | ||
1462 | |||
1463 | /* | ||
1464 | * Get the chctl flags and pull the openclose args and/or remote GPs as needed. | ||
1465 | */ | ||
1466 | static u64 | ||
1467 | xpc_get_chctl_all_flags_sn2(struct xpc_partition *part) | ||
1468 | { | ||
1469 | struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; | ||
1470 | unsigned long irq_flags; | ||
1471 | union xpc_channel_ctl_flags chctl; | ||
1472 | enum xp_retval ret; | ||
1473 | |||
1474 | /* | ||
1475 | * See if there are any chctl flags to be handled. | ||
1476 | */ | ||
1477 | |||
1478 | spin_lock_irqsave(&part->chctl_lock, irq_flags); | ||
1479 | chctl = part->chctl; | ||
1480 | if (chctl.all_flags != 0) | ||
1481 | part->chctl.all_flags = 0; | ||
1482 | |||
1483 | spin_unlock_irqrestore(&part->chctl_lock, irq_flags); | ||
1484 | |||
1485 | if (xpc_any_openclose_chctl_flags_set(&chctl)) { | ||
1486 | ret = xpc_pull_remote_cachelines_sn2(part, part-> | ||
1487 | remote_openclose_args, | ||
1488 | part_sn2-> | ||
1489 | remote_openclose_args_pa, | ||
1490 | XPC_OPENCLOSE_ARGS_SIZE); | ||
1491 | if (ret != xpSuccess) { | ||
1492 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
1493 | |||
1494 | dev_dbg(xpc_chan, "failed to pull openclose args from " | ||
1495 | "partition %d, ret=%d\n", XPC_PARTID(part), | ||
1496 | ret); | ||
1497 | |||
1498 | /* don't bother processing chctl flags anymore */ | ||
1499 | chctl.all_flags = 0; | ||
1500 | } | ||
1501 | } | ||
1502 | |||
1503 | if (xpc_any_msg_chctl_flags_set(&chctl)) { | ||
1504 | ret = xpc_pull_remote_cachelines_sn2(part, part_sn2->remote_GPs, | ||
1505 | part_sn2->remote_GPs_pa, | ||
1506 | XPC_GP_SIZE); | ||
1507 | if (ret != xpSuccess) { | ||
1508 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
1509 | |||
1510 | dev_dbg(xpc_chan, "failed to pull GPs from partition " | ||
1511 | "%d, ret=%d\n", XPC_PARTID(part), ret); | ||
1512 | |||
1513 | /* don't bother processing chctl flags anymore */ | ||
1514 | chctl.all_flags = 0; | ||
1515 | } | ||
1516 | } | ||
1517 | |||
1518 | return chctl.all_flags; | ||
1519 | } | ||
1520 | |||
1521 | /* | ||
1522 | * Allocate the local message queue and the notify queue. | ||
1523 | */ | ||
1524 | static enum xp_retval | ||
1525 | xpc_allocate_local_msgqueue_sn2(struct xpc_channel *ch) | ||
1526 | { | ||
1527 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1528 | unsigned long irq_flags; | ||
1529 | int nentries; | ||
1530 | size_t nbytes; | ||
1531 | |||
1532 | for (nentries = ch->local_nentries; nentries > 0; nentries--) { | ||
1533 | |||
1534 | nbytes = nentries * ch->entry_size; | ||
1535 | ch_sn2->local_msgqueue = | ||
1536 | xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, | ||
1537 | &ch_sn2->local_msgqueue_base); | ||
1538 | if (ch_sn2->local_msgqueue == NULL) | ||
1539 | continue; | ||
1540 | |||
1541 | nbytes = nentries * sizeof(struct xpc_notify_sn2); | ||
1542 | ch_sn2->notify_queue = kzalloc(nbytes, GFP_KERNEL); | ||
1543 | if (ch_sn2->notify_queue == NULL) { | ||
1544 | kfree(ch_sn2->local_msgqueue_base); | ||
1545 | ch_sn2->local_msgqueue = NULL; | ||
1546 | continue; | ||
1547 | } | ||
1548 | |||
1549 | spin_lock_irqsave(&ch->lock, irq_flags); | ||
1550 | if (nentries < ch->local_nentries) { | ||
1551 | dev_dbg(xpc_chan, "nentries=%d local_nentries=%d, " | ||
1552 | "partid=%d, channel=%d\n", nentries, | ||
1553 | ch->local_nentries, ch->partid, ch->number); | ||
1554 | |||
1555 | ch->local_nentries = nentries; | ||
1556 | } | ||
1557 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
1558 | return xpSuccess; | ||
1559 | } | ||
1560 | |||
1561 | dev_dbg(xpc_chan, "can't get memory for local message queue and notify " | ||
1562 | "queue, partid=%d, channel=%d\n", ch->partid, ch->number); | ||
1563 | return xpNoMemory; | ||
1564 | } | ||
1565 | |||
1566 | /* | ||
1567 | * Allocate the cached remote message queue. | ||
1568 | */ | ||
1569 | static enum xp_retval | ||
1570 | xpc_allocate_remote_msgqueue_sn2(struct xpc_channel *ch) | ||
1571 | { | ||
1572 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1573 | unsigned long irq_flags; | ||
1574 | int nentries; | ||
1575 | size_t nbytes; | ||
1576 | |||
1577 | DBUG_ON(ch->remote_nentries <= 0); | ||
1578 | |||
1579 | for (nentries = ch->remote_nentries; nentries > 0; nentries--) { | ||
1580 | |||
1581 | nbytes = nentries * ch->entry_size; | ||
1582 | ch_sn2->remote_msgqueue = | ||
1583 | xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, &ch_sn2-> | ||
1584 | remote_msgqueue_base); | ||
1585 | if (ch_sn2->remote_msgqueue == NULL) | ||
1586 | continue; | ||
1587 | |||
1588 | spin_lock_irqsave(&ch->lock, irq_flags); | ||
1589 | if (nentries < ch->remote_nentries) { | ||
1590 | dev_dbg(xpc_chan, "nentries=%d remote_nentries=%d, " | ||
1591 | "partid=%d, channel=%d\n", nentries, | ||
1592 | ch->remote_nentries, ch->partid, ch->number); | ||
1593 | |||
1594 | ch->remote_nentries = nentries; | ||
1595 | } | ||
1596 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
1597 | return xpSuccess; | ||
1598 | } | ||
1599 | |||
1600 | dev_dbg(xpc_chan, "can't get memory for cached remote message queue, " | ||
1601 | "partid=%d, channel=%d\n", ch->partid, ch->number); | ||
1602 | return xpNoMemory; | ||
1603 | } | ||
1604 | |||
1605 | /* | ||
1606 | * Allocate message queues and other stuff associated with a channel. | ||
1607 | * | ||
1608 | * Note: Assumes all of the channel sizes are filled in. | ||
1609 | */ | ||
1610 | static enum xp_retval | ||
1611 | xpc_setup_msg_structures_sn2(struct xpc_channel *ch) | ||
1612 | { | ||
1613 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1614 | enum xp_retval ret; | ||
1615 | |||
1616 | DBUG_ON(ch->flags & XPC_C_SETUP); | ||
1617 | |||
1618 | ret = xpc_allocate_local_msgqueue_sn2(ch); | ||
1619 | if (ret == xpSuccess) { | ||
1620 | |||
1621 | ret = xpc_allocate_remote_msgqueue_sn2(ch); | ||
1622 | if (ret != xpSuccess) { | ||
1623 | kfree(ch_sn2->local_msgqueue_base); | ||
1624 | ch_sn2->local_msgqueue = NULL; | ||
1625 | kfree(ch_sn2->notify_queue); | ||
1626 | ch_sn2->notify_queue = NULL; | ||
1627 | } | ||
1628 | } | ||
1629 | return ret; | ||
1630 | } | ||
1631 | |||
1632 | /* | ||
1633 | * Free up message queues and other stuff that were allocated for the specified | ||
1634 | * channel. | ||
1635 | */ | ||
1636 | static void | ||
1637 | xpc_teardown_msg_structures_sn2(struct xpc_channel *ch) | ||
1638 | { | ||
1639 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1640 | |||
1641 | DBUG_ON(!spin_is_locked(&ch->lock)); | ||
1642 | |||
1643 | ch_sn2->remote_msgqueue_pa = 0; | ||
1644 | |||
1645 | ch_sn2->local_GP->get = 0; | ||
1646 | ch_sn2->local_GP->put = 0; | ||
1647 | ch_sn2->remote_GP.get = 0; | ||
1648 | ch_sn2->remote_GP.put = 0; | ||
1649 | ch_sn2->w_local_GP.get = 0; | ||
1650 | ch_sn2->w_local_GP.put = 0; | ||
1651 | ch_sn2->w_remote_GP.get = 0; | ||
1652 | ch_sn2->w_remote_GP.put = 0; | ||
1653 | ch_sn2->next_msg_to_pull = 0; | ||
1654 | |||
1655 | if (ch->flags & XPC_C_SETUP) { | ||
1656 | dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n", | ||
1657 | ch->flags, ch->partid, ch->number); | ||
1658 | |||
1659 | kfree(ch_sn2->local_msgqueue_base); | ||
1660 | ch_sn2->local_msgqueue = NULL; | ||
1661 | kfree(ch_sn2->remote_msgqueue_base); | ||
1662 | ch_sn2->remote_msgqueue = NULL; | ||
1663 | kfree(ch_sn2->notify_queue); | ||
1664 | ch_sn2->notify_queue = NULL; | ||
1665 | } | ||
1666 | } | ||
1667 | |||
1668 | /* | ||
1669 | * Notify those who wanted to be notified upon delivery of their message. | ||
1670 | */ | ||
1671 | static void | ||
1672 | xpc_notify_senders_sn2(struct xpc_channel *ch, enum xp_retval reason, s64 put) | ||
1673 | { | ||
1674 | struct xpc_notify_sn2 *notify; | ||
1675 | u8 notify_type; | ||
1676 | s64 get = ch->sn.sn2.w_remote_GP.get - 1; | ||
1677 | |||
1678 | while (++get < put && atomic_read(&ch->n_to_notify) > 0) { | ||
1679 | |||
1680 | notify = &ch->sn.sn2.notify_queue[get % ch->local_nentries]; | ||
1681 | |||
1682 | /* | ||
1683 | * See if the notify entry indicates it was associated with | ||
1684 | * a message who's sender wants to be notified. It is possible | ||
1685 | * that it is, but someone else is doing or has done the | ||
1686 | * notification. | ||
1687 | */ | ||
1688 | notify_type = notify->type; | ||
1689 | if (notify_type == 0 || | ||
1690 | cmpxchg(¬ify->type, notify_type, 0) != notify_type) { | ||
1691 | continue; | ||
1692 | } | ||
1693 | |||
1694 | DBUG_ON(notify_type != XPC_N_CALL); | ||
1695 | |||
1696 | atomic_dec(&ch->n_to_notify); | ||
1697 | |||
1698 | if (notify->func != NULL) { | ||
1699 | dev_dbg(xpc_chan, "notify->func() called, notify=0x%p " | ||
1700 | "msg_number=%ld partid=%d channel=%d\n", | ||
1701 | (void *)notify, get, ch->partid, ch->number); | ||
1702 | |||
1703 | notify->func(reason, ch->partid, ch->number, | ||
1704 | notify->key); | ||
1705 | |||
1706 | dev_dbg(xpc_chan, "notify->func() returned, notify=0x%p" | ||
1707 | " msg_number=%ld partid=%d channel=%d\n", | ||
1708 | (void *)notify, get, ch->partid, ch->number); | ||
1709 | } | ||
1710 | } | ||
1711 | } | ||
1712 | |||
1713 | static void | ||
1714 | xpc_notify_senders_of_disconnect_sn2(struct xpc_channel *ch) | ||
1715 | { | ||
1716 | xpc_notify_senders_sn2(ch, ch->reason, ch->sn.sn2.w_local_GP.put); | ||
1717 | } | ||
1718 | |||
1719 | /* | ||
1720 | * Clear some of the msg flags in the local message queue. | ||
1721 | */ | ||
1722 | static inline void | ||
1723 | xpc_clear_local_msgqueue_flags_sn2(struct xpc_channel *ch) | ||
1724 | { | ||
1725 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1726 | struct xpc_msg_sn2 *msg; | ||
1727 | s64 get; | ||
1728 | |||
1729 | get = ch_sn2->w_remote_GP.get; | ||
1730 | do { | ||
1731 | msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue + | ||
1732 | (get % ch->local_nentries) * | ||
1733 | ch->entry_size); | ||
1734 | msg->flags = 0; | ||
1735 | } while (++get < ch_sn2->remote_GP.get); | ||
1736 | } | ||
1737 | |||
1738 | /* | ||
1739 | * Clear some of the msg flags in the remote message queue. | ||
1740 | */ | ||
1741 | static inline void | ||
1742 | xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch) | ||
1743 | { | ||
1744 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1745 | struct xpc_msg_sn2 *msg; | ||
1746 | s64 put; | ||
1747 | |||
1748 | put = ch_sn2->w_remote_GP.put; | ||
1749 | do { | ||
1750 | msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + | ||
1751 | (put % ch->remote_nentries) * | ||
1752 | ch->entry_size); | ||
1753 | msg->flags = 0; | ||
1754 | } while (++put < ch_sn2->remote_GP.put); | ||
1755 | } | ||
1756 | |||
1757 | static int | ||
1758 | xpc_n_of_deliverable_payloads_sn2(struct xpc_channel *ch) | ||
1759 | { | ||
1760 | return ch->sn.sn2.w_remote_GP.put - ch->sn.sn2.w_local_GP.get; | ||
1761 | } | ||
1762 | |||
1763 | static void | ||
1764 | xpc_process_msg_chctl_flags_sn2(struct xpc_partition *part, int ch_number) | ||
1765 | { | ||
1766 | struct xpc_channel *ch = &part->channels[ch_number]; | ||
1767 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1768 | int npayloads_sent; | ||
1769 | |||
1770 | ch_sn2->remote_GP = part->sn.sn2.remote_GPs[ch_number]; | ||
1771 | |||
1772 | /* See what, if anything, has changed for each connected channel */ | ||
1773 | |||
1774 | xpc_msgqueue_ref(ch); | ||
1775 | |||
1776 | if (ch_sn2->w_remote_GP.get == ch_sn2->remote_GP.get && | ||
1777 | ch_sn2->w_remote_GP.put == ch_sn2->remote_GP.put) { | ||
1778 | /* nothing changed since GPs were last pulled */ | ||
1779 | xpc_msgqueue_deref(ch); | ||
1780 | return; | ||
1781 | } | ||
1782 | |||
1783 | if (!(ch->flags & XPC_C_CONNECTED)) { | ||
1784 | xpc_msgqueue_deref(ch); | ||
1785 | return; | ||
1786 | } | ||
1787 | |||
1788 | /* | ||
1789 | * First check to see if messages recently sent by us have been | ||
1790 | * received by the other side. (The remote GET value will have | ||
1791 | * changed since we last looked at it.) | ||
1792 | */ | ||
1793 | |||
1794 | if (ch_sn2->w_remote_GP.get != ch_sn2->remote_GP.get) { | ||
1795 | |||
1796 | /* | ||
1797 | * We need to notify any senders that want to be notified | ||
1798 | * that their sent messages have been received by their | ||
1799 | * intended recipients. We need to do this before updating | ||
1800 | * w_remote_GP.get so that we don't allocate the same message | ||
1801 | * queue entries prematurely (see xpc_allocate_msg()). | ||
1802 | */ | ||
1803 | if (atomic_read(&ch->n_to_notify) > 0) { | ||
1804 | /* | ||
1805 | * Notify senders that messages sent have been | ||
1806 | * received and delivered by the other side. | ||
1807 | */ | ||
1808 | xpc_notify_senders_sn2(ch, xpMsgDelivered, | ||
1809 | ch_sn2->remote_GP.get); | ||
1810 | } | ||
1811 | |||
1812 | /* | ||
1813 | * Clear msg->flags in previously sent messages, so that | ||
1814 | * they're ready for xpc_allocate_msg(). | ||
1815 | */ | ||
1816 | xpc_clear_local_msgqueue_flags_sn2(ch); | ||
1817 | |||
1818 | ch_sn2->w_remote_GP.get = ch_sn2->remote_GP.get; | ||
1819 | |||
1820 | dev_dbg(xpc_chan, "w_remote_GP.get changed to %ld, partid=%d, " | ||
1821 | "channel=%d\n", ch_sn2->w_remote_GP.get, ch->partid, | ||
1822 | ch->number); | ||
1823 | |||
1824 | /* | ||
1825 | * If anyone was waiting for message queue entries to become | ||
1826 | * available, wake them up. | ||
1827 | */ | ||
1828 | if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) | ||
1829 | wake_up(&ch->msg_allocate_wq); | ||
1830 | } | ||
1831 | |||
1832 | /* | ||
1833 | * Now check for newly sent messages by the other side. (The remote | ||
1834 | * PUT value will have changed since we last looked at it.) | ||
1835 | */ | ||
1836 | |||
1837 | if (ch_sn2->w_remote_GP.put != ch_sn2->remote_GP.put) { | ||
1838 | /* | ||
1839 | * Clear msg->flags in previously received messages, so that | ||
1840 | * they're ready for xpc_get_deliverable_payload_sn2(). | ||
1841 | */ | ||
1842 | xpc_clear_remote_msgqueue_flags_sn2(ch); | ||
1843 | |||
1844 | ch_sn2->w_remote_GP.put = ch_sn2->remote_GP.put; | ||
1845 | |||
1846 | dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, " | ||
1847 | "channel=%d\n", ch_sn2->w_remote_GP.put, ch->partid, | ||
1848 | ch->number); | ||
1849 | |||
1850 | npayloads_sent = xpc_n_of_deliverable_payloads_sn2(ch); | ||
1851 | if (npayloads_sent > 0) { | ||
1852 | dev_dbg(xpc_chan, "msgs waiting to be copied and " | ||
1853 | "delivered=%d, partid=%d, channel=%d\n", | ||
1854 | npayloads_sent, ch->partid, ch->number); | ||
1855 | |||
1856 | if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) | ||
1857 | xpc_activate_kthreads(ch, npayloads_sent); | ||
1858 | } | ||
1859 | } | ||
1860 | |||
1861 | xpc_msgqueue_deref(ch); | ||
1862 | } | ||
1863 | |||
1864 | static struct xpc_msg_sn2 * | ||
1865 | xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) | ||
1866 | { | ||
1867 | struct xpc_partition *part = &xpc_partitions[ch->partid]; | ||
1868 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1869 | unsigned long remote_msg_pa; | ||
1870 | struct xpc_msg_sn2 *msg; | ||
1871 | u32 msg_index; | ||
1872 | u32 nmsgs; | ||
1873 | u64 msg_offset; | ||
1874 | enum xp_retval ret; | ||
1875 | |||
1876 | if (mutex_lock_interruptible(&ch_sn2->msg_to_pull_mutex) != 0) { | ||
1877 | /* we were interrupted by a signal */ | ||
1878 | return NULL; | ||
1879 | } | ||
1880 | |||
1881 | while (get >= ch_sn2->next_msg_to_pull) { | ||
1882 | |||
1883 | /* pull as many messages as are ready and able to be pulled */ | ||
1884 | |||
1885 | msg_index = ch_sn2->next_msg_to_pull % ch->remote_nentries; | ||
1886 | |||
1887 | DBUG_ON(ch_sn2->next_msg_to_pull >= ch_sn2->w_remote_GP.put); | ||
1888 | nmsgs = ch_sn2->w_remote_GP.put - ch_sn2->next_msg_to_pull; | ||
1889 | if (msg_index + nmsgs > ch->remote_nentries) { | ||
1890 | /* ignore the ones that wrap the msg queue for now */ | ||
1891 | nmsgs = ch->remote_nentries - msg_index; | ||
1892 | } | ||
1893 | |||
1894 | msg_offset = msg_index * ch->entry_size; | ||
1895 | msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + | ||
1896 | msg_offset); | ||
1897 | remote_msg_pa = ch_sn2->remote_msgqueue_pa + msg_offset; | ||
1898 | |||
1899 | ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg_pa, | ||
1900 | nmsgs * ch->entry_size); | ||
1901 | if (ret != xpSuccess) { | ||
1902 | |||
1903 | dev_dbg(xpc_chan, "failed to pull %d msgs starting with" | ||
1904 | " msg %ld from partition %d, channel=%d, " | ||
1905 | "ret=%d\n", nmsgs, ch_sn2->next_msg_to_pull, | ||
1906 | ch->partid, ch->number, ret); | ||
1907 | |||
1908 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
1909 | |||
1910 | mutex_unlock(&ch_sn2->msg_to_pull_mutex); | ||
1911 | return NULL; | ||
1912 | } | ||
1913 | |||
1914 | ch_sn2->next_msg_to_pull += nmsgs; | ||
1915 | } | ||
1916 | |||
1917 | mutex_unlock(&ch_sn2->msg_to_pull_mutex); | ||
1918 | |||
1919 | /* return the message we were looking for */ | ||
1920 | msg_offset = (get % ch->remote_nentries) * ch->entry_size; | ||
1921 | msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + msg_offset); | ||
1922 | |||
1923 | return msg; | ||
1924 | } | ||
1925 | |||
1926 | /* | ||
1927 | * Get the next deliverable message's payload. | ||
1928 | */ | ||
1929 | static void * | ||
1930 | xpc_get_deliverable_payload_sn2(struct xpc_channel *ch) | ||
1931 | { | ||
1932 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1933 | struct xpc_msg_sn2 *msg; | ||
1934 | void *payload = NULL; | ||
1935 | s64 get; | ||
1936 | |||
1937 | do { | ||
1938 | if (ch->flags & XPC_C_DISCONNECTING) | ||
1939 | break; | ||
1940 | |||
1941 | get = ch_sn2->w_local_GP.get; | ||
1942 | rmb(); /* guarantee that .get loads before .put */ | ||
1943 | if (get == ch_sn2->w_remote_GP.put) | ||
1944 | break; | ||
1945 | |||
1946 | /* There are messages waiting to be pulled and delivered. | ||
1947 | * We need to try to secure one for ourselves. We'll do this | ||
1948 | * by trying to increment w_local_GP.get and hope that no one | ||
1949 | * else beats us to it. If they do, we'll we'll simply have | ||
1950 | * to try again for the next one. | ||
1951 | */ | ||
1952 | |||
1953 | if (cmpxchg(&ch_sn2->w_local_GP.get, get, get + 1) == get) { | ||
1954 | /* we got the entry referenced by get */ | ||
1955 | |||
1956 | dev_dbg(xpc_chan, "w_local_GP.get changed to %ld, " | ||
1957 | "partid=%d, channel=%d\n", get + 1, | ||
1958 | ch->partid, ch->number); | ||
1959 | |||
1960 | /* pull the message from the remote partition */ | ||
1961 | |||
1962 | msg = xpc_pull_remote_msg_sn2(ch, get); | ||
1963 | |||
1964 | DBUG_ON(msg != NULL && msg->number != get); | ||
1965 | DBUG_ON(msg != NULL && (msg->flags & XPC_M_SN2_DONE)); | ||
1966 | DBUG_ON(msg != NULL && !(msg->flags & XPC_M_SN2_READY)); | ||
1967 | |||
1968 | payload = &msg->payload; | ||
1969 | break; | ||
1970 | } | ||
1971 | |||
1972 | } while (1); | ||
1973 | |||
1974 | return payload; | ||
1975 | } | ||
1976 | |||
1977 | /* | ||
1978 | * Now we actually send the messages that are ready to be sent by advancing | ||
1979 | * the local message queue's Put value and then send a chctl msgrequest to the | ||
1980 | * recipient partition. | ||
1981 | */ | ||
1982 | static void | ||
1983 | xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) | ||
1984 | { | ||
1985 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
1986 | struct xpc_msg_sn2 *msg; | ||
1987 | s64 put = initial_put + 1; | ||
1988 | int send_msgrequest = 0; | ||
1989 | |||
1990 | while (1) { | ||
1991 | |||
1992 | while (1) { | ||
1993 | if (put == ch_sn2->w_local_GP.put) | ||
1994 | break; | ||
1995 | |||
1996 | msg = (struct xpc_msg_sn2 *)((u64)ch_sn2-> | ||
1997 | local_msgqueue + (put % | ||
1998 | ch->local_nentries) * | ||
1999 | ch->entry_size); | ||
2000 | |||
2001 | if (!(msg->flags & XPC_M_SN2_READY)) | ||
2002 | break; | ||
2003 | |||
2004 | put++; | ||
2005 | } | ||
2006 | |||
2007 | if (put == initial_put) { | ||
2008 | /* nothing's changed */ | ||
2009 | break; | ||
2010 | } | ||
2011 | |||
2012 | if (cmpxchg_rel(&ch_sn2->local_GP->put, initial_put, put) != | ||
2013 | initial_put) { | ||
2014 | /* someone else beat us to it */ | ||
2015 | DBUG_ON(ch_sn2->local_GP->put < initial_put); | ||
2016 | break; | ||
2017 | } | ||
2018 | |||
2019 | /* we just set the new value of local_GP->put */ | ||
2020 | |||
2021 | dev_dbg(xpc_chan, "local_GP->put changed to %ld, partid=%d, " | ||
2022 | "channel=%d\n", put, ch->partid, ch->number); | ||
2023 | |||
2024 | send_msgrequest = 1; | ||
2025 | |||
2026 | /* | ||
2027 | * We need to ensure that the message referenced by | ||
2028 | * local_GP->put is not XPC_M_SN2_READY or that local_GP->put | ||
2029 | * equals w_local_GP.put, so we'll go have a look. | ||
2030 | */ | ||
2031 | initial_put = put; | ||
2032 | } | ||
2033 | |||
2034 | if (send_msgrequest) | ||
2035 | xpc_send_chctl_msgrequest_sn2(ch); | ||
2036 | } | ||
2037 | |||
2038 | /* | ||
2039 | * Allocate an entry for a message from the message queue associated with the | ||
2040 | * specified channel. | ||
2041 | */ | ||
2042 | static enum xp_retval | ||
2043 | xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, | ||
2044 | struct xpc_msg_sn2 **address_of_msg) | ||
2045 | { | ||
2046 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
2047 | struct xpc_msg_sn2 *msg; | ||
2048 | enum xp_retval ret; | ||
2049 | s64 put; | ||
2050 | |||
2051 | /* | ||
2052 | * Get the next available message entry from the local message queue. | ||
2053 | * If none are available, we'll make sure that we grab the latest | ||
2054 | * GP values. | ||
2055 | */ | ||
2056 | ret = xpTimeout; | ||
2057 | |||
2058 | while (1) { | ||
2059 | |||
2060 | put = ch_sn2->w_local_GP.put; | ||
2061 | rmb(); /* guarantee that .put loads before .get */ | ||
2062 | if (put - ch_sn2->w_remote_GP.get < ch->local_nentries) { | ||
2063 | |||
2064 | /* There are available message entries. We need to try | ||
2065 | * to secure one for ourselves. We'll do this by trying | ||
2066 | * to increment w_local_GP.put as long as someone else | ||
2067 | * doesn't beat us to it. If they do, we'll have to | ||
2068 | * try again. | ||
2069 | */ | ||
2070 | if (cmpxchg(&ch_sn2->w_local_GP.put, put, put + 1) == | ||
2071 | put) { | ||
2072 | /* we got the entry referenced by put */ | ||
2073 | break; | ||
2074 | } | ||
2075 | continue; /* try again */ | ||
2076 | } | ||
2077 | |||
2078 | /* | ||
2079 | * There aren't any available msg entries at this time. | ||
2080 | * | ||
2081 | * In waiting for a message entry to become available, | ||
2082 | * we set a timeout in case the other side is not sending | ||
2083 | * completion interrupts. This lets us fake a notify IRQ | ||
2084 | * that will cause the notify IRQ handler to fetch the latest | ||
2085 | * GP values as if an interrupt was sent by the other side. | ||
2086 | */ | ||
2087 | if (ret == xpTimeout) | ||
2088 | xpc_send_chctl_local_msgrequest_sn2(ch); | ||
2089 | |||
2090 | if (flags & XPC_NOWAIT) | ||
2091 | return xpNoWait; | ||
2092 | |||
2093 | ret = xpc_allocate_msg_wait(ch); | ||
2094 | if (ret != xpInterrupted && ret != xpTimeout) | ||
2095 | return ret; | ||
2096 | } | ||
2097 | |||
2098 | /* get the message's address and initialize it */ | ||
2099 | msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue + | ||
2100 | (put % ch->local_nentries) * | ||
2101 | ch->entry_size); | ||
2102 | |||
2103 | DBUG_ON(msg->flags != 0); | ||
2104 | msg->number = put; | ||
2105 | |||
2106 | dev_dbg(xpc_chan, "w_local_GP.put changed to %ld; msg=0x%p, " | ||
2107 | "msg_number=%ld, partid=%d, channel=%d\n", put + 1, | ||
2108 | (void *)msg, msg->number, ch->partid, ch->number); | ||
2109 | |||
2110 | *address_of_msg = msg; | ||
2111 | return xpSuccess; | ||
2112 | } | ||
2113 | |||
2114 | /* | ||
2115 | * Common code that does the actual sending of the message by advancing the | ||
2116 | * local message queue's Put value and sends a chctl msgrequest to the | ||
2117 | * partition the message is being sent to. | ||
2118 | */ | ||
2119 | static enum xp_retval | ||
2120 | xpc_send_payload_sn2(struct xpc_channel *ch, u32 flags, void *payload, | ||
2121 | u16 payload_size, u8 notify_type, xpc_notify_func func, | ||
2122 | void *key) | ||
2123 | { | ||
2124 | enum xp_retval ret = xpSuccess; | ||
2125 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
2126 | struct xpc_msg_sn2 *msg = msg; | ||
2127 | struct xpc_notify_sn2 *notify = notify; | ||
2128 | s64 msg_number; | ||
2129 | s64 put; | ||
2130 | |||
2131 | DBUG_ON(notify_type == XPC_N_CALL && func == NULL); | ||
2132 | |||
2133 | if (XPC_MSG_SIZE(payload_size) > ch->entry_size) | ||
2134 | return xpPayloadTooBig; | ||
2135 | |||
2136 | xpc_msgqueue_ref(ch); | ||
2137 | |||
2138 | if (ch->flags & XPC_C_DISCONNECTING) { | ||
2139 | ret = ch->reason; | ||
2140 | goto out_1; | ||
2141 | } | ||
2142 | if (!(ch->flags & XPC_C_CONNECTED)) { | ||
2143 | ret = xpNotConnected; | ||
2144 | goto out_1; | ||
2145 | } | ||
2146 | |||
2147 | ret = xpc_allocate_msg_sn2(ch, flags, &msg); | ||
2148 | if (ret != xpSuccess) | ||
2149 | goto out_1; | ||
2150 | |||
2151 | msg_number = msg->number; | ||
2152 | |||
2153 | if (notify_type != 0) { | ||
2154 | /* | ||
2155 | * Tell the remote side to send an ACK interrupt when the | ||
2156 | * message has been delivered. | ||
2157 | */ | ||
2158 | msg->flags |= XPC_M_SN2_INTERRUPT; | ||
2159 | |||
2160 | atomic_inc(&ch->n_to_notify); | ||
2161 | |||
2162 | notify = &ch_sn2->notify_queue[msg_number % ch->local_nentries]; | ||
2163 | notify->func = func; | ||
2164 | notify->key = key; | ||
2165 | notify->type = notify_type; | ||
2166 | |||
2167 | /* ??? Is a mb() needed here? */ | ||
2168 | |||
2169 | if (ch->flags & XPC_C_DISCONNECTING) { | ||
2170 | /* | ||
2171 | * An error occurred between our last error check and | ||
2172 | * this one. We will try to clear the type field from | ||
2173 | * the notify entry. If we succeed then | ||
2174 | * xpc_disconnect_channel() didn't already process | ||
2175 | * the notify entry. | ||
2176 | */ | ||
2177 | if (cmpxchg(¬ify->type, notify_type, 0) == | ||
2178 | notify_type) { | ||
2179 | atomic_dec(&ch->n_to_notify); | ||
2180 | ret = ch->reason; | ||
2181 | } | ||
2182 | goto out_1; | ||
2183 | } | ||
2184 | } | ||
2185 | |||
2186 | memcpy(&msg->payload, payload, payload_size); | ||
2187 | |||
2188 | msg->flags |= XPC_M_SN2_READY; | ||
2189 | |||
2190 | /* | ||
2191 | * The preceding store of msg->flags must occur before the following | ||
2192 | * load of local_GP->put. | ||
2193 | */ | ||
2194 | mb(); | ||
2195 | |||
2196 | /* see if the message is next in line to be sent, if so send it */ | ||
2197 | |||
2198 | put = ch_sn2->local_GP->put; | ||
2199 | if (put == msg_number) | ||
2200 | xpc_send_msgs_sn2(ch, put); | ||
2201 | |||
2202 | out_1: | ||
2203 | xpc_msgqueue_deref(ch); | ||
2204 | return ret; | ||
2205 | } | ||
2206 | |||
2207 | /* | ||
2208 | * Now we actually acknowledge the messages that have been delivered and ack'd | ||
2209 | * by advancing the cached remote message queue's Get value and if requested | ||
2210 | * send a chctl msgrequest to the message sender's partition. | ||
2211 | * | ||
2212 | * If a message has XPC_M_SN2_INTERRUPT set, send an interrupt to the partition | ||
2213 | * that sent the message. | ||
2214 | */ | ||
2215 | static void | ||
2216 | xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) | ||
2217 | { | ||
2218 | struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; | ||
2219 | struct xpc_msg_sn2 *msg; | ||
2220 | s64 get = initial_get + 1; | ||
2221 | int send_msgrequest = 0; | ||
2222 | |||
2223 | while (1) { | ||
2224 | |||
2225 | while (1) { | ||
2226 | if (get == ch_sn2->w_local_GP.get) | ||
2227 | break; | ||
2228 | |||
2229 | msg = (struct xpc_msg_sn2 *)((u64)ch_sn2-> | ||
2230 | remote_msgqueue + (get % | ||
2231 | ch->remote_nentries) * | ||
2232 | ch->entry_size); | ||
2233 | |||
2234 | if (!(msg->flags & XPC_M_SN2_DONE)) | ||
2235 | break; | ||
2236 | |||
2237 | msg_flags |= msg->flags; | ||
2238 | get++; | ||
2239 | } | ||
2240 | |||
2241 | if (get == initial_get) { | ||
2242 | /* nothing's changed */ | ||
2243 | break; | ||
2244 | } | ||
2245 | |||
2246 | if (cmpxchg_rel(&ch_sn2->local_GP->get, initial_get, get) != | ||
2247 | initial_get) { | ||
2248 | /* someone else beat us to it */ | ||
2249 | DBUG_ON(ch_sn2->local_GP->get <= initial_get); | ||
2250 | break; | ||
2251 | } | ||
2252 | |||
2253 | /* we just set the new value of local_GP->get */ | ||
2254 | |||
2255 | dev_dbg(xpc_chan, "local_GP->get changed to %ld, partid=%d, " | ||
2256 | "channel=%d\n", get, ch->partid, ch->number); | ||
2257 | |||
2258 | send_msgrequest = (msg_flags & XPC_M_SN2_INTERRUPT); | ||
2259 | |||
2260 | /* | ||
2261 | * We need to ensure that the message referenced by | ||
2262 | * local_GP->get is not XPC_M_SN2_DONE or that local_GP->get | ||
2263 | * equals w_local_GP.get, so we'll go have a look. | ||
2264 | */ | ||
2265 | initial_get = get; | ||
2266 | } | ||
2267 | |||
2268 | if (send_msgrequest) | ||
2269 | xpc_send_chctl_msgrequest_sn2(ch); | ||
2270 | } | ||
2271 | |||
2272 | static void | ||
2273 | xpc_received_payload_sn2(struct xpc_channel *ch, void *payload) | ||
2274 | { | ||
2275 | struct xpc_msg_sn2 *msg; | ||
2276 | s64 msg_number; | ||
2277 | s64 get; | ||
2278 | |||
2279 | msg = container_of(payload, struct xpc_msg_sn2, payload); | ||
2280 | msg_number = msg->number; | ||
2281 | |||
2282 | dev_dbg(xpc_chan, "msg=0x%p, msg_number=%ld, partid=%d, channel=%d\n", | ||
2283 | (void *)msg, msg_number, ch->partid, ch->number); | ||
2284 | |||
2285 | DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->entry_size) != | ||
2286 | msg_number % ch->remote_nentries); | ||
2287 | DBUG_ON(msg->flags & XPC_M_SN2_DONE); | ||
2288 | |||
2289 | msg->flags |= XPC_M_SN2_DONE; | ||
2290 | |||
2291 | /* | ||
2292 | * The preceding store of msg->flags must occur before the following | ||
2293 | * load of local_GP->get. | ||
2294 | */ | ||
2295 | mb(); | ||
2296 | |||
2297 | /* | ||
2298 | * See if this message is next in line to be acknowledged as having | ||
2299 | * been delivered. | ||
2300 | */ | ||
2301 | get = ch->sn.sn2.local_GP->get; | ||
2302 | if (get == msg_number) | ||
2303 | xpc_acknowledge_msgs_sn2(ch, get, msg->flags); | ||
2304 | } | ||
2305 | |||
2306 | int | ||
2307 | xpc_init_sn2(void) | ||
2308 | { | ||
2309 | int ret; | ||
2310 | size_t buf_size; | ||
2311 | |||
2312 | xpc_setup_partitions_sn = xpc_setup_partitions_sn_sn2; | ||
2313 | xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2; | ||
2314 | xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_sn2; | ||
2315 | xpc_increment_heartbeat = xpc_increment_heartbeat_sn2; | ||
2316 | xpc_offline_heartbeat = xpc_offline_heartbeat_sn2; | ||
2317 | xpc_online_heartbeat = xpc_online_heartbeat_sn2; | ||
2318 | xpc_heartbeat_init = xpc_heartbeat_init_sn2; | ||
2319 | xpc_heartbeat_exit = xpc_heartbeat_exit_sn2; | ||
2320 | xpc_get_remote_heartbeat = xpc_get_remote_heartbeat_sn2; | ||
2321 | |||
2322 | xpc_request_partition_activation = xpc_request_partition_activation_sn2; | ||
2323 | xpc_request_partition_reactivation = | ||
2324 | xpc_request_partition_reactivation_sn2; | ||
2325 | xpc_request_partition_deactivation = | ||
2326 | xpc_request_partition_deactivation_sn2; | ||
2327 | xpc_cancel_partition_deactivation_request = | ||
2328 | xpc_cancel_partition_deactivation_request_sn2; | ||
2329 | |||
2330 | xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_sn2; | ||
2331 | xpc_setup_ch_structures_sn = xpc_setup_ch_structures_sn_sn2; | ||
2332 | xpc_teardown_ch_structures_sn = xpc_teardown_ch_structures_sn_sn2; | ||
2333 | xpc_make_first_contact = xpc_make_first_contact_sn2; | ||
2334 | |||
2335 | xpc_get_chctl_all_flags = xpc_get_chctl_all_flags_sn2; | ||
2336 | xpc_send_chctl_closerequest = xpc_send_chctl_closerequest_sn2; | ||
2337 | xpc_send_chctl_closereply = xpc_send_chctl_closereply_sn2; | ||
2338 | xpc_send_chctl_openrequest = xpc_send_chctl_openrequest_sn2; | ||
2339 | xpc_send_chctl_openreply = xpc_send_chctl_openreply_sn2; | ||
2340 | |||
2341 | xpc_save_remote_msgqueue_pa = xpc_save_remote_msgqueue_pa_sn2; | ||
2342 | |||
2343 | xpc_setup_msg_structures = xpc_setup_msg_structures_sn2; | ||
2344 | xpc_teardown_msg_structures = xpc_teardown_msg_structures_sn2; | ||
2345 | |||
2346 | xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2; | ||
2347 | xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_sn2; | ||
2348 | xpc_n_of_deliverable_payloads = xpc_n_of_deliverable_payloads_sn2; | ||
2349 | xpc_get_deliverable_payload = xpc_get_deliverable_payload_sn2; | ||
2350 | |||
2351 | xpc_indicate_partition_engaged = xpc_indicate_partition_engaged_sn2; | ||
2352 | xpc_indicate_partition_disengaged = | ||
2353 | xpc_indicate_partition_disengaged_sn2; | ||
2354 | xpc_partition_engaged = xpc_partition_engaged_sn2; | ||
2355 | xpc_any_partition_engaged = xpc_any_partition_engaged_sn2; | ||
2356 | xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_sn2; | ||
2357 | |||
2358 | xpc_send_payload = xpc_send_payload_sn2; | ||
2359 | xpc_received_payload = xpc_received_payload_sn2; | ||
2360 | |||
2361 | if (offsetof(struct xpc_msg_sn2, payload) > XPC_MSG_HDR_MAX_SIZE) { | ||
2362 | dev_err(xpc_part, "header portion of struct xpc_msg_sn2 is " | ||
2363 | "larger than %d\n", XPC_MSG_HDR_MAX_SIZE); | ||
2364 | return -E2BIG; | ||
2365 | } | ||
2366 | |||
2367 | buf_size = max(XPC_RP_VARS_SIZE, | ||
2368 | XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES_SN2); | ||
2369 | xpc_remote_copy_buffer_sn2 = xpc_kmalloc_cacheline_aligned(buf_size, | ||
2370 | GFP_KERNEL, | ||
2371 | &xpc_remote_copy_buffer_base_sn2); | ||
2372 | if (xpc_remote_copy_buffer_sn2 == NULL) { | ||
2373 | dev_err(xpc_part, "can't get memory for remote copy buffer\n"); | ||
2374 | return -ENOMEM; | ||
2375 | } | ||
2376 | |||
2377 | /* open up protections for IPI and [potentially] amo operations */ | ||
2378 | xpc_allow_IPI_ops_sn2(); | ||
2379 | xpc_allow_amo_ops_shub_wars_1_1_sn2(); | ||
2380 | |||
2381 | /* | ||
2382 | * This is safe to do before the xpc_hb_checker thread has started | ||
2383 | * because the handler releases a wait queue. If an interrupt is | ||
2384 | * received before the thread is waiting, it will not go to sleep, | ||
2385 | * but rather immediately process the interrupt. | ||
2386 | */ | ||
2387 | ret = request_irq(SGI_XPC_ACTIVATE, xpc_handle_activate_IRQ_sn2, 0, | ||
2388 | "xpc hb", NULL); | ||
2389 | if (ret != 0) { | ||
2390 | dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " | ||
2391 | "errno=%d\n", -ret); | ||
2392 | xpc_disallow_IPI_ops_sn2(); | ||
2393 | kfree(xpc_remote_copy_buffer_base_sn2); | ||
2394 | } | ||
2395 | return ret; | ||
2396 | } | ||
2397 | |||
2398 | void | ||
2399 | xpc_exit_sn2(void) | ||
2400 | { | ||
2401 | free_irq(SGI_XPC_ACTIVATE, NULL); | ||
2402 | xpc_disallow_IPI_ops_sn2(); | ||
2403 | kfree(xpc_remote_copy_buffer_base_sn2); | ||
2404 | } | ||
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c new file mode 100644 index 000000000000..1ac694c01623 --- /dev/null +++ b/drivers/misc/sgi-xp/xpc_uv.c | |||
@@ -0,0 +1,1443 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Cross Partition Communication (XPC) uv-based functions. | ||
11 | * | ||
12 | * Architecture specific implementation of common functions. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <asm/uv/uv_hub.h> | ||
22 | #include "../sgi-gru/gru.h" | ||
23 | #include "../sgi-gru/grukservices.h" | ||
24 | #include "xpc.h" | ||
25 | |||
26 | static atomic64_t xpc_heartbeat_uv; | ||
27 | static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); | ||
28 | |||
29 | #define XPC_ACTIVATE_MSG_SIZE_UV (1 * GRU_CACHE_LINE_BYTES) | ||
30 | #define XPC_NOTIFY_MSG_SIZE_UV (2 * GRU_CACHE_LINE_BYTES) | ||
31 | |||
32 | #define XPC_ACTIVATE_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \ | ||
33 | XPC_ACTIVATE_MSG_SIZE_UV) | ||
34 | #define XPC_NOTIFY_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \ | ||
35 | XPC_NOTIFY_MSG_SIZE_UV) | ||
36 | |||
37 | static void *xpc_activate_mq_uv; | ||
38 | static void *xpc_notify_mq_uv; | ||
39 | |||
40 | static int | ||
41 | xpc_setup_partitions_sn_uv(void) | ||
42 | { | ||
43 | short partid; | ||
44 | struct xpc_partition_uv *part_uv; | ||
45 | |||
46 | for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) { | ||
47 | part_uv = &xpc_partitions[partid].sn.uv; | ||
48 | |||
49 | spin_lock_init(&part_uv->flags_lock); | ||
50 | part_uv->remote_act_state = XPC_P_AS_INACTIVE; | ||
51 | } | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static void * | ||
56 | xpc_create_gru_mq_uv(unsigned int mq_size, int cpuid, unsigned int irq, | ||
57 | irq_handler_t irq_handler) | ||
58 | { | ||
59 | int ret; | ||
60 | int nid; | ||
61 | int mq_order; | ||
62 | struct page *page; | ||
63 | void *mq; | ||
64 | |||
65 | nid = cpu_to_node(cpuid); | ||
66 | mq_order = get_order(mq_size); | ||
67 | page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, | ||
68 | mq_order); | ||
69 | if (page == NULL) { | ||
70 | dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d " | ||
71 | "bytes of memory on nid=%d for GRU mq\n", mq_size, nid); | ||
72 | return NULL; | ||
73 | } | ||
74 | |||
75 | mq = page_address(page); | ||
76 | ret = gru_create_message_queue(mq, mq_size); | ||
77 | if (ret != 0) { | ||
78 | dev_err(xpc_part, "gru_create_message_queue() returned " | ||
79 | "error=%d\n", ret); | ||
80 | free_pages((unsigned long)mq, mq_order); | ||
81 | return NULL; | ||
82 | } | ||
83 | |||
84 | /* !!! Need to do some other things to set up IRQ */ | ||
85 | |||
86 | ret = request_irq(irq, irq_handler, 0, "xpc", NULL); | ||
87 | if (ret != 0) { | ||
88 | dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n", | ||
89 | irq, ret); | ||
90 | free_pages((unsigned long)mq, mq_order); | ||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | /* !!! enable generation of irq when GRU mq op occurs to this mq */ | ||
95 | |||
96 | /* ??? allow other partitions to access GRU mq? */ | ||
97 | |||
98 | return mq; | ||
99 | } | ||
100 | |||
101 | static void | ||
102 | xpc_destroy_gru_mq_uv(void *mq, unsigned int mq_size, unsigned int irq) | ||
103 | { | ||
104 | /* ??? disallow other partitions to access GRU mq? */ | ||
105 | |||
106 | /* !!! disable generation of irq when GRU mq op occurs to this mq */ | ||
107 | |||
108 | free_irq(irq, NULL); | ||
109 | |||
110 | free_pages((unsigned long)mq, get_order(mq_size)); | ||
111 | } | ||
112 | |||
113 | static enum xp_retval | ||
114 | xpc_send_gru_msg(unsigned long mq_gpa, void *msg, size_t msg_size) | ||
115 | { | ||
116 | enum xp_retval xp_ret; | ||
117 | int ret; | ||
118 | |||
119 | while (1) { | ||
120 | ret = gru_send_message_gpa(mq_gpa, msg, msg_size); | ||
121 | if (ret == MQE_OK) { | ||
122 | xp_ret = xpSuccess; | ||
123 | break; | ||
124 | } | ||
125 | |||
126 | if (ret == MQE_QUEUE_FULL) { | ||
127 | dev_dbg(xpc_chan, "gru_send_message_gpa() returned " | ||
128 | "error=MQE_QUEUE_FULL\n"); | ||
129 | /* !!! handle QLimit reached; delay & try again */ | ||
130 | /* ??? Do we add a limit to the number of retries? */ | ||
131 | (void)msleep_interruptible(10); | ||
132 | } else if (ret == MQE_CONGESTION) { | ||
133 | dev_dbg(xpc_chan, "gru_send_message_gpa() returned " | ||
134 | "error=MQE_CONGESTION\n"); | ||
135 | /* !!! handle LB Overflow; simply try again */ | ||
136 | /* ??? Do we add a limit to the number of retries? */ | ||
137 | } else { | ||
138 | /* !!! Currently this is MQE_UNEXPECTED_CB_ERR */ | ||
139 | dev_err(xpc_chan, "gru_send_message_gpa() returned " | ||
140 | "error=%d\n", ret); | ||
141 | xp_ret = xpGruSendMqError; | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | return xp_ret; | ||
146 | } | ||
147 | |||
148 | static void | ||
149 | xpc_process_activate_IRQ_rcvd_uv(void) | ||
150 | { | ||
151 | unsigned long irq_flags; | ||
152 | short partid; | ||
153 | struct xpc_partition *part; | ||
154 | u8 act_state_req; | ||
155 | |||
156 | DBUG_ON(xpc_activate_IRQ_rcvd == 0); | ||
157 | |||
158 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
159 | for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) { | ||
160 | part = &xpc_partitions[partid]; | ||
161 | |||
162 | if (part->sn.uv.act_state_req == 0) | ||
163 | continue; | ||
164 | |||
165 | xpc_activate_IRQ_rcvd--; | ||
166 | BUG_ON(xpc_activate_IRQ_rcvd < 0); | ||
167 | |||
168 | act_state_req = part->sn.uv.act_state_req; | ||
169 | part->sn.uv.act_state_req = 0; | ||
170 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
171 | |||
172 | if (act_state_req == XPC_P_ASR_ACTIVATE_UV) { | ||
173 | if (part->act_state == XPC_P_AS_INACTIVE) | ||
174 | xpc_activate_partition(part); | ||
175 | else if (part->act_state == XPC_P_AS_DEACTIVATING) | ||
176 | XPC_DEACTIVATE_PARTITION(part, xpReactivating); | ||
177 | |||
178 | } else if (act_state_req == XPC_P_ASR_REACTIVATE_UV) { | ||
179 | if (part->act_state == XPC_P_AS_INACTIVE) | ||
180 | xpc_activate_partition(part); | ||
181 | else | ||
182 | XPC_DEACTIVATE_PARTITION(part, xpReactivating); | ||
183 | |||
184 | } else if (act_state_req == XPC_P_ASR_DEACTIVATE_UV) { | ||
185 | XPC_DEACTIVATE_PARTITION(part, part->sn.uv.reason); | ||
186 | |||
187 | } else { | ||
188 | BUG(); | ||
189 | } | ||
190 | |||
191 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
192 | if (xpc_activate_IRQ_rcvd == 0) | ||
193 | break; | ||
194 | } | ||
195 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
196 | |||
197 | } | ||
198 | |||
199 | static void | ||
200 | xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, | ||
201 | struct xpc_activate_mq_msghdr_uv *msg_hdr, | ||
202 | int *wakeup_hb_checker) | ||
203 | { | ||
204 | unsigned long irq_flags; | ||
205 | struct xpc_partition_uv *part_uv = &part->sn.uv; | ||
206 | struct xpc_openclose_args *args; | ||
207 | |||
208 | part_uv->remote_act_state = msg_hdr->act_state; | ||
209 | |||
210 | switch (msg_hdr->type) { | ||
211 | case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV: | ||
212 | /* syncing of remote_act_state was just done above */ | ||
213 | break; | ||
214 | |||
215 | case XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV: { | ||
216 | struct xpc_activate_mq_msg_heartbeat_req_uv *msg; | ||
217 | |||
218 | msg = container_of(msg_hdr, | ||
219 | struct xpc_activate_mq_msg_heartbeat_req_uv, | ||
220 | hdr); | ||
221 | part_uv->heartbeat = msg->heartbeat; | ||
222 | break; | ||
223 | } | ||
224 | case XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV: { | ||
225 | struct xpc_activate_mq_msg_heartbeat_req_uv *msg; | ||
226 | |||
227 | msg = container_of(msg_hdr, | ||
228 | struct xpc_activate_mq_msg_heartbeat_req_uv, | ||
229 | hdr); | ||
230 | part_uv->heartbeat = msg->heartbeat; | ||
231 | |||
232 | spin_lock_irqsave(&part_uv->flags_lock, irq_flags); | ||
233 | part_uv->flags |= XPC_P_HEARTBEAT_OFFLINE_UV; | ||
234 | spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); | ||
235 | break; | ||
236 | } | ||
237 | case XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV: { | ||
238 | struct xpc_activate_mq_msg_heartbeat_req_uv *msg; | ||
239 | |||
240 | msg = container_of(msg_hdr, | ||
241 | struct xpc_activate_mq_msg_heartbeat_req_uv, | ||
242 | hdr); | ||
243 | part_uv->heartbeat = msg->heartbeat; | ||
244 | |||
245 | spin_lock_irqsave(&part_uv->flags_lock, irq_flags); | ||
246 | part_uv->flags &= ~XPC_P_HEARTBEAT_OFFLINE_UV; | ||
247 | spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); | ||
248 | break; | ||
249 | } | ||
250 | case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: { | ||
251 | struct xpc_activate_mq_msg_activate_req_uv *msg; | ||
252 | |||
253 | /* | ||
254 | * ??? Do we deal here with ts_jiffies being different | ||
255 | * ??? if act_state != XPC_P_AS_INACTIVE instead of | ||
256 | * ??? below? | ||
257 | */ | ||
258 | msg = container_of(msg_hdr, struct | ||
259 | xpc_activate_mq_msg_activate_req_uv, hdr); | ||
260 | |||
261 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
262 | if (part_uv->act_state_req == 0) | ||
263 | xpc_activate_IRQ_rcvd++; | ||
264 | part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV; | ||
265 | part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */ | ||
266 | part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies; | ||
267 | part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa; | ||
268 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
269 | |||
270 | (*wakeup_hb_checker)++; | ||
271 | break; | ||
272 | } | ||
273 | case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: { | ||
274 | struct xpc_activate_mq_msg_deactivate_req_uv *msg; | ||
275 | |||
276 | msg = container_of(msg_hdr, struct | ||
277 | xpc_activate_mq_msg_deactivate_req_uv, hdr); | ||
278 | |||
279 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
280 | if (part_uv->act_state_req == 0) | ||
281 | xpc_activate_IRQ_rcvd++; | ||
282 | part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; | ||
283 | part_uv->reason = msg->reason; | ||
284 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
285 | |||
286 | (*wakeup_hb_checker)++; | ||
287 | return; | ||
288 | } | ||
289 | case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: { | ||
290 | struct xpc_activate_mq_msg_chctl_closerequest_uv *msg; | ||
291 | |||
292 | msg = container_of(msg_hdr, struct | ||
293 | xpc_activate_mq_msg_chctl_closerequest_uv, | ||
294 | hdr); | ||
295 | args = &part->remote_openclose_args[msg->ch_number]; | ||
296 | args->reason = msg->reason; | ||
297 | |||
298 | spin_lock_irqsave(&part->chctl_lock, irq_flags); | ||
299 | part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREQUEST; | ||
300 | spin_unlock_irqrestore(&part->chctl_lock, irq_flags); | ||
301 | |||
302 | xpc_wakeup_channel_mgr(part); | ||
303 | break; | ||
304 | } | ||
305 | case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: { | ||
306 | struct xpc_activate_mq_msg_chctl_closereply_uv *msg; | ||
307 | |||
308 | msg = container_of(msg_hdr, struct | ||
309 | xpc_activate_mq_msg_chctl_closereply_uv, | ||
310 | hdr); | ||
311 | |||
312 | spin_lock_irqsave(&part->chctl_lock, irq_flags); | ||
313 | part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREPLY; | ||
314 | spin_unlock_irqrestore(&part->chctl_lock, irq_flags); | ||
315 | |||
316 | xpc_wakeup_channel_mgr(part); | ||
317 | break; | ||
318 | } | ||
319 | case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: { | ||
320 | struct xpc_activate_mq_msg_chctl_openrequest_uv *msg; | ||
321 | |||
322 | msg = container_of(msg_hdr, struct | ||
323 | xpc_activate_mq_msg_chctl_openrequest_uv, | ||
324 | hdr); | ||
325 | args = &part->remote_openclose_args[msg->ch_number]; | ||
326 | args->entry_size = msg->entry_size; | ||
327 | args->local_nentries = msg->local_nentries; | ||
328 | |||
329 | spin_lock_irqsave(&part->chctl_lock, irq_flags); | ||
330 | part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREQUEST; | ||
331 | spin_unlock_irqrestore(&part->chctl_lock, irq_flags); | ||
332 | |||
333 | xpc_wakeup_channel_mgr(part); | ||
334 | break; | ||
335 | } | ||
336 | case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: { | ||
337 | struct xpc_activate_mq_msg_chctl_openreply_uv *msg; | ||
338 | |||
339 | msg = container_of(msg_hdr, struct | ||
340 | xpc_activate_mq_msg_chctl_openreply_uv, hdr); | ||
341 | args = &part->remote_openclose_args[msg->ch_number]; | ||
342 | args->remote_nentries = msg->remote_nentries; | ||
343 | args->local_nentries = msg->local_nentries; | ||
344 | args->local_msgqueue_pa = msg->local_notify_mq_gpa; | ||
345 | |||
346 | spin_lock_irqsave(&part->chctl_lock, irq_flags); | ||
347 | part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREPLY; | ||
348 | spin_unlock_irqrestore(&part->chctl_lock, irq_flags); | ||
349 | |||
350 | xpc_wakeup_channel_mgr(part); | ||
351 | break; | ||
352 | } | ||
353 | case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV: | ||
354 | spin_lock_irqsave(&part_uv->flags_lock, irq_flags); | ||
355 | part_uv->flags |= XPC_P_ENGAGED_UV; | ||
356 | spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); | ||
357 | break; | ||
358 | |||
359 | case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV: | ||
360 | spin_lock_irqsave(&part_uv->flags_lock, irq_flags); | ||
361 | part_uv->flags &= ~XPC_P_ENGAGED_UV; | ||
362 | spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); | ||
363 | break; | ||
364 | |||
365 | default: | ||
366 | dev_err(xpc_part, "received unknown activate_mq msg type=%d " | ||
367 | "from partition=%d\n", msg_hdr->type, XPC_PARTID(part)); | ||
368 | |||
369 | /* get hb checker to deactivate from the remote partition */ | ||
370 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
371 | if (part_uv->act_state_req == 0) | ||
372 | xpc_activate_IRQ_rcvd++; | ||
373 | part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; | ||
374 | part_uv->reason = xpBadMsgType; | ||
375 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
376 | |||
377 | (*wakeup_hb_checker)++; | ||
378 | return; | ||
379 | } | ||
380 | |||
381 | if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies && | ||
382 | part->remote_rp_ts_jiffies != 0) { | ||
383 | /* | ||
384 | * ??? Does what we do here need to be sensitive to | ||
385 | * ??? act_state or remote_act_state? | ||
386 | */ | ||
387 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
388 | if (part_uv->act_state_req == 0) | ||
389 | xpc_activate_IRQ_rcvd++; | ||
390 | part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV; | ||
391 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
392 | |||
393 | (*wakeup_hb_checker)++; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | static irqreturn_t | ||
398 | xpc_handle_activate_IRQ_uv(int irq, void *dev_id) | ||
399 | { | ||
400 | struct xpc_activate_mq_msghdr_uv *msg_hdr; | ||
401 | short partid; | ||
402 | struct xpc_partition *part; | ||
403 | int wakeup_hb_checker = 0; | ||
404 | |||
405 | while ((msg_hdr = gru_get_next_message(xpc_activate_mq_uv)) != NULL) { | ||
406 | |||
407 | partid = msg_hdr->partid; | ||
408 | if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) { | ||
409 | dev_err(xpc_part, "xpc_handle_activate_IRQ_uv() " | ||
410 | "received invalid partid=0x%x in message\n", | ||
411 | partid); | ||
412 | } else { | ||
413 | part = &xpc_partitions[partid]; | ||
414 | if (xpc_part_ref(part)) { | ||
415 | xpc_handle_activate_mq_msg_uv(part, msg_hdr, | ||
416 | &wakeup_hb_checker); | ||
417 | xpc_part_deref(part); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | gru_free_message(xpc_activate_mq_uv, msg_hdr); | ||
422 | } | ||
423 | |||
424 | if (wakeup_hb_checker) | ||
425 | wake_up_interruptible(&xpc_activate_IRQ_wq); | ||
426 | |||
427 | return IRQ_HANDLED; | ||
428 | } | ||
429 | |||
430 | static enum xp_retval | ||
431 | xpc_send_activate_IRQ_uv(struct xpc_partition *part, void *msg, size_t msg_size, | ||
432 | int msg_type) | ||
433 | { | ||
434 | struct xpc_activate_mq_msghdr_uv *msg_hdr = msg; | ||
435 | |||
436 | DBUG_ON(msg_size > XPC_ACTIVATE_MSG_SIZE_UV); | ||
437 | |||
438 | msg_hdr->type = msg_type; | ||
439 | msg_hdr->partid = XPC_PARTID(part); | ||
440 | msg_hdr->act_state = part->act_state; | ||
441 | msg_hdr->rp_ts_jiffies = xpc_rsvd_page->ts_jiffies; | ||
442 | |||
443 | /* ??? Is holding a spin_lock (ch->lock) during this call a bad idea? */ | ||
444 | return xpc_send_gru_msg(part->sn.uv.remote_activate_mq_gpa, msg, | ||
445 | msg_size); | ||
446 | } | ||
447 | |||
448 | static void | ||
449 | xpc_send_activate_IRQ_part_uv(struct xpc_partition *part, void *msg, | ||
450 | size_t msg_size, int msg_type) | ||
451 | { | ||
452 | enum xp_retval ret; | ||
453 | |||
454 | ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type); | ||
455 | if (unlikely(ret != xpSuccess)) | ||
456 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
457 | } | ||
458 | |||
459 | static void | ||
460 | xpc_send_activate_IRQ_ch_uv(struct xpc_channel *ch, unsigned long *irq_flags, | ||
461 | void *msg, size_t msg_size, int msg_type) | ||
462 | { | ||
463 | struct xpc_partition *part = &xpc_partitions[ch->number]; | ||
464 | enum xp_retval ret; | ||
465 | |||
466 | ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type); | ||
467 | if (unlikely(ret != xpSuccess)) { | ||
468 | if (irq_flags != NULL) | ||
469 | spin_unlock_irqrestore(&ch->lock, *irq_flags); | ||
470 | |||
471 | XPC_DEACTIVATE_PARTITION(part, ret); | ||
472 | |||
473 | if (irq_flags != NULL) | ||
474 | spin_lock_irqsave(&ch->lock, *irq_flags); | ||
475 | } | ||
476 | } | ||
477 | |||
478 | static void | ||
479 | xpc_send_local_activate_IRQ_uv(struct xpc_partition *part, int act_state_req) | ||
480 | { | ||
481 | unsigned long irq_flags; | ||
482 | struct xpc_partition_uv *part_uv = &part->sn.uv; | ||
483 | |||
484 | /* | ||
485 | * !!! Make our side think that the remote parition sent an activate | ||
486 | * !!! message our way by doing what the activate IRQ handler would | ||
487 | * !!! do had one really been sent. | ||
488 | */ | ||
489 | |||
490 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
491 | if (part_uv->act_state_req == 0) | ||
492 | xpc_activate_IRQ_rcvd++; | ||
493 | part_uv->act_state_req = act_state_req; | ||
494 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
495 | |||
496 | wake_up_interruptible(&xpc_activate_IRQ_wq); | ||
497 | } | ||
498 | |||
499 | static enum xp_retval | ||
500 | xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa, | ||
501 | size_t *len) | ||
502 | { | ||
503 | /* !!! call the UV version of sn_partition_reserved_page_pa() */ | ||
504 | return xpUnsupported; | ||
505 | } | ||
506 | |||
507 | static int | ||
508 | xpc_setup_rsvd_page_sn_uv(struct xpc_rsvd_page *rp) | ||
509 | { | ||
510 | rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv); | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static void | ||
515 | xpc_send_heartbeat_uv(int msg_type) | ||
516 | { | ||
517 | short partid; | ||
518 | struct xpc_partition *part; | ||
519 | struct xpc_activate_mq_msg_heartbeat_req_uv msg; | ||
520 | |||
521 | /* | ||
522 | * !!! On uv we're broadcasting a heartbeat message every 5 seconds. | ||
523 | * !!! Whereas on sn2 we're bte_copy'ng the heartbeat info every 20 | ||
524 | * !!! seconds. This is an increase in numalink traffic. | ||
525 | * ??? Is this good? | ||
526 | */ | ||
527 | |||
528 | msg.heartbeat = atomic64_inc_return(&xpc_heartbeat_uv); | ||
529 | |||
530 | partid = find_first_bit(xpc_heartbeating_to_mask_uv, | ||
531 | XP_MAX_NPARTITIONS_UV); | ||
532 | |||
533 | while (partid < XP_MAX_NPARTITIONS_UV) { | ||
534 | part = &xpc_partitions[partid]; | ||
535 | |||
536 | xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), | ||
537 | msg_type); | ||
538 | |||
539 | partid = find_next_bit(xpc_heartbeating_to_mask_uv, | ||
540 | XP_MAX_NPARTITIONS_UV, partid + 1); | ||
541 | } | ||
542 | } | ||
543 | |||
544 | static void | ||
545 | xpc_increment_heartbeat_uv(void) | ||
546 | { | ||
547 | xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV); | ||
548 | } | ||
549 | |||
550 | static void | ||
551 | xpc_offline_heartbeat_uv(void) | ||
552 | { | ||
553 | xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV); | ||
554 | } | ||
555 | |||
556 | static void | ||
557 | xpc_online_heartbeat_uv(void) | ||
558 | { | ||
559 | xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV); | ||
560 | } | ||
561 | |||
562 | static void | ||
563 | xpc_heartbeat_init_uv(void) | ||
564 | { | ||
565 | atomic64_set(&xpc_heartbeat_uv, 0); | ||
566 | bitmap_zero(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); | ||
567 | xpc_heartbeating_to_mask = &xpc_heartbeating_to_mask_uv[0]; | ||
568 | } | ||
569 | |||
570 | static void | ||
571 | xpc_heartbeat_exit_uv(void) | ||
572 | { | ||
573 | xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV); | ||
574 | } | ||
575 | |||
576 | static enum xp_retval | ||
577 | xpc_get_remote_heartbeat_uv(struct xpc_partition *part) | ||
578 | { | ||
579 | struct xpc_partition_uv *part_uv = &part->sn.uv; | ||
580 | enum xp_retval ret = xpNoHeartbeat; | ||
581 | |||
582 | if (part_uv->remote_act_state != XPC_P_AS_INACTIVE && | ||
583 | part_uv->remote_act_state != XPC_P_AS_DEACTIVATING) { | ||
584 | |||
585 | if (part_uv->heartbeat != part->last_heartbeat || | ||
586 | (part_uv->flags & XPC_P_HEARTBEAT_OFFLINE_UV)) { | ||
587 | |||
588 | part->last_heartbeat = part_uv->heartbeat; | ||
589 | ret = xpSuccess; | ||
590 | } | ||
591 | } | ||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | static void | ||
596 | xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp, | ||
597 | unsigned long remote_rp_gpa, int nasid) | ||
598 | { | ||
599 | short partid = remote_rp->SAL_partid; | ||
600 | struct xpc_partition *part = &xpc_partitions[partid]; | ||
601 | struct xpc_activate_mq_msg_activate_req_uv msg; | ||
602 | |||
603 | part->remote_rp_pa = remote_rp_gpa; /* !!! _pa here is really _gpa */ | ||
604 | part->remote_rp_ts_jiffies = remote_rp->ts_jiffies; | ||
605 | part->sn.uv.remote_activate_mq_gpa = remote_rp->sn.activate_mq_gpa; | ||
606 | |||
607 | /* | ||
608 | * ??? Is it a good idea to make this conditional on what is | ||
609 | * ??? potentially stale state information? | ||
610 | */ | ||
611 | if (part->sn.uv.remote_act_state == XPC_P_AS_INACTIVE) { | ||
612 | msg.rp_gpa = uv_gpa(xpc_rsvd_page); | ||
613 | msg.activate_mq_gpa = xpc_rsvd_page->sn.activate_mq_gpa; | ||
614 | xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), | ||
615 | XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV); | ||
616 | } | ||
617 | |||
618 | if (part->act_state == XPC_P_AS_INACTIVE) | ||
619 | xpc_send_local_activate_IRQ_uv(part, XPC_P_ASR_ACTIVATE_UV); | ||
620 | } | ||
621 | |||
622 | static void | ||
623 | xpc_request_partition_reactivation_uv(struct xpc_partition *part) | ||
624 | { | ||
625 | xpc_send_local_activate_IRQ_uv(part, XPC_P_ASR_ACTIVATE_UV); | ||
626 | } | ||
627 | |||
628 | static void | ||
629 | xpc_request_partition_deactivation_uv(struct xpc_partition *part) | ||
630 | { | ||
631 | struct xpc_activate_mq_msg_deactivate_req_uv msg; | ||
632 | |||
633 | /* | ||
634 | * ??? Is it a good idea to make this conditional on what is | ||
635 | * ??? potentially stale state information? | ||
636 | */ | ||
637 | if (part->sn.uv.remote_act_state != XPC_P_AS_DEACTIVATING && | ||
638 | part->sn.uv.remote_act_state != XPC_P_AS_INACTIVE) { | ||
639 | |||
640 | msg.reason = part->reason; | ||
641 | xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), | ||
642 | XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV); | ||
643 | } | ||
644 | } | ||
645 | |||
646 | static void | ||
647 | xpc_cancel_partition_deactivation_request_uv(struct xpc_partition *part) | ||
648 | { | ||
649 | /* nothing needs to be done */ | ||
650 | return; | ||
651 | } | ||
652 | |||
653 | static void | ||
654 | xpc_init_fifo_uv(struct xpc_fifo_head_uv *head) | ||
655 | { | ||
656 | head->first = NULL; | ||
657 | head->last = NULL; | ||
658 | spin_lock_init(&head->lock); | ||
659 | head->n_entries = 0; | ||
660 | } | ||
661 | |||
662 | static void * | ||
663 | xpc_get_fifo_entry_uv(struct xpc_fifo_head_uv *head) | ||
664 | { | ||
665 | unsigned long irq_flags; | ||
666 | struct xpc_fifo_entry_uv *first; | ||
667 | |||
668 | spin_lock_irqsave(&head->lock, irq_flags); | ||
669 | first = head->first; | ||
670 | if (head->first != NULL) { | ||
671 | head->first = first->next; | ||
672 | if (head->first == NULL) | ||
673 | head->last = NULL; | ||
674 | } | ||
675 | head->n_entries++; | ||
676 | spin_unlock_irqrestore(&head->lock, irq_flags); | ||
677 | first->next = NULL; | ||
678 | return first; | ||
679 | } | ||
680 | |||
681 | static void | ||
682 | xpc_put_fifo_entry_uv(struct xpc_fifo_head_uv *head, | ||
683 | struct xpc_fifo_entry_uv *last) | ||
684 | { | ||
685 | unsigned long irq_flags; | ||
686 | |||
687 | last->next = NULL; | ||
688 | spin_lock_irqsave(&head->lock, irq_flags); | ||
689 | if (head->last != NULL) | ||
690 | head->last->next = last; | ||
691 | else | ||
692 | head->first = last; | ||
693 | head->last = last; | ||
694 | head->n_entries--; | ||
695 | BUG_ON(head->n_entries < 0); | ||
696 | spin_unlock_irqrestore(&head->lock, irq_flags); | ||
697 | } | ||
698 | |||
699 | static int | ||
700 | xpc_n_of_fifo_entries_uv(struct xpc_fifo_head_uv *head) | ||
701 | { | ||
702 | return head->n_entries; | ||
703 | } | ||
704 | |||
705 | /* | ||
706 | * Setup the channel structures that are uv specific. | ||
707 | */ | ||
708 | static enum xp_retval | ||
709 | xpc_setup_ch_structures_sn_uv(struct xpc_partition *part) | ||
710 | { | ||
711 | struct xpc_channel_uv *ch_uv; | ||
712 | int ch_number; | ||
713 | |||
714 | for (ch_number = 0; ch_number < part->nchannels; ch_number++) { | ||
715 | ch_uv = &part->channels[ch_number].sn.uv; | ||
716 | |||
717 | xpc_init_fifo_uv(&ch_uv->msg_slot_free_list); | ||
718 | xpc_init_fifo_uv(&ch_uv->recv_msg_list); | ||
719 | } | ||
720 | |||
721 | return xpSuccess; | ||
722 | } | ||
723 | |||
724 | /* | ||
725 | * Teardown the channel structures that are uv specific. | ||
726 | */ | ||
727 | static void | ||
728 | xpc_teardown_ch_structures_sn_uv(struct xpc_partition *part) | ||
729 | { | ||
730 | /* nothing needs to be done */ | ||
731 | return; | ||
732 | } | ||
733 | |||
734 | static enum xp_retval | ||
735 | xpc_make_first_contact_uv(struct xpc_partition *part) | ||
736 | { | ||
737 | struct xpc_activate_mq_msg_uv msg; | ||
738 | |||
739 | /* | ||
740 | * We send a sync msg to get the remote partition's remote_act_state | ||
741 | * updated to our current act_state which at this point should | ||
742 | * be XPC_P_AS_ACTIVATING. | ||
743 | */ | ||
744 | xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), | ||
745 | XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV); | ||
746 | |||
747 | while (part->sn.uv.remote_act_state != XPC_P_AS_ACTIVATING) { | ||
748 | |||
749 | dev_dbg(xpc_part, "waiting to make first contact with " | ||
750 | "partition %d\n", XPC_PARTID(part)); | ||
751 | |||
752 | /* wait a 1/4 of a second or so */ | ||
753 | (void)msleep_interruptible(250); | ||
754 | |||
755 | if (part->act_state == XPC_P_AS_DEACTIVATING) | ||
756 | return part->reason; | ||
757 | } | ||
758 | |||
759 | return xpSuccess; | ||
760 | } | ||
761 | |||
762 | static u64 | ||
763 | xpc_get_chctl_all_flags_uv(struct xpc_partition *part) | ||
764 | { | ||
765 | unsigned long irq_flags; | ||
766 | union xpc_channel_ctl_flags chctl; | ||
767 | |||
768 | spin_lock_irqsave(&part->chctl_lock, irq_flags); | ||
769 | chctl = part->chctl; | ||
770 | if (chctl.all_flags != 0) | ||
771 | part->chctl.all_flags = 0; | ||
772 | |||
773 | spin_unlock_irqrestore(&part->chctl_lock, irq_flags); | ||
774 | return chctl.all_flags; | ||
775 | } | ||
776 | |||
777 | static enum xp_retval | ||
778 | xpc_allocate_send_msg_slot_uv(struct xpc_channel *ch) | ||
779 | { | ||
780 | struct xpc_channel_uv *ch_uv = &ch->sn.uv; | ||
781 | struct xpc_send_msg_slot_uv *msg_slot; | ||
782 | unsigned long irq_flags; | ||
783 | int nentries; | ||
784 | int entry; | ||
785 | size_t nbytes; | ||
786 | |||
787 | for (nentries = ch->local_nentries; nentries > 0; nentries--) { | ||
788 | nbytes = nentries * sizeof(struct xpc_send_msg_slot_uv); | ||
789 | ch_uv->send_msg_slots = kzalloc(nbytes, GFP_KERNEL); | ||
790 | if (ch_uv->send_msg_slots == NULL) | ||
791 | continue; | ||
792 | |||
793 | for (entry = 0; entry < nentries; entry++) { | ||
794 | msg_slot = &ch_uv->send_msg_slots[entry]; | ||
795 | |||
796 | msg_slot->msg_slot_number = entry; | ||
797 | xpc_put_fifo_entry_uv(&ch_uv->msg_slot_free_list, | ||
798 | &msg_slot->next); | ||
799 | } | ||
800 | |||
801 | spin_lock_irqsave(&ch->lock, irq_flags); | ||
802 | if (nentries < ch->local_nentries) | ||
803 | ch->local_nentries = nentries; | ||
804 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
805 | return xpSuccess; | ||
806 | } | ||
807 | |||
808 | return xpNoMemory; | ||
809 | } | ||
810 | |||
811 | static enum xp_retval | ||
812 | xpc_allocate_recv_msg_slot_uv(struct xpc_channel *ch) | ||
813 | { | ||
814 | struct xpc_channel_uv *ch_uv = &ch->sn.uv; | ||
815 | struct xpc_notify_mq_msg_uv *msg_slot; | ||
816 | unsigned long irq_flags; | ||
817 | int nentries; | ||
818 | int entry; | ||
819 | size_t nbytes; | ||
820 | |||
821 | for (nentries = ch->remote_nentries; nentries > 0; nentries--) { | ||
822 | nbytes = nentries * ch->entry_size; | ||
823 | ch_uv->recv_msg_slots = kzalloc(nbytes, GFP_KERNEL); | ||
824 | if (ch_uv->recv_msg_slots == NULL) | ||
825 | continue; | ||
826 | |||
827 | for (entry = 0; entry < nentries; entry++) { | ||
828 | msg_slot = ch_uv->recv_msg_slots + entry * | ||
829 | ch->entry_size; | ||
830 | |||
831 | msg_slot->hdr.msg_slot_number = entry; | ||
832 | } | ||
833 | |||
834 | spin_lock_irqsave(&ch->lock, irq_flags); | ||
835 | if (nentries < ch->remote_nentries) | ||
836 | ch->remote_nentries = nentries; | ||
837 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
838 | return xpSuccess; | ||
839 | } | ||
840 | |||
841 | return xpNoMemory; | ||
842 | } | ||
843 | |||
844 | /* | ||
845 | * Allocate msg_slots associated with the channel. | ||
846 | */ | ||
847 | static enum xp_retval | ||
848 | xpc_setup_msg_structures_uv(struct xpc_channel *ch) | ||
849 | { | ||
850 | static enum xp_retval ret; | ||
851 | struct xpc_channel_uv *ch_uv = &ch->sn.uv; | ||
852 | |||
853 | DBUG_ON(ch->flags & XPC_C_SETUP); | ||
854 | |||
855 | ret = xpc_allocate_send_msg_slot_uv(ch); | ||
856 | if (ret == xpSuccess) { | ||
857 | |||
858 | ret = xpc_allocate_recv_msg_slot_uv(ch); | ||
859 | if (ret != xpSuccess) { | ||
860 | kfree(ch_uv->send_msg_slots); | ||
861 | xpc_init_fifo_uv(&ch_uv->msg_slot_free_list); | ||
862 | } | ||
863 | } | ||
864 | return ret; | ||
865 | } | ||
866 | |||
867 | /* | ||
868 | * Free up msg_slots and clear other stuff that were setup for the specified | ||
869 | * channel. | ||
870 | */ | ||
871 | static void | ||
872 | xpc_teardown_msg_structures_uv(struct xpc_channel *ch) | ||
873 | { | ||
874 | struct xpc_channel_uv *ch_uv = &ch->sn.uv; | ||
875 | |||
876 | DBUG_ON(!spin_is_locked(&ch->lock)); | ||
877 | |||
878 | ch_uv->remote_notify_mq_gpa = 0; | ||
879 | |||
880 | if (ch->flags & XPC_C_SETUP) { | ||
881 | xpc_init_fifo_uv(&ch_uv->msg_slot_free_list); | ||
882 | kfree(ch_uv->send_msg_slots); | ||
883 | xpc_init_fifo_uv(&ch_uv->recv_msg_list); | ||
884 | kfree(ch_uv->recv_msg_slots); | ||
885 | } | ||
886 | } | ||
887 | |||
888 | static void | ||
889 | xpc_send_chctl_closerequest_uv(struct xpc_channel *ch, unsigned long *irq_flags) | ||
890 | { | ||
891 | struct xpc_activate_mq_msg_chctl_closerequest_uv msg; | ||
892 | |||
893 | msg.ch_number = ch->number; | ||
894 | msg.reason = ch->reason; | ||
895 | xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), | ||
896 | XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV); | ||
897 | } | ||
898 | |||
899 | static void | ||
900 | xpc_send_chctl_closereply_uv(struct xpc_channel *ch, unsigned long *irq_flags) | ||
901 | { | ||
902 | struct xpc_activate_mq_msg_chctl_closereply_uv msg; | ||
903 | |||
904 | msg.ch_number = ch->number; | ||
905 | xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), | ||
906 | XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV); | ||
907 | } | ||
908 | |||
909 | static void | ||
910 | xpc_send_chctl_openrequest_uv(struct xpc_channel *ch, unsigned long *irq_flags) | ||
911 | { | ||
912 | struct xpc_activate_mq_msg_chctl_openrequest_uv msg; | ||
913 | |||
914 | msg.ch_number = ch->number; | ||
915 | msg.entry_size = ch->entry_size; | ||
916 | msg.local_nentries = ch->local_nentries; | ||
917 | xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), | ||
918 | XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV); | ||
919 | } | ||
920 | |||
921 | static void | ||
922 | xpc_send_chctl_openreply_uv(struct xpc_channel *ch, unsigned long *irq_flags) | ||
923 | { | ||
924 | struct xpc_activate_mq_msg_chctl_openreply_uv msg; | ||
925 | |||
926 | msg.ch_number = ch->number; | ||
927 | msg.local_nentries = ch->local_nentries; | ||
928 | msg.remote_nentries = ch->remote_nentries; | ||
929 | msg.local_notify_mq_gpa = uv_gpa(xpc_notify_mq_uv); | ||
930 | xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), | ||
931 | XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV); | ||
932 | } | ||
933 | |||
934 | static void | ||
935 | xpc_send_chctl_local_msgrequest_uv(struct xpc_partition *part, int ch_number) | ||
936 | { | ||
937 | unsigned long irq_flags; | ||
938 | |||
939 | spin_lock_irqsave(&part->chctl_lock, irq_flags); | ||
940 | part->chctl.flags[ch_number] |= XPC_CHCTL_MSGREQUEST; | ||
941 | spin_unlock_irqrestore(&part->chctl_lock, irq_flags); | ||
942 | |||
943 | xpc_wakeup_channel_mgr(part); | ||
944 | } | ||
945 | |||
946 | static void | ||
947 | xpc_save_remote_msgqueue_pa_uv(struct xpc_channel *ch, | ||
948 | unsigned long msgqueue_pa) | ||
949 | { | ||
950 | ch->sn.uv.remote_notify_mq_gpa = msgqueue_pa; | ||
951 | } | ||
952 | |||
953 | static void | ||
954 | xpc_indicate_partition_engaged_uv(struct xpc_partition *part) | ||
955 | { | ||
956 | struct xpc_activate_mq_msg_uv msg; | ||
957 | |||
958 | xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), | ||
959 | XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV); | ||
960 | } | ||
961 | |||
962 | static void | ||
963 | xpc_indicate_partition_disengaged_uv(struct xpc_partition *part) | ||
964 | { | ||
965 | struct xpc_activate_mq_msg_uv msg; | ||
966 | |||
967 | xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), | ||
968 | XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV); | ||
969 | } | ||
970 | |||
971 | static void | ||
972 | xpc_assume_partition_disengaged_uv(short partid) | ||
973 | { | ||
974 | struct xpc_partition_uv *part_uv = &xpc_partitions[partid].sn.uv; | ||
975 | unsigned long irq_flags; | ||
976 | |||
977 | spin_lock_irqsave(&part_uv->flags_lock, irq_flags); | ||
978 | part_uv->flags &= ~XPC_P_ENGAGED_UV; | ||
979 | spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); | ||
980 | } | ||
981 | |||
982 | static int | ||
983 | xpc_partition_engaged_uv(short partid) | ||
984 | { | ||
985 | return (xpc_partitions[partid].sn.uv.flags & XPC_P_ENGAGED_UV) != 0; | ||
986 | } | ||
987 | |||
988 | static int | ||
989 | xpc_any_partition_engaged_uv(void) | ||
990 | { | ||
991 | struct xpc_partition_uv *part_uv; | ||
992 | short partid; | ||
993 | |||
994 | for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) { | ||
995 | part_uv = &xpc_partitions[partid].sn.uv; | ||
996 | if ((part_uv->flags & XPC_P_ENGAGED_UV) != 0) | ||
997 | return 1; | ||
998 | } | ||
999 | return 0; | ||
1000 | } | ||
1001 | |||
1002 | static enum xp_retval | ||
1003 | xpc_allocate_msg_slot_uv(struct xpc_channel *ch, u32 flags, | ||
1004 | struct xpc_send_msg_slot_uv **address_of_msg_slot) | ||
1005 | { | ||
1006 | enum xp_retval ret; | ||
1007 | struct xpc_send_msg_slot_uv *msg_slot; | ||
1008 | struct xpc_fifo_entry_uv *entry; | ||
1009 | |||
1010 | while (1) { | ||
1011 | entry = xpc_get_fifo_entry_uv(&ch->sn.uv.msg_slot_free_list); | ||
1012 | if (entry != NULL) | ||
1013 | break; | ||
1014 | |||
1015 | if (flags & XPC_NOWAIT) | ||
1016 | return xpNoWait; | ||
1017 | |||
1018 | ret = xpc_allocate_msg_wait(ch); | ||
1019 | if (ret != xpInterrupted && ret != xpTimeout) | ||
1020 | return ret; | ||
1021 | } | ||
1022 | |||
1023 | msg_slot = container_of(entry, struct xpc_send_msg_slot_uv, next); | ||
1024 | *address_of_msg_slot = msg_slot; | ||
1025 | return xpSuccess; | ||
1026 | } | ||
1027 | |||
1028 | static void | ||
1029 | xpc_free_msg_slot_uv(struct xpc_channel *ch, | ||
1030 | struct xpc_send_msg_slot_uv *msg_slot) | ||
1031 | { | ||
1032 | xpc_put_fifo_entry_uv(&ch->sn.uv.msg_slot_free_list, &msg_slot->next); | ||
1033 | |||
1034 | /* wakeup anyone waiting for a free msg slot */ | ||
1035 | if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) | ||
1036 | wake_up(&ch->msg_allocate_wq); | ||
1037 | } | ||
1038 | |||
1039 | static void | ||
1040 | xpc_notify_sender_uv(struct xpc_channel *ch, | ||
1041 | struct xpc_send_msg_slot_uv *msg_slot, | ||
1042 | enum xp_retval reason) | ||
1043 | { | ||
1044 | xpc_notify_func func = msg_slot->func; | ||
1045 | |||
1046 | if (func != NULL && cmpxchg(&msg_slot->func, func, NULL) == func) { | ||
1047 | |||
1048 | atomic_dec(&ch->n_to_notify); | ||
1049 | |||
1050 | dev_dbg(xpc_chan, "msg_slot->func() called, msg_slot=0x%p " | ||
1051 | "msg_slot_number=%d partid=%d channel=%d\n", msg_slot, | ||
1052 | msg_slot->msg_slot_number, ch->partid, ch->number); | ||
1053 | |||
1054 | func(reason, ch->partid, ch->number, msg_slot->key); | ||
1055 | |||
1056 | dev_dbg(xpc_chan, "msg_slot->func() returned, msg_slot=0x%p " | ||
1057 | "msg_slot_number=%d partid=%d channel=%d\n", msg_slot, | ||
1058 | msg_slot->msg_slot_number, ch->partid, ch->number); | ||
1059 | } | ||
1060 | } | ||
1061 | |||
1062 | static void | ||
1063 | xpc_handle_notify_mq_ack_uv(struct xpc_channel *ch, | ||
1064 | struct xpc_notify_mq_msg_uv *msg) | ||
1065 | { | ||
1066 | struct xpc_send_msg_slot_uv *msg_slot; | ||
1067 | int entry = msg->hdr.msg_slot_number % ch->local_nentries; | ||
1068 | |||
1069 | msg_slot = &ch->sn.uv.send_msg_slots[entry]; | ||
1070 | |||
1071 | BUG_ON(msg_slot->msg_slot_number != msg->hdr.msg_slot_number); | ||
1072 | msg_slot->msg_slot_number += ch->local_nentries; | ||
1073 | |||
1074 | if (msg_slot->func != NULL) | ||
1075 | xpc_notify_sender_uv(ch, msg_slot, xpMsgDelivered); | ||
1076 | |||
1077 | xpc_free_msg_slot_uv(ch, msg_slot); | ||
1078 | } | ||
1079 | |||
1080 | static void | ||
1081 | xpc_handle_notify_mq_msg_uv(struct xpc_partition *part, | ||
1082 | struct xpc_notify_mq_msg_uv *msg) | ||
1083 | { | ||
1084 | struct xpc_partition_uv *part_uv = &part->sn.uv; | ||
1085 | struct xpc_channel *ch; | ||
1086 | struct xpc_channel_uv *ch_uv; | ||
1087 | struct xpc_notify_mq_msg_uv *msg_slot; | ||
1088 | unsigned long irq_flags; | ||
1089 | int ch_number = msg->hdr.ch_number; | ||
1090 | |||
1091 | if (unlikely(ch_number >= part->nchannels)) { | ||
1092 | dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received invalid " | ||
1093 | "channel number=0x%x in message from partid=%d\n", | ||
1094 | ch_number, XPC_PARTID(part)); | ||
1095 | |||
1096 | /* get hb checker to deactivate from the remote partition */ | ||
1097 | spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
1098 | if (part_uv->act_state_req == 0) | ||
1099 | xpc_activate_IRQ_rcvd++; | ||
1100 | part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; | ||
1101 | part_uv->reason = xpBadChannelNumber; | ||
1102 | spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); | ||
1103 | |||
1104 | wake_up_interruptible(&xpc_activate_IRQ_wq); | ||
1105 | return; | ||
1106 | } | ||
1107 | |||
1108 | ch = &part->channels[ch_number]; | ||
1109 | xpc_msgqueue_ref(ch); | ||
1110 | |||
1111 | if (!(ch->flags & XPC_C_CONNECTED)) { | ||
1112 | xpc_msgqueue_deref(ch); | ||
1113 | return; | ||
1114 | } | ||
1115 | |||
1116 | /* see if we're really dealing with an ACK for a previously sent msg */ | ||
1117 | if (msg->hdr.size == 0) { | ||
1118 | xpc_handle_notify_mq_ack_uv(ch, msg); | ||
1119 | xpc_msgqueue_deref(ch); | ||
1120 | return; | ||
1121 | } | ||
1122 | |||
1123 | /* we're dealing with a normal message sent via the notify_mq */ | ||
1124 | ch_uv = &ch->sn.uv; | ||
1125 | |||
1126 | msg_slot = (struct xpc_notify_mq_msg_uv *)((u64)ch_uv->recv_msg_slots + | ||
1127 | (msg->hdr.msg_slot_number % ch->remote_nentries) * | ||
1128 | ch->entry_size); | ||
1129 | |||
1130 | BUG_ON(msg->hdr.msg_slot_number != msg_slot->hdr.msg_slot_number); | ||
1131 | BUG_ON(msg_slot->hdr.size != 0); | ||
1132 | |||
1133 | memcpy(msg_slot, msg, msg->hdr.size); | ||
1134 | |||
1135 | xpc_put_fifo_entry_uv(&ch_uv->recv_msg_list, &msg_slot->hdr.u.next); | ||
1136 | |||
1137 | if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) { | ||
1138 | /* | ||
1139 | * If there is an existing idle kthread get it to deliver | ||
1140 | * the payload, otherwise we'll have to get the channel mgr | ||
1141 | * for this partition to create a kthread to do the delivery. | ||
1142 | */ | ||
1143 | if (atomic_read(&ch->kthreads_idle) > 0) | ||
1144 | wake_up_nr(&ch->idle_wq, 1); | ||
1145 | else | ||
1146 | xpc_send_chctl_local_msgrequest_uv(part, ch->number); | ||
1147 | } | ||
1148 | xpc_msgqueue_deref(ch); | ||
1149 | } | ||
1150 | |||
1151 | static irqreturn_t | ||
1152 | xpc_handle_notify_IRQ_uv(int irq, void *dev_id) | ||
1153 | { | ||
1154 | struct xpc_notify_mq_msg_uv *msg; | ||
1155 | short partid; | ||
1156 | struct xpc_partition *part; | ||
1157 | |||
1158 | while ((msg = gru_get_next_message(xpc_notify_mq_uv)) != NULL) { | ||
1159 | |||
1160 | partid = msg->hdr.partid; | ||
1161 | if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) { | ||
1162 | dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received " | ||
1163 | "invalid partid=0x%x in message\n", partid); | ||
1164 | } else { | ||
1165 | part = &xpc_partitions[partid]; | ||
1166 | |||
1167 | if (xpc_part_ref(part)) { | ||
1168 | xpc_handle_notify_mq_msg_uv(part, msg); | ||
1169 | xpc_part_deref(part); | ||
1170 | } | ||
1171 | } | ||
1172 | |||
1173 | gru_free_message(xpc_notify_mq_uv, msg); | ||
1174 | } | ||
1175 | |||
1176 | return IRQ_HANDLED; | ||
1177 | } | ||
1178 | |||
1179 | static int | ||
1180 | xpc_n_of_deliverable_payloads_uv(struct xpc_channel *ch) | ||
1181 | { | ||
1182 | return xpc_n_of_fifo_entries_uv(&ch->sn.uv.recv_msg_list); | ||
1183 | } | ||
1184 | |||
1185 | static void | ||
1186 | xpc_process_msg_chctl_flags_uv(struct xpc_partition *part, int ch_number) | ||
1187 | { | ||
1188 | struct xpc_channel *ch = &part->channels[ch_number]; | ||
1189 | int ndeliverable_payloads; | ||
1190 | |||
1191 | xpc_msgqueue_ref(ch); | ||
1192 | |||
1193 | ndeliverable_payloads = xpc_n_of_deliverable_payloads_uv(ch); | ||
1194 | |||
1195 | if (ndeliverable_payloads > 0 && | ||
1196 | (ch->flags & XPC_C_CONNECTED) && | ||
1197 | (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE)) { | ||
1198 | |||
1199 | xpc_activate_kthreads(ch, ndeliverable_payloads); | ||
1200 | } | ||
1201 | |||
1202 | xpc_msgqueue_deref(ch); | ||
1203 | } | ||
1204 | |||
1205 | static enum xp_retval | ||
1206 | xpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload, | ||
1207 | u16 payload_size, u8 notify_type, xpc_notify_func func, | ||
1208 | void *key) | ||
1209 | { | ||
1210 | enum xp_retval ret = xpSuccess; | ||
1211 | struct xpc_send_msg_slot_uv *msg_slot = NULL; | ||
1212 | struct xpc_notify_mq_msg_uv *msg; | ||
1213 | u8 msg_buffer[XPC_NOTIFY_MSG_SIZE_UV]; | ||
1214 | size_t msg_size; | ||
1215 | |||
1216 | DBUG_ON(notify_type != XPC_N_CALL); | ||
1217 | |||
1218 | msg_size = sizeof(struct xpc_notify_mq_msghdr_uv) + payload_size; | ||
1219 | if (msg_size > ch->entry_size) | ||
1220 | return xpPayloadTooBig; | ||
1221 | |||
1222 | xpc_msgqueue_ref(ch); | ||
1223 | |||
1224 | if (ch->flags & XPC_C_DISCONNECTING) { | ||
1225 | ret = ch->reason; | ||
1226 | goto out_1; | ||
1227 | } | ||
1228 | if (!(ch->flags & XPC_C_CONNECTED)) { | ||
1229 | ret = xpNotConnected; | ||
1230 | goto out_1; | ||
1231 | } | ||
1232 | |||
1233 | ret = xpc_allocate_msg_slot_uv(ch, flags, &msg_slot); | ||
1234 | if (ret != xpSuccess) | ||
1235 | goto out_1; | ||
1236 | |||
1237 | if (func != NULL) { | ||
1238 | atomic_inc(&ch->n_to_notify); | ||
1239 | |||
1240 | msg_slot->key = key; | ||
1241 | wmb(); /* a non-NULL func must hit memory after the key */ | ||
1242 | msg_slot->func = func; | ||
1243 | |||
1244 | if (ch->flags & XPC_C_DISCONNECTING) { | ||
1245 | ret = ch->reason; | ||
1246 | goto out_2; | ||
1247 | } | ||
1248 | } | ||
1249 | |||
1250 | msg = (struct xpc_notify_mq_msg_uv *)&msg_buffer; | ||
1251 | msg->hdr.partid = xp_partition_id; | ||
1252 | msg->hdr.ch_number = ch->number; | ||
1253 | msg->hdr.size = msg_size; | ||
1254 | msg->hdr.msg_slot_number = msg_slot->msg_slot_number; | ||
1255 | memcpy(&msg->payload, payload, payload_size); | ||
1256 | |||
1257 | ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg, msg_size); | ||
1258 | if (ret == xpSuccess) | ||
1259 | goto out_1; | ||
1260 | |||
1261 | XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); | ||
1262 | out_2: | ||
1263 | if (func != NULL) { | ||
1264 | /* | ||
1265 | * Try to NULL the msg_slot's func field. If we fail, then | ||
1266 | * xpc_notify_senders_of_disconnect_uv() beat us to it, in which | ||
1267 | * case we need to pretend we succeeded to send the message | ||
1268 | * since the user will get a callout for the disconnect error | ||
1269 | * by xpc_notify_senders_of_disconnect_uv(), and to also get an | ||
1270 | * error returned here will confuse them. Additionally, since | ||
1271 | * in this case the channel is being disconnected we don't need | ||
1272 | * to put the the msg_slot back on the free list. | ||
1273 | */ | ||
1274 | if (cmpxchg(&msg_slot->func, func, NULL) != func) { | ||
1275 | ret = xpSuccess; | ||
1276 | goto out_1; | ||
1277 | } | ||
1278 | |||
1279 | msg_slot->key = NULL; | ||
1280 | atomic_dec(&ch->n_to_notify); | ||
1281 | } | ||
1282 | xpc_free_msg_slot_uv(ch, msg_slot); | ||
1283 | out_1: | ||
1284 | xpc_msgqueue_deref(ch); | ||
1285 | return ret; | ||
1286 | } | ||
1287 | |||
1288 | /* | ||
1289 | * Tell the callers of xpc_send_notify() that the status of their payloads | ||
1290 | * is unknown because the channel is now disconnecting. | ||
1291 | * | ||
1292 | * We don't worry about putting these msg_slots on the free list since the | ||
1293 | * msg_slots themselves are about to be kfree'd. | ||
1294 | */ | ||
1295 | static void | ||
1296 | xpc_notify_senders_of_disconnect_uv(struct xpc_channel *ch) | ||
1297 | { | ||
1298 | struct xpc_send_msg_slot_uv *msg_slot; | ||
1299 | int entry; | ||
1300 | |||
1301 | DBUG_ON(!(ch->flags & XPC_C_DISCONNECTING)); | ||
1302 | |||
1303 | for (entry = 0; entry < ch->local_nentries; entry++) { | ||
1304 | |||
1305 | if (atomic_read(&ch->n_to_notify) == 0) | ||
1306 | break; | ||
1307 | |||
1308 | msg_slot = &ch->sn.uv.send_msg_slots[entry]; | ||
1309 | if (msg_slot->func != NULL) | ||
1310 | xpc_notify_sender_uv(ch, msg_slot, ch->reason); | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | /* | ||
1315 | * Get the next deliverable message's payload. | ||
1316 | */ | ||
1317 | static void * | ||
1318 | xpc_get_deliverable_payload_uv(struct xpc_channel *ch) | ||
1319 | { | ||
1320 | struct xpc_fifo_entry_uv *entry; | ||
1321 | struct xpc_notify_mq_msg_uv *msg; | ||
1322 | void *payload = NULL; | ||
1323 | |||
1324 | if (!(ch->flags & XPC_C_DISCONNECTING)) { | ||
1325 | entry = xpc_get_fifo_entry_uv(&ch->sn.uv.recv_msg_list); | ||
1326 | if (entry != NULL) { | ||
1327 | msg = container_of(entry, struct xpc_notify_mq_msg_uv, | ||
1328 | hdr.u.next); | ||
1329 | payload = &msg->payload; | ||
1330 | } | ||
1331 | } | ||
1332 | return payload; | ||
1333 | } | ||
1334 | |||
1335 | static void | ||
1336 | xpc_received_payload_uv(struct xpc_channel *ch, void *payload) | ||
1337 | { | ||
1338 | struct xpc_notify_mq_msg_uv *msg; | ||
1339 | enum xp_retval ret; | ||
1340 | |||
1341 | msg = container_of(payload, struct xpc_notify_mq_msg_uv, payload); | ||
1342 | |||
1343 | /* return an ACK to the sender of this message */ | ||
1344 | |||
1345 | msg->hdr.partid = xp_partition_id; | ||
1346 | msg->hdr.size = 0; /* size of zero indicates this is an ACK */ | ||
1347 | |||
1348 | ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg, | ||
1349 | sizeof(struct xpc_notify_mq_msghdr_uv)); | ||
1350 | if (ret != xpSuccess) | ||
1351 | XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); | ||
1352 | |||
1353 | msg->hdr.msg_slot_number += ch->remote_nentries; | ||
1354 | } | ||
1355 | |||
1356 | int | ||
1357 | xpc_init_uv(void) | ||
1358 | { | ||
1359 | xpc_setup_partitions_sn = xpc_setup_partitions_sn_uv; | ||
1360 | xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_uv; | ||
1361 | xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_uv; | ||
1362 | xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_uv; | ||
1363 | xpc_increment_heartbeat = xpc_increment_heartbeat_uv; | ||
1364 | xpc_offline_heartbeat = xpc_offline_heartbeat_uv; | ||
1365 | xpc_online_heartbeat = xpc_online_heartbeat_uv; | ||
1366 | xpc_heartbeat_init = xpc_heartbeat_init_uv; | ||
1367 | xpc_heartbeat_exit = xpc_heartbeat_exit_uv; | ||
1368 | xpc_get_remote_heartbeat = xpc_get_remote_heartbeat_uv; | ||
1369 | |||
1370 | xpc_request_partition_activation = xpc_request_partition_activation_uv; | ||
1371 | xpc_request_partition_reactivation = | ||
1372 | xpc_request_partition_reactivation_uv; | ||
1373 | xpc_request_partition_deactivation = | ||
1374 | xpc_request_partition_deactivation_uv; | ||
1375 | xpc_cancel_partition_deactivation_request = | ||
1376 | xpc_cancel_partition_deactivation_request_uv; | ||
1377 | |||
1378 | xpc_setup_ch_structures_sn = xpc_setup_ch_structures_sn_uv; | ||
1379 | xpc_teardown_ch_structures_sn = xpc_teardown_ch_structures_sn_uv; | ||
1380 | |||
1381 | xpc_make_first_contact = xpc_make_first_contact_uv; | ||
1382 | |||
1383 | xpc_get_chctl_all_flags = xpc_get_chctl_all_flags_uv; | ||
1384 | xpc_send_chctl_closerequest = xpc_send_chctl_closerequest_uv; | ||
1385 | xpc_send_chctl_closereply = xpc_send_chctl_closereply_uv; | ||
1386 | xpc_send_chctl_openrequest = xpc_send_chctl_openrequest_uv; | ||
1387 | xpc_send_chctl_openreply = xpc_send_chctl_openreply_uv; | ||
1388 | |||
1389 | xpc_save_remote_msgqueue_pa = xpc_save_remote_msgqueue_pa_uv; | ||
1390 | |||
1391 | xpc_setup_msg_structures = xpc_setup_msg_structures_uv; | ||
1392 | xpc_teardown_msg_structures = xpc_teardown_msg_structures_uv; | ||
1393 | |||
1394 | xpc_indicate_partition_engaged = xpc_indicate_partition_engaged_uv; | ||
1395 | xpc_indicate_partition_disengaged = | ||
1396 | xpc_indicate_partition_disengaged_uv; | ||
1397 | xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_uv; | ||
1398 | xpc_partition_engaged = xpc_partition_engaged_uv; | ||
1399 | xpc_any_partition_engaged = xpc_any_partition_engaged_uv; | ||
1400 | |||
1401 | xpc_n_of_deliverable_payloads = xpc_n_of_deliverable_payloads_uv; | ||
1402 | xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_uv; | ||
1403 | xpc_send_payload = xpc_send_payload_uv; | ||
1404 | xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_uv; | ||
1405 | xpc_get_deliverable_payload = xpc_get_deliverable_payload_uv; | ||
1406 | xpc_received_payload = xpc_received_payload_uv; | ||
1407 | |||
1408 | if (sizeof(struct xpc_notify_mq_msghdr_uv) > XPC_MSG_HDR_MAX_SIZE) { | ||
1409 | dev_err(xpc_part, "xpc_notify_mq_msghdr_uv is larger than %d\n", | ||
1410 | XPC_MSG_HDR_MAX_SIZE); | ||
1411 | return -E2BIG; | ||
1412 | } | ||
1413 | |||
1414 | /* ??? The cpuid argument's value is 0, is that what we want? */ | ||
1415 | /* !!! The irq argument's value isn't correct. */ | ||
1416 | xpc_activate_mq_uv = xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, 0, 0, | ||
1417 | xpc_handle_activate_IRQ_uv); | ||
1418 | if (xpc_activate_mq_uv == NULL) | ||
1419 | return -ENOMEM; | ||
1420 | |||
1421 | /* ??? The cpuid argument's value is 0, is that what we want? */ | ||
1422 | /* !!! The irq argument's value isn't correct. */ | ||
1423 | xpc_notify_mq_uv = xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, 0, 0, | ||
1424 | xpc_handle_notify_IRQ_uv); | ||
1425 | if (xpc_notify_mq_uv == NULL) { | ||
1426 | /* !!! The irq argument's value isn't correct. */ | ||
1427 | xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, | ||
1428 | XPC_ACTIVATE_MQ_SIZE_UV, 0); | ||
1429 | return -ENOMEM; | ||
1430 | } | ||
1431 | |||
1432 | return 0; | ||
1433 | } | ||
1434 | |||
1435 | void | ||
1436 | xpc_exit_uv(void) | ||
1437 | { | ||
1438 | /* !!! The irq argument's value isn't correct. */ | ||
1439 | xpc_destroy_gru_mq_uv(xpc_notify_mq_uv, XPC_NOTIFY_MQ_SIZE_UV, 0); | ||
1440 | |||
1441 | /* !!! The irq argument's value isn't correct. */ | ||
1442 | xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, XPC_ACTIVATE_MQ_SIZE_UV, 0); | ||
1443 | } | ||
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 822dc8e8d7f0..71513b3af708 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c | |||
@@ -21,21 +21,8 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/types.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <linux/netdevice.h> | 24 | #include <linux/netdevice.h> |
29 | #include <linux/etherdevice.h> | 25 | #include <linux/etherdevice.h> |
30 | #include <linux/delay.h> | ||
31 | #include <linux/ethtool.h> | ||
32 | #include <linux/mii.h> | ||
33 | #include <linux/smp.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <asm/sn/bte.h> | ||
36 | #include <asm/sn/io.h> | ||
37 | #include <asm/sn/sn_sal.h> | ||
38 | #include <asm/atomic.h> | ||
39 | #include "xp.h" | 26 | #include "xp.h" |
40 | 27 | ||
41 | /* | 28 | /* |
@@ -57,7 +44,7 @@ struct xpnet_message { | |||
57 | u16 version; /* Version for this message */ | 44 | u16 version; /* Version for this message */ |
58 | u16 embedded_bytes; /* #of bytes embedded in XPC message */ | 45 | u16 embedded_bytes; /* #of bytes embedded in XPC message */ |
59 | u32 magic; /* Special number indicating this is xpnet */ | 46 | u32 magic; /* Special number indicating this is xpnet */ |
60 | u64 buf_pa; /* phys address of buffer to retrieve */ | 47 | unsigned long buf_pa; /* phys address of buffer to retrieve */ |
61 | u32 size; /* #of bytes in buffer */ | 48 | u32 size; /* #of bytes in buffer */ |
62 | u8 leadin_ignore; /* #of bytes to ignore at the beginning */ | 49 | u8 leadin_ignore; /* #of bytes to ignore at the beginning */ |
63 | u8 tailout_ignore; /* #of bytes to ignore at the end */ | 50 | u8 tailout_ignore; /* #of bytes to ignore at the end */ |
@@ -70,11 +57,10 @@ struct xpnet_message { | |||
70 | * | 57 | * |
71 | * XPC expects each message to exist in an individual cacheline. | 58 | * XPC expects each message to exist in an individual cacheline. |
72 | */ | 59 | */ |
73 | #define XPNET_MSG_SIZE (L1_CACHE_BYTES - XPC_MSG_PAYLOAD_OFFSET) | 60 | #define XPNET_MSG_SIZE XPC_MSG_PAYLOAD_MAX_SIZE |
74 | #define XPNET_MSG_DATA_MAX \ | 61 | #define XPNET_MSG_DATA_MAX \ |
75 | (XPNET_MSG_SIZE - (u64)(&((struct xpnet_message *)0)->data)) | 62 | (XPNET_MSG_SIZE - offsetof(struct xpnet_message, data)) |
76 | #define XPNET_MSG_ALIGNED_SIZE (L1_CACHE_ALIGN(XPNET_MSG_SIZE)) | 63 | #define XPNET_MSG_NENTRIES (PAGE_SIZE / XPC_MSG_MAX_SIZE) |
77 | #define XPNET_MSG_NENTRIES (PAGE_SIZE / XPNET_MSG_ALIGNED_SIZE) | ||
78 | 64 | ||
79 | #define XPNET_MAX_KTHREADS (XPNET_MSG_NENTRIES + 1) | 65 | #define XPNET_MAX_KTHREADS (XPNET_MSG_NENTRIES + 1) |
80 | #define XPNET_MAX_IDLE_KTHREADS (XPNET_MSG_NENTRIES + 1) | 66 | #define XPNET_MAX_IDLE_KTHREADS (XPNET_MSG_NENTRIES + 1) |
@@ -105,7 +91,6 @@ struct xpnet_message { | |||
105 | * then be released. | 91 | * then be released. |
106 | */ | 92 | */ |
107 | struct xpnet_pending_msg { | 93 | struct xpnet_pending_msg { |
108 | struct list_head free_list; | ||
109 | struct sk_buff *skb; | 94 | struct sk_buff *skb; |
110 | atomic_t use_count; | 95 | atomic_t use_count; |
111 | }; | 96 | }; |
@@ -121,7 +106,7 @@ struct net_device *xpnet_device; | |||
121 | * When we are notified of other partitions activating, we add them to | 106 | * When we are notified of other partitions activating, we add them to |
122 | * our bitmask of partitions to which we broadcast. | 107 | * our bitmask of partitions to which we broadcast. |
123 | */ | 108 | */ |
124 | static u64 xpnet_broadcast_partitions; | 109 | static unsigned long *xpnet_broadcast_partitions; |
125 | /* protect above */ | 110 | /* protect above */ |
126 | static DEFINE_SPINLOCK(xpnet_broadcast_lock); | 111 | static DEFINE_SPINLOCK(xpnet_broadcast_lock); |
127 | 112 | ||
@@ -141,16 +126,13 @@ static DEFINE_SPINLOCK(xpnet_broadcast_lock); | |||
141 | #define XPNET_DEF_MTU (0x8000UL) | 126 | #define XPNET_DEF_MTU (0x8000UL) |
142 | 127 | ||
143 | /* | 128 | /* |
144 | * The partition id is encapsulated in the MAC address. The following | 129 | * The partid is encapsulated in the MAC address beginning in the following |
145 | * define locates the octet the partid is in. | 130 | * octet and it consists of two octets. |
146 | */ | 131 | */ |
147 | #define XPNET_PARTID_OCTET 1 | 132 | #define XPNET_PARTID_OCTET 2 |
148 | #define XPNET_LICENSE_OCTET 2 | 133 | |
134 | /* Define the XPNET debug device structures to be used with dev_dbg() et al */ | ||
149 | 135 | ||
150 | /* | ||
151 | * Define the XPNET debug device structure that is to be used with dev_dbg(), | ||
152 | * dev_err(), dev_warn(), and dev_info(). | ||
153 | */ | ||
154 | struct device_driver xpnet_dbg_name = { | 136 | struct device_driver xpnet_dbg_name = { |
155 | .name = "xpnet" | 137 | .name = "xpnet" |
156 | }; | 138 | }; |
@@ -169,7 +151,8 @@ static void | |||
169 | xpnet_receive(short partid, int channel, struct xpnet_message *msg) | 151 | xpnet_receive(short partid, int channel, struct xpnet_message *msg) |
170 | { | 152 | { |
171 | struct sk_buff *skb; | 153 | struct sk_buff *skb; |
172 | bte_result_t bret; | 154 | void *dst; |
155 | enum xp_retval ret; | ||
173 | struct xpnet_dev_private *priv = | 156 | struct xpnet_dev_private *priv = |
174 | (struct xpnet_dev_private *)xpnet_device->priv; | 157 | (struct xpnet_dev_private *)xpnet_device->priv; |
175 | 158 | ||
@@ -201,7 +184,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) | |||
201 | 184 | ||
202 | /* | 185 | /* |
203 | * The allocated skb has some reserved space. | 186 | * The allocated skb has some reserved space. |
204 | * In order to use bte_copy, we need to get the | 187 | * In order to use xp_remote_memcpy(), we need to get the |
205 | * skb->data pointer moved forward. | 188 | * skb->data pointer moved forward. |
206 | */ | 189 | */ |
207 | skb_reserve(skb, (L1_CACHE_BYTES - ((u64)skb->data & | 190 | skb_reserve(skb, (L1_CACHE_BYTES - ((u64)skb->data & |
@@ -226,26 +209,21 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) | |||
226 | skb_copy_to_linear_data(skb, &msg->data, | 209 | skb_copy_to_linear_data(skb, &msg->data, |
227 | (size_t)msg->embedded_bytes); | 210 | (size_t)msg->embedded_bytes); |
228 | } else { | 211 | } else { |
212 | dst = (void *)((u64)skb->data & ~(L1_CACHE_BYTES - 1)); | ||
229 | dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t" | 213 | dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t" |
230 | "bte_copy(0x%p, 0x%p, %hu)\n", (void *)msg->buf_pa, | 214 | "xp_remote_memcpy(0x%p, 0x%p, %hu)\n", dst, |
231 | (void *)__pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)), | 215 | (void *)msg->buf_pa, msg->size); |
232 | msg->size); | ||
233 | |||
234 | bret = bte_copy(msg->buf_pa, | ||
235 | __pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)), | ||
236 | msg->size, (BTE_NOTIFY | BTE_WACQUIRE), NULL); | ||
237 | 216 | ||
238 | if (bret != BTE_SUCCESS) { | 217 | ret = xp_remote_memcpy(xp_pa(dst), msg->buf_pa, msg->size); |
218 | if (ret != xpSuccess) { | ||
239 | /* | 219 | /* |
240 | * >>> Need better way of cleaning skb. Currently skb | 220 | * !!! Need better way of cleaning skb. Currently skb |
241 | * >>> appears in_use and we can't just call | 221 | * !!! appears in_use and we can't just call |
242 | * >>> dev_kfree_skb. | 222 | * !!! dev_kfree_skb. |
243 | */ | 223 | */ |
244 | dev_err(xpnet, "bte_copy(0x%p, 0x%p, 0x%hx) returned " | 224 | dev_err(xpnet, "xp_remote_memcpy(0x%p, 0x%p, 0x%hx) " |
245 | "error=0x%x\n", (void *)msg->buf_pa, | 225 | "returned error=0x%x\n", dst, |
246 | (void *)__pa((u64)skb->data & | 226 | (void *)msg->buf_pa, msg->size, ret); |
247 | ~(L1_CACHE_BYTES - 1)), | ||
248 | msg->size, bret); | ||
249 | 227 | ||
250 | xpc_received(partid, channel, (void *)msg); | 228 | xpc_received(partid, channel, (void *)msg); |
251 | 229 | ||
@@ -285,9 +263,7 @@ static void | |||
285 | xpnet_connection_activity(enum xp_retval reason, short partid, int channel, | 263 | xpnet_connection_activity(enum xp_retval reason, short partid, int channel, |
286 | void *data, void *key) | 264 | void *data, void *key) |
287 | { | 265 | { |
288 | long bp; | 266 | DBUG_ON(partid < 0 || partid >= xp_max_npartitions); |
289 | |||
290 | DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); | ||
291 | DBUG_ON(channel != XPC_NET_CHANNEL); | 267 | DBUG_ON(channel != XPC_NET_CHANNEL); |
292 | 268 | ||
293 | switch (reason) { | 269 | switch (reason) { |
@@ -299,31 +275,28 @@ xpnet_connection_activity(enum xp_retval reason, short partid, int channel, | |||
299 | 275 | ||
300 | case xpConnected: /* connection completed to a partition */ | 276 | case xpConnected: /* connection completed to a partition */ |
301 | spin_lock_bh(&xpnet_broadcast_lock); | 277 | spin_lock_bh(&xpnet_broadcast_lock); |
302 | xpnet_broadcast_partitions |= 1UL << (partid - 1); | 278 | __set_bit(partid, xpnet_broadcast_partitions); |
303 | bp = xpnet_broadcast_partitions; | ||
304 | spin_unlock_bh(&xpnet_broadcast_lock); | 279 | spin_unlock_bh(&xpnet_broadcast_lock); |
305 | 280 | ||
306 | netif_carrier_on(xpnet_device); | 281 | netif_carrier_on(xpnet_device); |
307 | 282 | ||
308 | dev_dbg(xpnet, "%s connection created to partition %d; " | 283 | dev_dbg(xpnet, "%s connected to partition %d\n", |
309 | "xpnet_broadcast_partitions=0x%lx\n", | 284 | xpnet_device->name, partid); |
310 | xpnet_device->name, partid, bp); | ||
311 | break; | 285 | break; |
312 | 286 | ||
313 | default: | 287 | default: |
314 | spin_lock_bh(&xpnet_broadcast_lock); | 288 | spin_lock_bh(&xpnet_broadcast_lock); |
315 | xpnet_broadcast_partitions &= ~(1UL << (partid - 1)); | 289 | __clear_bit(partid, xpnet_broadcast_partitions); |
316 | bp = xpnet_broadcast_partitions; | ||
317 | spin_unlock_bh(&xpnet_broadcast_lock); | 290 | spin_unlock_bh(&xpnet_broadcast_lock); |
318 | 291 | ||
319 | if (bp == 0) | 292 | if (bitmap_empty((unsigned long *)xpnet_broadcast_partitions, |
293 | xp_max_npartitions)) { | ||
320 | netif_carrier_off(xpnet_device); | 294 | netif_carrier_off(xpnet_device); |
295 | } | ||
321 | 296 | ||
322 | dev_dbg(xpnet, "%s disconnected from partition %d; " | 297 | dev_dbg(xpnet, "%s disconnected from partition %d\n", |
323 | "xpnet_broadcast_partitions=0x%lx\n", | 298 | xpnet_device->name, partid); |
324 | xpnet_device->name, partid, bp); | ||
325 | break; | 299 | break; |
326 | |||
327 | } | 300 | } |
328 | } | 301 | } |
329 | 302 | ||
@@ -334,8 +307,10 @@ xpnet_dev_open(struct net_device *dev) | |||
334 | 307 | ||
335 | dev_dbg(xpnet, "calling xpc_connect(%d, 0x%p, NULL, %ld, %ld, %ld, " | 308 | dev_dbg(xpnet, "calling xpc_connect(%d, 0x%p, NULL, %ld, %ld, %ld, " |
336 | "%ld)\n", XPC_NET_CHANNEL, xpnet_connection_activity, | 309 | "%ld)\n", XPC_NET_CHANNEL, xpnet_connection_activity, |
337 | XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, XPNET_MAX_KTHREADS, | 310 | (unsigned long)XPNET_MSG_SIZE, |
338 | XPNET_MAX_IDLE_KTHREADS); | 311 | (unsigned long)XPNET_MSG_NENTRIES, |
312 | (unsigned long)XPNET_MAX_KTHREADS, | ||
313 | (unsigned long)XPNET_MAX_IDLE_KTHREADS); | ||
339 | 314 | ||
340 | ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL, | 315 | ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL, |
341 | XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, | 316 | XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, |
@@ -426,35 +401,74 @@ xpnet_send_completed(enum xp_retval reason, short partid, int channel, | |||
426 | } | 401 | } |
427 | } | 402 | } |
428 | 403 | ||
404 | static void | ||
405 | xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg, | ||
406 | u64 start_addr, u64 end_addr, u16 embedded_bytes, int dest_partid) | ||
407 | { | ||
408 | u8 msg_buffer[XPNET_MSG_SIZE]; | ||
409 | struct xpnet_message *msg = (struct xpnet_message *)&msg_buffer; | ||
410 | u16 msg_size = sizeof(struct xpnet_message); | ||
411 | enum xp_retval ret; | ||
412 | |||
413 | msg->embedded_bytes = embedded_bytes; | ||
414 | if (unlikely(embedded_bytes != 0)) { | ||
415 | msg->version = XPNET_VERSION_EMBED; | ||
416 | dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n", | ||
417 | &msg->data, skb->data, (size_t)embedded_bytes); | ||
418 | skb_copy_from_linear_data(skb, &msg->data, | ||
419 | (size_t)embedded_bytes); | ||
420 | msg_size += embedded_bytes - 1; | ||
421 | } else { | ||
422 | msg->version = XPNET_VERSION; | ||
423 | } | ||
424 | msg->magic = XPNET_MAGIC; | ||
425 | msg->size = end_addr - start_addr; | ||
426 | msg->leadin_ignore = (u64)skb->data - start_addr; | ||
427 | msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb); | ||
428 | msg->buf_pa = xp_pa((void *)start_addr); | ||
429 | |||
430 | dev_dbg(xpnet, "sending XPC message to %d:%d\n" | ||
431 | KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, " | ||
432 | "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n", | ||
433 | dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size, | ||
434 | msg->leadin_ignore, msg->tailout_ignore); | ||
435 | |||
436 | atomic_inc(&queued_msg->use_count); | ||
437 | |||
438 | ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT, msg, | ||
439 | msg_size, xpnet_send_completed, queued_msg); | ||
440 | if (unlikely(ret != xpSuccess)) | ||
441 | atomic_dec(&queued_msg->use_count); | ||
442 | } | ||
443 | |||
429 | /* | 444 | /* |
430 | * Network layer has formatted a packet (skb) and is ready to place it | 445 | * Network layer has formatted a packet (skb) and is ready to place it |
431 | * "on the wire". Prepare and send an xpnet_message to all partitions | 446 | * "on the wire". Prepare and send an xpnet_message to all partitions |
432 | * which have connected with us and are targets of this packet. | 447 | * which have connected with us and are targets of this packet. |
433 | * | 448 | * |
434 | * MAC-NOTE: For the XPNET driver, the MAC address contains the | 449 | * MAC-NOTE: For the XPNET driver, the MAC address contains the |
435 | * destination partition_id. If the destination partition id word | 450 | * destination partid. If the destination partid octets are 0xffff, |
436 | * is 0xff, this packet is to broadcast to all partitions. | 451 | * this packet is to be broadcast to all connected partitions. |
437 | */ | 452 | */ |
438 | static int | 453 | static int |
439 | xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | 454 | xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
440 | { | 455 | { |
441 | struct xpnet_pending_msg *queued_msg; | 456 | struct xpnet_pending_msg *queued_msg; |
442 | enum xp_retval ret; | ||
443 | struct xpnet_message *msg; | ||
444 | u64 start_addr, end_addr; | 457 | u64 start_addr, end_addr; |
445 | long dp; | ||
446 | u8 second_mac_octet; | ||
447 | short dest_partid; | 458 | short dest_partid; |
448 | struct xpnet_dev_private *priv; | 459 | struct xpnet_dev_private *priv = (struct xpnet_dev_private *)dev->priv; |
449 | u16 embedded_bytes; | 460 | u16 embedded_bytes = 0; |
450 | |||
451 | priv = (struct xpnet_dev_private *)dev->priv; | ||
452 | 461 | ||
453 | dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " | 462 | dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " |
454 | "skb->end=0x%p skb->len=%d\n", (void *)skb->head, | 463 | "skb->end=0x%p skb->len=%d\n", (void *)skb->head, |
455 | (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), | 464 | (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), |
456 | skb->len); | 465 | skb->len); |
457 | 466 | ||
467 | if (skb->data[0] == 0x33) { | ||
468 | dev_kfree_skb(skb); | ||
469 | return 0; /* nothing needed to be done */ | ||
470 | } | ||
471 | |||
458 | /* | 472 | /* |
459 | * The xpnet_pending_msg tracks how many outstanding | 473 | * The xpnet_pending_msg tracks how many outstanding |
460 | * xpc_send_notifies are relying on this skb. When none | 474 | * xpc_send_notifies are relying on this skb. When none |
@@ -466,7 +480,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
466 | "packet\n", sizeof(struct xpnet_pending_msg)); | 480 | "packet\n", sizeof(struct xpnet_pending_msg)); |
467 | 481 | ||
468 | priv->stats.tx_errors++; | 482 | priv->stats.tx_errors++; |
469 | |||
470 | return -ENOMEM; | 483 | return -ENOMEM; |
471 | } | 484 | } |
472 | 485 | ||
@@ -475,7 +488,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
475 | end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb)); | 488 | end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb)); |
476 | 489 | ||
477 | /* calculate how many bytes to embed in the XPC message */ | 490 | /* calculate how many bytes to embed in the XPC message */ |
478 | embedded_bytes = 0; | ||
479 | if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) { | 491 | if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) { |
480 | /* skb->data does fit so embed */ | 492 | /* skb->data does fit so embed */ |
481 | embedded_bytes = skb->len; | 493 | embedded_bytes = skb->len; |
@@ -491,82 +503,28 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
491 | atomic_set(&queued_msg->use_count, 1); | 503 | atomic_set(&queued_msg->use_count, 1); |
492 | queued_msg->skb = skb; | 504 | queued_msg->skb = skb; |
493 | 505 | ||
494 | second_mac_octet = skb->data[XPNET_PARTID_OCTET]; | 506 | if (skb->data[0] == 0xff) { |
495 | if (second_mac_octet == 0xff) { | ||
496 | /* we are being asked to broadcast to all partitions */ | 507 | /* we are being asked to broadcast to all partitions */ |
497 | dp = xpnet_broadcast_partitions; | 508 | for_each_bit(dest_partid, xpnet_broadcast_partitions, |
498 | } else if (second_mac_octet != 0) { | 509 | xp_max_npartitions) { |
499 | dp = xpnet_broadcast_partitions & | ||
500 | (1UL << (second_mac_octet - 1)); | ||
501 | } else { | ||
502 | /* 0 is an invalid partid. Ignore */ | ||
503 | dp = 0; | ||
504 | } | ||
505 | dev_dbg(xpnet, "destination Partitions mask (dp) = 0x%lx\n", dp); | ||
506 | |||
507 | /* | ||
508 | * If we wanted to allow promiscuous mode to work like an | ||
509 | * unswitched network, this would be a good point to OR in a | ||
510 | * mask of partitions which should be receiving all packets. | ||
511 | */ | ||
512 | |||
513 | /* | ||
514 | * Main send loop. | ||
515 | */ | ||
516 | for (dest_partid = 1; dp && dest_partid < XP_MAX_PARTITIONS; | ||
517 | dest_partid++) { | ||
518 | 510 | ||
519 | if (!(dp & (1UL << (dest_partid - 1)))) { | 511 | xpnet_send(skb, queued_msg, start_addr, end_addr, |
520 | /* not destined for this partition */ | 512 | embedded_bytes, dest_partid); |
521 | continue; | ||
522 | } | 513 | } |
514 | } else { | ||
515 | dest_partid = (short)skb->data[XPNET_PARTID_OCTET + 1]; | ||
516 | dest_partid |= (short)skb->data[XPNET_PARTID_OCTET + 0] << 8; | ||
523 | 517 | ||
524 | /* remove this partition from the destinations mask */ | 518 | if (dest_partid >= 0 && |
525 | dp &= ~(1UL << (dest_partid - 1)); | 519 | dest_partid < xp_max_npartitions && |
526 | 520 | test_bit(dest_partid, xpnet_broadcast_partitions) != 0) { | |
527 | /* found a partition to send to */ | 521 | |
528 | 522 | xpnet_send(skb, queued_msg, start_addr, end_addr, | |
529 | ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL, | 523 | embedded_bytes, dest_partid); |
530 | XPC_NOWAIT, (void **)&msg); | ||
531 | if (unlikely(ret != xpSuccess)) | ||
532 | continue; | ||
533 | |||
534 | msg->embedded_bytes = embedded_bytes; | ||
535 | if (unlikely(embedded_bytes != 0)) { | ||
536 | msg->version = XPNET_VERSION_EMBED; | ||
537 | dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n", | ||
538 | &msg->data, skb->data, (size_t)embedded_bytes); | ||
539 | skb_copy_from_linear_data(skb, &msg->data, | ||
540 | (size_t)embedded_bytes); | ||
541 | } else { | ||
542 | msg->version = XPNET_VERSION; | ||
543 | } | ||
544 | msg->magic = XPNET_MAGIC; | ||
545 | msg->size = end_addr - start_addr; | ||
546 | msg->leadin_ignore = (u64)skb->data - start_addr; | ||
547 | msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb); | ||
548 | msg->buf_pa = __pa(start_addr); | ||
549 | |||
550 | dev_dbg(xpnet, "sending XPC message to %d:%d\n" | ||
551 | KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, " | ||
552 | "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n", | ||
553 | dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size, | ||
554 | msg->leadin_ignore, msg->tailout_ignore); | ||
555 | |||
556 | atomic_inc(&queued_msg->use_count); | ||
557 | |||
558 | ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, msg, | ||
559 | xpnet_send_completed, queued_msg); | ||
560 | if (unlikely(ret != xpSuccess)) { | ||
561 | atomic_dec(&queued_msg->use_count); | ||
562 | continue; | ||
563 | } | 524 | } |
564 | } | 525 | } |
565 | 526 | ||
566 | if (atomic_dec_return(&queued_msg->use_count) == 0) { | 527 | if (atomic_dec_return(&queued_msg->use_count) == 0) { |
567 | dev_dbg(xpnet, "no partitions to receive packet destined for " | ||
568 | "%d\n", dest_partid); | ||
569 | |||
570 | dev_kfree_skb(skb); | 528 | dev_kfree_skb(skb); |
571 | kfree(queued_msg); | 529 | kfree(queued_msg); |
572 | } | 530 | } |
@@ -594,23 +552,28 @@ xpnet_dev_tx_timeout(struct net_device *dev) | |||
594 | static int __init | 552 | static int __init |
595 | xpnet_init(void) | 553 | xpnet_init(void) |
596 | { | 554 | { |
597 | int i; | 555 | int result; |
598 | u32 license_num; | ||
599 | int result = -ENOMEM; | ||
600 | 556 | ||
601 | if (!ia64_platform_is("sn2")) | 557 | if (!is_shub() && !is_uv()) |
602 | return -ENODEV; | 558 | return -ENODEV; |
603 | 559 | ||
604 | dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME); | 560 | dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME); |
605 | 561 | ||
562 | xpnet_broadcast_partitions = kzalloc(BITS_TO_LONGS(xp_max_npartitions) * | ||
563 | sizeof(long), GFP_KERNEL); | ||
564 | if (xpnet_broadcast_partitions == NULL) | ||
565 | return -ENOMEM; | ||
566 | |||
606 | /* | 567 | /* |
607 | * use ether_setup() to init the majority of our device | 568 | * use ether_setup() to init the majority of our device |
608 | * structure and then override the necessary pieces. | 569 | * structure and then override the necessary pieces. |
609 | */ | 570 | */ |
610 | xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private), | 571 | xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private), |
611 | XPNET_DEVICE_NAME, ether_setup); | 572 | XPNET_DEVICE_NAME, ether_setup); |
612 | if (xpnet_device == NULL) | 573 | if (xpnet_device == NULL) { |
574 | kfree(xpnet_broadcast_partitions); | ||
613 | return -ENOMEM; | 575 | return -ENOMEM; |
576 | } | ||
614 | 577 | ||
615 | netif_carrier_off(xpnet_device); | 578 | netif_carrier_off(xpnet_device); |
616 | 579 | ||
@@ -628,14 +591,10 @@ xpnet_init(void) | |||
628 | * MAC addresses. We chose the first octet of the MAC to be unlikely | 591 | * MAC addresses. We chose the first octet of the MAC to be unlikely |
629 | * to collide with any vendor's officially issued MAC. | 592 | * to collide with any vendor's officially issued MAC. |
630 | */ | 593 | */ |
631 | xpnet_device->dev_addr[0] = 0xfe; | 594 | xpnet_device->dev_addr[0] = 0x02; /* locally administered, no OUI */ |
632 | xpnet_device->dev_addr[XPNET_PARTID_OCTET] = sn_partition_id; | 595 | |
633 | license_num = sn_partition_serial_number_val(); | 596 | xpnet_device->dev_addr[XPNET_PARTID_OCTET + 1] = xp_partition_id; |
634 | for (i = 3; i >= 0; i--) { | 597 | xpnet_device->dev_addr[XPNET_PARTID_OCTET + 0] = (xp_partition_id >> 8); |
635 | xpnet_device->dev_addr[XPNET_LICENSE_OCTET + i] = | ||
636 | license_num & 0xff; | ||
637 | license_num = license_num >> 8; | ||
638 | } | ||
639 | 598 | ||
640 | /* | 599 | /* |
641 | * ether_setup() sets this to a multicast device. We are | 600 | * ether_setup() sets this to a multicast device. We are |
@@ -651,8 +610,10 @@ xpnet_init(void) | |||
651 | xpnet_device->features = NETIF_F_NO_CSUM; | 610 | xpnet_device->features = NETIF_F_NO_CSUM; |
652 | 611 | ||
653 | result = register_netdev(xpnet_device); | 612 | result = register_netdev(xpnet_device); |
654 | if (result != 0) | 613 | if (result != 0) { |
655 | free_netdev(xpnet_device); | 614 | free_netdev(xpnet_device); |
615 | kfree(xpnet_broadcast_partitions); | ||
616 | } | ||
656 | 617 | ||
657 | return result; | 618 | return result; |
658 | } | 619 | } |
@@ -666,8 +627,8 @@ xpnet_exit(void) | |||
666 | xpnet_device[0].name); | 627 | xpnet_device[0].name); |
667 | 628 | ||
668 | unregister_netdev(xpnet_device); | 629 | unregister_netdev(xpnet_device); |
669 | |||
670 | free_netdev(xpnet_device); | 630 | free_netdev(xpnet_device); |
631 | kfree(xpnet_broadcast_partitions); | ||
671 | } | 632 | } |
672 | 633 | ||
673 | module_exit(xpnet_exit); | 634 | module_exit(xpnet_exit); |
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 8ee7d7bb951b..e4765b713aba 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -6417,7 +6417,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) | |||
6417 | *class = CLASS_CODE_SCTP_IPV6; | 6417 | *class = CLASS_CODE_SCTP_IPV6; |
6418 | break; | 6418 | break; |
6419 | default: | 6419 | default: |
6420 | return -1; | 6420 | return 0; |
6421 | } | 6421 | } |
6422 | 6422 | ||
6423 | return 1; | 6423 | return 1; |
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 6b2dee0cf3a9..a834b52a6a2c 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c | |||
@@ -1024,7 +1024,7 @@ static int gelic_wl_set_encode(struct net_device *netdev, | |||
1024 | struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); | 1024 | struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); |
1025 | struct iw_point *enc = &data->encoding; | 1025 | struct iw_point *enc = &data->encoding; |
1026 | __u16 flags; | 1026 | __u16 flags; |
1027 | unsigned int irqflag; | 1027 | unsigned long irqflag; |
1028 | int key_index, index_specified; | 1028 | int key_index, index_specified; |
1029 | int ret = 0; | 1029 | int ret = 0; |
1030 | 1030 | ||
@@ -1097,7 +1097,7 @@ static int gelic_wl_get_encode(struct net_device *netdev, | |||
1097 | { | 1097 | { |
1098 | struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); | 1098 | struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); |
1099 | struct iw_point *enc = &data->encoding; | 1099 | struct iw_point *enc = &data->encoding; |
1100 | unsigned int irqflag; | 1100 | unsigned long irqflag; |
1101 | unsigned int key_index, index_specified; | 1101 | unsigned int key_index, index_specified; |
1102 | int ret = 0; | 1102 | int ret = 0; |
1103 | 1103 | ||
@@ -1215,7 +1215,7 @@ static int gelic_wl_set_encodeext(struct net_device *netdev, | |||
1215 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | 1215 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; |
1216 | __u16 alg; | 1216 | __u16 alg; |
1217 | __u16 flags; | 1217 | __u16 flags; |
1218 | unsigned int irqflag; | 1218 | unsigned long irqflag; |
1219 | int key_index; | 1219 | int key_index; |
1220 | int ret = 0; | 1220 | int ret = 0; |
1221 | 1221 | ||
@@ -1303,7 +1303,7 @@ static int gelic_wl_get_encodeext(struct net_device *netdev, | |||
1303 | struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); | 1303 | struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); |
1304 | struct iw_point *enc = &data->encoding; | 1304 | struct iw_point *enc = &data->encoding; |
1305 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | 1305 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; |
1306 | unsigned int irqflag; | 1306 | unsigned long irqflag; |
1307 | int key_index; | 1307 | int key_index; |
1308 | int ret = 0; | 1308 | int ret = 0; |
1309 | int max_key_len; | 1309 | int max_key_len; |
@@ -1426,7 +1426,7 @@ static int gelic_wl_priv_set_psk(struct net_device *net_dev, | |||
1426 | { | 1426 | { |
1427 | struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); | 1427 | struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); |
1428 | unsigned int len; | 1428 | unsigned int len; |
1429 | unsigned int irqflag; | 1429 | unsigned long irqflag; |
1430 | int ret = 0; | 1430 | int ret = 0; |
1431 | 1431 | ||
1432 | pr_debug("%s:<- len=%d\n", __func__, data->data.length); | 1432 | pr_debug("%s:<- len=%d\n", __func__, data->data.length); |
@@ -1467,7 +1467,7 @@ static int gelic_wl_priv_get_psk(struct net_device *net_dev, | |||
1467 | { | 1467 | { |
1468 | struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); | 1468 | struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); |
1469 | char *p; | 1469 | char *p; |
1470 | unsigned int irqflag; | 1470 | unsigned long irqflag; |
1471 | unsigned int i; | 1471 | unsigned int i; |
1472 | 1472 | ||
1473 | pr_debug("%s:<-\n", __func__); | 1473 | pr_debug("%s:<-\n", __func__); |
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index d9769c527346..ff3fad794b61 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -43,7 +43,9 @@ | |||
43 | #include <linux/version.h> | 43 | #include <linux/version.h> |
44 | #include <linux/module.h> | 44 | #include <linux/module.h> |
45 | #include <linux/delay.h> | 45 | #include <linux/delay.h> |
46 | #include <linux/hardirq.h> | ||
46 | #include <linux/if.h> | 47 | #include <linux/if.h> |
48 | #include <linux/io.h> | ||
47 | #include <linux/netdevice.h> | 49 | #include <linux/netdevice.h> |
48 | #include <linux/cache.h> | 50 | #include <linux/cache.h> |
49 | #include <linux/pci.h> | 51 | #include <linux/pci.h> |
@@ -471,9 +473,6 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
471 | /* Set private data */ | 473 | /* Set private data */ |
472 | pci_set_drvdata(pdev, hw); | 474 | pci_set_drvdata(pdev, hw); |
473 | 475 | ||
474 | /* Enable msi for devices that support it */ | ||
475 | pci_enable_msi(pdev); | ||
476 | |||
477 | /* Setup interrupt handler */ | 476 | /* Setup interrupt handler */ |
478 | ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); | 477 | ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); |
479 | if (ret) { | 478 | if (ret) { |
@@ -551,7 +550,6 @@ err_ah: | |||
551 | err_irq: | 550 | err_irq: |
552 | free_irq(pdev->irq, sc); | 551 | free_irq(pdev->irq, sc); |
553 | err_free: | 552 | err_free: |
554 | pci_disable_msi(pdev); | ||
555 | ieee80211_free_hw(hw); | 553 | ieee80211_free_hw(hw); |
556 | err_map: | 554 | err_map: |
557 | pci_iounmap(pdev, mem); | 555 | pci_iounmap(pdev, mem); |
@@ -573,7 +571,6 @@ ath5k_pci_remove(struct pci_dev *pdev) | |||
573 | ath5k_detach(pdev, hw); | 571 | ath5k_detach(pdev, hw); |
574 | ath5k_hw_detach(sc->ah); | 572 | ath5k_hw_detach(sc->ah); |
575 | free_irq(pdev->irq, sc); | 573 | free_irq(pdev->irq, sc); |
576 | pci_disable_msi(pdev); | ||
577 | pci_iounmap(pdev, sc->iobase); | 574 | pci_iounmap(pdev, sc->iobase); |
578 | pci_release_region(pdev, 0); | 575 | pci_release_region(pdev, 0); |
579 | pci_disable_device(pdev); | 576 | pci_disable_device(pdev); |
@@ -590,6 +587,9 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
590 | ath5k_led_off(sc); | 587 | ath5k_led_off(sc); |
591 | 588 | ||
592 | ath5k_stop_hw(sc); | 589 | ath5k_stop_hw(sc); |
590 | |||
591 | free_irq(pdev->irq, sc); | ||
592 | pci_disable_msi(pdev); | ||
593 | pci_save_state(pdev); | 593 | pci_save_state(pdev); |
594 | pci_disable_device(pdev); | 594 | pci_disable_device(pdev); |
595 | pci_set_power_state(pdev, PCI_D3hot); | 595 | pci_set_power_state(pdev, PCI_D3hot); |
@@ -605,15 +605,12 @@ ath5k_pci_resume(struct pci_dev *pdev) | |||
605 | struct ath5k_hw *ah = sc->ah; | 605 | struct ath5k_hw *ah = sc->ah; |
606 | int i, err; | 606 | int i, err; |
607 | 607 | ||
608 | err = pci_set_power_state(pdev, PCI_D0); | 608 | pci_restore_state(pdev); |
609 | if (err) | ||
610 | return err; | ||
611 | 609 | ||
612 | err = pci_enable_device(pdev); | 610 | err = pci_enable_device(pdev); |
613 | if (err) | 611 | if (err) |
614 | return err; | 612 | return err; |
615 | 613 | ||
616 | pci_restore_state(pdev); | ||
617 | /* | 614 | /* |
618 | * Suspend/Resume resets the PCI configuration space, so we have to | 615 | * Suspend/Resume resets the PCI configuration space, so we have to |
619 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | 616 | * re-disable the RETRY_TIMEOUT register (0x41) to keep |
@@ -621,7 +618,17 @@ ath5k_pci_resume(struct pci_dev *pdev) | |||
621 | */ | 618 | */ |
622 | pci_write_config_byte(pdev, 0x41, 0); | 619 | pci_write_config_byte(pdev, 0x41, 0); |
623 | 620 | ||
624 | ath5k_init(sc); | 621 | pci_enable_msi(pdev); |
622 | |||
623 | err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); | ||
624 | if (err) { | ||
625 | ATH5K_ERR(sc, "request_irq failed\n"); | ||
626 | goto err_msi; | ||
627 | } | ||
628 | |||
629 | err = ath5k_init(sc); | ||
630 | if (err) | ||
631 | goto err_irq; | ||
625 | ath5k_led_enable(sc); | 632 | ath5k_led_enable(sc); |
626 | 633 | ||
627 | /* | 634 | /* |
@@ -635,6 +642,12 @@ ath5k_pci_resume(struct pci_dev *pdev) | |||
635 | ath5k_hw_reset_key(ah, i); | 642 | ath5k_hw_reset_key(ah, i); |
636 | 643 | ||
637 | return 0; | 644 | return 0; |
645 | err_irq: | ||
646 | free_irq(pdev->irq, sc); | ||
647 | err_msi: | ||
648 | pci_disable_msi(pdev); | ||
649 | pci_disable_device(pdev); | ||
650 | return err; | ||
638 | } | 651 | } |
639 | #endif /* CONFIG_PM */ | 652 | #endif /* CONFIG_PM */ |
640 | 653 | ||
@@ -1224,7 +1237,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1224 | 1237 | ||
1225 | pktlen = skb->len; | 1238 | pktlen = skb->len; |
1226 | 1239 | ||
1227 | if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) { | 1240 | if (info->control.hw_key) { |
1228 | keyidx = info->control.hw_key->hw_key_idx; | 1241 | keyidx = info->control.hw_key->hw_key_idx; |
1229 | pktlen += info->control.icv_len; | 1242 | pktlen += info->control.icv_len; |
1230 | } | 1243 | } |
@@ -1249,6 +1262,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1249 | 1262 | ||
1250 | txq->link = &ds->ds_link; | 1263 | txq->link = &ds->ds_link; |
1251 | ath5k_hw_tx_start(ah, txq->qnum); | 1264 | ath5k_hw_tx_start(ah, txq->qnum); |
1265 | mmiowb(); | ||
1252 | spin_unlock_bh(&txq->lock); | 1266 | spin_unlock_bh(&txq->lock); |
1253 | 1267 | ||
1254 | return 0; | 1268 | return 0; |
@@ -1583,7 +1597,6 @@ ath5k_rx_stop(struct ath5k_softc *sc) | |||
1583 | ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ | 1597 | ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ |
1584 | ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ | 1598 | ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ |
1585 | ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ | 1599 | ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ |
1586 | mdelay(3); /* 3ms is long enough for 1 frame */ | ||
1587 | 1600 | ||
1588 | ath5k_debug_printrxbuffs(sc, ah); | 1601 | ath5k_debug_printrxbuffs(sc, ah); |
1589 | 1602 | ||
@@ -1682,31 +1695,44 @@ ath5k_tasklet_rx(unsigned long data) | |||
1682 | struct ath5k_rx_status rs = {}; | 1695 | struct ath5k_rx_status rs = {}; |
1683 | struct sk_buff *skb; | 1696 | struct sk_buff *skb; |
1684 | struct ath5k_softc *sc = (void *)data; | 1697 | struct ath5k_softc *sc = (void *)data; |
1685 | struct ath5k_buf *bf; | 1698 | struct ath5k_buf *bf, *bf_last; |
1686 | struct ath5k_desc *ds; | 1699 | struct ath5k_desc *ds; |
1687 | int ret; | 1700 | int ret; |
1688 | int hdrlen; | 1701 | int hdrlen; |
1689 | int pad; | 1702 | int pad; |
1690 | 1703 | ||
1691 | spin_lock(&sc->rxbuflock); | 1704 | spin_lock(&sc->rxbuflock); |
1705 | if (list_empty(&sc->rxbuf)) { | ||
1706 | ATH5K_WARN(sc, "empty rx buf pool\n"); | ||
1707 | goto unlock; | ||
1708 | } | ||
1709 | bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list); | ||
1692 | do { | 1710 | do { |
1693 | rxs.flag = 0; | 1711 | rxs.flag = 0; |
1694 | 1712 | ||
1695 | if (unlikely(list_empty(&sc->rxbuf))) { | ||
1696 | ATH5K_WARN(sc, "empty rx buf pool\n"); | ||
1697 | break; | ||
1698 | } | ||
1699 | bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); | 1713 | bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); |
1700 | BUG_ON(bf->skb == NULL); | 1714 | BUG_ON(bf->skb == NULL); |
1701 | skb = bf->skb; | 1715 | skb = bf->skb; |
1702 | ds = bf->desc; | 1716 | ds = bf->desc; |
1703 | 1717 | ||
1704 | /* TODO only one segment */ | 1718 | /* |
1705 | pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, | 1719 | * last buffer must not be freed to ensure proper hardware |
1706 | sc->desc_len, PCI_DMA_FROMDEVICE); | 1720 | * function. When the hardware finishes also a packet next to |
1707 | 1721 | * it, we are sure, it doesn't use it anymore and we can go on. | |
1708 | if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */ | 1722 | */ |
1709 | break; | 1723 | if (bf_last == bf) |
1724 | bf->flags |= 1; | ||
1725 | if (bf->flags) { | ||
1726 | struct ath5k_buf *bf_next = list_entry(bf->list.next, | ||
1727 | struct ath5k_buf, list); | ||
1728 | ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc, | ||
1729 | &rs); | ||
1730 | if (ret) | ||
1731 | break; | ||
1732 | bf->flags &= ~1; | ||
1733 | /* skip the overwritten one (even status is martian) */ | ||
1734 | goto next; | ||
1735 | } | ||
1710 | 1736 | ||
1711 | ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); | 1737 | ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); |
1712 | if (unlikely(ret == -EINPROGRESS)) | 1738 | if (unlikely(ret == -EINPROGRESS)) |
@@ -1752,8 +1778,6 @@ ath5k_tasklet_rx(unsigned long data) | |||
1752 | goto next; | 1778 | goto next; |
1753 | } | 1779 | } |
1754 | accept: | 1780 | accept: |
1755 | pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, | ||
1756 | rs.rs_datalen, PCI_DMA_FROMDEVICE); | ||
1757 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, | 1781 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, |
1758 | PCI_DMA_FROMDEVICE); | 1782 | PCI_DMA_FROMDEVICE); |
1759 | bf->skb = NULL; | 1783 | bf->skb = NULL; |
@@ -1816,6 +1840,7 @@ accept: | |||
1816 | next: | 1840 | next: |
1817 | list_move_tail(&bf->list, &sc->rxbuf); | 1841 | list_move_tail(&bf->list, &sc->rxbuf); |
1818 | } while (ath5k_rxbuf_setup(sc, bf) == 0); | 1842 | } while (ath5k_rxbuf_setup(sc, bf) == 0); |
1843 | unlock: | ||
1819 | spin_unlock(&sc->rxbuflock); | 1844 | spin_unlock(&sc->rxbuflock); |
1820 | } | 1845 | } |
1821 | 1846 | ||
@@ -1840,9 +1865,6 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
1840 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { | 1865 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { |
1841 | ds = bf->desc; | 1866 | ds = bf->desc; |
1842 | 1867 | ||
1843 | /* TODO only one segment */ | ||
1844 | pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, | ||
1845 | sc->desc_len, PCI_DMA_FROMDEVICE); | ||
1846 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); | 1868 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); |
1847 | if (unlikely(ret == -EINPROGRESS)) | 1869 | if (unlikely(ret == -EINPROGRESS)) |
1848 | break; | 1870 | break; |
@@ -2015,8 +2037,6 @@ ath5k_beacon_send(struct ath5k_softc *sc) | |||
2015 | ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); | 2037 | ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); |
2016 | /* NB: hw still stops DMA, so proceed */ | 2038 | /* NB: hw still stops DMA, so proceed */ |
2017 | } | 2039 | } |
2018 | pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len, | ||
2019 | PCI_DMA_TODEVICE); | ||
2020 | 2040 | ||
2021 | ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr); | 2041 | ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr); |
2022 | ath5k_hw_tx_start(ah, sc->bhalq); | 2042 | ath5k_hw_tx_start(ah, sc->bhalq); |
@@ -2240,6 +2260,7 @@ ath5k_init(struct ath5k_softc *sc) | |||
2240 | 2260 | ||
2241 | ret = 0; | 2261 | ret = 0; |
2242 | done: | 2262 | done: |
2263 | mmiowb(); | ||
2243 | mutex_unlock(&sc->lock); | 2264 | mutex_unlock(&sc->lock); |
2244 | return ret; | 2265 | return ret; |
2245 | } | 2266 | } |
@@ -2272,6 +2293,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) | |||
2272 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { | 2293 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { |
2273 | ath5k_led_off(sc); | 2294 | ath5k_led_off(sc); |
2274 | ath5k_hw_set_intr(ah, 0); | 2295 | ath5k_hw_set_intr(ah, 0); |
2296 | synchronize_irq(sc->pdev->irq); | ||
2275 | } | 2297 | } |
2276 | ath5k_txq_cleanup(sc); | 2298 | ath5k_txq_cleanup(sc); |
2277 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { | 2299 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { |
@@ -2321,9 +2343,13 @@ ath5k_stop_hw(struct ath5k_softc *sc) | |||
2321 | } | 2343 | } |
2322 | } | 2344 | } |
2323 | ath5k_txbuf_free(sc, sc->bbuf); | 2345 | ath5k_txbuf_free(sc, sc->bbuf); |
2346 | mmiowb(); | ||
2324 | mutex_unlock(&sc->lock); | 2347 | mutex_unlock(&sc->lock); |
2325 | 2348 | ||
2326 | del_timer_sync(&sc->calib_tim); | 2349 | del_timer_sync(&sc->calib_tim); |
2350 | tasklet_kill(&sc->rxtq); | ||
2351 | tasklet_kill(&sc->txtq); | ||
2352 | tasklet_kill(&sc->restq); | ||
2327 | 2353 | ||
2328 | return ret; | 2354 | return ret; |
2329 | } | 2355 | } |
@@ -2550,8 +2576,6 @@ ath5k_init_leds(struct ath5k_softc *sc) | |||
2550 | struct pci_dev *pdev = sc->pdev; | 2576 | struct pci_dev *pdev = sc->pdev; |
2551 | char name[ATH5K_LED_MAX_NAME_LEN + 1]; | 2577 | char name[ATH5K_LED_MAX_NAME_LEN + 1]; |
2552 | 2578 | ||
2553 | sc->led_on = 0; /* active low */ | ||
2554 | |||
2555 | /* | 2579 | /* |
2556 | * Auto-enable soft led processing for IBM cards and for | 2580 | * Auto-enable soft led processing for IBM cards and for |
2557 | * 5211 minipci cards. | 2581 | * 5211 minipci cards. |
@@ -2560,11 +2584,13 @@ ath5k_init_leds(struct ath5k_softc *sc) | |||
2560 | pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { | 2584 | pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { |
2561 | __set_bit(ATH_STAT_LEDSOFT, sc->status); | 2585 | __set_bit(ATH_STAT_LEDSOFT, sc->status); |
2562 | sc->led_pin = 0; | 2586 | sc->led_pin = 0; |
2587 | sc->led_on = 0; /* active low */ | ||
2563 | } | 2588 | } |
2564 | /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ | 2589 | /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ |
2565 | if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { | 2590 | if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { |
2566 | __set_bit(ATH_STAT_LEDSOFT, sc->status); | 2591 | __set_bit(ATH_STAT_LEDSOFT, sc->status); |
2567 | sc->led_pin = 1; | 2592 | sc->led_pin = 1; |
2593 | sc->led_on = 1; /* active high */ | ||
2568 | } | 2594 | } |
2569 | if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) | 2595 | if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) |
2570 | goto out; | 2596 | goto out; |
@@ -2783,6 +2809,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
2783 | /* XXX: assoc id is set to 0 for now, mac80211 doesn't have | 2809 | /* XXX: assoc id is set to 0 for now, mac80211 doesn't have |
2784 | * a clean way of letting us retrieve this yet. */ | 2810 | * a clean way of letting us retrieve this yet. */ |
2785 | ath5k_hw_set_associd(ah, ah->ah_bssid, 0); | 2811 | ath5k_hw_set_associd(ah, ah->ah_bssid, 0); |
2812 | mmiowb(); | ||
2786 | } | 2813 | } |
2787 | 2814 | ||
2788 | if (conf->changed & IEEE80211_IFCC_BEACON && | 2815 | if (conf->changed & IEEE80211_IFCC_BEACON && |
@@ -2971,6 +2998,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
2971 | } | 2998 | } |
2972 | 2999 | ||
2973 | unlock: | 3000 | unlock: |
3001 | mmiowb(); | ||
2974 | mutex_unlock(&sc->lock); | 3002 | mutex_unlock(&sc->lock); |
2975 | return ret; | 3003 | return ret; |
2976 | } | 3004 | } |
@@ -3032,8 +3060,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
3032 | 3060 | ||
3033 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); | 3061 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); |
3034 | 3062 | ||
3035 | mutex_lock(&sc->lock); | ||
3036 | |||
3037 | if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { | 3063 | if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { |
3038 | ret = -EIO; | 3064 | ret = -EIO; |
3039 | goto end; | 3065 | goto end; |
@@ -3044,11 +3070,12 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
3044 | ret = ath5k_beacon_setup(sc, sc->bbuf); | 3070 | ret = ath5k_beacon_setup(sc, sc->bbuf); |
3045 | if (ret) | 3071 | if (ret) |
3046 | sc->bbuf->skb = NULL; | 3072 | sc->bbuf->skb = NULL; |
3047 | else | 3073 | else { |
3048 | ath5k_beacon_config(sc); | 3074 | ath5k_beacon_config(sc); |
3075 | mmiowb(); | ||
3076 | } | ||
3049 | 3077 | ||
3050 | end: | 3078 | end: |
3051 | mutex_unlock(&sc->lock); | ||
3052 | return ret; | 3079 | return ret; |
3053 | } | 3080 | } |
3054 | 3081 | ||
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 47f414b09e67..d7e03e6b8271 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h | |||
@@ -56,7 +56,7 @@ | |||
56 | 56 | ||
57 | struct ath5k_buf { | 57 | struct ath5k_buf { |
58 | struct list_head list; | 58 | struct list_head list; |
59 | unsigned int flags; /* tx descriptor flags */ | 59 | unsigned int flags; /* rx descriptor flags */ |
60 | struct ath5k_desc *desc; /* virtual addr of desc */ | 60 | struct ath5k_desc *desc; /* virtual addr of desc */ |
61 | dma_addr_t daddr; /* physical addr of desc */ | 61 | dma_addr_t daddr; /* physical addr of desc */ |
62 | struct sk_buff *skb; /* skbuff for buf */ | 62 | struct sk_buff *skb; /* skbuff for buf */ |
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index c6d12c53bda4..7ca87a557312 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c | |||
@@ -1440,6 +1440,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
1440 | 1440 | ||
1441 | /* Stop queue */ | 1441 | /* Stop queue */ |
1442 | ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); | 1442 | ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); |
1443 | ath5k_hw_reg_read(ah, AR5K_CR); | ||
1443 | } else { | 1444 | } else { |
1444 | /* | 1445 | /* |
1445 | * Schedule TX disable and wait until queue is empty | 1446 | * Schedule TX disable and wait until queue is empty |
@@ -1456,6 +1457,8 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
1456 | 1457 | ||
1457 | /* Clear register */ | 1458 | /* Clear register */ |
1458 | ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); | 1459 | ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); |
1460 | if (pending) | ||
1461 | return -EBUSY; | ||
1459 | } | 1462 | } |
1460 | 1463 | ||
1461 | /* TODO: Check for success else return error */ | 1464 | /* TODO: Check for success else return error */ |
@@ -1716,6 +1719,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask) | |||
1716 | 1719 | ||
1717 | /* ..re-enable interrupts */ | 1720 | /* ..re-enable interrupts */ |
1718 | ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); | 1721 | ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); |
1722 | ath5k_hw_reg_read(ah, AR5K_IER); | ||
1719 | 1723 | ||
1720 | return old_mask; | 1724 | return old_mask; |
1721 | } | 1725 | } |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e78319aa47c1..3bf3a869361f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -4645,8 +4645,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4645 | } | 4645 | } |
4646 | 4646 | ||
4647 | /* fill hw info */ | 4647 | /* fill hw info */ |
4648 | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | | 4648 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
4649 | IEEE80211_HW_RX_INCLUDES_FCS | | ||
4650 | IEEE80211_HW_SIGNAL_DBM | | 4649 | IEEE80211_HW_SIGNAL_DBM | |
4651 | IEEE80211_HW_NOISE_DBM; | 4650 | IEEE80211_HW_NOISE_DBM; |
4652 | 4651 | ||
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 8d54502222a6..9dda8169f7cc 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c | |||
@@ -192,7 +192,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, | |||
192 | const struct b43_phy *phy = &dev->phy; | 192 | const struct b43_phy *phy = &dev->phy; |
193 | const struct ieee80211_hdr *wlhdr = | 193 | const struct ieee80211_hdr *wlhdr = |
194 | (const struct ieee80211_hdr *)fragment_data; | 194 | (const struct ieee80211_hdr *)fragment_data; |
195 | int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); | 195 | int use_encryption = !!info->control.hw_key; |
196 | __le16 fctl = wlhdr->frame_control; | 196 | __le16 fctl = wlhdr->frame_control; |
197 | struct ieee80211_rate *fbrate; | 197 | struct ieee80211_rate *fbrate; |
198 | u8 rate, rate_fb; | 198 | u8 rate, rate_fb; |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index a1b8bf3ee732..2541c81932f0 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c | |||
@@ -3702,8 +3702,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev) | |||
3702 | } | 3702 | } |
3703 | 3703 | ||
3704 | /* fill hw info */ | 3704 | /* fill hw info */ |
3705 | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | | 3705 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
3706 | IEEE80211_HW_RX_INCLUDES_FCS | | ||
3707 | IEEE80211_HW_SIGNAL_DBM | | 3706 | IEEE80211_HW_SIGNAL_DBM | |
3708 | IEEE80211_HW_NOISE_DBM; | 3707 | IEEE80211_HW_NOISE_DBM; |
3709 | hw->queues = 1; /* FIXME: hardware has more queues */ | 3708 | hw->queues = 1; /* FIXME: hardware has more queues */ |
@@ -3846,10 +3845,10 @@ static int b43legacy_resume(struct ssb_device *dev) | |||
3846 | goto out; | 3845 | goto out; |
3847 | } | 3846 | } |
3848 | } | 3847 | } |
3849 | mutex_unlock(&wl->mutex); | ||
3850 | 3848 | ||
3851 | b43legacydbg(wl, "Device resumed.\n"); | 3849 | b43legacydbg(wl, "Device resumed.\n"); |
3852 | out: | 3850 | out: |
3851 | mutex_unlock(&wl->mutex); | ||
3853 | return err; | 3852 | return err; |
3854 | } | 3853 | } |
3855 | 3854 | ||
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index e969ed8d412d..68e1f8c78727 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c | |||
@@ -192,7 +192,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, | |||
192 | u16 cookie) | 192 | u16 cookie) |
193 | { | 193 | { |
194 | const struct ieee80211_hdr *wlhdr; | 194 | const struct ieee80211_hdr *wlhdr; |
195 | int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); | 195 | int use_encryption = !!info->control.hw_key; |
196 | u16 fctl; | 196 | u16 fctl; |
197 | u8 rate; | 197 | u8 rate; |
198 | struct ieee80211_rate *rate_fb; | 198 | struct ieee80211_rate *rate_fb; |
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 5bf9e00b070c..c6f886ec08a3 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c | |||
@@ -6442,6 +6442,7 @@ static int ipw2100_resume(struct pci_dev *pci_dev) | |||
6442 | if (err) { | 6442 | if (err) { |
6443 | printk(KERN_ERR "%s: pci_enable_device failed on resume\n", | 6443 | printk(KERN_ERR "%s: pci_enable_device failed on resume\n", |
6444 | dev->name); | 6444 | dev->name); |
6445 | mutex_unlock(&priv->action_mutex); | ||
6445 | return err; | 6446 | return err; |
6446 | } | 6447 | } |
6447 | pci_restore_state(pci_dev); | 6448 | pci_restore_state(pci_dev); |
@@ -7146,7 +7147,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev, | |||
7146 | err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len); | 7147 | err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len); |
7147 | if (err) { | 7148 | if (err) { |
7148 | IPW_DEBUG_WX("failed querying ordinals.\n"); | 7149 | IPW_DEBUG_WX("failed querying ordinals.\n"); |
7149 | return err; | 7150 | goto done; |
7150 | } | 7151 | } |
7151 | 7152 | ||
7152 | switch (val & TX_RATE_MASK) { | 7153 | switch (val & TX_RATE_MASK) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index c2a76785b665..a51e0eaa1334 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -630,7 +630,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv, | |||
630 | struct ieee80211_rx_status *stats) | 630 | struct ieee80211_rx_status *stats) |
631 | { | 631 | { |
632 | struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data; | 632 | struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data; |
633 | #ifdef CONFIG_IWL3945_LEDS | ||
633 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); | 634 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); |
635 | #endif | ||
634 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | 636 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); |
635 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); | 637 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); |
636 | short len = le16_to_cpu(rx_hdr->len); | 638 | short len = le16_to_cpu(rx_hdr->len); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a44188bf4459..e3427c205ccf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -818,8 +818,7 @@ int iwl_setup_mac(struct iwl_priv *priv) | |||
818 | hw->rate_control_algorithm = "iwl-4965-rs"; | 818 | hw->rate_control_algorithm = "iwl-4965-rs"; |
819 | 819 | ||
820 | /* Tell mac80211 our characteristics */ | 820 | /* Tell mac80211 our characteristics */ |
821 | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | | 821 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
822 | IEEE80211_HW_SIGNAL_DBM | | ||
823 | IEEE80211_HW_NOISE_DBM; | 822 | IEEE80211_HW_NOISE_DBM; |
824 | /* Default value; 4 EDCA QOS priorities */ | 823 | /* Default value; 4 EDCA QOS priorities */ |
825 | hw->queues = 4; | 824 | hw->queues = 4; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 58384805a494..d6d729e86bdb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
@@ -68,12 +68,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); | |||
68 | #endif | 68 | #endif |
69 | 69 | ||
70 | #else | 70 | #else |
71 | static inline void IWL_DEBUG(int level, const char *fmt, ...) | 71 | #define IWL_DEBUG(level, fmt, args...) |
72 | { | 72 | #define IWL_DEBUG_LIMIT(level, fmt, args...) |
73 | } | ||
74 | static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) | ||
75 | { | ||
76 | } | ||
77 | #endif /* CONFIG_IWLWIFI_DEBUG */ | 73 | #endif /* CONFIG_IWLWIFI_DEBUG */ |
78 | 74 | ||
79 | 75 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 899d7a2567a8..61250e6a7d1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c | |||
@@ -268,7 +268,9 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) | |||
268 | if (tpt < 0) /* wrapparound */ | 268 | if (tpt < 0) /* wrapparound */ |
269 | tpt = -tpt; | 269 | tpt = -tpt; |
270 | 270 | ||
271 | IWL_DEBUG_LED("tpt %lld current_tpt %lld\n", tpt, current_tpt); | 271 | IWL_DEBUG_LED("tpt %lld current_tpt %llu\n", |
272 | (long long)tpt, | ||
273 | (unsigned long long)current_tpt); | ||
272 | priv->led_tpt = current_tpt; | 274 | priv->led_tpt = current_tpt; |
273 | 275 | ||
274 | if (!priv->allow_blinking) | 276 | if (!priv->allow_blinking) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index efc750d2fc5c..5a00ac23e2d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -270,6 +270,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, | |||
270 | static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, | 270 | static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, |
271 | struct iwl_rx_mem_buffer *rxb) | 271 | struct iwl_rx_mem_buffer *rxb) |
272 | { | 272 | { |
273 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
273 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 274 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
274 | struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; | 275 | struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; |
275 | 276 | ||
@@ -277,6 +278,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, | |||
277 | scan_notif->scanned_channels, | 278 | scan_notif->scanned_channels, |
278 | scan_notif->tsf_low, | 279 | scan_notif->tsf_low, |
279 | scan_notif->tsf_high, scan_notif->status); | 280 | scan_notif->tsf_high, scan_notif->status); |
281 | #endif | ||
280 | 282 | ||
281 | /* The HW is no longer scanning */ | 283 | /* The HW is no longer scanning */ |
282 | clear_bit(STATUS_SCAN_HW, &priv->status); | 284 | clear_bit(STATUS_SCAN_HW, &priv->status); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9b50b1052b09..f72cd0bf6aa3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -906,7 +906,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
906 | * first entry */ | 906 | * first entry */ |
907 | iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); | 907 | iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); |
908 | 908 | ||
909 | if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) | 909 | if (info->control.hw_key) |
910 | iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); | 910 | iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); |
911 | 911 | ||
912 | /* Set up TFD's 2nd entry to point directly to remainder of skb, | 912 | /* Set up TFD's 2nd entry to point directly to remainder of skb, |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4a22d3fba75b..7c82ecfa30a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -2667,7 +2667,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) | |||
2667 | * first entry */ | 2667 | * first entry */ |
2668 | iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); | 2668 | iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); |
2669 | 2669 | ||
2670 | if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) | 2670 | if (info->control.hw_key) |
2671 | iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0); | 2671 | iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0); |
2672 | 2672 | ||
2673 | /* Set up TFD's 2nd entry to point directly to remainder of skb, | 2673 | /* Set up TFD's 2nd entry to point directly to remainder of skb, |
@@ -7899,8 +7899,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
7899 | priv->ibss_beacon = NULL; | 7899 | priv->ibss_beacon = NULL; |
7900 | 7900 | ||
7901 | /* Tell mac80211 our characteristics */ | 7901 | /* Tell mac80211 our characteristics */ |
7902 | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | | 7902 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
7903 | IEEE80211_HW_SIGNAL_DBM | | ||
7904 | IEEE80211_HW_NOISE_DBM; | 7903 | IEEE80211_HW_NOISE_DBM; |
7905 | 7904 | ||
7906 | /* 4 EDCA QOS priorities */ | 7905 | /* 4 EDCA QOS priorities */ |
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index 6d0ff8decaf7..3309a9c3cfef 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c | |||
@@ -48,7 +48,7 @@ static ssize_t bootflag_get(struct device *dev, | |||
48 | if (ret) | 48 | if (ret) |
49 | return ret; | 49 | return ret; |
50 | 50 | ||
51 | return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag)); | 51 | return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag)); |
52 | } | 52 | } |
53 | 53 | ||
54 | /** | 54 | /** |
@@ -63,8 +63,8 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, | |||
63 | int ret; | 63 | int ret; |
64 | 64 | ||
65 | memset(&cmd, 0, sizeof(cmd)); | 65 | memset(&cmd, 0, sizeof(cmd)); |
66 | ret = sscanf(buf, "%x", &datum); | 66 | ret = sscanf(buf, "%d", &datum); |
67 | if (ret != 1) | 67 | if ((ret != 1) || (datum > 1)) |
68 | return -EINVAL; | 68 | return -EINVAL; |
69 | 69 | ||
70 | *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum); | 70 | *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum); |
@@ -91,7 +91,7 @@ static ssize_t boottime_get(struct device *dev, | |||
91 | if (ret) | 91 | if (ret) |
92 | return ret; | 92 | return ret; |
93 | 93 | ||
94 | return snprintf(buf, 12, "0x%x\n", defs.boottime); | 94 | return snprintf(buf, 12, "%d\n", defs.boottime); |
95 | } | 95 | } |
96 | 96 | ||
97 | /** | 97 | /** |
@@ -106,8 +106,8 @@ static ssize_t boottime_set(struct device *dev, | |||
106 | int ret; | 106 | int ret; |
107 | 107 | ||
108 | memset(&cmd, 0, sizeof(cmd)); | 108 | memset(&cmd, 0, sizeof(cmd)); |
109 | ret = sscanf(buf, "%x", &datum); | 109 | ret = sscanf(buf, "%d", &datum); |
110 | if (ret != 1) | 110 | if ((ret != 1) || (datum > 255)) |
111 | return -EINVAL; | 111 | return -EINVAL; |
112 | 112 | ||
113 | /* A too small boot time will result in the device booting into | 113 | /* A too small boot time will result in the device booting into |
@@ -143,7 +143,7 @@ static ssize_t channel_get(struct device *dev, | |||
143 | if (ret) | 143 | if (ret) |
144 | return ret; | 144 | return ret; |
145 | 145 | ||
146 | return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel)); | 146 | return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel)); |
147 | } | 147 | } |
148 | 148 | ||
149 | /** | 149 | /** |
@@ -154,11 +154,11 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, | |||
154 | { | 154 | { |
155 | struct lbs_private *priv = to_net_dev(dev)->priv; | 155 | struct lbs_private *priv = to_net_dev(dev)->priv; |
156 | struct cmd_ds_mesh_config cmd; | 156 | struct cmd_ds_mesh_config cmd; |
157 | uint16_t datum; | 157 | uint32_t datum; |
158 | int ret; | 158 | int ret; |
159 | 159 | ||
160 | memset(&cmd, 0, sizeof(cmd)); | 160 | memset(&cmd, 0, sizeof(cmd)); |
161 | ret = sscanf(buf, "%hx", &datum); | 161 | ret = sscanf(buf, "%d", &datum); |
162 | if (ret != 1 || datum < 1 || datum > 11) | 162 | if (ret != 1 || datum < 1 || datum > 11) |
163 | return -EINVAL; | 163 | return -EINVAL; |
164 | 164 | ||
@@ -274,8 +274,8 @@ static ssize_t protocol_id_set(struct device *dev, | |||
274 | int ret; | 274 | int ret; |
275 | 275 | ||
276 | memset(&cmd, 0, sizeof(cmd)); | 276 | memset(&cmd, 0, sizeof(cmd)); |
277 | ret = sscanf(buf, "%x", &datum); | 277 | ret = sscanf(buf, "%d", &datum); |
278 | if (ret != 1) | 278 | if ((ret != 1) || (datum > 255)) |
279 | return -EINVAL; | 279 | return -EINVAL; |
280 | 280 | ||
281 | /* fetch all other Information Element parameters */ | 281 | /* fetch all other Information Element parameters */ |
@@ -328,8 +328,8 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, | |||
328 | int ret; | 328 | int ret; |
329 | 329 | ||
330 | memset(&cmd, 0, sizeof(cmd)); | 330 | memset(&cmd, 0, sizeof(cmd)); |
331 | ret = sscanf(buf, "%x", &datum); | 331 | ret = sscanf(buf, "%d", &datum); |
332 | if (ret != 1) | 332 | if ((ret != 1) || (datum > 255)) |
333 | return -EINVAL; | 333 | return -EINVAL; |
334 | 334 | ||
335 | /* fetch all other Information Element parameters */ | 335 | /* fetch all other Information Element parameters */ |
@@ -382,8 +382,8 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, | |||
382 | int ret; | 382 | int ret; |
383 | 383 | ||
384 | memset(&cmd, 0, sizeof(cmd)); | 384 | memset(&cmd, 0, sizeof(cmd)); |
385 | ret = sscanf(buf, "%x", &datum); | 385 | ret = sscanf(buf, "%d", &datum); |
386 | if (ret != 1) | 386 | if ((ret != 1) || (datum > 255)) |
387 | return -EINVAL; | 387 | return -EINVAL; |
388 | 388 | ||
389 | /* fetch all other Information Element parameters */ | 389 | /* fetch all other Information Element parameters */ |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 5816230d58f8..248d31a7aa33 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -500,7 +500,7 @@ failed_hw: | |||
500 | device_unregister(data->dev); | 500 | device_unregister(data->dev); |
501 | failed_drvdata: | 501 | failed_drvdata: |
502 | ieee80211_free_hw(hw); | 502 | ieee80211_free_hw(hw); |
503 | hwsim_radios[i] = 0; | 503 | hwsim_radios[i] = NULL; |
504 | failed: | 504 | failed: |
505 | mac80211_hwsim_free(); | 505 | mac80211_hwsim_free(); |
506 | return err; | 506 | return err; |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3558cb210747..3078417b326b 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -1121,6 +1121,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) | |||
1121 | int pipe = usb_sndbulkpipe(usb_dev, 1); | 1121 | int pipe = usb_sndbulkpipe(usb_dev, 1); |
1122 | int length; | 1122 | int length; |
1123 | u16 reg; | 1123 | u16 reg; |
1124 | u32 word, len; | ||
1124 | 1125 | ||
1125 | /* | 1126 | /* |
1126 | * Add the descriptor in front of the skb. | 1127 | * Add the descriptor in front of the skb. |
@@ -1130,6 +1131,17 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) | |||
1130 | skbdesc->desc = entry->skb->data; | 1131 | skbdesc->desc = entry->skb->data; |
1131 | 1132 | ||
1132 | /* | 1133 | /* |
1134 | * Adjust the beacon databyte count. The current number is | ||
1135 | * calculated before this function gets called, but falsely | ||
1136 | * assumes that the descriptor was already present in the SKB. | ||
1137 | */ | ||
1138 | rt2x00_desc_read(skbdesc->desc, 0, &word); | ||
1139 | len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); | ||
1140 | len += skbdesc->desc_len; | ||
1141 | rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); | ||
1142 | rt2x00_desc_write(skbdesc->desc, 0, word); | ||
1143 | |||
1144 | /* | ||
1133 | * Disable beaconing while we are reloading the beacon data, | 1145 | * Disable beaconing while we are reloading the beacon data, |
1134 | * otherwise we might be sending out invalid data. | 1146 | * otherwise we might be sending out invalid data. |
1135 | */ | 1147 | */ |
@@ -1650,7 +1662,6 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
1650 | * Initialize all hw fields. | 1662 | * Initialize all hw fields. |
1651 | */ | 1663 | */ |
1652 | rt2x00dev->hw->flags = | 1664 | rt2x00dev->hw->flags = |
1653 | IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | | ||
1654 | IEEE80211_HW_RX_INCLUDES_FCS | | 1665 | IEEE80211_HW_RX_INCLUDES_FCS | |
1655 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1666 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1656 | IEEE80211_HW_SIGNAL_DBM; | 1667 | IEEE80211_HW_SIGNAL_DBM; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 07b03b3c7ef1..db2dc976d831 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -108,7 +108,10 @@ | |||
108 | #define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME ) | 108 | #define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME ) |
109 | #define DIFS ( PIFS + SLOT_TIME ) | 109 | #define DIFS ( PIFS + SLOT_TIME ) |
110 | #define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME ) | 110 | #define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME ) |
111 | #define EIFS ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) ) | 111 | #define EIFS ( SIFS + DIFS + \ |
112 | (8 * (IEEE80211_HEADER + ACK_SIZE)) ) | ||
113 | #define SHORT_EIFS ( SIFS + SHORT_DIFS + \ | ||
114 | (8 * (IEEE80211_HEADER + ACK_SIZE)) ) | ||
112 | 115 | ||
113 | /* | 116 | /* |
114 | * Chipset identification | 117 | * Chipset identification |
@@ -597,6 +600,7 @@ enum rt2x00_flags { | |||
597 | DEVICE_STARTED_SUSPEND, | 600 | DEVICE_STARTED_SUSPEND, |
598 | DEVICE_ENABLED_RADIO, | 601 | DEVICE_ENABLED_RADIO, |
599 | DEVICE_DISABLED_RADIO_HW, | 602 | DEVICE_DISABLED_RADIO_HW, |
603 | DEVICE_DIRTY_CONFIG, | ||
600 | 604 | ||
601 | /* | 605 | /* |
602 | * Driver features | 606 | * Driver features |
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index f20ca712504f..3f89516e8332 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c | |||
@@ -271,7 +271,7 @@ config: | |||
271 | libconf.sifs = SIFS; | 271 | libconf.sifs = SIFS; |
272 | libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS; | 272 | libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS; |
273 | libconf.difs = short_slot_time ? SHORT_DIFS : DIFS; | 273 | libconf.difs = short_slot_time ? SHORT_DIFS : DIFS; |
274 | libconf.eifs = EIFS; | 274 | libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS; |
275 | } | 275 | } |
276 | 276 | ||
277 | libconf.conf = conf; | 277 | libconf.conf = conf; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 8c93eb8353b0..f42283ad7b02 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -1013,6 +1013,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) | |||
1013 | rt2x00dev->intf_associated = 0; | 1013 | rt2x00dev->intf_associated = 0; |
1014 | 1014 | ||
1015 | __set_bit(DEVICE_STARTED, &rt2x00dev->flags); | 1015 | __set_bit(DEVICE_STARTED, &rt2x00dev->flags); |
1016 | __set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); | ||
1016 | 1017 | ||
1017 | return 0; | 1018 | return 0; |
1018 | } | 1019 | } |
@@ -1237,9 +1238,9 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) | |||
1237 | /* | 1238 | /* |
1238 | * Reconfigure device. | 1239 | * Reconfigure device. |
1239 | */ | 1240 | */ |
1240 | rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1); | 1241 | retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); |
1241 | if (!rt2x00dev->hw->conf.radio_enabled) | 1242 | if (retval) |
1242 | rt2x00lib_disable_radio(rt2x00dev); | 1243 | goto exit; |
1243 | 1244 | ||
1244 | /* | 1245 | /* |
1245 | * Iterator over each active interface to | 1246 | * Iterator over each active interface to |
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index f2c9b0e79b5f..c5fb3a72cf37 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h | |||
@@ -125,13 +125,6 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); | |||
125 | void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); | 125 | void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); |
126 | 126 | ||
127 | /** | 127 | /** |
128 | * rt2x00queue_free_skb - free a skb | ||
129 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | ||
130 | * @skb: The skb to free. | ||
131 | */ | ||
132 | void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); | ||
133 | |||
134 | /** | ||
135 | * rt2x00queue_write_tx_frame - Write TX frame to hardware | 128 | * rt2x00queue_write_tx_frame - Write TX frame to hardware |
136 | * @queue: Queue over which the frame should be send | 129 | * @queue: Queue over which the frame should be send |
137 | * @skb: The skb to send | 130 | * @skb: The skb to send |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index f1dcbaa80c3c..c3ee4ecba792 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -63,7 +63,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, | |||
63 | */ | 63 | */ |
64 | memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); | 64 | memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); |
65 | rts_info = IEEE80211_SKB_CB(skb); | 65 | rts_info = IEEE80211_SKB_CB(skb); |
66 | rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; | 66 | rts_info->control.hw_key = NULL; |
67 | rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; | 67 | rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; |
68 | rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; | 68 | rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; |
69 | rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; | 69 | rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; |
@@ -83,6 +83,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, | |||
83 | (struct ieee80211_rts *)(skb->data)); | 83 | (struct ieee80211_rts *)(skb->data)); |
84 | 84 | ||
85 | if (rt2x00queue_write_tx_frame(queue, skb)) { | 85 | if (rt2x00queue_write_tx_frame(queue, skb)) { |
86 | dev_kfree_skb_any(skb); | ||
86 | WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); | 87 | WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); |
87 | return NETDEV_TX_BUSY; | 88 | return NETDEV_TX_BUSY; |
88 | } | 89 | } |
@@ -96,7 +97,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
96 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 97 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
97 | struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; | 98 | struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; |
98 | enum data_queue_qid qid = skb_get_queue_mapping(skb); | 99 | enum data_queue_qid qid = skb_get_queue_mapping(skb); |
99 | struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); | ||
100 | struct data_queue *queue; | 100 | struct data_queue *queue; |
101 | u16 frame_control; | 101 | u16 frame_control; |
102 | 102 | ||
@@ -152,18 +152,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
152 | } | 152 | } |
153 | } | 153 | } |
154 | 154 | ||
155 | /* | ||
156 | * XXX: This is as wrong as the old mac80211 code was, | ||
157 | * due to beacons not getting sequence numbers assigned | ||
158 | * properly. | ||
159 | */ | ||
160 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | ||
161 | if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) | ||
162 | intf->seqno += 0x10; | ||
163 | ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); | ||
164 | ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno); | ||
165 | } | ||
166 | |||
167 | if (rt2x00queue_write_tx_frame(queue, skb)) { | 155 | if (rt2x00queue_write_tx_frame(queue, skb)) { |
168 | ieee80211_stop_queue(rt2x00dev->hw, qid); | 156 | ieee80211_stop_queue(rt2x00dev->hw, qid); |
169 | return NETDEV_TX_BUSY; | 157 | return NETDEV_TX_BUSY; |
@@ -322,6 +310,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); | |||
322 | int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) | 310 | int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) |
323 | { | 311 | { |
324 | struct rt2x00_dev *rt2x00dev = hw->priv; | 312 | struct rt2x00_dev *rt2x00dev = hw->priv; |
313 | int force_reconfig; | ||
325 | 314 | ||
326 | /* | 315 | /* |
327 | * Mac80211 might be calling this function while we are trying | 316 | * Mac80211 might be calling this function while we are trying |
@@ -341,7 +330,17 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) | |||
341 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); | 330 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); |
342 | } | 331 | } |
343 | 332 | ||
344 | rt2x00lib_config(rt2x00dev, conf, 0); | 333 | /* |
334 | * When the DEVICE_DIRTY_CONFIG flag is set, the device has recently | ||
335 | * been started and the configuration must be forced upon the hardware. | ||
336 | * Otherwise registers will not be intialized correctly and could | ||
337 | * result in non-working hardware because essential registers aren't | ||
338 | * initialized. | ||
339 | */ | ||
340 | force_reconfig = | ||
341 | __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); | ||
342 | |||
343 | rt2x00lib_config(rt2x00dev, conf, force_reconfig); | ||
345 | 344 | ||
346 | /* | 345 | /* |
347 | * Reenable RX only if the radio should be on. | 346 | * Reenable RX only if the radio should be on. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 7f442030f5ad..3b27f6aa860c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -120,6 +120,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, | |||
120 | { | 120 | { |
121 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 121 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
122 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); | 122 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); |
123 | struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); | ||
123 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; | 124 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; |
124 | struct ieee80211_rate *rate = | 125 | struct ieee80211_rate *rate = |
125 | ieee80211_get_tx_rate(rt2x00dev->hw, tx_info); | 126 | ieee80211_get_tx_rate(rt2x00dev->hw, tx_info); |
@@ -200,6 +201,31 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, | |||
200 | } | 201 | } |
201 | 202 | ||
202 | /* | 203 | /* |
204 | * Hardware should insert sequence counter. | ||
205 | * FIXME: We insert a software sequence counter first for | ||
206 | * hardware that doesn't support hardware sequence counting. | ||
207 | * | ||
208 | * This is wrong because beacons are not getting sequence | ||
209 | * numbers assigned properly. | ||
210 | * | ||
211 | * A secondary problem exists for drivers that cannot toggle | ||
212 | * sequence counting per-frame, since those will override the | ||
213 | * sequence counter given by mac80211. | ||
214 | */ | ||
215 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | ||
216 | spin_lock(&intf->lock); | ||
217 | |||
218 | if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) | ||
219 | intf->seqno += 0x10; | ||
220 | hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); | ||
221 | hdr->seq_ctrl |= cpu_to_le16(intf->seqno); | ||
222 | |||
223 | spin_unlock(&intf->lock); | ||
224 | |||
225 | __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); | ||
226 | } | ||
227 | |||
228 | /* | ||
203 | * PLCP setup | 229 | * PLCP setup |
204 | * Length calculation depends on OFDM/CCK rate. | 230 | * Length calculation depends on OFDM/CCK rate. |
205 | */ | 231 | */ |
@@ -466,9 +492,12 @@ void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev) | |||
466 | if (!rt2x00dev->ops->lib->init_rxentry) | 492 | if (!rt2x00dev->ops->lib->init_rxentry) |
467 | return; | 493 | return; |
468 | 494 | ||
469 | for (i = 0; i < queue->limit; i++) | 495 | for (i = 0; i < queue->limit; i++) { |
496 | queue->entries[i].flags = 0; | ||
497 | |||
470 | rt2x00dev->ops->lib->init_rxentry(rt2x00dev, | 498 | rt2x00dev->ops->lib->init_rxentry(rt2x00dev, |
471 | &queue->entries[i]); | 499 | &queue->entries[i]); |
500 | } | ||
472 | } | 501 | } |
473 | 502 | ||
474 | void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev) | 503 | void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev) |
@@ -482,9 +511,12 @@ void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev) | |||
482 | if (!rt2x00dev->ops->lib->init_txentry) | 511 | if (!rt2x00dev->ops->lib->init_txentry) |
483 | continue; | 512 | continue; |
484 | 513 | ||
485 | for (i = 0; i < queue->limit; i++) | 514 | for (i = 0; i < queue->limit; i++) { |
515 | queue->entries[i].flags = 0; | ||
516 | |||
486 | rt2x00dev->ops->lib->init_txentry(rt2x00dev, | 517 | rt2x00dev->ops->lib->init_txentry(rt2x00dev, |
487 | &queue->entries[i]); | 518 | &queue->entries[i]); |
519 | } | ||
488 | } | 520 | } |
489 | } | 521 | } |
490 | 522 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 8945945c892e..a4a8c57004db 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h | |||
@@ -199,6 +199,7 @@ struct txdone_entry_desc { | |||
199 | * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. | 199 | * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. |
200 | * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame. | 200 | * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame. |
201 | * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. | 201 | * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. |
202 | * @ENTRY_TXD_GENERATE_SEQ: This frame requires sequence counter. | ||
202 | * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame. | 203 | * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame. |
203 | * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. | 204 | * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. |
204 | * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted. | 205 | * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted. |
@@ -210,6 +211,7 @@ enum txentry_desc_flags { | |||
210 | ENTRY_TXD_RTS_FRAME, | 211 | ENTRY_TXD_RTS_FRAME, |
211 | ENTRY_TXD_CTS_FRAME, | 212 | ENTRY_TXD_CTS_FRAME, |
212 | ENTRY_TXD_OFDM_RATE, | 213 | ENTRY_TXD_OFDM_RATE, |
214 | ENTRY_TXD_GENERATE_SEQ, | ||
213 | ENTRY_TXD_FIRST_FRAGMENT, | 215 | ENTRY_TXD_FIRST_FRAGMENT, |
214 | ENTRY_TXD_MORE_FRAG, | 216 | ENTRY_TXD_MORE_FRAG, |
215 | ENTRY_TXD_REQ_TIMESTAMP, | 217 | ENTRY_TXD_REQ_TIMESTAMP, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 83862e7f7aec..933e6cc9359d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -122,6 +122,38 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, | |||
122 | } | 122 | } |
123 | EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); | 123 | EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); |
124 | 124 | ||
125 | int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, | ||
126 | const u8 request, const u8 requesttype, | ||
127 | const u16 offset, void *buffer, | ||
128 | const u16 buffer_length, | ||
129 | const int timeout) | ||
130 | { | ||
131 | int status = 0; | ||
132 | unsigned char *tb; | ||
133 | u16 off, len, bsize; | ||
134 | |||
135 | mutex_lock(&rt2x00dev->usb_cache_mutex); | ||
136 | |||
137 | tb = buffer; | ||
138 | off = offset; | ||
139 | len = buffer_length; | ||
140 | while (len && !status) { | ||
141 | bsize = min_t(u16, CSR_CACHE_SIZE, len); | ||
142 | status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request, | ||
143 | requesttype, off, tb, | ||
144 | bsize, timeout); | ||
145 | |||
146 | tb += bsize; | ||
147 | len -= bsize; | ||
148 | off += bsize; | ||
149 | } | ||
150 | |||
151 | mutex_unlock(&rt2x00dev->usb_cache_mutex); | ||
152 | |||
153 | return status; | ||
154 | } | ||
155 | EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff); | ||
156 | |||
125 | /* | 157 | /* |
126 | * TX data handlers. | 158 | * TX data handlers. |
127 | */ | 159 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index aad794adf52c..ee3875f894aa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h | |||
@@ -70,8 +70,7 @@ | |||
70 | /* | 70 | /* |
71 | * Cache size | 71 | * Cache size |
72 | */ | 72 | */ |
73 | #define CSR_CACHE_SIZE 8 | 73 | #define CSR_CACHE_SIZE 64 |
74 | #define CSR_CACHE_SIZE_FIRMWARE 64 | ||
75 | 74 | ||
76 | /* | 75 | /* |
77 | * USB request types. | 76 | * USB request types. |
@@ -172,6 +171,25 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, | |||
172 | const u16 buffer_length, const int timeout); | 171 | const u16 buffer_length, const int timeout); |
173 | 172 | ||
174 | /** | 173 | /** |
174 | * rt2x00usb_vendor_request_large_buff - Send register command to device (buffered) | ||
175 | * @rt2x00dev: Pointer to &struct rt2x00_dev | ||
176 | * @request: USB vendor command (See &enum rt2x00usb_vendor_request) | ||
177 | * @requesttype: Request type &USB_VENDOR_REQUEST_* | ||
178 | * @offset: Register start offset to perform action on | ||
179 | * @buffer: Buffer where information will be read/written to by device | ||
180 | * @buffer_length: Size of &buffer | ||
181 | * @timeout: Operation timeout | ||
182 | * | ||
183 | * This function is used to transfer register data in blocks larger | ||
184 | * then CSR_CACHE_SIZE. Use for firmware upload, keys and beacons. | ||
185 | */ | ||
186 | int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, | ||
187 | const u8 request, const u8 requesttype, | ||
188 | const u16 offset, void *buffer, | ||
189 | const u16 buffer_length, | ||
190 | const int timeout); | ||
191 | |||
192 | /** | ||
175 | * rt2x00usb_vendor_request_sw - Send single register command to device | 193 | * rt2x00usb_vendor_request_sw - Send single register command to device |
176 | * @rt2x00dev: Pointer to &struct rt2x00_dev | 194 | * @rt2x00dev: Pointer to &struct rt2x00_dev |
177 | * @request: USB vendor command (See &enum rt2x00usb_vendor_request) | 195 | * @request: USB vendor command (See &enum rt2x00usb_vendor_request) |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f7c1f92c1448..fbe2a652e014 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -1544,7 +1544,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, | |||
1544 | rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); | 1544 | rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); |
1545 | rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); | 1545 | rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); |
1546 | rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); | 1546 | rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); |
1547 | rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); | 1547 | rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, |
1548 | test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); | ||
1548 | rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); | 1549 | rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); |
1549 | rt2x00_desc_write(txd, 1, word); | 1550 | rt2x00_desc_write(txd, 1, word); |
1550 | 1551 | ||
@@ -2278,7 +2279,6 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
2278 | * Initialize all hw fields. | 2279 | * Initialize all hw fields. |
2279 | */ | 2280 | */ |
2280 | rt2x00dev->hw->flags = | 2281 | rt2x00dev->hw->flags = |
2281 | IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | | ||
2282 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 2282 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
2283 | IEEE80211_HW_SIGNAL_DBM; | 2283 | IEEE80211_HW_SIGNAL_DBM; |
2284 | rt2x00dev->hw->extra_tx_headroom = 0; | 2284 | rt2x00dev->hw->extra_tx_headroom = 0; |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d383735ab8f2..9761eaaa08be 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -890,9 +890,6 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, | |||
890 | unsigned int i; | 890 | unsigned int i; |
891 | int status; | 891 | int status; |
892 | u32 reg; | 892 | u32 reg; |
893 | const char *ptr = data; | ||
894 | char *cache; | ||
895 | int buflen; | ||
896 | 893 | ||
897 | /* | 894 | /* |
898 | * Wait for stable hardware. | 895 | * Wait for stable hardware. |
@@ -911,31 +908,12 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, | |||
911 | 908 | ||
912 | /* | 909 | /* |
913 | * Write firmware to device. | 910 | * Write firmware to device. |
914 | * We setup a seperate cache for this action, | ||
915 | * since we are going to write larger chunks of data | ||
916 | * then normally used cache size. | ||
917 | */ | 911 | */ |
918 | cache = kmalloc(CSR_CACHE_SIZE_FIRMWARE, GFP_KERNEL); | 912 | rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, |
919 | if (!cache) { | 913 | USB_VENDOR_REQUEST_OUT, |
920 | ERROR(rt2x00dev, "Failed to allocate firmware cache.\n"); | 914 | FIRMWARE_IMAGE_BASE, |
921 | return -ENOMEM; | 915 | data, len, |
922 | } | 916 | REGISTER_TIMEOUT32(len)); |
923 | |||
924 | for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) { | ||
925 | buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE); | ||
926 | |||
927 | memcpy(cache, ptr, buflen); | ||
928 | |||
929 | rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, | ||
930 | USB_VENDOR_REQUEST_OUT, | ||
931 | FIRMWARE_IMAGE_BASE + i, 0, | ||
932 | cache, buflen, | ||
933 | REGISTER_TIMEOUT32(buflen)); | ||
934 | |||
935 | ptr += buflen; | ||
936 | } | ||
937 | |||
938 | kfree(cache); | ||
939 | 917 | ||
940 | /* | 918 | /* |
941 | * Send firmware request to device to load firmware, | 919 | * Send firmware request to device to load firmware, |
@@ -1303,7 +1281,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, | |||
1303 | rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); | 1281 | rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); |
1304 | rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); | 1282 | rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); |
1305 | rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); | 1283 | rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); |
1306 | rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); | 1284 | rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, |
1285 | test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); | ||
1307 | rt2x00_desc_write(txd, 1, word); | 1286 | rt2x00_desc_write(txd, 1, word); |
1308 | 1287 | ||
1309 | rt2x00_desc_read(txd, 2, &word); | 1288 | rt2x00_desc_read(txd, 2, &word); |
@@ -1352,6 +1331,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry) | |||
1352 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); | 1331 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); |
1353 | unsigned int beacon_base; | 1332 | unsigned int beacon_base; |
1354 | u32 reg; | 1333 | u32 reg; |
1334 | u32 word, len; | ||
1355 | 1335 | ||
1356 | /* | 1336 | /* |
1357 | * Add the descriptor in front of the skb. | 1337 | * Add the descriptor in front of the skb. |
@@ -1361,6 +1341,17 @@ static void rt73usb_write_beacon(struct queue_entry *entry) | |||
1361 | skbdesc->desc = entry->skb->data; | 1341 | skbdesc->desc = entry->skb->data; |
1362 | 1342 | ||
1363 | /* | 1343 | /* |
1344 | * Adjust the beacon databyte count. The current number is | ||
1345 | * calculated before this function gets called, but falsely | ||
1346 | * assumes that the descriptor was already present in the SKB. | ||
1347 | */ | ||
1348 | rt2x00_desc_read(skbdesc->desc, 0, &word); | ||
1349 | len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); | ||
1350 | len += skbdesc->desc_len; | ||
1351 | rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); | ||
1352 | rt2x00_desc_write(skbdesc->desc, 0, word); | ||
1353 | |||
1354 | /* | ||
1364 | * Disable beaconing while we are reloading the beacon data, | 1355 | * Disable beaconing while we are reloading the beacon data, |
1365 | * otherwise we might be sending out invalid data. | 1356 | * otherwise we might be sending out invalid data. |
1366 | */ | 1357 | */ |
@@ -1374,10 +1365,10 @@ static void rt73usb_write_beacon(struct queue_entry *entry) | |||
1374 | * Write entire beacon with descriptor to register. | 1365 | * Write entire beacon with descriptor to register. |
1375 | */ | 1366 | */ |
1376 | beacon_base = HW_BEACON_OFFSET(entry->entry_idx); | 1367 | beacon_base = HW_BEACON_OFFSET(entry->entry_idx); |
1377 | rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, | 1368 | rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, |
1378 | USB_VENDOR_REQUEST_OUT, beacon_base, 0, | 1369 | USB_VENDOR_REQUEST_OUT, beacon_base, |
1379 | entry->skb->data, entry->skb->len, | 1370 | entry->skb->data, entry->skb->len, |
1380 | REGISTER_TIMEOUT32(entry->skb->len)); | 1371 | REGISTER_TIMEOUT32(entry->skb->len)); |
1381 | 1372 | ||
1382 | /* | 1373 | /* |
1383 | * Clean up the beacon skb. | 1374 | * Clean up the beacon skb. |
@@ -1871,7 +1862,6 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
1871 | * Initialize all hw fields. | 1862 | * Initialize all hw fields. |
1872 | */ | 1863 | */ |
1873 | rt2x00dev->hw->flags = | 1864 | rt2x00dev->hw->flags = |
1874 | IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | | ||
1875 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1865 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1876 | IEEE80211_HW_SIGNAL_DBM; | 1866 | IEEE80211_HW_SIGNAL_DBM; |
1877 | rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; | 1867 | rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; |
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 3afb49f8866a..1b0d750f6623 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h | |||
@@ -47,11 +47,13 @@ struct rtl8187_rx_hdr { | |||
47 | struct rtl8187b_rx_hdr { | 47 | struct rtl8187b_rx_hdr { |
48 | __le32 flags; | 48 | __le32 flags; |
49 | __le64 mac_time; | 49 | __le64 mac_time; |
50 | u8 noise; | 50 | u8 sq; |
51 | u8 signal; | 51 | u8 rssi; |
52 | u8 agc; | 52 | u8 agc; |
53 | u8 reserved; | 53 | u8 flags2; |
54 | __le32 unused; | 54 | __le16 snr_long2end; |
55 | s8 pwdb_g12; | ||
56 | u8 fot; | ||
55 | } __attribute__((packed)); | 57 | } __attribute__((packed)); |
56 | 58 | ||
57 | /* {rtl8187,rtl8187b}_tx_info is in skb */ | 59 | /* {rtl8187,rtl8187b}_tx_info is in skb */ |
@@ -100,6 +102,7 @@ struct rtl8187_priv { | |||
100 | struct usb_device *udev; | 102 | struct usb_device *udev; |
101 | u32 rx_conf; | 103 | u32 rx_conf; |
102 | u16 txpwr_base; | 104 | u16 txpwr_base; |
105 | u16 seqno; | ||
103 | u8 asic_rev; | 106 | u8 asic_rev; |
104 | u8 is_rtl8187b; | 107 | u8 is_rtl8187b; |
105 | enum { | 108 | enum { |
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index d3067b1216ca..177988efd660 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c | |||
@@ -169,6 +169,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
169 | { | 169 | { |
170 | struct rtl8187_priv *priv = dev->priv; | 170 | struct rtl8187_priv *priv = dev->priv; |
171 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 171 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
172 | struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; | ||
172 | unsigned int ep; | 173 | unsigned int ep; |
173 | void *buf; | 174 | void *buf; |
174 | struct urb *urb; | 175 | struct urb *urb; |
@@ -234,6 +235,20 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
234 | ep = epmap[skb_get_queue_mapping(skb)]; | 235 | ep = epmap[skb_get_queue_mapping(skb)]; |
235 | } | 236 | } |
236 | 237 | ||
238 | /* FIXME: The sequence that follows is needed for this driver to | ||
239 | * work with mac80211 since "mac80211: fix TX sequence numbers". | ||
240 | * As with the temporary code in rt2x00, changes will be needed | ||
241 | * to get proper sequence numbers on beacons. In addition, this | ||
242 | * patch places the sequence number in the hardware state, which | ||
243 | * limits us to a single virtual state. | ||
244 | */ | ||
245 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | ||
246 | if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) | ||
247 | priv->seqno += 0x10; | ||
248 | ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); | ||
249 | ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); | ||
250 | } | ||
251 | |||
237 | info->driver_data[0] = dev; | 252 | info->driver_data[0] = dev; |
238 | info->driver_data[1] = urb; | 253 | info->driver_data[1] = urb; |
239 | 254 | ||
@@ -257,6 +272,7 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
257 | struct ieee80211_rx_status rx_status = { 0 }; | 272 | struct ieee80211_rx_status rx_status = { 0 }; |
258 | int rate, signal; | 273 | int rate, signal; |
259 | u32 flags; | 274 | u32 flags; |
275 | u32 quality; | ||
260 | 276 | ||
261 | spin_lock(&priv->rx_queue.lock); | 277 | spin_lock(&priv->rx_queue.lock); |
262 | if (skb->next) | 278 | if (skb->next) |
@@ -280,44 +296,57 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
280 | flags = le32_to_cpu(hdr->flags); | 296 | flags = le32_to_cpu(hdr->flags); |
281 | signal = hdr->signal & 0x7f; | 297 | signal = hdr->signal & 0x7f; |
282 | rx_status.antenna = (hdr->signal >> 7) & 1; | 298 | rx_status.antenna = (hdr->signal >> 7) & 1; |
283 | rx_status.signal = signal; | ||
284 | rx_status.noise = hdr->noise; | 299 | rx_status.noise = hdr->noise; |
285 | rx_status.mactime = le64_to_cpu(hdr->mac_time); | 300 | rx_status.mactime = le64_to_cpu(hdr->mac_time); |
286 | priv->signal = signal; | ||
287 | priv->quality = signal; | 301 | priv->quality = signal; |
302 | rx_status.qual = priv->quality; | ||
288 | priv->noise = hdr->noise; | 303 | priv->noise = hdr->noise; |
304 | rate = (flags >> 20) & 0xF; | ||
305 | if (rate > 3) { /* OFDM rate */ | ||
306 | if (signal > 90) | ||
307 | signal = 90; | ||
308 | else if (signal < 25) | ||
309 | signal = 25; | ||
310 | signal = 90 - signal; | ||
311 | } else { /* CCK rate */ | ||
312 | if (signal > 95) | ||
313 | signal = 95; | ||
314 | else if (signal < 30) | ||
315 | signal = 30; | ||
316 | signal = 95 - signal; | ||
317 | } | ||
318 | rx_status.signal = signal; | ||
319 | priv->signal = signal; | ||
289 | } else { | 320 | } else { |
290 | struct rtl8187b_rx_hdr *hdr = | 321 | struct rtl8187b_rx_hdr *hdr = |
291 | (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); | 322 | (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); |
323 | /* The Realtek datasheet for the RTL8187B shows that the RX | ||
324 | * header contains the following quantities: signal quality, | ||
325 | * RSSI, AGC, the received power in dB, and the measured SNR. | ||
326 | * In testing, none of these quantities show qualitative | ||
327 | * agreement with AP signal strength, except for the AGC, | ||
328 | * which is inversely proportional to the strength of the | ||
329 | * signal. In the following, the quality and signal strength | ||
330 | * are derived from the AGC. The arbitrary scaling constants | ||
331 | * are chosen to make the results close to the values obtained | ||
332 | * for a BCM4312 using b43 as the driver. The noise is ignored | ||
333 | * for now. | ||
334 | */ | ||
292 | flags = le32_to_cpu(hdr->flags); | 335 | flags = le32_to_cpu(hdr->flags); |
293 | signal = hdr->agc >> 1; | 336 | quality = 170 - hdr->agc; |
294 | rx_status.antenna = (hdr->signal >> 7) & 1; | 337 | if (quality > 100) |
295 | rx_status.signal = 64 - min(hdr->noise, (u8)64); | 338 | quality = 100; |
296 | rx_status.noise = hdr->noise; | 339 | signal = 14 - hdr->agc / 2; |
340 | rx_status.qual = quality; | ||
341 | priv->quality = quality; | ||
342 | rx_status.signal = signal; | ||
343 | priv->signal = signal; | ||
344 | rx_status.antenna = (hdr->rssi >> 7) & 1; | ||
297 | rx_status.mactime = le64_to_cpu(hdr->mac_time); | 345 | rx_status.mactime = le64_to_cpu(hdr->mac_time); |
298 | priv->signal = hdr->signal; | 346 | rate = (flags >> 20) & 0xF; |
299 | priv->quality = hdr->agc >> 1; | ||
300 | priv->noise = hdr->noise; | ||
301 | } | 347 | } |
302 | 348 | ||
303 | skb_trim(skb, flags & 0x0FFF); | 349 | skb_trim(skb, flags & 0x0FFF); |
304 | rate = (flags >> 20) & 0xF; | ||
305 | if (rate > 3) { /* OFDM rate */ | ||
306 | if (signal > 90) | ||
307 | signal = 90; | ||
308 | else if (signal < 25) | ||
309 | signal = 25; | ||
310 | signal = 90 - signal; | ||
311 | } else { /* CCK rate */ | ||
312 | if (signal > 95) | ||
313 | signal = 95; | ||
314 | else if (signal < 30) | ||
315 | signal = 30; | ||
316 | signal = 95 - signal; | ||
317 | } | ||
318 | |||
319 | rx_status.qual = priv->quality; | ||
320 | rx_status.signal = signal; | ||
321 | rx_status.rate_idx = rate; | 350 | rx_status.rate_idx = rate; |
322 | rx_status.freq = dev->conf.channel->center_freq; | 351 | rx_status.freq = dev->conf.channel->center_freq; |
323 | rx_status.band = dev->conf.channel->band; | 352 | rx_status.band = dev->conf.channel->band; |
@@ -1015,9 +1044,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, | |||
1015 | 1044 | ||
1016 | priv->mode = IEEE80211_IF_TYPE_MNTR; | 1045 | priv->mode = IEEE80211_IF_TYPE_MNTR; |
1017 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1046 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1018 | IEEE80211_HW_RX_INCLUDES_FCS | | 1047 | IEEE80211_HW_RX_INCLUDES_FCS; |
1019 | IEEE80211_HW_SIGNAL_UNSPEC; | ||
1020 | dev->max_signal = 65; | ||
1021 | 1048 | ||
1022 | eeprom.data = dev; | 1049 | eeprom.data = dev; |
1023 | eeprom.register_read = rtl8187_eeprom_register_read; | 1050 | eeprom.register_read = rtl8187_eeprom_register_read; |
@@ -1132,10 +1159,16 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, | |||
1132 | (*channel++).hw_value = txpwr >> 8; | 1159 | (*channel++).hw_value = txpwr >> 8; |
1133 | } | 1160 | } |
1134 | 1161 | ||
1135 | if (priv->is_rtl8187b) | 1162 | if (priv->is_rtl8187b) { |
1136 | printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " | 1163 | printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " |
1137 | "is EXPERIMENTAL, and could damage your\n" | 1164 | "is EXPERIMENTAL, and could damage your\n" |
1138 | " hardware, use at your own risk\n"); | 1165 | " hardware, use at your own risk\n"); |
1166 | dev->flags |= IEEE80211_HW_SIGNAL_DBM; | ||
1167 | } else { | ||
1168 | dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; | ||
1169 | dev->max_signal = 65; | ||
1170 | } | ||
1171 | |||
1139 | if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) | 1172 | if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) |
1140 | printk(KERN_INFO "rtl8187: inconsistency between id with OEM" | 1173 | printk(KERN_INFO "rtl8187: inconsistency between id with OEM" |
1141 | " info!\n"); | 1174 | " info!\n"); |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index fcc532bb6a7e..4d7b98b05030 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -935,7 +935,6 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) | |||
935 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; | 935 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; |
936 | 936 | ||
937 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | 937 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
938 | IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | | ||
939 | IEEE80211_HW_SIGNAL_DB; | 938 | IEEE80211_HW_SIGNAL_DB; |
940 | 939 | ||
941 | hw->max_signal = 100; | 940 | hw->max_signal = 100; |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 1323a43285d7..ad27e9e225a6 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -1103,7 +1103,7 @@ static inline void dbg_ctrl(struct controller *ctrl) | |||
1103 | dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); | 1103 | dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); |
1104 | dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); | 1104 | dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); |
1105 | dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); | 1105 | dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); |
1106 | dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes"); | 1106 | dbg(" Command Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes"); |
1107 | pciehp_readw(ctrl, SLOTSTATUS, ®16); | 1107 | pciehp_readw(ctrl, SLOTSTATUS, ®16); |
1108 | dbg("Slot Status : 0x%04x\n", reg16); | 1108 | dbg("Slot Status : 0x%04x\n", reg16); |
1109 | pciehp_readw(ctrl, SLOTCTRL, ®16); | 1109 | pciehp_readw(ctrl, SLOTCTRL, ®16); |
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 15af618d36e2..18354817173c 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -126,7 +126,16 @@ static void msix_flush_writes(unsigned int irq) | |||
126 | } | 126 | } |
127 | } | 127 | } |
128 | 128 | ||
129 | static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) | 129 | /* |
130 | * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to | ||
131 | * mask all MSI interrupts by clearing the MSI enable bit does not work | ||
132 | * reliably as devices without an INTx disable bit will then generate a | ||
133 | * level IRQ which will never be cleared. | ||
134 | * | ||
135 | * Returns 1 if it succeeded in masking the interrupt and 0 if the device | ||
136 | * doesn't support MSI masking. | ||
137 | */ | ||
138 | static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) | ||
130 | { | 139 | { |
131 | struct msi_desc *entry; | 140 | struct msi_desc *entry; |
132 | 141 | ||
@@ -144,8 +153,7 @@ static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) | |||
144 | mask_bits |= flag & mask; | 153 | mask_bits |= flag & mask; |
145 | pci_write_config_dword(entry->dev, pos, mask_bits); | 154 | pci_write_config_dword(entry->dev, pos, mask_bits); |
146 | } else { | 155 | } else { |
147 | __msi_set_enable(entry->dev, entry->msi_attrib.pos, | 156 | return 0; |
148 | !flag); | ||
149 | } | 157 | } |
150 | break; | 158 | break; |
151 | case PCI_CAP_ID_MSIX: | 159 | case PCI_CAP_ID_MSIX: |
@@ -161,6 +169,7 @@ static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) | |||
161 | break; | 169 | break; |
162 | } | 170 | } |
163 | entry->msi_attrib.masked = !!flag; | 171 | entry->msi_attrib.masked = !!flag; |
172 | return 1; | ||
164 | } | 173 | } |
165 | 174 | ||
166 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) | 175 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) |
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 7764768b6a0e..89a2f0fa10f9 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/pci-aspm.h> | ||
14 | #include <acpi/acpi.h> | 15 | #include <acpi/acpi.h> |
15 | #include <acpi/acnamesp.h> | 16 | #include <acpi/acnamesp.h> |
16 | #include <acpi/acresrc.h> | 17 | #include <acpi/acresrc.h> |
@@ -372,6 +373,12 @@ static int __init acpi_pci_init(void) | |||
372 | printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n"); | 373 | printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n"); |
373 | pci_no_msi(); | 374 | pci_no_msi(); |
374 | } | 375 | } |
376 | |||
377 | if (acpi_gbl_FADT.boot_flags & BAF_PCIE_ASPM_CONTROL) { | ||
378 | printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); | ||
379 | pcie_no_aspm(); | ||
380 | } | ||
381 | |||
375 | ret = register_acpi_bus_type(&acpi_pci_bus); | 382 | ret = register_acpi_bus_type(&acpi_pci_bus); |
376 | if (ret) | 383 | if (ret) |
377 | return 0; | 384 | return 0; |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e9c356236d27..0a3d856833fc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -572,6 +572,10 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
572 | if (!ret) | 572 | if (!ret) |
573 | pci_update_current_state(dev); | 573 | pci_update_current_state(dev); |
574 | } | 574 | } |
575 | /* This device is quirked not to be put into D3, so | ||
576 | don't put it in D3 */ | ||
577 | if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3)) | ||
578 | return 0; | ||
575 | 579 | ||
576 | error = pci_raw_set_power_state(dev, state); | 580 | error = pci_raw_set_power_state(dev, state); |
577 | 581 | ||
@@ -1123,6 +1127,12 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) | |||
1123 | } | 1127 | } |
1124 | 1128 | ||
1125 | /** | 1129 | /** |
1130 | * pci_target_state - find an appropriate low power state for a given PCI dev | ||
1131 | * @dev: PCI device | ||
1132 | * | ||
1133 | * Use underlying platform code to find a supported low power state for @dev. | ||
1134 | * If the platform can't manage @dev, return the deepest state from which it | ||
1135 | * can generate wake events, based on any available PME info. | ||
1126 | */ | 1136 | */ |
1127 | pci_power_t pci_target_state(struct pci_dev *dev) | 1137 | pci_power_t pci_target_state(struct pci_dev *dev) |
1128 | { | 1138 | { |
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index f82495583e63..9a7c9e1408a4 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -55,7 +55,7 @@ struct pcie_link_state { | |||
55 | struct endpoint_state endpoints[8]; | 55 | struct endpoint_state endpoints[8]; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static int aspm_disabled; | 58 | static int aspm_disabled, aspm_force; |
59 | static DEFINE_MUTEX(aspm_lock); | 59 | static DEFINE_MUTEX(aspm_lock); |
60 | static LIST_HEAD(link_list); | 60 | static LIST_HEAD(link_list); |
61 | 61 | ||
@@ -510,6 +510,7 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) | |||
510 | { | 510 | { |
511 | struct pci_dev *child_dev; | 511 | struct pci_dev *child_dev; |
512 | int child_pos; | 512 | int child_pos; |
513 | u32 reg32; | ||
513 | 514 | ||
514 | /* | 515 | /* |
515 | * Some functions in a slot might not all be PCIE functions, very | 516 | * Some functions in a slot might not all be PCIE functions, very |
@@ -519,6 +520,19 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) | |||
519 | child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); | 520 | child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); |
520 | if (!child_pos) | 521 | if (!child_pos) |
521 | return -EINVAL; | 522 | return -EINVAL; |
523 | |||
524 | /* | ||
525 | * Disable ASPM for pre-1.1 PCIe device, we follow MS to use | ||
526 | * RBER bit to determine if a function is 1.1 version device | ||
527 | */ | ||
528 | pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP, | ||
529 | ®32); | ||
530 | if (!(reg32 & PCI_EXP_DEVCAP_RBER && !aspm_force)) { | ||
531 | printk("Pre-1.1 PCIe device detected, " | ||
532 | "disable ASPM for %s. It can be enabled forcedly" | ||
533 | " with 'pcie_aspm=force'\n", pci_name(pdev)); | ||
534 | return -EINVAL; | ||
535 | } | ||
522 | } | 536 | } |
523 | return 0; | 537 | return 0; |
524 | } | 538 | } |
@@ -802,11 +816,23 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) | |||
802 | 816 | ||
803 | static int __init pcie_aspm_disable(char *str) | 817 | static int __init pcie_aspm_disable(char *str) |
804 | { | 818 | { |
805 | aspm_disabled = 1; | 819 | if (!strcmp(str, "off")) { |
820 | aspm_disabled = 1; | ||
821 | printk(KERN_INFO "PCIe ASPM is disabled\n"); | ||
822 | } else if (!strcmp(str, "force")) { | ||
823 | aspm_force = 1; | ||
824 | printk(KERN_INFO "PCIe ASPM is forcedly enabled\n"); | ||
825 | } | ||
806 | return 1; | 826 | return 1; |
807 | } | 827 | } |
808 | 828 | ||
809 | __setup("pcie_noaspm", pcie_aspm_disable); | 829 | __setup("pcie_aspm=", pcie_aspm_disable); |
830 | |||
831 | void pcie_no_aspm(void) | ||
832 | { | ||
833 | if (!aspm_force) | ||
834 | aspm_disabled = 1; | ||
835 | } | ||
810 | 836 | ||
811 | #ifdef CONFIG_ACPI | 837 | #ifdef CONFIG_ACPI |
812 | #include <acpi/acpi_bus.h> | 838 | #include <acpi/acpi_bus.h> |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index b1724cf31b66..7098dfb07449 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -163,12 +163,9 @@ static inline unsigned int pci_calc_resource_flags(unsigned int flags) | |||
163 | return IORESOURCE_MEM; | 163 | return IORESOURCE_MEM; |
164 | } | 164 | } |
165 | 165 | ||
166 | /* | 166 | static u64 pci_size(u64 base, u64 maxbase, u64 mask) |
167 | * Find the extent of a PCI decode.. | ||
168 | */ | ||
169 | static u32 pci_size(u32 base, u32 maxbase, u32 mask) | ||
170 | { | 167 | { |
171 | u32 size = mask & maxbase; /* Find the significant bits */ | 168 | u64 size = mask & maxbase; /* Find the significant bits */ |
172 | if (!size) | 169 | if (!size) |
173 | return 0; | 170 | return 0; |
174 | 171 | ||
@@ -184,135 +181,142 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask) | |||
184 | return size; | 181 | return size; |
185 | } | 182 | } |
186 | 183 | ||
187 | static u64 pci_size64(u64 base, u64 maxbase, u64 mask) | 184 | enum pci_bar_type { |
188 | { | 185 | pci_bar_unknown, /* Standard PCI BAR probe */ |
189 | u64 size = mask & maxbase; /* Find the significant bits */ | 186 | pci_bar_io, /* An io port BAR */ |
190 | if (!size) | 187 | pci_bar_mem32, /* A 32-bit memory BAR */ |
191 | return 0; | 188 | pci_bar_mem64, /* A 64-bit memory BAR */ |
189 | }; | ||
192 | 190 | ||
193 | /* Get the lowest of them to find the decode size, and | 191 | static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar) |
194 | from that the extent. */ | 192 | { |
195 | size = (size & ~(size-1)) - 1; | 193 | if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { |
194 | res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; | ||
195 | return pci_bar_io; | ||
196 | } | ||
196 | 197 | ||
197 | /* base == maxbase can be valid only if the BAR has | 198 | res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; |
198 | already been programmed with all 1s. */ | ||
199 | if (base == maxbase && ((base | size) & mask) != mask) | ||
200 | return 0; | ||
201 | 199 | ||
202 | return size; | 200 | if (res->flags == PCI_BASE_ADDRESS_MEM_TYPE_64) |
201 | return pci_bar_mem64; | ||
202 | return pci_bar_mem32; | ||
203 | } | 203 | } |
204 | 204 | ||
205 | static inline int is_64bit_memory(u32 mask) | 205 | /* |
206 | * If the type is not unknown, we assume that the lowest bit is 'enable'. | ||
207 | * Returns 1 if the BAR was 64-bit and 0 if it was 32-bit. | ||
208 | */ | ||
209 | static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | ||
210 | struct resource *res, unsigned int pos) | ||
206 | { | 211 | { |
207 | if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == | 212 | u32 l, sz, mask; |
208 | (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) | ||
209 | return 1; | ||
210 | return 0; | ||
211 | } | ||
212 | 213 | ||
213 | static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | 214 | mask = type ? ~PCI_ROM_ADDRESS_ENABLE : ~0; |
214 | { | ||
215 | unsigned int pos, reg, next; | ||
216 | u32 l, sz; | ||
217 | struct resource *res; | ||
218 | 215 | ||
219 | for(pos=0; pos<howmany; pos = next) { | 216 | res->name = pci_name(dev); |
220 | u64 l64; | ||
221 | u64 sz64; | ||
222 | u32 raw_sz; | ||
223 | 217 | ||
224 | next = pos+1; | 218 | pci_read_config_dword(dev, pos, &l); |
225 | res = &dev->resource[pos]; | 219 | pci_write_config_dword(dev, pos, mask); |
226 | res->name = pci_name(dev); | 220 | pci_read_config_dword(dev, pos, &sz); |
227 | reg = PCI_BASE_ADDRESS_0 + (pos << 2); | 221 | pci_write_config_dword(dev, pos, l); |
228 | pci_read_config_dword(dev, reg, &l); | 222 | |
229 | pci_write_config_dword(dev, reg, ~0); | 223 | /* |
230 | pci_read_config_dword(dev, reg, &sz); | 224 | * All bits set in sz means the device isn't working properly. |
231 | pci_write_config_dword(dev, reg, l); | 225 | * If the BAR isn't implemented, all bits must be 0. If it's a |
232 | if (!sz || sz == 0xffffffff) | 226 | * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit |
233 | continue; | 227 | * 1 must be clear. |
234 | if (l == 0xffffffff) | 228 | */ |
235 | l = 0; | 229 | if (!sz || sz == 0xffffffff) |
236 | raw_sz = sz; | 230 | goto fail; |
237 | if ((l & PCI_BASE_ADDRESS_SPACE) == | 231 | |
238 | PCI_BASE_ADDRESS_SPACE_MEMORY) { | 232 | /* |
239 | sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK); | 233 | * I don't know how l can have all bits set. Copied from old code. |
240 | /* | 234 | * Maybe it fixes a bug on some ancient platform. |
241 | * For 64bit prefetchable memory sz could be 0, if the | 235 | */ |
242 | * real size is bigger than 4G, so we need to check | 236 | if (l == 0xffffffff) |
243 | * szhi for that. | 237 | l = 0; |
244 | */ | 238 | |
245 | if (!is_64bit_memory(l) && !sz) | 239 | if (type == pci_bar_unknown) { |
246 | continue; | 240 | type = decode_bar(res, l); |
247 | res->start = l & PCI_BASE_ADDRESS_MEM_MASK; | 241 | res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; |
248 | res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; | 242 | if (type == pci_bar_io) { |
243 | l &= PCI_BASE_ADDRESS_IO_MASK; | ||
244 | mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff; | ||
249 | } else { | 245 | } else { |
250 | sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff); | 246 | l &= PCI_BASE_ADDRESS_MEM_MASK; |
251 | if (!sz) | 247 | mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; |
252 | continue; | ||
253 | res->start = l & PCI_BASE_ADDRESS_IO_MASK; | ||
254 | res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; | ||
255 | } | 248 | } |
256 | res->end = res->start + (unsigned long) sz; | 249 | } else { |
257 | res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; | 250 | res->flags |= (l & IORESOURCE_ROM_ENABLE); |
258 | if (is_64bit_memory(l)) { | 251 | l &= PCI_ROM_ADDRESS_MASK; |
259 | u32 szhi, lhi; | 252 | mask = (u32)PCI_ROM_ADDRESS_MASK; |
260 | 253 | } | |
261 | pci_read_config_dword(dev, reg+4, &lhi); | 254 | |
262 | pci_write_config_dword(dev, reg+4, ~0); | 255 | if (type == pci_bar_mem64) { |
263 | pci_read_config_dword(dev, reg+4, &szhi); | 256 | u64 l64 = l; |
264 | pci_write_config_dword(dev, reg+4, lhi); | 257 | u64 sz64 = sz; |
265 | sz64 = ((u64)szhi << 32) | raw_sz; | 258 | u64 mask64 = mask | (u64)~0 << 32; |
266 | l64 = ((u64)lhi << 32) | l; | 259 | |
267 | sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK); | 260 | pci_read_config_dword(dev, pos + 4, &l); |
268 | next++; | 261 | pci_write_config_dword(dev, pos + 4, ~0); |
269 | #if BITS_PER_LONG == 64 | 262 | pci_read_config_dword(dev, pos + 4, &sz); |
270 | if (!sz64) { | 263 | pci_write_config_dword(dev, pos + 4, l); |
271 | res->start = 0; | 264 | |
272 | res->end = 0; | 265 | l64 |= ((u64)l << 32); |
273 | res->flags = 0; | 266 | sz64 |= ((u64)sz << 32); |
274 | continue; | 267 | |
275 | } | 268 | sz64 = pci_size(l64, sz64, mask64); |
276 | res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK; | 269 | |
277 | res->end = res->start + sz64; | 270 | if (!sz64) |
278 | #else | 271 | goto fail; |
279 | if (sz64 > 0x100000000ULL) { | 272 | |
280 | dev_err(&dev->dev, "BAR %d: can't handle 64-bit" | 273 | if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) { |
281 | " BAR\n", pos); | 274 | dev_err(&dev->dev, "can't handle 64-bit BAR\n"); |
282 | res->start = 0; | 275 | goto fail; |
283 | res->flags = 0; | 276 | } else if ((sizeof(resource_size_t) < 8) && l) { |
284 | } else if (lhi) { | 277 | /* Address above 32-bit boundary; disable the BAR */ |
285 | /* 64-bit wide address, treat as disabled */ | 278 | pci_write_config_dword(dev, pos, 0); |
286 | pci_write_config_dword(dev, reg, | 279 | pci_write_config_dword(dev, pos + 4, 0); |
287 | l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); | 280 | res->start = 0; |
288 | pci_write_config_dword(dev, reg+4, 0); | 281 | res->end = sz64; |
289 | res->start = 0; | 282 | } else { |
290 | res->end = sz; | 283 | res->start = l64; |
291 | } | 284 | res->end = l64 + sz64; |
292 | #endif | ||
293 | } | 285 | } |
286 | } else { | ||
287 | sz = pci_size(l, sz, mask); | ||
288 | |||
289 | if (!sz) | ||
290 | goto fail; | ||
291 | |||
292 | res->start = l; | ||
293 | res->end = l + sz; | ||
294 | } | 294 | } |
295 | |||
296 | out: | ||
297 | return (type == pci_bar_mem64) ? 1 : 0; | ||
298 | fail: | ||
299 | res->flags = 0; | ||
300 | goto out; | ||
301 | } | ||
302 | |||
303 | static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | ||
304 | { | ||
305 | unsigned int pos, reg; | ||
306 | |||
307 | for (pos = 0; pos < howmany; pos++) { | ||
308 | struct resource *res = &dev->resource[pos]; | ||
309 | reg = PCI_BASE_ADDRESS_0 + (pos << 2); | ||
310 | pos += __pci_read_base(dev, pci_bar_unknown, res, reg); | ||
311 | } | ||
312 | |||
295 | if (rom) { | 313 | if (rom) { |
314 | struct resource *res = &dev->resource[PCI_ROM_RESOURCE]; | ||
296 | dev->rom_base_reg = rom; | 315 | dev->rom_base_reg = rom; |
297 | res = &dev->resource[PCI_ROM_RESOURCE]; | 316 | res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | |
298 | res->name = pci_name(dev); | 317 | IORESOURCE_READONLY | IORESOURCE_CACHEABLE | |
299 | pci_read_config_dword(dev, rom, &l); | 318 | IORESOURCE_SIZEALIGN; |
300 | pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE); | 319 | __pci_read_base(dev, pci_bar_mem32, res, rom); |
301 | pci_read_config_dword(dev, rom, &sz); | ||
302 | pci_write_config_dword(dev, rom, l); | ||
303 | if (l == 0xffffffff) | ||
304 | l = 0; | ||
305 | if (sz && sz != 0xffffffff) { | ||
306 | sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK); | ||
307 | if (sz) { | ||
308 | res->flags = (l & IORESOURCE_ROM_ENABLE) | | ||
309 | IORESOURCE_MEM | IORESOURCE_PREFETCH | | ||
310 | IORESOURCE_READONLY | IORESOURCE_CACHEABLE | | ||
311 | IORESOURCE_SIZEALIGN; | ||
312 | res->start = l & PCI_ROM_ADDRESS_MASK; | ||
313 | res->end = res->start + (unsigned long) sz; | ||
314 | } | ||
315 | } | ||
316 | } | 320 | } |
317 | } | 321 | } |
318 | 322 | ||
@@ -1053,7 +1057,8 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) | |||
1053 | } | 1057 | } |
1054 | } | 1058 | } |
1055 | 1059 | ||
1056 | if (bus->self) | 1060 | /* only one slot has pcie device */ |
1061 | if (bus->self && nr) | ||
1057 | pcie_aspm_init_link_state(bus->self); | 1062 | pcie_aspm_init_link_state(bus->self); |
1058 | 1063 | ||
1059 | return nr; | 1064 | return nr; |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 12d489395fad..0fb365074288 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -923,6 +923,19 @@ static void __init quirk_ide_samemode(struct pci_dev *pdev) | |||
923 | } | 923 | } |
924 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, quirk_ide_samemode); | 924 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, quirk_ide_samemode); |
925 | 925 | ||
926 | /* | ||
927 | * Some ATA devices break if put into D3 | ||
928 | */ | ||
929 | |||
930 | static void __devinit quirk_no_ata_d3(struct pci_dev *pdev) | ||
931 | { | ||
932 | /* Quirk the legacy ATA devices only. The AHCI ones are ok */ | ||
933 | if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) | ||
934 | pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; | ||
935 | } | ||
936 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID, quirk_no_ata_d3); | ||
937 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID, quirk_no_ata_d3); | ||
938 | |||
926 | /* This was originally an Alpha specific thing, but it really fits here. | 939 | /* This was originally an Alpha specific thing, but it really fits here. |
927 | * The i82375 PCI/EISA bridge appears as non-classified. Fix that. | 940 | * The i82375 PCI/EISA bridge appears as non-classified. Fix that. |
928 | */ | 941 | */ |
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index d397fa5f3a91..7af60b98d8a4 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
@@ -20,7 +20,7 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | |||
20 | 20 | ||
21 | err = mutex_lock_interruptible(&rtc->ops_lock); | 21 | err = mutex_lock_interruptible(&rtc->ops_lock); |
22 | if (err) | 22 | if (err) |
23 | return -EBUSY; | 23 | return err; |
24 | 24 | ||
25 | if (!rtc->ops) | 25 | if (!rtc->ops) |
26 | err = -ENODEV; | 26 | err = -ENODEV; |
@@ -46,7 +46,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) | |||
46 | 46 | ||
47 | err = mutex_lock_interruptible(&rtc->ops_lock); | 47 | err = mutex_lock_interruptible(&rtc->ops_lock); |
48 | if (err) | 48 | if (err) |
49 | return -EBUSY; | 49 | return err; |
50 | 50 | ||
51 | if (!rtc->ops) | 51 | if (!rtc->ops) |
52 | err = -ENODEV; | 52 | err = -ENODEV; |
@@ -66,7 +66,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) | |||
66 | 66 | ||
67 | err = mutex_lock_interruptible(&rtc->ops_lock); | 67 | err = mutex_lock_interruptible(&rtc->ops_lock); |
68 | if (err) | 68 | if (err) |
69 | return -EBUSY; | 69 | return err; |
70 | 70 | ||
71 | if (!rtc->ops) | 71 | if (!rtc->ops) |
72 | err = -ENODEV; | 72 | err = -ENODEV; |
@@ -106,7 +106,7 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al | |||
106 | 106 | ||
107 | err = mutex_lock_interruptible(&rtc->ops_lock); | 107 | err = mutex_lock_interruptible(&rtc->ops_lock); |
108 | if (err) | 108 | if (err) |
109 | return -EBUSY; | 109 | return err; |
110 | 110 | ||
111 | if (rtc->ops == NULL) | 111 | if (rtc->ops == NULL) |
112 | err = -ENODEV; | 112 | err = -ENODEV; |
@@ -293,7 +293,7 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | |||
293 | 293 | ||
294 | err = mutex_lock_interruptible(&rtc->ops_lock); | 294 | err = mutex_lock_interruptible(&rtc->ops_lock); |
295 | if (err) | 295 | if (err) |
296 | return -EBUSY; | 296 | return err; |
297 | 297 | ||
298 | if (!rtc->ops) | 298 | if (!rtc->ops) |
299 | err = -ENODEV; | 299 | err = -ENODEV; |
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 0a870b7e5c32..856cc1af40df 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c | |||
@@ -221,7 +221,7 @@ static long rtc_dev_ioctl(struct file *file, | |||
221 | 221 | ||
222 | err = mutex_lock_interruptible(&rtc->ops_lock); | 222 | err = mutex_lock_interruptible(&rtc->ops_lock); |
223 | if (err) | 223 | if (err) |
224 | return -EBUSY; | 224 | return err; |
225 | 225 | ||
226 | /* check that the calling task has appropriate permissions | 226 | /* check that the calling task has appropriate permissions |
227 | * for certain ioctls. doing this check here is useful | 227 | * for certain ioctls. doing this check here is useful |
@@ -432,6 +432,8 @@ static int rtc_dev_release(struct inode *inode, struct file *file) | |||
432 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | 432 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL |
433 | clear_uie(rtc); | 433 | clear_uie(rtc); |
434 | #endif | 434 | #endif |
435 | rtc_irq_set_state(rtc, NULL, 0); | ||
436 | |||
435 | if (rtc->ops->release) | 437 | if (rtc->ops->release) |
436 | rtc->ops->release(rtc->dev.parent); | 438 | rtc->ops->release(rtc->dev.parent); |
437 | 439 | ||
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 2d8df0b30538..20676cdef4a5 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
@@ -91,7 +91,8 @@ static struct alias_pav_group *_find_group(struct alias_lcu *lcu, | |||
91 | else | 91 | else |
92 | search_unit_addr = uid->base_unit_addr; | 92 | search_unit_addr = uid->base_unit_addr; |
93 | list_for_each_entry(pos, &lcu->grouplist, group) { | 93 | list_for_each_entry(pos, &lcu->grouplist, group) { |
94 | if (pos->uid.base_unit_addr == search_unit_addr) | 94 | if (pos->uid.base_unit_addr == search_unit_addr && |
95 | !strncmp(pos->uid.vduit, uid->vduit, sizeof(uid->vduit))) | ||
95 | return pos; | 96 | return pos; |
96 | }; | 97 | }; |
97 | return NULL; | 98 | return NULL; |
@@ -332,6 +333,7 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, | |||
332 | group->uid.base_unit_addr = uid->real_unit_addr; | 333 | group->uid.base_unit_addr = uid->real_unit_addr; |
333 | else | 334 | else |
334 | group->uid.base_unit_addr = uid->base_unit_addr; | 335 | group->uid.base_unit_addr = uid->base_unit_addr; |
336 | memcpy(group->uid.vduit, uid->vduit, sizeof(uid->vduit)); | ||
335 | INIT_LIST_HEAD(&group->group); | 337 | INIT_LIST_HEAD(&group->group); |
336 | INIT_LIST_HEAD(&group->baselist); | 338 | INIT_LIST_HEAD(&group->baselist); |
337 | INIT_LIST_HEAD(&group->aliaslist); | 339 | INIT_LIST_HEAD(&group->aliaslist); |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index d774e79476fe..cd3335c1c307 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -913,7 +913,8 @@ dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
913 | static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); | 913 | static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); |
914 | 914 | ||
915 | #define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ | 915 | #define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ |
916 | /* SSID */ 4 + 1 + /* unit addr */ 2 + 1) | 916 | /* SSID */ 4 + 1 + /* unit addr */ 2 + 1 +\ |
917 | /* vduit */ 32 + 1) | ||
917 | 918 | ||
918 | static ssize_t | 919 | static ssize_t |
919 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) | 920 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) |
@@ -945,8 +946,17 @@ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
945 | sprintf(ua_string, "%02x", uid->real_unit_addr); | 946 | sprintf(ua_string, "%02x", uid->real_unit_addr); |
946 | break; | 947 | break; |
947 | } | 948 | } |
948 | snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s", | 949 | if (strlen(uid->vduit) > 0) |
949 | uid->vendor, uid->serial, uid->ssid, ua_string); | 950 | snprintf(uid_string, sizeof(uid_string), |
951 | "%s.%s.%04x.%s.%s", | ||
952 | uid->vendor, uid->serial, | ||
953 | uid->ssid, ua_string, | ||
954 | uid->vduit); | ||
955 | else | ||
956 | snprintf(uid_string, sizeof(uid_string), | ||
957 | "%s.%s.%04x.%s", | ||
958 | uid->vendor, uid->serial, | ||
959 | uid->ssid, ua_string); | ||
950 | spin_unlock(&dasd_devmap_lock); | 960 | spin_unlock(&dasd_devmap_lock); |
951 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); | 961 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); |
952 | } | 962 | } |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 3590fdb5b2fd..773b3fe275b2 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -313,8 +313,8 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk, | |||
313 | memset(pfxdata, 0, sizeof(*pfxdata)); | 313 | memset(pfxdata, 0, sizeof(*pfxdata)); |
314 | /* prefix data */ | 314 | /* prefix data */ |
315 | pfxdata->format = 0; | 315 | pfxdata->format = 0; |
316 | pfxdata->base_address = basepriv->conf_data.ned1.unit_addr; | 316 | pfxdata->base_address = basepriv->ned->unit_addr; |
317 | pfxdata->base_lss = basepriv->conf_data.ned1.ID; | 317 | pfxdata->base_lss = basepriv->ned->ID; |
318 | pfxdata->validity.define_extend = 1; | 318 | pfxdata->validity.define_extend = 1; |
319 | 319 | ||
320 | /* private uid is kept up to date, conf_data may be outdated */ | 320 | /* private uid is kept up to date, conf_data may be outdated */ |
@@ -536,36 +536,40 @@ dasd_eckd_cdl_reclen(int recid) | |||
536 | /* | 536 | /* |
537 | * Generate device unique id that specifies the physical device. | 537 | * Generate device unique id that specifies the physical device. |
538 | */ | 538 | */ |
539 | static int | 539 | static int dasd_eckd_generate_uid(struct dasd_device *device, |
540 | dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) | 540 | struct dasd_uid *uid) |
541 | { | 541 | { |
542 | struct dasd_eckd_private *private; | 542 | struct dasd_eckd_private *private; |
543 | struct dasd_eckd_confdata *confdata; | 543 | int count; |
544 | 544 | ||
545 | private = (struct dasd_eckd_private *) device->private; | 545 | private = (struct dasd_eckd_private *) device->private; |
546 | if (!private) | 546 | if (!private) |
547 | return -ENODEV; | 547 | return -ENODEV; |
548 | confdata = &private->conf_data; | 548 | if (!private->ned || !private->gneq) |
549 | if (!confdata) | ||
550 | return -ENODEV; | 549 | return -ENODEV; |
551 | 550 | ||
552 | memset(uid, 0, sizeof(struct dasd_uid)); | 551 | memset(uid, 0, sizeof(struct dasd_uid)); |
553 | memcpy(uid->vendor, confdata->ned1.HDA_manufacturer, | 552 | memcpy(uid->vendor, private->ned->HDA_manufacturer, |
554 | sizeof(uid->vendor) - 1); | 553 | sizeof(uid->vendor) - 1); |
555 | EBCASC(uid->vendor, sizeof(uid->vendor) - 1); | 554 | EBCASC(uid->vendor, sizeof(uid->vendor) - 1); |
556 | memcpy(uid->serial, confdata->ned1.HDA_location, | 555 | memcpy(uid->serial, private->ned->HDA_location, |
557 | sizeof(uid->serial) - 1); | 556 | sizeof(uid->serial) - 1); |
558 | EBCASC(uid->serial, sizeof(uid->serial) - 1); | 557 | EBCASC(uid->serial, sizeof(uid->serial) - 1); |
559 | uid->ssid = confdata->neq.subsystemID; | 558 | uid->ssid = private->gneq->subsystemID; |
560 | uid->real_unit_addr = confdata->ned1.unit_addr; | 559 | uid->real_unit_addr = private->ned->unit_addr;; |
561 | if (confdata->ned2.sneq.flags == 0x40 && | 560 | if (private->sneq) { |
562 | confdata->ned2.sneq.format == 0x0001) { | 561 | uid->type = private->sneq->sua_flags; |
563 | uid->type = confdata->ned2.sneq.sua_flags; | ||
564 | if (uid->type == UA_BASE_PAV_ALIAS) | 562 | if (uid->type == UA_BASE_PAV_ALIAS) |
565 | uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr; | 563 | uid->base_unit_addr = private->sneq->base_unit_addr; |
566 | } else { | 564 | } else { |
567 | uid->type = UA_BASE_DEVICE; | 565 | uid->type = UA_BASE_DEVICE; |
568 | } | 566 | } |
567 | if (private->vdsneq) { | ||
568 | for (count = 0; count < 16; count++) { | ||
569 | sprintf(uid->vduit+2*count, "%02x", | ||
570 | private->vdsneq->uit[count]); | ||
571 | } | ||
572 | } | ||
569 | return 0; | 573 | return 0; |
570 | } | 574 | } |
571 | 575 | ||
@@ -623,6 +627,15 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, | |||
623 | ret = -ENOMEM; | 627 | ret = -ENOMEM; |
624 | goto out_error; | 628 | goto out_error; |
625 | } | 629 | } |
630 | |||
631 | /* | ||
632 | * buffer has to start with EBCDIC "V1.0" to show | ||
633 | * support for virtual device SNEQ | ||
634 | */ | ||
635 | rcd_buf[0] = 0xE5; | ||
636 | rcd_buf[1] = 0xF1; | ||
637 | rcd_buf[2] = 0x4B; | ||
638 | rcd_buf[3] = 0xF0; | ||
626 | cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); | 639 | cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); |
627 | if (IS_ERR(cqr)) { | 640 | if (IS_ERR(cqr)) { |
628 | ret = PTR_ERR(cqr); | 641 | ret = PTR_ERR(cqr); |
@@ -646,8 +659,62 @@ out_error: | |||
646 | return ret; | 659 | return ret; |
647 | } | 660 | } |
648 | 661 | ||
649 | static int | 662 | static int dasd_eckd_identify_conf_parts(struct dasd_eckd_private *private) |
650 | dasd_eckd_read_conf(struct dasd_device *device) | 663 | { |
664 | |||
665 | struct dasd_sneq *sneq; | ||
666 | int i, count; | ||
667 | |||
668 | private->ned = NULL; | ||
669 | private->sneq = NULL; | ||
670 | private->vdsneq = NULL; | ||
671 | private->gneq = NULL; | ||
672 | count = private->conf_len / sizeof(struct dasd_sneq); | ||
673 | sneq = (struct dasd_sneq *)private->conf_data; | ||
674 | for (i = 0; i < count; ++i) { | ||
675 | if (sneq->flags.identifier == 1 && sneq->format == 1) | ||
676 | private->sneq = sneq; | ||
677 | else if (sneq->flags.identifier == 1 && sneq->format == 4) | ||
678 | private->vdsneq = (struct vd_sneq *)sneq; | ||
679 | else if (sneq->flags.identifier == 2) | ||
680 | private->gneq = (struct dasd_gneq *)sneq; | ||
681 | else if (sneq->flags.identifier == 3 && sneq->res1 == 1) | ||
682 | private->ned = (struct dasd_ned *)sneq; | ||
683 | sneq++; | ||
684 | } | ||
685 | if (!private->ned || !private->gneq) { | ||
686 | private->ned = NULL; | ||
687 | private->sneq = NULL; | ||
688 | private->vdsneq = NULL; | ||
689 | private->gneq = NULL; | ||
690 | return -EINVAL; | ||
691 | } | ||
692 | return 0; | ||
693 | |||
694 | }; | ||
695 | |||
696 | static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len) | ||
697 | { | ||
698 | struct dasd_gneq *gneq; | ||
699 | int i, count, found; | ||
700 | |||
701 | count = conf_len / sizeof(*gneq); | ||
702 | gneq = (struct dasd_gneq *)conf_data; | ||
703 | found = 0; | ||
704 | for (i = 0; i < count; ++i) { | ||
705 | if (gneq->flags.identifier == 2) { | ||
706 | found = 1; | ||
707 | break; | ||
708 | } | ||
709 | gneq++; | ||
710 | } | ||
711 | if (found) | ||
712 | return ((char *)gneq)[18] & 0x07; | ||
713 | else | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static int dasd_eckd_read_conf(struct dasd_device *device) | ||
651 | { | 718 | { |
652 | void *conf_data; | 719 | void *conf_data; |
653 | int conf_len, conf_data_saved; | 720 | int conf_len, conf_data_saved; |
@@ -661,7 +728,6 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
661 | path_data->opm = ccw_device_get_path_mask(device->cdev); | 728 | path_data->opm = ccw_device_get_path_mask(device->cdev); |
662 | lpm = 0x80; | 729 | lpm = 0x80; |
663 | conf_data_saved = 0; | 730 | conf_data_saved = 0; |
664 | |||
665 | /* get configuration data per operational path */ | 731 | /* get configuration data per operational path */ |
666 | for (lpm = 0x80; lpm; lpm>>= 1) { | 732 | for (lpm = 0x80; lpm; lpm>>= 1) { |
667 | if (lpm & path_data->opm){ | 733 | if (lpm & path_data->opm){ |
@@ -678,22 +744,20 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
678 | "data retrieved"); | 744 | "data retrieved"); |
679 | continue; /* no error */ | 745 | continue; /* no error */ |
680 | } | 746 | } |
681 | if (conf_len != sizeof(struct dasd_eckd_confdata)) { | ||
682 | MESSAGE(KERN_WARNING, | ||
683 | "sizes of configuration data mismatch" | ||
684 | "%d (read) vs %ld (expected)", | ||
685 | conf_len, | ||
686 | sizeof(struct dasd_eckd_confdata)); | ||
687 | kfree(conf_data); | ||
688 | continue; /* no error */ | ||
689 | } | ||
690 | /* save first valid configuration data */ | 747 | /* save first valid configuration data */ |
691 | if (!conf_data_saved){ | 748 | if (!conf_data_saved) { |
692 | memcpy(&private->conf_data, conf_data, | 749 | kfree(private->conf_data); |
693 | sizeof(struct dasd_eckd_confdata)); | 750 | private->conf_data = conf_data; |
751 | private->conf_len = conf_len; | ||
752 | if (dasd_eckd_identify_conf_parts(private)) { | ||
753 | private->conf_data = NULL; | ||
754 | private->conf_len = 0; | ||
755 | kfree(conf_data); | ||
756 | continue; | ||
757 | } | ||
694 | conf_data_saved++; | 758 | conf_data_saved++; |
695 | } | 759 | } |
696 | switch (((char *)conf_data)[242] & 0x07){ | 760 | switch (dasd_eckd_path_access(conf_data, conf_len)) { |
697 | case 0x02: | 761 | case 0x02: |
698 | path_data->npm |= lpm; | 762 | path_data->npm |= lpm; |
699 | break; | 763 | break; |
@@ -701,7 +765,8 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
701 | path_data->ppm |= lpm; | 765 | path_data->ppm |= lpm; |
702 | break; | 766 | break; |
703 | } | 767 | } |
704 | kfree(conf_data); | 768 | if (conf_data != private->conf_data) |
769 | kfree(conf_data); | ||
705 | } | 770 | } |
706 | } | 771 | } |
707 | return 0; | 772 | return 0; |
@@ -952,6 +1017,7 @@ out_err2: | |||
952 | dasd_free_block(device->block); | 1017 | dasd_free_block(device->block); |
953 | device->block = NULL; | 1018 | device->block = NULL; |
954 | out_err1: | 1019 | out_err1: |
1020 | kfree(private->conf_data); | ||
955 | kfree(device->private); | 1021 | kfree(device->private); |
956 | device->private = NULL; | 1022 | device->private = NULL; |
957 | return rc; | 1023 | return rc; |
@@ -959,7 +1025,17 @@ out_err1: | |||
959 | 1025 | ||
960 | static void dasd_eckd_uncheck_device(struct dasd_device *device) | 1026 | static void dasd_eckd_uncheck_device(struct dasd_device *device) |
961 | { | 1027 | { |
1028 | struct dasd_eckd_private *private; | ||
1029 | |||
1030 | private = (struct dasd_eckd_private *) device->private; | ||
962 | dasd_alias_disconnect_device_from_lcu(device); | 1031 | dasd_alias_disconnect_device_from_lcu(device); |
1032 | private->ned = NULL; | ||
1033 | private->sneq = NULL; | ||
1034 | private->vdsneq = NULL; | ||
1035 | private->gneq = NULL; | ||
1036 | private->conf_len = 0; | ||
1037 | kfree(private->conf_data); | ||
1038 | private->conf_data = NULL; | ||
963 | } | 1039 | } |
964 | 1040 | ||
965 | static struct dasd_ccw_req * | 1041 | static struct dasd_ccw_req * |
@@ -1746,9 +1822,10 @@ dasd_eckd_fill_info(struct dasd_device * device, | |||
1746 | info->characteristics_size = sizeof(struct dasd_eckd_characteristics); | 1822 | info->characteristics_size = sizeof(struct dasd_eckd_characteristics); |
1747 | memcpy(info->characteristics, &private->rdc_data, | 1823 | memcpy(info->characteristics, &private->rdc_data, |
1748 | sizeof(struct dasd_eckd_characteristics)); | 1824 | sizeof(struct dasd_eckd_characteristics)); |
1749 | info->confdata_size = sizeof(struct dasd_eckd_confdata); | 1825 | info->confdata_size = min((unsigned long)private->conf_len, |
1750 | memcpy(info->configuration_data, &private->conf_data, | 1826 | sizeof(info->configuration_data)); |
1751 | sizeof(struct dasd_eckd_confdata)); | 1827 | memcpy(info->configuration_data, private->conf_data, |
1828 | info->confdata_size); | ||
1752 | return 0; | 1829 | return 0; |
1753 | } | 1830 | } |
1754 | 1831 | ||
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index fc2509c939bc..4bf0aa5112c1 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h | |||
@@ -231,133 +231,62 @@ struct dasd_eckd_characteristics { | |||
231 | __u8 reserved3[10]; | 231 | __u8 reserved3[10]; |
232 | } __attribute__ ((packed)); | 232 | } __attribute__ ((packed)); |
233 | 233 | ||
234 | struct dasd_eckd_confdata { | 234 | /* elements of the configuration data */ |
235 | struct dasd_ned { | ||
235 | struct { | 236 | struct { |
236 | struct { | 237 | __u8 identifier:2; |
237 | unsigned char identifier:2; | 238 | __u8 token_id:1; |
238 | unsigned char token_id:1; | 239 | __u8 sno_valid:1; |
239 | unsigned char sno_valid:1; | 240 | __u8 subst_sno:1; |
240 | unsigned char subst_sno:1; | 241 | __u8 recNED:1; |
241 | unsigned char recNED:1; | 242 | __u8 emuNED:1; |
242 | unsigned char emuNED:1; | 243 | __u8 reserved:1; |
243 | unsigned char reserved:1; | 244 | } __attribute__ ((packed)) flags; |
244 | } __attribute__ ((packed)) flags; | 245 | __u8 descriptor; |
245 | __u8 descriptor; | 246 | __u8 dev_class; |
246 | __u8 dev_class; | 247 | __u8 reserved; |
247 | __u8 reserved; | 248 | __u8 dev_type[6]; |
248 | unsigned char dev_type[6]; | 249 | __u8 dev_model[3]; |
249 | unsigned char dev_model[3]; | 250 | __u8 HDA_manufacturer[3]; |
250 | unsigned char HDA_manufacturer[3]; | 251 | __u8 HDA_location[2]; |
251 | unsigned char HDA_location[2]; | 252 | __u8 HDA_seqno[12]; |
252 | unsigned char HDA_seqno[12]; | 253 | __u8 ID; |
253 | __u8 ID; | 254 | __u8 unit_addr; |
254 | __u8 unit_addr; | 255 | } __attribute__ ((packed)); |
255 | } __attribute__ ((packed)) ned1; | 256 | |
256 | union { | 257 | struct dasd_sneq { |
257 | struct { | ||
258 | struct { | ||
259 | unsigned char identifier:2; | ||
260 | unsigned char token_id:1; | ||
261 | unsigned char sno_valid:1; | ||
262 | unsigned char subst_sno:1; | ||
263 | unsigned char recNED:1; | ||
264 | unsigned char emuNED:1; | ||
265 | unsigned char reserved:1; | ||
266 | } __attribute__ ((packed)) flags; | ||
267 | __u8 descriptor; | ||
268 | __u8 reserved[2]; | ||
269 | unsigned char dev_type[6]; | ||
270 | unsigned char dev_model[3]; | ||
271 | unsigned char DASD_manufacturer[3]; | ||
272 | unsigned char DASD_location[2]; | ||
273 | unsigned char DASD_seqno[12]; | ||
274 | __u16 ID; | ||
275 | } __attribute__ ((packed)) ned; | ||
276 | struct { | ||
277 | unsigned char flags; /* byte 0 */ | ||
278 | unsigned char res1; /* byte 1 */ | ||
279 | __u16 format; /* byte 2-3 */ | ||
280 | unsigned char res2[4]; /* byte 4-7 */ | ||
281 | unsigned char sua_flags; /* byte 8 */ | ||
282 | __u8 base_unit_addr; /* byte 9 */ | ||
283 | unsigned char res3[22]; /* byte 10-31 */ | ||
284 | } __attribute__ ((packed)) sneq; | ||
285 | } __attribute__ ((packed)) ned2; | ||
286 | struct { | 258 | struct { |
287 | struct { | 259 | __u8 identifier:2; |
288 | unsigned char identifier:2; | 260 | __u8 reserved:6; |
289 | unsigned char token_id:1; | 261 | } __attribute__ ((packed)) flags; |
290 | unsigned char sno_valid:1; | 262 | __u8 res1; |
291 | unsigned char subst_sno:1; | 263 | __u16 format; |
292 | unsigned char recNED:1; | 264 | __u8 res2[4]; /* byte 4- 7 */ |
293 | unsigned char emuNED:1; | 265 | __u8 sua_flags; /* byte 8 */ |
294 | unsigned char reserved:1; | 266 | __u8 base_unit_addr; /* byte 9 */ |
295 | } __attribute__ ((packed)) flags; | 267 | __u8 res3[22]; /* byte 10-31 */ |
296 | __u8 descriptor; | 268 | } __attribute__ ((packed)); |
297 | __u8 reserved[2]; | 269 | |
298 | unsigned char cont_type[6]; | 270 | struct vd_sneq { |
299 | unsigned char cont_model[3]; | ||
300 | unsigned char cont_manufacturer[3]; | ||
301 | unsigned char cont_location[2]; | ||
302 | unsigned char cont_seqno[12]; | ||
303 | __u16 ID; | ||
304 | } __attribute__ ((packed)) ned3; | ||
305 | struct { | 271 | struct { |
306 | struct { | 272 | __u8 identifier:2; |
307 | unsigned char identifier:2; | 273 | __u8 reserved:6; |
308 | unsigned char token_id:1; | 274 | } __attribute__ ((packed)) flags; |
309 | unsigned char sno_valid:1; | 275 | __u8 res1; |
310 | unsigned char subst_sno:1; | 276 | __u16 format; |
311 | unsigned char recNED:1; | 277 | __u8 res2[4]; /* byte 4- 7 */ |
312 | unsigned char emuNED:1; | 278 | __u8 uit[16]; /* byte 8-23 */ |
313 | unsigned char reserved:1; | 279 | __u8 res3[8]; /* byte 24-31 */ |
314 | } __attribute__ ((packed)) flags; | 280 | } __attribute__ ((packed)); |
315 | __u8 descriptor; | 281 | |
316 | __u8 reserved[2]; | 282 | struct dasd_gneq { |
317 | unsigned char cont_type[6]; | ||
318 | unsigned char empty[3]; | ||
319 | unsigned char cont_manufacturer[3]; | ||
320 | unsigned char cont_location[2]; | ||
321 | unsigned char cont_seqno[12]; | ||
322 | __u16 ID; | ||
323 | } __attribute__ ((packed)) ned4; | ||
324 | unsigned char ned5[32]; | ||
325 | unsigned char ned6[32]; | ||
326 | unsigned char ned7[32]; | ||
327 | struct { | 283 | struct { |
328 | struct { | 284 | __u8 identifier:2; |
329 | unsigned char identifier:2; | 285 | __u8 reserved:6; |
330 | unsigned char reserved:6; | 286 | } __attribute__ ((packed)) flags; |
331 | } __attribute__ ((packed)) flags; | 287 | __u8 reserved[7]; |
332 | __u8 selector; | 288 | __u16 subsystemID; |
333 | __u16 interfaceID; | 289 | __u8 reserved2[22]; |
334 | __u32 reserved; | ||
335 | __u16 subsystemID; | ||
336 | struct { | ||
337 | unsigned char sp0:1; | ||
338 | unsigned char sp1:1; | ||
339 | unsigned char reserved:5; | ||
340 | unsigned char scluster:1; | ||
341 | } __attribute__ ((packed)) spathID; | ||
342 | __u8 unit_address; | ||
343 | __u8 dev_ID; | ||
344 | __u8 dev_address; | ||
345 | __u8 adapterID; | ||
346 | __u16 link_address; | ||
347 | struct { | ||
348 | unsigned char parallel:1; | ||
349 | unsigned char escon:1; | ||
350 | unsigned char reserved:1; | ||
351 | unsigned char ficon:1; | ||
352 | unsigned char reserved2:4; | ||
353 | } __attribute__ ((packed)) protocol_type; | ||
354 | struct { | ||
355 | unsigned char PID_in_236:1; | ||
356 | unsigned char reserved:7; | ||
357 | } __attribute__ ((packed)) format_flags; | ||
358 | __u8 log_dev_address; | ||
359 | unsigned char reserved2[12]; | ||
360 | } __attribute__ ((packed)) neq; | ||
361 | } __attribute__ ((packed)); | 290 | } __attribute__ ((packed)); |
362 | 291 | ||
363 | struct dasd_eckd_path { | 292 | struct dasd_eckd_path { |
@@ -463,7 +392,14 @@ struct alias_pav_group { | |||
463 | 392 | ||
464 | struct dasd_eckd_private { | 393 | struct dasd_eckd_private { |
465 | struct dasd_eckd_characteristics rdc_data; | 394 | struct dasd_eckd_characteristics rdc_data; |
466 | struct dasd_eckd_confdata conf_data; | 395 | u8 *conf_data; |
396 | int conf_len; | ||
397 | /* pointers to specific parts in the conf_data */ | ||
398 | struct dasd_ned *ned; | ||
399 | struct dasd_sneq *sneq; | ||
400 | struct vd_sneq *vdsneq; | ||
401 | struct dasd_gneq *gneq; | ||
402 | |||
467 | struct dasd_eckd_path path_data; | 403 | struct dasd_eckd_path path_data; |
468 | struct eckd_count count_area[5]; | 404 | struct eckd_count count_area[5]; |
469 | int init_cqr_status; | 405 | int init_cqr_status; |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index fb2f931cf844..31ecaa4a40e4 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -307,6 +307,7 @@ struct dasd_uid { | |||
307 | __u16 ssid; | 307 | __u16 ssid; |
308 | __u8 real_unit_addr; | 308 | __u8 real_unit_addr; |
309 | __u8 base_unit_addr; | 309 | __u8 base_unit_addr; |
310 | char vduit[33]; | ||
310 | }; | 311 | }; |
311 | 312 | ||
312 | /* | 313 | /* |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 3c8b25e6c345..1fd8f2193ed8 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
@@ -399,6 +399,7 @@ sclp_tod_from_jiffies(unsigned long jiffies) | |||
399 | void | 399 | void |
400 | sclp_sync_wait(void) | 400 | sclp_sync_wait(void) |
401 | { | 401 | { |
402 | unsigned long long old_tick; | ||
402 | unsigned long flags; | 403 | unsigned long flags; |
403 | unsigned long cr0, cr0_sync; | 404 | unsigned long cr0, cr0_sync; |
404 | u64 timeout; | 405 | u64 timeout; |
@@ -419,11 +420,12 @@ sclp_sync_wait(void) | |||
419 | if (!irq_context) | 420 | if (!irq_context) |
420 | local_bh_disable(); | 421 | local_bh_disable(); |
421 | /* Enable service-signal interruption, disable timer interrupts */ | 422 | /* Enable service-signal interruption, disable timer interrupts */ |
423 | old_tick = local_tick_disable(); | ||
422 | trace_hardirqs_on(); | 424 | trace_hardirqs_on(); |
423 | __ctl_store(cr0, 0, 0); | 425 | __ctl_store(cr0, 0, 0); |
424 | cr0_sync = cr0; | 426 | cr0_sync = cr0; |
427 | cr0_sync &= 0xffff00a0; | ||
425 | cr0_sync |= 0x00000200; | 428 | cr0_sync |= 0x00000200; |
426 | cr0_sync &= 0xFFFFF3AC; | ||
427 | __ctl_load(cr0_sync, 0, 0); | 429 | __ctl_load(cr0_sync, 0, 0); |
428 | __raw_local_irq_stosm(0x01); | 430 | __raw_local_irq_stosm(0x01); |
429 | /* Loop until driver state indicates finished request */ | 431 | /* Loop until driver state indicates finished request */ |
@@ -439,9 +441,9 @@ sclp_sync_wait(void) | |||
439 | __ctl_load(cr0, 0, 0); | 441 | __ctl_load(cr0, 0, 0); |
440 | if (!irq_context) | 442 | if (!irq_context) |
441 | _local_bh_enable(); | 443 | _local_bh_enable(); |
444 | local_tick_enable(old_tick); | ||
442 | local_irq_restore(flags); | 445 | local_irq_restore(flags); |
443 | } | 446 | } |
444 | |||
445 | EXPORT_SYMBOL(sclp_sync_wait); | 447 | EXPORT_SYMBOL(sclp_sync_wait); |
446 | 448 | ||
447 | /* Dispatch changes in send and receive mask to registered listeners. */ | 449 | /* Dispatch changes in send and receive mask to registered listeners. */ |
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 0c2b77493db4..eb5f1b8bc57f 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c | |||
@@ -427,6 +427,8 @@ static int sclp_mem_notifier(struct notifier_block *nb, | |||
427 | sclp_attach_storage(id); | 427 | sclp_attach_storage(id); |
428 | switch (action) { | 428 | switch (action) { |
429 | case MEM_ONLINE: | 429 | case MEM_ONLINE: |
430 | case MEM_GOING_OFFLINE: | ||
431 | case MEM_CANCEL_OFFLINE: | ||
430 | break; | 432 | break; |
431 | case MEM_GOING_ONLINE: | 433 | case MEM_GOING_ONLINE: |
432 | rc = sclp_mem_change_state(start, size, 1); | 434 | rc = sclp_mem_change_state(start, size, 1); |
@@ -434,6 +436,9 @@ static int sclp_mem_notifier(struct notifier_block *nb, | |||
434 | case MEM_CANCEL_ONLINE: | 436 | case MEM_CANCEL_ONLINE: |
435 | sclp_mem_change_state(start, size, 0); | 437 | sclp_mem_change_state(start, size, 0); |
436 | break; | 438 | break; |
439 | case MEM_OFFLINE: | ||
440 | sclp_mem_change_state(start, size, 0); | ||
441 | break; | ||
437 | default: | 442 | default: |
438 | rc = -EINVAL; | 443 | rc = -EINVAL; |
439 | break; | 444 | break; |
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index fff4ff485d9b..4cebd6ee6d27 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
9 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
10 | #include <linux/cpu.h> | 10 | #include <linux/cpu.h> |
11 | #include <linux/kthread.h> | ||
12 | #include <linux/sysdev.h> | 11 | #include <linux/sysdev.h> |
13 | #include <linux/workqueue.h> | 12 | #include <linux/workqueue.h> |
14 | #include <asm/smp.h> | 13 | #include <asm/smp.h> |
@@ -41,19 +40,9 @@ static void sclp_cpu_capability_notify(struct work_struct *work) | |||
41 | put_online_cpus(); | 40 | put_online_cpus(); |
42 | } | 41 | } |
43 | 42 | ||
44 | static int sclp_cpu_kthread(void *data) | ||
45 | { | ||
46 | smp_rescan_cpus(); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void __ref sclp_cpu_change_notify(struct work_struct *work) | 43 | static void __ref sclp_cpu_change_notify(struct work_struct *work) |
51 | { | 44 | { |
52 | /* Can't call smp_rescan_cpus() from workqueue context since it may | 45 | smp_rescan_cpus(); |
53 | * deadlock in case of cpu hotplug. So we have to create a kernel | ||
54 | * thread in order to call it. | ||
55 | */ | ||
56 | kthread_run(sclp_cpu_kthread, NULL, "cpu_rescan"); | ||
57 | } | 46 | } |
58 | 47 | ||
59 | static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) | 48 | static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) |
diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index ef7bc0a125ef..cf8f24a4b5eb 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 5 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/slab.h> | 8 | #include <linux/vmalloc.h> |
9 | #include <linux/bitops.h> | 9 | #include <linux/bitops.h> |
10 | #include "idset.h" | 10 | #include "idset.h" |
11 | #include "css.h" | 11 | #include "css.h" |
@@ -25,18 +25,18 @@ static struct idset *idset_new(int num_ssid, int num_id) | |||
25 | { | 25 | { |
26 | struct idset *set; | 26 | struct idset *set; |
27 | 27 | ||
28 | set = kzalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id), | 28 | set = vmalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id)); |
29 | GFP_KERNEL); | ||
30 | if (set) { | 29 | if (set) { |
31 | set->num_ssid = num_ssid; | 30 | set->num_ssid = num_ssid; |
32 | set->num_id = num_id; | 31 | set->num_id = num_id; |
32 | memset(set->bitmap, 0, bitmap_size(num_ssid, num_id)); | ||
33 | } | 33 | } |
34 | return set; | 34 | return set; |
35 | } | 35 | } |
36 | 36 | ||
37 | void idset_free(struct idset *set) | 37 | void idset_free(struct idset *set) |
38 | { | 38 | { |
39 | kfree(set); | 39 | vfree(set); |
40 | } | 40 | } |
41 | 41 | ||
42 | void idset_clear(struct idset *set) | 42 | void idset_clear(struct idset *set) |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index d10c73cc1688..d15648514a0f 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -1355,7 +1355,7 @@ int qdio_allocate(struct qdio_initialize *init_data) | |||
1355 | goto out_rel; | 1355 | goto out_rel; |
1356 | 1356 | ||
1357 | /* qdr is used in ccw1.cda which is u32 */ | 1357 | /* qdr is used in ccw1.cda which is u32 */ |
1358 | irq_ptr->qdr = kzalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA); | 1358 | irq_ptr->qdr = (struct qdr *) get_zeroed_page(GFP_KERNEL | GFP_DMA); |
1359 | if (!irq_ptr->qdr) | 1359 | if (!irq_ptr->qdr) |
1360 | goto out_rel; | 1360 | goto out_rel; |
1361 | WARN_ON((unsigned long)irq_ptr->qdr & 0xfff); | 1361 | WARN_ON((unsigned long)irq_ptr->qdr & 0xfff); |
diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c index ea01b85b1cc9..ec5c4a414235 100644 --- a/drivers/s390/cio/qdio_perf.c +++ b/drivers/s390/cio/qdio_perf.c | |||
@@ -142,7 +142,7 @@ int __init qdio_setup_perf_stats(void) | |||
142 | return 0; | 142 | return 0; |
143 | } | 143 | } |
144 | 144 | ||
145 | void __exit qdio_remove_perf_stats(void) | 145 | void qdio_remove_perf_stats(void) |
146 | { | 146 | { |
147 | #ifdef CONFIG_PROC_FS | 147 | #ifdef CONFIG_PROC_FS |
148 | remove_proc_entry("qdio_perf", NULL); | 148 | remove_proc_entry("qdio_perf", NULL); |
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index f0923a8aceda..1bd2a208db28 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c | |||
@@ -325,7 +325,7 @@ void qdio_release_memory(struct qdio_irq *irq_ptr) | |||
325 | kmem_cache_free(qdio_q_cache, q); | 325 | kmem_cache_free(qdio_q_cache, q); |
326 | } | 326 | } |
327 | } | 327 | } |
328 | kfree(irq_ptr->qdr); | 328 | free_page((unsigned long) irq_ptr->qdr); |
329 | free_page(irq_ptr->chsc_page); | 329 | free_page(irq_ptr->chsc_page); |
330 | free_page((unsigned long) irq_ptr); | 330 | free_page((unsigned long) irq_ptr); |
331 | } | 331 | } |
@@ -515,7 +515,7 @@ int __init qdio_setup_init(void) | |||
515 | return 0; | 515 | return 0; |
516 | } | 516 | } |
517 | 517 | ||
518 | void __exit qdio_setup_exit(void) | 518 | void qdio_setup_exit(void) |
519 | { | 519 | { |
520 | kmem_cache_destroy(qdio_q_cache); | 520 | kmem_cache_destroy(qdio_q_cache); |
521 | } | 521 | } |
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 79954bd6bfa5..292b60da6dc7 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -352,7 +352,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) | |||
352 | return len; | 352 | return len; |
353 | } | 353 | } |
354 | 354 | ||
355 | void s390_virtio_console_init(void) | 355 | void __init s390_virtio_console_init(void) |
356 | { | 356 | { |
357 | virtio_cons_early_init(early_put_chars); | 357 | virtio_cons_early_init(early_put_chars); |
358 | } | 358 | } |
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 1895dbb553cd..80971c21ea1a 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -419,6 +419,7 @@ struct qeth_qdio_out_buffer { | |||
419 | int next_element_to_fill; | 419 | int next_element_to_fill; |
420 | struct sk_buff_head skb_list; | 420 | struct sk_buff_head skb_list; |
421 | struct list_head ctx_list; | 421 | struct list_head ctx_list; |
422 | int is_header[16]; | ||
422 | }; | 423 | }; |
423 | 424 | ||
424 | struct qeth_card; | 425 | struct qeth_card; |
@@ -785,7 +786,7 @@ void qeth_core_remove_osn_attributes(struct device *); | |||
785 | 786 | ||
786 | /* exports for qeth discipline device drivers */ | 787 | /* exports for qeth discipline device drivers */ |
787 | extern struct qeth_card_list_struct qeth_core_card_list; | 788 | extern struct qeth_card_list_struct qeth_core_card_list; |
788 | 789 | extern struct kmem_cache *qeth_core_header_cache; | |
789 | extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS]; | 790 | extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS]; |
790 | 791 | ||
791 | void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); | 792 | void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); |
@@ -843,7 +844,7 @@ int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); | |||
843 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); | 844 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); |
844 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, | 845 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, |
845 | struct sk_buff *, struct qeth_hdr *, int, | 846 | struct sk_buff *, struct qeth_hdr *, int, |
846 | struct qeth_eddp_context *); | 847 | struct qeth_eddp_context *, int, int); |
847 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, | 848 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, |
848 | struct sk_buff *, struct qeth_hdr *, | 849 | struct sk_buff *, struct qeth_hdr *, |
849 | int, struct qeth_eddp_context *); | 850 | int, struct qeth_eddp_context *); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index cebb25e36e82..bd420d1b9a0d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -19,8 +19,8 @@ | |||
19 | #include <linux/mii.h> | 19 | #include <linux/mii.h> |
20 | #include <linux/kthread.h> | 20 | #include <linux/kthread.h> |
21 | 21 | ||
22 | #include <asm-s390/ebcdic.h> | 22 | #include <asm/ebcdic.h> |
23 | #include <asm-s390/io.h> | 23 | #include <asm/io.h> |
24 | #include <asm/s390_rdev.h> | 24 | #include <asm/s390_rdev.h> |
25 | 25 | ||
26 | #include "qeth_core.h" | 26 | #include "qeth_core.h" |
@@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(qeth_dbf); | |||
48 | 48 | ||
49 | struct qeth_card_list_struct qeth_core_card_list; | 49 | struct qeth_card_list_struct qeth_core_card_list; |
50 | EXPORT_SYMBOL_GPL(qeth_core_card_list); | 50 | EXPORT_SYMBOL_GPL(qeth_core_card_list); |
51 | struct kmem_cache *qeth_core_header_cache; | ||
52 | EXPORT_SYMBOL_GPL(qeth_core_header_cache); | ||
51 | 53 | ||
52 | static struct device *qeth_core_root_dev; | 54 | static struct device *qeth_core_root_dev; |
53 | static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY; | 55 | static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY; |
@@ -933,6 +935,10 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, | |||
933 | } | 935 | } |
934 | qeth_eddp_buf_release_contexts(buf); | 936 | qeth_eddp_buf_release_contexts(buf); |
935 | for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { | 937 | for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { |
938 | if (buf->buffer->element[i].addr && buf->is_header[i]) | ||
939 | kmem_cache_free(qeth_core_header_cache, | ||
940 | buf->buffer->element[i].addr); | ||
941 | buf->is_header[i] = 0; | ||
936 | buf->buffer->element[i].length = 0; | 942 | buf->buffer->element[i].length = 0; |
937 | buf->buffer->element[i].addr = NULL; | 943 | buf->buffer->element[i].addr = NULL; |
938 | buf->buffer->element[i].flags = 0; | 944 | buf->buffer->element[i].flags = 0; |
@@ -3002,8 +3008,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
3002 | if (skb_shinfo(skb)->nr_frags > 0) | 3008 | if (skb_shinfo(skb)->nr_frags > 0) |
3003 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); | 3009 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); |
3004 | if (elements_needed == 0) | 3010 | if (elements_needed == 0) |
3005 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) | 3011 | elements_needed = 1 + (((((unsigned long) skb->data) % |
3006 | + skb->len) >> PAGE_SHIFT); | 3012 | PAGE_SIZE) + skb->len) >> PAGE_SHIFT); |
3007 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { | 3013 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { |
3008 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " | 3014 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " |
3009 | "(Number=%d / Length=%d). Discarded.\n", | 3015 | "(Number=%d / Length=%d). Discarded.\n", |
@@ -3015,7 +3021,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
3015 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); | 3021 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); |
3016 | 3022 | ||
3017 | static inline void __qeth_fill_buffer(struct sk_buff *skb, | 3023 | static inline void __qeth_fill_buffer(struct sk_buff *skb, |
3018 | struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill) | 3024 | struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill, |
3025 | int offset) | ||
3019 | { | 3026 | { |
3020 | int length = skb->len; | 3027 | int length = skb->len; |
3021 | int length_here; | 3028 | int length_here; |
@@ -3027,6 +3034,11 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, | |||
3027 | data = skb->data; | 3034 | data = skb->data; |
3028 | first_lap = (is_tso == 0 ? 1 : 0); | 3035 | first_lap = (is_tso == 0 ? 1 : 0); |
3029 | 3036 | ||
3037 | if (offset >= 0) { | ||
3038 | data = skb->data + offset; | ||
3039 | first_lap = 0; | ||
3040 | } | ||
3041 | |||
3030 | while (length > 0) { | 3042 | while (length > 0) { |
3031 | /* length_here is the remaining amount of data in this page */ | 3043 | /* length_here is the remaining amount of data in this page */ |
3032 | length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); | 3044 | length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); |
@@ -3058,22 +3070,22 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, | |||
3058 | } | 3070 | } |
3059 | 3071 | ||
3060 | static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | 3072 | static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, |
3061 | struct qeth_qdio_out_buffer *buf, struct sk_buff *skb) | 3073 | struct qeth_qdio_out_buffer *buf, struct sk_buff *skb, |
3074 | struct qeth_hdr *hdr, int offset, int hd_len) | ||
3062 | { | 3075 | { |
3063 | struct qdio_buffer *buffer; | 3076 | struct qdio_buffer *buffer; |
3064 | struct qeth_hdr_tso *hdr; | ||
3065 | int flush_cnt = 0, hdr_len, large_send = 0; | 3077 | int flush_cnt = 0, hdr_len, large_send = 0; |
3066 | 3078 | ||
3067 | buffer = buf->buffer; | 3079 | buffer = buf->buffer; |
3068 | atomic_inc(&skb->users); | 3080 | atomic_inc(&skb->users); |
3069 | skb_queue_tail(&buf->skb_list, skb); | 3081 | skb_queue_tail(&buf->skb_list, skb); |
3070 | 3082 | ||
3071 | hdr = (struct qeth_hdr_tso *) skb->data; | ||
3072 | /*check first on TSO ....*/ | 3083 | /*check first on TSO ....*/ |
3073 | if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) { | 3084 | if (hdr->hdr.l3.id == QETH_HEADER_TYPE_TSO) { |
3074 | int element = buf->next_element_to_fill; | 3085 | int element = buf->next_element_to_fill; |
3075 | 3086 | ||
3076 | hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len; | 3087 | hdr_len = sizeof(struct qeth_hdr_tso) + |
3088 | ((struct qeth_hdr_tso *)hdr)->ext.dg_hdr_len; | ||
3077 | /*fill first buffer entry only with header information */ | 3089 | /*fill first buffer entry only with header information */ |
3078 | buffer->element[element].addr = skb->data; | 3090 | buffer->element[element].addr = skb->data; |
3079 | buffer->element[element].length = hdr_len; | 3091 | buffer->element[element].length = hdr_len; |
@@ -3083,9 +3095,20 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | |||
3083 | skb->len -= hdr_len; | 3095 | skb->len -= hdr_len; |
3084 | large_send = 1; | 3096 | large_send = 1; |
3085 | } | 3097 | } |
3098 | |||
3099 | if (offset >= 0) { | ||
3100 | int element = buf->next_element_to_fill; | ||
3101 | buffer->element[element].addr = hdr; | ||
3102 | buffer->element[element].length = sizeof(struct qeth_hdr) + | ||
3103 | hd_len; | ||
3104 | buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG; | ||
3105 | buf->is_header[element] = 1; | ||
3106 | buf->next_element_to_fill++; | ||
3107 | } | ||
3108 | |||
3086 | if (skb_shinfo(skb)->nr_frags == 0) | 3109 | if (skb_shinfo(skb)->nr_frags == 0) |
3087 | __qeth_fill_buffer(skb, buffer, large_send, | 3110 | __qeth_fill_buffer(skb, buffer, large_send, |
3088 | (int *)&buf->next_element_to_fill); | 3111 | (int *)&buf->next_element_to_fill, offset); |
3089 | else | 3112 | else |
3090 | __qeth_fill_buffer_frag(skb, buffer, large_send, | 3113 | __qeth_fill_buffer_frag(skb, buffer, large_send, |
3091 | (int *)&buf->next_element_to_fill); | 3114 | (int *)&buf->next_element_to_fill); |
@@ -3115,7 +3138,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | |||
3115 | int qeth_do_send_packet_fast(struct qeth_card *card, | 3138 | int qeth_do_send_packet_fast(struct qeth_card *card, |
3116 | struct qeth_qdio_out_q *queue, struct sk_buff *skb, | 3139 | struct qeth_qdio_out_q *queue, struct sk_buff *skb, |
3117 | struct qeth_hdr *hdr, int elements_needed, | 3140 | struct qeth_hdr *hdr, int elements_needed, |
3118 | struct qeth_eddp_context *ctx) | 3141 | struct qeth_eddp_context *ctx, int offset, int hd_len) |
3119 | { | 3142 | { |
3120 | struct qeth_qdio_out_buffer *buffer; | 3143 | struct qeth_qdio_out_buffer *buffer; |
3121 | int buffers_needed = 0; | 3144 | int buffers_needed = 0; |
@@ -3148,7 +3171,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card, | |||
3148 | } | 3171 | } |
3149 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | 3172 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); |
3150 | if (ctx == NULL) { | 3173 | if (ctx == NULL) { |
3151 | qeth_fill_buffer(queue, buffer, skb); | 3174 | qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); |
3152 | qeth_flush_buffers(queue, index, 1); | 3175 | qeth_flush_buffers(queue, index, 1); |
3153 | } else { | 3176 | } else { |
3154 | flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index); | 3177 | flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index); |
@@ -3224,7 +3247,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
3224 | } | 3247 | } |
3225 | } | 3248 | } |
3226 | if (ctx == NULL) | 3249 | if (ctx == NULL) |
3227 | tmp = qeth_fill_buffer(queue, buffer, skb); | 3250 | tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0); |
3228 | else { | 3251 | else { |
3229 | tmp = qeth_eddp_fill_buffer(queue, ctx, | 3252 | tmp = qeth_eddp_fill_buffer(queue, ctx, |
3230 | queue->next_buf_to_fill); | 3253 | queue->next_buf_to_fill); |
@@ -4443,8 +4466,17 @@ static int __init qeth_core_init(void) | |||
4443 | rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; | 4466 | rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; |
4444 | if (rc) | 4467 | if (rc) |
4445 | goto register_err; | 4468 | goto register_err; |
4446 | return 0; | ||
4447 | 4469 | ||
4470 | qeth_core_header_cache = kmem_cache_create("qeth_hdr", | ||
4471 | sizeof(struct qeth_hdr) + ETH_HLEN, 64, 0, NULL); | ||
4472 | if (!qeth_core_header_cache) { | ||
4473 | rc = -ENOMEM; | ||
4474 | goto slab_err; | ||
4475 | } | ||
4476 | |||
4477 | return 0; | ||
4478 | slab_err: | ||
4479 | s390_root_dev_unregister(qeth_core_root_dev); | ||
4448 | register_err: | 4480 | register_err: |
4449 | driver_remove_file(&qeth_core_ccwgroup_driver.driver, | 4481 | driver_remove_file(&qeth_core_ccwgroup_driver.driver, |
4450 | &driver_attr_group); | 4482 | &driver_attr_group); |
@@ -4466,6 +4498,7 @@ static void __exit qeth_core_exit(void) | |||
4466 | &driver_attr_group); | 4498 | &driver_attr_group); |
4467 | ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); | 4499 | ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); |
4468 | ccw_driver_unregister(&qeth_ccw_driver); | 4500 | ccw_driver_unregister(&qeth_ccw_driver); |
4501 | kmem_cache_destroy(qeth_core_header_cache); | ||
4469 | qeth_unregister_dbf_views(); | 4502 | qeth_unregister_dbf_views(); |
4470 | PRINT_INFO("core functions removed\n"); | 4503 | PRINT_INFO("core functions removed\n"); |
4471 | } | 4504 | } |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index a8b069cd9a4c..b3cee032f578 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -243,8 +243,7 @@ static void qeth_l2_get_packet_type(struct qeth_card *card, | |||
243 | static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | 243 | static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, |
244 | struct sk_buff *skb, int ipv, int cast_type) | 244 | struct sk_buff *skb, int ipv, int cast_type) |
245 | { | 245 | { |
246 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)((skb->data) + | 246 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); |
247 | QETH_HEADER_SIZE); | ||
248 | 247 | ||
249 | memset(hdr, 0, sizeof(struct qeth_hdr)); | 248 | memset(hdr, 0, sizeof(struct qeth_hdr)); |
250 | hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; | 249 | hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; |
@@ -621,6 +620,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
621 | int tx_bytes = skb->len; | 620 | int tx_bytes = skb->len; |
622 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; | 621 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; |
623 | struct qeth_eddp_context *ctx = NULL; | 622 | struct qeth_eddp_context *ctx = NULL; |
623 | int data_offset = -1; | ||
624 | int elements_needed = 0; | ||
625 | int hd_len = 0; | ||
624 | 626 | ||
625 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { | 627 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { |
626 | card->stats.tx_carrier_errors++; | 628 | card->stats.tx_carrier_errors++; |
@@ -643,13 +645,32 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
643 | if (card->info.type == QETH_CARD_TYPE_OSN) | 645 | if (card->info.type == QETH_CARD_TYPE_OSN) |
644 | hdr = (struct qeth_hdr *)skb->data; | 646 | hdr = (struct qeth_hdr *)skb->data; |
645 | else { | 647 | else { |
646 | /* create a clone with writeable headroom */ | 648 | if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && |
647 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr)); | 649 | (skb_shinfo(skb)->nr_frags == 0)) { |
648 | if (!new_skb) | 650 | new_skb = skb; |
649 | goto tx_drop; | 651 | data_offset = ETH_HLEN; |
650 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 652 | hd_len = ETH_HLEN; |
653 | hdr = kmem_cache_alloc(qeth_core_header_cache, | ||
654 | GFP_ATOMIC); | ||
655 | if (!hdr) | ||
656 | goto tx_drop; | ||
657 | elements_needed++; | ||
658 | skb_reset_mac_header(new_skb); | ||
659 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | ||
660 | hdr->hdr.l2.pkt_length = new_skb->len; | ||
661 | memcpy(((char *)hdr) + sizeof(struct qeth_hdr), | ||
662 | skb_mac_header(new_skb), ETH_HLEN); | ||
663 | } else { | ||
664 | /* create a clone with writeable headroom */ | ||
665 | new_skb = skb_realloc_headroom(skb, | ||
666 | sizeof(struct qeth_hdr)); | ||
667 | if (!new_skb) | ||
668 | goto tx_drop; | ||
669 | hdr = (struct qeth_hdr *)skb_push(new_skb, | ||
651 | sizeof(struct qeth_hdr)); | 670 | sizeof(struct qeth_hdr)); |
652 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | 671 | skb_set_mac_header(new_skb, sizeof(struct qeth_hdr)); |
672 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | ||
673 | } | ||
653 | } | 674 | } |
654 | 675 | ||
655 | if (large_send == QETH_LARGE_SEND_EDDP) { | 676 | if (large_send == QETH_LARGE_SEND_EDDP) { |
@@ -660,9 +681,13 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
660 | goto tx_drop; | 681 | goto tx_drop; |
661 | } | 682 | } |
662 | } else { | 683 | } else { |
663 | elements = qeth_get_elements_no(card, (void *)hdr, new_skb, 0); | 684 | elements = qeth_get_elements_no(card, (void *)hdr, new_skb, |
664 | if (!elements) | 685 | elements_needed); |
686 | if (!elements) { | ||
687 | if (data_offset >= 0) | ||
688 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
665 | goto tx_drop; | 689 | goto tx_drop; |
690 | } | ||
666 | } | 691 | } |
667 | 692 | ||
668 | if ((large_send == QETH_LARGE_SEND_NO) && | 693 | if ((large_send == QETH_LARGE_SEND_NO) && |
@@ -674,7 +699,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
674 | elements, ctx); | 699 | elements, ctx); |
675 | else | 700 | else |
676 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, | 701 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
677 | elements, ctx); | 702 | elements, ctx, data_offset, hd_len); |
678 | if (!rc) { | 703 | if (!rc) { |
679 | card->stats.tx_packets++; | 704 | card->stats.tx_packets++; |
680 | card->stats.tx_bytes += tx_bytes; | 705 | card->stats.tx_bytes += tx_bytes; |
@@ -701,6 +726,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
701 | if (ctx != NULL) | 726 | if (ctx != NULL) |
702 | qeth_eddp_put_context(ctx); | 727 | qeth_eddp_put_context(ctx); |
703 | 728 | ||
729 | if (data_offset >= 0) | ||
730 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
731 | |||
704 | if (rc == -EBUSY) { | 732 | if (rc == -EBUSY) { |
705 | if (new_skb != skb) | 733 | if (new_skb != skb) |
706 | dev_kfree_skb_any(new_skb); | 734 | dev_kfree_skb_any(new_skb); |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 3e1d13857350..dd72c3c20165 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -2604,6 +2604,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2604 | int tx_bytes = skb->len; | 2604 | int tx_bytes = skb->len; |
2605 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; | 2605 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; |
2606 | struct qeth_eddp_context *ctx = NULL; | 2606 | struct qeth_eddp_context *ctx = NULL; |
2607 | int data_offset = -1; | ||
2607 | 2608 | ||
2608 | if ((card->info.type == QETH_CARD_TYPE_IQD) && | 2609 | if ((card->info.type == QETH_CARD_TYPE_IQD) && |
2609 | (skb->protocol != htons(ETH_P_IPV6)) && | 2610 | (skb->protocol != htons(ETH_P_IPV6)) && |
@@ -2624,14 +2625,28 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2624 | card->perf_stats.outbound_start_time = qeth_get_micros(); | 2625 | card->perf_stats.outbound_start_time = qeth_get_micros(); |
2625 | } | 2626 | } |
2626 | 2627 | ||
2627 | /* create a clone with writeable headroom */ | 2628 | if (skb_is_gso(skb)) |
2628 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) + | 2629 | large_send = card->options.large_send; |
2629 | VLAN_HLEN); | 2630 | |
2630 | if (!new_skb) | 2631 | if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && |
2631 | goto tx_drop; | 2632 | (skb_shinfo(skb)->nr_frags == 0)) { |
2633 | new_skb = skb; | ||
2634 | data_offset = ETH_HLEN; | ||
2635 | hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); | ||
2636 | if (!hdr) | ||
2637 | goto tx_drop; | ||
2638 | elements_needed++; | ||
2639 | } else { | ||
2640 | /* create a clone with writeable headroom */ | ||
2641 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) | ||
2642 | + VLAN_HLEN); | ||
2643 | if (!new_skb) | ||
2644 | goto tx_drop; | ||
2645 | } | ||
2632 | 2646 | ||
2633 | if (card->info.type == QETH_CARD_TYPE_IQD) { | 2647 | if (card->info.type == QETH_CARD_TYPE_IQD) { |
2634 | skb_pull(new_skb, ETH_HLEN); | 2648 | if (data_offset < 0) |
2649 | skb_pull(new_skb, ETH_HLEN); | ||
2635 | } else { | 2650 | } else { |
2636 | if (new_skb->protocol == htons(ETH_P_IP)) { | 2651 | if (new_skb->protocol == htons(ETH_P_IP)) { |
2637 | if (card->dev->type == ARPHRD_IEEE802_TR) | 2652 | if (card->dev->type == ARPHRD_IEEE802_TR) |
@@ -2657,9 +2672,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2657 | 2672 | ||
2658 | netif_stop_queue(dev); | 2673 | netif_stop_queue(dev); |
2659 | 2674 | ||
2660 | if (skb_is_gso(new_skb)) | ||
2661 | large_send = card->options.large_send; | ||
2662 | |||
2663 | /* fix hardware limitation: as long as we do not have sbal | 2675 | /* fix hardware limitation: as long as we do not have sbal |
2664 | * chaining we can not send long frag lists so we temporary | 2676 | * chaining we can not send long frag lists so we temporary |
2665 | * switch to EDDP | 2677 | * switch to EDDP |
@@ -2677,9 +2689,16 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2677 | qeth_tso_fill_header(card, hdr, new_skb); | 2689 | qeth_tso_fill_header(card, hdr, new_skb); |
2678 | elements_needed++; | 2690 | elements_needed++; |
2679 | } else { | 2691 | } else { |
2680 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 2692 | if (data_offset < 0) { |
2693 | hdr = (struct qeth_hdr *)skb_push(new_skb, | ||
2681 | sizeof(struct qeth_hdr)); | 2694 | sizeof(struct qeth_hdr)); |
2682 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); | 2695 | qeth_l3_fill_header(card, hdr, new_skb, ipv, |
2696 | cast_type); | ||
2697 | } else { | ||
2698 | qeth_l3_fill_header(card, hdr, new_skb, ipv, | ||
2699 | cast_type); | ||
2700 | hdr->hdr.l3.length = new_skb->len - data_offset; | ||
2701 | } | ||
2683 | } | 2702 | } |
2684 | 2703 | ||
2685 | if (large_send == QETH_LARGE_SEND_EDDP) { | 2704 | if (large_send == QETH_LARGE_SEND_EDDP) { |
@@ -2695,8 +2714,11 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2695 | } else { | 2714 | } else { |
2696 | int elems = qeth_get_elements_no(card, (void *)hdr, new_skb, | 2715 | int elems = qeth_get_elements_no(card, (void *)hdr, new_skb, |
2697 | elements_needed); | 2716 | elements_needed); |
2698 | if (!elems) | 2717 | if (!elems) { |
2718 | if (data_offset >= 0) | ||
2719 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
2699 | goto tx_drop; | 2720 | goto tx_drop; |
2721 | } | ||
2700 | elements_needed += elems; | 2722 | elements_needed += elems; |
2701 | } | 2723 | } |
2702 | 2724 | ||
@@ -2709,7 +2731,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2709 | elements_needed, ctx); | 2731 | elements_needed, ctx); |
2710 | else | 2732 | else |
2711 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, | 2733 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
2712 | elements_needed, ctx); | 2734 | elements_needed, ctx, data_offset, 0); |
2713 | 2735 | ||
2714 | if (!rc) { | 2736 | if (!rc) { |
2715 | card->stats.tx_packets++; | 2737 | card->stats.tx_packets++; |
@@ -2737,6 +2759,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2737 | if (ctx != NULL) | 2759 | if (ctx != NULL) |
2738 | qeth_eddp_put_context(ctx); | 2760 | qeth_eddp_put_context(ctx); |
2739 | 2761 | ||
2762 | if (data_offset >= 0) | ||
2763 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
2764 | |||
2740 | if (rc == -EBUSY) { | 2765 | if (rc == -EBUSY) { |
2741 | if (new_skb != skb) | 2766 | if (new_skb != skb) |
2742 | dev_kfree_skb_any(new_skb); | 2767 | dev_kfree_skb_any(new_skb); |
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 7a4409ab30ea..a319a20ed440 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include <linux/kthread.h> | 9 | #include <linux/kthread.h> |
10 | #include <linux/vmalloc.h> | 10 | #include <linux/vmalloc.h> |
11 | #include <linux/delay.h> | ||
11 | 12 | ||
12 | static int qla24xx_vport_disable(struct fc_vport *, bool); | 13 | static int qla24xx_vport_disable(struct fc_vport *, bool); |
13 | 14 | ||
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index a97f1ae11f78..342e12fb1c25 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -1885,7 +1885,7 @@ static int serial8250_startup(struct uart_port *port) | |||
1885 | * the interrupt is enabled. Delays are necessary to | 1885 | * the interrupt is enabled. Delays are necessary to |
1886 | * allow register changes to become visible. | 1886 | * allow register changes to become visible. |
1887 | */ | 1887 | */ |
1888 | spin_lock(&up->port.lock); | 1888 | spin_lock_irqsave(&up->port.lock, flags); |
1889 | if (up->port.flags & UPF_SHARE_IRQ) | 1889 | if (up->port.flags & UPF_SHARE_IRQ) |
1890 | disable_irq_nosync(up->port.irq); | 1890 | disable_irq_nosync(up->port.irq); |
1891 | 1891 | ||
@@ -1901,7 +1901,7 @@ static int serial8250_startup(struct uart_port *port) | |||
1901 | 1901 | ||
1902 | if (up->port.flags & UPF_SHARE_IRQ) | 1902 | if (up->port.flags & UPF_SHARE_IRQ) |
1903 | enable_irq(up->port.irq); | 1903 | enable_irq(up->port.irq); |
1904 | spin_unlock(&up->port.lock); | 1904 | spin_unlock_irqrestore(&up->port.lock, flags); |
1905 | 1905 | ||
1906 | /* | 1906 | /* |
1907 | * If the interrupt is not reasserted, setup a timer to | 1907 | * If the interrupt is not reasserted, setup a timer to |
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 3a0bbbe17aa3..7e7383e890d8 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile | |||
@@ -42,7 +42,6 @@ obj-$(CONFIG_SERIAL_68328) += 68328serial.o | |||
42 | obj-$(CONFIG_SERIAL_68360) += 68360serial.o | 42 | obj-$(CONFIG_SERIAL_68360) += 68360serial.o |
43 | obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o | 43 | obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o |
44 | obj-$(CONFIG_SERIAL_MCF) += mcf.o | 44 | obj-$(CONFIG_SERIAL_MCF) += mcf.o |
45 | obj-$(CONFIG_V850E_UART) += v850e_uart.o | ||
46 | obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o | 45 | obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o |
47 | obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o | 46 | obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o |
48 | obj-$(CONFIG_SERIAL_DZ) += dz.o | 47 | obj-$(CONFIG_SERIAL_DZ) += dz.o |
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 5c76e0ae0582..7274b527a3c1 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h | |||
@@ -50,6 +50,15 @@ | |||
50 | 50 | ||
51 | #define SCC_WAIT_CLOSING 100 | 51 | #define SCC_WAIT_CLOSING 100 |
52 | 52 | ||
53 | #define GPIO_CTS 0 | ||
54 | #define GPIO_RTS 1 | ||
55 | #define GPIO_DCD 2 | ||
56 | #define GPIO_DSR 3 | ||
57 | #define GPIO_DTR 4 | ||
58 | #define GPIO_RI 5 | ||
59 | |||
60 | #define NUM_GPIOS (GPIO_RI+1) | ||
61 | |||
53 | struct uart_cpm_port { | 62 | struct uart_cpm_port { |
54 | struct uart_port port; | 63 | struct uart_port port; |
55 | u16 rx_nrfifos; | 64 | u16 rx_nrfifos; |
@@ -68,6 +77,7 @@ struct uart_cpm_port { | |||
68 | unsigned char *rx_buf; | 77 | unsigned char *rx_buf; |
69 | u32 flags; | 78 | u32 flags; |
70 | void (*set_lineif)(struct uart_cpm_port *); | 79 | void (*set_lineif)(struct uart_cpm_port *); |
80 | struct clk *clk; | ||
71 | u8 brg; | 81 | u8 brg; |
72 | uint dp_addr; | 82 | uint dp_addr; |
73 | void *mem_addr; | 83 | void *mem_addr; |
@@ -82,6 +92,7 @@ struct uart_cpm_port { | |||
82 | int wait_closing; | 92 | int wait_closing; |
83 | /* value to combine with opcode to form cpm command */ | 93 | /* value to combine with opcode to form cpm command */ |
84 | u32 command; | 94 | u32 command; |
95 | int gpios[NUM_GPIOS]; | ||
85 | }; | 96 | }; |
86 | 97 | ||
87 | extern int cpm_uart_nr; | 98 | extern int cpm_uart_nr; |
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index a4f86927a74b..25efca5a7a1f 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c | |||
@@ -43,6 +43,9 @@ | |||
43 | #include <linux/dma-mapping.h> | 43 | #include <linux/dma-mapping.h> |
44 | #include <linux/fs_uart_pd.h> | 44 | #include <linux/fs_uart_pd.h> |
45 | #include <linux/of_platform.h> | 45 | #include <linux/of_platform.h> |
46 | #include <linux/gpio.h> | ||
47 | #include <linux/of_gpio.h> | ||
48 | #include <linux/clk.h> | ||
46 | 49 | ||
47 | #include <asm/io.h> | 50 | #include <asm/io.h> |
48 | #include <asm/irq.h> | 51 | #include <asm/irq.h> |
@@ -96,13 +99,41 @@ static unsigned int cpm_uart_tx_empty(struct uart_port *port) | |||
96 | 99 | ||
97 | static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) | 100 | static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) |
98 | { | 101 | { |
99 | /* Whee. Do nothing. */ | 102 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; |
103 | |||
104 | if (pinfo->gpios[GPIO_RTS] >= 0) | ||
105 | gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS)); | ||
106 | |||
107 | if (pinfo->gpios[GPIO_DTR] >= 0) | ||
108 | gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR)); | ||
100 | } | 109 | } |
101 | 110 | ||
102 | static unsigned int cpm_uart_get_mctrl(struct uart_port *port) | 111 | static unsigned int cpm_uart_get_mctrl(struct uart_port *port) |
103 | { | 112 | { |
104 | /* Whee. Do nothing. */ | 113 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; |
105 | return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; | 114 | unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; |
115 | |||
116 | if (pinfo->gpios[GPIO_CTS] >= 0) { | ||
117 | if (gpio_get_value(pinfo->gpios[GPIO_CTS])) | ||
118 | mctrl &= ~TIOCM_CTS; | ||
119 | } | ||
120 | |||
121 | if (pinfo->gpios[GPIO_DSR] >= 0) { | ||
122 | if (gpio_get_value(pinfo->gpios[GPIO_DSR])) | ||
123 | mctrl &= ~TIOCM_DSR; | ||
124 | } | ||
125 | |||
126 | if (pinfo->gpios[GPIO_DCD] >= 0) { | ||
127 | if (gpio_get_value(pinfo->gpios[GPIO_DCD])) | ||
128 | mctrl &= ~TIOCM_CAR; | ||
129 | } | ||
130 | |||
131 | if (pinfo->gpios[GPIO_RI] >= 0) { | ||
132 | if (!gpio_get_value(pinfo->gpios[GPIO_RI])) | ||
133 | mctrl |= TIOCM_RNG; | ||
134 | } | ||
135 | |||
136 | return mctrl; | ||
106 | } | 137 | } |
107 | 138 | ||
108 | /* | 139 | /* |
@@ -566,7 +597,10 @@ static void cpm_uart_set_termios(struct uart_port *port, | |||
566 | out_be16(&sccp->scc_psmr, (sbits << 12) | scval); | 597 | out_be16(&sccp->scc_psmr, (sbits << 12) | scval); |
567 | } | 598 | } |
568 | 599 | ||
569 | cpm_set_brg(pinfo->brg - 1, baud); | 600 | if (pinfo->clk) |
601 | clk_set_rate(pinfo->clk, baud); | ||
602 | else | ||
603 | cpm_set_brg(pinfo->brg - 1, baud); | ||
570 | spin_unlock_irqrestore(&port->lock, flags); | 604 | spin_unlock_irqrestore(&port->lock, flags); |
571 | } | 605 | } |
572 | 606 | ||
@@ -991,14 +1025,23 @@ static int cpm_uart_init_port(struct device_node *np, | |||
991 | void __iomem *mem, *pram; | 1025 | void __iomem *mem, *pram; |
992 | int len; | 1026 | int len; |
993 | int ret; | 1027 | int ret; |
1028 | int i; | ||
994 | 1029 | ||
995 | data = of_get_property(np, "fsl,cpm-brg", &len); | 1030 | data = of_get_property(np, "clock", NULL); |
996 | if (!data || len != 4) { | 1031 | if (data) { |
997 | printk(KERN_ERR "CPM UART %s has no/invalid " | 1032 | struct clk *clk = clk_get(NULL, (const char*)data); |
998 | "fsl,cpm-brg property.\n", np->name); | 1033 | if (!IS_ERR(clk)) |
999 | return -EINVAL; | 1034 | pinfo->clk = clk; |
1035 | } | ||
1036 | if (!pinfo->clk) { | ||
1037 | data = of_get_property(np, "fsl,cpm-brg", &len); | ||
1038 | if (!data || len != 4) { | ||
1039 | printk(KERN_ERR "CPM UART %s has no/invalid " | ||
1040 | "fsl,cpm-brg property.\n", np->name); | ||
1041 | return -EINVAL; | ||
1042 | } | ||
1043 | pinfo->brg = *data; | ||
1000 | } | 1044 | } |
1001 | pinfo->brg = *data; | ||
1002 | 1045 | ||
1003 | data = of_get_property(np, "fsl,cpm-command", &len); | 1046 | data = of_get_property(np, "fsl,cpm-command", &len); |
1004 | if (!data || len != 4) { | 1047 | if (!data || len != 4) { |
@@ -1050,6 +1093,9 @@ static int cpm_uart_init_port(struct device_node *np, | |||
1050 | goto out_pram; | 1093 | goto out_pram; |
1051 | } | 1094 | } |
1052 | 1095 | ||
1096 | for (i = 0; i < NUM_GPIOS; i++) | ||
1097 | pinfo->gpios[i] = of_get_gpio(np, i); | ||
1098 | |||
1053 | return cpm_uart_request_port(&pinfo->port); | 1099 | return cpm_uart_request_port(&pinfo->port); |
1054 | 1100 | ||
1055 | out_pram: | 1101 | out_pram: |
diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c deleted file mode 100644 index 5acf061b6cd2..000000000000 --- a/drivers/serial/v850e_uart.c +++ /dev/null | |||
@@ -1,548 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/serial/v850e_uart.c -- Serial I/O using V850E on-chip UART or UARTB | ||
3 | * | ||
4 | * Copyright (C) 2001,02,03 NEC Electronics Corporation | ||
5 | * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General | ||
8 | * Public License. See the file COPYING in the main directory of this | ||
9 | * archive for more details. | ||
10 | * | ||
11 | * Written by Miles Bader <miles@gnu.org> | ||
12 | */ | ||
13 | |||
14 | /* This driver supports both the original V850E UART interface (called | ||
15 | merely `UART' in the docs) and the newer `UARTB' interface, which is | ||
16 | roughly a superset of the first one. The selection is made at | ||
17 | configure time -- if CONFIG_V850E_UARTB is defined, then UARTB is | ||
18 | presumed, otherwise the old UART -- as these are on-CPU UARTS, a system | ||
19 | can never have both. | ||
20 | |||
21 | The UARTB interface also has a 16-entry FIFO mode, which is not | ||
22 | yet supported by this driver. */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/console.h> | ||
28 | #include <linux/tty.h> | ||
29 | #include <linux/tty_flip.h> | ||
30 | #include <linux/serial.h> | ||
31 | #include <linux/serial_core.h> | ||
32 | |||
33 | #include <asm/v850e_uart.h> | ||
34 | |||
35 | /* Initial UART state. This may be overridden by machine-dependent headers. */ | ||
36 | #ifndef V850E_UART_INIT_BAUD | ||
37 | #define V850E_UART_INIT_BAUD 115200 | ||
38 | #endif | ||
39 | #ifndef V850E_UART_INIT_CFLAGS | ||
40 | #define V850E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD) | ||
41 | #endif | ||
42 | |||
43 | /* A string used for prefixing printed descriptions; since the same UART | ||
44 | macro is actually used on other chips than the V850E. This must be a | ||
45 | constant string. */ | ||
46 | #ifndef V850E_UART_CHIP_NAME | ||
47 | #define V850E_UART_CHIP_NAME "V850E" | ||
48 | #endif | ||
49 | |||
50 | #define V850E_UART_MINOR_BASE 64 /* First tty minor number */ | ||
51 | |||
52 | |||
53 | /* Low-level UART functions. */ | ||
54 | |||
55 | /* Configure and turn on uart channel CHAN, using the termios `control | ||
56 | modes' bits in CFLAGS, and a baud-rate of BAUD. */ | ||
57 | void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud) | ||
58 | { | ||
59 | int flags; | ||
60 | v850e_uart_speed_t old_speed; | ||
61 | v850e_uart_config_t old_config; | ||
62 | v850e_uart_speed_t new_speed = v850e_uart_calc_speed (baud); | ||
63 | v850e_uart_config_t new_config = v850e_uart_calc_config (cflags); | ||
64 | |||
65 | /* Disable interrupts while we're twiddling the hardware. */ | ||
66 | local_irq_save (flags); | ||
67 | |||
68 | #ifdef V850E_UART_PRE_CONFIGURE | ||
69 | V850E_UART_PRE_CONFIGURE (chan, cflags, baud); | ||
70 | #endif | ||
71 | |||
72 | old_config = V850E_UART_CONFIG (chan); | ||
73 | old_speed = v850e_uart_speed (chan); | ||
74 | |||
75 | if (! v850e_uart_speed_eq (old_speed, new_speed)) { | ||
76 | /* The baud rate has changed. First, disable the UART. */ | ||
77 | V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_FINI; | ||
78 | old_config = 0; /* Force the uart to be re-initialized. */ | ||
79 | |||
80 | /* Reprogram the baud-rate generator. */ | ||
81 | v850e_uart_set_speed (chan, new_speed); | ||
82 | } | ||
83 | |||
84 | if (! (old_config & V850E_UART_CONFIG_ENABLED)) { | ||
85 | /* If we are using the uart for the first time, start by | ||
86 | enabling it, which must be done before turning on any | ||
87 | other bits. */ | ||
88 | V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_INIT; | ||
89 | /* See the initial state. */ | ||
90 | old_config = V850E_UART_CONFIG (chan); | ||
91 | } | ||
92 | |||
93 | if (new_config != old_config) { | ||
94 | /* Which of the TXE/RXE bits we'll temporarily turn off | ||
95 | before changing other control bits. */ | ||
96 | unsigned temp_disable = 0; | ||
97 | /* Which of the TXE/RXE bits will be enabled. */ | ||
98 | unsigned enable = 0; | ||
99 | unsigned changed_bits = new_config ^ old_config; | ||
100 | |||
101 | /* Which of RX/TX will be enabled in the new configuration. */ | ||
102 | if (new_config & V850E_UART_CONFIG_RX_BITS) | ||
103 | enable |= (new_config & V850E_UART_CONFIG_RX_ENABLE); | ||
104 | if (new_config & V850E_UART_CONFIG_TX_BITS) | ||
105 | enable |= (new_config & V850E_UART_CONFIG_TX_ENABLE); | ||
106 | |||
107 | /* Figure out which of RX/TX needs to be disabled; note | ||
108 | that this will only happen if they're not already | ||
109 | disabled. */ | ||
110 | if (changed_bits & V850E_UART_CONFIG_RX_BITS) | ||
111 | temp_disable | ||
112 | |= (old_config & V850E_UART_CONFIG_RX_ENABLE); | ||
113 | if (changed_bits & V850E_UART_CONFIG_TX_BITS) | ||
114 | temp_disable | ||
115 | |= (old_config & V850E_UART_CONFIG_TX_ENABLE); | ||
116 | |||
117 | /* We have to turn off RX and/or TX mode before changing | ||
118 | any associated control bits. */ | ||
119 | if (temp_disable) | ||
120 | V850E_UART_CONFIG (chan) = old_config & ~temp_disable; | ||
121 | |||
122 | /* Write the new control bits, while RX/TX are disabled. */ | ||
123 | if (changed_bits & ~enable) | ||
124 | V850E_UART_CONFIG (chan) = new_config & ~enable; | ||
125 | |||
126 | v850e_uart_config_delay (new_config, new_speed); | ||
127 | |||
128 | /* Write the final version, with enable bits turned on. */ | ||
129 | V850E_UART_CONFIG (chan) = new_config; | ||
130 | } | ||
131 | |||
132 | local_irq_restore (flags); | ||
133 | } | ||
134 | |||
135 | |||
136 | /* Low-level console. */ | ||
137 | |||
138 | #ifdef CONFIG_V850E_UART_CONSOLE | ||
139 | |||
140 | static void v850e_uart_cons_write (struct console *co, | ||
141 | const char *s, unsigned count) | ||
142 | { | ||
143 | if (count > 0) { | ||
144 | unsigned chan = co->index; | ||
145 | unsigned irq = V850E_UART_TX_IRQ (chan); | ||
146 | int irq_was_enabled, irq_was_pending, flags; | ||
147 | |||
148 | /* We don't want to get `transmission completed' | ||
149 | interrupts, since we're busy-waiting, so we disable them | ||
150 | while sending (we don't disable interrupts entirely | ||
151 | because sending over a serial line is really slow). We | ||
152 | save the status of the tx interrupt and restore it when | ||
153 | we're done so that using printk doesn't interfere with | ||
154 | normal serial transmission (other than interleaving the | ||
155 | output, of course!). This should work correctly even if | ||
156 | this function is interrupted and the interrupt printks | ||
157 | something. */ | ||
158 | |||
159 | /* Disable interrupts while fiddling with tx interrupt. */ | ||
160 | local_irq_save (flags); | ||
161 | /* Get current tx interrupt status. */ | ||
162 | irq_was_enabled = v850e_intc_irq_enabled (irq); | ||
163 | irq_was_pending = v850e_intc_irq_pending (irq); | ||
164 | /* Disable tx interrupt if necessary. */ | ||
165 | if (irq_was_enabled) | ||
166 | v850e_intc_disable_irq (irq); | ||
167 | /* Turn interrupts back on. */ | ||
168 | local_irq_restore (flags); | ||
169 | |||
170 | /* Send characters. */ | ||
171 | while (count > 0) { | ||
172 | int ch = *s++; | ||
173 | |||
174 | if (ch == '\n') { | ||
175 | /* We don't have the benefit of a tty | ||
176 | driver, so translate NL into CR LF. */ | ||
177 | v850e_uart_wait_for_xmit_ok (chan); | ||
178 | v850e_uart_putc (chan, '\r'); | ||
179 | } | ||
180 | |||
181 | v850e_uart_wait_for_xmit_ok (chan); | ||
182 | v850e_uart_putc (chan, ch); | ||
183 | |||
184 | count--; | ||
185 | } | ||
186 | |||
187 | /* Restore saved tx interrupt status. */ | ||
188 | if (irq_was_enabled) { | ||
189 | /* Wait for the last character we sent to be | ||
190 | completely transmitted (as we'll get an | ||
191 | interrupt interrupt at that point). */ | ||
192 | v850e_uart_wait_for_xmit_done (chan); | ||
193 | /* Clear pending interrupts received due | ||
194 | to our transmission, unless there was already | ||
195 | one pending, in which case we want the | ||
196 | handler to be called. */ | ||
197 | if (! irq_was_pending) | ||
198 | v850e_intc_clear_pending_irq (irq); | ||
199 | /* ... and then turn back on handling. */ | ||
200 | v850e_intc_enable_irq (irq); | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | |||
205 | extern struct uart_driver v850e_uart_driver; | ||
206 | static struct console v850e_uart_cons = | ||
207 | { | ||
208 | .name = "ttyS", | ||
209 | .write = v850e_uart_cons_write, | ||
210 | .device = uart_console_device, | ||
211 | .flags = CON_PRINTBUFFER, | ||
212 | .cflag = V850E_UART_INIT_CFLAGS, | ||
213 | .index = -1, | ||
214 | .data = &v850e_uart_driver, | ||
215 | }; | ||
216 | |||
217 | void v850e_uart_cons_init (unsigned chan) | ||
218 | { | ||
219 | v850e_uart_configure (chan, V850E_UART_INIT_CFLAGS, | ||
220 | V850E_UART_INIT_BAUD); | ||
221 | v850e_uart_cons.index = chan; | ||
222 | register_console (&v850e_uart_cons); | ||
223 | printk ("Console: %s on-chip UART channel %d\n", | ||
224 | V850E_UART_CHIP_NAME, chan); | ||
225 | } | ||
226 | |||
227 | /* This is what the init code actually calls. */ | ||
228 | static int v850e_uart_console_init (void) | ||
229 | { | ||
230 | v850e_uart_cons_init (V850E_UART_CONSOLE_CHANNEL); | ||
231 | return 0; | ||
232 | } | ||
233 | console_initcall(v850e_uart_console_init); | ||
234 | |||
235 | #define V850E_UART_CONSOLE &v850e_uart_cons | ||
236 | |||
237 | #else /* !CONFIG_V850E_UART_CONSOLE */ | ||
238 | #define V850E_UART_CONSOLE 0 | ||
239 | #endif /* CONFIG_V850E_UART_CONSOLE */ | ||
240 | |||
241 | /* TX/RX interrupt handlers. */ | ||
242 | |||
243 | static void v850e_uart_stop_tx (struct uart_port *port); | ||
244 | |||
245 | void v850e_uart_tx (struct uart_port *port) | ||
246 | { | ||
247 | struct circ_buf *xmit = &port->info->xmit; | ||
248 | int stopped = uart_tx_stopped (port); | ||
249 | |||
250 | if (v850e_uart_xmit_ok (port->line)) { | ||
251 | int tx_ch; | ||
252 | |||
253 | if (port->x_char) { | ||
254 | tx_ch = port->x_char; | ||
255 | port->x_char = 0; | ||
256 | } else if (!uart_circ_empty (xmit) && !stopped) { | ||
257 | tx_ch = xmit->buf[xmit->tail]; | ||
258 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
259 | } else | ||
260 | goto no_xmit; | ||
261 | |||
262 | v850e_uart_putc (port->line, tx_ch); | ||
263 | port->icount.tx++; | ||
264 | |||
265 | if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) | ||
266 | uart_write_wakeup (port); | ||
267 | } | ||
268 | |||
269 | no_xmit: | ||
270 | if (uart_circ_empty (xmit) || stopped) | ||
271 | v850e_uart_stop_tx (port, stopped); | ||
272 | } | ||
273 | |||
274 | static irqreturn_t v850e_uart_tx_irq(int irq, void *data) | ||
275 | { | ||
276 | struct uart_port *port = data; | ||
277 | v850e_uart_tx (port); | ||
278 | return IRQ_HANDLED; | ||
279 | } | ||
280 | |||
281 | static irqreturn_t v850e_uart_rx_irq(int irq, void *data) | ||
282 | { | ||
283 | struct uart_port *port = data; | ||
284 | unsigned ch_stat = TTY_NORMAL; | ||
285 | unsigned ch = v850e_uart_getc (port->line); | ||
286 | unsigned err = v850e_uart_err (port->line); | ||
287 | |||
288 | if (err) { | ||
289 | if (err & V850E_UART_ERR_OVERRUN) { | ||
290 | ch_stat = TTY_OVERRUN; | ||
291 | port->icount.overrun++; | ||
292 | } else if (err & V850E_UART_ERR_FRAME) { | ||
293 | ch_stat = TTY_FRAME; | ||
294 | port->icount.frame++; | ||
295 | } else if (err & V850E_UART_ERR_PARITY) { | ||
296 | ch_stat = TTY_PARITY; | ||
297 | port->icount.parity++; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | port->icount.rx++; | ||
302 | |||
303 | tty_insert_flip_char (port->info->port.tty, ch, ch_stat); | ||
304 | tty_schedule_flip (port->info->port.tty); | ||
305 | |||
306 | return IRQ_HANDLED; | ||
307 | } | ||
308 | |||
309 | |||
310 | /* Control functions for the serial framework. */ | ||
311 | |||
312 | static void v850e_uart_nop (struct uart_port *port) { } | ||
313 | static int v850e_uart_success (struct uart_port *port) { return 0; } | ||
314 | |||
315 | static unsigned v850e_uart_tx_empty (struct uart_port *port) | ||
316 | { | ||
317 | return TIOCSER_TEMT; /* Can't detect. */ | ||
318 | } | ||
319 | |||
320 | static void v850e_uart_set_mctrl (struct uart_port *port, unsigned mctrl) | ||
321 | { | ||
322 | #ifdef V850E_UART_SET_RTS | ||
323 | V850E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS)); | ||
324 | #endif | ||
325 | } | ||
326 | |||
327 | static unsigned v850e_uart_get_mctrl (struct uart_port *port) | ||
328 | { | ||
329 | /* We don't support DCD or DSR, so consider them permanently active. */ | ||
330 | int mctrl = TIOCM_CAR | TIOCM_DSR; | ||
331 | |||
332 | /* We may support CTS. */ | ||
333 | #ifdef V850E_UART_CTS | ||
334 | mctrl |= V850E_UART_CTS(port->line) ? TIOCM_CTS : 0; | ||
335 | #else | ||
336 | mctrl |= TIOCM_CTS; | ||
337 | #endif | ||
338 | |||
339 | return mctrl; | ||
340 | } | ||
341 | |||
342 | static void v850e_uart_start_tx (struct uart_port *port) | ||
343 | { | ||
344 | v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); | ||
345 | v850e_uart_tx (port); | ||
346 | v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line)); | ||
347 | } | ||
348 | |||
349 | static void v850e_uart_stop_tx (struct uart_port *port) | ||
350 | { | ||
351 | v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); | ||
352 | } | ||
353 | |||
354 | static void v850e_uart_start_rx (struct uart_port *port) | ||
355 | { | ||
356 | v850e_intc_enable_irq (V850E_UART_RX_IRQ (port->line)); | ||
357 | } | ||
358 | |||
359 | static void v850e_uart_stop_rx (struct uart_port *port) | ||
360 | { | ||
361 | v850e_intc_disable_irq (V850E_UART_RX_IRQ (port->line)); | ||
362 | } | ||
363 | |||
364 | static void v850e_uart_break_ctl (struct uart_port *port, int break_ctl) | ||
365 | { | ||
366 | /* Umm, do this later. */ | ||
367 | } | ||
368 | |||
369 | static int v850e_uart_startup (struct uart_port *port) | ||
370 | { | ||
371 | int err; | ||
372 | |||
373 | /* Alloc RX irq. */ | ||
374 | err = request_irq (V850E_UART_RX_IRQ (port->line), v850e_uart_rx_irq, | ||
375 | IRQF_DISABLED, "v850e_uart", port); | ||
376 | if (err) | ||
377 | return err; | ||
378 | |||
379 | /* Alloc TX irq. */ | ||
380 | err = request_irq (V850E_UART_TX_IRQ (port->line), v850e_uart_tx_irq, | ||
381 | IRQF_DISABLED, "v850e_uart", port); | ||
382 | if (err) { | ||
383 | free_irq (V850E_UART_RX_IRQ (port->line), port); | ||
384 | return err; | ||
385 | } | ||
386 | |||
387 | v850e_uart_start_rx (port); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static void v850e_uart_shutdown (struct uart_port *port) | ||
393 | { | ||
394 | /* Disable port interrupts. */ | ||
395 | free_irq (V850E_UART_TX_IRQ (port->line), port); | ||
396 | free_irq (V850E_UART_RX_IRQ (port->line), port); | ||
397 | |||
398 | /* Turn off xmit/recv enable bits. */ | ||
399 | V850E_UART_CONFIG (port->line) | ||
400 | &= ~(V850E_UART_CONFIG_TX_ENABLE | ||
401 | | V850E_UART_CONFIG_RX_ENABLE); | ||
402 | /* Then reset the channel. */ | ||
403 | V850E_UART_CONFIG (port->line) = 0; | ||
404 | } | ||
405 | |||
406 | static void | ||
407 | v850e_uart_set_termios (struct uart_port *port, struct ktermios *termios, | ||
408 | struct ktermios *old) | ||
409 | { | ||
410 | unsigned cflags = termios->c_cflag; | ||
411 | |||
412 | /* Restrict flags to legal values. */ | ||
413 | if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8) | ||
414 | /* The new value of CSIZE is invalid, use the old value. */ | ||
415 | cflags = (cflags & ~CSIZE) | ||
416 | | (old ? (old->c_cflag & CSIZE) : CS8); | ||
417 | |||
418 | termios->c_cflag = cflags; | ||
419 | |||
420 | v850e_uart_configure (port->line, cflags, | ||
421 | uart_get_baud_rate (port, termios, old, | ||
422 | v850e_uart_min_baud(), | ||
423 | v850e_uart_max_baud())); | ||
424 | } | ||
425 | |||
426 | static const char *v850e_uart_type (struct uart_port *port) | ||
427 | { | ||
428 | return port->type == PORT_V850E_UART ? "v850e_uart" : 0; | ||
429 | } | ||
430 | |||
431 | static void v850e_uart_config_port (struct uart_port *port, int flags) | ||
432 | { | ||
433 | if (flags & UART_CONFIG_TYPE) | ||
434 | port->type = PORT_V850E_UART; | ||
435 | } | ||
436 | |||
437 | static int | ||
438 | v850e_uart_verify_port (struct uart_port *port, struct serial_struct *ser) | ||
439 | { | ||
440 | if (ser->type != PORT_UNKNOWN && ser->type != PORT_V850E_UART) | ||
441 | return -EINVAL; | ||
442 | if (ser->irq != V850E_UART_TX_IRQ (port->line)) | ||
443 | return -EINVAL; | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static struct uart_ops v850e_uart_ops = { | ||
448 | .tx_empty = v850e_uart_tx_empty, | ||
449 | .get_mctrl = v850e_uart_get_mctrl, | ||
450 | .set_mctrl = v850e_uart_set_mctrl, | ||
451 | .start_tx = v850e_uart_start_tx, | ||
452 | .stop_tx = v850e_uart_stop_tx, | ||
453 | .stop_rx = v850e_uart_stop_rx, | ||
454 | .enable_ms = v850e_uart_nop, | ||
455 | .break_ctl = v850e_uart_break_ctl, | ||
456 | .startup = v850e_uart_startup, | ||
457 | .shutdown = v850e_uart_shutdown, | ||
458 | .set_termios = v850e_uart_set_termios, | ||
459 | .type = v850e_uart_type, | ||
460 | .release_port = v850e_uart_nop, | ||
461 | .request_port = v850e_uart_success, | ||
462 | .config_port = v850e_uart_config_port, | ||
463 | .verify_port = v850e_uart_verify_port, | ||
464 | }; | ||
465 | |||
466 | /* Initialization and cleanup. */ | ||
467 | |||
468 | static struct uart_driver v850e_uart_driver = { | ||
469 | .owner = THIS_MODULE, | ||
470 | .driver_name = "v850e_uart", | ||
471 | .dev_name = "ttyS", | ||
472 | .major = TTY_MAJOR, | ||
473 | .minor = V850E_UART_MINOR_BASE, | ||
474 | .nr = V850E_UART_NUM_CHANNELS, | ||
475 | .cons = V850E_UART_CONSOLE, | ||
476 | }; | ||
477 | |||
478 | |||
479 | static struct uart_port v850e_uart_ports[V850E_UART_NUM_CHANNELS]; | ||
480 | |||
481 | static int __init v850e_uart_init (void) | ||
482 | { | ||
483 | int rval; | ||
484 | |||
485 | printk (KERN_INFO "%s on-chip UART\n", V850E_UART_CHIP_NAME); | ||
486 | |||
487 | rval = uart_register_driver (&v850e_uart_driver); | ||
488 | if (rval == 0) { | ||
489 | unsigned chan; | ||
490 | |||
491 | for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) { | ||
492 | struct uart_port *port = &v850e_uart_ports[chan]; | ||
493 | |||
494 | memset (port, 0, sizeof *port); | ||
495 | |||
496 | port->ops = &v850e_uart_ops; | ||
497 | port->line = chan; | ||
498 | port->iotype = UPIO_MEM; | ||
499 | port->flags = UPF_BOOT_AUTOCONF; | ||
500 | |||
501 | /* We actually use multiple IRQs, but the serial | ||
502 | framework seems to mainly use this for | ||
503 | informational purposes anyway. Here we use the TX | ||
504 | irq. */ | ||
505 | port->irq = V850E_UART_TX_IRQ (chan); | ||
506 | |||
507 | /* The serial framework doesn't really use these | ||
508 | membase/mapbase fields for anything useful, but | ||
509 | it requires that they be something non-zero to | ||
510 | consider the port `valid', and also uses them | ||
511 | for informational purposes. */ | ||
512 | port->membase = (void *)V850E_UART_BASE_ADDR (chan); | ||
513 | port->mapbase = V850E_UART_BASE_ADDR (chan); | ||
514 | |||
515 | /* The framework insists on knowing the uart's master | ||
516 | clock freq, though it doesn't seem to do anything | ||
517 | useful for us with it. We must make it at least | ||
518 | higher than (the maximum baud rate * 16), otherwise | ||
519 | the framework will puke during its internal | ||
520 | calculations, and force the baud rate to be 9600. | ||
521 | To be accurate though, just repeat the calculation | ||
522 | we use when actually setting the speed. */ | ||
523 | port->uartclk = v850e_uart_max_clock() * 16; | ||
524 | |||
525 | uart_add_one_port (&v850e_uart_driver, port); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | return rval; | ||
530 | } | ||
531 | |||
532 | static void __exit v850e_uart_exit (void) | ||
533 | { | ||
534 | unsigned chan; | ||
535 | |||
536 | for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) | ||
537 | uart_remove_one_port (&v850e_uart_driver, | ||
538 | &v850e_uart_ports[chan]); | ||
539 | |||
540 | uart_unregister_driver (&v850e_uart_driver); | ||
541 | } | ||
542 | |||
543 | module_init (v850e_uart_init); | ||
544 | module_exit (v850e_uart_exit); | ||
545 | |||
546 | MODULE_AUTHOR ("Miles Bader"); | ||
547 | MODULE_DESCRIPTION ("NEC " V850E_UART_CHIP_NAME " on-chip UART"); | ||
548 | MODULE_LICENSE ("GPL"); | ||
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index 604e5f0a2d95..25eda71f4bf4 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c | |||
@@ -148,7 +148,6 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, | |||
148 | unsigned rfalarm; | 148 | unsigned rfalarm; |
149 | unsigned send_at_once = MPC52xx_PSC_BUFSIZE; | 149 | unsigned send_at_once = MPC52xx_PSC_BUFSIZE; |
150 | unsigned recv_at_once; | 150 | unsigned recv_at_once; |
151 | unsigned bpw = mps->bits_per_word / 8; | ||
152 | 151 | ||
153 | if (!t->tx_buf && !t->rx_buf && t->len) | 152 | if (!t->tx_buf && !t->rx_buf && t->len) |
154 | return -EINVAL; | 153 | return -EINVAL; |
@@ -164,22 +163,15 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, | |||
164 | } | 163 | } |
165 | 164 | ||
166 | dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once); | 165 | dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once); |
167 | if (tx_buf) { | 166 | for (; send_at_once; sb++, send_at_once--) { |
168 | for (; send_at_once; sb++, send_at_once--) { | 167 | /* set EOF flag before the last word is sent */ |
169 | /* set EOF flag */ | 168 | if (send_at_once == 1) |
170 | if (mps->bits_per_word | 169 | out_8(&psc->ircr2, 0x01); |
171 | && (sb + 1) % bpw == 0) | 170 | |
172 | out_8(&psc->ircr2, 0x01); | 171 | if (tx_buf) |
173 | out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]); | 172 | out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]); |
174 | } | 173 | else |
175 | } else { | ||
176 | for (; send_at_once; sb++, send_at_once--) { | ||
177 | /* set EOF flag */ | ||
178 | if (mps->bits_per_word | ||
179 | && ((sb + 1) % bpw) == 0) | ||
180 | out_8(&psc->ircr2, 0x01); | ||
181 | out_8(&psc->mpc52xx_psc_buffer_8, 0); | 174 | out_8(&psc->mpc52xx_psc_buffer_8, 0); |
182 | } | ||
183 | } | 175 | } |
184 | 176 | ||
185 | 177 | ||
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index 0885cc357a37..1c643c9e1f15 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c | |||
@@ -270,6 +270,7 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev) | |||
270 | /* setup the master state. */ | 270 | /* setup the master state. */ |
271 | 271 | ||
272 | master->num_chipselect = hw->pdata->num_cs; | 272 | master->num_chipselect = hw->pdata->num_cs; |
273 | master->bus_num = pdata->bus_num; | ||
273 | 274 | ||
274 | /* setup the state for the bitbang driver */ | 275 | /* setup the state for the bitbang driver */ |
275 | 276 | ||
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 8da7535c0c70..77b44fb48f0a 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c | |||
@@ -1593,7 +1593,7 @@ static int __init m66592_probe(struct platform_device *pdev) | |||
1593 | 1593 | ||
1594 | m66592->gadget.ops = &m66592_gadget_ops; | 1594 | m66592->gadget.ops = &m66592_gadget_ops; |
1595 | device_initialize(&m66592->gadget.dev); | 1595 | device_initialize(&m66592->gadget.dev); |
1596 | dev_set_name(&m66592->gadget, "gadget"); | 1596 | dev_set_name(&m66592->gadget.dev, "gadget"); |
1597 | m66592->gadget.is_dualspeed = 1; | 1597 | m66592->gadget.is_dualspeed = 1; |
1598 | m66592->gadget.dev.parent = &pdev->dev; | 1598 | m66592->gadget.dev.parent = &pdev->dev; |
1599 | m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; | 1599 | m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; |
diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 5001bd4ef466..38a1e8308c83 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c | |||
@@ -1126,11 +1126,8 @@ static int ark_pci_resume (struct pci_dev* dev) | |||
1126 | acquire_console_sem(); | 1126 | acquire_console_sem(); |
1127 | mutex_lock(&(par->open_lock)); | 1127 | mutex_lock(&(par->open_lock)); |
1128 | 1128 | ||
1129 | if (par->ref_count == 0) { | 1129 | if (par->ref_count == 0) |
1130 | mutex_unlock(&(par->open_lock)); | 1130 | goto fail; |
1131 | release_console_sem(); | ||
1132 | return 0; | ||
1133 | } | ||
1134 | 1131 | ||
1135 | pci_set_power_state(dev, PCI_D0); | 1132 | pci_set_power_state(dev, PCI_D0); |
1136 | pci_restore_state(dev); | 1133 | pci_restore_state(dev); |
@@ -1143,8 +1140,8 @@ static int ark_pci_resume (struct pci_dev* dev) | |||
1143 | arkfb_set_par(info); | 1140 | arkfb_set_par(info); |
1144 | fb_set_suspend(info, 0); | 1141 | fb_set_suspend(info, 0); |
1145 | 1142 | ||
1146 | mutex_unlock(&(par->open_lock)); | ||
1147 | fail: | 1143 | fail: |
1144 | mutex_unlock(&(par->open_lock)); | ||
1148 | release_console_sem(); | 1145 | release_console_sem(); |
1149 | return 0; | 1146 | return 0; |
1150 | } | 1147 | } |
diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index 72d44dbfce82..738694d23889 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c | |||
@@ -92,7 +92,7 @@ static int __devinit platform_lcd_probe(struct platform_device *pdev) | |||
92 | 92 | ||
93 | plcd->us = dev; | 93 | plcd->us = dev; |
94 | plcd->pdata = pdata; | 94 | plcd->pdata = pdata; |
95 | plcd->lcd = lcd_device_register("platform-lcd", dev, | 95 | plcd->lcd = lcd_device_register(dev_name(dev), dev, |
96 | plcd, &platform_lcd_ops); | 96 | plcd, &platform_lcd_ops); |
97 | if (IS_ERR(plcd->lcd)) { | 97 | if (IS_ERR(plcd->lcd)) { |
98 | dev_err(dev, "cannot register lcd device\n"); | 98 | dev_err(dev, "cannot register lcd device\n"); |
@@ -101,6 +101,8 @@ static int __devinit platform_lcd_probe(struct platform_device *pdev) | |||
101 | } | 101 | } |
102 | 102 | ||
103 | platform_set_drvdata(pdev, plcd); | 103 | platform_set_drvdata(pdev, plcd); |
104 | platform_lcd_set_power(plcd->lcd, FB_BLANK_NORMAL); | ||
105 | |||
104 | return 0; | 106 | return 0; |
105 | 107 | ||
106 | err_mem: | 108 | err_mem: |
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index d7822af0e00a..ef7870f5ea08 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/hardware.h> | 24 | #include <asm/hardware.h> |
25 | #include <asm/parisc-device.h> | 25 | #include <asm/parisc-device.h> |
26 | #include <asm/cacheflush.h> | 26 | #include <asm/cacheflush.h> |
27 | #include <asm/grfioctl.h> | ||
27 | 28 | ||
28 | #include "../sticore.h" | 29 | #include "../sticore.h" |
29 | 30 | ||
@@ -725,6 +726,7 @@ static int __devinit sti_read_rom(int wordmode, struct sti_struct *sti, | |||
725 | { | 726 | { |
726 | struct sti_cooked_rom *cooked; | 727 | struct sti_cooked_rom *cooked; |
727 | struct sti_rom *raw = NULL; | 728 | struct sti_rom *raw = NULL; |
729 | unsigned long revno; | ||
728 | 730 | ||
729 | cooked = kmalloc(sizeof *cooked, GFP_KERNEL); | 731 | cooked = kmalloc(sizeof *cooked, GFP_KERNEL); |
730 | if (!cooked) | 732 | if (!cooked) |
@@ -767,9 +769,35 @@ static int __devinit sti_read_rom(int wordmode, struct sti_struct *sti, | |||
767 | sti->graphics_id[1] = raw->graphics_id[1]; | 769 | sti->graphics_id[1] = raw->graphics_id[1]; |
768 | 770 | ||
769 | sti_dump_rom(raw); | 771 | sti_dump_rom(raw); |
770 | 772 | ||
773 | /* check if the ROM routines in this card are compatible */ | ||
774 | if (wordmode || sti->graphics_id[1] != 0x09A02587) | ||
775 | goto ok; | ||
776 | |||
777 | revno = (raw->revno[0] << 8) | raw->revno[1]; | ||
778 | |||
779 | switch (sti->graphics_id[0]) { | ||
780 | case S9000_ID_HCRX: | ||
781 | /* HyperA or HyperB ? */ | ||
782 | if (revno == 0x8408 || revno == 0x840b) | ||
783 | goto msg_not_supported; | ||
784 | break; | ||
785 | case CRT_ID_THUNDER: | ||
786 | if (revno == 0x8509) | ||
787 | goto msg_not_supported; | ||
788 | break; | ||
789 | case CRT_ID_THUNDER2: | ||
790 | if (revno == 0x850c) | ||
791 | goto msg_not_supported; | ||
792 | } | ||
793 | ok: | ||
771 | return 1; | 794 | return 1; |
772 | 795 | ||
796 | msg_not_supported: | ||
797 | printk(KERN_ERR "Sorry, this GSC/STI card is not yet supported.\n"); | ||
798 | printk(KERN_ERR "Please see http://parisc-linux.org/faq/" | ||
799 | "graphics-howto.html for more info.\n"); | ||
800 | /* fall through */ | ||
773 | out_err: | 801 | out_err: |
774 | kfree(raw); | 802 | kfree(raw); |
775 | kfree(cooked); | 803 | kfree(cooked); |
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 2e552d5bbb5d..f89c3cce1e0c 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c | |||
@@ -87,6 +87,8 @@ static int gbe_revision; | |||
87 | static int ypan, ywrap; | 87 | static int ypan, ywrap; |
88 | 88 | ||
89 | static uint32_t pseudo_palette[16]; | 89 | static uint32_t pseudo_palette[16]; |
90 | static uint32_t gbe_cmap[256]; | ||
91 | static int gbe_turned_on; /* 0 turned off, 1 turned on */ | ||
90 | 92 | ||
91 | static char *mode_option __initdata = NULL; | 93 | static char *mode_option __initdata = NULL; |
92 | 94 | ||
@@ -208,6 +210,8 @@ void gbe_turn_off(void) | |||
208 | int i; | 210 | int i; |
209 | unsigned int val, x, y, vpixen_off; | 211 | unsigned int val, x, y, vpixen_off; |
210 | 212 | ||
213 | gbe_turned_on = 0; | ||
214 | |||
211 | /* check if pixel counter is on */ | 215 | /* check if pixel counter is on */ |
212 | val = gbe->vt_xy; | 216 | val = gbe->vt_xy; |
213 | if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1) | 217 | if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1) |
@@ -371,6 +375,22 @@ static void gbe_turn_on(void) | |||
371 | } | 375 | } |
372 | if (i == 10000) | 376 | if (i == 10000) |
373 | printk(KERN_ERR "gbefb: turn on DMA timed out\n"); | 377 | printk(KERN_ERR "gbefb: turn on DMA timed out\n"); |
378 | |||
379 | gbe_turned_on = 1; | ||
380 | } | ||
381 | |||
382 | static void gbe_loadcmap(void) | ||
383 | { | ||
384 | int i, j; | ||
385 | |||
386 | for (i = 0; i < 256; i++) { | ||
387 | for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++) | ||
388 | udelay(10); | ||
389 | if (j == 1000) | ||
390 | printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); | ||
391 | |||
392 | gbe->cmap[i] = gbe_cmap[i]; | ||
393 | } | ||
374 | } | 394 | } |
375 | 395 | ||
376 | /* | 396 | /* |
@@ -382,6 +402,7 @@ static int gbefb_blank(int blank, struct fb_info *info) | |||
382 | switch (blank) { | 402 | switch (blank) { |
383 | case FB_BLANK_UNBLANK: /* unblank */ | 403 | case FB_BLANK_UNBLANK: /* unblank */ |
384 | gbe_turn_on(); | 404 | gbe_turn_on(); |
405 | gbe_loadcmap(); | ||
385 | break; | 406 | break; |
386 | 407 | ||
387 | case FB_BLANK_NORMAL: /* blank */ | 408 | case FB_BLANK_NORMAL: /* blank */ |
@@ -796,16 +817,10 @@ static int gbefb_set_par(struct fb_info *info) | |||
796 | gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8); | 817 | gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8); |
797 | 818 | ||
798 | /* Initialize the color map */ | 819 | /* Initialize the color map */ |
799 | for (i = 0; i < 256; i++) { | 820 | for (i = 0; i < 256; i++) |
800 | int j; | 821 | gbe_cmap[i] = (i << 8) | (i << 16) | (i << 24); |
801 | |||
802 | for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++) | ||
803 | udelay(10); | ||
804 | if (j == 1000) | ||
805 | printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); | ||
806 | 822 | ||
807 | gbe->cmap[i] = (i << 8) | (i << 16) | (i << 24); | 823 | gbe_loadcmap(); |
808 | } | ||
809 | 824 | ||
810 | return 0; | 825 | return 0; |
811 | } | 826 | } |
@@ -855,14 +870,17 @@ static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
855 | blue >>= 8; | 870 | blue >>= 8; |
856 | 871 | ||
857 | if (info->var.bits_per_pixel <= 8) { | 872 | if (info->var.bits_per_pixel <= 8) { |
858 | /* wait for the color map FIFO to have a free entry */ | 873 | gbe_cmap[regno] = (red << 24) | (green << 16) | (blue << 8); |
859 | for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) | 874 | if (gbe_turned_on) { |
860 | udelay(10); | 875 | /* wait for the color map FIFO to have a free entry */ |
861 | if (i == 1000) { | 876 | for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) |
862 | printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); | 877 | udelay(10); |
863 | return 1; | 878 | if (i == 1000) { |
879 | printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); | ||
880 | return 1; | ||
881 | } | ||
882 | gbe->cmap[regno] = gbe_cmap[regno]; | ||
864 | } | 883 | } |
865 | gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); | ||
866 | } else if (regno < 16) { | 884 | } else if (regno < 16) { |
867 | switch (info->var.bits_per_pixel) { | 885 | switch (info->var.bits_per_pixel) { |
868 | case 15: | 886 | case 15: |
diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index 4d0e28c5790b..8d0212da4514 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c | |||
@@ -152,6 +152,7 @@ static int sh7760fb_setcmap(struct fb_cmap *cmap, struct fb_info *info) | |||
152 | col |= ((*g) & 0xff) << 8; | 152 | col |= ((*g) & 0xff) << 8; |
153 | col |= ((*b) & 0xff); | 153 | col |= ((*b) & 0xff); |
154 | col &= SH7760FB_PALETTE_MASK; | 154 | col &= SH7760FB_PALETTE_MASK; |
155 | iowrite32(col, par->base + LDPR(s)); | ||
155 | 156 | ||
156 | if (s < 16) | 157 | if (s < 16) |
157 | ((u32 *) (info->pseudo_palette))[s] = s; | 158 | ((u32 *) (info->pseudo_palette))[s] = s; |
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 536ab11623f0..4a484ee98f8a 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c | |||
@@ -853,11 +853,8 @@ static int vt8623_pci_resume(struct pci_dev* dev) | |||
853 | acquire_console_sem(); | 853 | acquire_console_sem(); |
854 | mutex_lock(&(par->open_lock)); | 854 | mutex_lock(&(par->open_lock)); |
855 | 855 | ||
856 | if (par->ref_count == 0) { | 856 | if (par->ref_count == 0) |
857 | mutex_unlock(&(par->open_lock)); | 857 | goto fail; |
858 | release_console_sem(); | ||
859 | return 0; | ||
860 | } | ||
861 | 858 | ||
862 | pci_set_power_state(dev, PCI_D0); | 859 | pci_set_power_state(dev, PCI_D0); |
863 | pci_restore_state(dev); | 860 | pci_restore_state(dev); |
@@ -870,8 +867,8 @@ static int vt8623_pci_resume(struct pci_dev* dev) | |||
870 | vt8623fb_set_par(info); | 867 | vt8623fb_set_par(info); |
871 | fb_set_suspend(info, 0); | 868 | fb_set_suspend(info, 0); |
872 | 869 | ||
873 | mutex_unlock(&(par->open_lock)); | ||
874 | fail: | 870 | fail: |
871 | mutex_unlock(&(par->open_lock)); | ||
875 | release_console_sem(); | 872 | release_console_sem(); |
876 | 873 | ||
877 | return 0; | 874 | return 0; |
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index eaa3f2a79ff5..ccd6c530782d 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
@@ -420,7 +420,7 @@ static int __devinit detect_cru_service(void) | |||
420 | static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, | 420 | static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, |
421 | void *data) | 421 | void *data) |
422 | { | 422 | { |
423 | static unsigned long rom_pl; | 423 | unsigned long rom_pl; |
424 | static int die_nmi_called; | 424 | static int die_nmi_called; |
425 | 425 | ||
426 | if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) | 426 | if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) |
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 63e2ee63058d..c3e174b35fe6 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c | |||
@@ -705,7 +705,6 @@ void __init bio_integrity_init_slab(void) | |||
705 | bio_integrity_slab = KMEM_CACHE(bio_integrity_payload, | 705 | bio_integrity_slab = KMEM_CACHE(bio_integrity_payload, |
706 | SLAB_HWCACHE_ALIGN|SLAB_PANIC); | 706 | SLAB_HWCACHE_ALIGN|SLAB_PANIC); |
707 | } | 707 | } |
708 | EXPORT_SYMBOL(bio_integrity_init_slab); | ||
709 | 708 | ||
710 | static int __init integrity_init(void) | 709 | static int __init integrity_init(void) |
711 | { | 710 | { |
diff --git a/fs/buffer.c b/fs/buffer.c index f95805019639..4dbe52948e8f 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -580,7 +580,7 @@ EXPORT_SYMBOL(mark_buffer_async_write); | |||
580 | /* | 580 | /* |
581 | * The buffer's backing address_space's private_lock must be held | 581 | * The buffer's backing address_space's private_lock must be held |
582 | */ | 582 | */ |
583 | static inline void __remove_assoc_queue(struct buffer_head *bh) | 583 | static void __remove_assoc_queue(struct buffer_head *bh) |
584 | { | 584 | { |
585 | list_del_init(&bh->b_assoc_buffers); | 585 | list_del_init(&bh->b_assoc_buffers); |
586 | WARN_ON(!bh->b_assoc_map); | 586 | WARN_ON(!bh->b_assoc_map); |
@@ -2096,6 +2096,52 @@ int generic_write_end(struct file *file, struct address_space *mapping, | |||
2096 | EXPORT_SYMBOL(generic_write_end); | 2096 | EXPORT_SYMBOL(generic_write_end); |
2097 | 2097 | ||
2098 | /* | 2098 | /* |
2099 | * block_is_partially_uptodate checks whether buffers within a page are | ||
2100 | * uptodate or not. | ||
2101 | * | ||
2102 | * Returns true if all buffers which correspond to a file portion | ||
2103 | * we want to read are uptodate. | ||
2104 | */ | ||
2105 | int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc, | ||
2106 | unsigned long from) | ||
2107 | { | ||
2108 | struct inode *inode = page->mapping->host; | ||
2109 | unsigned block_start, block_end, blocksize; | ||
2110 | unsigned to; | ||
2111 | struct buffer_head *bh, *head; | ||
2112 | int ret = 1; | ||
2113 | |||
2114 | if (!page_has_buffers(page)) | ||
2115 | return 0; | ||
2116 | |||
2117 | blocksize = 1 << inode->i_blkbits; | ||
2118 | to = min_t(unsigned, PAGE_CACHE_SIZE - from, desc->count); | ||
2119 | to = from + to; | ||
2120 | if (from < blocksize && to > PAGE_CACHE_SIZE - blocksize) | ||
2121 | return 0; | ||
2122 | |||
2123 | head = page_buffers(page); | ||
2124 | bh = head; | ||
2125 | block_start = 0; | ||
2126 | do { | ||
2127 | block_end = block_start + blocksize; | ||
2128 | if (block_end > from && block_start < to) { | ||
2129 | if (!buffer_uptodate(bh)) { | ||
2130 | ret = 0; | ||
2131 | break; | ||
2132 | } | ||
2133 | if (block_end >= to) | ||
2134 | break; | ||
2135 | } | ||
2136 | block_start = block_end; | ||
2137 | bh = bh->b_this_page; | ||
2138 | } while (bh != head); | ||
2139 | |||
2140 | return ret; | ||
2141 | } | ||
2142 | EXPORT_SYMBOL(block_is_partially_uptodate); | ||
2143 | |||
2144 | /* | ||
2099 | * Generic "read page" function for block devices that have the normal | 2145 | * Generic "read page" function for block devices that have the normal |
2100 | * get_block functionality. This is most of the block device filesystems. | 2146 | * get_block functionality. This is most of the block device filesystems. |
2101 | * Reads the page asynchronously --- the unlock_buffer() and | 2147 | * Reads the page asynchronously --- the unlock_buffer() and |
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 7b99917ffadc..06db79d05c12 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c | |||
@@ -475,8 +475,8 @@ int ecryptfs_encrypt_page(struct page *page) | |||
475 | { | 475 | { |
476 | struct inode *ecryptfs_inode; | 476 | struct inode *ecryptfs_inode; |
477 | struct ecryptfs_crypt_stat *crypt_stat; | 477 | struct ecryptfs_crypt_stat *crypt_stat; |
478 | char *enc_extent_virt = NULL; | 478 | char *enc_extent_virt; |
479 | struct page *enc_extent_page; | 479 | struct page *enc_extent_page = NULL; |
480 | loff_t extent_offset; | 480 | loff_t extent_offset; |
481 | int rc = 0; | 481 | int rc = 0; |
482 | 482 | ||
@@ -492,14 +492,14 @@ int ecryptfs_encrypt_page(struct page *page) | |||
492 | page->index); | 492 | page->index); |
493 | goto out; | 493 | goto out; |
494 | } | 494 | } |
495 | enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER); | 495 | enc_extent_page = alloc_page(GFP_USER); |
496 | if (!enc_extent_virt) { | 496 | if (!enc_extent_page) { |
497 | rc = -ENOMEM; | 497 | rc = -ENOMEM; |
498 | ecryptfs_printk(KERN_ERR, "Error allocating memory for " | 498 | ecryptfs_printk(KERN_ERR, "Error allocating memory for " |
499 | "encrypted extent\n"); | 499 | "encrypted extent\n"); |
500 | goto out; | 500 | goto out; |
501 | } | 501 | } |
502 | enc_extent_page = virt_to_page(enc_extent_virt); | 502 | enc_extent_virt = kmap(enc_extent_page); |
503 | for (extent_offset = 0; | 503 | for (extent_offset = 0; |
504 | extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); | 504 | extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); |
505 | extent_offset++) { | 505 | extent_offset++) { |
@@ -527,7 +527,10 @@ int ecryptfs_encrypt_page(struct page *page) | |||
527 | } | 527 | } |
528 | } | 528 | } |
529 | out: | 529 | out: |
530 | kfree(enc_extent_virt); | 530 | if (enc_extent_page) { |
531 | kunmap(enc_extent_page); | ||
532 | __free_page(enc_extent_page); | ||
533 | } | ||
531 | return rc; | 534 | return rc; |
532 | } | 535 | } |
533 | 536 | ||
@@ -609,8 +612,8 @@ int ecryptfs_decrypt_page(struct page *page) | |||
609 | { | 612 | { |
610 | struct inode *ecryptfs_inode; | 613 | struct inode *ecryptfs_inode; |
611 | struct ecryptfs_crypt_stat *crypt_stat; | 614 | struct ecryptfs_crypt_stat *crypt_stat; |
612 | char *enc_extent_virt = NULL; | 615 | char *enc_extent_virt; |
613 | struct page *enc_extent_page; | 616 | struct page *enc_extent_page = NULL; |
614 | unsigned long extent_offset; | 617 | unsigned long extent_offset; |
615 | int rc = 0; | 618 | int rc = 0; |
616 | 619 | ||
@@ -627,14 +630,14 @@ int ecryptfs_decrypt_page(struct page *page) | |||
627 | page->index); | 630 | page->index); |
628 | goto out; | 631 | goto out; |
629 | } | 632 | } |
630 | enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER); | 633 | enc_extent_page = alloc_page(GFP_USER); |
631 | if (!enc_extent_virt) { | 634 | if (!enc_extent_page) { |
632 | rc = -ENOMEM; | 635 | rc = -ENOMEM; |
633 | ecryptfs_printk(KERN_ERR, "Error allocating memory for " | 636 | ecryptfs_printk(KERN_ERR, "Error allocating memory for " |
634 | "encrypted extent\n"); | 637 | "encrypted extent\n"); |
635 | goto out; | 638 | goto out; |
636 | } | 639 | } |
637 | enc_extent_page = virt_to_page(enc_extent_virt); | 640 | enc_extent_virt = kmap(enc_extent_page); |
638 | for (extent_offset = 0; | 641 | for (extent_offset = 0; |
639 | extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); | 642 | extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); |
640 | extent_offset++) { | 643 | extent_offset++) { |
@@ -662,7 +665,10 @@ int ecryptfs_decrypt_page(struct page *page) | |||
662 | } | 665 | } |
663 | } | 666 | } |
664 | out: | 667 | out: |
665 | kfree(enc_extent_virt); | 668 | if (enc_extent_page) { |
669 | kunmap(enc_extent_page); | ||
670 | __free_page(enc_extent_page); | ||
671 | } | ||
666 | return rc; | 672 | return rc; |
667 | } | 673 | } |
668 | 674 | ||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/swap.h> | 32 | #include <linux/swap.h> |
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/pagemap.h> | ||
35 | #include <linux/highmem.h> | 36 | #include <linux/highmem.h> |
36 | #include <linux/spinlock.h> | 37 | #include <linux/spinlock.h> |
37 | #include <linux/key.h> | 38 | #include <linux/key.h> |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 384fc0d1dd74..991d6dfeb51f 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -791,6 +791,7 @@ const struct address_space_operations ext2_aops = { | |||
791 | .direct_IO = ext2_direct_IO, | 791 | .direct_IO = ext2_direct_IO, |
792 | .writepages = ext2_writepages, | 792 | .writepages = ext2_writepages, |
793 | .migratepage = buffer_migrate_page, | 793 | .migratepage = buffer_migrate_page, |
794 | .is_partially_uptodate = block_is_partially_uptodate, | ||
794 | }; | 795 | }; |
795 | 796 | ||
796 | const struct address_space_operations ext2_aops_xip = { | 797 | const struct address_space_operations ext2_aops_xip = { |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 3bf07d70b914..507d8689b111 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -1767,44 +1767,47 @@ static int ext3_journalled_set_page_dirty(struct page *page) | |||
1767 | } | 1767 | } |
1768 | 1768 | ||
1769 | static const struct address_space_operations ext3_ordered_aops = { | 1769 | static const struct address_space_operations ext3_ordered_aops = { |
1770 | .readpage = ext3_readpage, | 1770 | .readpage = ext3_readpage, |
1771 | .readpages = ext3_readpages, | 1771 | .readpages = ext3_readpages, |
1772 | .writepage = ext3_ordered_writepage, | 1772 | .writepage = ext3_ordered_writepage, |
1773 | .sync_page = block_sync_page, | 1773 | .sync_page = block_sync_page, |
1774 | .write_begin = ext3_write_begin, | 1774 | .write_begin = ext3_write_begin, |
1775 | .write_end = ext3_ordered_write_end, | 1775 | .write_end = ext3_ordered_write_end, |
1776 | .bmap = ext3_bmap, | 1776 | .bmap = ext3_bmap, |
1777 | .invalidatepage = ext3_invalidatepage, | 1777 | .invalidatepage = ext3_invalidatepage, |
1778 | .releasepage = ext3_releasepage, | 1778 | .releasepage = ext3_releasepage, |
1779 | .direct_IO = ext3_direct_IO, | 1779 | .direct_IO = ext3_direct_IO, |
1780 | .migratepage = buffer_migrate_page, | 1780 | .migratepage = buffer_migrate_page, |
1781 | .is_partially_uptodate = block_is_partially_uptodate, | ||
1781 | }; | 1782 | }; |
1782 | 1783 | ||
1783 | static const struct address_space_operations ext3_writeback_aops = { | 1784 | static const struct address_space_operations ext3_writeback_aops = { |
1784 | .readpage = ext3_readpage, | 1785 | .readpage = ext3_readpage, |
1785 | .readpages = ext3_readpages, | 1786 | .readpages = ext3_readpages, |
1786 | .writepage = ext3_writeback_writepage, | 1787 | .writepage = ext3_writeback_writepage, |
1787 | .sync_page = block_sync_page, | 1788 | .sync_page = block_sync_page, |
1788 | .write_begin = ext3_write_begin, | 1789 | .write_begin = ext3_write_begin, |
1789 | .write_end = ext3_writeback_write_end, | 1790 | .write_end = ext3_writeback_write_end, |
1790 | .bmap = ext3_bmap, | 1791 | .bmap = ext3_bmap, |
1791 | .invalidatepage = ext3_invalidatepage, | 1792 | .invalidatepage = ext3_invalidatepage, |
1792 | .releasepage = ext3_releasepage, | 1793 | .releasepage = ext3_releasepage, |
1793 | .direct_IO = ext3_direct_IO, | 1794 | .direct_IO = ext3_direct_IO, |
1794 | .migratepage = buffer_migrate_page, | 1795 | .migratepage = buffer_migrate_page, |
1796 | .is_partially_uptodate = block_is_partially_uptodate, | ||
1795 | }; | 1797 | }; |
1796 | 1798 | ||
1797 | static const struct address_space_operations ext3_journalled_aops = { | 1799 | static const struct address_space_operations ext3_journalled_aops = { |
1798 | .readpage = ext3_readpage, | 1800 | .readpage = ext3_readpage, |
1799 | .readpages = ext3_readpages, | 1801 | .readpages = ext3_readpages, |
1800 | .writepage = ext3_journalled_writepage, | 1802 | .writepage = ext3_journalled_writepage, |
1801 | .sync_page = block_sync_page, | 1803 | .sync_page = block_sync_page, |
1802 | .write_begin = ext3_write_begin, | 1804 | .write_begin = ext3_write_begin, |
1803 | .write_end = ext3_journalled_write_end, | 1805 | .write_end = ext3_journalled_write_end, |
1804 | .set_page_dirty = ext3_journalled_set_page_dirty, | 1806 | .set_page_dirty = ext3_journalled_set_page_dirty, |
1805 | .bmap = ext3_bmap, | 1807 | .bmap = ext3_bmap, |
1806 | .invalidatepage = ext3_invalidatepage, | 1808 | .invalidatepage = ext3_invalidatepage, |
1807 | .releasepage = ext3_releasepage, | 1809 | .releasepage = ext3_releasepage, |
1810 | .is_partially_uptodate = block_is_partially_uptodate, | ||
1808 | }; | 1811 | }; |
1809 | 1812 | ||
1810 | void ext3_set_aops(struct inode *inode) | 1813 | void ext3_set_aops(struct inode *inode) |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 8ca2763df091..9843b046c235 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -2806,59 +2806,63 @@ static int ext4_journalled_set_page_dirty(struct page *page) | |||
2806 | } | 2806 | } |
2807 | 2807 | ||
2808 | static const struct address_space_operations ext4_ordered_aops = { | 2808 | static const struct address_space_operations ext4_ordered_aops = { |
2809 | .readpage = ext4_readpage, | 2809 | .readpage = ext4_readpage, |
2810 | .readpages = ext4_readpages, | 2810 | .readpages = ext4_readpages, |
2811 | .writepage = ext4_normal_writepage, | 2811 | .writepage = ext4_normal_writepage, |
2812 | .sync_page = block_sync_page, | 2812 | .sync_page = block_sync_page, |
2813 | .write_begin = ext4_write_begin, | 2813 | .write_begin = ext4_write_begin, |
2814 | .write_end = ext4_ordered_write_end, | 2814 | .write_end = ext4_ordered_write_end, |
2815 | .bmap = ext4_bmap, | 2815 | .bmap = ext4_bmap, |
2816 | .invalidatepage = ext4_invalidatepage, | 2816 | .invalidatepage = ext4_invalidatepage, |
2817 | .releasepage = ext4_releasepage, | 2817 | .releasepage = ext4_releasepage, |
2818 | .direct_IO = ext4_direct_IO, | 2818 | .direct_IO = ext4_direct_IO, |
2819 | .migratepage = buffer_migrate_page, | 2819 | .migratepage = buffer_migrate_page, |
2820 | .is_partially_uptodate = block_is_partially_uptodate, | ||
2820 | }; | 2821 | }; |
2821 | 2822 | ||
2822 | static const struct address_space_operations ext4_writeback_aops = { | 2823 | static const struct address_space_operations ext4_writeback_aops = { |
2823 | .readpage = ext4_readpage, | 2824 | .readpage = ext4_readpage, |
2824 | .readpages = ext4_readpages, | 2825 | .readpages = ext4_readpages, |
2825 | .writepage = ext4_normal_writepage, | 2826 | .writepage = ext4_normal_writepage, |
2826 | .sync_page = block_sync_page, | 2827 | .sync_page = block_sync_page, |
2827 | .write_begin = ext4_write_begin, | 2828 | .write_begin = ext4_write_begin, |
2828 | .write_end = ext4_writeback_write_end, | 2829 | .write_end = ext4_writeback_write_end, |
2829 | .bmap = ext4_bmap, | 2830 | .bmap = ext4_bmap, |
2830 | .invalidatepage = ext4_invalidatepage, | 2831 | .invalidatepage = ext4_invalidatepage, |
2831 | .releasepage = ext4_releasepage, | 2832 | .releasepage = ext4_releasepage, |
2832 | .direct_IO = ext4_direct_IO, | 2833 | .direct_IO = ext4_direct_IO, |
2833 | .migratepage = buffer_migrate_page, | 2834 | .migratepage = buffer_migrate_page, |
2835 | .is_partially_uptodate = block_is_partially_uptodate, | ||
2834 | }; | 2836 | }; |
2835 | 2837 | ||
2836 | static const struct address_space_operations ext4_journalled_aops = { | 2838 | static const struct address_space_operations ext4_journalled_aops = { |
2837 | .readpage = ext4_readpage, | 2839 | .readpage = ext4_readpage, |
2838 | .readpages = ext4_readpages, | 2840 | .readpages = ext4_readpages, |
2839 | .writepage = ext4_journalled_writepage, | 2841 | .writepage = ext4_journalled_writepage, |
2840 | .sync_page = block_sync_page, | 2842 | .sync_page = block_sync_page, |
2841 | .write_begin = ext4_write_begin, | 2843 | .write_begin = ext4_write_begin, |
2842 | .write_end = ext4_journalled_write_end, | 2844 | .write_end = ext4_journalled_write_end, |
2843 | .set_page_dirty = ext4_journalled_set_page_dirty, | 2845 | .set_page_dirty = ext4_journalled_set_page_dirty, |
2844 | .bmap = ext4_bmap, | 2846 | .bmap = ext4_bmap, |
2845 | .invalidatepage = ext4_invalidatepage, | 2847 | .invalidatepage = ext4_invalidatepage, |
2846 | .releasepage = ext4_releasepage, | 2848 | .releasepage = ext4_releasepage, |
2849 | .is_partially_uptodate = block_is_partially_uptodate, | ||
2847 | }; | 2850 | }; |
2848 | 2851 | ||
2849 | static const struct address_space_operations ext4_da_aops = { | 2852 | static const struct address_space_operations ext4_da_aops = { |
2850 | .readpage = ext4_readpage, | 2853 | .readpage = ext4_readpage, |
2851 | .readpages = ext4_readpages, | 2854 | .readpages = ext4_readpages, |
2852 | .writepage = ext4_da_writepage, | 2855 | .writepage = ext4_da_writepage, |
2853 | .writepages = ext4_da_writepages, | 2856 | .writepages = ext4_da_writepages, |
2854 | .sync_page = block_sync_page, | 2857 | .sync_page = block_sync_page, |
2855 | .write_begin = ext4_da_write_begin, | 2858 | .write_begin = ext4_da_write_begin, |
2856 | .write_end = ext4_da_write_end, | 2859 | .write_end = ext4_da_write_end, |
2857 | .bmap = ext4_bmap, | 2860 | .bmap = ext4_bmap, |
2858 | .invalidatepage = ext4_da_invalidatepage, | 2861 | .invalidatepage = ext4_da_invalidatepage, |
2859 | .releasepage = ext4_releasepage, | 2862 | .releasepage = ext4_releasepage, |
2860 | .direct_IO = ext4_direct_IO, | 2863 | .direct_IO = ext4_direct_IO, |
2861 | .migratepage = buffer_migrate_page, | 2864 | .migratepage = buffer_migrate_page, |
2865 | .is_partially_uptodate = block_is_partially_uptodate, | ||
2862 | }; | 2866 | }; |
2863 | 2867 | ||
2864 | void ext4_set_aops(struct inode *inode) | 2868 | void ext4_set_aops(struct inode *inode) |
diff --git a/fs/libfs.c b/fs/libfs.c index baeb71ee1cde..1add676a19df 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -216,8 +216,8 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name, | |||
216 | 216 | ||
217 | s->s_flags = MS_NOUSER; | 217 | s->s_flags = MS_NOUSER; |
218 | s->s_maxbytes = ~0ULL; | 218 | s->s_maxbytes = ~0ULL; |
219 | s->s_blocksize = 1024; | 219 | s->s_blocksize = PAGE_SIZE; |
220 | s->s_blocksize_bits = 10; | 220 | s->s_blocksize_bits = PAGE_SHIFT; |
221 | s->s_magic = magic; | 221 | s->s_magic = magic; |
222 | s->s_op = ops ? ops : &simple_super_operations; | 222 | s->s_op = ops ? ops : &simple_super_operations; |
223 | s->s_time_gran = 1; | 223 | s->s_time_gran = 1; |
diff --git a/fs/omfs/bitmap.c b/fs/omfs/bitmap.c index dc75f22be3f2..697663b01bae 100644 --- a/fs/omfs/bitmap.c +++ b/fs/omfs/bitmap.c | |||
@@ -71,10 +71,10 @@ static int set_run(struct super_block *sb, int map, | |||
71 | } | 71 | } |
72 | if (set) { | 72 | if (set) { |
73 | set_bit(bit, sbi->s_imap[map]); | 73 | set_bit(bit, sbi->s_imap[map]); |
74 | set_bit(bit, (long *) bh->b_data); | 74 | set_bit(bit, (unsigned long *)bh->b_data); |
75 | } else { | 75 | } else { |
76 | clear_bit(bit, sbi->s_imap[map]); | 76 | clear_bit(bit, sbi->s_imap[map]); |
77 | clear_bit(bit, (long *) bh->b_data); | 77 | clear_bit(bit, (unsigned long *)bh->b_data); |
78 | } | 78 | } |
79 | } | 79 | } |
80 | mark_buffer_dirty(bh); | 80 | mark_buffer_dirty(bh); |
@@ -109,7 +109,7 @@ int omfs_allocate_block(struct super_block *sb, u64 block) | |||
109 | if (!bh) | 109 | if (!bh) |
110 | goto out; | 110 | goto out; |
111 | 111 | ||
112 | set_bit(bit, (long *) bh->b_data); | 112 | set_bit(bit, (unsigned long *)bh->b_data); |
113 | mark_buffer_dirty(bh); | 113 | mark_buffer_dirty(bh); |
114 | brelse(bh); | 114 | brelse(bh); |
115 | } | 115 | } |
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index 05a5bc31e4bd..c0757e998876 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c | |||
@@ -104,7 +104,7 @@ int omfs_make_empty(struct inode *inode, struct super_block *sb) | |||
104 | 104 | ||
105 | oi = (struct omfs_inode *) bh->b_data; | 105 | oi = (struct omfs_inode *) bh->b_data; |
106 | oi->i_head.h_self = cpu_to_be64(inode->i_ino); | 106 | oi->i_head.h_self = cpu_to_be64(inode->i_ino); |
107 | oi->i_sibling = ~0ULL; | 107 | oi->i_sibling = ~cpu_to_be64(0ULL); |
108 | 108 | ||
109 | mark_buffer_dirty(bh); | 109 | mark_buffer_dirty(bh); |
110 | brelse(bh); | 110 | brelse(bh); |
diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 66e01fae4384..7e2499053e4d 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c | |||
@@ -30,11 +30,11 @@ void omfs_make_empty_table(struct buffer_head *bh, int offset) | |||
30 | { | 30 | { |
31 | struct omfs_extent *oe = (struct omfs_extent *) &bh->b_data[offset]; | 31 | struct omfs_extent *oe = (struct omfs_extent *) &bh->b_data[offset]; |
32 | 32 | ||
33 | oe->e_next = ~0ULL; | 33 | oe->e_next = ~cpu_to_be64(0ULL); |
34 | oe->e_extent_count = cpu_to_be32(1), | 34 | oe->e_extent_count = cpu_to_be32(1), |
35 | oe->e_fill = cpu_to_be32(0x22), | 35 | oe->e_fill = cpu_to_be32(0x22), |
36 | oe->e_entry.e_cluster = ~0ULL; | 36 | oe->e_entry.e_cluster = ~cpu_to_be64(0ULL); |
37 | oe->e_entry.e_blocks = ~0ULL; | 37 | oe->e_entry.e_blocks = ~cpu_to_be64(0ULL); |
38 | } | 38 | } |
39 | 39 | ||
40 | int omfs_shrink_inode(struct inode *inode) | 40 | int omfs_shrink_inode(struct inode *inode) |
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 8e51a2aaa977..60d2f822e87b 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c | |||
@@ -418,7 +418,8 @@ static int | |||
418 | romfs_readpage(struct file *file, struct page * page) | 418 | romfs_readpage(struct file *file, struct page * page) |
419 | { | 419 | { |
420 | struct inode *inode = page->mapping->host; | 420 | struct inode *inode = page->mapping->host; |
421 | loff_t offset, avail, readlen; | 421 | loff_t offset, size; |
422 | unsigned long filled; | ||
422 | void *buf; | 423 | void *buf; |
423 | int result = -EIO; | 424 | int result = -EIO; |
424 | 425 | ||
@@ -430,21 +431,29 @@ romfs_readpage(struct file *file, struct page * page) | |||
430 | 431 | ||
431 | /* 32 bit warning -- but not for us :) */ | 432 | /* 32 bit warning -- but not for us :) */ |
432 | offset = page_offset(page); | 433 | offset = page_offset(page); |
433 | if (offset < i_size_read(inode)) { | 434 | size = i_size_read(inode); |
434 | avail = inode->i_size-offset; | 435 | filled = 0; |
435 | readlen = min_t(unsigned long, avail, PAGE_SIZE); | 436 | result = 0; |
436 | if (romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen) == readlen) { | 437 | if (offset < size) { |
437 | if (readlen < PAGE_SIZE) { | 438 | unsigned long readlen; |
438 | memset(buf + readlen,0,PAGE_SIZE-readlen); | 439 | |
439 | } | 440 | size -= offset; |
440 | SetPageUptodate(page); | 441 | readlen = size > PAGE_SIZE ? PAGE_SIZE : size; |
441 | result = 0; | 442 | |
443 | filled = romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen); | ||
444 | |||
445 | if (filled != readlen) { | ||
446 | SetPageError(page); | ||
447 | filled = 0; | ||
448 | result = -EIO; | ||
442 | } | 449 | } |
443 | } | 450 | } |
444 | if (result) { | 451 | |
445 | memset(buf, 0, PAGE_SIZE); | 452 | if (filled < PAGE_SIZE) |
446 | SetPageError(page); | 453 | memset(buf + filled, 0, PAGE_SIZE-filled); |
447 | } | 454 | |
455 | if (!result) | ||
456 | SetPageUptodate(page); | ||
448 | flush_dcache_page(page); | 457 | flush_dcache_page(page); |
449 | 458 | ||
450 | unlock_page(page); | 459 | unlock_page(page); |
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index 1ebbe883f786..13a3d9ad92db 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h | |||
@@ -277,6 +277,7 @@ enum acpi_prefered_pm_profiles { | |||
277 | #define BAF_LEGACY_DEVICES 0x0001 | 277 | #define BAF_LEGACY_DEVICES 0x0001 |
278 | #define BAF_8042_KEYBOARD_CONTROLLER 0x0002 | 278 | #define BAF_8042_KEYBOARD_CONTROLLER 0x0002 |
279 | #define BAF_MSI_NOT_SUPPORTED 0x0008 | 279 | #define BAF_MSI_NOT_SUPPORTED 0x0008 |
280 | #define BAF_PCIE_ASPM_CONTROL 0x0010 | ||
280 | 281 | ||
281 | #define FADT2_REVISION_ID 3 | 282 | #define FADT2_REVISION_ID 3 |
282 | #define FADT2_MINUS_REVISION_ID 2 | 283 | #define FADT2_MINUS_REVISION_ID 2 |
diff --git a/include/asm-arm/arch-s3c2410/spi.h b/include/asm-arm/arch-s3c2410/spi.h index 352d33860b63..442169887d3b 100644 --- a/include/asm-arm/arch-s3c2410/spi.h +++ b/include/asm-arm/arch-s3c2410/spi.h | |||
@@ -16,6 +16,7 @@ | |||
16 | struct s3c2410_spi_info { | 16 | struct s3c2410_spi_info { |
17 | unsigned long pin_cs; /* simple gpio cs */ | 17 | unsigned long pin_cs; /* simple gpio cs */ |
18 | unsigned int num_cs; /* total chipselects */ | 18 | unsigned int num_cs; /* total chipselects */ |
19 | int bus_num; /* bus number to use. */ | ||
19 | 20 | ||
20 | void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol); | 21 | void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol); |
21 | }; | 22 | }; |
diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h index f41335ba6337..45329fca1b64 100644 --- a/include/asm-arm/dma-mapping.h +++ b/include/asm-arm/dma-mapping.h | |||
@@ -7,6 +7,8 @@ | |||
7 | 7 | ||
8 | #include <linux/scatterlist.h> | 8 | #include <linux/scatterlist.h> |
9 | 9 | ||
10 | #include <asm-generic/dma-coherent.h> | ||
11 | |||
10 | /* | 12 | /* |
11 | * DMA-consistent mapping functions. These allocate/free a region of | 13 | * DMA-consistent mapping functions. These allocate/free a region of |
12 | * uncached, unwrite-buffered mapped memory space for use with DMA | 14 | * uncached, unwrite-buffered mapped memory space for use with DMA |
diff --git a/include/asm-cris/dma-mapping.h b/include/asm-cris/dma-mapping.h index cb2fb25ff8d9..da8ef8e8f842 100644 --- a/include/asm-cris/dma-mapping.h +++ b/include/asm-cris/dma-mapping.h | |||
@@ -14,6 +14,8 @@ | |||
14 | #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) | 14 | #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) |
15 | 15 | ||
16 | #ifdef CONFIG_PCI | 16 | #ifdef CONFIG_PCI |
17 | #include <asm-generic/dma-coherent.h> | ||
18 | |||
17 | void *dma_alloc_coherent(struct device *dev, size_t size, | 19 | void *dma_alloc_coherent(struct device *dev, size_t size, |
18 | dma_addr_t *dma_handle, gfp_t flag); | 20 | dma_addr_t *dma_handle, gfp_t flag); |
19 | 21 | ||
diff --git a/include/asm-generic/dma-coherent.h b/include/asm-generic/dma-coherent.h new file mode 100644 index 000000000000..85a3ffaa0242 --- /dev/null +++ b/include/asm-generic/dma-coherent.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifndef DMA_COHERENT_H | ||
2 | #define DMA_COHERENT_H | ||
3 | |||
4 | #ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT | ||
5 | /* | ||
6 | * These two functions are only for dma allocator. | ||
7 | * Don't use them in device drivers. | ||
8 | */ | ||
9 | int dma_alloc_from_coherent(struct device *dev, ssize_t size, | ||
10 | dma_addr_t *dma_handle, void **ret); | ||
11 | int dma_release_from_coherent(struct device *dev, int order, void *vaddr); | ||
12 | |||
13 | /* | ||
14 | * Standard interface | ||
15 | */ | ||
16 | #define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY | ||
17 | extern int | ||
18 | dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
19 | dma_addr_t device_addr, size_t size, int flags); | ||
20 | |||
21 | extern void | ||
22 | dma_release_declared_memory(struct device *dev); | ||
23 | |||
24 | extern void * | ||
25 | dma_mark_declared_memory_occupied(struct device *dev, | ||
26 | dma_addr_t device_addr, size_t size); | ||
27 | #else | ||
28 | #define dma_alloc_from_coherent(dev, size, handle, ret) (0) | ||
29 | #define dma_release_from_coherent(dev, order, vaddr) (0) | ||
30 | #endif | ||
31 | |||
32 | #endif | ||
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index c764a8fcb058..0f99ad38b012 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _ASM_GENERIC_GPIO_H | 2 | #define _ASM_GENERIC_GPIO_H |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/errno.h> | ||
5 | 6 | ||
6 | #ifdef CONFIG_GPIOLIB | 7 | #ifdef CONFIG_GPIOLIB |
7 | 8 | ||
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h index 087325ede76c..a7cdc48e8b78 100644 --- a/include/asm-generic/pgtable-nopmd.h +++ b/include/asm-generic/pgtable-nopmd.h | |||
@@ -5,6 +5,8 @@ | |||
5 | 5 | ||
6 | #include <asm-generic/pgtable-nopud.h> | 6 | #include <asm-generic/pgtable-nopud.h> |
7 | 7 | ||
8 | struct mm_struct; | ||
9 | |||
8 | #define __PAGETABLE_PMD_FOLDED | 10 | #define __PAGETABLE_PMD_FOLDED |
9 | 11 | ||
10 | /* | 12 | /* |
@@ -54,7 +56,9 @@ static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address) | |||
54 | * inside the pud, so has no extra memory associated with it. | 56 | * inside the pud, so has no extra memory associated with it. |
55 | */ | 57 | */ |
56 | #define pmd_alloc_one(mm, address) NULL | 58 | #define pmd_alloc_one(mm, address) NULL |
57 | #define pmd_free(mm, x) do { } while (0) | 59 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) |
60 | { | ||
61 | } | ||
58 | #define __pmd_free_tlb(tlb, x) do { } while (0) | 62 | #define __pmd_free_tlb(tlb, x) do { } while (0) |
59 | 63 | ||
60 | #undef pmd_addr_end | 64 | #undef pmd_addr_end |
diff --git a/include/asm-ia64/sn/mspec.h b/include/asm-ia64/sn/mspec.h index dbe13c6121a8..c1d3c50c3223 100644 --- a/include/asm-ia64/sn/mspec.h +++ b/include/asm-ia64/sn/mspec.h | |||
@@ -4,7 +4,7 @@ | |||
4 | * License. See the file "COPYING" in the main directory of this archive | 4 | * License. See the file "COPYING" in the main directory of this archive |
5 | * for more details. | 5 | * for more details. |
6 | * | 6 | * |
7 | * Copyright (c) 2001-2004 Silicon Graphics, Inc. All rights reserved. | 7 | * Copyright (c) 2001-2008 Silicon Graphics, Inc. All rights reserved. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #ifndef _ASM_IA64_SN_MSPEC_H | 10 | #ifndef _ASM_IA64_SN_MSPEC_H |
@@ -32,26 +32,26 @@ | |||
32 | #ifdef __KERNEL__ | 32 | #ifdef __KERNEL__ |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * Each Atomic Memory Operation (AMO formerly known as fetchop) | 35 | * Each Atomic Memory Operation (amo, formerly known as fetchop) |
36 | * variable is 64 bytes long. The first 8 bytes are used. The | 36 | * variable is 64 bytes long. The first 8 bytes are used. The |
37 | * remaining 56 bytes are unaddressable due to the operation taking | 37 | * remaining 56 bytes are unaddressable due to the operation taking |
38 | * that portion of the address. | 38 | * that portion of the address. |
39 | * | 39 | * |
40 | * NOTE: The AMO_t _MUST_ be placed in either the first or second half | 40 | * NOTE: The amo structure _MUST_ be placed in either the first or second |
41 | * of the cache line. The cache line _MUST NOT_ be used for anything | 41 | * half of the cache line. The cache line _MUST NOT_ be used for anything |
42 | * other than additional AMO_t entries. This is because there are two | 42 | * other than additional amo entries. This is because there are two |
43 | * addresses which reference the same physical cache line. One will | 43 | * addresses which reference the same physical cache line. One will |
44 | * be a cached entry with the memory type bits all set. This address | 44 | * be a cached entry with the memory type bits all set. This address |
45 | * may be loaded into processor cache. The AMO_t will be referenced | 45 | * may be loaded into processor cache. The amo will be referenced |
46 | * uncached via the memory special memory type. If any portion of the | 46 | * uncached via the memory special memory type. If any portion of the |
47 | * cached cache-line is modified, when that line is flushed, it will | 47 | * cached cache-line is modified, when that line is flushed, it will |
48 | * overwrite the uncached value in physical memory and lead to | 48 | * overwrite the uncached value in physical memory and lead to |
49 | * inconsistency. | 49 | * inconsistency. |
50 | */ | 50 | */ |
51 | typedef struct { | 51 | struct amo { |
52 | u64 variable; | 52 | u64 variable; |
53 | u64 unused[7]; | 53 | u64 unused[7]; |
54 | } AMO_t; | 54 | }; |
55 | 55 | ||
56 | 56 | ||
57 | #endif /* __KERNEL__ */ | 57 | #endif /* __KERNEL__ */ |
diff --git a/include/asm-mips/gdb-stub.h b/include/asm-mips/gdb-stub.h deleted file mode 100644 index 22f67d4a71ab..000000000000 --- a/include/asm-mips/gdb-stub.h +++ /dev/null | |||
@@ -1,215 +0,0 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 1995 Andreas Busse | ||
7 | * Copyright (C) 2003 Ralf Baechle | ||
8 | */ | ||
9 | #ifndef _ASM_GDB_STUB_H | ||
10 | #define _ASM_GDB_STUB_H | ||
11 | |||
12 | |||
13 | /* | ||
14 | * important register numbers | ||
15 | */ | ||
16 | |||
17 | #define REG_EPC 37 | ||
18 | #define REG_FP 72 | ||
19 | #define REG_SP 29 | ||
20 | |||
21 | /* | ||
22 | * Stack layout for the GDB exception handler | ||
23 | * Derived from the stack layout described in asm-mips/stackframe.h | ||
24 | * | ||
25 | * The first PTRSIZE*6 bytes are argument save space for C subroutines. | ||
26 | */ | ||
27 | #define NUMREGS 90 | ||
28 | |||
29 | #define GDB_FR_REG0 (PTRSIZE*6) /* 0 */ | ||
30 | #define GDB_FR_REG1 ((GDB_FR_REG0) + LONGSIZE) /* 1 */ | ||
31 | #define GDB_FR_REG2 ((GDB_FR_REG1) + LONGSIZE) /* 2 */ | ||
32 | #define GDB_FR_REG3 ((GDB_FR_REG2) + LONGSIZE) /* 3 */ | ||
33 | #define GDB_FR_REG4 ((GDB_FR_REG3) + LONGSIZE) /* 4 */ | ||
34 | #define GDB_FR_REG5 ((GDB_FR_REG4) + LONGSIZE) /* 5 */ | ||
35 | #define GDB_FR_REG6 ((GDB_FR_REG5) + LONGSIZE) /* 6 */ | ||
36 | #define GDB_FR_REG7 ((GDB_FR_REG6) + LONGSIZE) /* 7 */ | ||
37 | #define GDB_FR_REG8 ((GDB_FR_REG7) + LONGSIZE) /* 8 */ | ||
38 | #define GDB_FR_REG9 ((GDB_FR_REG8) + LONGSIZE) /* 9 */ | ||
39 | #define GDB_FR_REG10 ((GDB_FR_REG9) + LONGSIZE) /* 10 */ | ||
40 | #define GDB_FR_REG11 ((GDB_FR_REG10) + LONGSIZE) /* 11 */ | ||
41 | #define GDB_FR_REG12 ((GDB_FR_REG11) + LONGSIZE) /* 12 */ | ||
42 | #define GDB_FR_REG13 ((GDB_FR_REG12) + LONGSIZE) /* 13 */ | ||
43 | #define GDB_FR_REG14 ((GDB_FR_REG13) + LONGSIZE) /* 14 */ | ||
44 | #define GDB_FR_REG15 ((GDB_FR_REG14) + LONGSIZE) /* 15 */ | ||
45 | #define GDB_FR_REG16 ((GDB_FR_REG15) + LONGSIZE) /* 16 */ | ||
46 | #define GDB_FR_REG17 ((GDB_FR_REG16) + LONGSIZE) /* 17 */ | ||
47 | #define GDB_FR_REG18 ((GDB_FR_REG17) + LONGSIZE) /* 18 */ | ||
48 | #define GDB_FR_REG19 ((GDB_FR_REG18) + LONGSIZE) /* 19 */ | ||
49 | #define GDB_FR_REG20 ((GDB_FR_REG19) + LONGSIZE) /* 20 */ | ||
50 | #define GDB_FR_REG21 ((GDB_FR_REG20) + LONGSIZE) /* 21 */ | ||
51 | #define GDB_FR_REG22 ((GDB_FR_REG21) + LONGSIZE) /* 22 */ | ||
52 | #define GDB_FR_REG23 ((GDB_FR_REG22) + LONGSIZE) /* 23 */ | ||
53 | #define GDB_FR_REG24 ((GDB_FR_REG23) + LONGSIZE) /* 24 */ | ||
54 | #define GDB_FR_REG25 ((GDB_FR_REG24) + LONGSIZE) /* 25 */ | ||
55 | #define GDB_FR_REG26 ((GDB_FR_REG25) + LONGSIZE) /* 26 */ | ||
56 | #define GDB_FR_REG27 ((GDB_FR_REG26) + LONGSIZE) /* 27 */ | ||
57 | #define GDB_FR_REG28 ((GDB_FR_REG27) + LONGSIZE) /* 28 */ | ||
58 | #define GDB_FR_REG29 ((GDB_FR_REG28) + LONGSIZE) /* 29 */ | ||
59 | #define GDB_FR_REG30 ((GDB_FR_REG29) + LONGSIZE) /* 30 */ | ||
60 | #define GDB_FR_REG31 ((GDB_FR_REG30) + LONGSIZE) /* 31 */ | ||
61 | |||
62 | /* | ||
63 | * Saved special registers | ||
64 | */ | ||
65 | #define GDB_FR_STATUS ((GDB_FR_REG31) + LONGSIZE) /* 32 */ | ||
66 | #define GDB_FR_LO ((GDB_FR_STATUS) + LONGSIZE) /* 33 */ | ||
67 | #define GDB_FR_HI ((GDB_FR_LO) + LONGSIZE) /* 34 */ | ||
68 | #define GDB_FR_BADVADDR ((GDB_FR_HI) + LONGSIZE) /* 35 */ | ||
69 | #define GDB_FR_CAUSE ((GDB_FR_BADVADDR) + LONGSIZE) /* 36 */ | ||
70 | #define GDB_FR_EPC ((GDB_FR_CAUSE) + LONGSIZE) /* 37 */ | ||
71 | |||
72 | /* | ||
73 | * Saved floating point registers | ||
74 | */ | ||
75 | #define GDB_FR_FPR0 ((GDB_FR_EPC) + LONGSIZE) /* 38 */ | ||
76 | #define GDB_FR_FPR1 ((GDB_FR_FPR0) + LONGSIZE) /* 39 */ | ||
77 | #define GDB_FR_FPR2 ((GDB_FR_FPR1) + LONGSIZE) /* 40 */ | ||
78 | #define GDB_FR_FPR3 ((GDB_FR_FPR2) + LONGSIZE) /* 41 */ | ||
79 | #define GDB_FR_FPR4 ((GDB_FR_FPR3) + LONGSIZE) /* 42 */ | ||
80 | #define GDB_FR_FPR5 ((GDB_FR_FPR4) + LONGSIZE) /* 43 */ | ||
81 | #define GDB_FR_FPR6 ((GDB_FR_FPR5) + LONGSIZE) /* 44 */ | ||
82 | #define GDB_FR_FPR7 ((GDB_FR_FPR6) + LONGSIZE) /* 45 */ | ||
83 | #define GDB_FR_FPR8 ((GDB_FR_FPR7) + LONGSIZE) /* 46 */ | ||
84 | #define GDB_FR_FPR9 ((GDB_FR_FPR8) + LONGSIZE) /* 47 */ | ||
85 | #define GDB_FR_FPR10 ((GDB_FR_FPR9) + LONGSIZE) /* 48 */ | ||
86 | #define GDB_FR_FPR11 ((GDB_FR_FPR10) + LONGSIZE) /* 49 */ | ||
87 | #define GDB_FR_FPR12 ((GDB_FR_FPR11) + LONGSIZE) /* 50 */ | ||
88 | #define GDB_FR_FPR13 ((GDB_FR_FPR12) + LONGSIZE) /* 51 */ | ||
89 | #define GDB_FR_FPR14 ((GDB_FR_FPR13) + LONGSIZE) /* 52 */ | ||
90 | #define GDB_FR_FPR15 ((GDB_FR_FPR14) + LONGSIZE) /* 53 */ | ||
91 | #define GDB_FR_FPR16 ((GDB_FR_FPR15) + LONGSIZE) /* 54 */ | ||
92 | #define GDB_FR_FPR17 ((GDB_FR_FPR16) + LONGSIZE) /* 55 */ | ||
93 | #define GDB_FR_FPR18 ((GDB_FR_FPR17) + LONGSIZE) /* 56 */ | ||
94 | #define GDB_FR_FPR19 ((GDB_FR_FPR18) + LONGSIZE) /* 57 */ | ||
95 | #define GDB_FR_FPR20 ((GDB_FR_FPR19) + LONGSIZE) /* 58 */ | ||
96 | #define GDB_FR_FPR21 ((GDB_FR_FPR20) + LONGSIZE) /* 59 */ | ||
97 | #define GDB_FR_FPR22 ((GDB_FR_FPR21) + LONGSIZE) /* 60 */ | ||
98 | #define GDB_FR_FPR23 ((GDB_FR_FPR22) + LONGSIZE) /* 61 */ | ||
99 | #define GDB_FR_FPR24 ((GDB_FR_FPR23) + LONGSIZE) /* 62 */ | ||
100 | #define GDB_FR_FPR25 ((GDB_FR_FPR24) + LONGSIZE) /* 63 */ | ||
101 | #define GDB_FR_FPR26 ((GDB_FR_FPR25) + LONGSIZE) /* 64 */ | ||
102 | #define GDB_FR_FPR27 ((GDB_FR_FPR26) + LONGSIZE) /* 65 */ | ||
103 | #define GDB_FR_FPR28 ((GDB_FR_FPR27) + LONGSIZE) /* 66 */ | ||
104 | #define GDB_FR_FPR29 ((GDB_FR_FPR28) + LONGSIZE) /* 67 */ | ||
105 | #define GDB_FR_FPR30 ((GDB_FR_FPR29) + LONGSIZE) /* 68 */ | ||
106 | #define GDB_FR_FPR31 ((GDB_FR_FPR30) + LONGSIZE) /* 69 */ | ||
107 | |||
108 | #define GDB_FR_FSR ((GDB_FR_FPR31) + LONGSIZE) /* 70 */ | ||
109 | #define GDB_FR_FIR ((GDB_FR_FSR) + LONGSIZE) /* 71 */ | ||
110 | #define GDB_FR_FRP ((GDB_FR_FIR) + LONGSIZE) /* 72 */ | ||
111 | |||
112 | #define GDB_FR_DUMMY ((GDB_FR_FRP) + LONGSIZE) /* 73, unused ??? */ | ||
113 | |||
114 | /* | ||
115 | * Again, CP0 registers | ||
116 | */ | ||
117 | #define GDB_FR_CP0_INDEX ((GDB_FR_DUMMY) + LONGSIZE) /* 74 */ | ||
118 | #define GDB_FR_CP0_RANDOM ((GDB_FR_CP0_INDEX) + LONGSIZE) /* 75 */ | ||
119 | #define GDB_FR_CP0_ENTRYLO0 ((GDB_FR_CP0_RANDOM) + LONGSIZE)/* 76 */ | ||
120 | #define GDB_FR_CP0_ENTRYLO1 ((GDB_FR_CP0_ENTRYLO0) + LONGSIZE)/* 77 */ | ||
121 | #define GDB_FR_CP0_CONTEXT ((GDB_FR_CP0_ENTRYLO1) + LONGSIZE)/* 78 */ | ||
122 | #define GDB_FR_CP0_PAGEMASK ((GDB_FR_CP0_CONTEXT) + LONGSIZE)/* 79 */ | ||
123 | #define GDB_FR_CP0_WIRED ((GDB_FR_CP0_PAGEMASK) + LONGSIZE)/* 80 */ | ||
124 | #define GDB_FR_CP0_REG7 ((GDB_FR_CP0_WIRED) + LONGSIZE) /* 81 */ | ||
125 | #define GDB_FR_CP0_REG8 ((GDB_FR_CP0_REG7) + LONGSIZE) /* 82 */ | ||
126 | #define GDB_FR_CP0_REG9 ((GDB_FR_CP0_REG8) + LONGSIZE) /* 83 */ | ||
127 | #define GDB_FR_CP0_ENTRYHI ((GDB_FR_CP0_REG9) + LONGSIZE) /* 84 */ | ||
128 | #define GDB_FR_CP0_REG11 ((GDB_FR_CP0_ENTRYHI) + LONGSIZE)/* 85 */ | ||
129 | #define GDB_FR_CP0_REG12 ((GDB_FR_CP0_REG11) + LONGSIZE) /* 86 */ | ||
130 | #define GDB_FR_CP0_REG13 ((GDB_FR_CP0_REG12) + LONGSIZE) /* 87 */ | ||
131 | #define GDB_FR_CP0_REG14 ((GDB_FR_CP0_REG13) + LONGSIZE) /* 88 */ | ||
132 | #define GDB_FR_CP0_PRID ((GDB_FR_CP0_REG14) + LONGSIZE) /* 89 */ | ||
133 | |||
134 | #define GDB_FR_SIZE ((((GDB_FR_CP0_PRID) + LONGSIZE) + (PTRSIZE-1)) & ~(PTRSIZE-1)) | ||
135 | |||
136 | #ifndef __ASSEMBLY__ | ||
137 | |||
138 | /* | ||
139 | * This is the same as above, but for the high-level | ||
140 | * part of the GDB stub. | ||
141 | */ | ||
142 | |||
143 | struct gdb_regs { | ||
144 | /* | ||
145 | * Pad bytes for argument save space on the stack | ||
146 | * 24/48 Bytes for 32/64 bit code | ||
147 | */ | ||
148 | unsigned long pad0[6]; | ||
149 | |||
150 | /* | ||
151 | * saved main processor registers | ||
152 | */ | ||
153 | long reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7; | ||
154 | long reg8, reg9, reg10, reg11, reg12, reg13, reg14, reg15; | ||
155 | long reg16, reg17, reg18, reg19, reg20, reg21, reg22, reg23; | ||
156 | long reg24, reg25, reg26, reg27, reg28, reg29, reg30, reg31; | ||
157 | |||
158 | /* | ||
159 | * Saved special registers | ||
160 | */ | ||
161 | long cp0_status; | ||
162 | long lo; | ||
163 | long hi; | ||
164 | long cp0_badvaddr; | ||
165 | long cp0_cause; | ||
166 | long cp0_epc; | ||
167 | |||
168 | /* | ||
169 | * Saved floating point registers | ||
170 | */ | ||
171 | long fpr0, fpr1, fpr2, fpr3, fpr4, fpr5, fpr6, fpr7; | ||
172 | long fpr8, fpr9, fpr10, fpr11, fpr12, fpr13, fpr14, fpr15; | ||
173 | long fpr16, fpr17, fpr18, fpr19, fpr20, fpr21, fpr22, fpr23; | ||
174 | long fpr24, fpr25, fpr26, fpr27, fpr28, fpr29, fpr30, fpr31; | ||
175 | |||
176 | long cp1_fsr; | ||
177 | long cp1_fir; | ||
178 | |||
179 | /* | ||
180 | * Frame pointer | ||
181 | */ | ||
182 | long frame_ptr; | ||
183 | long dummy; /* unused */ | ||
184 | |||
185 | /* | ||
186 | * saved cp0 registers | ||
187 | */ | ||
188 | long cp0_index; | ||
189 | long cp0_random; | ||
190 | long cp0_entrylo0; | ||
191 | long cp0_entrylo1; | ||
192 | long cp0_context; | ||
193 | long cp0_pagemask; | ||
194 | long cp0_wired; | ||
195 | long cp0_reg7; | ||
196 | long cp0_reg8; | ||
197 | long cp0_reg9; | ||
198 | long cp0_entryhi; | ||
199 | long cp0_reg11; | ||
200 | long cp0_reg12; | ||
201 | long cp0_reg13; | ||
202 | long cp0_reg14; | ||
203 | long cp0_prid; | ||
204 | }; | ||
205 | |||
206 | /* | ||
207 | * Prototypes | ||
208 | */ | ||
209 | |||
210 | extern int kgdb_enabled; | ||
211 | void set_debug_traps(void); | ||
212 | void set_async_breakpoint(unsigned long *epc); | ||
213 | |||
214 | #endif /* !__ASSEMBLY__ */ | ||
215 | #endif /* _ASM_GDB_STUB_H */ | ||
diff --git a/include/asm-mips/kdebug.h b/include/asm-mips/kdebug.h index 6ece1b037665..5bf62aafc890 100644 --- a/include/asm-mips/kdebug.h +++ b/include/asm-mips/kdebug.h | |||
@@ -1 +1,13 @@ | |||
1 | #include <asm-generic/kdebug.h> | 1 | #ifndef _ASM_MIPS_KDEBUG_H |
2 | #define _ASM_MIPS_KDEBUG_H | ||
3 | |||
4 | #include <linux/notifier.h> | ||
5 | |||
6 | enum die_val { | ||
7 | DIE_OOPS = 1, | ||
8 | DIE_FP, | ||
9 | DIE_TRAP, | ||
10 | DIE_RI, | ||
11 | }; | ||
12 | |||
13 | #endif /* _ASM_MIPS_KDEBUG_H */ | ||
diff --git a/include/asm-mips/kgdb.h b/include/asm-mips/kgdb.h new file mode 100644 index 000000000000..48223b09396c --- /dev/null +++ b/include/asm-mips/kgdb.h | |||
@@ -0,0 +1,44 @@ | |||
1 | #ifndef __ASM_KGDB_H_ | ||
2 | #define __ASM_KGDB_H_ | ||
3 | |||
4 | #ifdef __KERNEL__ | ||
5 | |||
6 | #include <asm/sgidefs.h> | ||
7 | |||
8 | #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ | ||
9 | (_MIPS_ISA == _MIPS_ISA_MIPS32) | ||
10 | |||
11 | #define KGDB_GDB_REG_SIZE 32 | ||
12 | |||
13 | #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ | ||
14 | (_MIPS_ISA == _MIPS_ISA_MIPS64) | ||
15 | |||
16 | #ifdef CONFIG_32BIT | ||
17 | #define KGDB_GDB_REG_SIZE 32 | ||
18 | #else /* CONFIG_CPU_32BIT */ | ||
19 | #define KGDB_GDB_REG_SIZE 64 | ||
20 | #endif | ||
21 | #else | ||
22 | #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" | ||
23 | #endif /* _MIPS_ISA */ | ||
24 | |||
25 | #define BUFMAX 2048 | ||
26 | #if (KGDB_GDB_REG_SIZE == 32) | ||
27 | #define NUMREGBYTES (90*sizeof(u32)) | ||
28 | #define NUMCRITREGBYTES (12*sizeof(u32)) | ||
29 | #else | ||
30 | #define NUMREGBYTES (90*sizeof(u64)) | ||
31 | #define NUMCRITREGBYTES (12*sizeof(u64)) | ||
32 | #endif | ||
33 | #define BREAK_INSTR_SIZE 4 | ||
34 | #define CACHE_FLUSH_IS_SAFE 0 | ||
35 | |||
36 | extern void arch_kgdb_breakpoint(void); | ||
37 | extern int kgdb_early_setup; | ||
38 | extern void *saved_vectors[32]; | ||
39 | extern void handle_exception(struct pt_regs *regs); | ||
40 | extern void breakinst(void); | ||
41 | |||
42 | #endif /* __KERNEL__ */ | ||
43 | |||
44 | #endif /* __ASM_KGDB_H_ */ | ||
diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h index c205875d7f31..5510c53b7feb 100644 --- a/include/asm-mips/pci.h +++ b/include/asm-mips/pci.h | |||
@@ -174,4 +174,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) | |||
174 | 174 | ||
175 | extern int pci_probe_only; | 175 | extern int pci_probe_only; |
176 | 176 | ||
177 | extern char * (*pcibios_plat_setup)(char *str); | ||
178 | |||
177 | #endif /* _ASM_PCI_H */ | 179 | #endif /* _ASM_PCI_H */ |
diff --git a/include/asm-mips/txx9/generic.h b/include/asm-mips/txx9/generic.h index cbae37ec3d88..5b1ccf901c62 100644 --- a/include/asm-mips/txx9/generic.h +++ b/include/asm-mips/txx9/generic.h | |||
@@ -44,5 +44,19 @@ extern struct txx9_board_vec *txx9_board_vec; | |||
44 | extern int (*txx9_irq_dispatch)(int pending); | 44 | extern int (*txx9_irq_dispatch)(int pending); |
45 | void prom_init_cmdline(void); | 45 | void prom_init_cmdline(void); |
46 | char *prom_getcmdline(void); | 46 | char *prom_getcmdline(void); |
47 | void txx9_wdt_init(unsigned long base); | ||
48 | void txx9_spi_init(int busid, unsigned long base, int irq); | ||
49 | void txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr); | ||
50 | void txx9_sio_init(unsigned long baseaddr, int irq, | ||
51 | unsigned int line, unsigned int sclk, int nocts); | ||
52 | void prom_putchar(char c); | ||
53 | #ifdef CONFIG_EARLY_PRINTK | ||
54 | extern void (*txx9_prom_putchar)(char c); | ||
55 | void txx9_sio_putchar_init(unsigned long baseaddr); | ||
56 | #else | ||
57 | static inline void txx9_sio_putchar_init(unsigned long baseaddr) | ||
58 | { | ||
59 | } | ||
60 | #endif | ||
47 | 61 | ||
48 | #endif /* __ASM_TXX9_GENERIC_H */ | 62 | #endif /* __ASM_TXX9_GENERIC_H */ |
diff --git a/include/asm-mips/txx9/jmr3927.h b/include/asm-mips/txx9/jmr3927.h index d6eb1b6a54eb..a409c446bf18 100644 --- a/include/asm-mips/txx9/jmr3927.h +++ b/include/asm-mips/txx9/jmr3927.h | |||
@@ -149,8 +149,6 @@ | |||
149 | 149 | ||
150 | /* Clocks */ | 150 | /* Clocks */ |
151 | #define JMR3927_CORECLK 132710400 /* 132.7MHz */ | 151 | #define JMR3927_CORECLK 132710400 /* 132.7MHz */ |
152 | #define JMR3927_GBUSCLK (JMR3927_CORECLK / 2) /* 66.35MHz */ | ||
153 | #define JMR3927_IMCLK (JMR3927_CORECLK / 4) /* 33.17MHz */ | ||
154 | 152 | ||
155 | /* | 153 | /* |
156 | * TX3927 Pin Configuration: | 154 | * TX3927 Pin Configuration: |
diff --git a/include/asm-mips/txx9/pci.h b/include/asm-mips/txx9/pci.h index d89a45091e24..3d32529060aa 100644 --- a/include/asm-mips/txx9/pci.h +++ b/include/asm-mips/txx9/pci.h | |||
@@ -33,4 +33,7 @@ enum txx9_pci_err_action { | |||
33 | }; | 33 | }; |
34 | extern enum txx9_pci_err_action txx9_pci_err_action; | 34 | extern enum txx9_pci_err_action txx9_pci_err_action; |
35 | 35 | ||
36 | extern char * (*txx9_board_pcibios_setup)(char *str); | ||
37 | char *txx9_pcibios_setup(char *str); | ||
38 | |||
36 | #endif /* __ASM_TXX9_PCI_H */ | 39 | #endif /* __ASM_TXX9_PCI_H */ |
diff --git a/include/asm-mips/txx9/smsc_fdc37m81x.h b/include/asm-mips/txx9/smsc_fdc37m81x.h index 9375e4fc2289..02e161d0755d 100644 --- a/include/asm-mips/txx9/smsc_fdc37m81x.h +++ b/include/asm-mips/txx9/smsc_fdc37m81x.h | |||
@@ -56,7 +56,7 @@ | |||
56 | #define SMSC_FDC37M81X_CONFIG_EXIT 0xaa | 56 | #define SMSC_FDC37M81X_CONFIG_EXIT 0xaa |
57 | #define SMSC_FDC37M81X_CHIP_ID 0x4d | 57 | #define SMSC_FDC37M81X_CHIP_ID 0x4d |
58 | 58 | ||
59 | unsigned long __init smsc_fdc37m81x_init(unsigned long port); | 59 | unsigned long smsc_fdc37m81x_init(unsigned long port); |
60 | 60 | ||
61 | void smsc_fdc37m81x_config_beg(void); | 61 | void smsc_fdc37m81x_config_beg(void); |
62 | 62 | ||
diff --git a/include/asm-mips/txx9/tx3927.h b/include/asm-mips/txx9/tx3927.h index ea79e1b16e71..587deb9592d2 100644 --- a/include/asm-mips/txx9/tx3927.h +++ b/include/asm-mips/txx9/tx3927.h | |||
@@ -8,9 +8,8 @@ | |||
8 | #ifndef __ASM_TXX9_TX3927_H | 8 | #ifndef __ASM_TXX9_TX3927_H |
9 | #define __ASM_TXX9_TX3927_H | 9 | #define __ASM_TXX9_TX3927_H |
10 | 10 | ||
11 | #include <asm/txx9/txx927.h> | ||
12 | |||
13 | #define TX3927_REG_BASE 0xfffe0000UL | 11 | #define TX3927_REG_BASE 0xfffe0000UL |
12 | #define TX3927_REG_SIZE 0x00010000 | ||
14 | #define TX3927_SDRAMC_REG (TX3927_REG_BASE + 0x8000) | 13 | #define TX3927_SDRAMC_REG (TX3927_REG_BASE + 0x8000) |
15 | #define TX3927_ROMC_REG (TX3927_REG_BASE + 0x9000) | 14 | #define TX3927_ROMC_REG (TX3927_REG_BASE + 0x9000) |
16 | #define TX3927_DMA_REG (TX3927_REG_BASE + 0xb000) | 15 | #define TX3927_DMA_REG (TX3927_REG_BASE + 0xb000) |
@@ -236,11 +235,17 @@ struct tx3927_ccfg_reg { | |||
236 | /* see PCI_STATUS_XXX in linux/pci.h */ | 235 | /* see PCI_STATUS_XXX in linux/pci.h */ |
237 | #define PCI_STATUS_NEW_CAP 0x0010 | 236 | #define PCI_STATUS_NEW_CAP 0x0010 |
238 | 237 | ||
238 | /* bits for ISTAT/IIM */ | ||
239 | #define TX3927_PCIC_IIM_ALL 0x00001600 | ||
240 | |||
239 | /* bits for TC */ | 241 | /* bits for TC */ |
240 | #define TX3927_PCIC_TC_OF16E 0x00000020 | 242 | #define TX3927_PCIC_TC_OF16E 0x00000020 |
241 | #define TX3927_PCIC_TC_IF8E 0x00000010 | 243 | #define TX3927_PCIC_TC_IF8E 0x00000010 |
242 | #define TX3927_PCIC_TC_OF8E 0x00000008 | 244 | #define TX3927_PCIC_TC_OF8E 0x00000008 |
243 | 245 | ||
246 | /* bits for TSTAT/TIM */ | ||
247 | #define TX3927_PCIC_TIM_ALL 0x0003ffff | ||
248 | |||
244 | /* bits for IOBA/MBA */ | 249 | /* bits for IOBA/MBA */ |
245 | /* see PCI_BASE_ADDRESS_XXX in linux/pci.h */ | 250 | /* see PCI_BASE_ADDRESS_XXX in linux/pci.h */ |
246 | 251 | ||
@@ -313,12 +318,22 @@ struct tx3927_ccfg_reg { | |||
313 | #define tx3927_dmaptr ((struct tx3927_dma_reg *)TX3927_DMA_REG) | 318 | #define tx3927_dmaptr ((struct tx3927_dma_reg *)TX3927_DMA_REG) |
314 | #define tx3927_pcicptr ((struct tx3927_pcic_reg *)TX3927_PCIC_REG) | 319 | #define tx3927_pcicptr ((struct tx3927_pcic_reg *)TX3927_PCIC_REG) |
315 | #define tx3927_ccfgptr ((struct tx3927_ccfg_reg *)TX3927_CCFG_REG) | 320 | #define tx3927_ccfgptr ((struct tx3927_ccfg_reg *)TX3927_CCFG_REG) |
316 | #define tx3927_tmrptr(ch) ((struct txx927_tmr_reg *)TX3927_TMR_REG(ch)) | ||
317 | #define tx3927_sioptr(ch) ((struct txx927_sio_reg *)TX3927_SIO_REG(ch)) | 321 | #define tx3927_sioptr(ch) ((struct txx927_sio_reg *)TX3927_SIO_REG(ch)) |
318 | #define tx3927_pioptr ((struct txx9_pio_reg __iomem *)TX3927_PIO_REG) | 322 | #define tx3927_pioptr ((struct txx9_pio_reg __iomem *)TX3927_PIO_REG) |
319 | 323 | ||
324 | #define TX3927_REV_PCODE() (tx3927_ccfgptr->crir >> 16) | ||
325 | #define TX3927_ROMC_BA(ch) (tx3927_romcptr->cr[(ch)] & 0xfff00000) | ||
326 | #define TX3927_ROMC_SIZE(ch) \ | ||
327 | (0x00100000 << ((tx3927_romcptr->cr[(ch)] >> 8) & 0xf)) | ||
328 | |||
329 | void tx3927_wdt_init(void); | ||
330 | void tx3927_setup(void); | ||
331 | void tx3927_time_init(unsigned int evt_tmrnr, unsigned int src_tmrnr); | ||
332 | void tx3927_sio_init(unsigned int sclk, unsigned int cts_mask); | ||
320 | struct pci_controller; | 333 | struct pci_controller; |
321 | void __init tx3927_pcic_setup(struct pci_controller *channel, | 334 | void tx3927_pcic_setup(struct pci_controller *channel, |
322 | unsigned long sdram_size, int extarb); | 335 | unsigned long sdram_size, int extarb); |
336 | void tx3927_setup_pcierr_irq(void); | ||
337 | void tx3927_irq_init(void); | ||
323 | 338 | ||
324 | #endif /* __ASM_TXX9_TX3927_H */ | 339 | #endif /* __ASM_TXX9_TX3927_H */ |
diff --git a/include/asm-mips/txx9/tx4927.h b/include/asm-mips/txx9/tx4927.h index ceb4b79ff4e3..195f6515db9a 100644 --- a/include/asm-mips/txx9/tx4927.h +++ b/include/asm-mips/txx9/tx4927.h | |||
@@ -243,12 +243,13 @@ static inline void tx4927_ccfg_change(__u64 change, __u64 new) | |||
243 | } | 243 | } |
244 | 244 | ||
245 | unsigned int tx4927_get_mem_size(void); | 245 | unsigned int tx4927_get_mem_size(void); |
246 | void tx4927_wdr_init(void); | 246 | void tx4927_wdt_init(void); |
247 | void tx4927_setup(void); | 247 | void tx4927_setup(void); |
248 | void tx4927_time_init(unsigned int tmrnr); | 248 | void tx4927_time_init(unsigned int tmrnr); |
249 | void tx4927_setup_serial(void); | 249 | void tx4927_sio_init(unsigned int sclk, unsigned int cts_mask); |
250 | int tx4927_report_pciclk(void); | 250 | int tx4927_report_pciclk(void); |
251 | int tx4927_pciclk66_setup(void); | 251 | int tx4927_pciclk66_setup(void); |
252 | void tx4927_setup_pcierr_irq(void); | ||
252 | void tx4927_irq_init(void); | 253 | void tx4927_irq_init(void); |
253 | 254 | ||
254 | #endif /* __ASM_TXX9_TX4927_H */ | 255 | #endif /* __ASM_TXX9_TX4927_H */ |
diff --git a/include/asm-mips/txx9/tx4927pcic.h b/include/asm-mips/txx9/tx4927pcic.h index d61c3d09c4a2..c470b8a5fe57 100644 --- a/include/asm-mips/txx9/tx4927pcic.h +++ b/include/asm-mips/txx9/tx4927pcic.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #define __ASM_TXX9_TX4927PCIC_H | 10 | #define __ASM_TXX9_TX4927PCIC_H |
11 | 11 | ||
12 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
13 | #include <linux/irqreturn.h> | ||
13 | 14 | ||
14 | struct tx4927_pcic_reg { | 15 | struct tx4927_pcic_reg { |
15 | u32 pciid; | 16 | u32 pciid; |
@@ -192,8 +193,11 @@ struct tx4927_pcic_reg { | |||
192 | 193 | ||
193 | struct tx4927_pcic_reg __iomem *get_tx4927_pcicptr( | 194 | struct tx4927_pcic_reg __iomem *get_tx4927_pcicptr( |
194 | struct pci_controller *channel); | 195 | struct pci_controller *channel); |
195 | void __init tx4927_pcic_setup(struct tx4927_pcic_reg __iomem *pcicptr, | 196 | void tx4927_pcic_setup(struct tx4927_pcic_reg __iomem *pcicptr, |
196 | struct pci_controller *channel, int extarb); | 197 | struct pci_controller *channel, int extarb); |
197 | void tx4927_report_pcic_status(void); | 198 | void tx4927_report_pcic_status(void); |
199 | char *tx4927_pcibios_setup(char *str); | ||
200 | void tx4927_dump_pcic_settings(void); | ||
201 | irqreturn_t tx4927_pcierr_interrupt(int irq, void *dev_id); | ||
198 | 202 | ||
199 | #endif /* __ASM_TXX9_TX4927PCIC_H */ | 203 | #endif /* __ASM_TXX9_TX4927PCIC_H */ |
diff --git a/include/asm-mips/txx9/tx4938.h b/include/asm-mips/txx9/tx4938.h index 1ed969d381d6..8175d4ccbc39 100644 --- a/include/asm-mips/txx9/tx4938.h +++ b/include/asm-mips/txx9/tx4938.h | |||
@@ -276,15 +276,18 @@ struct tx4938_ccfg_reg { | |||
276 | #define TX4938_EBUSC_SIZE(ch) TX4927_EBUSC_SIZE(ch) | 276 | #define TX4938_EBUSC_SIZE(ch) TX4927_EBUSC_SIZE(ch) |
277 | 277 | ||
278 | #define tx4938_get_mem_size() tx4927_get_mem_size() | 278 | #define tx4938_get_mem_size() tx4927_get_mem_size() |
279 | void tx4938_wdr_init(void); | 279 | void tx4938_wdt_init(void); |
280 | void tx4938_setup(void); | 280 | void tx4938_setup(void); |
281 | void tx4938_time_init(unsigned int tmrnr); | 281 | void tx4938_time_init(unsigned int tmrnr); |
282 | void tx4938_setup_serial(void); | 282 | void tx4938_sio_init(unsigned int sclk, unsigned int cts_mask); |
283 | void tx4938_spi_init(int busid); | ||
284 | void tx4938_ethaddr_init(unsigned char *addr0, unsigned char *addr1); | ||
283 | int tx4938_report_pciclk(void); | 285 | int tx4938_report_pciclk(void); |
284 | void tx4938_report_pci1clk(void); | 286 | void tx4938_report_pci1clk(void); |
285 | int tx4938_pciclk66_setup(void); | 287 | int tx4938_pciclk66_setup(void); |
286 | struct pci_dev; | 288 | struct pci_dev; |
287 | int tx4938_pcic1_map_irq(const struct pci_dev *dev, u8 slot); | 289 | int tx4938_pcic1_map_irq(const struct pci_dev *dev, u8 slot); |
290 | void tx4938_setup_pcierr_irq(void); | ||
288 | void tx4938_irq_init(void); | 291 | void tx4938_irq_init(void); |
289 | 292 | ||
290 | #endif | 293 | #endif |
diff --git a/include/asm-mips/txx9/txx927.h b/include/asm-mips/txx9/txx927.h deleted file mode 100644 index 97dd7ad1a890..000000000000 --- a/include/asm-mips/txx9/txx927.h +++ /dev/null | |||
@@ -1,121 +0,0 @@ | |||
1 | /* | ||
2 | * Common definitions for TX3927/TX4927 | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (C) 2000 Toshiba Corporation | ||
9 | */ | ||
10 | #ifndef __ASM_TXX9_TXX927_H | ||
11 | #define __ASM_TXX9_TXX927_H | ||
12 | |||
13 | struct txx927_sio_reg { | ||
14 | volatile unsigned long lcr; | ||
15 | volatile unsigned long dicr; | ||
16 | volatile unsigned long disr; | ||
17 | volatile unsigned long cisr; | ||
18 | volatile unsigned long fcr; | ||
19 | volatile unsigned long flcr; | ||
20 | volatile unsigned long bgr; | ||
21 | volatile unsigned long tfifo; | ||
22 | volatile unsigned long rfifo; | ||
23 | }; | ||
24 | |||
25 | /* | ||
26 | * SIO | ||
27 | */ | ||
28 | /* SILCR : Line Control */ | ||
29 | #define TXx927_SILCR_SCS_MASK 0x00000060 | ||
30 | #define TXx927_SILCR_SCS_IMCLK 0x00000000 | ||
31 | #define TXx927_SILCR_SCS_IMCLK_BG 0x00000020 | ||
32 | #define TXx927_SILCR_SCS_SCLK 0x00000040 | ||
33 | #define TXx927_SILCR_SCS_SCLK_BG 0x00000060 | ||
34 | #define TXx927_SILCR_UEPS 0x00000010 | ||
35 | #define TXx927_SILCR_UPEN 0x00000008 | ||
36 | #define TXx927_SILCR_USBL_MASK 0x00000004 | ||
37 | #define TXx927_SILCR_USBL_1BIT 0x00000004 | ||
38 | #define TXx927_SILCR_USBL_2BIT 0x00000000 | ||
39 | #define TXx927_SILCR_UMODE_MASK 0x00000003 | ||
40 | #define TXx927_SILCR_UMODE_8BIT 0x00000000 | ||
41 | #define TXx927_SILCR_UMODE_7BIT 0x00000001 | ||
42 | |||
43 | /* SIDICR : DMA/Int. Control */ | ||
44 | #define TXx927_SIDICR_TDE 0x00008000 | ||
45 | #define TXx927_SIDICR_RDE 0x00004000 | ||
46 | #define TXx927_SIDICR_TIE 0x00002000 | ||
47 | #define TXx927_SIDICR_RIE 0x00001000 | ||
48 | #define TXx927_SIDICR_SPIE 0x00000800 | ||
49 | #define TXx927_SIDICR_CTSAC 0x00000600 | ||
50 | #define TXx927_SIDICR_STIE_MASK 0x0000003f | ||
51 | #define TXx927_SIDICR_STIE_OERS 0x00000020 | ||
52 | #define TXx927_SIDICR_STIE_CTSS 0x00000010 | ||
53 | #define TXx927_SIDICR_STIE_RBRKD 0x00000008 | ||
54 | #define TXx927_SIDICR_STIE_TRDY 0x00000004 | ||
55 | #define TXx927_SIDICR_STIE_TXALS 0x00000002 | ||
56 | #define TXx927_SIDICR_STIE_UBRKD 0x00000001 | ||
57 | |||
58 | /* SIDISR : DMA/Int. Status */ | ||
59 | #define TXx927_SIDISR_UBRK 0x00008000 | ||
60 | #define TXx927_SIDISR_UVALID 0x00004000 | ||
61 | #define TXx927_SIDISR_UFER 0x00002000 | ||
62 | #define TXx927_SIDISR_UPER 0x00001000 | ||
63 | #define TXx927_SIDISR_UOER 0x00000800 | ||
64 | #define TXx927_SIDISR_ERI 0x00000400 | ||
65 | #define TXx927_SIDISR_TOUT 0x00000200 | ||
66 | #define TXx927_SIDISR_TDIS 0x00000100 | ||
67 | #define TXx927_SIDISR_RDIS 0x00000080 | ||
68 | #define TXx927_SIDISR_STIS 0x00000040 | ||
69 | #define TXx927_SIDISR_RFDN_MASK 0x0000001f | ||
70 | |||
71 | /* SICISR : Change Int. Status */ | ||
72 | #define TXx927_SICISR_OERS 0x00000020 | ||
73 | #define TXx927_SICISR_CTSS 0x00000010 | ||
74 | #define TXx927_SICISR_RBRKD 0x00000008 | ||
75 | #define TXx927_SICISR_TRDY 0x00000004 | ||
76 | #define TXx927_SICISR_TXALS 0x00000002 | ||
77 | #define TXx927_SICISR_UBRKD 0x00000001 | ||
78 | |||
79 | /* SIFCR : FIFO Control */ | ||
80 | #define TXx927_SIFCR_SWRST 0x00008000 | ||
81 | #define TXx927_SIFCR_RDIL_MASK 0x00000180 | ||
82 | #define TXx927_SIFCR_RDIL_1 0x00000000 | ||
83 | #define TXx927_SIFCR_RDIL_4 0x00000080 | ||
84 | #define TXx927_SIFCR_RDIL_8 0x00000100 | ||
85 | #define TXx927_SIFCR_RDIL_12 0x00000180 | ||
86 | #define TXx927_SIFCR_RDIL_MAX 0x00000180 | ||
87 | #define TXx927_SIFCR_TDIL_MASK 0x00000018 | ||
88 | #define TXx927_SIFCR_TDIL_MASK 0x00000018 | ||
89 | #define TXx927_SIFCR_TDIL_1 0x00000000 | ||
90 | #define TXx927_SIFCR_TDIL_4 0x00000001 | ||
91 | #define TXx927_SIFCR_TDIL_8 0x00000010 | ||
92 | #define TXx927_SIFCR_TDIL_MAX 0x00000010 | ||
93 | #define TXx927_SIFCR_TFRST 0x00000004 | ||
94 | #define TXx927_SIFCR_RFRST 0x00000002 | ||
95 | #define TXx927_SIFCR_FRSTE 0x00000001 | ||
96 | #define TXx927_SIO_TX_FIFO 8 | ||
97 | #define TXx927_SIO_RX_FIFO 16 | ||
98 | |||
99 | /* SIFLCR : Flow Control */ | ||
100 | #define TXx927_SIFLCR_RCS 0x00001000 | ||
101 | #define TXx927_SIFLCR_TES 0x00000800 | ||
102 | #define TXx927_SIFLCR_RTSSC 0x00000200 | ||
103 | #define TXx927_SIFLCR_RSDE 0x00000100 | ||
104 | #define TXx927_SIFLCR_TSDE 0x00000080 | ||
105 | #define TXx927_SIFLCR_RTSTL_MASK 0x0000001e | ||
106 | #define TXx927_SIFLCR_RTSTL_MAX 0x0000001e | ||
107 | #define TXx927_SIFLCR_TBRK 0x00000001 | ||
108 | |||
109 | /* SIBGR : Baudrate Control */ | ||
110 | #define TXx927_SIBGR_BCLK_MASK 0x00000300 | ||
111 | #define TXx927_SIBGR_BCLK_T0 0x00000000 | ||
112 | #define TXx927_SIBGR_BCLK_T2 0x00000100 | ||
113 | #define TXx927_SIBGR_BCLK_T4 0x00000200 | ||
114 | #define TXx927_SIBGR_BCLK_T6 0x00000300 | ||
115 | #define TXx927_SIBGR_BRD_MASK 0x000000ff | ||
116 | |||
117 | /* | ||
118 | * PIO | ||
119 | */ | ||
120 | |||
121 | #endif /* __ASM_TXX9_TXX927_H */ | ||
diff --git a/include/asm-mips/txx9irq.h b/include/asm-mips/txx9irq.h index 1c439e51b875..5620879be37f 100644 --- a/include/asm-mips/txx9irq.h +++ b/include/asm-mips/txx9irq.h | |||
@@ -14,8 +14,12 @@ | |||
14 | #ifdef CONFIG_IRQ_CPU | 14 | #ifdef CONFIG_IRQ_CPU |
15 | #define TXX9_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8) | 15 | #define TXX9_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8) |
16 | #else | 16 | #else |
17 | #ifdef CONFIG_I8259 | ||
18 | #define TXX9_IRQ_BASE (I8259A_IRQ_BASE + 16) | ||
19 | #else | ||
17 | #define TXX9_IRQ_BASE 0 | 20 | #define TXX9_IRQ_BASE 0 |
18 | #endif | 21 | #endif |
22 | #endif | ||
19 | 23 | ||
20 | #ifdef CONFIG_CPU_TX39XX | 24 | #ifdef CONFIG_CPU_TX39XX |
21 | #define TXx9_MAX_IR 16 | 25 | #define TXx9_MAX_IR 16 |
diff --git a/include/asm-powerpc/cpm.h b/include/asm-powerpc/cpm.h index 63a55337c2de..24d79e3abd8e 100644 --- a/include/asm-powerpc/cpm.h +++ b/include/asm-powerpc/cpm.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/compiler.h> | 4 | #include <linux/compiler.h> |
5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
6 | #include <linux/of.h> | ||
6 | 7 | ||
7 | /* Opcodes common to CPM1 and CPM2 | 8 | /* Opcodes common to CPM1 and CPM2 |
8 | */ | 9 | */ |
@@ -100,4 +101,6 @@ unsigned long cpm_muram_offset(void __iomem *addr); | |||
100 | dma_addr_t cpm_muram_dma(void __iomem *addr); | 101 | dma_addr_t cpm_muram_dma(void __iomem *addr); |
101 | int cpm_command(u32 command, u8 opcode); | 102 | int cpm_command(u32 command, u8 opcode); |
102 | 103 | ||
104 | int cpm2_gpiochip_add32(struct device_node *np); | ||
105 | |||
103 | #endif | 106 | #endif |
diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h index 2c7fd9cee291..2a6fa0183ac9 100644 --- a/include/asm-powerpc/cpm2.h +++ b/include/asm-powerpc/cpm2.h | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <asm/immap_cpm2.h> | 13 | #include <asm/immap_cpm2.h> |
14 | #include <asm/cpm.h> | 14 | #include <asm/cpm.h> |
15 | #include <sysdev/fsl_soc.h> | ||
15 | 16 | ||
16 | #ifdef CONFIG_PPC_85xx | 17 | #ifdef CONFIG_PPC_85xx |
17 | #define CPM_MAP_ADDR (get_immrbase() + 0x80000) | 18 | #define CPM_MAP_ADDR (get_immrbase() + 0x80000) |
@@ -93,10 +94,40 @@ extern cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor */ | |||
93 | #define cpm_dpfree cpm_muram_free | 94 | #define cpm_dpfree cpm_muram_free |
94 | #define cpm_dpram_addr cpm_muram_addr | 95 | #define cpm_dpram_addr cpm_muram_addr |
95 | 96 | ||
96 | extern void cpm_setbrg(uint brg, uint rate); | ||
97 | extern void cpm2_fastbrg(uint brg, uint rate, int div16); | ||
98 | extern void cpm2_reset(void); | 97 | extern void cpm2_reset(void); |
99 | 98 | ||
99 | /* Baud rate generators. | ||
100 | */ | ||
101 | #define CPM_BRG_RST ((uint)0x00020000) | ||
102 | #define CPM_BRG_EN ((uint)0x00010000) | ||
103 | #define CPM_BRG_EXTC_INT ((uint)0x00000000) | ||
104 | #define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000) | ||
105 | #define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000) | ||
106 | #define CPM_BRG_ATB ((uint)0x00002000) | ||
107 | #define CPM_BRG_CD_MASK ((uint)0x00001ffe) | ||
108 | #define CPM_BRG_DIV16 ((uint)0x00000001) | ||
109 | |||
110 | #define CPM2_BRG_INT_CLK (get_brgfreq()) | ||
111 | #define CPM2_BRG_UART_CLK (CPM2_BRG_INT_CLK/16) | ||
112 | |||
113 | extern void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src); | ||
114 | |||
115 | /* This function is used by UARTS, or anything else that uses a 16x | ||
116 | * oversampled clock. | ||
117 | */ | ||
118 | static inline void cpm_setbrg(uint brg, uint rate) | ||
119 | { | ||
120 | __cpm2_setbrg(brg, rate, CPM2_BRG_UART_CLK, 0, CPM_BRG_EXTC_INT); | ||
121 | } | ||
122 | |||
123 | /* This function is used to set high speed synchronous baud rate | ||
124 | * clocks. | ||
125 | */ | ||
126 | static inline void cpm2_fastbrg(uint brg, uint rate, int div16) | ||
127 | { | ||
128 | __cpm2_setbrg(brg, rate, CPM2_BRG_INT_CLK, div16, CPM_BRG_EXTC_INT); | ||
129 | } | ||
130 | |||
100 | /* Function code bits, usually generic to devices. | 131 | /* Function code bits, usually generic to devices. |
101 | */ | 132 | */ |
102 | #define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ | 133 | #define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ |
@@ -195,17 +226,6 @@ typedef struct smc_uart { | |||
195 | #define SMCM_TX ((unsigned char)0x02) | 226 | #define SMCM_TX ((unsigned char)0x02) |
196 | #define SMCM_RX ((unsigned char)0x01) | 227 | #define SMCM_RX ((unsigned char)0x01) |
197 | 228 | ||
198 | /* Baud rate generators. | ||
199 | */ | ||
200 | #define CPM_BRG_RST ((uint)0x00020000) | ||
201 | #define CPM_BRG_EN ((uint)0x00010000) | ||
202 | #define CPM_BRG_EXTC_INT ((uint)0x00000000) | ||
203 | #define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000) | ||
204 | #define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000) | ||
205 | #define CPM_BRG_ATB ((uint)0x00002000) | ||
206 | #define CPM_BRG_CD_MASK ((uint)0x00001ffe) | ||
207 | #define CPM_BRG_DIV16 ((uint)0x00000001) | ||
208 | |||
209 | /* SCCs. | 229 | /* SCCs. |
210 | */ | 230 | */ |
211 | #define SCC_GSMRH_IRP ((uint)0x00040000) | 231 | #define SCC_GSMRH_IRP ((uint)0x00040000) |
diff --git a/include/asm-powerpc/pgtable-ppc64.h b/include/asm-powerpc/pgtable-ppc64.h index 5fc78c0be302..74c6f380b805 100644 --- a/include/asm-powerpc/pgtable-ppc64.h +++ b/include/asm-powerpc/pgtable-ppc64.h | |||
@@ -461,6 +461,8 @@ void pgtable_cache_init(void); | |||
461 | return pt; | 461 | return pt; |
462 | } | 462 | } |
463 | 463 | ||
464 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long address); | ||
465 | |||
464 | #endif /* __ASSEMBLY__ */ | 466 | #endif /* __ASSEMBLY__ */ |
465 | 467 | ||
466 | #endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */ | 468 | #endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */ |
diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h index 4b7cb964ff35..89ec7056da28 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h | |||
@@ -34,4 +34,18 @@ typedef struct { | |||
34 | 34 | ||
35 | void clock_comparator_work(void); | 35 | void clock_comparator_work(void); |
36 | 36 | ||
37 | static inline unsigned long long local_tick_disable(void) | ||
38 | { | ||
39 | unsigned long long old; | ||
40 | |||
41 | old = S390_lowcore.clock_comparator; | ||
42 | S390_lowcore.clock_comparator = -1ULL; | ||
43 | return old; | ||
44 | } | ||
45 | |||
46 | static inline void local_tick_enable(unsigned long long comp) | ||
47 | { | ||
48 | S390_lowcore.clock_comparator = comp; | ||
49 | } | ||
50 | |||
37 | #endif /* __ASM_HARDIRQ_H */ | 51 | #endif /* __ASM_HARDIRQ_H */ |
diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h index eaca6dff5405..1171e6d144a3 100644 --- a/include/asm-s390/ipl.h +++ b/include/asm-s390/ipl.h | |||
@@ -159,7 +159,8 @@ enum diag308_vm_flags { | |||
159 | }; | 159 | }; |
160 | 160 | ||
161 | enum diag308_rc { | 161 | enum diag308_rc { |
162 | DIAG308_RC_OK = 1, | 162 | DIAG308_RC_OK = 0x0001, |
163 | DIAG308_RC_NOCONFIG = 0x0102, | ||
163 | }; | 164 | }; |
164 | 165 | ||
165 | extern int diag308(unsigned long subcode, void *addr); | 166 | extern int diag308(unsigned long subcode, void *addr); |
diff --git a/include/asm-s390/schid.h b/include/asm-s390/schid.h index 7bdc0fe15691..825503cf3dc2 100644 --- a/include/asm-s390/schid.h +++ b/include/asm-s390/schid.h | |||
@@ -11,6 +11,7 @@ struct subchannel_id { | |||
11 | } __attribute__ ((packed, aligned(4))); | 11 | } __attribute__ ((packed, aligned(4))); |
12 | 12 | ||
13 | #ifdef __KERNEL__ | 13 | #ifdef __KERNEL__ |
14 | #include <linux/string.h> | ||
14 | 15 | ||
15 | /* Helper function for sane state of pre-allocated subchannel_id. */ | 16 | /* Helper function for sane state of pre-allocated subchannel_id. */ |
16 | static inline void | 17 | static inline void |
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h index 4ba14e463e83..2bd9faeb3919 100644 --- a/include/asm-s390/setup.h +++ b/include/asm-s390/setup.h | |||
@@ -65,7 +65,6 @@ extern unsigned long machine_flags; | |||
65 | 65 | ||
66 | #define MACHINE_FLAG_VM (1UL << 0) | 66 | #define MACHINE_FLAG_VM (1UL << 0) |
67 | #define MACHINE_FLAG_IEEE (1UL << 1) | 67 | #define MACHINE_FLAG_IEEE (1UL << 1) |
68 | #define MACHINE_FLAG_P390 (1UL << 2) | ||
69 | #define MACHINE_FLAG_CSP (1UL << 3) | 68 | #define MACHINE_FLAG_CSP (1UL << 3) |
70 | #define MACHINE_FLAG_MVPG (1UL << 4) | 69 | #define MACHINE_FLAG_MVPG (1UL << 4) |
71 | #define MACHINE_FLAG_DIAG44 (1UL << 5) | 70 | #define MACHINE_FLAG_DIAG44 (1UL << 5) |
diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index 583da807ea97..c8ad350d1444 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h | |||
@@ -259,7 +259,13 @@ | |||
259 | #define __NR_timerfd_create 319 | 259 | #define __NR_timerfd_create 319 |
260 | #define __NR_timerfd_settime 320 | 260 | #define __NR_timerfd_settime 320 |
261 | #define __NR_timerfd_gettime 321 | 261 | #define __NR_timerfd_gettime 321 |
262 | #define NR_syscalls 322 | 262 | #define __NR_signalfd4 322 |
263 | #define __NR_eventfd2 323 | ||
264 | #define __NR_inotify_init1 324 | ||
265 | #define __NR_pipe2 325 | ||
266 | #define __NR_dup3 326 | ||
267 | #define __NR_epoll_create1 327 | ||
268 | #define NR_syscalls 328 | ||
263 | 269 | ||
264 | /* | 270 | /* |
265 | * There are some system calls that are not present on 64 bit, some | 271 | * There are some system calls that are not present on 64 bit, some |
diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h index 0eaa9bf6011f..ad9cd6d49bfc 100644 --- a/include/asm-x86/dma-mapping.h +++ b/include/asm-x86/dma-mapping.h | |||
@@ -249,25 +249,5 @@ static inline int dma_get_cache_alignment(void) | |||
249 | 249 | ||
250 | #define dma_is_consistent(d, h) (1) | 250 | #define dma_is_consistent(d, h) (1) |
251 | 251 | ||
252 | #ifdef CONFIG_X86_32 | 252 | #include <asm-generic/dma-coherent.h> |
253 | # define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY | ||
254 | struct dma_coherent_mem { | ||
255 | void *virt_base; | ||
256 | u32 device_base; | ||
257 | int size; | ||
258 | int flags; | ||
259 | unsigned long *bitmap; | ||
260 | }; | ||
261 | |||
262 | extern int | ||
263 | dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
264 | dma_addr_t device_addr, size_t size, int flags); | ||
265 | |||
266 | extern void | ||
267 | dma_release_declared_memory(struct device *dev); | ||
268 | |||
269 | extern void * | ||
270 | dma_mark_declared_memory_occupied(struct device *dev, | ||
271 | dma_addr_t device_addr, size_t size); | ||
272 | #endif /* CONFIG_X86_32 */ | ||
273 | #endif | 253 | #endif |
diff --git a/include/asm-x86/iommu.h b/include/asm-x86/iommu.h index ecc8061904a9..5f888cc5be49 100644 --- a/include/asm-x86/iommu.h +++ b/include/asm-x86/iommu.h | |||
@@ -7,6 +7,8 @@ extern struct dma_mapping_ops nommu_dma_ops; | |||
7 | extern int force_iommu, no_iommu; | 7 | extern int force_iommu, no_iommu; |
8 | extern int iommu_detected; | 8 | extern int iommu_detected; |
9 | 9 | ||
10 | extern unsigned long iommu_num_pages(unsigned long addr, unsigned long len); | ||
11 | |||
10 | #ifdef CONFIG_GART_IOMMU | 12 | #ifdef CONFIG_GART_IOMMU |
11 | extern int gart_iommu_aperture; | 13 | extern int gart_iommu_aperture; |
12 | extern int gart_iommu_aperture_allowed; | 14 | extern int gart_iommu_aperture_allowed; |
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 82aa36c53ea7..50cfe8ceb478 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h | |||
@@ -205,6 +205,8 @@ void block_invalidatepage(struct page *page, unsigned long offset); | |||
205 | int block_write_full_page(struct page *page, get_block_t *get_block, | 205 | int block_write_full_page(struct page *page, get_block_t *get_block, |
206 | struct writeback_control *wbc); | 206 | struct writeback_control *wbc); |
207 | int block_read_full_page(struct page*, get_block_t*); | 207 | int block_read_full_page(struct page*, get_block_t*); |
208 | int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc, | ||
209 | unsigned long from); | ||
208 | int block_write_begin(struct file *, struct address_space *, | 210 | int block_write_begin(struct file *, struct address_space *, |
209 | loff_t, unsigned, unsigned, | 211 | loff_t, unsigned, unsigned, |
210 | struct page **, void **, get_block_t*); | 212 | struct page **, void **, get_block_t*); |
diff --git a/include/linux/connector.h b/include/linux/connector.h index 96a89d3d6727..5c7f9468f753 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h | |||
@@ -38,8 +38,9 @@ | |||
38 | #define CN_W1_VAL 0x1 | 38 | #define CN_W1_VAL 0x1 |
39 | #define CN_IDX_V86D 0x4 | 39 | #define CN_IDX_V86D 0x4 |
40 | #define CN_VAL_V86D_UVESAFB 0x1 | 40 | #define CN_VAL_V86D_UVESAFB 0x1 |
41 | #define CN_IDX_BB 0x5 /* BlackBoard, from the TSP GPL sampling framework */ | ||
41 | 42 | ||
42 | #define CN_NETLINK_USERS 5 | 43 | #define CN_NETLINK_USERS 6 |
43 | 44 | ||
44 | /* | 45 | /* |
45 | * Maximum connector's message size. | 46 | * Maximum connector's message size. |
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 2270ca5ec631..6fd5668aa572 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
@@ -106,6 +106,7 @@ struct cpufreq_policy { | |||
106 | #define CPUFREQ_ADJUST (0) | 106 | #define CPUFREQ_ADJUST (0) |
107 | #define CPUFREQ_INCOMPATIBLE (1) | 107 | #define CPUFREQ_INCOMPATIBLE (1) |
108 | #define CPUFREQ_NOTIFY (2) | 108 | #define CPUFREQ_NOTIFY (2) |
109 | #define CPUFREQ_START (3) | ||
109 | 110 | ||
110 | #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ | 111 | #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ |
111 | #define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */ | 112 | #define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */ |
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 1b5c98e7fef7..d3219d73f8e6 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h | |||
@@ -62,15 +62,7 @@ | |||
62 | * int next_cpu_nr(cpu, mask) Next cpu past 'cpu', or nr_cpu_ids | 62 | * int next_cpu_nr(cpu, mask) Next cpu past 'cpu', or nr_cpu_ids |
63 | * | 63 | * |
64 | * cpumask_t cpumask_of_cpu(cpu) Return cpumask with bit 'cpu' set | 64 | * cpumask_t cpumask_of_cpu(cpu) Return cpumask with bit 'cpu' set |
65 | *ifdef CONFIG_HAS_CPUMASK_OF_CPU | 65 | * (can be used as an lvalue) |
66 | * cpumask_of_cpu_ptr_declare(v) Declares cpumask_t *v | ||
67 | * cpumask_of_cpu_ptr_next(v, cpu) Sets v = &cpumask_of_cpu_map[cpu] | ||
68 | * cpumask_of_cpu_ptr(v, cpu) Combines above two operations | ||
69 | *else | ||
70 | * cpumask_of_cpu_ptr_declare(v) Declares cpumask_t _v and *v = &_v | ||
71 | * cpumask_of_cpu_ptr_next(v, cpu) Sets _v = cpumask_of_cpu(cpu) | ||
72 | * cpumask_of_cpu_ptr(v, cpu) Combines above two operations | ||
73 | *endif | ||
74 | * CPU_MASK_ALL Initializer - all bits set | 66 | * CPU_MASK_ALL Initializer - all bits set |
75 | * CPU_MASK_NONE Initializer - no bits set | 67 | * CPU_MASK_NONE Initializer - no bits set |
76 | * unsigned long *cpus_addr(mask) Array of unsigned long's in mask | 68 | * unsigned long *cpus_addr(mask) Array of unsigned long's in mask |
@@ -273,37 +265,30 @@ static inline void __cpus_shift_left(cpumask_t *dstp, | |||
273 | bitmap_shift_left(dstp->bits, srcp->bits, n, nbits); | 265 | bitmap_shift_left(dstp->bits, srcp->bits, n, nbits); |
274 | } | 266 | } |
275 | 267 | ||
268 | /* | ||
269 | * Special-case data structure for "single bit set only" constant CPU masks. | ||
270 | * | ||
271 | * We pre-generate all the 64 (or 32) possible bit positions, with enough | ||
272 | * padding to the left and the right, and return the constant pointer | ||
273 | * appropriately offset. | ||
274 | */ | ||
275 | extern const unsigned long | ||
276 | cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)]; | ||
277 | |||
278 | static inline const cpumask_t *get_cpu_mask(unsigned int cpu) | ||
279 | { | ||
280 | const unsigned long *p = cpu_bit_bitmap[1 + cpu % BITS_PER_LONG]; | ||
281 | p -= cpu / BITS_PER_LONG; | ||
282 | return (const cpumask_t *)p; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * In cases where we take the address of the cpumask immediately, | ||
287 | * gcc optimizes it out (it's a constant) and there's no huge stack | ||
288 | * variable created: | ||
289 | */ | ||
290 | #define cpumask_of_cpu(cpu) (*get_cpu_mask(cpu)) | ||
276 | 291 | ||
277 | #ifdef CONFIG_HAVE_CPUMASK_OF_CPU_MAP | ||
278 | extern cpumask_t *cpumask_of_cpu_map; | ||
279 | #define cpumask_of_cpu(cpu) (cpumask_of_cpu_map[cpu]) | ||
280 | #define cpumask_of_cpu_ptr(v, cpu) \ | ||
281 | const cpumask_t *v = &cpumask_of_cpu(cpu) | ||
282 | #define cpumask_of_cpu_ptr_declare(v) \ | ||
283 | const cpumask_t *v | ||
284 | #define cpumask_of_cpu_ptr_next(v, cpu) \ | ||
285 | v = &cpumask_of_cpu(cpu) | ||
286 | #else | ||
287 | #define cpumask_of_cpu(cpu) \ | ||
288 | ({ \ | ||
289 | typeof(_unused_cpumask_arg_) m; \ | ||
290 | if (sizeof(m) == sizeof(unsigned long)) { \ | ||
291 | m.bits[0] = 1UL<<(cpu); \ | ||
292 | } else { \ | ||
293 | cpus_clear(m); \ | ||
294 | cpu_set((cpu), m); \ | ||
295 | } \ | ||
296 | m; \ | ||
297 | }) | ||
298 | #define cpumask_of_cpu_ptr(v, cpu) \ | ||
299 | cpumask_t _##v = cpumask_of_cpu(cpu); \ | ||
300 | const cpumask_t *v = &_##v | ||
301 | #define cpumask_of_cpu_ptr_declare(v) \ | ||
302 | cpumask_t _##v; \ | ||
303 | const cpumask_t *v = &_##v | ||
304 | #define cpumask_of_cpu_ptr_next(v, cpu) \ | ||
305 | _##v = cpumask_of_cpu(cpu) | ||
306 | #endif | ||
307 | 292 | ||
308 | #define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS) | 293 | #define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS) |
309 | 294 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 8252b045e624..580b513668fe 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -443,6 +443,27 @@ static inline size_t iov_iter_count(struct iov_iter *i) | |||
443 | return i->count; | 443 | return i->count; |
444 | } | 444 | } |
445 | 445 | ||
446 | /* | ||
447 | * "descriptor" for what we're up to with a read. | ||
448 | * This allows us to use the same read code yet | ||
449 | * have multiple different users of the data that | ||
450 | * we read from a file. | ||
451 | * | ||
452 | * The simplest case just copies the data to user | ||
453 | * mode. | ||
454 | */ | ||
455 | typedef struct { | ||
456 | size_t written; | ||
457 | size_t count; | ||
458 | union { | ||
459 | char __user *buf; | ||
460 | void *data; | ||
461 | } arg; | ||
462 | int error; | ||
463 | } read_descriptor_t; | ||
464 | |||
465 | typedef int (*read_actor_t)(read_descriptor_t *, struct page *, | ||
466 | unsigned long, unsigned long); | ||
446 | 467 | ||
447 | struct address_space_operations { | 468 | struct address_space_operations { |
448 | int (*writepage)(struct page *page, struct writeback_control *wbc); | 469 | int (*writepage)(struct page *page, struct writeback_control *wbc); |
@@ -484,6 +505,8 @@ struct address_space_operations { | |||
484 | int (*migratepage) (struct address_space *, | 505 | int (*migratepage) (struct address_space *, |
485 | struct page *, struct page *); | 506 | struct page *, struct page *); |
486 | int (*launder_page) (struct page *); | 507 | int (*launder_page) (struct page *); |
508 | int (*is_partially_uptodate) (struct page *, read_descriptor_t *, | ||
509 | unsigned long); | ||
487 | }; | 510 | }; |
488 | 511 | ||
489 | /* | 512 | /* |
@@ -1198,27 +1221,6 @@ struct block_device_operations { | |||
1198 | struct module *owner; | 1221 | struct module *owner; |
1199 | }; | 1222 | }; |
1200 | 1223 | ||
1201 | /* | ||
1202 | * "descriptor" for what we're up to with a read. | ||
1203 | * This allows us to use the same read code yet | ||
1204 | * have multiple different users of the data that | ||
1205 | * we read from a file. | ||
1206 | * | ||
1207 | * The simplest case just copies the data to user | ||
1208 | * mode. | ||
1209 | */ | ||
1210 | typedef struct { | ||
1211 | size_t written; | ||
1212 | size_t count; | ||
1213 | union { | ||
1214 | char __user * buf; | ||
1215 | void *data; | ||
1216 | } arg; | ||
1217 | int error; | ||
1218 | } read_descriptor_t; | ||
1219 | |||
1220 | typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long); | ||
1221 | |||
1222 | /* These macros are for out of kernel modules to test that | 1224 | /* These macros are for out of kernel modules to test that |
1223 | * the kernel supports the unlocked_ioctl and compat_ioctl | 1225 | * the kernel supports the unlocked_ioctl and compat_ioctl |
1224 | * fields in struct file_operations. */ | 1226 | * fields in struct file_operations. */ |
diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 2cd07cc29687..22d2115458c6 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h | |||
@@ -118,6 +118,10 @@ extern int allocate_resource(struct resource *root, struct resource *new, | |||
118 | int adjust_resource(struct resource *res, resource_size_t start, | 118 | int adjust_resource(struct resource *res, resource_size_t start, |
119 | resource_size_t size); | 119 | resource_size_t size); |
120 | resource_size_t resource_alignment(struct resource *res); | 120 | resource_size_t resource_alignment(struct resource *res); |
121 | static inline resource_size_t resource_size(struct resource *res) | ||
122 | { | ||
123 | return res->end - res->start + 1; | ||
124 | } | ||
121 | 125 | ||
122 | /* Convenience shorthand with allocation */ | 126 | /* Convenience shorthand with allocation */ |
123 | #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) | 127 | #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) |
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index 57aefa160a92..b96144887444 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h | |||
@@ -108,8 +108,7 @@ static inline void print_fn_descriptor_symbol(const char *fmt, void *addr) | |||
108 | 108 | ||
109 | static inline void print_ip_sym(unsigned long ip) | 109 | static inline void print_ip_sym(unsigned long ip) |
110 | { | 110 | { |
111 | printk("[<%p>]", (void *) ip); | 111 | printk("[<%p>] %pS\n", (void *) ip, (void *) ip); |
112 | print_symbol(" %s\n", ip); | ||
113 | } | 112 | } |
114 | 113 | ||
115 | #endif /*_LINUX_KALLSYMS_H*/ | 114 | #endif /*_LINUX_KALLSYMS_H*/ |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index fdbbf72ca2eb..aaa998f65c7a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -75,6 +75,12 @@ extern const char linux_proc_banner[]; | |||
75 | */ | 75 | */ |
76 | #define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) | 76 | #define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) |
77 | 77 | ||
78 | /** | ||
79 | * lower_32_bits - return bits 0-31 of a number | ||
80 | * @n: the number we're accessing | ||
81 | */ | ||
82 | #define lower_32_bits(n) ((u32)(n)) | ||
83 | |||
78 | #define KERN_EMERG "<0>" /* system is unusable */ | 84 | #define KERN_EMERG "<0>" /* system is unusable */ |
79 | #define KERN_ALERT "<1>" /* action must be taken immediately */ | 85 | #define KERN_ALERT "<1>" /* action must be taken immediately */ |
80 | #define KERN_CRIT "<2>" /* critical conditions */ | 86 | #define KERN_CRIT "<2>" /* critical conditions */ |
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index bb3dd0545928..49ef857cdb2d 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h | |||
@@ -1,5 +1,3 @@ | |||
1 | #ifndef MFD_CORE_H | ||
2 | #define MFD_CORE_H | ||
3 | /* | 1 | /* |
4 | * drivers/mfd/mfd-core.h | 2 | * drivers/mfd/mfd-core.h |
5 | * | 3 | * |
@@ -13,6 +11,9 @@ | |||
13 | * | 11 | * |
14 | */ | 12 | */ |
15 | 13 | ||
14 | #ifndef MFD_CORE_H | ||
15 | #define MFD_CORE_H | ||
16 | |||
16 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
17 | 18 | ||
18 | /* | 19 | /* |
@@ -28,7 +29,13 @@ struct mfd_cell { | |||
28 | int (*suspend)(struct platform_device *dev); | 29 | int (*suspend)(struct platform_device *dev); |
29 | int (*resume)(struct platform_device *dev); | 30 | int (*resume)(struct platform_device *dev); |
30 | 31 | ||
31 | void *driver_data; /* driver-specific data */ | 32 | /* driver-specific data for MFD-aware "cell" drivers */ |
33 | void *driver_data; | ||
34 | |||
35 | /* platform_data can be used to either pass data to "generic" | ||
36 | driver or as a hook to mfd_cell for the "cell" drivers */ | ||
37 | void *platform_data; | ||
38 | size_t data_size; | ||
32 | 39 | ||
33 | /* | 40 | /* |
34 | * This resources can be specified relatievly to the parent device. | 41 | * This resources can be specified relatievly to the parent device. |
@@ -38,18 +45,11 @@ struct mfd_cell { | |||
38 | const struct resource *resources; | 45 | const struct resource *resources; |
39 | }; | 46 | }; |
40 | 47 | ||
41 | static inline struct mfd_cell * | 48 | extern int mfd_add_devices(struct device *parent, int id, |
42 | mfd_get_cell(struct platform_device *pdev) | 49 | const struct mfd_cell *cells, int n_devs, |
43 | { | 50 | struct resource *mem_base, |
44 | return (struct mfd_cell *)pdev->dev.platform_data; | 51 | int irq_base); |
45 | } | ||
46 | |||
47 | extern int mfd_add_devices( | ||
48 | struct platform_device *parent, | ||
49 | const struct mfd_cell *cells, int n_devs, | ||
50 | struct resource *mem_base, | ||
51 | int irq_base); | ||
52 | 52 | ||
53 | extern void mfd_remove_devices(struct platform_device *parent); | 53 | extern void mfd_remove_devices(struct device *parent); |
54 | 54 | ||
55 | #endif | 55 | #endif |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 6e695eaab4ce..335288bff1b7 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -744,6 +744,8 @@ struct zap_details { | |||
744 | struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, | 744 | struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, |
745 | pte_t pte); | 745 | pte_t pte); |
746 | 746 | ||
747 | int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, | ||
748 | unsigned long size); | ||
747 | unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, | 749 | unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, |
748 | unsigned long size, struct zap_details *); | 750 | unsigned long size, struct zap_details *); |
749 | unsigned long unmap_vmas(struct mmu_gather **tlb, | 751 | unsigned long unmap_vmas(struct mmu_gather **tlb, |
@@ -1041,7 +1043,6 @@ extern unsigned long absent_pages_in_range(unsigned long start_pfn, | |||
1041 | extern void get_pfn_range_for_nid(unsigned int nid, | 1043 | extern void get_pfn_range_for_nid(unsigned int nid, |
1042 | unsigned long *start_pfn, unsigned long *end_pfn); | 1044 | unsigned long *start_pfn, unsigned long *end_pfn); |
1043 | extern unsigned long find_min_pfn_with_active_regions(void); | 1045 | extern unsigned long find_min_pfn_with_active_regions(void); |
1044 | extern unsigned long find_max_pfn_with_active_regions(void); | ||
1045 | extern void free_bootmem_with_active_regions(int nid, | 1046 | extern void free_bootmem_with_active_regions(int nid, |
1046 | unsigned long max_low_pfn); | 1047 | unsigned long max_low_pfn); |
1047 | typedef int (*work_fn_t)(unsigned long, unsigned long, void *); | 1048 | typedef int (*work_fn_t)(unsigned long, unsigned long, void *); |
@@ -1104,6 +1105,9 @@ extern struct vm_area_struct *copy_vma(struct vm_area_struct **, | |||
1104 | unsigned long addr, unsigned long len, pgoff_t pgoff); | 1105 | unsigned long addr, unsigned long len, pgoff_t pgoff); |
1105 | extern void exit_mmap(struct mm_struct *); | 1106 | extern void exit_mmap(struct mm_struct *); |
1106 | 1107 | ||
1108 | extern int mm_take_all_locks(struct mm_struct *mm); | ||
1109 | extern void mm_drop_all_locks(struct mm_struct *mm); | ||
1110 | |||
1107 | #ifdef CONFIG_PROC_FS | 1111 | #ifdef CONFIG_PROC_FS |
1108 | /* From fs/proc/base.c. callers must _not_ hold the mm's exe_file_lock */ | 1112 | /* From fs/proc/base.c. callers must _not_ hold the mm's exe_file_lock */ |
1109 | extern void added_exe_file_vma(struct mm_struct *mm); | 1113 | extern void added_exe_file_vma(struct mm_struct *mm); |
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 746f975b58ef..386edbe2cb4e 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/rbtree.h> | 10 | #include <linux/rbtree.h> |
11 | #include <linux/rwsem.h> | 11 | #include <linux/rwsem.h> |
12 | #include <linux/completion.h> | 12 | #include <linux/completion.h> |
13 | #include <linux/cpumask.h> | ||
13 | #include <asm/page.h> | 14 | #include <asm/page.h> |
14 | #include <asm/mmu.h> | 15 | #include <asm/mmu.h> |
15 | 16 | ||
@@ -253,6 +254,9 @@ struct mm_struct { | |||
253 | struct file *exe_file; | 254 | struct file *exe_file; |
254 | unsigned long num_exe_file_vmas; | 255 | unsigned long num_exe_file_vmas; |
255 | #endif | 256 | #endif |
257 | #ifdef CONFIG_MMU_NOTIFIER | ||
258 | struct mmu_notifier_mm *mmu_notifier_mm; | ||
259 | #endif | ||
256 | }; | 260 | }; |
257 | 261 | ||
258 | #endif /* _LINUX_MM_TYPES_H */ | 262 | #endif /* _LINUX_MM_TYPES_H */ |
diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h new file mode 100644 index 000000000000..b77486d152cd --- /dev/null +++ b/include/linux/mmu_notifier.h | |||
@@ -0,0 +1,279 @@ | |||
1 | #ifndef _LINUX_MMU_NOTIFIER_H | ||
2 | #define _LINUX_MMU_NOTIFIER_H | ||
3 | |||
4 | #include <linux/list.h> | ||
5 | #include <linux/spinlock.h> | ||
6 | #include <linux/mm_types.h> | ||
7 | |||
8 | struct mmu_notifier; | ||
9 | struct mmu_notifier_ops; | ||
10 | |||
11 | #ifdef CONFIG_MMU_NOTIFIER | ||
12 | |||
13 | /* | ||
14 | * The mmu notifier_mm structure is allocated and installed in | ||
15 | * mm->mmu_notifier_mm inside the mm_take_all_locks() protected | ||
16 | * critical section and it's released only when mm_count reaches zero | ||
17 | * in mmdrop(). | ||
18 | */ | ||
19 | struct mmu_notifier_mm { | ||
20 | /* all mmu notifiers registerd in this mm are queued in this list */ | ||
21 | struct hlist_head list; | ||
22 | /* to serialize the list modifications and hlist_unhashed */ | ||
23 | spinlock_t lock; | ||
24 | }; | ||
25 | |||
26 | struct mmu_notifier_ops { | ||
27 | /* | ||
28 | * Called either by mmu_notifier_unregister or when the mm is | ||
29 | * being destroyed by exit_mmap, always before all pages are | ||
30 | * freed. This can run concurrently with other mmu notifier | ||
31 | * methods (the ones invoked outside the mm context) and it | ||
32 | * should tear down all secondary mmu mappings and freeze the | ||
33 | * secondary mmu. If this method isn't implemented you've to | ||
34 | * be sure that nothing could possibly write to the pages | ||
35 | * through the secondary mmu by the time the last thread with | ||
36 | * tsk->mm == mm exits. | ||
37 | * | ||
38 | * As side note: the pages freed after ->release returns could | ||
39 | * be immediately reallocated by the gart at an alias physical | ||
40 | * address with a different cache model, so if ->release isn't | ||
41 | * implemented because all _software_ driven memory accesses | ||
42 | * through the secondary mmu are terminated by the time the | ||
43 | * last thread of this mm quits, you've also to be sure that | ||
44 | * speculative _hardware_ operations can't allocate dirty | ||
45 | * cachelines in the cpu that could not be snooped and made | ||
46 | * coherent with the other read and write operations happening | ||
47 | * through the gart alias address, so leading to memory | ||
48 | * corruption. | ||
49 | */ | ||
50 | void (*release)(struct mmu_notifier *mn, | ||
51 | struct mm_struct *mm); | ||
52 | |||
53 | /* | ||
54 | * clear_flush_young is called after the VM is | ||
55 | * test-and-clearing the young/accessed bitflag in the | ||
56 | * pte. This way the VM will provide proper aging to the | ||
57 | * accesses to the page through the secondary MMUs and not | ||
58 | * only to the ones through the Linux pte. | ||
59 | */ | ||
60 | int (*clear_flush_young)(struct mmu_notifier *mn, | ||
61 | struct mm_struct *mm, | ||
62 | unsigned long address); | ||
63 | |||
64 | /* | ||
65 | * Before this is invoked any secondary MMU is still ok to | ||
66 | * read/write to the page previously pointed to by the Linux | ||
67 | * pte because the page hasn't been freed yet and it won't be | ||
68 | * freed until this returns. If required set_page_dirty has to | ||
69 | * be called internally to this method. | ||
70 | */ | ||
71 | void (*invalidate_page)(struct mmu_notifier *mn, | ||
72 | struct mm_struct *mm, | ||
73 | unsigned long address); | ||
74 | |||
75 | /* | ||
76 | * invalidate_range_start() and invalidate_range_end() must be | ||
77 | * paired and are called only when the mmap_sem and/or the | ||
78 | * locks protecting the reverse maps are held. The subsystem | ||
79 | * must guarantee that no additional references are taken to | ||
80 | * the pages in the range established between the call to | ||
81 | * invalidate_range_start() and the matching call to | ||
82 | * invalidate_range_end(). | ||
83 | * | ||
84 | * Invalidation of multiple concurrent ranges may be | ||
85 | * optionally permitted by the driver. Either way the | ||
86 | * establishment of sptes is forbidden in the range passed to | ||
87 | * invalidate_range_begin/end for the whole duration of the | ||
88 | * invalidate_range_begin/end critical section. | ||
89 | * | ||
90 | * invalidate_range_start() is called when all pages in the | ||
91 | * range are still mapped and have at least a refcount of one. | ||
92 | * | ||
93 | * invalidate_range_end() is called when all pages in the | ||
94 | * range have been unmapped and the pages have been freed by | ||
95 | * the VM. | ||
96 | * | ||
97 | * The VM will remove the page table entries and potentially | ||
98 | * the page between invalidate_range_start() and | ||
99 | * invalidate_range_end(). If the page must not be freed | ||
100 | * because of pending I/O or other circumstances then the | ||
101 | * invalidate_range_start() callback (or the initial mapping | ||
102 | * by the driver) must make sure that the refcount is kept | ||
103 | * elevated. | ||
104 | * | ||
105 | * If the driver increases the refcount when the pages are | ||
106 | * initially mapped into an address space then either | ||
107 | * invalidate_range_start() or invalidate_range_end() may | ||
108 | * decrease the refcount. If the refcount is decreased on | ||
109 | * invalidate_range_start() then the VM can free pages as page | ||
110 | * table entries are removed. If the refcount is only | ||
111 | * droppped on invalidate_range_end() then the driver itself | ||
112 | * will drop the last refcount but it must take care to flush | ||
113 | * any secondary tlb before doing the final free on the | ||
114 | * page. Pages will no longer be referenced by the linux | ||
115 | * address space but may still be referenced by sptes until | ||
116 | * the last refcount is dropped. | ||
117 | */ | ||
118 | void (*invalidate_range_start)(struct mmu_notifier *mn, | ||
119 | struct mm_struct *mm, | ||
120 | unsigned long start, unsigned long end); | ||
121 | void (*invalidate_range_end)(struct mmu_notifier *mn, | ||
122 | struct mm_struct *mm, | ||
123 | unsigned long start, unsigned long end); | ||
124 | }; | ||
125 | |||
126 | /* | ||
127 | * The notifier chains are protected by mmap_sem and/or the reverse map | ||
128 | * semaphores. Notifier chains are only changed when all reverse maps and | ||
129 | * the mmap_sem locks are taken. | ||
130 | * | ||
131 | * Therefore notifier chains can only be traversed when either | ||
132 | * | ||
133 | * 1. mmap_sem is held. | ||
134 | * 2. One of the reverse map locks is held (i_mmap_lock or anon_vma->lock). | ||
135 | * 3. No other concurrent thread can access the list (release) | ||
136 | */ | ||
137 | struct mmu_notifier { | ||
138 | struct hlist_node hlist; | ||
139 | const struct mmu_notifier_ops *ops; | ||
140 | }; | ||
141 | |||
142 | static inline int mm_has_notifiers(struct mm_struct *mm) | ||
143 | { | ||
144 | return unlikely(mm->mmu_notifier_mm); | ||
145 | } | ||
146 | |||
147 | extern int mmu_notifier_register(struct mmu_notifier *mn, | ||
148 | struct mm_struct *mm); | ||
149 | extern int __mmu_notifier_register(struct mmu_notifier *mn, | ||
150 | struct mm_struct *mm); | ||
151 | extern void mmu_notifier_unregister(struct mmu_notifier *mn, | ||
152 | struct mm_struct *mm); | ||
153 | extern void __mmu_notifier_mm_destroy(struct mm_struct *mm); | ||
154 | extern void __mmu_notifier_release(struct mm_struct *mm); | ||
155 | extern int __mmu_notifier_clear_flush_young(struct mm_struct *mm, | ||
156 | unsigned long address); | ||
157 | extern void __mmu_notifier_invalidate_page(struct mm_struct *mm, | ||
158 | unsigned long address); | ||
159 | extern void __mmu_notifier_invalidate_range_start(struct mm_struct *mm, | ||
160 | unsigned long start, unsigned long end); | ||
161 | extern void __mmu_notifier_invalidate_range_end(struct mm_struct *mm, | ||
162 | unsigned long start, unsigned long end); | ||
163 | |||
164 | static inline void mmu_notifier_release(struct mm_struct *mm) | ||
165 | { | ||
166 | if (mm_has_notifiers(mm)) | ||
167 | __mmu_notifier_release(mm); | ||
168 | } | ||
169 | |||
170 | static inline int mmu_notifier_clear_flush_young(struct mm_struct *mm, | ||
171 | unsigned long address) | ||
172 | { | ||
173 | if (mm_has_notifiers(mm)) | ||
174 | return __mmu_notifier_clear_flush_young(mm, address); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static inline void mmu_notifier_invalidate_page(struct mm_struct *mm, | ||
179 | unsigned long address) | ||
180 | { | ||
181 | if (mm_has_notifiers(mm)) | ||
182 | __mmu_notifier_invalidate_page(mm, address); | ||
183 | } | ||
184 | |||
185 | static inline void mmu_notifier_invalidate_range_start(struct mm_struct *mm, | ||
186 | unsigned long start, unsigned long end) | ||
187 | { | ||
188 | if (mm_has_notifiers(mm)) | ||
189 | __mmu_notifier_invalidate_range_start(mm, start, end); | ||
190 | } | ||
191 | |||
192 | static inline void mmu_notifier_invalidate_range_end(struct mm_struct *mm, | ||
193 | unsigned long start, unsigned long end) | ||
194 | { | ||
195 | if (mm_has_notifiers(mm)) | ||
196 | __mmu_notifier_invalidate_range_end(mm, start, end); | ||
197 | } | ||
198 | |||
199 | static inline void mmu_notifier_mm_init(struct mm_struct *mm) | ||
200 | { | ||
201 | mm->mmu_notifier_mm = NULL; | ||
202 | } | ||
203 | |||
204 | static inline void mmu_notifier_mm_destroy(struct mm_struct *mm) | ||
205 | { | ||
206 | if (mm_has_notifiers(mm)) | ||
207 | __mmu_notifier_mm_destroy(mm); | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * These two macros will sometime replace ptep_clear_flush. | ||
212 | * ptep_clear_flush is impleemnted as macro itself, so this also is | ||
213 | * implemented as a macro until ptep_clear_flush will converted to an | ||
214 | * inline function, to diminish the risk of compilation failure. The | ||
215 | * invalidate_page method over time can be moved outside the PT lock | ||
216 | * and these two macros can be later removed. | ||
217 | */ | ||
218 | #define ptep_clear_flush_notify(__vma, __address, __ptep) \ | ||
219 | ({ \ | ||
220 | pte_t __pte; \ | ||
221 | struct vm_area_struct *___vma = __vma; \ | ||
222 | unsigned long ___address = __address; \ | ||
223 | __pte = ptep_clear_flush(___vma, ___address, __ptep); \ | ||
224 | mmu_notifier_invalidate_page(___vma->vm_mm, ___address); \ | ||
225 | __pte; \ | ||
226 | }) | ||
227 | |||
228 | #define ptep_clear_flush_young_notify(__vma, __address, __ptep) \ | ||
229 | ({ \ | ||
230 | int __young; \ | ||
231 | struct vm_area_struct *___vma = __vma; \ | ||
232 | unsigned long ___address = __address; \ | ||
233 | __young = ptep_clear_flush_young(___vma, ___address, __ptep); \ | ||
234 | __young |= mmu_notifier_clear_flush_young(___vma->vm_mm, \ | ||
235 | ___address); \ | ||
236 | __young; \ | ||
237 | }) | ||
238 | |||
239 | #else /* CONFIG_MMU_NOTIFIER */ | ||
240 | |||
241 | static inline void mmu_notifier_release(struct mm_struct *mm) | ||
242 | { | ||
243 | } | ||
244 | |||
245 | static inline int mmu_notifier_clear_flush_young(struct mm_struct *mm, | ||
246 | unsigned long address) | ||
247 | { | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static inline void mmu_notifier_invalidate_page(struct mm_struct *mm, | ||
252 | unsigned long address) | ||
253 | { | ||
254 | } | ||
255 | |||
256 | static inline void mmu_notifier_invalidate_range_start(struct mm_struct *mm, | ||
257 | unsigned long start, unsigned long end) | ||
258 | { | ||
259 | } | ||
260 | |||
261 | static inline void mmu_notifier_invalidate_range_end(struct mm_struct *mm, | ||
262 | unsigned long start, unsigned long end) | ||
263 | { | ||
264 | } | ||
265 | |||
266 | static inline void mmu_notifier_mm_init(struct mm_struct *mm) | ||
267 | { | ||
268 | } | ||
269 | |||
270 | static inline void mmu_notifier_mm_destroy(struct mm_struct *mm) | ||
271 | { | ||
272 | } | ||
273 | |||
274 | #define ptep_clear_flush_young_notify ptep_clear_flush_young | ||
275 | #define ptep_clear_flush_notify ptep_clear_flush | ||
276 | |||
277 | #endif /* CONFIG_MMU_NOTIFIER */ | ||
278 | |||
279 | #endif /* _LINUX_MMU_NOTIFIER_H */ | ||
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 54590a9a103e..25aaccdb2f26 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h | |||
@@ -239,9 +239,6 @@ static inline void __SetPageUptodate(struct page *page) | |||
239 | { | 239 | { |
240 | smp_wmb(); | 240 | smp_wmb(); |
241 | __set_bit(PG_uptodate, &(page)->flags); | 241 | __set_bit(PG_uptodate, &(page)->flags); |
242 | #ifdef CONFIG_S390 | ||
243 | page_clear_dirty(page); | ||
244 | #endif | ||
245 | } | 242 | } |
246 | 243 | ||
247 | static inline void SetPageUptodate(struct page *page) | 244 | static inline void SetPageUptodate(struct page *page) |
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index a81d81890422..69ed3cb1197a 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h | |||
@@ -20,6 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | #define AS_EIO (__GFP_BITS_SHIFT + 0) /* IO error on async write */ | 21 | #define AS_EIO (__GFP_BITS_SHIFT + 0) /* IO error on async write */ |
22 | #define AS_ENOSPC (__GFP_BITS_SHIFT + 1) /* ENOSPC on async write */ | 22 | #define AS_ENOSPC (__GFP_BITS_SHIFT + 1) /* ENOSPC on async write */ |
23 | #define AS_MM_ALL_LOCKS (__GFP_BITS_SHIFT + 2) /* under mm_take_all_locks() */ | ||
23 | 24 | ||
24 | static inline void mapping_set_error(struct address_space *mapping, int error) | 25 | static inline void mapping_set_error(struct address_space *mapping, int error) |
25 | { | 26 | { |
@@ -142,6 +143,29 @@ static inline int page_cache_get_speculative(struct page *page) | |||
142 | return 1; | 143 | return 1; |
143 | } | 144 | } |
144 | 145 | ||
146 | /* | ||
147 | * Same as above, but add instead of inc (could just be merged) | ||
148 | */ | ||
149 | static inline int page_cache_add_speculative(struct page *page, int count) | ||
150 | { | ||
151 | VM_BUG_ON(in_interrupt()); | ||
152 | |||
153 | #if !defined(CONFIG_SMP) && defined(CONFIG_CLASSIC_RCU) | ||
154 | # ifdef CONFIG_PREEMPT | ||
155 | VM_BUG_ON(!in_atomic()); | ||
156 | # endif | ||
157 | VM_BUG_ON(page_count(page) == 0); | ||
158 | atomic_add(count, &page->_count); | ||
159 | |||
160 | #else | ||
161 | if (unlikely(!atomic_add_unless(&page->_count, count, 0))) | ||
162 | return 0; | ||
163 | #endif | ||
164 | VM_BUG_ON(PageCompound(page) && page != compound_head(page)); | ||
165 | |||
166 | return 1; | ||
167 | } | ||
168 | |||
145 | static inline int page_freeze_refs(struct page *page, int count) | 169 | static inline int page_freeze_refs(struct page *page, int count) |
146 | { | 170 | { |
147 | return likely(atomic_cmpxchg(&page->_count, count, 0) == count); | 171 | return likely(atomic_cmpxchg(&page->_count, count, 0) == count); |
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h index a1a1e618e996..91ba0b338b47 100644 --- a/include/linux/pci-aspm.h +++ b/include/linux/pci-aspm.h | |||
@@ -27,6 +27,7 @@ extern void pcie_aspm_init_link_state(struct pci_dev *pdev); | |||
27 | extern void pcie_aspm_exit_link_state(struct pci_dev *pdev); | 27 | extern void pcie_aspm_exit_link_state(struct pci_dev *pdev); |
28 | extern void pcie_aspm_pm_state_change(struct pci_dev *pdev); | 28 | extern void pcie_aspm_pm_state_change(struct pci_dev *pdev); |
29 | extern void pci_disable_link_state(struct pci_dev *pdev, int state); | 29 | extern void pci_disable_link_state(struct pci_dev *pdev, int state); |
30 | extern void pcie_no_aspm(void); | ||
30 | #else | 31 | #else |
31 | static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) | 32 | static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) |
32 | { | 33 | { |
@@ -40,6 +41,10 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) | |||
40 | static inline void pci_disable_link_state(struct pci_dev *pdev, int state) | 41 | static inline void pci_disable_link_state(struct pci_dev *pdev, int state) |
41 | { | 42 | { |
42 | } | 43 | } |
44 | |||
45 | static inline void pcie_no_aspm(void) | ||
46 | { | ||
47 | } | ||
43 | #endif | 48 | #endif |
44 | 49 | ||
45 | #ifdef CONFIG_PCIEASPM_DEBUG /* this depends on CONFIG_PCIEASPM */ | 50 | #ifdef CONFIG_PCIEASPM_DEBUG /* this depends on CONFIG_PCIEASPM */ |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 1d296d31abe0..825be3878f68 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -124,6 +124,8 @@ enum pci_dev_flags { | |||
124 | * generation too. | 124 | * generation too. |
125 | */ | 125 | */ |
126 | PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) 1, | 126 | PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) 1, |
127 | /* Device configuration is irrevocably lost if disabled into D3 */ | ||
128 | PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2, | ||
127 | }; | 129 | }; |
128 | 130 | ||
129 | typedef unsigned short __bitwise pci_bus_flags_t; | 131 | typedef unsigned short __bitwise pci_bus_flags_t; |
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 19958b929905..450684f7eaac 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h | |||
@@ -374,6 +374,7 @@ | |||
374 | #define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ | 374 | #define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ |
375 | #define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ | 375 | #define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ |
376 | #define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ | 376 | #define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ |
377 | #define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ | ||
377 | #define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ | 378 | #define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ |
378 | #define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ | 379 | #define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ |
379 | #define PCI_EXP_DEVCTL 8 /* Device Control */ | 380 | #define PCI_EXP_DEVCTL 8 /* Device Control */ |
diff --git a/include/linux/rculist.h b/include/linux/rculist.h index b0f39be08b6c..eb4443c7e05b 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h | |||
@@ -98,6 +98,34 @@ static inline void list_del_rcu(struct list_head *entry) | |||
98 | } | 98 | } |
99 | 99 | ||
100 | /** | 100 | /** |
101 | * hlist_del_init_rcu - deletes entry from hash list with re-initialization | ||
102 | * @n: the element to delete from the hash list. | ||
103 | * | ||
104 | * Note: list_unhashed() on the node return true after this. It is | ||
105 | * useful for RCU based read lockfree traversal if the writer side | ||
106 | * must know if the list entry is still hashed or already unhashed. | ||
107 | * | ||
108 | * In particular, it means that we can not poison the forward pointers | ||
109 | * that may still be used for walking the hash list and we can only | ||
110 | * zero the pprev pointer so list_unhashed() will return true after | ||
111 | * this. | ||
112 | * | ||
113 | * The caller must take whatever precautions are necessary (such as | ||
114 | * holding appropriate locks) to avoid racing with another | ||
115 | * list-mutation primitive, such as hlist_add_head_rcu() or | ||
116 | * hlist_del_rcu(), running on this same list. However, it is | ||
117 | * perfectly legal to run concurrently with the _rcu list-traversal | ||
118 | * primitives, such as hlist_for_each_entry_rcu(). | ||
119 | */ | ||
120 | static inline void hlist_del_init_rcu(struct hlist_node *n) | ||
121 | { | ||
122 | if (!hlist_unhashed(n)) { | ||
123 | __hlist_del(n); | ||
124 | n->pprev = NULL; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /** | ||
101 | * list_replace_rcu - replace old entry by new one | 129 | * list_replace_rcu - replace old entry by new one |
102 | * @old : the element to be replaced | 130 | * @old : the element to be replaced |
103 | * @new : the new element to insert | 131 | * @new : the new element to insert |
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index c5f6e54ec6ae..741d1a62cc3f 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h | |||
@@ -68,7 +68,8 @@ enum rfkill_state { | |||
68 | * @user_claim_unsupported: Whether the hardware supports exclusive | 68 | * @user_claim_unsupported: Whether the hardware supports exclusive |
69 | * RF-kill control by userspace. Set this before registering. | 69 | * RF-kill control by userspace. Set this before registering. |
70 | * @user_claim: Set when the switch is controlled exlusively by userspace. | 70 | * @user_claim: Set when the switch is controlled exlusively by userspace. |
71 | * @mutex: Guards switch state transitions | 71 | * @mutex: Guards switch state transitions. It serializes callbacks |
72 | * and also protects the state. | ||
72 | * @data: Pointer to the RF button drivers private data which will be | 73 | * @data: Pointer to the RF button drivers private data which will be |
73 | * passed along when toggling radio state. | 74 | * passed along when toggling radio state. |
74 | * @toggle_radio(): Mandatory handler to control state of the radio. | 75 | * @toggle_radio(): Mandatory handler to control state of the radio. |
@@ -89,12 +90,13 @@ struct rfkill { | |||
89 | const char *name; | 90 | const char *name; |
90 | enum rfkill_type type; | 91 | enum rfkill_type type; |
91 | 92 | ||
92 | enum rfkill_state state; | ||
93 | bool user_claim_unsupported; | 93 | bool user_claim_unsupported; |
94 | bool user_claim; | 94 | bool user_claim; |
95 | 95 | ||
96 | /* the mutex serializes callbacks and also protects | ||
97 | * the state */ | ||
96 | struct mutex mutex; | 98 | struct mutex mutex; |
97 | 99 | enum rfkill_state state; | |
98 | void *data; | 100 | void *data; |
99 | int (*toggle_radio)(void *data, enum rfkill_state state); | 101 | int (*toggle_radio)(void *data, enum rfkill_state state); |
100 | int (*get_state)(void *data, enum rfkill_state *state); | 102 | int (*get_state)(void *data, enum rfkill_state *state); |
diff --git a/include/linux/rmap.h b/include/linux/rmap.h index 1383692ac5bd..69407f85e10b 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h | |||
@@ -26,6 +26,14 @@ | |||
26 | */ | 26 | */ |
27 | struct anon_vma { | 27 | struct anon_vma { |
28 | spinlock_t lock; /* Serialize access to vma list */ | 28 | spinlock_t lock; /* Serialize access to vma list */ |
29 | /* | ||
30 | * NOTE: the LSB of the head.next is set by | ||
31 | * mm_take_all_locks() _after_ taking the above lock. So the | ||
32 | * head must only be read/written after taking the above lock | ||
33 | * to be sure to see a valid next pointer. The LSB bit itself | ||
34 | * is serialized by a system wide lock only visible to | ||
35 | * mm_take_all_locks() (mm_all_locks_mutex). | ||
36 | */ | ||
29 | struct list_head head; /* List of private "related" vmas */ | 37 | struct list_head head; /* List of private "related" vmas */ |
30 | }; | 38 | }; |
31 | 39 | ||
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7ea44f6621f2..a640385e0598 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -316,7 +316,10 @@ struct sk_buff { | |||
316 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 316 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
317 | __u8 ndisc_nodetype:2; | 317 | __u8 ndisc_nodetype:2; |
318 | #endif | 318 | #endif |
319 | /* 14 bit hole */ | 319 | #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) |
320 | __u8 do_not_encrypt:1; | ||
321 | #endif | ||
322 | /* 0/13/14 bit hole */ | ||
320 | 323 | ||
321 | #ifdef CONFIG_NET_DMA | 324 | #ifdef CONFIG_NET_DMA |
322 | dma_cookie_t dma_cookie; | 325 | dma_cookie_t dma_cookie; |
diff --git a/include/linux/snmp.h b/include/linux/snmp.h index 5df62ef1280c..7a6e6bba4a71 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h | |||
@@ -214,6 +214,8 @@ enum | |||
214 | LINUX_MIB_TCPDSACKIGNOREDOLD, /* TCPSACKIgnoredOld */ | 214 | LINUX_MIB_TCPDSACKIGNOREDOLD, /* TCPSACKIgnoredOld */ |
215 | LINUX_MIB_TCPDSACKIGNOREDNOUNDO, /* TCPSACKIgnoredNoUndo */ | 215 | LINUX_MIB_TCPDSACKIGNOREDNOUNDO, /* TCPSACKIgnoredNoUndo */ |
216 | LINUX_MIB_TCPSPURIOUSRTOS, /* TCPSpuriousRTOs */ | 216 | LINUX_MIB_TCPSPURIOUSRTOS, /* TCPSpuriousRTOs */ |
217 | LINUX_MIB_TCPMD5NOTFOUND, /* TCPMD5NotFound */ | ||
218 | LINUX_MIB_TCPMD5UNEXPECTED, /* TCPMD5Unexpected */ | ||
217 | __LINUX_MIB_MAX | 219 | __LINUX_MIB_MAX |
218 | }; | 220 | }; |
219 | 221 | ||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4dd3d93e1960..b52721008be8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -206,8 +206,6 @@ struct ieee80211_bss_conf { | |||
206 | * These flags are used with the @flags member of &ieee80211_tx_info. | 206 | * These flags are used with the @flags member of &ieee80211_tx_info. |
207 | * | 207 | * |
208 | * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. | 208 | * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. |
209 | * @IEEE80211_TX_CTL_DO_NOT_ENCRYPT: send this frame without encryption; | ||
210 | * e.g., for EAPOL frame | ||
211 | * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame | 209 | * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame |
212 | * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., | 210 | * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., |
213 | * for combined 802.11g / 802.11b networks) | 211 | * for combined 802.11g / 802.11b networks) |
@@ -220,7 +218,6 @@ struct ieee80211_bss_conf { | |||
220 | * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD | 218 | * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD |
221 | * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the | 219 | * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the |
222 | * through set_retry_limit configured long retry value | 220 | * through set_retry_limit configured long retry value |
223 | * @IEEE80211_TX_CTL_EAPOL_FRAME: internal to mac80211 | ||
224 | * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon | 221 | * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon |
225 | * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU | 222 | * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU |
226 | * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number | 223 | * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number |
@@ -253,7 +250,6 @@ struct ieee80211_bss_conf { | |||
253 | */ | 250 | */ |
254 | enum mac80211_tx_control_flags { | 251 | enum mac80211_tx_control_flags { |
255 | IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), | 252 | IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), |
256 | IEEE80211_TX_CTL_DO_NOT_ENCRYPT = BIT(1), | ||
257 | IEEE80211_TX_CTL_USE_RTS_CTS = BIT(2), | 253 | IEEE80211_TX_CTL_USE_RTS_CTS = BIT(2), |
258 | IEEE80211_TX_CTL_USE_CTS_PROTECT = BIT(3), | 254 | IEEE80211_TX_CTL_USE_CTS_PROTECT = BIT(3), |
259 | IEEE80211_TX_CTL_NO_ACK = BIT(4), | 255 | IEEE80211_TX_CTL_NO_ACK = BIT(4), |
@@ -263,7 +259,6 @@ enum mac80211_tx_control_flags { | |||
263 | IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8), | 259 | IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8), |
264 | IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9), | 260 | IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9), |
265 | IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10), | 261 | IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10), |
266 | IEEE80211_TX_CTL_EAPOL_FRAME = BIT(11), | ||
267 | IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12), | 262 | IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12), |
268 | IEEE80211_TX_CTL_AMPDU = BIT(13), | 263 | IEEE80211_TX_CTL_AMPDU = BIT(13), |
269 | IEEE80211_TX_CTL_OFDM_HT = BIT(14), | 264 | IEEE80211_TX_CTL_OFDM_HT = BIT(14), |
@@ -323,7 +318,6 @@ struct ieee80211_tx_info { | |||
323 | struct ieee80211_vif *vif; | 318 | struct ieee80211_vif *vif; |
324 | struct ieee80211_key_conf *hw_key; | 319 | struct ieee80211_key_conf *hw_key; |
325 | unsigned long jiffies; | 320 | unsigned long jiffies; |
326 | int ifindex; | ||
327 | u16 aid; | 321 | u16 aid; |
328 | s8 rts_cts_rate_idx, alt_retry_rate_idx; | 322 | s8 rts_cts_rate_idx, alt_retry_rate_idx; |
329 | u8 retry_limit; | 323 | u8 retry_limit; |
@@ -746,7 +740,6 @@ enum ieee80211_tkip_key_type { | |||
746 | * Measurement, Channel Switch, Quieting, TPC | 740 | * Measurement, Channel Switch, Quieting, TPC |
747 | */ | 741 | */ |
748 | enum ieee80211_hw_flags { | 742 | enum ieee80211_hw_flags { |
749 | IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0, | ||
750 | IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, | 743 | IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, |
751 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, | 744 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, |
752 | IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, | 745 | IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, |
diff --git a/init/Kconfig b/init/Kconfig index 43d6989c275f..250e02c8f8f9 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -802,6 +802,10 @@ config PROC_PAGE_MONITOR | |||
802 | 802 | ||
803 | endmenu # General setup | 803 | endmenu # General setup |
804 | 804 | ||
805 | config HAVE_GENERIC_DMA_COHERENT | ||
806 | bool | ||
807 | default n | ||
808 | |||
805 | config SLABINFO | 809 | config SLABINFO |
806 | bool | 810 | bool |
807 | depends on PROC_FS | 811 | depends on PROC_FS |
diff --git a/init/calibrate.c b/init/calibrate.c index 7963e3fc51d9..a379c9061199 100644 --- a/init/calibrate.c +++ b/init/calibrate.c | |||
@@ -170,7 +170,7 @@ void __cpuinit calibrate_delay(void) | |||
170 | loops_per_jiffy &= ~loopbit; | 170 | loops_per_jiffy &= ~loopbit; |
171 | } | 171 | } |
172 | } | 172 | } |
173 | printk(KERN_INFO "%lu.%02lu BogoMIPS (lpj=%lu)\n", | 173 | printk(KERN_CONT "%lu.%02lu BogoMIPS (lpj=%lu)\n", |
174 | loops_per_jiffy/(500000/HZ), | 174 | loops_per_jiffy/(500000/HZ), |
175 | (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy); | 175 | (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy); |
176 | } | 176 | } |
diff --git a/init/main.c b/init/main.c index 20fdc9884b77..9c3b68b86ca0 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -635,10 +635,11 @@ asmlinkage void __init start_kernel(void) | |||
635 | 635 | ||
636 | #ifdef CONFIG_BLK_DEV_INITRD | 636 | #ifdef CONFIG_BLK_DEV_INITRD |
637 | if (initrd_start && !initrd_below_start_ok && | 637 | if (initrd_start && !initrd_below_start_ok && |
638 | page_to_pfn(virt_to_page(initrd_start)) < min_low_pfn) { | 638 | page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) { |
639 | printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " | 639 | printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " |
640 | "disabling it.\n", | 640 | "disabling it.\n", |
641 | page_to_pfn(virt_to_page(initrd_start)), min_low_pfn); | 641 | page_to_pfn(virt_to_page((void *)initrd_start)), |
642 | min_low_pfn); | ||
642 | initrd_start = 0; | 643 | initrd_start = 0; |
643 | } | 644 | } |
644 | #endif | 645 | #endif |
diff --git a/kernel/Makefile b/kernel/Makefile index 54f69837d35a..4e1d7df7c3e2 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
@@ -84,6 +84,7 @@ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o | |||
84 | obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o | 84 | obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o |
85 | obj-$(CONFIG_MARKERS) += marker.o | 85 | obj-$(CONFIG_MARKERS) += marker.o |
86 | obj-$(CONFIG_LATENCYTOP) += latencytop.o | 86 | obj-$(CONFIG_LATENCYTOP) += latencytop.o |
87 | obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o | ||
87 | obj-$(CONFIG_FTRACE) += trace/ | 88 | obj-$(CONFIG_FTRACE) += trace/ |
88 | obj-$(CONFIG_TRACING) += trace/ | 89 | obj-$(CONFIG_TRACING) += trace/ |
89 | obj-$(CONFIG_SMP) += sched_cpupri.o | 90 | obj-$(CONFIG_SMP) += sched_cpupri.o |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 657f8f8d93a5..13932abde159 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -355,6 +355,17 @@ static struct css_set *find_existing_css_set( | |||
355 | return NULL; | 355 | return NULL; |
356 | } | 356 | } |
357 | 357 | ||
358 | static void free_cg_links(struct list_head *tmp) | ||
359 | { | ||
360 | struct cg_cgroup_link *link; | ||
361 | struct cg_cgroup_link *saved_link; | ||
362 | |||
363 | list_for_each_entry_safe(link, saved_link, tmp, cgrp_link_list) { | ||
364 | list_del(&link->cgrp_link_list); | ||
365 | kfree(link); | ||
366 | } | ||
367 | } | ||
368 | |||
358 | /* | 369 | /* |
359 | * allocate_cg_links() allocates "count" cg_cgroup_link structures | 370 | * allocate_cg_links() allocates "count" cg_cgroup_link structures |
360 | * and chains them on tmp through their cgrp_link_list fields. Returns 0 on | 371 | * and chains them on tmp through their cgrp_link_list fields. Returns 0 on |
@@ -363,17 +374,12 @@ static struct css_set *find_existing_css_set( | |||
363 | static int allocate_cg_links(int count, struct list_head *tmp) | 374 | static int allocate_cg_links(int count, struct list_head *tmp) |
364 | { | 375 | { |
365 | struct cg_cgroup_link *link; | 376 | struct cg_cgroup_link *link; |
366 | struct cg_cgroup_link *saved_link; | ||
367 | int i; | 377 | int i; |
368 | INIT_LIST_HEAD(tmp); | 378 | INIT_LIST_HEAD(tmp); |
369 | for (i = 0; i < count; i++) { | 379 | for (i = 0; i < count; i++) { |
370 | link = kmalloc(sizeof(*link), GFP_KERNEL); | 380 | link = kmalloc(sizeof(*link), GFP_KERNEL); |
371 | if (!link) { | 381 | if (!link) { |
372 | list_for_each_entry_safe(link, saved_link, tmp, | 382 | free_cg_links(tmp); |
373 | cgrp_link_list) { | ||
374 | list_del(&link->cgrp_link_list); | ||
375 | kfree(link); | ||
376 | } | ||
377 | return -ENOMEM; | 383 | return -ENOMEM; |
378 | } | 384 | } |
379 | list_add(&link->cgrp_link_list, tmp); | 385 | list_add(&link->cgrp_link_list, tmp); |
@@ -381,17 +387,6 @@ static int allocate_cg_links(int count, struct list_head *tmp) | |||
381 | return 0; | 387 | return 0; |
382 | } | 388 | } |
383 | 389 | ||
384 | static void free_cg_links(struct list_head *tmp) | ||
385 | { | ||
386 | struct cg_cgroup_link *link; | ||
387 | struct cg_cgroup_link *saved_link; | ||
388 | |||
389 | list_for_each_entry_safe(link, saved_link, tmp, cgrp_link_list) { | ||
390 | list_del(&link->cgrp_link_list); | ||
391 | kfree(link); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | /* | 390 | /* |
396 | * find_css_set() takes an existing cgroup group and a | 391 | * find_css_set() takes an existing cgroup group and a |
397 | * cgroup object, and returns a css_set object that's | 392 | * cgroup object, and returns a css_set object that's |
@@ -956,7 +951,6 @@ static int cgroup_get_sb(struct file_system_type *fs_type, | |||
956 | struct super_block *sb; | 951 | struct super_block *sb; |
957 | struct cgroupfs_root *root; | 952 | struct cgroupfs_root *root; |
958 | struct list_head tmp_cg_links; | 953 | struct list_head tmp_cg_links; |
959 | INIT_LIST_HEAD(&tmp_cg_links); | ||
960 | 954 | ||
961 | /* First find the desired set of subsystems */ | 955 | /* First find the desired set of subsystems */ |
962 | ret = parse_cgroupfs_options(data, &opts); | 956 | ret = parse_cgroupfs_options(data, &opts); |
@@ -1424,14 +1418,17 @@ static ssize_t cgroup_write_string(struct cgroup *cgrp, struct cftype *cft, | |||
1424 | if (buffer == NULL) | 1418 | if (buffer == NULL) |
1425 | return -ENOMEM; | 1419 | return -ENOMEM; |
1426 | } | 1420 | } |
1427 | if (nbytes && copy_from_user(buffer, userbuf, nbytes)) | 1421 | if (nbytes && copy_from_user(buffer, userbuf, nbytes)) { |
1428 | return -EFAULT; | 1422 | retval = -EFAULT; |
1423 | goto out; | ||
1424 | } | ||
1429 | 1425 | ||
1430 | buffer[nbytes] = 0; /* nul-terminate */ | 1426 | buffer[nbytes] = 0; /* nul-terminate */ |
1431 | strstrip(buffer); | 1427 | strstrip(buffer); |
1432 | retval = cft->write_string(cgrp, cft, buffer); | 1428 | retval = cft->write_string(cgrp, cft, buffer); |
1433 | if (!retval) | 1429 | if (!retval) |
1434 | retval = nbytes; | 1430 | retval = nbytes; |
1431 | out: | ||
1435 | if (buffer != local_buffer) | 1432 | if (buffer != local_buffer) |
1436 | kfree(buffer); | 1433 | kfree(buffer); |
1437 | return retval; | 1434 | return retval; |
@@ -2371,7 +2368,7 @@ static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
2371 | return cgroup_create(c_parent, dentry, mode | S_IFDIR); | 2368 | return cgroup_create(c_parent, dentry, mode | S_IFDIR); |
2372 | } | 2369 | } |
2373 | 2370 | ||
2374 | static inline int cgroup_has_css_refs(struct cgroup *cgrp) | 2371 | static int cgroup_has_css_refs(struct cgroup *cgrp) |
2375 | { | 2372 | { |
2376 | /* Check the reference count on each subsystem. Since we | 2373 | /* Check the reference count on each subsystem. Since we |
2377 | * already established that there are no tasks in the | 2374 | * already established that there are no tasks in the |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 29510d68338a..e202a68d1cc1 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -455,3 +455,28 @@ out: | |||
455 | #endif /* CONFIG_PM_SLEEP_SMP */ | 455 | #endif /* CONFIG_PM_SLEEP_SMP */ |
456 | 456 | ||
457 | #endif /* CONFIG_SMP */ | 457 | #endif /* CONFIG_SMP */ |
458 | |||
459 | /* | ||
460 | * cpu_bit_bitmap[] is a special, "compressed" data structure that | ||
461 | * represents all NR_CPUS bits binary values of 1<<nr. | ||
462 | * | ||
463 | * It is used by cpumask_of_cpu() to get a constant address to a CPU | ||
464 | * mask value that has a single bit set only. | ||
465 | */ | ||
466 | |||
467 | /* cpu_bit_bitmap[0] is empty - so we can back into it */ | ||
468 | #define MASK_DECLARE_1(x) [x+1][0] = 1UL << (x) | ||
469 | #define MASK_DECLARE_2(x) MASK_DECLARE_1(x), MASK_DECLARE_1(x+1) | ||
470 | #define MASK_DECLARE_4(x) MASK_DECLARE_2(x), MASK_DECLARE_2(x+2) | ||
471 | #define MASK_DECLARE_8(x) MASK_DECLARE_4(x), MASK_DECLARE_4(x+4) | ||
472 | |||
473 | const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = { | ||
474 | |||
475 | MASK_DECLARE_8(0), MASK_DECLARE_8(8), | ||
476 | MASK_DECLARE_8(16), MASK_DECLARE_8(24), | ||
477 | #if BITS_PER_LONG > 32 | ||
478 | MASK_DECLARE_8(32), MASK_DECLARE_8(40), | ||
479 | MASK_DECLARE_8(48), MASK_DECLARE_8(56), | ||
480 | #endif | ||
481 | }; | ||
482 | EXPORT_SYMBOL_GPL(cpu_bit_bitmap); | ||
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 91cf85b36dd5..d5ab79cf516d 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -54,7 +54,6 @@ | |||
54 | #include <asm/uaccess.h> | 54 | #include <asm/uaccess.h> |
55 | #include <asm/atomic.h> | 55 | #include <asm/atomic.h> |
56 | #include <linux/mutex.h> | 56 | #include <linux/mutex.h> |
57 | #include <linux/kfifo.h> | ||
58 | #include <linux/workqueue.h> | 57 | #include <linux/workqueue.h> |
59 | #include <linux/cgroup.h> | 58 | #include <linux/cgroup.h> |
60 | 59 | ||
@@ -486,13 +485,38 @@ static int cpusets_overlap(struct cpuset *a, struct cpuset *b) | |||
486 | static void | 485 | static void |
487 | update_domain_attr(struct sched_domain_attr *dattr, struct cpuset *c) | 486 | update_domain_attr(struct sched_domain_attr *dattr, struct cpuset *c) |
488 | { | 487 | { |
489 | if (!dattr) | ||
490 | return; | ||
491 | if (dattr->relax_domain_level < c->relax_domain_level) | 488 | if (dattr->relax_domain_level < c->relax_domain_level) |
492 | dattr->relax_domain_level = c->relax_domain_level; | 489 | dattr->relax_domain_level = c->relax_domain_level; |
493 | return; | 490 | return; |
494 | } | 491 | } |
495 | 492 | ||
493 | static void | ||
494 | update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c) | ||
495 | { | ||
496 | LIST_HEAD(q); | ||
497 | |||
498 | list_add(&c->stack_list, &q); | ||
499 | while (!list_empty(&q)) { | ||
500 | struct cpuset *cp; | ||
501 | struct cgroup *cont; | ||
502 | struct cpuset *child; | ||
503 | |||
504 | cp = list_first_entry(&q, struct cpuset, stack_list); | ||
505 | list_del(q.next); | ||
506 | |||
507 | if (cpus_empty(cp->cpus_allowed)) | ||
508 | continue; | ||
509 | |||
510 | if (is_sched_load_balance(cp)) | ||
511 | update_domain_attr(dattr, cp); | ||
512 | |||
513 | list_for_each_entry(cont, &cp->css.cgroup->children, sibling) { | ||
514 | child = cgroup_cs(cont); | ||
515 | list_add_tail(&child->stack_list, &q); | ||
516 | } | ||
517 | } | ||
518 | } | ||
519 | |||
496 | /* | 520 | /* |
497 | * rebuild_sched_domains() | 521 | * rebuild_sched_domains() |
498 | * | 522 | * |
@@ -532,7 +556,7 @@ update_domain_attr(struct sched_domain_attr *dattr, struct cpuset *c) | |||
532 | * So the reverse nesting would risk an ABBA deadlock. | 556 | * So the reverse nesting would risk an ABBA deadlock. |
533 | * | 557 | * |
534 | * The three key local variables below are: | 558 | * The three key local variables below are: |
535 | * q - a kfifo queue of cpuset pointers, used to implement a | 559 | * q - a linked-list queue of cpuset pointers, used to implement a |
536 | * top-down scan of all cpusets. This scan loads a pointer | 560 | * top-down scan of all cpusets. This scan loads a pointer |
537 | * to each cpuset marked is_sched_load_balance into the | 561 | * to each cpuset marked is_sched_load_balance into the |
538 | * array 'csa'. For our purposes, rebuilding the schedulers | 562 | * array 'csa'. For our purposes, rebuilding the schedulers |
@@ -567,7 +591,7 @@ update_domain_attr(struct sched_domain_attr *dattr, struct cpuset *c) | |||
567 | 591 | ||
568 | void rebuild_sched_domains(void) | 592 | void rebuild_sched_domains(void) |
569 | { | 593 | { |
570 | struct kfifo *q; /* queue of cpusets to be scanned */ | 594 | LIST_HEAD(q); /* queue of cpusets to be scanned*/ |
571 | struct cpuset *cp; /* scans q */ | 595 | struct cpuset *cp; /* scans q */ |
572 | struct cpuset **csa; /* array of all cpuset ptrs */ | 596 | struct cpuset **csa; /* array of all cpuset ptrs */ |
573 | int csn; /* how many cpuset ptrs in csa so far */ | 597 | int csn; /* how many cpuset ptrs in csa so far */ |
@@ -577,7 +601,6 @@ void rebuild_sched_domains(void) | |||
577 | int ndoms; /* number of sched domains in result */ | 601 | int ndoms; /* number of sched domains in result */ |
578 | int nslot; /* next empty doms[] cpumask_t slot */ | 602 | int nslot; /* next empty doms[] cpumask_t slot */ |
579 | 603 | ||
580 | q = NULL; | ||
581 | csa = NULL; | 604 | csa = NULL; |
582 | doms = NULL; | 605 | doms = NULL; |
583 | dattr = NULL; | 606 | dattr = NULL; |
@@ -591,35 +614,42 @@ void rebuild_sched_domains(void) | |||
591 | dattr = kmalloc(sizeof(struct sched_domain_attr), GFP_KERNEL); | 614 | dattr = kmalloc(sizeof(struct sched_domain_attr), GFP_KERNEL); |
592 | if (dattr) { | 615 | if (dattr) { |
593 | *dattr = SD_ATTR_INIT; | 616 | *dattr = SD_ATTR_INIT; |
594 | update_domain_attr(dattr, &top_cpuset); | 617 | update_domain_attr_tree(dattr, &top_cpuset); |
595 | } | 618 | } |
596 | *doms = top_cpuset.cpus_allowed; | 619 | *doms = top_cpuset.cpus_allowed; |
597 | goto rebuild; | 620 | goto rebuild; |
598 | } | 621 | } |
599 | 622 | ||
600 | q = kfifo_alloc(number_of_cpusets * sizeof(cp), GFP_KERNEL, NULL); | ||
601 | if (IS_ERR(q)) | ||
602 | goto done; | ||
603 | csa = kmalloc(number_of_cpusets * sizeof(cp), GFP_KERNEL); | 623 | csa = kmalloc(number_of_cpusets * sizeof(cp), GFP_KERNEL); |
604 | if (!csa) | 624 | if (!csa) |
605 | goto done; | 625 | goto done; |
606 | csn = 0; | 626 | csn = 0; |
607 | 627 | ||
608 | cp = &top_cpuset; | 628 | list_add(&top_cpuset.stack_list, &q); |
609 | __kfifo_put(q, (void *)&cp, sizeof(cp)); | 629 | while (!list_empty(&q)) { |
610 | while (__kfifo_get(q, (void *)&cp, sizeof(cp))) { | ||
611 | struct cgroup *cont; | 630 | struct cgroup *cont; |
612 | struct cpuset *child; /* scans child cpusets of cp */ | 631 | struct cpuset *child; /* scans child cpusets of cp */ |
613 | 632 | ||
633 | cp = list_first_entry(&q, struct cpuset, stack_list); | ||
634 | list_del(q.next); | ||
635 | |||
614 | if (cpus_empty(cp->cpus_allowed)) | 636 | if (cpus_empty(cp->cpus_allowed)) |
615 | continue; | 637 | continue; |
616 | 638 | ||
617 | if (is_sched_load_balance(cp)) | 639 | /* |
640 | * All child cpusets contain a subset of the parent's cpus, so | ||
641 | * just skip them, and then we call update_domain_attr_tree() | ||
642 | * to calc relax_domain_level of the corresponding sched | ||
643 | * domain. | ||
644 | */ | ||
645 | if (is_sched_load_balance(cp)) { | ||
618 | csa[csn++] = cp; | 646 | csa[csn++] = cp; |
647 | continue; | ||
648 | } | ||
619 | 649 | ||
620 | list_for_each_entry(cont, &cp->css.cgroup->children, sibling) { | 650 | list_for_each_entry(cont, &cp->css.cgroup->children, sibling) { |
621 | child = cgroup_cs(cont); | 651 | child = cgroup_cs(cont); |
622 | __kfifo_put(q, (void *)&child, sizeof(cp)); | 652 | list_add_tail(&child->stack_list, &q); |
623 | } | 653 | } |
624 | } | 654 | } |
625 | 655 | ||
@@ -686,7 +716,7 @@ restart: | |||
686 | cpus_or(*dp, *dp, b->cpus_allowed); | 716 | cpus_or(*dp, *dp, b->cpus_allowed); |
687 | b->pn = -1; | 717 | b->pn = -1; |
688 | if (dattr) | 718 | if (dattr) |
689 | update_domain_attr(dattr | 719 | update_domain_attr_tree(dattr |
690 | + nslot, b); | 720 | + nslot, b); |
691 | } | 721 | } |
692 | } | 722 | } |
@@ -702,8 +732,6 @@ rebuild: | |||
702 | put_online_cpus(); | 732 | put_online_cpus(); |
703 | 733 | ||
704 | done: | 734 | done: |
705 | if (q && !IS_ERR(q)) | ||
706 | kfifo_free(q); | ||
707 | kfree(csa); | 735 | kfree(csa); |
708 | /* Don't kfree(doms) -- partition_sched_domains() does that. */ | 736 | /* Don't kfree(doms) -- partition_sched_domains() does that. */ |
709 | /* Don't kfree(dattr) -- partition_sched_domains() does that. */ | 737 | /* Don't kfree(dattr) -- partition_sched_domains() does that. */ |
@@ -1833,24 +1861,21 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs) | |||
1833 | */ | 1861 | */ |
1834 | static void scan_for_empty_cpusets(const struct cpuset *root) | 1862 | static void scan_for_empty_cpusets(const struct cpuset *root) |
1835 | { | 1863 | { |
1864 | LIST_HEAD(queue); | ||
1836 | struct cpuset *cp; /* scans cpusets being updated */ | 1865 | struct cpuset *cp; /* scans cpusets being updated */ |
1837 | struct cpuset *child; /* scans child cpusets of cp */ | 1866 | struct cpuset *child; /* scans child cpusets of cp */ |
1838 | struct list_head queue; | ||
1839 | struct cgroup *cont; | 1867 | struct cgroup *cont; |
1840 | nodemask_t oldmems; | 1868 | nodemask_t oldmems; |
1841 | 1869 | ||
1842 | INIT_LIST_HEAD(&queue); | ||
1843 | |||
1844 | list_add_tail((struct list_head *)&root->stack_list, &queue); | 1870 | list_add_tail((struct list_head *)&root->stack_list, &queue); |
1845 | 1871 | ||
1846 | while (!list_empty(&queue)) { | 1872 | while (!list_empty(&queue)) { |
1847 | cp = container_of(queue.next, struct cpuset, stack_list); | 1873 | cp = list_first_entry(&queue, struct cpuset, stack_list); |
1848 | list_del(queue.next); | 1874 | list_del(queue.next); |
1849 | list_for_each_entry(cont, &cp->css.cgroup->children, sibling) { | 1875 | list_for_each_entry(cont, &cp->css.cgroup->children, sibling) { |
1850 | child = cgroup_cs(cont); | 1876 | child = cgroup_cs(cont); |
1851 | list_add_tail(&child->stack_list, &queue); | 1877 | list_add_tail(&child->stack_list, &queue); |
1852 | } | 1878 | } |
1853 | cont = cp->css.cgroup; | ||
1854 | 1879 | ||
1855 | /* Continue past cpusets with all cpus, mems online */ | 1880 | /* Continue past cpusets with all cpus, mems online */ |
1856 | if (cpus_subset(cp->cpus_allowed, cpu_online_map) && | 1881 | if (cpus_subset(cp->cpus_allowed, cpu_online_map) && |
diff --git a/kernel/dma-coherent.c b/kernel/dma-coherent.c new file mode 100644 index 000000000000..7517115a8cce --- /dev/null +++ b/kernel/dma-coherent.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * Coherent per-device memory handling. | ||
3 | * Borrowed from i386 | ||
4 | */ | ||
5 | #include <linux/kernel.h> | ||
6 | #include <linux/dma-mapping.h> | ||
7 | |||
8 | struct dma_coherent_mem { | ||
9 | void *virt_base; | ||
10 | u32 device_base; | ||
11 | int size; | ||
12 | int flags; | ||
13 | unsigned long *bitmap; | ||
14 | }; | ||
15 | |||
16 | int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
17 | dma_addr_t device_addr, size_t size, int flags) | ||
18 | { | ||
19 | void __iomem *mem_base = NULL; | ||
20 | int pages = size >> PAGE_SHIFT; | ||
21 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
22 | |||
23 | if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) | ||
24 | goto out; | ||
25 | if (!size) | ||
26 | goto out; | ||
27 | if (dev->dma_mem) | ||
28 | goto out; | ||
29 | |||
30 | /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ | ||
31 | |||
32 | mem_base = ioremap(bus_addr, size); | ||
33 | if (!mem_base) | ||
34 | goto out; | ||
35 | |||
36 | dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); | ||
37 | if (!dev->dma_mem) | ||
38 | goto out; | ||
39 | dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
40 | if (!dev->dma_mem->bitmap) | ||
41 | goto free1_out; | ||
42 | |||
43 | dev->dma_mem->virt_base = mem_base; | ||
44 | dev->dma_mem->device_base = device_addr; | ||
45 | dev->dma_mem->size = pages; | ||
46 | dev->dma_mem->flags = flags; | ||
47 | |||
48 | if (flags & DMA_MEMORY_MAP) | ||
49 | return DMA_MEMORY_MAP; | ||
50 | |||
51 | return DMA_MEMORY_IO; | ||
52 | |||
53 | free1_out: | ||
54 | kfree(dev->dma_mem); | ||
55 | out: | ||
56 | if (mem_base) | ||
57 | iounmap(mem_base); | ||
58 | return 0; | ||
59 | } | ||
60 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
61 | |||
62 | void dma_release_declared_memory(struct device *dev) | ||
63 | { | ||
64 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
65 | |||
66 | if (!mem) | ||
67 | return; | ||
68 | dev->dma_mem = NULL; | ||
69 | iounmap(mem->virt_base); | ||
70 | kfree(mem->bitmap); | ||
71 | kfree(mem); | ||
72 | } | ||
73 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
74 | |||
75 | void *dma_mark_declared_memory_occupied(struct device *dev, | ||
76 | dma_addr_t device_addr, size_t size) | ||
77 | { | ||
78 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
79 | int pos, err; | ||
80 | int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1); | ||
81 | |||
82 | pages >>= PAGE_SHIFT; | ||
83 | |||
84 | if (!mem) | ||
85 | return ERR_PTR(-EINVAL); | ||
86 | |||
87 | pos = (device_addr - mem->device_base) >> PAGE_SHIFT; | ||
88 | err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); | ||
89 | if (err != 0) | ||
90 | return ERR_PTR(err); | ||
91 | return mem->virt_base + (pos << PAGE_SHIFT); | ||
92 | } | ||
93 | EXPORT_SYMBOL(dma_mark_declared_memory_occupied); | ||
94 | |||
95 | /** | ||
96 | * Try to allocate memory from the per-device coherent area. | ||
97 | * | ||
98 | * @dev: device from which we allocate memory | ||
99 | * @size: size of requested memory area | ||
100 | * @dma_handle: This will be filled with the correct dma handle | ||
101 | * @ret: This pointer will be filled with the virtual address | ||
102 | * to allocated area. | ||
103 | * | ||
104 | * This function should be only called from per-arch %dma_alloc_coherent() | ||
105 | * to support allocation from per-device coherent memory pools. | ||
106 | * | ||
107 | * Returns 0 if dma_alloc_coherent should continue with allocating from | ||
108 | * generic memory areas, or !0 if dma_alloc_coherent should return %ret. | ||
109 | */ | ||
110 | int dma_alloc_from_coherent(struct device *dev, ssize_t size, | ||
111 | dma_addr_t *dma_handle, void **ret) | ||
112 | { | ||
113 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
114 | int order = get_order(size); | ||
115 | |||
116 | if (mem) { | ||
117 | int page = bitmap_find_free_region(mem->bitmap, mem->size, | ||
118 | order); | ||
119 | if (page >= 0) { | ||
120 | *dma_handle = mem->device_base + (page << PAGE_SHIFT); | ||
121 | *ret = mem->virt_base + (page << PAGE_SHIFT); | ||
122 | memset(*ret, 0, size); | ||
123 | } else if (mem->flags & DMA_MEMORY_EXCLUSIVE) | ||
124 | *ret = NULL; | ||
125 | } | ||
126 | return (mem != NULL); | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * Try to free the memory allocated from per-device coherent memory pool. | ||
131 | * @dev: device from which the memory was allocated | ||
132 | * @order: the order of pages allocated | ||
133 | * @vaddr: virtual address of allocated pages | ||
134 | * | ||
135 | * This checks whether the memory was allocated from the per-device | ||
136 | * coherent memory pool and if so, releases that memory. | ||
137 | * | ||
138 | * Returns 1 if we correctly released the memory, or 0 if | ||
139 | * %dma_release_coherent() should proceed with releasing memory from | ||
140 | * generic pools. | ||
141 | */ | ||
142 | int dma_release_from_coherent(struct device *dev, int order, void *vaddr) | ||
143 | { | ||
144 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
145 | |||
146 | if (mem && vaddr >= mem->virt_base && vaddr < | ||
147 | (mem->virt_base + (mem->size << PAGE_SHIFT))) { | ||
148 | int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; | ||
149 | |||
150 | bitmap_release_region(mem->bitmap, page, order); | ||
151 | return 1; | ||
152 | } | ||
153 | return 0; | ||
154 | } | ||
diff --git a/kernel/fork.c b/kernel/fork.c index 8214ba7c8bb1..7ce2ebe84796 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/key.h> | 27 | #include <linux/key.h> |
28 | #include <linux/binfmts.h> | 28 | #include <linux/binfmts.h> |
29 | #include <linux/mman.h> | 29 | #include <linux/mman.h> |
30 | #include <linux/mmu_notifier.h> | ||
30 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
31 | #include <linux/nsproxy.h> | 32 | #include <linux/nsproxy.h> |
32 | #include <linux/capability.h> | 33 | #include <linux/capability.h> |
@@ -414,6 +415,7 @@ static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p) | |||
414 | 415 | ||
415 | if (likely(!mm_alloc_pgd(mm))) { | 416 | if (likely(!mm_alloc_pgd(mm))) { |
416 | mm->def_flags = 0; | 417 | mm->def_flags = 0; |
418 | mmu_notifier_mm_init(mm); | ||
417 | return mm; | 419 | return mm; |
418 | } | 420 | } |
419 | 421 | ||
@@ -446,6 +448,7 @@ void __mmdrop(struct mm_struct *mm) | |||
446 | BUG_ON(mm == &init_mm); | 448 | BUG_ON(mm == &init_mm); |
447 | mm_free_pgd(mm); | 449 | mm_free_pgd(mm); |
448 | destroy_context(mm); | 450 | destroy_context(mm); |
451 | mmu_notifier_mm_destroy(mm); | ||
449 | free_mm(mm); | 452 | free_mm(mm); |
450 | } | 453 | } |
451 | EXPORT_SYMBOL_GPL(__mmdrop); | 454 | EXPORT_SYMBOL_GPL(__mmdrop); |
diff --git a/kernel/marker.c b/kernel/marker.c index 971da5317903..7d1faecd7a51 100644 --- a/kernel/marker.c +++ b/kernel/marker.c | |||
@@ -126,6 +126,11 @@ void marker_probe_cb(const struct marker *mdata, void *call_private, ...) | |||
126 | struct marker_probe_closure *multi; | 126 | struct marker_probe_closure *multi; |
127 | int i; | 127 | int i; |
128 | /* | 128 | /* |
129 | * Read mdata->ptype before mdata->multi. | ||
130 | */ | ||
131 | smp_rmb(); | ||
132 | multi = mdata->multi; | ||
133 | /* | ||
129 | * multi points to an array, therefore accessing the array | 134 | * multi points to an array, therefore accessing the array |
130 | * depends on reading multi. However, even in this case, | 135 | * depends on reading multi. However, even in this case, |
131 | * we must insure that the pointer is read _before_ the array | 136 | * we must insure that the pointer is read _before_ the array |
@@ -133,7 +138,6 @@ void marker_probe_cb(const struct marker *mdata, void *call_private, ...) | |||
133 | * in the fast path, so put the explicit barrier here. | 138 | * in the fast path, so put the explicit barrier here. |
134 | */ | 139 | */ |
135 | smp_read_barrier_depends(); | 140 | smp_read_barrier_depends(); |
136 | multi = mdata->multi; | ||
137 | for (i = 0; multi[i].func; i++) { | 141 | for (i = 0; multi[i].func; i++) { |
138 | va_start(args, call_private); | 142 | va_start(args, call_private); |
139 | multi[i].func(multi[i].probe_private, call_private, | 143 | multi[i].func(multi[i].probe_private, call_private, |
@@ -175,6 +179,11 @@ void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...) | |||
175 | struct marker_probe_closure *multi; | 179 | struct marker_probe_closure *multi; |
176 | int i; | 180 | int i; |
177 | /* | 181 | /* |
182 | * Read mdata->ptype before mdata->multi. | ||
183 | */ | ||
184 | smp_rmb(); | ||
185 | multi = mdata->multi; | ||
186 | /* | ||
178 | * multi points to an array, therefore accessing the array | 187 | * multi points to an array, therefore accessing the array |
179 | * depends on reading multi. However, even in this case, | 188 | * depends on reading multi. However, even in this case, |
180 | * we must insure that the pointer is read _before_ the array | 189 | * we must insure that the pointer is read _before_ the array |
@@ -182,7 +191,6 @@ void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...) | |||
182 | * in the fast path, so put the explicit barrier here. | 191 | * in the fast path, so put the explicit barrier here. |
183 | */ | 192 | */ |
184 | smp_read_barrier_depends(); | 193 | smp_read_barrier_depends(); |
185 | multi = mdata->multi; | ||
186 | for (i = 0; multi[i].func; i++) | 194 | for (i = 0; multi[i].func; i++) |
187 | multi[i].func(multi[i].probe_private, call_private, | 195 | multi[i].func(multi[i].probe_private, call_private, |
188 | mdata->format, &args); | 196 | mdata->format, &args); |
diff --git a/kernel/printk.c b/kernel/printk.c index a7f7559c5f6c..b51b1567bb55 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -1309,14 +1309,14 @@ void tty_write_message(struct tty_struct *tty, char *msg) | |||
1309 | 1309 | ||
1310 | #if defined CONFIG_PRINTK | 1310 | #if defined CONFIG_PRINTK |
1311 | 1311 | ||
1312 | DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); | ||
1313 | /* | 1312 | /* |
1314 | * printk rate limiting, lifted from the networking subsystem. | 1313 | * printk rate limiting, lifted from the networking subsystem. |
1315 | * | 1314 | * |
1316 | * This enforces a rate limit: not more than one kernel message | 1315 | * This enforces a rate limit: not more than 10 kernel messages |
1317 | * every printk_ratelimit_jiffies to make a denial-of-service | 1316 | * every 5s to make a denial-of-service attack impossible. |
1318 | * attack impossible. | ||
1319 | */ | 1317 | */ |
1318 | DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); | ||
1319 | |||
1320 | int printk_ratelimit(void) | 1320 | int printk_ratelimit(void) |
1321 | { | 1321 | { |
1322 | return __ratelimit(&printk_ratelimit_state); | 1322 | return __ratelimit(&printk_ratelimit_state); |
diff --git a/kernel/resource.c b/kernel/resource.c index 74af2d7cb5a1..f5b518eabefe 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -490,7 +490,7 @@ resource_size_t resource_alignment(struct resource *res) | |||
490 | { | 490 | { |
491 | switch (res->flags & (IORESOURCE_SIZEALIGN | IORESOURCE_STARTALIGN)) { | 491 | switch (res->flags & (IORESOURCE_SIZEALIGN | IORESOURCE_STARTALIGN)) { |
492 | case IORESOURCE_SIZEALIGN: | 492 | case IORESOURCE_SIZEALIGN: |
493 | return res->end - res->start + 1; | 493 | return resource_size(res); |
494 | case IORESOURCE_STARTALIGN: | 494 | case IORESOURCE_STARTALIGN: |
495 | return res->start; | 495 | return res->start; |
496 | default: | 496 | default: |
diff --git a/kernel/sched.c b/kernel/sched.c index 0236958addcb..21f7da94662e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -7671,34 +7671,34 @@ static ssize_t sched_power_savings_store(const char *buf, size_t count, int smt) | |||
7671 | } | 7671 | } |
7672 | 7672 | ||
7673 | #ifdef CONFIG_SCHED_MC | 7673 | #ifdef CONFIG_SCHED_MC |
7674 | static ssize_t sched_mc_power_savings_show(struct sys_device *dev, | 7674 | static ssize_t sched_mc_power_savings_show(struct sysdev_class *class, |
7675 | struct sysdev_attribute *attr, char *page) | 7675 | char *page) |
7676 | { | 7676 | { |
7677 | return sprintf(page, "%u\n", sched_mc_power_savings); | 7677 | return sprintf(page, "%u\n", sched_mc_power_savings); |
7678 | } | 7678 | } |
7679 | static ssize_t sched_mc_power_savings_store(struct sys_device *dev, | 7679 | static ssize_t sched_mc_power_savings_store(struct sysdev_class *class, |
7680 | struct sysdev_attribute *attr, | ||
7681 | const char *buf, size_t count) | 7680 | const char *buf, size_t count) |
7682 | { | 7681 | { |
7683 | return sched_power_savings_store(buf, count, 0); | 7682 | return sched_power_savings_store(buf, count, 0); |
7684 | } | 7683 | } |
7685 | static SYSDEV_ATTR(sched_mc_power_savings, 0644, sched_mc_power_savings_show, | 7684 | static SYSDEV_CLASS_ATTR(sched_mc_power_savings, 0644, |
7686 | sched_mc_power_savings_store); | 7685 | sched_mc_power_savings_show, |
7686 | sched_mc_power_savings_store); | ||
7687 | #endif | 7687 | #endif |
7688 | 7688 | ||
7689 | #ifdef CONFIG_SCHED_SMT | 7689 | #ifdef CONFIG_SCHED_SMT |
7690 | static ssize_t sched_smt_power_savings_show(struct sys_device *dev, | 7690 | static ssize_t sched_smt_power_savings_show(struct sysdev_class *dev, |
7691 | struct sysdev_attribute *attr, char *page) | 7691 | char *page) |
7692 | { | 7692 | { |
7693 | return sprintf(page, "%u\n", sched_smt_power_savings); | 7693 | return sprintf(page, "%u\n", sched_smt_power_savings); |
7694 | } | 7694 | } |
7695 | static ssize_t sched_smt_power_savings_store(struct sys_device *dev, | 7695 | static ssize_t sched_smt_power_savings_store(struct sysdev_class *dev, |
7696 | struct sysdev_attribute *attr, | ||
7697 | const char *buf, size_t count) | 7696 | const char *buf, size_t count) |
7698 | { | 7697 | { |
7699 | return sched_power_savings_store(buf, count, 1); | 7698 | return sched_power_savings_store(buf, count, 1); |
7700 | } | 7699 | } |
7701 | static SYSDEV_ATTR(sched_smt_power_savings, 0644, sched_smt_power_savings_show, | 7700 | static SYSDEV_CLASS_ATTR(sched_smt_power_savings, 0644, |
7701 | sched_smt_power_savings_show, | ||
7702 | sched_smt_power_savings_store); | 7702 | sched_smt_power_savings_store); |
7703 | #endif | 7703 | #endif |
7704 | 7704 | ||
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index bf43284d6855..80c4336f4188 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
@@ -196,12 +196,10 @@ static int tick_check_new_device(struct clock_event_device *newdev) | |||
196 | struct tick_device *td; | 196 | struct tick_device *td; |
197 | int cpu, ret = NOTIFY_OK; | 197 | int cpu, ret = NOTIFY_OK; |
198 | unsigned long flags; | 198 | unsigned long flags; |
199 | cpumask_of_cpu_ptr_declare(cpumask); | ||
200 | 199 | ||
201 | spin_lock_irqsave(&tick_device_lock, flags); | 200 | spin_lock_irqsave(&tick_device_lock, flags); |
202 | 201 | ||
203 | cpu = smp_processor_id(); | 202 | cpu = smp_processor_id(); |
204 | cpumask_of_cpu_ptr_next(cpumask, cpu); | ||
205 | if (!cpu_isset(cpu, newdev->cpumask)) | 203 | if (!cpu_isset(cpu, newdev->cpumask)) |
206 | goto out_bc; | 204 | goto out_bc; |
207 | 205 | ||
@@ -209,7 +207,7 @@ static int tick_check_new_device(struct clock_event_device *newdev) | |||
209 | curdev = td->evtdev; | 207 | curdev = td->evtdev; |
210 | 208 | ||
211 | /* cpu local device ? */ | 209 | /* cpu local device ? */ |
212 | if (!cpus_equal(newdev->cpumask, *cpumask)) { | 210 | if (!cpus_equal(newdev->cpumask, cpumask_of_cpu(cpu))) { |
213 | 211 | ||
214 | /* | 212 | /* |
215 | * If the cpu affinity of the device interrupt can not | 213 | * If the cpu affinity of the device interrupt can not |
@@ -222,7 +220,7 @@ static int tick_check_new_device(struct clock_event_device *newdev) | |||
222 | * If we have a cpu local device already, do not replace it | 220 | * If we have a cpu local device already, do not replace it |
223 | * by a non cpu local device | 221 | * by a non cpu local device |
224 | */ | 222 | */ |
225 | if (curdev && cpus_equal(curdev->cpumask, *cpumask)) | 223 | if (curdev && cpus_equal(curdev->cpumask, cpumask_of_cpu(cpu))) |
226 | goto out_bc; | 224 | goto out_bc; |
227 | } | 225 | } |
228 | 226 | ||
@@ -254,7 +252,7 @@ static int tick_check_new_device(struct clock_event_device *newdev) | |||
254 | curdev = NULL; | 252 | curdev = NULL; |
255 | } | 253 | } |
256 | clockevents_exchange_device(curdev, newdev); | 254 | clockevents_exchange_device(curdev, newdev); |
257 | tick_setup_device(td, newdev, cpu, cpumask); | 255 | tick_setup_device(td, newdev, cpu, &cpumask_of_cpu(cpu)); |
258 | if (newdev->features & CLOCK_EVT_FEAT_ONESHOT) | 256 | if (newdev->features & CLOCK_EVT_FEAT_ONESHOT) |
259 | tick_oneshot_notify(); | 257 | tick_oneshot_notify(); |
260 | 258 | ||
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c index ce2d723c10e1..bb948e52ce20 100644 --- a/kernel/trace/trace_sysprof.c +++ b/kernel/trace/trace_sysprof.c | |||
@@ -213,9 +213,7 @@ static void start_stack_timers(void) | |||
213 | int cpu; | 213 | int cpu; |
214 | 214 | ||
215 | for_each_online_cpu(cpu) { | 215 | for_each_online_cpu(cpu) { |
216 | cpumask_of_cpu_ptr(new_mask, cpu); | 216 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
217 | |||
218 | set_cpus_allowed_ptr(current, new_mask); | ||
219 | start_stack_timer(cpu); | 217 | start_stack_timer(cpu); |
220 | } | 218 | } |
221 | set_cpus_allowed_ptr(current, &saved_mask); | 219 | set_cpus_allowed_ptr(current, &saved_mask); |
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index ec7e4f62aaff..4a26a1382df0 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -830,10 +830,21 @@ struct workqueue_struct *__create_workqueue_key(const char *name, | |||
830 | start_workqueue_thread(cwq, -1); | 830 | start_workqueue_thread(cwq, -1); |
831 | } else { | 831 | } else { |
832 | cpu_maps_update_begin(); | 832 | cpu_maps_update_begin(); |
833 | /* | ||
834 | * We must place this wq on list even if the code below fails. | ||
835 | * cpu_down(cpu) can remove cpu from cpu_populated_map before | ||
836 | * destroy_workqueue() takes the lock, in that case we leak | ||
837 | * cwq[cpu]->thread. | ||
838 | */ | ||
833 | spin_lock(&workqueue_lock); | 839 | spin_lock(&workqueue_lock); |
834 | list_add(&wq->list, &workqueues); | 840 | list_add(&wq->list, &workqueues); |
835 | spin_unlock(&workqueue_lock); | 841 | spin_unlock(&workqueue_lock); |
836 | 842 | /* | |
843 | * We must initialize cwqs for each possible cpu even if we | ||
844 | * are going to call destroy_workqueue() finally. Otherwise | ||
845 | * cpu_up() can hit the uninitialized cwq once we drop the | ||
846 | * lock. | ||
847 | */ | ||
837 | for_each_possible_cpu(cpu) { | 848 | for_each_possible_cpu(cpu) { |
838 | cwq = init_cpu_workqueue(wq, cpu); | 849 | cwq = init_cpu_workqueue(wq, cpu); |
839 | if (err || !cpu_online(cpu)) | 850 | if (err || !cpu_online(cpu)) |
diff --git a/lib/ratelimit.c b/lib/ratelimit.c index 35136671b215..26187edcc7ea 100644 --- a/lib/ratelimit.c +++ b/lib/ratelimit.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | 16 | ||
17 | static DEFINE_SPINLOCK(ratelimit_lock); | 17 | static DEFINE_SPINLOCK(ratelimit_lock); |
18 | static unsigned long flags; | ||
19 | 18 | ||
20 | /* | 19 | /* |
21 | * __ratelimit - rate limiting | 20 | * __ratelimit - rate limiting |
@@ -26,6 +25,8 @@ static unsigned long flags; | |||
26 | */ | 25 | */ |
27 | int __ratelimit(struct ratelimit_state *rs) | 26 | int __ratelimit(struct ratelimit_state *rs) |
28 | { | 27 | { |
28 | unsigned long flags; | ||
29 | |||
29 | if (!rs->interval) | 30 | if (!rs->interval) |
30 | return 1; | 31 | return 1; |
31 | 32 | ||
diff --git a/lib/smp_processor_id.c b/lib/smp_processor_id.c index c4381d9516f6..0f8fc22ed103 100644 --- a/lib/smp_processor_id.c +++ b/lib/smp_processor_id.c | |||
@@ -11,7 +11,6 @@ notrace unsigned int debug_smp_processor_id(void) | |||
11 | { | 11 | { |
12 | unsigned long preempt_count = preempt_count(); | 12 | unsigned long preempt_count = preempt_count(); |
13 | int this_cpu = raw_smp_processor_id(); | 13 | int this_cpu = raw_smp_processor_id(); |
14 | cpumask_of_cpu_ptr_declare(this_mask); | ||
15 | 14 | ||
16 | if (likely(preempt_count)) | 15 | if (likely(preempt_count)) |
17 | goto out; | 16 | goto out; |
@@ -23,9 +22,7 @@ notrace unsigned int debug_smp_processor_id(void) | |||
23 | * Kernel threads bound to a single CPU can safely use | 22 | * Kernel threads bound to a single CPU can safely use |
24 | * smp_processor_id(): | 23 | * smp_processor_id(): |
25 | */ | 24 | */ |
26 | cpumask_of_cpu_ptr_next(this_mask, this_cpu); | 25 | if (cpus_equal(current->cpus_allowed, cpumask_of_cpu(this_cpu))) |
27 | |||
28 | if (cpus_equal(current->cpus_allowed, *this_mask)) | ||
29 | goto out; | 26 | goto out; |
30 | 27 | ||
31 | /* | 28 | /* |
diff --git a/mm/Kconfig b/mm/Kconfig index efee5d379df4..446c6588c753 100644 --- a/mm/Kconfig +++ b/mm/Kconfig | |||
@@ -208,3 +208,6 @@ config NR_QUICK | |||
208 | config VIRT_TO_BUS | 208 | config VIRT_TO_BUS |
209 | def_bool y | 209 | def_bool y |
210 | depends on !ARCH_NO_VIRT_TO_BUS | 210 | depends on !ARCH_NO_VIRT_TO_BUS |
211 | |||
212 | config MMU_NOTIFIER | ||
213 | bool | ||
diff --git a/mm/Makefile b/mm/Makefile index 06ca2381fef1..da4ccf015aea 100644 --- a/mm/Makefile +++ b/mm/Makefile | |||
@@ -25,6 +25,7 @@ obj-$(CONFIG_SHMEM) += shmem.o | |||
25 | obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o | 25 | obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o |
26 | obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o | 26 | obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o |
27 | obj-$(CONFIG_SLOB) += slob.o | 27 | obj-$(CONFIG_SLOB) += slob.o |
28 | obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o | ||
28 | obj-$(CONFIG_SLAB) += slab.o | 29 | obj-$(CONFIG_SLAB) += slab.o |
29 | obj-$(CONFIG_SLUB) += slub.o | 30 | obj-$(CONFIG_SLUB) += slub.o |
30 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o | 31 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o |
diff --git a/mm/filemap.c b/mm/filemap.c index 5de7633e1dbe..d97d1ad55473 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1023,8 +1023,17 @@ find_page: | |||
1023 | ra, filp, page, | 1023 | ra, filp, page, |
1024 | index, last_index - index); | 1024 | index, last_index - index); |
1025 | } | 1025 | } |
1026 | if (!PageUptodate(page)) | 1026 | if (!PageUptodate(page)) { |
1027 | goto page_not_up_to_date; | 1027 | if (inode->i_blkbits == PAGE_CACHE_SHIFT || |
1028 | !mapping->a_ops->is_partially_uptodate) | ||
1029 | goto page_not_up_to_date; | ||
1030 | if (TestSetPageLocked(page)) | ||
1031 | goto page_not_up_to_date; | ||
1032 | if (!mapping->a_ops->is_partially_uptodate(page, | ||
1033 | desc, offset)) | ||
1034 | goto page_not_up_to_date_locked; | ||
1035 | unlock_page(page); | ||
1036 | } | ||
1028 | page_ok: | 1037 | page_ok: |
1029 | /* | 1038 | /* |
1030 | * i_size must be checked after we know the page is Uptodate. | 1039 | * i_size must be checked after we know the page is Uptodate. |
@@ -1094,6 +1103,7 @@ page_not_up_to_date: | |||
1094 | if (lock_page_killable(page)) | 1103 | if (lock_page_killable(page)) |
1095 | goto readpage_eio; | 1104 | goto readpage_eio; |
1096 | 1105 | ||
1106 | page_not_up_to_date_locked: | ||
1097 | /* Did it get truncated before we got the lock? */ | 1107 | /* Did it get truncated before we got the lock? */ |
1098 | if (!page->mapping) { | 1108 | if (!page->mapping) { |
1099 | unlock_page(page); | 1109 | unlock_page(page); |
@@ -1869,7 +1879,7 @@ void iov_iter_advance(struct iov_iter *i, size_t bytes) | |||
1869 | * The !iov->iov_len check ensures we skip over unlikely | 1879 | * The !iov->iov_len check ensures we skip over unlikely |
1870 | * zero-length segments (without overruning the iovec). | 1880 | * zero-length segments (without overruning the iovec). |
1871 | */ | 1881 | */ |
1872 | while (bytes || unlikely(!iov->iov_len && i->count)) { | 1882 | while (bytes || unlikely(i->count && !iov->iov_len)) { |
1873 | int copy; | 1883 | int copy; |
1874 | 1884 | ||
1875 | copy = min(bytes, iov->iov_len - base); | 1885 | copy = min(bytes, iov->iov_len - base); |
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c index 98a3f31ccd6a..380ab402d711 100644 --- a/mm/filemap_xip.c +++ b/mm/filemap_xip.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/uio.h> | 14 | #include <linux/uio.h> |
15 | #include <linux/rmap.h> | 15 | #include <linux/rmap.h> |
16 | #include <linux/mmu_notifier.h> | ||
16 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
17 | #include <asm/tlbflush.h> | 18 | #include <asm/tlbflush.h> |
18 | #include <asm/io.h> | 19 | #include <asm/io.h> |
@@ -188,7 +189,7 @@ __xip_unmap (struct address_space * mapping, | |||
188 | if (pte) { | 189 | if (pte) { |
189 | /* Nuke the page table entry. */ | 190 | /* Nuke the page table entry. */ |
190 | flush_cache_page(vma, address, pte_pfn(*pte)); | 191 | flush_cache_page(vma, address, pte_pfn(*pte)); |
191 | pteval = ptep_clear_flush(vma, address, pte); | 192 | pteval = ptep_clear_flush_notify(vma, address, pte); |
192 | page_remove_rmap(page, vma); | 193 | page_remove_rmap(page, vma); |
193 | dec_mm_counter(mm, file_rss); | 194 | dec_mm_counter(mm, file_rss); |
194 | BUG_ON(pte_dirty(pteval)); | 195 | BUG_ON(pte_dirty(pteval)); |
diff --git a/mm/fremap.c b/mm/fremap.c index 07a9c82ce1a3..7881638e4a12 100644 --- a/mm/fremap.c +++ b/mm/fremap.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/rmap.h> | 15 | #include <linux/rmap.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/syscalls.h> | 17 | #include <linux/syscalls.h> |
18 | #include <linux/mmu_notifier.h> | ||
18 | 19 | ||
19 | #include <asm/mmu_context.h> | 20 | #include <asm/mmu_context.h> |
20 | #include <asm/cacheflush.h> | 21 | #include <asm/cacheflush.h> |
@@ -214,7 +215,9 @@ asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size, | |||
214 | spin_unlock(&mapping->i_mmap_lock); | 215 | spin_unlock(&mapping->i_mmap_lock); |
215 | } | 216 | } |
216 | 217 | ||
218 | mmu_notifier_invalidate_range_start(mm, start, start + size); | ||
217 | err = populate_range(mm, vma, start, size, pgoff); | 219 | err = populate_range(mm, vma, start, size, pgoff); |
220 | mmu_notifier_invalidate_range_end(mm, start, start + size); | ||
218 | if (!err && !(flags & MAP_NONBLOCK)) { | 221 | if (!err && !(flags & MAP_NONBLOCK)) { |
219 | if (unlikely(has_write_lock)) { | 222 | if (unlikely(has_write_lock)) { |
220 | downgrade_write(&mm->mmap_sem); | 223 | downgrade_write(&mm->mmap_sem); |
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index b3c78640b629..d237a02eb228 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/mm.h> | 9 | #include <linux/mm.h> |
10 | #include <linux/sysctl.h> | 10 | #include <linux/sysctl.h> |
11 | #include <linux/highmem.h> | 11 | #include <linux/highmem.h> |
12 | #include <linux/mmu_notifier.h> | ||
12 | #include <linux/nodemask.h> | 13 | #include <linux/nodemask.h> |
13 | #include <linux/pagemap.h> | 14 | #include <linux/pagemap.h> |
14 | #include <linux/mempolicy.h> | 15 | #include <linux/mempolicy.h> |
@@ -19,6 +20,7 @@ | |||
19 | #include <asm/io.h> | 20 | #include <asm/io.h> |
20 | #include <asm/page.h> | 21 | #include <asm/page.h> |
21 | #include <asm/pgtable.h> | 22 | #include <asm/pgtable.h> |
23 | #include <asm/io.h> | ||
22 | 24 | ||
23 | #include <linux/hugetlb.h> | 25 | #include <linux/hugetlb.h> |
24 | #include "internal.h" | 26 | #include "internal.h" |
@@ -1672,6 +1674,7 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, | |||
1672 | BUG_ON(start & ~huge_page_mask(h)); | 1674 | BUG_ON(start & ~huge_page_mask(h)); |
1673 | BUG_ON(end & ~huge_page_mask(h)); | 1675 | BUG_ON(end & ~huge_page_mask(h)); |
1674 | 1676 | ||
1677 | mmu_notifier_invalidate_range_start(mm, start, end); | ||
1675 | spin_lock(&mm->page_table_lock); | 1678 | spin_lock(&mm->page_table_lock); |
1676 | for (address = start; address < end; address += sz) { | 1679 | for (address = start; address < end; address += sz) { |
1677 | ptep = huge_pte_offset(mm, address); | 1680 | ptep = huge_pte_offset(mm, address); |
@@ -1713,6 +1716,7 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, | |||
1713 | } | 1716 | } |
1714 | spin_unlock(&mm->page_table_lock); | 1717 | spin_unlock(&mm->page_table_lock); |
1715 | flush_tlb_range(vma, start, end); | 1718 | flush_tlb_range(vma, start, end); |
1719 | mmu_notifier_invalidate_range_end(mm, start, end); | ||
1716 | list_for_each_entry_safe(page, tmp, &page_list, lru) { | 1720 | list_for_each_entry_safe(page, tmp, &page_list, lru) { |
1717 | list_del(&page->lru); | 1721 | list_del(&page->lru); |
1718 | put_page(page); | 1722 | put_page(page); |
diff --git a/mm/madvise.c b/mm/madvise.c index 23a0ec3e0ea0..f9349c18a1b5 100644 --- a/mm/madvise.c +++ b/mm/madvise.c | |||
@@ -132,10 +132,10 @@ static long madvise_willneed(struct vm_area_struct * vma, | |||
132 | * Application no longer needs these pages. If the pages are dirty, | 132 | * Application no longer needs these pages. If the pages are dirty, |
133 | * it's OK to just throw them away. The app will be more careful about | 133 | * it's OK to just throw them away. The app will be more careful about |
134 | * data it wants to keep. Be sure to free swap resources too. The | 134 | * data it wants to keep. Be sure to free swap resources too. The |
135 | * zap_page_range call sets things up for refill_inactive to actually free | 135 | * zap_page_range call sets things up for shrink_active_list to actually free |
136 | * these pages later if no one else has touched them in the meantime, | 136 | * these pages later if no one else has touched them in the meantime, |
137 | * although we could add these pages to a global reuse list for | 137 | * although we could add these pages to a global reuse list for |
138 | * refill_inactive to pick up before reclaiming other pages. | 138 | * shrink_active_list to pick up before reclaiming other pages. |
139 | * | 139 | * |
140 | * NB: This interface discards data rather than pushes it out to swap, | 140 | * NB: This interface discards data rather than pushes it out to swap, |
141 | * as some implementations do. This has performance implications for | 141 | * as some implementations do. This has performance implications for |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index fba566c51322..7056c3bdb478 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -1168,9 +1168,6 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss, | |||
1168 | mem = mem_cgroup_from_cont(cont); | 1168 | mem = mem_cgroup_from_cont(cont); |
1169 | old_mem = mem_cgroup_from_cont(old_cont); | 1169 | old_mem = mem_cgroup_from_cont(old_cont); |
1170 | 1170 | ||
1171 | if (mem == old_mem) | ||
1172 | goto out; | ||
1173 | |||
1174 | /* | 1171 | /* |
1175 | * Only thread group leaders are allowed to migrate, the mm_struct is | 1172 | * Only thread group leaders are allowed to migrate, the mm_struct is |
1176 | * in effect owned by the leader | 1173 | * in effect owned by the leader |
diff --git a/mm/memory.c b/mm/memory.c index a8ca04faaea6..0e4eea10c7b0 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/init.h> | 51 | #include <linux/init.h> |
52 | #include <linux/writeback.h> | 52 | #include <linux/writeback.h> |
53 | #include <linux/memcontrol.h> | 53 | #include <linux/memcontrol.h> |
54 | #include <linux/mmu_notifier.h> | ||
54 | 55 | ||
55 | #include <asm/pgalloc.h> | 56 | #include <asm/pgalloc.h> |
56 | #include <asm/uaccess.h> | 57 | #include <asm/uaccess.h> |
@@ -652,6 +653,7 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
652 | unsigned long next; | 653 | unsigned long next; |
653 | unsigned long addr = vma->vm_start; | 654 | unsigned long addr = vma->vm_start; |
654 | unsigned long end = vma->vm_end; | 655 | unsigned long end = vma->vm_end; |
656 | int ret; | ||
655 | 657 | ||
656 | /* | 658 | /* |
657 | * Don't copy ptes where a page fault will fill them correctly. | 659 | * Don't copy ptes where a page fault will fill them correctly. |
@@ -667,17 +669,33 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
667 | if (is_vm_hugetlb_page(vma)) | 669 | if (is_vm_hugetlb_page(vma)) |
668 | return copy_hugetlb_page_range(dst_mm, src_mm, vma); | 670 | return copy_hugetlb_page_range(dst_mm, src_mm, vma); |
669 | 671 | ||
672 | /* | ||
673 | * We need to invalidate the secondary MMU mappings only when | ||
674 | * there could be a permission downgrade on the ptes of the | ||
675 | * parent mm. And a permission downgrade will only happen if | ||
676 | * is_cow_mapping() returns true. | ||
677 | */ | ||
678 | if (is_cow_mapping(vma->vm_flags)) | ||
679 | mmu_notifier_invalidate_range_start(src_mm, addr, end); | ||
680 | |||
681 | ret = 0; | ||
670 | dst_pgd = pgd_offset(dst_mm, addr); | 682 | dst_pgd = pgd_offset(dst_mm, addr); |
671 | src_pgd = pgd_offset(src_mm, addr); | 683 | src_pgd = pgd_offset(src_mm, addr); |
672 | do { | 684 | do { |
673 | next = pgd_addr_end(addr, end); | 685 | next = pgd_addr_end(addr, end); |
674 | if (pgd_none_or_clear_bad(src_pgd)) | 686 | if (pgd_none_or_clear_bad(src_pgd)) |
675 | continue; | 687 | continue; |
676 | if (copy_pud_range(dst_mm, src_mm, dst_pgd, src_pgd, | 688 | if (unlikely(copy_pud_range(dst_mm, src_mm, dst_pgd, src_pgd, |
677 | vma, addr, next)) | 689 | vma, addr, next))) { |
678 | return -ENOMEM; | 690 | ret = -ENOMEM; |
691 | break; | ||
692 | } | ||
679 | } while (dst_pgd++, src_pgd++, addr = next, addr != end); | 693 | } while (dst_pgd++, src_pgd++, addr = next, addr != end); |
680 | return 0; | 694 | |
695 | if (is_cow_mapping(vma->vm_flags)) | ||
696 | mmu_notifier_invalidate_range_end(src_mm, | ||
697 | vma->vm_start, end); | ||
698 | return ret; | ||
681 | } | 699 | } |
682 | 700 | ||
683 | static unsigned long zap_pte_range(struct mmu_gather *tlb, | 701 | static unsigned long zap_pte_range(struct mmu_gather *tlb, |
@@ -881,7 +899,9 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp, | |||
881 | unsigned long start = start_addr; | 899 | unsigned long start = start_addr; |
882 | spinlock_t *i_mmap_lock = details? details->i_mmap_lock: NULL; | 900 | spinlock_t *i_mmap_lock = details? details->i_mmap_lock: NULL; |
883 | int fullmm = (*tlbp)->fullmm; | 901 | int fullmm = (*tlbp)->fullmm; |
902 | struct mm_struct *mm = vma->vm_mm; | ||
884 | 903 | ||
904 | mmu_notifier_invalidate_range_start(mm, start_addr, end_addr); | ||
885 | for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) { | 905 | for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) { |
886 | unsigned long end; | 906 | unsigned long end; |
887 | 907 | ||
@@ -946,6 +966,7 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp, | |||
946 | } | 966 | } |
947 | } | 967 | } |
948 | out: | 968 | out: |
969 | mmu_notifier_invalidate_range_end(mm, start_addr, end_addr); | ||
949 | return start; /* which is now the end (or restart) address */ | 970 | return start; /* which is now the end (or restart) address */ |
950 | } | 971 | } |
951 | 972 | ||
@@ -972,6 +993,30 @@ unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, | |||
972 | tlb_finish_mmu(tlb, address, end); | 993 | tlb_finish_mmu(tlb, address, end); |
973 | return end; | 994 | return end; |
974 | } | 995 | } |
996 | EXPORT_SYMBOL_GPL(zap_page_range); | ||
997 | |||
998 | /** | ||
999 | * zap_vma_ptes - remove ptes mapping the vma | ||
1000 | * @vma: vm_area_struct holding ptes to be zapped | ||
1001 | * @address: starting address of pages to zap | ||
1002 | * @size: number of bytes to zap | ||
1003 | * | ||
1004 | * This function only unmaps ptes assigned to VM_PFNMAP vmas. | ||
1005 | * | ||
1006 | * The entire address range must be fully contained within the vma. | ||
1007 | * | ||
1008 | * Returns 0 if successful. | ||
1009 | */ | ||
1010 | int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, | ||
1011 | unsigned long size) | ||
1012 | { | ||
1013 | if (address < vma->vm_start || address + size > vma->vm_end || | ||
1014 | !(vma->vm_flags & VM_PFNMAP)) | ||
1015 | return -1; | ||
1016 | zap_page_range(vma, address, size, NULL); | ||
1017 | return 0; | ||
1018 | } | ||
1019 | EXPORT_SYMBOL_GPL(zap_vma_ptes); | ||
975 | 1020 | ||
976 | /* | 1021 | /* |
977 | * Do a quick page-table lookup for a single page. | 1022 | * Do a quick page-table lookup for a single page. |
@@ -1066,6 +1111,7 @@ no_page_table: | |||
1066 | } | 1111 | } |
1067 | return page; | 1112 | return page; |
1068 | } | 1113 | } |
1114 | EXPORT_SYMBOL_GPL(follow_page); | ||
1069 | 1115 | ||
1070 | /* Can we do the FOLL_ANON optimization? */ | 1116 | /* Can we do the FOLL_ANON optimization? */ |
1071 | static inline int use_zero_page(struct vm_area_struct *vma) | 1117 | static inline int use_zero_page(struct vm_area_struct *vma) |
@@ -1616,10 +1662,11 @@ int apply_to_page_range(struct mm_struct *mm, unsigned long addr, | |||
1616 | { | 1662 | { |
1617 | pgd_t *pgd; | 1663 | pgd_t *pgd; |
1618 | unsigned long next; | 1664 | unsigned long next; |
1619 | unsigned long end = addr + size; | 1665 | unsigned long start = addr, end = addr + size; |
1620 | int err; | 1666 | int err; |
1621 | 1667 | ||
1622 | BUG_ON(addr >= end); | 1668 | BUG_ON(addr >= end); |
1669 | mmu_notifier_invalidate_range_start(mm, start, end); | ||
1623 | pgd = pgd_offset(mm, addr); | 1670 | pgd = pgd_offset(mm, addr); |
1624 | do { | 1671 | do { |
1625 | next = pgd_addr_end(addr, end); | 1672 | next = pgd_addr_end(addr, end); |
@@ -1627,6 +1674,7 @@ int apply_to_page_range(struct mm_struct *mm, unsigned long addr, | |||
1627 | if (err) | 1674 | if (err) |
1628 | break; | 1675 | break; |
1629 | } while (pgd++, addr = next, addr != end); | 1676 | } while (pgd++, addr = next, addr != end); |
1677 | mmu_notifier_invalidate_range_end(mm, start, end); | ||
1630 | return err; | 1678 | return err; |
1631 | } | 1679 | } |
1632 | EXPORT_SYMBOL_GPL(apply_to_page_range); | 1680 | EXPORT_SYMBOL_GPL(apply_to_page_range); |
@@ -1839,7 +1887,7 @@ gotten: | |||
1839 | * seen in the presence of one thread doing SMC and another | 1887 | * seen in the presence of one thread doing SMC and another |
1840 | * thread doing COW. | 1888 | * thread doing COW. |
1841 | */ | 1889 | */ |
1842 | ptep_clear_flush(vma, address, page_table); | 1890 | ptep_clear_flush_notify(vma, address, page_table); |
1843 | set_pte_at(mm, address, page_table, entry); | 1891 | set_pte_at(mm, address, page_table, entry); |
1844 | update_mmu_cache(vma, address, entry); | 1892 | update_mmu_cache(vma, address, entry); |
1845 | lru_cache_add_active(new_page); | 1893 | lru_cache_add_active(new_page); |
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/mount.h> | 26 | #include <linux/mount.h> |
27 | #include <linux/mempolicy.h> | 27 | #include <linux/mempolicy.h> |
28 | #include <linux/rmap.h> | 28 | #include <linux/rmap.h> |
29 | #include <linux/mmu_notifier.h> | ||
29 | 30 | ||
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
31 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
@@ -2061,6 +2062,7 @@ void exit_mmap(struct mm_struct *mm) | |||
2061 | 2062 | ||
2062 | /* mm's last user has gone, and its about to be pulled down */ | 2063 | /* mm's last user has gone, and its about to be pulled down */ |
2063 | arch_exit_mmap(mm); | 2064 | arch_exit_mmap(mm); |
2065 | mmu_notifier_release(mm); | ||
2064 | 2066 | ||
2065 | lru_add_drain(); | 2067 | lru_add_drain(); |
2066 | flush_cache_mm(mm); | 2068 | flush_cache_mm(mm); |
@@ -2268,3 +2270,161 @@ int install_special_mapping(struct mm_struct *mm, | |||
2268 | 2270 | ||
2269 | return 0; | 2271 | return 0; |
2270 | } | 2272 | } |
2273 | |||
2274 | static DEFINE_MUTEX(mm_all_locks_mutex); | ||
2275 | |||
2276 | static void vm_lock_anon_vma(struct anon_vma *anon_vma) | ||
2277 | { | ||
2278 | if (!test_bit(0, (unsigned long *) &anon_vma->head.next)) { | ||
2279 | /* | ||
2280 | * The LSB of head.next can't change from under us | ||
2281 | * because we hold the mm_all_locks_mutex. | ||
2282 | */ | ||
2283 | spin_lock(&anon_vma->lock); | ||
2284 | /* | ||
2285 | * We can safely modify head.next after taking the | ||
2286 | * anon_vma->lock. If some other vma in this mm shares | ||
2287 | * the same anon_vma we won't take it again. | ||
2288 | * | ||
2289 | * No need of atomic instructions here, head.next | ||
2290 | * can't change from under us thanks to the | ||
2291 | * anon_vma->lock. | ||
2292 | */ | ||
2293 | if (__test_and_set_bit(0, (unsigned long *) | ||
2294 | &anon_vma->head.next)) | ||
2295 | BUG(); | ||
2296 | } | ||
2297 | } | ||
2298 | |||
2299 | static void vm_lock_mapping(struct address_space *mapping) | ||
2300 | { | ||
2301 | if (!test_bit(AS_MM_ALL_LOCKS, &mapping->flags)) { | ||
2302 | /* | ||
2303 | * AS_MM_ALL_LOCKS can't change from under us because | ||
2304 | * we hold the mm_all_locks_mutex. | ||
2305 | * | ||
2306 | * Operations on ->flags have to be atomic because | ||
2307 | * even if AS_MM_ALL_LOCKS is stable thanks to the | ||
2308 | * mm_all_locks_mutex, there may be other cpus | ||
2309 | * changing other bitflags in parallel to us. | ||
2310 | */ | ||
2311 | if (test_and_set_bit(AS_MM_ALL_LOCKS, &mapping->flags)) | ||
2312 | BUG(); | ||
2313 | spin_lock(&mapping->i_mmap_lock); | ||
2314 | } | ||
2315 | } | ||
2316 | |||
2317 | /* | ||
2318 | * This operation locks against the VM for all pte/vma/mm related | ||
2319 | * operations that could ever happen on a certain mm. This includes | ||
2320 | * vmtruncate, try_to_unmap, and all page faults. | ||
2321 | * | ||
2322 | * The caller must take the mmap_sem in write mode before calling | ||
2323 | * mm_take_all_locks(). The caller isn't allowed to release the | ||
2324 | * mmap_sem until mm_drop_all_locks() returns. | ||
2325 | * | ||
2326 | * mmap_sem in write mode is required in order to block all operations | ||
2327 | * that could modify pagetables and free pages without need of | ||
2328 | * altering the vma layout (for example populate_range() with | ||
2329 | * nonlinear vmas). It's also needed in write mode to avoid new | ||
2330 | * anon_vmas to be associated with existing vmas. | ||
2331 | * | ||
2332 | * A single task can't take more than one mm_take_all_locks() in a row | ||
2333 | * or it would deadlock. | ||
2334 | * | ||
2335 | * The LSB in anon_vma->head.next and the AS_MM_ALL_LOCKS bitflag in | ||
2336 | * mapping->flags avoid to take the same lock twice, if more than one | ||
2337 | * vma in this mm is backed by the same anon_vma or address_space. | ||
2338 | * | ||
2339 | * We can take all the locks in random order because the VM code | ||
2340 | * taking i_mmap_lock or anon_vma->lock outside the mmap_sem never | ||
2341 | * takes more than one of them in a row. Secondly we're protected | ||
2342 | * against a concurrent mm_take_all_locks() by the mm_all_locks_mutex. | ||
2343 | * | ||
2344 | * mm_take_all_locks() and mm_drop_all_locks are expensive operations | ||
2345 | * that may have to take thousand of locks. | ||
2346 | * | ||
2347 | * mm_take_all_locks() can fail if it's interrupted by signals. | ||
2348 | */ | ||
2349 | int mm_take_all_locks(struct mm_struct *mm) | ||
2350 | { | ||
2351 | struct vm_area_struct *vma; | ||
2352 | int ret = -EINTR; | ||
2353 | |||
2354 | BUG_ON(down_read_trylock(&mm->mmap_sem)); | ||
2355 | |||
2356 | mutex_lock(&mm_all_locks_mutex); | ||
2357 | |||
2358 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
2359 | if (signal_pending(current)) | ||
2360 | goto out_unlock; | ||
2361 | if (vma->anon_vma) | ||
2362 | vm_lock_anon_vma(vma->anon_vma); | ||
2363 | if (vma->vm_file && vma->vm_file->f_mapping) | ||
2364 | vm_lock_mapping(vma->vm_file->f_mapping); | ||
2365 | } | ||
2366 | ret = 0; | ||
2367 | |||
2368 | out_unlock: | ||
2369 | if (ret) | ||
2370 | mm_drop_all_locks(mm); | ||
2371 | |||
2372 | return ret; | ||
2373 | } | ||
2374 | |||
2375 | static void vm_unlock_anon_vma(struct anon_vma *anon_vma) | ||
2376 | { | ||
2377 | if (test_bit(0, (unsigned long *) &anon_vma->head.next)) { | ||
2378 | /* | ||
2379 | * The LSB of head.next can't change to 0 from under | ||
2380 | * us because we hold the mm_all_locks_mutex. | ||
2381 | * | ||
2382 | * We must however clear the bitflag before unlocking | ||
2383 | * the vma so the users using the anon_vma->head will | ||
2384 | * never see our bitflag. | ||
2385 | * | ||
2386 | * No need of atomic instructions here, head.next | ||
2387 | * can't change from under us until we release the | ||
2388 | * anon_vma->lock. | ||
2389 | */ | ||
2390 | if (!__test_and_clear_bit(0, (unsigned long *) | ||
2391 | &anon_vma->head.next)) | ||
2392 | BUG(); | ||
2393 | spin_unlock(&anon_vma->lock); | ||
2394 | } | ||
2395 | } | ||
2396 | |||
2397 | static void vm_unlock_mapping(struct address_space *mapping) | ||
2398 | { | ||
2399 | if (test_bit(AS_MM_ALL_LOCKS, &mapping->flags)) { | ||
2400 | /* | ||
2401 | * AS_MM_ALL_LOCKS can't change to 0 from under us | ||
2402 | * because we hold the mm_all_locks_mutex. | ||
2403 | */ | ||
2404 | spin_unlock(&mapping->i_mmap_lock); | ||
2405 | if (!test_and_clear_bit(AS_MM_ALL_LOCKS, | ||
2406 | &mapping->flags)) | ||
2407 | BUG(); | ||
2408 | } | ||
2409 | } | ||
2410 | |||
2411 | /* | ||
2412 | * The mmap_sem cannot be released by the caller until | ||
2413 | * mm_drop_all_locks() returns. | ||
2414 | */ | ||
2415 | void mm_drop_all_locks(struct mm_struct *mm) | ||
2416 | { | ||
2417 | struct vm_area_struct *vma; | ||
2418 | |||
2419 | BUG_ON(down_read_trylock(&mm->mmap_sem)); | ||
2420 | BUG_ON(!mutex_is_locked(&mm_all_locks_mutex)); | ||
2421 | |||
2422 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
2423 | if (vma->anon_vma) | ||
2424 | vm_unlock_anon_vma(vma->anon_vma); | ||
2425 | if (vma->vm_file && vma->vm_file->f_mapping) | ||
2426 | vm_unlock_mapping(vma->vm_file->f_mapping); | ||
2427 | } | ||
2428 | |||
2429 | mutex_unlock(&mm_all_locks_mutex); | ||
2430 | } | ||
diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c new file mode 100644 index 000000000000..5f4ef0250bee --- /dev/null +++ b/mm/mmu_notifier.c | |||
@@ -0,0 +1,277 @@ | |||
1 | /* | ||
2 | * linux/mm/mmu_notifier.c | ||
3 | * | ||
4 | * Copyright (C) 2008 Qumranet, Inc. | ||
5 | * Copyright (C) 2008 SGI | ||
6 | * Christoph Lameter <clameter@sgi.com> | ||
7 | * | ||
8 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
9 | * the COPYING file in the top-level directory. | ||
10 | */ | ||
11 | |||
12 | #include <linux/rculist.h> | ||
13 | #include <linux/mmu_notifier.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/rcupdate.h> | ||
18 | #include <linux/sched.h> | ||
19 | |||
20 | /* | ||
21 | * This function can't run concurrently against mmu_notifier_register | ||
22 | * because mm->mm_users > 0 during mmu_notifier_register and exit_mmap | ||
23 | * runs with mm_users == 0. Other tasks may still invoke mmu notifiers | ||
24 | * in parallel despite there being no task using this mm any more, | ||
25 | * through the vmas outside of the exit_mmap context, such as with | ||
26 | * vmtruncate. This serializes against mmu_notifier_unregister with | ||
27 | * the mmu_notifier_mm->lock in addition to RCU and it serializes | ||
28 | * against the other mmu notifiers with RCU. struct mmu_notifier_mm | ||
29 | * can't go away from under us as exit_mmap holds an mm_count pin | ||
30 | * itself. | ||
31 | */ | ||
32 | void __mmu_notifier_release(struct mm_struct *mm) | ||
33 | { | ||
34 | struct mmu_notifier *mn; | ||
35 | |||
36 | spin_lock(&mm->mmu_notifier_mm->lock); | ||
37 | while (unlikely(!hlist_empty(&mm->mmu_notifier_mm->list))) { | ||
38 | mn = hlist_entry(mm->mmu_notifier_mm->list.first, | ||
39 | struct mmu_notifier, | ||
40 | hlist); | ||
41 | /* | ||
42 | * We arrived before mmu_notifier_unregister so | ||
43 | * mmu_notifier_unregister will do nothing other than | ||
44 | * to wait ->release to finish and | ||
45 | * mmu_notifier_unregister to return. | ||
46 | */ | ||
47 | hlist_del_init_rcu(&mn->hlist); | ||
48 | /* | ||
49 | * RCU here will block mmu_notifier_unregister until | ||
50 | * ->release returns. | ||
51 | */ | ||
52 | rcu_read_lock(); | ||
53 | spin_unlock(&mm->mmu_notifier_mm->lock); | ||
54 | /* | ||
55 | * if ->release runs before mmu_notifier_unregister it | ||
56 | * must be handled as it's the only way for the driver | ||
57 | * to flush all existing sptes and stop the driver | ||
58 | * from establishing any more sptes before all the | ||
59 | * pages in the mm are freed. | ||
60 | */ | ||
61 | if (mn->ops->release) | ||
62 | mn->ops->release(mn, mm); | ||
63 | rcu_read_unlock(); | ||
64 | spin_lock(&mm->mmu_notifier_mm->lock); | ||
65 | } | ||
66 | spin_unlock(&mm->mmu_notifier_mm->lock); | ||
67 | |||
68 | /* | ||
69 | * synchronize_rcu here prevents mmu_notifier_release to | ||
70 | * return to exit_mmap (which would proceed freeing all pages | ||
71 | * in the mm) until the ->release method returns, if it was | ||
72 | * invoked by mmu_notifier_unregister. | ||
73 | * | ||
74 | * The mmu_notifier_mm can't go away from under us because one | ||
75 | * mm_count is hold by exit_mmap. | ||
76 | */ | ||
77 | synchronize_rcu(); | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * If no young bitflag is supported by the hardware, ->clear_flush_young can | ||
82 | * unmap the address and return 1 or 0 depending if the mapping previously | ||
83 | * existed or not. | ||
84 | */ | ||
85 | int __mmu_notifier_clear_flush_young(struct mm_struct *mm, | ||
86 | unsigned long address) | ||
87 | { | ||
88 | struct mmu_notifier *mn; | ||
89 | struct hlist_node *n; | ||
90 | int young = 0; | ||
91 | |||
92 | rcu_read_lock(); | ||
93 | hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { | ||
94 | if (mn->ops->clear_flush_young) | ||
95 | young |= mn->ops->clear_flush_young(mn, mm, address); | ||
96 | } | ||
97 | rcu_read_unlock(); | ||
98 | |||
99 | return young; | ||
100 | } | ||
101 | |||
102 | void __mmu_notifier_invalidate_page(struct mm_struct *mm, | ||
103 | unsigned long address) | ||
104 | { | ||
105 | struct mmu_notifier *mn; | ||
106 | struct hlist_node *n; | ||
107 | |||
108 | rcu_read_lock(); | ||
109 | hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { | ||
110 | if (mn->ops->invalidate_page) | ||
111 | mn->ops->invalidate_page(mn, mm, address); | ||
112 | } | ||
113 | rcu_read_unlock(); | ||
114 | } | ||
115 | |||
116 | void __mmu_notifier_invalidate_range_start(struct mm_struct *mm, | ||
117 | unsigned long start, unsigned long end) | ||
118 | { | ||
119 | struct mmu_notifier *mn; | ||
120 | struct hlist_node *n; | ||
121 | |||
122 | rcu_read_lock(); | ||
123 | hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { | ||
124 | if (mn->ops->invalidate_range_start) | ||
125 | mn->ops->invalidate_range_start(mn, mm, start, end); | ||
126 | } | ||
127 | rcu_read_unlock(); | ||
128 | } | ||
129 | |||
130 | void __mmu_notifier_invalidate_range_end(struct mm_struct *mm, | ||
131 | unsigned long start, unsigned long end) | ||
132 | { | ||
133 | struct mmu_notifier *mn; | ||
134 | struct hlist_node *n; | ||
135 | |||
136 | rcu_read_lock(); | ||
137 | hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist) { | ||
138 | if (mn->ops->invalidate_range_end) | ||
139 | mn->ops->invalidate_range_end(mn, mm, start, end); | ||
140 | } | ||
141 | rcu_read_unlock(); | ||
142 | } | ||
143 | |||
144 | static int do_mmu_notifier_register(struct mmu_notifier *mn, | ||
145 | struct mm_struct *mm, | ||
146 | int take_mmap_sem) | ||
147 | { | ||
148 | struct mmu_notifier_mm *mmu_notifier_mm; | ||
149 | int ret; | ||
150 | |||
151 | BUG_ON(atomic_read(&mm->mm_users) <= 0); | ||
152 | |||
153 | ret = -ENOMEM; | ||
154 | mmu_notifier_mm = kmalloc(sizeof(struct mmu_notifier_mm), GFP_KERNEL); | ||
155 | if (unlikely(!mmu_notifier_mm)) | ||
156 | goto out; | ||
157 | |||
158 | if (take_mmap_sem) | ||
159 | down_write(&mm->mmap_sem); | ||
160 | ret = mm_take_all_locks(mm); | ||
161 | if (unlikely(ret)) | ||
162 | goto out_cleanup; | ||
163 | |||
164 | if (!mm_has_notifiers(mm)) { | ||
165 | INIT_HLIST_HEAD(&mmu_notifier_mm->list); | ||
166 | spin_lock_init(&mmu_notifier_mm->lock); | ||
167 | mm->mmu_notifier_mm = mmu_notifier_mm; | ||
168 | mmu_notifier_mm = NULL; | ||
169 | } | ||
170 | atomic_inc(&mm->mm_count); | ||
171 | |||
172 | /* | ||
173 | * Serialize the update against mmu_notifier_unregister. A | ||
174 | * side note: mmu_notifier_release can't run concurrently with | ||
175 | * us because we hold the mm_users pin (either implicitly as | ||
176 | * current->mm or explicitly with get_task_mm() or similar). | ||
177 | * We can't race against any other mmu notifier method either | ||
178 | * thanks to mm_take_all_locks(). | ||
179 | */ | ||
180 | spin_lock(&mm->mmu_notifier_mm->lock); | ||
181 | hlist_add_head(&mn->hlist, &mm->mmu_notifier_mm->list); | ||
182 | spin_unlock(&mm->mmu_notifier_mm->lock); | ||
183 | |||
184 | mm_drop_all_locks(mm); | ||
185 | out_cleanup: | ||
186 | if (take_mmap_sem) | ||
187 | up_write(&mm->mmap_sem); | ||
188 | /* kfree() does nothing if mmu_notifier_mm is NULL */ | ||
189 | kfree(mmu_notifier_mm); | ||
190 | out: | ||
191 | BUG_ON(atomic_read(&mm->mm_users) <= 0); | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Must not hold mmap_sem nor any other VM related lock when calling | ||
197 | * this registration function. Must also ensure mm_users can't go down | ||
198 | * to zero while this runs to avoid races with mmu_notifier_release, | ||
199 | * so mm has to be current->mm or the mm should be pinned safely such | ||
200 | * as with get_task_mm(). If the mm is not current->mm, the mm_users | ||
201 | * pin should be released by calling mmput after mmu_notifier_register | ||
202 | * returns. mmu_notifier_unregister must be always called to | ||
203 | * unregister the notifier. mm_count is automatically pinned to allow | ||
204 | * mmu_notifier_unregister to safely run at any time later, before or | ||
205 | * after exit_mmap. ->release will always be called before exit_mmap | ||
206 | * frees the pages. | ||
207 | */ | ||
208 | int mmu_notifier_register(struct mmu_notifier *mn, struct mm_struct *mm) | ||
209 | { | ||
210 | return do_mmu_notifier_register(mn, mm, 1); | ||
211 | } | ||
212 | EXPORT_SYMBOL_GPL(mmu_notifier_register); | ||
213 | |||
214 | /* | ||
215 | * Same as mmu_notifier_register but here the caller must hold the | ||
216 | * mmap_sem in write mode. | ||
217 | */ | ||
218 | int __mmu_notifier_register(struct mmu_notifier *mn, struct mm_struct *mm) | ||
219 | { | ||
220 | return do_mmu_notifier_register(mn, mm, 0); | ||
221 | } | ||
222 | EXPORT_SYMBOL_GPL(__mmu_notifier_register); | ||
223 | |||
224 | /* this is called after the last mmu_notifier_unregister() returned */ | ||
225 | void __mmu_notifier_mm_destroy(struct mm_struct *mm) | ||
226 | { | ||
227 | BUG_ON(!hlist_empty(&mm->mmu_notifier_mm->list)); | ||
228 | kfree(mm->mmu_notifier_mm); | ||
229 | mm->mmu_notifier_mm = LIST_POISON1; /* debug */ | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * This releases the mm_count pin automatically and frees the mm | ||
234 | * structure if it was the last user of it. It serializes against | ||
235 | * running mmu notifiers with RCU and against mmu_notifier_unregister | ||
236 | * with the unregister lock + RCU. All sptes must be dropped before | ||
237 | * calling mmu_notifier_unregister. ->release or any other notifier | ||
238 | * method may be invoked concurrently with mmu_notifier_unregister, | ||
239 | * and only after mmu_notifier_unregister returned we're guaranteed | ||
240 | * that ->release or any other method can't run anymore. | ||
241 | */ | ||
242 | void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm) | ||
243 | { | ||
244 | BUG_ON(atomic_read(&mm->mm_count) <= 0); | ||
245 | |||
246 | spin_lock(&mm->mmu_notifier_mm->lock); | ||
247 | if (!hlist_unhashed(&mn->hlist)) { | ||
248 | hlist_del_rcu(&mn->hlist); | ||
249 | |||
250 | /* | ||
251 | * RCU here will force exit_mmap to wait ->release to finish | ||
252 | * before freeing the pages. | ||
253 | */ | ||
254 | rcu_read_lock(); | ||
255 | spin_unlock(&mm->mmu_notifier_mm->lock); | ||
256 | /* | ||
257 | * exit_mmap will block in mmu_notifier_release to | ||
258 | * guarantee ->release is called before freeing the | ||
259 | * pages. | ||
260 | */ | ||
261 | if (mn->ops->release) | ||
262 | mn->ops->release(mn, mm); | ||
263 | rcu_read_unlock(); | ||
264 | } else | ||
265 | spin_unlock(&mm->mmu_notifier_mm->lock); | ||
266 | |||
267 | /* | ||
268 | * Wait any running method to finish, of course including | ||
269 | * ->release if it was run by mmu_notifier_relase instead of us. | ||
270 | */ | ||
271 | synchronize_rcu(); | ||
272 | |||
273 | BUG_ON(atomic_read(&mm->mm_count) <= 0); | ||
274 | |||
275 | mmdrop(mm); | ||
276 | } | ||
277 | EXPORT_SYMBOL_GPL(mmu_notifier_unregister); | ||
diff --git a/mm/mprotect.c b/mm/mprotect.c index abd645a3b0a0..fded06f923f4 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/syscalls.h> | 21 | #include <linux/syscalls.h> |
22 | #include <linux/swap.h> | 22 | #include <linux/swap.h> |
23 | #include <linux/swapops.h> | 23 | #include <linux/swapops.h> |
24 | #include <linux/mmu_notifier.h> | ||
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
25 | #include <asm/pgtable.h> | 26 | #include <asm/pgtable.h> |
26 | #include <asm/cacheflush.h> | 27 | #include <asm/cacheflush.h> |
@@ -203,10 +204,12 @@ success: | |||
203 | dirty_accountable = 1; | 204 | dirty_accountable = 1; |
204 | } | 205 | } |
205 | 206 | ||
207 | mmu_notifier_invalidate_range_start(mm, start, end); | ||
206 | if (is_vm_hugetlb_page(vma)) | 208 | if (is_vm_hugetlb_page(vma)) |
207 | hugetlb_change_protection(vma, start, end, vma->vm_page_prot); | 209 | hugetlb_change_protection(vma, start, end, vma->vm_page_prot); |
208 | else | 210 | else |
209 | change_protection(vma, start, end, vma->vm_page_prot, dirty_accountable); | 211 | change_protection(vma, start, end, vma->vm_page_prot, dirty_accountable); |
212 | mmu_notifier_invalidate_range_end(mm, start, end); | ||
210 | vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); | 213 | vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); |
211 | vm_stat_account(mm, newflags, vma->vm_file, nrpages); | 214 | vm_stat_account(mm, newflags, vma->vm_file, nrpages); |
212 | return 0; | 215 | return 0; |
diff --git a/mm/mremap.c b/mm/mremap.c index 08e3c7f2bd15..1a7743923c8c 100644 --- a/mm/mremap.c +++ b/mm/mremap.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/highmem.h> | 18 | #include <linux/highmem.h> |
19 | #include <linux/security.h> | 19 | #include <linux/security.h> |
20 | #include <linux/syscalls.h> | 20 | #include <linux/syscalls.h> |
21 | #include <linux/mmu_notifier.h> | ||
21 | 22 | ||
22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
23 | #include <asm/cacheflush.h> | 24 | #include <asm/cacheflush.h> |
@@ -74,7 +75,11 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, | |||
74 | struct mm_struct *mm = vma->vm_mm; | 75 | struct mm_struct *mm = vma->vm_mm; |
75 | pte_t *old_pte, *new_pte, pte; | 76 | pte_t *old_pte, *new_pte, pte; |
76 | spinlock_t *old_ptl, *new_ptl; | 77 | spinlock_t *old_ptl, *new_ptl; |
78 | unsigned long old_start; | ||
77 | 79 | ||
80 | old_start = old_addr; | ||
81 | mmu_notifier_invalidate_range_start(vma->vm_mm, | ||
82 | old_start, old_end); | ||
78 | if (vma->vm_file) { | 83 | if (vma->vm_file) { |
79 | /* | 84 | /* |
80 | * Subtle point from Rajesh Venkatasubramanian: before | 85 | * Subtle point from Rajesh Venkatasubramanian: before |
@@ -116,6 +121,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, | |||
116 | pte_unmap_unlock(old_pte - 1, old_ptl); | 121 | pte_unmap_unlock(old_pte - 1, old_ptl); |
117 | if (mapping) | 122 | if (mapping) |
118 | spin_unlock(&mapping->i_mmap_lock); | 123 | spin_unlock(&mapping->i_mmap_lock); |
124 | mmu_notifier_invalidate_range_end(vma->vm_mm, old_start, old_end); | ||
119 | } | 125 | } |
120 | 126 | ||
121 | #define LATENCY_LIMIT (64 * PAGE_SIZE) | 127 | #define LATENCY_LIMIT (64 * PAGE_SIZE) |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3cf3d05b6bd4..401d104d2bb6 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -3753,23 +3753,6 @@ unsigned long __init find_min_pfn_with_active_regions(void) | |||
3753 | return find_min_pfn_for_node(MAX_NUMNODES); | 3753 | return find_min_pfn_for_node(MAX_NUMNODES); |
3754 | } | 3754 | } |
3755 | 3755 | ||
3756 | /** | ||
3757 | * find_max_pfn_with_active_regions - Find the maximum PFN registered | ||
3758 | * | ||
3759 | * It returns the maximum PFN based on information provided via | ||
3760 | * add_active_range(). | ||
3761 | */ | ||
3762 | unsigned long __init find_max_pfn_with_active_regions(void) | ||
3763 | { | ||
3764 | int i; | ||
3765 | unsigned long max_pfn = 0; | ||
3766 | |||
3767 | for (i = 0; i < nr_nodemap_entries; i++) | ||
3768 | max_pfn = max(max_pfn, early_node_map[i].end_pfn); | ||
3769 | |||
3770 | return max_pfn; | ||
3771 | } | ||
3772 | |||
3773 | /* | 3756 | /* |
3774 | * early_calculate_totalpages() | 3757 | * early_calculate_totalpages() |
3775 | * Sum pages in active regions for movable zone. | 3758 | * Sum pages in active regions for movable zone. |
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/module.h> | 49 | #include <linux/module.h> |
50 | #include <linux/kallsyms.h> | 50 | #include <linux/kallsyms.h> |
51 | #include <linux/memcontrol.h> | 51 | #include <linux/memcontrol.h> |
52 | #include <linux/mmu_notifier.h> | ||
52 | 53 | ||
53 | #include <asm/tlbflush.h> | 54 | #include <asm/tlbflush.h> |
54 | 55 | ||
@@ -287,7 +288,7 @@ static int page_referenced_one(struct page *page, | |||
287 | if (vma->vm_flags & VM_LOCKED) { | 288 | if (vma->vm_flags & VM_LOCKED) { |
288 | referenced++; | 289 | referenced++; |
289 | *mapcount = 1; /* break early from loop */ | 290 | *mapcount = 1; /* break early from loop */ |
290 | } else if (ptep_clear_flush_young(vma, address, pte)) | 291 | } else if (ptep_clear_flush_young_notify(vma, address, pte)) |
291 | referenced++; | 292 | referenced++; |
292 | 293 | ||
293 | /* Pretend the page is referenced if the task has the | 294 | /* Pretend the page is referenced if the task has the |
@@ -457,7 +458,7 @@ static int page_mkclean_one(struct page *page, struct vm_area_struct *vma) | |||
457 | pte_t entry; | 458 | pte_t entry; |
458 | 459 | ||
459 | flush_cache_page(vma, address, pte_pfn(*pte)); | 460 | flush_cache_page(vma, address, pte_pfn(*pte)); |
460 | entry = ptep_clear_flush(vma, address, pte); | 461 | entry = ptep_clear_flush_notify(vma, address, pte); |
461 | entry = pte_wrprotect(entry); | 462 | entry = pte_wrprotect(entry); |
462 | entry = pte_mkclean(entry); | 463 | entry = pte_mkclean(entry); |
463 | set_pte_at(mm, address, pte, entry); | 464 | set_pte_at(mm, address, pte, entry); |
@@ -666,7 +667,8 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma) | |||
666 | * Leaving it set also helps swapoff to reinstate ptes | 667 | * Leaving it set also helps swapoff to reinstate ptes |
667 | * faster for those pages still in swapcache. | 668 | * faster for those pages still in swapcache. |
668 | */ | 669 | */ |
669 | if (page_test_dirty(page)) { | 670 | if ((!PageAnon(page) || PageSwapCache(page)) && |
671 | page_test_dirty(page)) { | ||
670 | page_clear_dirty(page); | 672 | page_clear_dirty(page); |
671 | set_page_dirty(page); | 673 | set_page_dirty(page); |
672 | } | 674 | } |
@@ -705,14 +707,14 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, | |||
705 | * skipped over this mm) then we should reactivate it. | 707 | * skipped over this mm) then we should reactivate it. |
706 | */ | 708 | */ |
707 | if (!migration && ((vma->vm_flags & VM_LOCKED) || | 709 | if (!migration && ((vma->vm_flags & VM_LOCKED) || |
708 | (ptep_clear_flush_young(vma, address, pte)))) { | 710 | (ptep_clear_flush_young_notify(vma, address, pte)))) { |
709 | ret = SWAP_FAIL; | 711 | ret = SWAP_FAIL; |
710 | goto out_unmap; | 712 | goto out_unmap; |
711 | } | 713 | } |
712 | 714 | ||
713 | /* Nuke the page table entry. */ | 715 | /* Nuke the page table entry. */ |
714 | flush_cache_page(vma, address, page_to_pfn(page)); | 716 | flush_cache_page(vma, address, page_to_pfn(page)); |
715 | pteval = ptep_clear_flush(vma, address, pte); | 717 | pteval = ptep_clear_flush_notify(vma, address, pte); |
716 | 718 | ||
717 | /* Move the dirty bit to the physical page now the pte is gone. */ | 719 | /* Move the dirty bit to the physical page now the pte is gone. */ |
718 | if (pte_dirty(pteval)) | 720 | if (pte_dirty(pteval)) |
@@ -837,12 +839,12 @@ static void try_to_unmap_cluster(unsigned long cursor, | |||
837 | page = vm_normal_page(vma, address, *pte); | 839 | page = vm_normal_page(vma, address, *pte); |
838 | BUG_ON(!page || PageAnon(page)); | 840 | BUG_ON(!page || PageAnon(page)); |
839 | 841 | ||
840 | if (ptep_clear_flush_young(vma, address, pte)) | 842 | if (ptep_clear_flush_young_notify(vma, address, pte)) |
841 | continue; | 843 | continue; |
842 | 844 | ||
843 | /* Nuke the page table entry. */ | 845 | /* Nuke the page table entry. */ |
844 | flush_cache_page(vma, address, pte_pfn(*pte)); | 846 | flush_cache_page(vma, address, pte_pfn(*pte)); |
845 | pteval = ptep_clear_flush(vma, address, pte); | 847 | pteval = ptep_clear_flush_notify(vma, address, pte); |
846 | 848 | ||
847 | /* If nonlinear, store the file page offset in the pte. */ | 849 | /* If nonlinear, store the file page offset in the pte. */ |
848 | if (page->index != linear_page_index(vma, address)) | 850 | if (page->index != linear_page_index(vma, address)) |
diff --git a/mm/shmem.c b/mm/shmem.c index 952d361774bb..c1e5a3b4f758 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -1513,7 +1513,6 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
1513 | inode->i_uid = current->fsuid; | 1513 | inode->i_uid = current->fsuid; |
1514 | inode->i_gid = current->fsgid; | 1514 | inode->i_gid = current->fsgid; |
1515 | inode->i_blocks = 0; | 1515 | inode->i_blocks = 0; |
1516 | inode->i_mapping->a_ops = &shmem_aops; | ||
1517 | inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; | 1516 | inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; |
1518 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 1517 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
1519 | inode->i_generation = get_seconds(); | 1518 | inode->i_generation = get_seconds(); |
@@ -1528,6 +1527,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
1528 | init_special_inode(inode, mode, dev); | 1527 | init_special_inode(inode, mode, dev); |
1529 | break; | 1528 | break; |
1530 | case S_IFREG: | 1529 | case S_IFREG: |
1530 | inode->i_mapping->a_ops = &shmem_aops; | ||
1531 | inode->i_op = &shmem_inode_operations; | 1531 | inode->i_op = &shmem_inode_operations; |
1532 | inode->i_fop = &shmem_file_operations; | 1532 | inode->i_fop = &shmem_file_operations; |
1533 | mpol_shared_policy_init(&info->policy, | 1533 | mpol_shared_policy_init(&info->policy, |
@@ -1929,6 +1929,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s | |||
1929 | return error; | 1929 | return error; |
1930 | } | 1930 | } |
1931 | unlock_page(page); | 1931 | unlock_page(page); |
1932 | inode->i_mapping->a_ops = &shmem_aops; | ||
1932 | inode->i_op = &shmem_symlink_inode_operations; | 1933 | inode->i_op = &shmem_symlink_inode_operations; |
1933 | kaddr = kmap_atomic(page, KM_USER0); | 1934 | kaddr = kmap_atomic(page, KM_USER0); |
1934 | memcpy(kaddr, symname, len); | 1935 | memcpy(kaddr, symname, len); |
@@ -278,9 +278,10 @@ int lru_add_drain_all(void) | |||
278 | * Avoid taking zone->lru_lock if possible, but if it is taken, retain it | 278 | * Avoid taking zone->lru_lock if possible, but if it is taken, retain it |
279 | * for the remainder of the operation. | 279 | * for the remainder of the operation. |
280 | * | 280 | * |
281 | * The locking in this function is against shrink_cache(): we recheck the | 281 | * The locking in this function is against shrink_inactive_list(): we recheck |
282 | * page count inside the lock to see whether shrink_cache grabbed the page | 282 | * the page count inside the lock to see whether shrink_inactive_list() |
283 | * via the LRU. If it did, give up: shrink_cache will free it. | 283 | * grabbed the page via the LRU. If it did, give up: shrink_inactive_list() |
284 | * will free it. | ||
284 | */ | 285 | */ |
285 | void release_pages(struct page **pages, int nr, int cold) | 286 | void release_pages(struct page **pages, int nr, int cold) |
286 | { | 287 | { |
diff --git a/mm/swapfile.c b/mm/swapfile.c index 6beb6251e99d..bb7f79641f9e 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -656,8 +656,8 @@ static int unuse_mm(struct mm_struct *mm, | |||
656 | 656 | ||
657 | if (!down_read_trylock(&mm->mmap_sem)) { | 657 | if (!down_read_trylock(&mm->mmap_sem)) { |
658 | /* | 658 | /* |
659 | * Activate page so shrink_cache is unlikely to unmap its | 659 | * Activate page so shrink_inactive_list is unlikely to unmap |
660 | * ptes while lock is dropped, so swapoff can make progress. | 660 | * its ptes while lock is dropped, so swapoff can make progress. |
661 | */ | 661 | */ |
662 | activate_page(page); | 662 | activate_page(page); |
663 | unlock_page(page); | 663 | unlock_page(page); |
diff --git a/mm/vmscan.c b/mm/vmscan.c index 8f71761bc4b7..75be453628bf 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -1408,7 +1408,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, | |||
1408 | if (sc->nr_scanned && priority < DEF_PRIORITY - 2) | 1408 | if (sc->nr_scanned && priority < DEF_PRIORITY - 2) |
1409 | congestion_wait(WRITE, HZ/10); | 1409 | congestion_wait(WRITE, HZ/10); |
1410 | } | 1410 | } |
1411 | /* top priority shrink_caches still had more to do? don't OOM, then */ | 1411 | /* top priority shrink_zones still had more to do? don't OOM, then */ |
1412 | if (!sc->all_unreclaimable && scan_global_lru(sc)) | 1412 | if (!sc->all_unreclaimable && scan_global_lru(sc)) |
1413 | ret = nr_reclaimed; | 1413 | ret = nr_reclaimed; |
1414 | out: | 1414 | out: |
@@ -1979,7 +1979,7 @@ module_init(kswapd_init) | |||
1979 | int zone_reclaim_mode __read_mostly; | 1979 | int zone_reclaim_mode __read_mostly; |
1980 | 1980 | ||
1981 | #define RECLAIM_OFF 0 | 1981 | #define RECLAIM_OFF 0 |
1982 | #define RECLAIM_ZONE (1<<0) /* Run shrink_cache on the zone */ | 1982 | #define RECLAIM_ZONE (1<<0) /* Run shrink_inactive_list on the zone */ |
1983 | #define RECLAIM_WRITE (1<<1) /* Writeout pages during reclaim */ | 1983 | #define RECLAIM_WRITE (1<<1) /* Writeout pages during reclaim */ |
1984 | #define RECLAIM_SWAP (1<<2) /* Swap pages out during reclaim */ | 1984 | #define RECLAIM_SWAP (1<<2) /* Swap pages out during reclaim */ |
1985 | 1985 | ||
diff --git a/net/Kconfig b/net/Kconfig index b98668751749..7612cc8c337c 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
@@ -2,9 +2,7 @@ | |||
2 | # Network configuration | 2 | # Network configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "Networking" | 5 | menuconfig NET |
6 | |||
7 | config NET | ||
8 | bool "Networking support" | 6 | bool "Networking support" |
9 | ---help--- | 7 | ---help--- |
10 | Unless you really know what you are doing, you should say Y here. | 8 | Unless you really know what you are doing, you should say Y here. |
@@ -22,7 +20,6 @@ config NET | |||
22 | recommended to read the NET-HOWTO, available from | 20 | recommended to read the NET-HOWTO, available from |
23 | <http://www.tldp.org/docs.html#howto>. | 21 | <http://www.tldp.org/docs.html#howto>. |
24 | 22 | ||
25 | # Make sure that all config symbols are dependent on NET | ||
26 | if NET | 23 | if NET |
27 | 24 | ||
28 | menu "Networking options" | 25 | menu "Networking options" |
@@ -252,5 +249,3 @@ source "net/rfkill/Kconfig" | |||
252 | source "net/9p/Kconfig" | 249 | source "net/9p/Kconfig" |
253 | 250 | ||
254 | endif # if NET | 251 | endif # if NET |
255 | endmenu # Networking | ||
256 | |||
diff --git a/net/core/dev.c b/net/core/dev.c index 8d13a9b9f1df..63d6bcddbf46 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2100,7 +2100,7 @@ static int ing_filter(struct sk_buff *skb) | |||
2100 | rxq = &dev->rx_queue; | 2100 | rxq = &dev->rx_queue; |
2101 | 2101 | ||
2102 | q = rxq->qdisc; | 2102 | q = rxq->qdisc; |
2103 | if (q) { | 2103 | if (q != &noop_qdisc) { |
2104 | spin_lock(qdisc_lock(q)); | 2104 | spin_lock(qdisc_lock(q)); |
2105 | result = qdisc_enqueue_root(skb, q); | 2105 | result = qdisc_enqueue_root(skb, q); |
2106 | spin_unlock(qdisc_lock(q)); | 2106 | spin_unlock(qdisc_lock(q)); |
@@ -2113,7 +2113,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb, | |||
2113 | struct packet_type **pt_prev, | 2113 | struct packet_type **pt_prev, |
2114 | int *ret, struct net_device *orig_dev) | 2114 | int *ret, struct net_device *orig_dev) |
2115 | { | 2115 | { |
2116 | if (!skb->dev->rx_queue.qdisc) | 2116 | if (skb->dev->rx_queue.qdisc == &noop_qdisc) |
2117 | goto out; | 2117 | goto out; |
2118 | 2118 | ||
2119 | if (*pt_prev) { | 2119 | if (*pt_prev) { |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4e0c92274189..84640172d65d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -485,6 +485,9 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) | |||
485 | C(head); | 485 | C(head); |
486 | C(data); | 486 | C(data); |
487 | C(truesize); | 487 | C(truesize); |
488 | #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) | ||
489 | C(do_not_encrypt); | ||
490 | #endif | ||
488 | atomic_set(&n->users, 1); | 491 | atomic_set(&n->users, 1); |
489 | 492 | ||
490 | atomic_inc(&(skb_shinfo(skb)->dataref)); | 493 | atomic_inc(&(skb_shinfo(skb)->dataref)); |
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 834356ea99df..8f5a403f6f6b 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c | |||
@@ -232,6 +232,8 @@ static const struct snmp_mib snmp4_net_list[] = { | |||
232 | SNMP_MIB_ITEM("TCPDSACKIgnoredOld", LINUX_MIB_TCPDSACKIGNOREDOLD), | 232 | SNMP_MIB_ITEM("TCPDSACKIgnoredOld", LINUX_MIB_TCPDSACKIGNOREDOLD), |
233 | SNMP_MIB_ITEM("TCPDSACKIgnoredNoUndo", LINUX_MIB_TCPDSACKIGNOREDNOUNDO), | 233 | SNMP_MIB_ITEM("TCPDSACKIgnoredNoUndo", LINUX_MIB_TCPDSACKIGNOREDNOUNDO), |
234 | SNMP_MIB_ITEM("TCPSpuriousRTOs", LINUX_MIB_TCPSPURIOUSRTOS), | 234 | SNMP_MIB_ITEM("TCPSpuriousRTOs", LINUX_MIB_TCPSPURIOUSRTOS), |
235 | SNMP_MIB_ITEM("TCPMD5NotFound", LINUX_MIB_TCPMD5NOTFOUND), | ||
236 | SNMP_MIB_ITEM("TCPMD5Unexpected", LINUX_MIB_TCPMD5UNEXPECTED), | ||
235 | SNMP_MIB_SENTINEL | 237 | SNMP_MIB_SENTINEL |
236 | }; | 238 | }; |
237 | 239 | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a2b06d0cc26b..b3875c0d83c7 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1116,18 +1116,12 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) | |||
1116 | return 0; | 1116 | return 0; |
1117 | 1117 | ||
1118 | if (hash_expected && !hash_location) { | 1118 | if (hash_expected && !hash_location) { |
1119 | LIMIT_NETDEBUG(KERN_INFO "MD5 Hash expected but NOT found " | 1119 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND); |
1120 | "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", | ||
1121 | NIPQUAD(iph->saddr), ntohs(th->source), | ||
1122 | NIPQUAD(iph->daddr), ntohs(th->dest)); | ||
1123 | return 1; | 1120 | return 1; |
1124 | } | 1121 | } |
1125 | 1122 | ||
1126 | if (!hash_expected && hash_location) { | 1123 | if (!hash_expected && hash_location) { |
1127 | LIMIT_NETDEBUG(KERN_INFO "MD5 Hash NOT expected but found " | 1124 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED); |
1128 | "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", | ||
1129 | NIPQUAD(iph->saddr), ntohs(th->source), | ||
1130 | NIPQUAD(iph->daddr), ntohs(th->dest)); | ||
1131 | return 1; | 1125 | return 1; |
1132 | } | 1126 | } |
1133 | 1127 | ||
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index f7b535dec860..410046a8cc91 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -732,7 +732,7 @@ int datagram_send_ctl(struct net *net, | |||
732 | LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n", | 732 | LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n", |
733 | cmsg->cmsg_type); | 733 | cmsg->cmsg_type); |
734 | err = -EINVAL; | 734 | err = -EINVAL; |
735 | break; | 735 | goto exit_f; |
736 | } | 736 | } |
737 | } | 737 | } |
738 | 738 | ||
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index f82f6074cf85..0179b66864f1 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -286,7 +286,6 @@ proc_net_fail: | |||
286 | 286 | ||
287 | void ipv6_misc_proc_exit(void) | 287 | void ipv6_misc_proc_exit(void) |
288 | { | 288 | { |
289 | proc_net_remove(&init_net, "sockstat6"); | ||
290 | proc_net_remove(&init_net, "dev_snmp6"); | 289 | proc_net_remove(&init_net, "dev_snmp6"); |
291 | proc_net_remove(&init_net, "snmp6"); | 290 | proc_net_remove(&init_net, "snmp6"); |
292 | unregister_pernet_subsys(&ipv6_proc_ops); | 291 | unregister_pernet_subsys(&ipv6_proc_ops); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index cff778b23a7f..1db45216b232 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -849,28 +849,17 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
849 | hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); | 849 | hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); |
850 | hash_location = tcp_parse_md5sig_option(th); | 850 | hash_location = tcp_parse_md5sig_option(th); |
851 | 851 | ||
852 | /* do we have a hash as expected? */ | 852 | /* We've parsed the options - do we have a hash? */ |
853 | if (!hash_expected) { | 853 | if (!hash_expected && !hash_location) |
854 | if (!hash_location) | 854 | return 0; |
855 | return 0; | 855 | |
856 | if (net_ratelimit()) { | 856 | if (hash_expected && !hash_location) { |
857 | printk(KERN_INFO "MD5 Hash NOT expected but found " | 857 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND); |
858 | "(" NIP6_FMT ", %u)->" | ||
859 | "(" NIP6_FMT ", %u)\n", | ||
860 | NIP6(ip6h->saddr), ntohs(th->source), | ||
861 | NIP6(ip6h->daddr), ntohs(th->dest)); | ||
862 | } | ||
863 | return 1; | 858 | return 1; |
864 | } | 859 | } |
865 | 860 | ||
866 | if (!hash_location) { | 861 | if (!hash_expected && hash_location) { |
867 | if (net_ratelimit()) { | 862 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED); |
868 | printk(KERN_INFO "MD5 Hash expected but NOT found " | ||
869 | "(" NIP6_FMT ", %u)->" | ||
870 | "(" NIP6_FMT ", %u)\n", | ||
871 | NIP6(ip6h->saddr), ntohs(th->source), | ||
872 | NIP6(ip6h->daddr), ntohs(th->dest)); | ||
873 | } | ||
874 | return 1; | 863 | return 1; |
875 | } | 864 | } |
876 | 865 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8e7ba0e62cf5..297c257864c7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -81,6 +81,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | |||
81 | enum nl80211_iftype type, u32 *flags, | 81 | enum nl80211_iftype type, u32 *flags, |
82 | struct vif_params *params) | 82 | struct vif_params *params) |
83 | { | 83 | { |
84 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
84 | struct net_device *dev; | 85 | struct net_device *dev; |
85 | enum ieee80211_if_types itype; | 86 | enum ieee80211_if_types itype; |
86 | struct ieee80211_sub_if_data *sdata; | 87 | struct ieee80211_sub_if_data *sdata; |
@@ -95,6 +96,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | |||
95 | if (itype == IEEE80211_IF_TYPE_INVALID) | 96 | if (itype == IEEE80211_IF_TYPE_INVALID) |
96 | return -EINVAL; | 97 | return -EINVAL; |
97 | 98 | ||
99 | if (dev == local->mdev) | ||
100 | return -EOPNOTSUPP; | ||
101 | |||
98 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 102 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
99 | 103 | ||
100 | ret = ieee80211_if_change_type(sdata, itype); | 104 | ret = ieee80211_if_change_type(sdata, itype); |
@@ -117,12 +121,16 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
117 | u8 key_idx, u8 *mac_addr, | 121 | u8 key_idx, u8 *mac_addr, |
118 | struct key_params *params) | 122 | struct key_params *params) |
119 | { | 123 | { |
124 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
120 | struct ieee80211_sub_if_data *sdata; | 125 | struct ieee80211_sub_if_data *sdata; |
121 | struct sta_info *sta = NULL; | 126 | struct sta_info *sta = NULL; |
122 | enum ieee80211_key_alg alg; | 127 | enum ieee80211_key_alg alg; |
123 | struct ieee80211_key *key; | 128 | struct ieee80211_key *key; |
124 | int err; | 129 | int err; |
125 | 130 | ||
131 | if (dev == local->mdev) | ||
132 | return -EOPNOTSUPP; | ||
133 | |||
126 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 134 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
127 | 135 | ||
128 | switch (params->cipher) { | 136 | switch (params->cipher) { |
@@ -167,10 +175,14 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
167 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 175 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
168 | u8 key_idx, u8 *mac_addr) | 176 | u8 key_idx, u8 *mac_addr) |
169 | { | 177 | { |
178 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
170 | struct ieee80211_sub_if_data *sdata; | 179 | struct ieee80211_sub_if_data *sdata; |
171 | struct sta_info *sta; | 180 | struct sta_info *sta; |
172 | int ret; | 181 | int ret; |
173 | 182 | ||
183 | if (dev == local->mdev) | ||
184 | return -EOPNOTSUPP; | ||
185 | |||
174 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 186 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
175 | 187 | ||
176 | rcu_read_lock(); | 188 | rcu_read_lock(); |
@@ -211,7 +223,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
211 | void (*callback)(void *cookie, | 223 | void (*callback)(void *cookie, |
212 | struct key_params *params)) | 224 | struct key_params *params)) |
213 | { | 225 | { |
214 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 226 | struct ieee80211_local *local = wiphy_priv(wiphy); |
227 | struct ieee80211_sub_if_data *sdata; | ||
215 | struct sta_info *sta = NULL; | 228 | struct sta_info *sta = NULL; |
216 | u8 seq[6] = {0}; | 229 | u8 seq[6] = {0}; |
217 | struct key_params params; | 230 | struct key_params params; |
@@ -220,6 +233,11 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
220 | u16 iv16; | 233 | u16 iv16; |
221 | int err = -ENOENT; | 234 | int err = -ENOENT; |
222 | 235 | ||
236 | if (dev == local->mdev) | ||
237 | return -EOPNOTSUPP; | ||
238 | |||
239 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
240 | |||
223 | rcu_read_lock(); | 241 | rcu_read_lock(); |
224 | 242 | ||
225 | if (mac_addr) { | 243 | if (mac_addr) { |
@@ -293,8 +311,12 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, | |||
293 | struct net_device *dev, | 311 | struct net_device *dev, |
294 | u8 key_idx) | 312 | u8 key_idx) |
295 | { | 313 | { |
314 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
296 | struct ieee80211_sub_if_data *sdata; | 315 | struct ieee80211_sub_if_data *sdata; |
297 | 316 | ||
317 | if (dev == local->mdev) | ||
318 | return -EOPNOTSUPP; | ||
319 | |||
298 | rcu_read_lock(); | 320 | rcu_read_lock(); |
299 | 321 | ||
300 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 322 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -475,9 +497,15 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
475 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | 497 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, |
476 | struct beacon_parameters *params) | 498 | struct beacon_parameters *params) |
477 | { | 499 | { |
478 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 500 | struct ieee80211_local *local = wiphy_priv(wiphy); |
501 | struct ieee80211_sub_if_data *sdata; | ||
479 | struct beacon_data *old; | 502 | struct beacon_data *old; |
480 | 503 | ||
504 | if (dev == local->mdev) | ||
505 | return -EOPNOTSUPP; | ||
506 | |||
507 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
508 | |||
481 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP) | 509 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP) |
482 | return -EINVAL; | 510 | return -EINVAL; |
483 | 511 | ||
@@ -492,9 +520,15 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
492 | static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | 520 | static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, |
493 | struct beacon_parameters *params) | 521 | struct beacon_parameters *params) |
494 | { | 522 | { |
495 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 523 | struct ieee80211_local *local = wiphy_priv(wiphy); |
524 | struct ieee80211_sub_if_data *sdata; | ||
496 | struct beacon_data *old; | 525 | struct beacon_data *old; |
497 | 526 | ||
527 | if (dev == local->mdev) | ||
528 | return -EOPNOTSUPP; | ||
529 | |||
530 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
531 | |||
498 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP) | 532 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP) |
499 | return -EINVAL; | 533 | return -EINVAL; |
500 | 534 | ||
@@ -508,9 +542,15 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
508 | 542 | ||
509 | static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | 543 | static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) |
510 | { | 544 | { |
511 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 545 | struct ieee80211_local *local = wiphy_priv(wiphy); |
546 | struct ieee80211_sub_if_data *sdata; | ||
512 | struct beacon_data *old; | 547 | struct beacon_data *old; |
513 | 548 | ||
549 | if (dev == local->mdev) | ||
550 | return -EOPNOTSUPP; | ||
551 | |||
552 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
553 | |||
514 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP) | 554 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP) |
515 | return -EINVAL; | 555 | return -EINVAL; |
516 | 556 | ||
@@ -646,11 +686,14 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
646 | static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | 686 | static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, |
647 | u8 *mac, struct station_parameters *params) | 687 | u8 *mac, struct station_parameters *params) |
648 | { | 688 | { |
649 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 689 | struct ieee80211_local *local = wiphy_priv(wiphy); |
650 | struct sta_info *sta; | 690 | struct sta_info *sta; |
651 | struct ieee80211_sub_if_data *sdata; | 691 | struct ieee80211_sub_if_data *sdata; |
652 | int err; | 692 | int err; |
653 | 693 | ||
694 | if (dev == local->mdev || params->vlan == local->mdev) | ||
695 | return -EOPNOTSUPP; | ||
696 | |||
654 | /* Prevent a race with changing the rate control algorithm */ | 697 | /* Prevent a race with changing the rate control algorithm */ |
655 | if (!netif_running(dev)) | 698 | if (!netif_running(dev)) |
656 | return -ENETDOWN; | 699 | return -ENETDOWN; |
@@ -701,10 +744,15 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
701 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 744 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
702 | u8 *mac) | 745 | u8 *mac) |
703 | { | 746 | { |
704 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 747 | struct ieee80211_local *local = wiphy_priv(wiphy); |
705 | struct ieee80211_local *local = sdata->local; | 748 | struct ieee80211_sub_if_data *sdata; |
706 | struct sta_info *sta; | 749 | struct sta_info *sta; |
707 | 750 | ||
751 | if (dev == local->mdev) | ||
752 | return -EOPNOTSUPP; | ||
753 | |||
754 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
755 | |||
708 | if (mac) { | 756 | if (mac) { |
709 | rcu_read_lock(); | 757 | rcu_read_lock(); |
710 | 758 | ||
@@ -730,10 +778,13 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
730 | u8 *mac, | 778 | u8 *mac, |
731 | struct station_parameters *params) | 779 | struct station_parameters *params) |
732 | { | 780 | { |
733 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 781 | struct ieee80211_local *local = wiphy_priv(wiphy); |
734 | struct sta_info *sta; | 782 | struct sta_info *sta; |
735 | struct ieee80211_sub_if_data *vlansdata; | 783 | struct ieee80211_sub_if_data *vlansdata; |
736 | 784 | ||
785 | if (dev == local->mdev || params->vlan == local->mdev) | ||
786 | return -EOPNOTSUPP; | ||
787 | |||
737 | rcu_read_lock(); | 788 | rcu_read_lock(); |
738 | 789 | ||
739 | /* XXX: get sta belonging to dev */ | 790 | /* XXX: get sta belonging to dev */ |
@@ -752,7 +803,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
752 | return -EINVAL; | 803 | return -EINVAL; |
753 | } | 804 | } |
754 | 805 | ||
755 | sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 806 | sta->sdata = vlansdata; |
756 | ieee80211_send_layer2_update(sta); | 807 | ieee80211_send_layer2_update(sta); |
757 | } | 808 | } |
758 | 809 | ||
@@ -767,15 +818,20 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
767 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | 818 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, |
768 | u8 *dst, u8 *next_hop) | 819 | u8 *dst, u8 *next_hop) |
769 | { | 820 | { |
770 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 821 | struct ieee80211_local *local = wiphy_priv(wiphy); |
771 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 822 | struct ieee80211_sub_if_data *sdata; |
772 | struct mesh_path *mpath; | 823 | struct mesh_path *mpath; |
773 | struct sta_info *sta; | 824 | struct sta_info *sta; |
774 | int err; | 825 | int err; |
775 | 826 | ||
827 | if (dev == local->mdev) | ||
828 | return -EOPNOTSUPP; | ||
829 | |||
776 | if (!netif_running(dev)) | 830 | if (!netif_running(dev)) |
777 | return -ENETDOWN; | 831 | return -ENETDOWN; |
778 | 832 | ||
833 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
834 | |||
779 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | 835 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) |
780 | return -ENOTSUPP; | 836 | return -ENOTSUPP; |
781 | 837 | ||
@@ -817,14 +873,19 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
817 | struct net_device *dev, | 873 | struct net_device *dev, |
818 | u8 *dst, u8 *next_hop) | 874 | u8 *dst, u8 *next_hop) |
819 | { | 875 | { |
820 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 876 | struct ieee80211_local *local = wiphy_priv(wiphy); |
821 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 877 | struct ieee80211_sub_if_data *sdata; |
822 | struct mesh_path *mpath; | 878 | struct mesh_path *mpath; |
823 | struct sta_info *sta; | 879 | struct sta_info *sta; |
824 | 880 | ||
881 | if (dev == local->mdev) | ||
882 | return -EOPNOTSUPP; | ||
883 | |||
825 | if (!netif_running(dev)) | 884 | if (!netif_running(dev)) |
826 | return -ENETDOWN; | 885 | return -ENETDOWN; |
827 | 886 | ||
887 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
888 | |||
828 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | 889 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) |
829 | return -ENOTSUPP; | 890 | return -ENOTSUPP; |
830 | 891 | ||
@@ -891,9 +952,15 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
891 | u8 *dst, u8 *next_hop, struct mpath_info *pinfo) | 952 | u8 *dst, u8 *next_hop, struct mpath_info *pinfo) |
892 | 953 | ||
893 | { | 954 | { |
894 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 955 | struct ieee80211_local *local = wiphy_priv(wiphy); |
956 | struct ieee80211_sub_if_data *sdata; | ||
895 | struct mesh_path *mpath; | 957 | struct mesh_path *mpath; |
896 | 958 | ||
959 | if (dev == local->mdev) | ||
960 | return -EOPNOTSUPP; | ||
961 | |||
962 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
963 | |||
897 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | 964 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) |
898 | return -ENOTSUPP; | 965 | return -ENOTSUPP; |
899 | 966 | ||
@@ -913,9 +980,15 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
913 | int idx, u8 *dst, u8 *next_hop, | 980 | int idx, u8 *dst, u8 *next_hop, |
914 | struct mpath_info *pinfo) | 981 | struct mpath_info *pinfo) |
915 | { | 982 | { |
916 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 983 | struct ieee80211_local *local = wiphy_priv(wiphy); |
984 | struct ieee80211_sub_if_data *sdata; | ||
917 | struct mesh_path *mpath; | 985 | struct mesh_path *mpath; |
918 | 986 | ||
987 | if (dev == local->mdev) | ||
988 | return -EOPNOTSUPP; | ||
989 | |||
990 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
991 | |||
919 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | 992 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) |
920 | return -ENOTSUPP; | 993 | return -ENOTSUPP; |
921 | 994 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f1a83d450ea0..a4c5b90de769 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -1233,18 +1233,12 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
1233 | /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to | 1233 | /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to |
1234 | * make a prepared TX frame (one that has been given to hw) to look like brand | 1234 | * make a prepared TX frame (one that has been given to hw) to look like brand |
1235 | * new IEEE 802.11 frame that is ready to go through TX processing again. | 1235 | * new IEEE 802.11 frame that is ready to go through TX processing again. |
1236 | * Also, tx_packet_data in cb is restored from tx_control. */ | 1236 | */ |
1237 | static void ieee80211_remove_tx_extra(struct ieee80211_local *local, | 1237 | static void ieee80211_remove_tx_extra(struct ieee80211_local *local, |
1238 | struct ieee80211_key *key, | 1238 | struct ieee80211_key *key, |
1239 | struct sk_buff *skb) | 1239 | struct sk_buff *skb) |
1240 | { | 1240 | { |
1241 | int hdrlen, iv_len, mic_len; | 1241 | int hdrlen, iv_len, mic_len; |
1242 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1243 | |||
1244 | info->flags &= IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
1245 | IEEE80211_TX_CTL_DO_NOT_ENCRYPT | | ||
1246 | IEEE80211_TX_CTL_REQUEUE | | ||
1247 | IEEE80211_TX_CTL_EAPOL_FRAME; | ||
1248 | 1242 | ||
1249 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | 1243 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); |
1250 | 1244 | ||
@@ -1731,8 +1725,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1731 | result = ieee80211_wep_init(local); | 1725 | result = ieee80211_wep_init(local); |
1732 | 1726 | ||
1733 | if (result < 0) { | 1727 | if (result < 0) { |
1734 | printk(KERN_DEBUG "%s: Failed to initialize wep\n", | 1728 | printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", |
1735 | wiphy_name(local->hw.wiphy)); | 1729 | wiphy_name(local->hw.wiphy), result); |
1736 | goto fail_wep; | 1730 | goto fail_wep; |
1737 | } | 1731 | } |
1738 | 1732 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d7c371e36bf0..acb04133a95d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -606,7 +606,6 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, | |||
606 | int encrypt) | 606 | int encrypt) |
607 | { | 607 | { |
608 | struct ieee80211_sub_if_data *sdata; | 608 | struct ieee80211_sub_if_data *sdata; |
609 | struct ieee80211_tx_info *info; | ||
610 | 609 | ||
611 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 610 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
612 | skb->dev = sdata->local->mdev; | 611 | skb->dev = sdata->local->mdev; |
@@ -614,11 +613,8 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, | |||
614 | skb_set_network_header(skb, 0); | 613 | skb_set_network_header(skb, 0); |
615 | skb_set_transport_header(skb, 0); | 614 | skb_set_transport_header(skb, 0); |
616 | 615 | ||
617 | info = IEEE80211_SKB_CB(skb); | 616 | skb->iif = sdata->dev->ifindex; |
618 | memset(info, 0, sizeof(struct ieee80211_tx_info)); | 617 | skb->do_not_encrypt = !encrypt; |
619 | info->control.ifindex = sdata->dev->ifindex; | ||
620 | if (!encrypt) | ||
621 | info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; | ||
622 | 618 | ||
623 | dev_queue_xmit(skb); | 619 | dev_queue_xmit(skb); |
624 | } | 620 | } |
@@ -3303,6 +3299,7 @@ void ieee80211_start_mesh(struct net_device *dev) | |||
3303 | ifsta = &sdata->u.sta; | 3299 | ifsta = &sdata->u.sta; |
3304 | ifsta->state = IEEE80211_MESH_UP; | 3300 | ifsta->state = IEEE80211_MESH_UP; |
3305 | ieee80211_sta_timer((unsigned long)sdata); | 3301 | ieee80211_sta_timer((unsigned long)sdata); |
3302 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | ||
3306 | } | 3303 | } |
3307 | #endif | 3304 | #endif |
3308 | 3305 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0fbadd8b983c..69019e943873 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -305,7 +305,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
305 | rcu_read_unlock(); | 305 | rcu_read_unlock(); |
306 | 306 | ||
307 | local->total_ps_buffered = total; | 307 | local->total_ps_buffered = total; |
308 | #ifdef MAC80211_VERBOSE_PS_DEBUG | 308 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
309 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", | 309 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", |
310 | wiphy_name(local->hw.wiphy), purged); | 310 | wiphy_name(local->hw.wiphy), purged); |
311 | #endif | 311 | #endif |
@@ -342,7 +342,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
342 | purge_old_ps_buffers(tx->local); | 342 | purge_old_ps_buffers(tx->local); |
343 | if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= | 343 | if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= |
344 | AP_MAX_BC_BUFFER) { | 344 | AP_MAX_BC_BUFFER) { |
345 | #ifdef MAC80211_VERBOSE_PS_DEBUG | 345 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
346 | if (net_ratelimit()) { | 346 | if (net_ratelimit()) { |
347 | printk(KERN_DEBUG "%s: BC TX buffer full - " | 347 | printk(KERN_DEBUG "%s: BC TX buffer full - " |
348 | "dropping the oldest frame\n", | 348 | "dropping the oldest frame\n", |
@@ -389,7 +389,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
389 | purge_old_ps_buffers(tx->local); | 389 | purge_old_ps_buffers(tx->local); |
390 | if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { | 390 | if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { |
391 | struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); | 391 | struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); |
392 | #ifdef MAC80211_VERBOSE_PS_DEBUG | 392 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
393 | if (net_ratelimit()) { | 393 | if (net_ratelimit()) { |
394 | printk(KERN_DEBUG "%s: STA %s TX " | 394 | printk(KERN_DEBUG "%s: STA %s TX " |
395 | "buffer full - dropping oldest frame\n", | 395 | "buffer full - dropping oldest frame\n", |
@@ -439,14 +439,14 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
439 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 439 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
440 | u16 fc = tx->fc; | 440 | u16 fc = tx->fc; |
441 | 441 | ||
442 | if (unlikely(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) | 442 | if (unlikely(tx->skb->do_not_encrypt)) |
443 | tx->key = NULL; | 443 | tx->key = NULL; |
444 | else if (tx->sta && (key = rcu_dereference(tx->sta->key))) | 444 | else if (tx->sta && (key = rcu_dereference(tx->sta->key))) |
445 | tx->key = key; | 445 | tx->key = key; |
446 | else if ((key = rcu_dereference(tx->sdata->default_key))) | 446 | else if ((key = rcu_dereference(tx->sdata->default_key))) |
447 | tx->key = key; | 447 | tx->key = key; |
448 | else if (tx->sdata->drop_unencrypted && | 448 | else if (tx->sdata->drop_unencrypted && |
449 | !(info->flags & IEEE80211_TX_CTL_EAPOL_FRAME) && | 449 | (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) && |
450 | !(info->flags & IEEE80211_TX_CTL_INJECTED)) { | 450 | !(info->flags & IEEE80211_TX_CTL_INJECTED)) { |
451 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); | 451 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); |
452 | return TX_DROP; | 452 | return TX_DROP; |
@@ -476,7 +476,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
476 | } | 476 | } |
477 | 477 | ||
478 | if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) | 478 | if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) |
479 | info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; | 479 | tx->skb->do_not_encrypt = 1; |
480 | 480 | ||
481 | return TX_CONTINUE; | 481 | return TX_CONTINUE; |
482 | } | 482 | } |
@@ -732,6 +732,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
732 | memcpy(skb_put(frag, copylen), pos, copylen); | 732 | memcpy(skb_put(frag, copylen), pos, copylen); |
733 | memcpy(frag->cb, first->cb, sizeof(frag->cb)); | 733 | memcpy(frag->cb, first->cb, sizeof(frag->cb)); |
734 | skb_copy_queue_mapping(frag, first); | 734 | skb_copy_queue_mapping(frag, first); |
735 | frag->do_not_encrypt = first->do_not_encrypt; | ||
735 | 736 | ||
736 | pos += copylen; | 737 | pos += copylen; |
737 | left -= copylen; | 738 | left -= copylen; |
@@ -852,7 +853,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
852 | 853 | ||
853 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; | 854 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; |
854 | 855 | ||
855 | info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; | 856 | skb->do_not_encrypt = 1; |
856 | info->flags |= IEEE80211_TX_CTL_INJECTED; | 857 | info->flags |= IEEE80211_TX_CTL_INJECTED; |
857 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; | 858 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; |
858 | 859 | ||
@@ -925,8 +926,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
925 | skb_trim(skb, skb->len - FCS_LEN); | 926 | skb_trim(skb, skb->len - FCS_LEN); |
926 | } | 927 | } |
927 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) | 928 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) |
928 | info->flags &= | 929 | tx->skb->do_not_encrypt = 0; |
929 | ~IEEE80211_TX_CTL_DO_NOT_ENCRYPT; | ||
930 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) | 930 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) |
931 | tx->flags |= IEEE80211_TX_FRAGMENTED; | 931 | tx->flags |= IEEE80211_TX_FRAGMENTED; |
932 | break; | 932 | break; |
@@ -1042,10 +1042,9 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, | |||
1042 | struct sk_buff *skb, | 1042 | struct sk_buff *skb, |
1043 | struct net_device *mdev) | 1043 | struct net_device *mdev) |
1044 | { | 1044 | { |
1045 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1046 | struct net_device *dev; | 1045 | struct net_device *dev; |
1047 | 1046 | ||
1048 | dev = dev_get_by_index(&init_net, info->control.ifindex); | 1047 | dev = dev_get_by_index(&init_net, skb->iif); |
1049 | if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { | 1048 | if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { |
1050 | dev_put(dev); | 1049 | dev_put(dev); |
1051 | dev = NULL; | 1050 | dev = NULL; |
@@ -1306,8 +1305,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, | |||
1306 | bool may_encrypt; | 1305 | bool may_encrypt; |
1307 | int ret; | 1306 | int ret; |
1308 | 1307 | ||
1309 | if (info->control.ifindex) | 1308 | if (skb->iif) |
1310 | odev = dev_get_by_index(&init_net, info->control.ifindex); | 1309 | odev = dev_get_by_index(&init_net, skb->iif); |
1311 | if (unlikely(odev && !is_ieee80211_device(odev, dev))) { | 1310 | if (unlikely(odev && !is_ieee80211_device(odev, dev))) { |
1312 | dev_put(odev); | 1311 | dev_put(odev); |
1313 | odev = NULL; | 1312 | odev = NULL; |
@@ -1321,9 +1320,13 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, | |||
1321 | return 0; | 1320 | return 0; |
1322 | } | 1321 | } |
1323 | 1322 | ||
1323 | memset(info, 0, sizeof(*info)); | ||
1324 | |||
1325 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
1326 | |||
1324 | osdata = IEEE80211_DEV_TO_SUB_IF(odev); | 1327 | osdata = IEEE80211_DEV_TO_SUB_IF(odev); |
1325 | 1328 | ||
1326 | may_encrypt = !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT); | 1329 | may_encrypt = !skb->do_not_encrypt; |
1327 | 1330 | ||
1328 | headroom = osdata->local->tx_headroom; | 1331 | headroom = osdata->local->tx_headroom; |
1329 | if (may_encrypt) | 1332 | if (may_encrypt) |
@@ -1348,7 +1351,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1348 | struct net_device *dev) | 1351 | struct net_device *dev) |
1349 | { | 1352 | { |
1350 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1353 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1351 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1352 | struct ieee80211_radiotap_header *prthdr = | 1354 | struct ieee80211_radiotap_header *prthdr = |
1353 | (struct ieee80211_radiotap_header *)skb->data; | 1355 | (struct ieee80211_radiotap_header *)skb->data; |
1354 | u16 len_rthdr; | 1356 | u16 len_rthdr; |
@@ -1371,11 +1373,11 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1371 | skb->dev = local->mdev; | 1373 | skb->dev = local->mdev; |
1372 | 1374 | ||
1373 | /* needed because we set skb device to master */ | 1375 | /* needed because we set skb device to master */ |
1374 | info->control.ifindex = dev->ifindex; | 1376 | skb->iif = dev->ifindex; |
1375 | 1377 | ||
1376 | info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; | 1378 | /* sometimes we do encrypt injected frames, will be fixed |
1377 | /* Interfaces should always request a status report */ | 1379 | * up in radiotap parser if not wanted */ |
1378 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | 1380 | skb->do_not_encrypt = 0; |
1379 | 1381 | ||
1380 | /* | 1382 | /* |
1381 | * fix up the pointers accounting for the radiotap | 1383 | * fix up the pointers accounting for the radiotap |
@@ -1419,7 +1421,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1419 | struct net_device *dev) | 1421 | struct net_device *dev) |
1420 | { | 1422 | { |
1421 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1423 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1422 | struct ieee80211_tx_info *info; | ||
1423 | struct ieee80211_sub_if_data *sdata; | 1424 | struct ieee80211_sub_if_data *sdata; |
1424 | int ret = 1, head_need; | 1425 | int ret = 1, head_need; |
1425 | u16 ethertype, hdrlen, meshhdrlen = 0; | 1426 | u16 ethertype, hdrlen, meshhdrlen = 0; |
@@ -1645,14 +1646,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1645 | nh_pos += hdrlen; | 1646 | nh_pos += hdrlen; |
1646 | h_pos += hdrlen; | 1647 | h_pos += hdrlen; |
1647 | 1648 | ||
1648 | info = IEEE80211_SKB_CB(skb); | 1649 | skb->iif = dev->ifindex; |
1649 | memset(info, 0, sizeof(*info)); | ||
1650 | info->control.ifindex = dev->ifindex; | ||
1651 | if (ethertype == ETH_P_PAE) | ||
1652 | info->flags |= IEEE80211_TX_CTL_EAPOL_FRAME; | ||
1653 | |||
1654 | /* Interfaces should always request a status report */ | ||
1655 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
1656 | 1650 | ||
1657 | skb->dev = local->mdev; | 1651 | skb->dev = local->mdev; |
1658 | dev->stats.tx_packets++; | 1652 | dev->stats.tx_packets++; |
@@ -1922,6 +1916,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1922 | 1916 | ||
1923 | info = IEEE80211_SKB_CB(skb); | 1917 | info = IEEE80211_SKB_CB(skb); |
1924 | 1918 | ||
1919 | skb->do_not_encrypt = 1; | ||
1920 | |||
1925 | info->band = band; | 1921 | info->band = band; |
1926 | rate_control_get_rate(local->mdev, sband, skb, &rsel); | 1922 | rate_control_get_rate(local->mdev, sband, skb, &rsel); |
1927 | 1923 | ||
@@ -1931,7 +1927,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1931 | "no rate found\n", | 1927 | "no rate found\n", |
1932 | wiphy_name(local->hw.wiphy)); | 1928 | wiphy_name(local->hw.wiphy)); |
1933 | } | 1929 | } |
1934 | dev_kfree_skb(skb); | 1930 | dev_kfree_skb_any(skb); |
1935 | skb = NULL; | 1931 | skb = NULL; |
1936 | goto out; | 1932 | goto out; |
1937 | } | 1933 | } |
@@ -1940,7 +1936,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1940 | info->tx_rate_idx = rsel.rate_idx; | 1936 | info->tx_rate_idx = rsel.rate_idx; |
1941 | 1937 | ||
1942 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | 1938 | info->flags |= IEEE80211_TX_CTL_NO_ACK; |
1943 | info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; | ||
1944 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; | 1939 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; |
1945 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; | 1940 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; |
1946 | if (sdata->bss_conf.use_short_preamble && | 1941 | if (sdata->bss_conf.use_short_preamble && |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 872d2fcd1a5b..5c2bf0a3d4db 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -31,13 +31,13 @@ int ieee80211_wep_init(struct ieee80211_local *local) | |||
31 | local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, | 31 | local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, |
32 | CRYPTO_ALG_ASYNC); | 32 | CRYPTO_ALG_ASYNC); |
33 | if (IS_ERR(local->wep_tx_tfm)) | 33 | if (IS_ERR(local->wep_tx_tfm)) |
34 | return -ENOMEM; | 34 | return PTR_ERR(local->wep_tx_tfm); |
35 | 35 | ||
36 | local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, | 36 | local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, |
37 | CRYPTO_ALG_ASYNC); | 37 | CRYPTO_ALG_ASYNC); |
38 | if (IS_ERR(local->wep_rx_tfm)) { | 38 | if (IS_ERR(local->wep_rx_tfm)) { |
39 | crypto_free_blkcipher(local->wep_tx_tfm); | 39 | crypto_free_blkcipher(local->wep_tx_tfm); |
40 | return -ENOMEM; | 40 | return PTR_ERR(local->wep_rx_tfm); |
41 | } | 41 | } |
42 | 42 | ||
43 | return 0; | 43 | return 0; |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 07edda0b8a5c..28437f0001db 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -188,6 +188,9 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, | |||
188 | { | 188 | { |
189 | int i; | 189 | int i; |
190 | 190 | ||
191 | /* XXX: currently broken due to cb/requeue use */ | ||
192 | return -EPERM; | ||
193 | |||
191 | /* prepare the filter and save it for the SW queue | 194 | /* prepare the filter and save it for the SW queue |
192 | * matching the received HW queue */ | 195 | * matching the received HW queue */ |
193 | 196 | ||
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 7a560b785097..c6f2f388cb72 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c | |||
@@ -130,7 +130,6 @@ static void update_rfkill_state(struct rfkill *rfkill) | |||
130 | 130 | ||
131 | /** | 131 | /** |
132 | * rfkill_toggle_radio - wrapper for toggle_radio hook | 132 | * rfkill_toggle_radio - wrapper for toggle_radio hook |
133 | * | ||
134 | * @rfkill: the rfkill struct to use | 133 | * @rfkill: the rfkill struct to use |
135 | * @force: calls toggle_radio even if cache says it is not needed, | 134 | * @force: calls toggle_radio even if cache says it is not needed, |
136 | * and also makes sure notifications of the state will be | 135 | * and also makes sure notifications of the state will be |
@@ -141,8 +140,8 @@ static void update_rfkill_state(struct rfkill *rfkill) | |||
141 | * calls and handling all the red tape such as issuing notifications | 140 | * calls and handling all the red tape such as issuing notifications |
142 | * if the call is successful. | 141 | * if the call is successful. |
143 | * | 142 | * |
144 | * Note that @force cannot override a (possibly cached) state of | 143 | * Note that the @force parameter cannot override a (possibly cached) |
145 | * RFKILL_STATE_HARD_BLOCKED. Any device making use of | 144 | * state of RFKILL_STATE_HARD_BLOCKED. Any device making use of |
146 | * RFKILL_STATE_HARD_BLOCKED implements either get_state() or | 145 | * RFKILL_STATE_HARD_BLOCKED implements either get_state() or |
147 | * rfkill_force_state(), so the cache either is bypassed or valid. | 146 | * rfkill_force_state(), so the cache either is bypassed or valid. |
148 | * | 147 | * |
@@ -150,7 +149,7 @@ static void update_rfkill_state(struct rfkill *rfkill) | |||
150 | * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to | 149 | * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to |
151 | * give the driver a hint that it should double-BLOCK the transmitter. | 150 | * give the driver a hint that it should double-BLOCK the transmitter. |
152 | * | 151 | * |
153 | * Caller must have aquired rfkill_mutex. | 152 | * Caller must have acquired rfkill->mutex. |
154 | */ | 153 | */ |
155 | static int rfkill_toggle_radio(struct rfkill *rfkill, | 154 | static int rfkill_toggle_radio(struct rfkill *rfkill, |
156 | enum rfkill_state state, | 155 | enum rfkill_state state, |
@@ -200,12 +199,12 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, | |||
200 | 199 | ||
201 | /** | 200 | /** |
202 | * rfkill_switch_all - Toggle state of all switches of given type | 201 | * rfkill_switch_all - Toggle state of all switches of given type |
203 | * @type: type of interfaces to be affeceted | 202 | * @type: type of interfaces to be affected |
204 | * @state: the new state | 203 | * @state: the new state |
205 | * | 204 | * |
206 | * This function toggles state of all switches of given type unless | 205 | * This function toggles the state of all switches of given type, |
207 | * a specific switch is claimed by userspace in which case it is | 206 | * unless a specific switch is claimed by userspace (in which case, |
208 | * left alone. | 207 | * that switch is left alone). |
209 | */ | 208 | */ |
210 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | 209 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) |
211 | { | 210 | { |
@@ -216,8 +215,11 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | |||
216 | rfkill_states[type] = state; | 215 | rfkill_states[type] = state; |
217 | 216 | ||
218 | list_for_each_entry(rfkill, &rfkill_list, node) { | 217 | list_for_each_entry(rfkill, &rfkill_list, node) { |
219 | if ((!rfkill->user_claim) && (rfkill->type == type)) | 218 | if ((!rfkill->user_claim) && (rfkill->type == type)) { |
219 | mutex_lock(&rfkill->mutex); | ||
220 | rfkill_toggle_radio(rfkill, state, 0); | 220 | rfkill_toggle_radio(rfkill, state, 0); |
221 | mutex_unlock(&rfkill->mutex); | ||
222 | } | ||
221 | } | 223 | } |
222 | 224 | ||
223 | mutex_unlock(&rfkill_mutex); | 225 | mutex_unlock(&rfkill_mutex); |
@@ -228,7 +230,7 @@ EXPORT_SYMBOL(rfkill_switch_all); | |||
228 | * rfkill_epo - emergency power off all transmitters | 230 | * rfkill_epo - emergency power off all transmitters |
229 | * | 231 | * |
230 | * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring | 232 | * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring |
231 | * everything in its path but rfkill_mutex. | 233 | * everything in its path but rfkill_mutex and rfkill->mutex. |
232 | */ | 234 | */ |
233 | void rfkill_epo(void) | 235 | void rfkill_epo(void) |
234 | { | 236 | { |
@@ -236,7 +238,9 @@ void rfkill_epo(void) | |||
236 | 238 | ||
237 | mutex_lock(&rfkill_mutex); | 239 | mutex_lock(&rfkill_mutex); |
238 | list_for_each_entry(rfkill, &rfkill_list, node) { | 240 | list_for_each_entry(rfkill, &rfkill_list, node) { |
241 | mutex_lock(&rfkill->mutex); | ||
239 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | 242 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); |
243 | mutex_unlock(&rfkill->mutex); | ||
240 | } | 244 | } |
241 | mutex_unlock(&rfkill_mutex); | 245 | mutex_unlock(&rfkill_mutex); |
242 | } | 246 | } |
@@ -252,7 +256,12 @@ EXPORT_SYMBOL_GPL(rfkill_epo); | |||
252 | * a notification by the firmware/hardware of the current *real* | 256 | * a notification by the firmware/hardware of the current *real* |
253 | * state of the radio rfkill switch. | 257 | * state of the radio rfkill switch. |
254 | * | 258 | * |
255 | * It may not be called from an atomic context. | 259 | * Devices which are subject to external changes on their rfkill |
260 | * state (such as those caused by a hardware rfkill line) MUST | ||
261 | * have their driver arrange to call rfkill_force_state() as soon | ||
262 | * as possible after such a change. | ||
263 | * | ||
264 | * This function may not be called from an atomic context. | ||
256 | */ | 265 | */ |
257 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) | 266 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) |
258 | { | 267 | { |
@@ -367,6 +376,9 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
367 | if (!capable(CAP_NET_ADMIN)) | 376 | if (!capable(CAP_NET_ADMIN)) |
368 | return -EPERM; | 377 | return -EPERM; |
369 | 378 | ||
379 | if (rfkill->user_claim_unsupported) | ||
380 | return -EOPNOTSUPP; | ||
381 | |||
370 | /* | 382 | /* |
371 | * Take the global lock to make sure the kernel is not in | 383 | * Take the global lock to make sure the kernel is not in |
372 | * the middle of rfkill_switch_all | 384 | * the middle of rfkill_switch_all |
@@ -375,19 +387,17 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
375 | if (error) | 387 | if (error) |
376 | return error; | 388 | return error; |
377 | 389 | ||
378 | if (rfkill->user_claim_unsupported) { | ||
379 | error = -EOPNOTSUPP; | ||
380 | goto out_unlock; | ||
381 | } | ||
382 | if (rfkill->user_claim != claim) { | 390 | if (rfkill->user_claim != claim) { |
383 | if (!claim) | 391 | if (!claim) { |
392 | mutex_lock(&rfkill->mutex); | ||
384 | rfkill_toggle_radio(rfkill, | 393 | rfkill_toggle_radio(rfkill, |
385 | rfkill_states[rfkill->type], | 394 | rfkill_states[rfkill->type], |
386 | 0); | 395 | 0); |
396 | mutex_unlock(&rfkill->mutex); | ||
397 | } | ||
387 | rfkill->user_claim = claim; | 398 | rfkill->user_claim = claim; |
388 | } | 399 | } |
389 | 400 | ||
390 | out_unlock: | ||
391 | mutex_unlock(&rfkill_mutex); | 401 | mutex_unlock(&rfkill_mutex); |
392 | 402 | ||
393 | return error ? error : count; | 403 | return error ? error : count; |
@@ -516,8 +526,11 @@ static void rfkill_remove_switch(struct rfkill *rfkill) | |||
516 | { | 526 | { |
517 | mutex_lock(&rfkill_mutex); | 527 | mutex_lock(&rfkill_mutex); |
518 | list_del_init(&rfkill->node); | 528 | list_del_init(&rfkill->node); |
519 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | ||
520 | mutex_unlock(&rfkill_mutex); | 529 | mutex_unlock(&rfkill_mutex); |
530 | |||
531 | mutex_lock(&rfkill->mutex); | ||
532 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | ||
533 | mutex_unlock(&rfkill->mutex); | ||
521 | } | 534 | } |
522 | 535 | ||
523 | /** | 536 | /** |
@@ -526,9 +539,10 @@ static void rfkill_remove_switch(struct rfkill *rfkill) | |||
526 | * @type: type of the switch (RFKILL_TYPE_*) | 539 | * @type: type of the switch (RFKILL_TYPE_*) |
527 | * | 540 | * |
528 | * This function should be called by the network driver when it needs | 541 | * This function should be called by the network driver when it needs |
529 | * rfkill structure. Once the structure is allocated the driver shoud | 542 | * rfkill structure. Once the structure is allocated the driver should |
530 | * finish its initialization by setting name, private data, enable_radio | 543 | * finish its initialization by setting the name, private data, enable_radio |
531 | * and disable_radio methods and then register it with rfkill_register(). | 544 | * and disable_radio methods and then register it with rfkill_register(). |
545 | * | ||
532 | * NOTE: If registration fails the structure shoudl be freed by calling | 546 | * NOTE: If registration fails the structure shoudl be freed by calling |
533 | * rfkill_free() otherwise rfkill_unregister() should be used. | 547 | * rfkill_free() otherwise rfkill_unregister() should be used. |
534 | */ | 548 | */ |
@@ -560,7 +574,7 @@ EXPORT_SYMBOL(rfkill_allocate); | |||
560 | * rfkill_free - Mark rfkill structure for deletion | 574 | * rfkill_free - Mark rfkill structure for deletion |
561 | * @rfkill: rfkill structure to be destroyed | 575 | * @rfkill: rfkill structure to be destroyed |
562 | * | 576 | * |
563 | * Decrements reference count of rfkill structure so it is destroyed. | 577 | * Decrements reference count of the rfkill structure so it is destroyed. |
564 | * Note that rfkill_free() should _not_ be called after rfkill_unregister(). | 578 | * Note that rfkill_free() should _not_ be called after rfkill_unregister(). |
565 | */ | 579 | */ |
566 | void rfkill_free(struct rfkill *rfkill) | 580 | void rfkill_free(struct rfkill *rfkill) |
@@ -585,8 +599,10 @@ static void rfkill_led_trigger_register(struct rfkill *rfkill) | |||
585 | static void rfkill_led_trigger_unregister(struct rfkill *rfkill) | 599 | static void rfkill_led_trigger_unregister(struct rfkill *rfkill) |
586 | { | 600 | { |
587 | #ifdef CONFIG_RFKILL_LEDS | 601 | #ifdef CONFIG_RFKILL_LEDS |
588 | if (rfkill->led_trigger.name) | 602 | if (rfkill->led_trigger.name) { |
589 | led_trigger_unregister(&rfkill->led_trigger); | 603 | led_trigger_unregister(&rfkill->led_trigger); |
604 | rfkill->led_trigger.name = NULL; | ||
605 | } | ||
590 | #endif | 606 | #endif |
591 | } | 607 | } |
592 | 608 | ||
@@ -622,8 +638,8 @@ int rfkill_register(struct rfkill *rfkill) | |||
622 | 638 | ||
623 | error = device_add(dev); | 639 | error = device_add(dev); |
624 | if (error) { | 640 | if (error) { |
625 | rfkill_led_trigger_unregister(rfkill); | ||
626 | rfkill_remove_switch(rfkill); | 641 | rfkill_remove_switch(rfkill); |
642 | rfkill_led_trigger_unregister(rfkill); | ||
627 | return error; | 643 | return error; |
628 | } | 644 | } |
629 | 645 | ||
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index b0601642e227..4840aff47256 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -572,44 +572,21 @@ static u32 qdisc_alloc_handle(struct net_device *dev) | |||
572 | static struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, | 572 | static struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, |
573 | struct Qdisc *qdisc) | 573 | struct Qdisc *qdisc) |
574 | { | 574 | { |
575 | struct Qdisc *oqdisc = dev_queue->qdisc_sleeping; | ||
575 | spinlock_t *root_lock; | 576 | spinlock_t *root_lock; |
576 | struct Qdisc *oqdisc; | ||
577 | int ingress; | ||
578 | |||
579 | ingress = 0; | ||
580 | if (qdisc && qdisc->flags&TCQ_F_INGRESS) | ||
581 | ingress = 1; | ||
582 | |||
583 | if (ingress) { | ||
584 | oqdisc = dev_queue->qdisc; | ||
585 | } else { | ||
586 | oqdisc = dev_queue->qdisc_sleeping; | ||
587 | } | ||
588 | 577 | ||
589 | root_lock = qdisc_root_lock(oqdisc); | 578 | root_lock = qdisc_root_lock(oqdisc); |
590 | spin_lock_bh(root_lock); | 579 | spin_lock_bh(root_lock); |
591 | 580 | ||
592 | if (ingress) { | 581 | /* Prune old scheduler */ |
593 | /* Prune old scheduler */ | 582 | if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) |
594 | if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) { | 583 | qdisc_reset(oqdisc); |
595 | /* delete */ | ||
596 | qdisc_reset(oqdisc); | ||
597 | dev_queue->qdisc = NULL; | ||
598 | } else { /* new */ | ||
599 | dev_queue->qdisc = qdisc; | ||
600 | } | ||
601 | 584 | ||
602 | } else { | 585 | /* ... and graft new one */ |
603 | /* Prune old scheduler */ | 586 | if (qdisc == NULL) |
604 | if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) | 587 | qdisc = &noop_qdisc; |
605 | qdisc_reset(oqdisc); | 588 | dev_queue->qdisc_sleeping = qdisc; |
606 | 589 | dev_queue->qdisc = &noop_qdisc; | |
607 | /* ... and graft new one */ | ||
608 | if (qdisc == NULL) | ||
609 | qdisc = &noop_qdisc; | ||
610 | dev_queue->qdisc_sleeping = qdisc; | ||
611 | dev_queue->qdisc = &noop_qdisc; | ||
612 | } | ||
613 | 590 | ||
614 | spin_unlock_bh(root_lock); | 591 | spin_unlock_bh(root_lock); |
615 | 592 | ||
@@ -678,7 +655,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, | |||
678 | 655 | ||
679 | ingress = 0; | 656 | ingress = 0; |
680 | num_q = dev->num_tx_queues; | 657 | num_q = dev->num_tx_queues; |
681 | if (q && q->flags & TCQ_F_INGRESS) { | 658 | if ((q && q->flags & TCQ_F_INGRESS) || |
659 | (new && new->flags & TCQ_F_INGRESS)) { | ||
682 | num_q = 1; | 660 | num_q = 1; |
683 | ingress = 1; | 661 | ingress = 1; |
684 | } | 662 | } |
@@ -692,13 +670,10 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, | |||
692 | if (!ingress) | 670 | if (!ingress) |
693 | dev_queue = netdev_get_tx_queue(dev, i); | 671 | dev_queue = netdev_get_tx_queue(dev, i); |
694 | 672 | ||
695 | if (ingress) { | 673 | old = dev_graft_qdisc(dev_queue, new); |
696 | old = dev_graft_qdisc(dev_queue, q); | 674 | if (new && i > 0) |
697 | } else { | 675 | atomic_inc(&new->refcnt); |
698 | old = dev_graft_qdisc(dev_queue, new); | 676 | |
699 | if (new && i > 0) | ||
700 | atomic_inc(&new->refcnt); | ||
701 | } | ||
702 | notify_and_destroy(skb, n, classid, old, new); | 677 | notify_and_destroy(skb, n, classid, old, new); |
703 | } | 678 | } |
704 | 679 | ||
@@ -817,7 +792,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, | |||
817 | goto err_out3; | 792 | goto err_out3; |
818 | } | 793 | } |
819 | } | 794 | } |
820 | if (parent) | 795 | if (parent && !(sch->flags & TCQ_F_INGRESS)) |
821 | list_add_tail(&sch->list, &dev_queue->qdisc->list); | 796 | list_add_tail(&sch->list, &dev_queue->qdisc->list); |
822 | 797 | ||
823 | return sch; | 798 | return sch; |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index fd2a6cadb115..345838a2e369 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -596,7 +596,7 @@ static void transition_one_qdisc(struct net_device *dev, | |||
596 | int *need_watchdog_p = _need_watchdog; | 596 | int *need_watchdog_p = _need_watchdog; |
597 | 597 | ||
598 | rcu_assign_pointer(dev_queue->qdisc, new_qdisc); | 598 | rcu_assign_pointer(dev_queue->qdisc, new_qdisc); |
599 | if (new_qdisc != &noqueue_qdisc) | 599 | if (need_watchdog_p && new_qdisc != &noqueue_qdisc) |
600 | *need_watchdog_p = 1; | 600 | *need_watchdog_p = 1; |
601 | } | 601 | } |
602 | 602 | ||
@@ -619,6 +619,7 @@ void dev_activate(struct net_device *dev) | |||
619 | 619 | ||
620 | need_watchdog = 0; | 620 | need_watchdog = 0; |
621 | netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog); | 621 | netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog); |
622 | transition_one_qdisc(dev, &dev->rx_queue, NULL); | ||
622 | 623 | ||
623 | if (need_watchdog) { | 624 | if (need_watchdog) { |
624 | dev->trans_start = jiffies; | 625 | dev->trans_start = jiffies; |
@@ -677,6 +678,7 @@ void dev_deactivate(struct net_device *dev) | |||
677 | bool running; | 678 | bool running; |
678 | 679 | ||
679 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc); | 680 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc); |
681 | dev_deactivate_queue(dev, &dev->rx_queue, &noop_qdisc); | ||
680 | 682 | ||
681 | dev_watchdog_down(dev); | 683 | dev_watchdog_down(dev); |
682 | 684 | ||
@@ -718,7 +720,7 @@ static void dev_init_scheduler_queue(struct net_device *dev, | |||
718 | void dev_init_scheduler(struct net_device *dev) | 720 | void dev_init_scheduler(struct net_device *dev) |
719 | { | 721 | { |
720 | netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); | 722 | netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); |
721 | dev_init_scheduler_queue(dev, &dev->rx_queue, NULL); | 723 | dev_init_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); |
722 | 724 | ||
723 | setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev); | 725 | setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev); |
724 | } | 726 | } |
@@ -745,6 +747,6 @@ static void shutdown_scheduler_queue(struct net_device *dev, | |||
745 | void dev_shutdown(struct net_device *dev) | 747 | void dev_shutdown(struct net_device *dev) |
746 | { | 748 | { |
747 | netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); | 749 | netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); |
748 | shutdown_scheduler_queue(dev, &dev->rx_queue, NULL); | 750 | shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); |
749 | WARN_ON(timer_pending(&dev->watchdog_timer)); | 751 | WARN_ON(timer_pending(&dev->watchdog_timer)); |
750 | } | 752 | } |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 835d27413083..5a32cb7c4bb4 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -310,8 +310,7 @@ svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx) | |||
310 | switch (m->mode) { | 310 | switch (m->mode) { |
311 | case SVC_POOL_PERCPU: | 311 | case SVC_POOL_PERCPU: |
312 | { | 312 | { |
313 | cpumask_of_cpu_ptr(cpumask, node); | 313 | set_cpus_allowed_ptr(task, &cpumask_of_cpu(node)); |
314 | set_cpus_allowed_ptr(task, cpumask); | ||
315 | break; | 314 | break; |
316 | } | 315 | } |
317 | case SVC_POOL_PERNODE: | 316 | case SVC_POOL_PERNODE: |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b7fefffd2d0d..59eb2cf42e5f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -29,16 +29,16 @@ static struct genl_family nl80211_fam = { | |||
29 | }; | 29 | }; |
30 | 30 | ||
31 | /* internal helper: get drv and dev */ | 31 | /* internal helper: get drv and dev */ |
32 | static int get_drv_dev_by_info_ifindex(struct genl_info *info, | 32 | static int get_drv_dev_by_info_ifindex(struct nlattr **attrs, |
33 | struct cfg80211_registered_device **drv, | 33 | struct cfg80211_registered_device **drv, |
34 | struct net_device **dev) | 34 | struct net_device **dev) |
35 | { | 35 | { |
36 | int ifindex; | 36 | int ifindex; |
37 | 37 | ||
38 | if (!info->attrs[NL80211_ATTR_IFINDEX]) | 38 | if (!attrs[NL80211_ATTR_IFINDEX]) |
39 | return -EINVAL; | 39 | return -EINVAL; |
40 | 40 | ||
41 | ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); | 41 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
42 | *dev = dev_get_by_index(&init_net, ifindex); | 42 | *dev = dev_get_by_index(&init_net, ifindex); |
43 | if (!*dev) | 43 | if (!*dev) |
44 | return -ENODEV; | 44 | return -ENODEV; |
@@ -291,21 +291,31 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
291 | 291 | ||
292 | mutex_lock(&cfg80211_drv_mutex); | 292 | mutex_lock(&cfg80211_drv_mutex); |
293 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | 293 | list_for_each_entry(dev, &cfg80211_drv_list, list) { |
294 | if (++wp_idx < wp_start) | 294 | if (wp_idx < wp_start) { |
295 | wp_idx++; | ||
295 | continue; | 296 | continue; |
297 | } | ||
296 | if_idx = 0; | 298 | if_idx = 0; |
297 | 299 | ||
298 | mutex_lock(&dev->devlist_mtx); | 300 | mutex_lock(&dev->devlist_mtx); |
299 | list_for_each_entry(wdev, &dev->netdev_list, list) { | 301 | list_for_each_entry(wdev, &dev->netdev_list, list) { |
300 | if (++if_idx < if_start) | 302 | if (if_idx < if_start) { |
303 | if_idx++; | ||
301 | continue; | 304 | continue; |
305 | } | ||
302 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 306 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
303 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 307 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
304 | wdev->netdev) < 0) | 308 | wdev->netdev) < 0) { |
305 | break; | 309 | mutex_unlock(&dev->devlist_mtx); |
310 | goto out; | ||
311 | } | ||
312 | if_idx++; | ||
306 | } | 313 | } |
307 | mutex_unlock(&dev->devlist_mtx); | 314 | mutex_unlock(&dev->devlist_mtx); |
315 | |||
316 | wp_idx++; | ||
308 | } | 317 | } |
318 | out: | ||
309 | mutex_unlock(&cfg80211_drv_mutex); | 319 | mutex_unlock(&cfg80211_drv_mutex); |
310 | 320 | ||
311 | cb->args[0] = wp_idx; | 321 | cb->args[0] = wp_idx; |
@@ -321,7 +331,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
321 | struct net_device *netdev; | 331 | struct net_device *netdev; |
322 | int err; | 332 | int err; |
323 | 333 | ||
324 | err = get_drv_dev_by_info_ifindex(info, &dev, &netdev); | 334 | err = get_drv_dev_by_info_ifindex(info->attrs, &dev, &netdev); |
325 | if (err) | 335 | if (err) |
326 | return err; | 336 | return err; |
327 | 337 | ||
@@ -392,7 +402,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
392 | } else | 402 | } else |
393 | return -EINVAL; | 403 | return -EINVAL; |
394 | 404 | ||
395 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 405 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
396 | if (err) | 406 | if (err) |
397 | return err; | 407 | return err; |
398 | ifindex = dev->ifindex; | 408 | ifindex = dev->ifindex; |
@@ -477,7 +487,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
477 | int ifindex, err; | 487 | int ifindex, err; |
478 | struct net_device *dev; | 488 | struct net_device *dev; |
479 | 489 | ||
480 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 490 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
481 | if (err) | 491 | if (err) |
482 | return err; | 492 | return err; |
483 | ifindex = dev->ifindex; | 493 | ifindex = dev->ifindex; |
@@ -545,7 +555,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
545 | if (info->attrs[NL80211_ATTR_MAC]) | 555 | if (info->attrs[NL80211_ATTR_MAC]) |
546 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 556 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
547 | 557 | ||
548 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 558 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
549 | if (err) | 559 | if (err) |
550 | return err; | 560 | return err; |
551 | 561 | ||
@@ -618,7 +628,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
618 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) | 628 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) |
619 | return -EINVAL; | 629 | return -EINVAL; |
620 | 630 | ||
621 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 631 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
622 | if (err) | 632 | if (err) |
623 | return err; | 633 | return err; |
624 | 634 | ||
@@ -699,7 +709,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
699 | return -EINVAL; | 709 | return -EINVAL; |
700 | } | 710 | } |
701 | 711 | ||
702 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 712 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
703 | if (err) | 713 | if (err) |
704 | return err; | 714 | return err; |
705 | 715 | ||
@@ -735,7 +745,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
735 | if (info->attrs[NL80211_ATTR_MAC]) | 745 | if (info->attrs[NL80211_ATTR_MAC]) |
736 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 746 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
737 | 747 | ||
738 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 748 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
739 | if (err) | 749 | if (err) |
740 | return err; | 750 | return err; |
741 | 751 | ||
@@ -764,7 +774,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
764 | struct beacon_parameters params; | 774 | struct beacon_parameters params; |
765 | int haveinfo = 0; | 775 | int haveinfo = 0; |
766 | 776 | ||
767 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 777 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
768 | if (err) | 778 | if (err) |
769 | return err; | 779 | return err; |
770 | 780 | ||
@@ -843,7 +853,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | |||
843 | int err; | 853 | int err; |
844 | struct net_device *dev; | 854 | struct net_device *dev; |
845 | 855 | ||
846 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 856 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
847 | if (err) | 857 | if (err) |
848 | return err; | 858 | return err; |
849 | 859 | ||
@@ -937,67 +947,78 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
937 | } | 947 | } |
938 | 948 | ||
939 | static int nl80211_dump_station(struct sk_buff *skb, | 949 | static int nl80211_dump_station(struct sk_buff *skb, |
940 | struct netlink_callback *cb) | 950 | struct netlink_callback *cb) |
941 | { | 951 | { |
942 | int wp_idx = 0; | ||
943 | int if_idx = 0; | ||
944 | int sta_idx = cb->args[2]; | ||
945 | int wp_start = cb->args[0]; | ||
946 | int if_start = cb->args[1]; | ||
947 | struct station_info sinfo; | 952 | struct station_info sinfo; |
948 | struct cfg80211_registered_device *dev; | 953 | struct cfg80211_registered_device *dev; |
949 | struct wireless_dev *wdev; | 954 | struct net_device *netdev; |
950 | u8 mac_addr[ETH_ALEN]; | 955 | u8 mac_addr[ETH_ALEN]; |
956 | int ifidx = cb->args[0]; | ||
957 | int sta_idx = cb->args[1]; | ||
951 | int err; | 958 | int err; |
952 | int exit = 0; | ||
953 | 959 | ||
954 | /* TODO: filter by device */ | 960 | if (!ifidx) { |
955 | mutex_lock(&cfg80211_drv_mutex); | 961 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
956 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | 962 | nl80211_fam.attrbuf, nl80211_fam.maxattr, |
957 | if (exit) | 963 | nl80211_policy); |
964 | if (err) | ||
965 | return err; | ||
966 | |||
967 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
968 | return -EINVAL; | ||
969 | |||
970 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
971 | if (!ifidx) | ||
972 | return -EINVAL; | ||
973 | } | ||
974 | |||
975 | netdev = dev_get_by_index(&init_net, ifidx); | ||
976 | if (!netdev) | ||
977 | return -ENODEV; | ||
978 | |||
979 | dev = cfg80211_get_dev_from_ifindex(ifidx); | ||
980 | if (IS_ERR(dev)) { | ||
981 | err = PTR_ERR(dev); | ||
982 | goto out_put_netdev; | ||
983 | } | ||
984 | |||
985 | if (!dev->ops->dump_station) { | ||
986 | err = -ENOSYS; | ||
987 | goto out_err; | ||
988 | } | ||
989 | |||
990 | rtnl_lock(); | ||
991 | |||
992 | while (1) { | ||
993 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, | ||
994 | mac_addr, &sinfo); | ||
995 | if (err == -ENOENT) | ||
958 | break; | 996 | break; |
959 | if (++wp_idx < wp_start) | 997 | if (err) |
960 | continue; | 998 | goto out_err_rtnl; |
961 | if_idx = 0; | ||
962 | 999 | ||
963 | mutex_lock(&dev->devlist_mtx); | 1000 | if (nl80211_send_station(skb, |
964 | list_for_each_entry(wdev, &dev->netdev_list, list) { | 1001 | NETLINK_CB(cb->skb).pid, |
965 | if (exit) | 1002 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
966 | break; | 1003 | netdev, mac_addr, |
967 | if (++if_idx < if_start) | 1004 | &sinfo) < 0) |
968 | continue; | 1005 | goto out; |
969 | if (!dev->ops->dump_station) | ||
970 | continue; | ||
971 | 1006 | ||
972 | for (;; ++sta_idx) { | 1007 | sta_idx++; |
973 | rtnl_lock(); | ||
974 | err = dev->ops->dump_station(&dev->wiphy, | ||
975 | wdev->netdev, sta_idx, mac_addr, | ||
976 | &sinfo); | ||
977 | rtnl_unlock(); | ||
978 | if (err) { | ||
979 | sta_idx = 0; | ||
980 | break; | ||
981 | } | ||
982 | if (nl80211_send_station(skb, | ||
983 | NETLINK_CB(cb->skb).pid, | ||
984 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
985 | wdev->netdev, mac_addr, | ||
986 | &sinfo) < 0) { | ||
987 | exit = 1; | ||
988 | break; | ||
989 | } | ||
990 | } | ||
991 | } | ||
992 | mutex_unlock(&dev->devlist_mtx); | ||
993 | } | 1008 | } |
994 | mutex_unlock(&cfg80211_drv_mutex); | ||
995 | 1009 | ||
996 | cb->args[0] = wp_idx; | ||
997 | cb->args[1] = if_idx; | ||
998 | cb->args[2] = sta_idx; | ||
999 | 1010 | ||
1000 | return skb->len; | 1011 | out: |
1012 | cb->args[1] = sta_idx; | ||
1013 | err = skb->len; | ||
1014 | out_err_rtnl: | ||
1015 | rtnl_unlock(); | ||
1016 | out_err: | ||
1017 | cfg80211_put_dev(dev); | ||
1018 | out_put_netdev: | ||
1019 | dev_put(netdev); | ||
1020 | |||
1021 | return err; | ||
1001 | } | 1022 | } |
1002 | 1023 | ||
1003 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 1024 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) |
@@ -1016,7 +1037,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1016 | 1037 | ||
1017 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1038 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1018 | 1039 | ||
1019 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1040 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1020 | if (err) | 1041 | if (err) |
1021 | return err; | 1042 | return err; |
1022 | 1043 | ||
@@ -1112,7 +1133,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1112 | params.plink_action = | 1133 | params.plink_action = |
1113 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 1134 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
1114 | 1135 | ||
1115 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1136 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1116 | if (err) | 1137 | if (err) |
1117 | return err; | 1138 | return err; |
1118 | 1139 | ||
@@ -1172,7 +1193,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1172 | ¶ms.station_flags)) | 1193 | ¶ms.station_flags)) |
1173 | return -EINVAL; | 1194 | return -EINVAL; |
1174 | 1195 | ||
1175 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1196 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1176 | if (err) | 1197 | if (err) |
1177 | return err; | 1198 | return err; |
1178 | 1199 | ||
@@ -1207,7 +1228,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
1207 | if (info->attrs[NL80211_ATTR_MAC]) | 1228 | if (info->attrs[NL80211_ATTR_MAC]) |
1208 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1229 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1209 | 1230 | ||
1210 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1231 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1211 | if (err) | 1232 | if (err) |
1212 | return err; | 1233 | return err; |
1213 | 1234 | ||
@@ -1277,68 +1298,78 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | |||
1277 | } | 1298 | } |
1278 | 1299 | ||
1279 | static int nl80211_dump_mpath(struct sk_buff *skb, | 1300 | static int nl80211_dump_mpath(struct sk_buff *skb, |
1280 | struct netlink_callback *cb) | 1301 | struct netlink_callback *cb) |
1281 | { | 1302 | { |
1282 | int wp_idx = 0; | ||
1283 | int if_idx = 0; | ||
1284 | int sta_idx = cb->args[2]; | ||
1285 | int wp_start = cb->args[0]; | ||
1286 | int if_start = cb->args[1]; | ||
1287 | struct mpath_info pinfo; | 1303 | struct mpath_info pinfo; |
1288 | struct cfg80211_registered_device *dev; | 1304 | struct cfg80211_registered_device *dev; |
1289 | struct wireless_dev *wdev; | 1305 | struct net_device *netdev; |
1290 | u8 dst[ETH_ALEN]; | 1306 | u8 dst[ETH_ALEN]; |
1291 | u8 next_hop[ETH_ALEN]; | 1307 | u8 next_hop[ETH_ALEN]; |
1308 | int ifidx = cb->args[0]; | ||
1309 | int path_idx = cb->args[1]; | ||
1292 | int err; | 1310 | int err; |
1293 | int exit = 0; | ||
1294 | 1311 | ||
1295 | /* TODO: filter by device */ | 1312 | if (!ifidx) { |
1296 | mutex_lock(&cfg80211_drv_mutex); | 1313 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
1297 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | 1314 | nl80211_fam.attrbuf, nl80211_fam.maxattr, |
1298 | if (exit) | 1315 | nl80211_policy); |
1316 | if (err) | ||
1317 | return err; | ||
1318 | |||
1319 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
1320 | return -EINVAL; | ||
1321 | |||
1322 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
1323 | if (!ifidx) | ||
1324 | return -EINVAL; | ||
1325 | } | ||
1326 | |||
1327 | netdev = dev_get_by_index(&init_net, ifidx); | ||
1328 | if (!netdev) | ||
1329 | return -ENODEV; | ||
1330 | |||
1331 | dev = cfg80211_get_dev_from_ifindex(ifidx); | ||
1332 | if (IS_ERR(dev)) { | ||
1333 | err = PTR_ERR(dev); | ||
1334 | goto out_put_netdev; | ||
1335 | } | ||
1336 | |||
1337 | if (!dev->ops->dump_mpath) { | ||
1338 | err = -ENOSYS; | ||
1339 | goto out_err; | ||
1340 | } | ||
1341 | |||
1342 | rtnl_lock(); | ||
1343 | |||
1344 | while (1) { | ||
1345 | err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, | ||
1346 | dst, next_hop, &pinfo); | ||
1347 | if (err == -ENOENT) | ||
1299 | break; | 1348 | break; |
1300 | if (++wp_idx < wp_start) | 1349 | if (err) |
1301 | continue; | 1350 | goto out_err_rtnl; |
1302 | if_idx = 0; | ||
1303 | 1351 | ||
1304 | mutex_lock(&dev->devlist_mtx); | 1352 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, |
1305 | list_for_each_entry(wdev, &dev->netdev_list, list) { | 1353 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
1306 | if (exit) | 1354 | netdev, dst, next_hop, |
1307 | break; | 1355 | &pinfo) < 0) |
1308 | if (++if_idx < if_start) | 1356 | goto out; |
1309 | continue; | ||
1310 | if (!dev->ops->dump_mpath) | ||
1311 | continue; | ||
1312 | 1357 | ||
1313 | for (;; ++sta_idx) { | 1358 | path_idx++; |
1314 | rtnl_lock(); | ||
1315 | err = dev->ops->dump_mpath(&dev->wiphy, | ||
1316 | wdev->netdev, sta_idx, dst, | ||
1317 | next_hop, &pinfo); | ||
1318 | rtnl_unlock(); | ||
1319 | if (err) { | ||
1320 | sta_idx = 0; | ||
1321 | break; | ||
1322 | } | ||
1323 | if (nl80211_send_mpath(skb, | ||
1324 | NETLINK_CB(cb->skb).pid, | ||
1325 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
1326 | wdev->netdev, dst, next_hop, | ||
1327 | &pinfo) < 0) { | ||
1328 | exit = 1; | ||
1329 | break; | ||
1330 | } | ||
1331 | } | ||
1332 | } | ||
1333 | mutex_unlock(&dev->devlist_mtx); | ||
1334 | } | 1359 | } |
1335 | mutex_unlock(&cfg80211_drv_mutex); | ||
1336 | 1360 | ||
1337 | cb->args[0] = wp_idx; | ||
1338 | cb->args[1] = if_idx; | ||
1339 | cb->args[2] = sta_idx; | ||
1340 | 1361 | ||
1341 | return skb->len; | 1362 | out: |
1363 | cb->args[1] = path_idx; | ||
1364 | err = skb->len; | ||
1365 | out_err_rtnl: | ||
1366 | rtnl_unlock(); | ||
1367 | out_err: | ||
1368 | cfg80211_put_dev(dev); | ||
1369 | out_put_netdev: | ||
1370 | dev_put(netdev); | ||
1371 | |||
1372 | return err; | ||
1342 | } | 1373 | } |
1343 | 1374 | ||
1344 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | 1375 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) |
@@ -1358,7 +1389,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1358 | 1389 | ||
1359 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1390 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1360 | 1391 | ||
1361 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1392 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1362 | if (err) | 1393 | if (err) |
1363 | return err; | 1394 | return err; |
1364 | 1395 | ||
@@ -1411,7 +1442,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1411 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1442 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1412 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 1443 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
1413 | 1444 | ||
1414 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1445 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1415 | if (err) | 1446 | if (err) |
1416 | return err; | 1447 | return err; |
1417 | 1448 | ||
@@ -1446,7 +1477,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1446 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1477 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1447 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 1478 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
1448 | 1479 | ||
1449 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1480 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1450 | if (err) | 1481 | if (err) |
1451 | return err; | 1482 | return err; |
1452 | 1483 | ||
@@ -1475,7 +1506,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1475 | if (info->attrs[NL80211_ATTR_MAC]) | 1506 | if (info->attrs[NL80211_ATTR_MAC]) |
1476 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1507 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1477 | 1508 | ||
1478 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1509 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1479 | if (err) | 1510 | if (err) |
1480 | return err; | 1511 | return err; |
1481 | 1512 | ||
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 8f038e6d5f98..418cd7dbbc93 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -1468,7 +1468,7 @@ static void section_rel(const char *modname, struct elf_info *elf, | |||
1468 | * marked __initdata will be discarded when the module has been intialized. | 1468 | * marked __initdata will be discarded when the module has been intialized. |
1469 | * Likewise for modules used built-in the sections marked __exit | 1469 | * Likewise for modules used built-in the sections marked __exit |
1470 | * are discarded because __exit marked function are supposed to be called | 1470 | * are discarded because __exit marked function are supposed to be called |
1471 | * only when a moduel is unloaded which never happes for built-in modules. | 1471 | * only when a module is unloaded which never happens for built-in modules. |
1472 | * The check_sec_ref() function traverses all relocation records | 1472 | * The check_sec_ref() function traverses all relocation records |
1473 | * to find all references to a section that reference a section that will | 1473 | * to find all references to a section that reference a section that will |
1474 | * be discarded and warns about it. | 1474 | * be discarded and warns about it. |