Compare commits
280 Commits
Author | SHA1 | Date |
---|---|---|
Chuck Ebbert | 4f60038bf4 | |
Josh Boyer | cf59e182a8 | |
Josh Boyer | df53fa5f95 | |
Josh Boyer | 445b543dc9 | |
Josh Boyer | 4f79121e0c | |
Dave Jones | 6c4e09df79 | |
Josh Boyer | ff37d2b109 | |
Josh Boyer | 3ea9b96c57 | |
Josh Boyer | 29298df87d | |
Josh Boyer | 528c087e36 | |
Chuck Ebbert | 4d20e68f2c | |
Dave Jones | c8c0a79ec2 | |
Dave Jones | 87d5560157 | |
Josh Boyer | 379959bc82 | |
Dave Jones | 6f7506e776 | |
Josh Boyer | c6232b615c | |
Dave Jones | 80bd8b191d | |
Dave Jones | 6cf4af8ebf | |
Dave Jones | 712881a12e | |
Dave Jones | 7e156f0d65 | |
Josh Boyer | 646ec82800 | |
Josh Boyer | 18a614272e | |
Josh Boyer | b45a41b9eb | |
Josh Boyer | c0d43b7963 | |
Josh Boyer | 398017defd | |
Josh Boyer | b2fe2ed5a1 | |
Josh Boyer | 51ba367fb0 | |
Josh Boyer | bc96a9d65d | |
Josh Boyer | cf5a635e41 | |
Josh Boyer | d078fed40e | |
Josh Boyer | 3aec185937 | |
Josh Boyer | 2702d51eae | |
Josh Boyer | fad102a10b | |
Josh Boyer | 248cf7df49 | |
Josh Boyer | a62b54cb1c | |
Josh Boyer | 92fb0ab0ab | |
Chuck Ebbert | 29f392610c | |
Dave Jones | b5c25fa75f | |
Dave Jones | 83a9139012 | |
Chuck Ebbert | e7409b2d7e | |
Chuck Ebbert | c9e8c10a43 | |
Chuck Ebbert | 8ba25ec095 | |
Chuck Ebbert | f77745ccf7 | |
Chuck Ebbert | bdfca38df2 | |
Chuck Ebbert | fa21cb2d4c | |
Chuck Ebbert | 7760c97dcd | |
Kyle McMartin | 398aba2d45 | |
Chuck Ebbert | fcf9248627 | |
Chuck Ebbert | 7e51f2f324 | |
Chuck Ebbert | dd4a4083bb | |
Chuck Ebbert | 64c2b6747d | |
Chuck Ebbert | 6047d0e750 | |
Kyle McMartin | cc37b46764 | |
Chuck Ebbert | 3bf2bfa0d8 | |
Chuck Ebbert | ca79828415 | |
Chuck Ebbert | 2c4c81ad30 | |
Chuck Ebbert | b8c6e51855 | |
Chuck Ebbert | 9e4696b4a4 | |
Kyle McMartin | c6f2ed6008 | |
Chuck Ebbert | 1caa10e2d5 | |
Chuck Ebbert | d54c89365e | |
Kyle McMartin | 3472dfdd75 | |
Kyle McMartin | 21c6036496 | |
Ben Skeggs | e372080592 | |
Kyle McMartin | 20692ec6bc | |
Jarod Wilson | eb037c6bac | |
Chuck Ebbert | d564948d65 | |
Chuck Ebbert | 6143eb5b67 | |
Chuck Ebbert | fcca07d327 | |
Chuck Ebbert | d65a153150 | |
Chuck Ebbert | b4877f1260 | |
Dan Horák | d84ac0f64e | |
Chuck Ebbert | 6e3a83fee3 | |
Matthew Garrett | c7ff2c5553 | |
Chuck Ebbert | 841a0e2190 | |
Chuck Ebbert | f9c2b4dd6f | |
Chuck Ebbert | 57d9bc3966 | |
Chuck Ebbert | d85fb28313 | |
Jarod Wilson | e2f91db6ff | |
Jarod Wilson | 639fa258dc | |
Jarod Wilson | 1875248d2a | |
Jarod Wilson | ef402ae0aa | |
Jarod Wilson | c998b6666e | |
Jarod Wilson | dd3abe2b99 | |
Jarod Wilson | 893aff6339 | |
Kyle McMartin | 7aeac617c0 | |
Jarod Wilson | 0252aa3de3 | |
Jarod Wilson | 5423b80362 | |
Jarod Wilson | a49e3abdff | |
Chuck Ebbert | b11f51521b | |
Jarod Wilson | b97dc7392d | |
Jarod Wilson | 49ee500dd9 | |
Jarod Wilson | f0f13be684 | |
Jarod Wilson | 4b2adb7be5 | |
Chuck Ebbert | aee782a97f | |
Chuck Ebbert | 1f90e5b6f6 | |
Chuck Ebbert | b1f2f04a2b | |
Jarod Wilson | 3ebdcc0e61 | |
Jarod Wilson | d1877af9bb | |
Matthew Garrett | 70d2ada596 | |
Matthew Garrett | 73ab1e483b | |
Kyle McMartin | c60b83ee86 | |
Kyle McMartin | 0cb25895ed | |
Kyle McMartin | bd64b2b5de | |
Jarod Wilson | 1328b3a839 | |
Kyle McMartin | 249677902c | |
Kyle McMartin | 646207ff5c | |
Jarod Wilson | 1cd0593638 | |
Jarod Wilson | 42434a4dc9 | |
Jarod Wilson | d3e2823f71 | |
Kyle McMartin | 358f4a55c5 | |
Kyle McMartin | 825b8ce73a | |
Kyle McMartin | f8d75b80e6 | |
Kyle McMartin | 3dbb45b665 | |
Kyle McMartin | 68b623121d | |
Kyle McMartin | 558463d9fb | |
Jarod Wilson | 703515438b | |
Jarod Wilson | fbfed34fec | |
Jarod Wilson | 92d37ba1d3 | |
Chuck Ebbert | 8f007394cd | |
Kyle McMartin | f045c5648e | |
Kyle McMartin | f2ed8cf30b | |
Kyle McMartin | 5a95077aa5 | |
Kyle McMartin | 54f1e03004 | |
Kyle McMartin | 9d6e5dc425 | |
Kyle McMartin | 4bd3ae5daa | |
Kyle McMartin | bd61adb09d | |
Chuck Ebbert | 983a2bb5c5 | |
Kyle McMartin | bed92c4e50 | |
Kyle McMartin | 20b0493429 | |
Kyle McMartin | 65c06ec080 | |
Kyle McMartin | 76a7ebfb42 | |
Kyle McMartin | d40233bb75 | |
Kyle McMartin | 592f4fb443 | |
Kyle McMartin | 48eb5c319b | |
Kyle McMartin | 26ea0f2631 | |
Kyle McMartin | ca2a17f441 | |
Kyle McMartin | 6abfea1c89 | |
kyle | 7a80ec3e7d | |
kyle | e1c14200b1 | |
John W. Linville | dd99fe005c | |
Kyle McMartin | 003654d6ca | |
Kyle McMartin | c86d4707a6 | |
Kyle McMartin | de964e3639 | |
Kyle McMartin | 55415ebd4a | |
Kyle McMartin | cc7fb594a9 | |
Jarod Wilson | 51157289c8 | |
Chuck Ebbert | 0081a7139c | |
Ben Skeggs | 466450dbeb | |
Kyle McMartin | b2e700d12a | |
Kyle McMartin | 4c76cc7f94 | |
Dave Airlie | d5b83e3877 | |
Dave Airlie | 5f72d41789 | |
Dave Airlie | 171d7cfb89 | |
Justin M. Forbes | adfff05db3 | |
Jarod Wilson | 28683a07fb | |
Dave Airlie | 5ddd90a5d8 | |
Dave Airlie | a474625d92 | |
Dave Airlie | 05493c4e57 | |
Ben Skeggs | 383a70142a | |
Ben Skeggs | c7b0072805 | |
Ben Skeggs | df57a85a75 | |
Jarod Wilson | 030d3b3b4b | |
Chuck Ebbert | 643d353feb | |
Kyle McMartin | cbdb312a9e | |
Kyle McMartin | 8311d5168d | |
Jarod Wilson | 61d7a69fe6 | |
Jarod Wilson | 59a83bd584 | |
Kyle McMartin | c4e830cb35 | |
Kyle McMartin | e38a760c9a | |
Kyle McMartin | f1b58c7ca8 | |
Kyle McMartin | a1b8c4ed84 | |
Kyle McMartin | 6268215f01 | |
Kyle McMartin | 6aca938822 | |
kyle | c76455ec66 | |
kyle | 915df7f6de | |
Kyle McMartin | 7d350a94ee | |
Kyle McMartin | 9ee136bcf7 | |
Kyle McMartin | 97e19f7196 | |
Peter Jones | 7810142e6c | |
Dave Jones | c13cbf3b7d | |
Kyle McMartin | c19187e334 | |
Kyle McMartin | a2d889c53a | |
Kyle McMartin | 7140c9dd2d | |
Jarod Wilson | 167ee12e60 | |
Jarod Wilson | 870acad08e | |
Jarod Wilson | 866bf4f059 | |
Ben Skeggs | bd31d54eac | |
Kyle McMartin | f7f1f5ef4a | |
Dave Jones | a09b817bc1 | |
Kyle McMartin | 2fe1e8e397 | |
Kyle McMartin | eaab8be2d4 | |
Kyle McMartin | bc9e072d9b | |
Ben Skeggs | 2e4b75da82 | |
Dave Jones | db140fac23 | |
Ben Skeggs | 7043d42b5a | |
Dave Jones | 452369b936 | |
Dave Jones | 8f3d6a8c3f | |
Dave Jones | fbce23b0ff | |
Dave Jones | bbaea70ee5 | |
Dave Jones | 04093b926b | |
Chuck Ebbert | 4141bfc9b1 | |
Kyle McMartin | 05f615c82e | |
Chuck Ebbert | b999dfdb6a | |
Chuck Ebbert | b49b116bb0 | |
Chuck Ebbert | eda054e8bd | |
Kyle McMartin | c2aa9135d2 | |
Kyle McMartin | 2348a607b7 | |
Kyle McMartin | b13dd03f62 | |
Kyle McMartin | 6289a5fca9 | |
Ben Skeggs | 31ce2e5e16 | |
Chuck Ebbert | b2398b3ef3 | |
Chuck Ebbert | 69a476baa9 | |
Kyle McMartin | 027325ab53 | |
Chuck Ebbert | b218718b2b | |
Chuck Ebbert | 7a68cb0b55 | |
Dennis Gilmore | 42589b1be2 | |
Dennis Gilmore | 6daeb4142a | |
Dennis Gilmore | c549b813ae | |
Hans de Goede | 7193965656 | |
Dave Jones | 291833d307 | |
Hans de Goede | cb6f3ab735 | |
Chuck Ebbert | db056c27c3 | |
Chuck Ebbert | 14525abb6d | |
Kyle McMartin | a1b0ec05b6 | |
Chuck Ebbert | 9bd241a830 | |
Ben Skeggs | 4badda4370 | |
Jarod Wilson | 17a76a95c4 | |
Bastien Nocera | 9ea075ebba | |
Bastien Nocera | ea6d873cc2 | |
Kyle McMartin | 88a50a0b1d | |
Kyle McMartin | 102e2d6718 | |
Chuck Ebbert | 63fcde2459 | |
Ben Skeggs | fbc4283e12 | |
Kyle McMartin | 3ceeb77a79 | |
Kyle McMartin | 72b3bf972e | |
Ben Skeggs | 0fe99e9810 | |
Ben Skeggs | 215a71b03d | |
Dave Jones | 2eba9aa0ec | |
Jarod Wilson | f4da561c3d | |
Kyle McMartin | 8b695bdd15 | |
Kyle McMartin | 426c30b2f1 | |
Kyle McMartin | cfdae029cc | |
Jarod Wilson | 8ccfe4ce6a | |
Ben Skeggs | 1001ab34f7 | |
Kyle McMartin | d3a72eaedc | |
Chuck Ebbert | 44c4f071d9 | |
Dave Jones | 7def7eaed3 | |
Dave Jones | 35cc504508 | |
Dave Jones | 705539efb5 | |
Dave Jones | c348adbe39 | |
Chuck Ebbert | 0c8a5559c3 | |
Kyle McMartin | 3c5d4de07c | |
Dave Jones | 90303f9462 | |
Dave Jones | 10931f1112 | |
Chuck Ebbert | 27e8302707 | |
Chuck Ebbert | 8f132e348c | |
Chuck Ebbert | b30c150da1 | |
Chuck Ebbert | 3e8e94e0cd | |
Chuck Ebbert | 74e18cdf9e | |
Dave Jones | 4135368fb0 | |
Chuck Ebbert | 13dcde2426 | |
Chuck Ebbert | bfc8e84a86 | |
Kyle McMartin | e2302e0109 | |
Kyle McMartin | 4cfceabb6c | |
Jarod Wilson | b9878dcfec | |
Chuck Ebbert | e1151597d5 | |
Chuck Ebbert | d6d51a1a42 | |
Chuck Ebbert | 4ed348073c | |
Ben Skeggs | 71e9b6763f | |
Chuck Ebbert | 74b9092d38 | |
Chuck Ebbert | 9a98a7ebe3 | |
Chuck Ebbert | 6c58ce89ec | |
Chuck Ebbert | 85a693ce78 | |
Dave Jones | 4326aa56d8 | |
Chuck Ebbert | 4d5b945030 | |
Chuck Ebbert | b6805461ca | |
Chuck Ebbert | 557b0fb7c4 | |
Dave Jones | f8200febc9 | |
Dave Jones | 37cd8b7c4c |
|
@ -1,5 +1,6 @@
|
|||
linux-*.tar.bz2
|
||||
patch-*.bz2
|
||||
clog
|
||||
*.bz2
|
||||
*.rpm
|
||||
*.orig
|
||||
kernel-2.6.*/
|
||||
kernel-3.*/
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
From 1729d20333739e6cc23023e405fe8668f08117a2 Mon Sep 17 00:00:00 2001
|
||||
From: Alan Stern <stern@rowland.harvard.edu>
|
||||
Date: Tue, 17 May 2011 10:40:51 -0400
|
||||
Subject: [PATCH 1/2] EHCI: don't rescan interrupt QHs needlessly
|
||||
|
||||
This patch (as1466) speeds up processing of ehci-hcd's periodic list.
|
||||
The existing code will pointlessly rescan an interrupt endpoint queue
|
||||
each time it encounters the queue's QH in the periodic list, which can
|
||||
happen quite a few times if the endpoint's period is low. On some
|
||||
embedded systems, this useless overhead can waste so much time that
|
||||
the driver falls hopelessly behind and loses events.
|
||||
|
||||
The patch introduces a "periodic_stamp" variable, which gets
|
||||
incremented each time scan_periodic() runs and each time the scan
|
||||
advances to a new frame. If the corresponding stamp in an interrupt
|
||||
QH is equal to the current periodic_stamp, we assume the QH has
|
||||
already been scanned and skip over it. Otherwise we scan the QH as
|
||||
usual, and if none of its URBs have completed then we store the
|
||||
current periodic_stamp in the QH's stamp, preventing it from being
|
||||
scanned again.
|
||||
|
||||
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
---
|
||||
drivers/usb/host/ehci-q.c | 1 +
|
||||
drivers/usb/host/ehci-sched.c | 14 ++++++++++----
|
||||
drivers/usb/host/ehci.h | 1 +
|
||||
3 files changed, 12 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
|
||||
index ed8db6a..0079610 100644
|
||||
--- a/drivers/usb/host/ehci-q.c
|
||||
+++ b/drivers/usb/host/ehci-q.c
|
||||
@@ -826,6 +826,7 @@ qh_make (
|
||||
is_input, 0,
|
||||
hb_mult(maxp) * max_packet(maxp)));
|
||||
qh->start = NO_FRAME;
|
||||
+ qh->stamp = ehci->periodic_stamp;
|
||||
|
||||
if (urb->dev->speed == USB_SPEED_HIGH) {
|
||||
qh->c_usecs = 0;
|
||||
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
|
||||
index a530856..9e54e85 100644
|
||||
--- a/drivers/usb/host/ehci-sched.c
|
||||
+++ b/drivers/usb/host/ehci-sched.c
|
||||
@@ -2351,6 +2351,7 @@ scan_periodic (struct ehci_hcd *ehci)
|
||||
}
|
||||
clock %= mod;
|
||||
clock_frame = clock >> 3;
|
||||
+ ++ehci->periodic_stamp;
|
||||
|
||||
for (;;) {
|
||||
union ehci_shadow q, *q_p;
|
||||
@@ -2379,10 +2380,14 @@ restart:
|
||||
temp.qh = qh_get (q.qh);
|
||||
type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
|
||||
q = q.qh->qh_next;
|
||||
- modified = qh_completions (ehci, temp.qh);
|
||||
- if (unlikely(list_empty(&temp.qh->qtd_list) ||
|
||||
- temp.qh->needs_rescan))
|
||||
- intr_deschedule (ehci, temp.qh);
|
||||
+ if (temp.qh->stamp != ehci->periodic_stamp) {
|
||||
+ modified = qh_completions(ehci, temp.qh);
|
||||
+ if (!modified)
|
||||
+ temp.qh->stamp = ehci->periodic_stamp;
|
||||
+ if (unlikely(list_empty(&temp.qh->qtd_list) ||
|
||||
+ temp.qh->needs_rescan))
|
||||
+ intr_deschedule(ehci, temp.qh);
|
||||
+ }
|
||||
qh_put (temp.qh);
|
||||
break;
|
||||
case Q_TYPE_FSTN:
|
||||
@@ -2515,6 +2520,7 @@ restart:
|
||||
if (ehci->clock_frame != clock_frame) {
|
||||
free_cached_lists(ehci);
|
||||
ehci->clock_frame = clock_frame;
|
||||
+ ++ehci->periodic_stamp;
|
||||
}
|
||||
} else {
|
||||
now_uframe++;
|
||||
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
|
||||
index c702e4b..c2c2f9d 100644
|
||||
--- a/drivers/usb/host/ehci.h
|
||||
+++ b/drivers/usb/host/ehci.h
|
||||
@@ -117,6 +117,7 @@ struct ehci_hcd { /* one per controller */
|
||||
struct timer_list watchdog;
|
||||
unsigned long actions;
|
||||
unsigned stamp;
|
||||
+ unsigned periodic_stamp;
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
ktime_t last_periodic_enable;
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
From e8b80056d07bc849777d032bc699a59cc28f9ddb Mon Sep 17 00:00:00 2001
|
||||
From: Alan Stern <stern@rowland.harvard.edu>
|
||||
Date: Tue, 5 Jul 2011 12:34:05 -0400
|
||||
Subject: [PATCH 2/2] USB: EHCI: go back to using the system clock for QH
|
||||
unlinks
|
||||
|
||||
This patch (as1477) fixes a problem affecting a few types of EHCI
|
||||
controller. Contrary to what one might expect, these controllers
|
||||
automatically stop their internal frame counter when no ports are
|
||||
enabled. Since ehci-hcd currently relies on the frame counter for
|
||||
determining when it should unlink QHs from the async schedule, those
|
||||
controllers run into trouble: The frame counter stops and the QHs
|
||||
never get unlinked.
|
||||
|
||||
Some systems have also experienced other problems traced back to
|
||||
commit b963801164618e25fbdc0cd452ce49c3628b46c8 (USB: ehci-hcd unlink
|
||||
speedups), which made the original switch from using the system clock
|
||||
to using the frame counter. It never became clear what the reason was
|
||||
for these problems, but evidently it is related to use of the frame
|
||||
counter.
|
||||
|
||||
To fix all these problems, this patch more or less reverts that commit
|
||||
and goes back to using the system clock. But this can't be done
|
||||
cleanly because other changes have since been made to the scan_async()
|
||||
subroutine. One of these changes involved the tricky logic that tries
|
||||
to avoid rescanning QHs that have already been seen when the scanning
|
||||
loop is restarted, which happens whenever an URB is given back.
|
||||
Switching back to clock-based unlinks would make this logic even more
|
||||
complicated.
|
||||
|
||||
Therefore the new code doesn't rescan the entire async list whenever a
|
||||
giveback occurs. Instead it rescans only the current QH and continues
|
||||
on from there. This requires the use of a separate pointer to keep
|
||||
track of the next QH to scan, since the current QH may be unlinked
|
||||
while the scanning is in progress. That new pointer must be global,
|
||||
so that it can be adjusted forward whenever the _next_ QH gets
|
||||
unlinked. (uhci-hcd uses this same trick.)
|
||||
|
||||
Simplification of the scanning loop removes a level of indentation,
|
||||
which accounts for the size of the patch. The amount of code changed
|
||||
is relatively small, and it isn't exactly a reversion of the
|
||||
b963801164 commit.
|
||||
|
||||
This fixes Bugzilla #32432.
|
||||
|
||||
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
CC: <stable@kernel.org>
|
||||
Tested-by: Matej Kenda <matejken@gmail.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
---
|
||||
drivers/usb/host/ehci-hcd.c | 8 ++---
|
||||
drivers/usb/host/ehci-q.c | 82 +++++++++++++++++++++----------------------
|
||||
drivers/usb/host/ehci.h | 3 +-
|
||||
3 files changed, 45 insertions(+), 48 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
|
||||
index 761bbb3..8e5b995 100644
|
||||
--- a/drivers/usb/host/ehci-hcd.c
|
||||
+++ b/drivers/usb/host/ehci-hcd.c
|
||||
@@ -83,7 +83,8 @@ static const char hcd_name [] = "ehci_hcd";
|
||||
#define EHCI_IAA_MSECS 10 /* arbitrary */
|
||||
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
|
||||
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
|
||||
-#define EHCI_SHRINK_FRAMES 5 /* async qh unlink delay */
|
||||
+#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1)
|
||||
+ /* 200-ms async qh unlink delay */
|
||||
|
||||
/* Initial IRQ latency: faster than hw default */
|
||||
static int log2_irq_thresh = 0; // 0 to 6
|
||||
@@ -138,10 +139,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
|
||||
break;
|
||||
/* case TIMER_ASYNC_SHRINK: */
|
||||
default:
|
||||
- /* add a jiffie since we synch against the
|
||||
- * 8 KHz uframe counter.
|
||||
- */
|
||||
- t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
|
||||
+ t = EHCI_SHRINK_JIFFIES;
|
||||
break;
|
||||
}
|
||||
mod_timer(&ehci->watchdog, t + jiffies);
|
||||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
|
||||
index 0079610..a664203 100644
|
||||
--- a/drivers/usb/host/ehci-q.c
|
||||
+++ b/drivers/usb/host/ehci-q.c
|
||||
@@ -1226,6 +1226,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
|
||||
prev->hw->hw_next = qh->hw->hw_next;
|
||||
prev->qh_next = qh->qh_next;
|
||||
+ if (ehci->qh_scan_next == qh)
|
||||
+ ehci->qh_scan_next = qh->qh_next.qh;
|
||||
wmb ();
|
||||
|
||||
/* If the controller isn't running, we don't have to wait for it */
|
||||
@@ -1251,53 +1253,49 @@ static void scan_async (struct ehci_hcd *ehci)
|
||||
struct ehci_qh *qh;
|
||||
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
|
||||
|
||||
- ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
|
||||
-rescan:
|
||||
stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
|
||||
- qh = ehci->async->qh_next.qh;
|
||||
- if (likely (qh != NULL)) {
|
||||
- do {
|
||||
- /* clean any finished work for this qh */
|
||||
- if (!list_empty(&qh->qtd_list) && (stopped ||
|
||||
- qh->stamp != ehci->stamp)) {
|
||||
- int temp;
|
||||
-
|
||||
- /* unlinks could happen here; completion
|
||||
- * reporting drops the lock. rescan using
|
||||
- * the latest schedule, but don't rescan
|
||||
- * qhs we already finished (no looping)
|
||||
- * unless the controller is stopped.
|
||||
- */
|
||||
- qh = qh_get (qh);
|
||||
- qh->stamp = ehci->stamp;
|
||||
- temp = qh_completions (ehci, qh);
|
||||
- if (qh->needs_rescan)
|
||||
- unlink_async(ehci, qh);
|
||||
- qh_put (qh);
|
||||
- if (temp != 0) {
|
||||
- goto rescan;
|
||||
- }
|
||||
- }
|
||||
|
||||
- /* unlink idle entries, reducing DMA usage as well
|
||||
- * as HCD schedule-scanning costs. delay for any qh
|
||||
- * we just scanned, there's a not-unusual case that it
|
||||
- * doesn't stay idle for long.
|
||||
- * (plus, avoids some kind of re-activation race.)
|
||||
+ ehci->qh_scan_next = ehci->async->qh_next.qh;
|
||||
+ while (ehci->qh_scan_next) {
|
||||
+ qh = ehci->qh_scan_next;
|
||||
+ ehci->qh_scan_next = qh->qh_next.qh;
|
||||
+ rescan:
|
||||
+ /* clean any finished work for this qh */
|
||||
+ if (!list_empty(&qh->qtd_list)) {
|
||||
+ int temp;
|
||||
+
|
||||
+ /*
|
||||
+ * Unlinks could happen here; completion reporting
|
||||
+ * drops the lock. That's why ehci->qh_scan_next
|
||||
+ * always holds the next qh to scan; if the next qh
|
||||
+ * gets unlinked then ehci->qh_scan_next is adjusted
|
||||
+ * in start_unlink_async().
|
||||
*/
|
||||
- if (list_empty(&qh->qtd_list)
|
||||
- && qh->qh_state == QH_STATE_LINKED) {
|
||||
- if (!ehci->reclaim && (stopped ||
|
||||
- ((ehci->stamp - qh->stamp) & 0x1fff)
|
||||
- >= EHCI_SHRINK_FRAMES * 8))
|
||||
- start_unlink_async(ehci, qh);
|
||||
- else
|
||||
- action = TIMER_ASYNC_SHRINK;
|
||||
- }
|
||||
+ qh = qh_get(qh);
|
||||
+ temp = qh_completions(ehci, qh);
|
||||
+ if (qh->needs_rescan)
|
||||
+ unlink_async(ehci, qh);
|
||||
+ qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
|
||||
+ qh_put(qh);
|
||||
+ if (temp != 0)
|
||||
+ goto rescan;
|
||||
+ }
|
||||
|
||||
- qh = qh->qh_next.qh;
|
||||
- } while (qh);
|
||||
+ /* unlink idle entries, reducing DMA usage as well
|
||||
+ * as HCD schedule-scanning costs. delay for any qh
|
||||
+ * we just scanned, there's a not-unusual case that it
|
||||
+ * doesn't stay idle for long.
|
||||
+ * (plus, avoids some kind of re-activation race.)
|
||||
+ */
|
||||
+ if (list_empty(&qh->qtd_list)
|
||||
+ && qh->qh_state == QH_STATE_LINKED) {
|
||||
+ if (!ehci->reclaim && (stopped ||
|
||||
+ time_after_eq(jiffies, qh->unlink_time)))
|
||||
+ start_unlink_async(ehci, qh);
|
||||
+ else
|
||||
+ action = TIMER_ASYNC_SHRINK;
|
||||
+ }
|
||||
}
|
||||
if (action == TIMER_ASYNC_SHRINK)
|
||||
timer_action (ehci, TIMER_ASYNC_SHRINK);
|
||||
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
|
||||
index c2c2f9d..23d9a5e 100644
|
||||
--- a/drivers/usb/host/ehci.h
|
||||
+++ b/drivers/usb/host/ehci.h
|
||||
@@ -74,6 +74,7 @@ struct ehci_hcd { /* one per controller */
|
||||
/* async schedule support */
|
||||
struct ehci_qh *async;
|
||||
struct ehci_qh *reclaim;
|
||||
+ struct ehci_qh *qh_scan_next;
|
||||
unsigned scanning : 1;
|
||||
|
||||
/* periodic schedule support */
|
||||
@@ -116,7 +117,6 @@ struct ehci_hcd { /* one per controller */
|
||||
struct timer_list iaa_watchdog;
|
||||
struct timer_list watchdog;
|
||||
unsigned long actions;
|
||||
- unsigned stamp;
|
||||
unsigned periodic_stamp;
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
@@ -337,6 +337,7 @@ struct ehci_qh {
|
||||
struct ehci_qh *reclaim; /* next to reclaim */
|
||||
|
||||
struct ehci_hcd *ehci;
|
||||
+ unsigned long unlink_time;
|
||||
|
||||
/*
|
||||
* Do NOT use atomic operations for QH refcounting. On some CPUs
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
From ed62f63919f93dcb040109959ee19983eda8ea84 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Thu, 15 Sep 2011 12:48:12 -0400
|
||||
Subject: [PATCH] Ecryptfs: Add mount option to check uid of device being
|
||||
mounted = expect uid
|
||||
|
||||
Close a TOCTOU race for mounts done via ecryptfs-mount-private. The mount
|
||||
source (device) can be raced when the ownership test is done in userspace.
|
||||
Provide Ecryptfs a means to force the uid check at mount time.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Cc: <stable@kernel.org>
|
||||
Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
|
||||
|
||||
Backported to 2.6.35.14 by Josh Boyer <jwboyer@redhat.com>
|
||||
---
|
||||
fs/ecryptfs/main.c | 27 ++++++++++++++++++++++-----
|
||||
1 files changed, 22 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
|
||||
index cbd4e18..c249d14 100644
|
||||
--- a/fs/ecryptfs/main.c
|
||||
+++ b/fs/ecryptfs/main.c
|
||||
@@ -208,7 +208,7 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,
|
||||
ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,
|
||||
ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig,
|
||||
ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes,
|
||||
- ecryptfs_opt_unlink_sigs, ecryptfs_opt_err };
|
||||
+ ecryptfs_opt_unlink_sigs, ecryptfs_opt_check_dev_ruid, ecryptfs_opt_err };
|
||||
|
||||
static const match_table_t tokens = {
|
||||
{ecryptfs_opt_sig, "sig=%s"},
|
||||
@@ -223,6 +223,7 @@ static const match_table_t tokens = {
|
||||
{ecryptfs_opt_fn_cipher, "ecryptfs_fn_cipher=%s"},
|
||||
{ecryptfs_opt_fn_cipher_key_bytes, "ecryptfs_fn_key_bytes=%u"},
|
||||
{ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"},
|
||||
+ {ecryptfs_opt_check_dev_ruid, "ecryptfs_check_dev_ruid"},
|
||||
{ecryptfs_opt_err, NULL}
|
||||
};
|
||||
|
||||
@@ -266,6 +267,7 @@ static void ecryptfs_init_mount_crypt_stat(
|
||||
* ecryptfs_parse_options
|
||||
* @sb: The ecryptfs super block
|
||||
* @options: The options pased to the kernel
|
||||
+ * @check_ruid: set to 1 if device uid should be checked against the ruid
|
||||
*
|
||||
* Parse mount options:
|
||||
* debug=N - ecryptfs_verbosity level for debug output
|
||||
@@ -281,7 +283,7 @@ static void ecryptfs_init_mount_crypt_stat(
|
||||
*
|
||||
* Returns zero on success; non-zero on error
|
||||
*/
|
||||
-static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
|
||||
+static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, uid_t *check_ruid)
|
||||
{
|
||||
char *p;
|
||||
int rc = 0;
|
||||
@@ -306,6 +308,8 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
|
||||
char *cipher_key_bytes_src;
|
||||
char *fn_cipher_key_bytes_src;
|
||||
|
||||
+ *check_ruid = 0;
|
||||
+
|
||||
if (!options) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
@@ -406,6 +410,9 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
|
||||
case ecryptfs_opt_unlink_sigs:
|
||||
mount_crypt_stat->flags |= ECRYPTFS_UNLINK_SIGS;
|
||||
break;
|
||||
+ case ecryptfs_opt_check_dev_ruid:
|
||||
+ *check_ruid = 1;
|
||||
+ break;
|
||||
case ecryptfs_opt_err:
|
||||
default:
|
||||
printk(KERN_WARNING
|
||||
@@ -494,7 +501,7 @@ static struct file_system_type ecryptfs_fs_type;
|
||||
* ecryptfs_interpose to create our initial inode and super block
|
||||
* struct.
|
||||
*/
|
||||
-static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
|
||||
+static int ecryptfs_read_super(struct super_block *sb, const char *dev_name, uid_t check_ruid)
|
||||
{
|
||||
struct path path;
|
||||
int rc;
|
||||
@@ -511,6 +518,15 @@ static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
|
||||
"known incompatibilities\n");
|
||||
goto out_free;
|
||||
}
|
||||
+
|
||||
+ if (check_ruid && path.dentry->d_inode->i_uid != current_uid()) {
|
||||
+ rc = -EPERM;
|
||||
+ printk(KERN_ERR "Mount of device (uid: %d) not owned by "
|
||||
+ "requested user (uid: %d)\n",
|
||||
+ path.dentry->d_inode->i_uid, current_uid());
|
||||
+ goto out_free;
|
||||
+ }
|
||||
+
|
||||
ecryptfs_set_superblock_lower(sb, path.dentry->d_sb);
|
||||
sb->s_maxbytes = path.dentry->d_sb->s_maxbytes;
|
||||
sb->s_blocksize = path.dentry->d_sb->s_blocksize;
|
||||
@@ -549,6 +565,7 @@ static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
struct ecryptfs_dentry_info *root_info;
|
||||
const char *err = "Getting sb failed";
|
||||
int rc;
|
||||
+ uid_t check_ruid;
|
||||
|
||||
sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL);
|
||||
if (!sbi) {
|
||||
@@ -556,7 +573,7 @@ static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- rc = ecryptfs_parse_options(sbi, raw_data);
|
||||
+ rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid);
|
||||
if (rc) {
|
||||
err = "Error parsing options";
|
||||
goto out;
|
||||
@@ -601,7 +618,7 @@ static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
/* ->kill_sb() will take care of root_info */
|
||||
ecryptfs_set_dentry_private(s->s_root, root_info);
|
||||
s->s_flags |= MS_ACTIVE;
|
||||
- rc = ecryptfs_read_super(s, dev_name);
|
||||
+ rc = ecryptfs_read_super(s, dev_name, check_ruid);
|
||||
if (rc) {
|
||||
deactivate_locked_super(s);
|
||||
err = "Reading sb failed";
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
From f8789858be5c1b13543040b74d978ea448461155 Mon Sep 17 00:00:00 2001
|
||||
From: David Howells <dhowells@redhat.com>
|
||||
Date: Tue, 15 Nov 2011 22:09:45 +0000
|
||||
Subject: [PATCH] KEYS: Fix a NULL pointer deref in the user-defined key type
|
||||
|
||||
commit 9f35a33b8d06263a165efe3541d9aa0cdbd70b3b upstream.
|
||||
|
||||
Fix a NULL pointer deref in the user-defined key type whereby updating a
|
||||
negative key into a fully instantiated key will cause an oops to occur
|
||||
when the code attempts to free the non-existent old payload.
|
||||
|
||||
This results in an oops that looks something like the following:
|
||||
|
||||
BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
|
||||
IP: [<ffffffff81085fa1>] __call_rcu+0x11/0x13e
|
||||
PGD 3391d067 PUD 3894a067 PMD 0
|
||||
Oops: 0002 [#1] SMP
|
||||
CPU 1
|
||||
Pid: 4354, comm: keyctl Not tainted 3.1.0-fsdevel+ #1140 /DG965RY
|
||||
RIP: 0010:[<ffffffff81085fa1>] [<ffffffff81085fa1>] __call_rcu+0x11/0x13e
|
||||
RSP: 0018:ffff88003d591df8 EFLAGS: 00010246
|
||||
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 000000000000006e
|
||||
RDX: ffffffff8161d0c0 RSI: 0000000000000000 RDI: 0000000000000000
|
||||
RBP: ffff88003d591e18 R08: 0000000000000000 R09: ffffffff8152fa6c
|
||||
R10: 0000000000000000 R11: 0000000000000300 R12: ffff88003b8f9538
|
||||
R13: ffffffff8161d0c0 R14: ffff88003b8f9d50 R15: ffff88003c69f908
|
||||
FS: 00007f97eb18c720(0000) GS:ffff88003bd00000(0000) knlGS:0000000000000000
|
||||
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
CR2: 0000000000000008 CR3: 000000003d47a000 CR4: 00000000000006e0
|
||||
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
|
||||
Process keyctl (pid: 4354, threadinfo ffff88003d590000, task ffff88003c78a040)
|
||||
Stack:
|
||||
ffff88003e0ffde0 ffff88003b8f9538 0000000000000001 ffff88003b8f9d50
|
||||
ffff88003d591e28 ffffffff810860f0 ffff88003d591e68 ffffffff8117bfea
|
||||
ffff88003d591e68 ffffffff00000000 ffff88003e0ffde1 ffff88003e0ffde0
|
||||
Call Trace:
|
||||
[<ffffffff810860f0>] call_rcu_sched+0x10/0x12
|
||||
[<ffffffff8117bfea>] user_update+0x8d/0xa2
|
||||
[<ffffffff8117723a>] key_create_or_update+0x236/0x270
|
||||
[<ffffffff811789b1>] sys_add_key+0x123/0x17e
|
||||
[<ffffffff813b84bb>] system_call_fastpath+0x16/0x1b
|
||||
|
||||
Signed-off-by: David Howells <dhowells@redhat.com>
|
||||
Acked-by: Jeff Layton <jlayton@redhat.com>
|
||||
Acked-by: Neil Horman <nhorman@redhat.com>
|
||||
Acked-by: Steve Dickson <steved@redhat.com>
|
||||
Acked-by: James Morris <jmorris@namei.org>
|
||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
---
|
||||
security/keys/user_defined.c | 3 ++-
|
||||
1 files changed, 2 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
|
||||
index e9aa079..d6781b9 100644
|
||||
--- a/security/keys/user_defined.c
|
||||
+++ b/security/keys/user_defined.c
|
||||
@@ -119,7 +119,8 @@ int user_update(struct key *key, const void *data, size_t datalen)
|
||||
key->expiry = 0;
|
||||
}
|
||||
|
||||
- call_rcu(&zap->rcu, user_update_rcu_disposal);
|
||||
+ if (zap)
|
||||
+ call_rcu(&zap->rcu, user_update_rcu_disposal);
|
||||
|
||||
error:
|
||||
return ret;
|
||||
--
|
||||
1.7.7.1
|
||||
|
6
Makefile
6
Makefile
|
@ -88,6 +88,7 @@ debug:
|
|||
@perl -pi -e 's/# CONFIG_KDB_KEYBOARD is not set/CONFIG_KDB_KEYBOARD=y/' config-nodebug
|
||||
@perl -pi -e 's/# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set/CONFIG_CPU_NOTIFIER_ERROR_INJECT=m/' config-nodebug
|
||||
@perl -pi -e 's/# CONFIG_DEBUG_PER_CPU_MAPS is not set/CONFIG_DEBUG_PER_CPU_MAPS=y/' config-nodebug
|
||||
#@perl -pi -e 's/# CONFIG_PCI_DEFAULT_USE_CRS is not set/CONFIG_PCI_DEFAULT_USE_CRS=y/' config-nodebug
|
||||
|
||||
@# just in case we're going from extremedebug -> debug
|
||||
@perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-nodebug
|
||||
|
@ -97,6 +98,10 @@ debug:
|
|||
@perl -pi -e 's/^%define debugbuildsenabled 1/%define debugbuildsenabled 0/' kernel.spec
|
||||
@perl -pi -e 's/^%define rawhide_skip_docs 0/%define rawhide_skip_docs 1/' kernel.spec
|
||||
|
||||
nodebuginfo:
|
||||
@perl -pi -e 's/^%define with_debuginfo %\{\?_without_debuginfo: 0\} %\{\?\!_without_debuginfo: 1\}/%define with_debuginfo %\{\?_without_debuginfo: 0\} %\{\?\!_without_debuginfo: 0\}/' kernel.spec
|
||||
nodebug: release
|
||||
@perl -pi -e 's/^%define debugbuildsenabled 1/%define debugbuildsenabled 0/' kernel.spec
|
||||
release:
|
||||
@perl -pi -e 's/CONFIG_SLUB_DEBUG_ON=y/# CONFIG_SLUB_DEBUG_ON is not set/' config-nodebug
|
||||
@perl -pi -e 's/CONFIG_LOCK_STAT=y/# CONFIG_LOCK_STAT is not set/' config-nodebug
|
||||
|
@ -156,6 +161,7 @@ release:
|
|||
#@perl -pi -e 's/CONFIG_KGDB_KDB=y/# CONFIG_KGDB_KDB is not set/' config-nodebug
|
||||
#@perl -pi -e 's/CONFIG_KDB_KEYBOARD=y/# CONFIG_KDB_KEYBOARD is not set/' config-nodebug
|
||||
@perl -pi -e 's/CONFIG_DEBUG_PER_CPU_MAPS=y/# CONFIG_DEBUG_PER_CPU_MAPS is not set/' config-nodebug
|
||||
#@perl -pi -e 's/CONFIG_PCI_DEFAULT_USE_CRS=y/# CONFIG_PCI_DEFAULT_USE_CRS is not set/' config-nodebug
|
||||
|
||||
@perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-debug
|
||||
@perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-nodebug
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
From 6b07d30aca7e52f2881b8c8c20c8a2cd28e8b3d3 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Huewe <huewe.external.infineon@googlemail.com>
|
||||
Date: Thu, 15 Sep 2011 14:37:43 -0300
|
||||
Subject: [PATCH] TPM: Call tpm_transmit with correct size
|
||||
|
||||
This patch changes the call of tpm_transmit by supplying the size of the
|
||||
userspace buffer instead of TPM_BUFSIZE.
|
||||
|
||||
This got assigned CVE-2011-1161.
|
||||
|
||||
[The first hunk didn't make sense given one could expect
|
||||
way less data than TPM_BUFSIZE, so added tpm_transmit boundary
|
||||
check over bufsiz instead
|
||||
The last parameter of tpm_transmit() reflects the amount
|
||||
of data expected from the device, and not the buffer size
|
||||
being supplied to it. It isn't ideal to parse it directly,
|
||||
so we just set it to the maximum the input buffer can handle
|
||||
and let the userspace API to do such job.]
|
||||
|
||||
Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
|
||||
Cc: Stable Kernel <stable@kernel.org>
|
||||
Signed-off-by: James Morris <jmorris@namei.org>
|
||||
---
|
||||
drivers/char/tpm/tpm.c | 3 +++
|
||||
1 files changed, 3 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
|
||||
index caf8012..1fe9793 100644
|
||||
--- a/drivers/char/tpm/tpm.c
|
||||
+++ b/drivers/char/tpm/tpm.c
|
||||
@@ -383,6 +383,9 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||
u32 count, ordinal;
|
||||
unsigned long stop;
|
||||
|
||||
+ if (bufsiz > TPM_BUFSIZE)
|
||||
+ bufsiz = TPM_BUFSIZE;
|
||||
+
|
||||
count = be32_to_cpu(*((__be32 *) (buf + 2)));
|
||||
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
|
||||
if (count == 0)
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
From 3321c07ae5068568cd61ac9f4ba749006a7185c9 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Huewe <huewe.external.infineon@googlemail.com>
|
||||
Date: Thu, 15 Sep 2011 14:47:42 -0300
|
||||
Subject: [PATCH] TPM: Zero buffer after copying to userspace
|
||||
|
||||
Since the buffer might contain security related data it might be a good idea to
|
||||
zero the buffer after we have copied it to userspace.
|
||||
|
||||
This got assigned CVE-2011-1162.
|
||||
|
||||
Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
|
||||
Cc: Stable Kernel <stable@kernel.org>
|
||||
Signed-off-by: James Morris <jmorris@namei.org>
|
||||
---
|
||||
drivers/char/tpm/tpm.c | 6 +++++-
|
||||
1 files changed, 5 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
|
||||
index 1fe9793..9ca5c02 100644
|
||||
--- a/drivers/char/tpm/tpm.c
|
||||
+++ b/drivers/char/tpm/tpm.c
|
||||
@@ -1105,6 +1105,7 @@ ssize_t tpm_read(struct file *file, char __user *buf,
|
||||
{
|
||||
struct tpm_chip *chip = file->private_data;
|
||||
ssize_t ret_size;
|
||||
+ int rc;
|
||||
|
||||
del_singleshot_timer_sync(&chip->user_read_timer);
|
||||
flush_work_sync(&chip->work);
|
||||
@@ -1115,8 +1116,11 @@ ssize_t tpm_read(struct file *file, char __user *buf,
|
||||
ret_size = size;
|
||||
|
||||
mutex_lock(&chip->buffer_mutex);
|
||||
- if (copy_to_user(buf, chip->data_buffer, ret_size))
|
||||
+ rc = copy_to_user(buf, chip->data_buffer, ret_size);
|
||||
+ memset(chip->data_buffer, 0, ret_size);
|
||||
+ if (rc)
|
||||
ret_size = -EFAULT;
|
||||
+
|
||||
mutex_unlock(&chip->buffer_mutex);
|
||||
}
|
||||
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
commit 08a0799d5736f1494ef35d386570d177447acbfb
|
||||
Author: Lee, Chun-Yi <joeyli.kernel@gmail.com>
|
||||
Date: Wed Apr 6 17:40:06 2011 +0800
|
||||
|
||||
acer-wmi: Fix capitalisation of GUID in module alias
|
||||
|
||||
wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3 needs to be
|
||||
wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3 in module alias for acer-wmi is
|
||||
automatically loaded.
|
||||
|
||||
Cc: Pali Rohár <pali.rohar@gmail.com>
|
||||
Cc: Carlos Corbacho <carlos@strangeworlds.co.uk>
|
||||
Cc: Matthew Garrett <mjg@redhat.com>
|
||||
Signed-off-by: Lee, Chun-Yi <jlee@novell.com>
|
||||
Signed-off-by: Matthew Garrett <mjg@redhat.com>
|
||||
|
||||
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
|
||||
index 5ea6c34..ac4e7f8 100644
|
||||
--- a/drivers/platform/x86/acer-wmi.c
|
||||
+++ b/drivers/platform/x86/acer-wmi.c
|
||||
@@ -95,7 +95,7 @@ struct acer_quirks {
|
||||
#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
|
||||
|
||||
MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
|
||||
-MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
|
||||
+MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3");
|
||||
|
||||
/*
|
||||
* Interface capability flags
|
|
@ -0,0 +1,38 @@
|
|||
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
|
||||
index 3ed80b2..17fc718 100644
|
||||
--- a/drivers/acpi/sleep.c
|
||||
+++ b/drivers/acpi/sleep.c
|
||||
@@ -390,6 +390,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
|
||||
},
|
||||
{
|
||||
.callback = init_nvs_nosave,
|
||||
+ .ident = "Sony Vaio VGN-FW21E",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .callback = init_nvs_nosave,
|
||||
.ident = "Sony Vaio VGN-SR11M",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
||||
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
|
||||
index 0e46fae..6d9a3ab 100644
|
||||
--- a/drivers/acpi/sleep.c
|
||||
+++ b/drivers/acpi/sleep.c
|
||||
@@ -398,6 +398,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
|
||||
},
|
||||
{
|
||||
.callback = init_nvs_nosave,
|
||||
+ .ident = "Sony Vaio VPCEB17FX",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .callback = init_nvs_nosave,
|
||||
.ident = "Sony Vaio VGN-SR11M",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
|
@ -0,0 +1,68 @@
|
|||
--- linux-2.6.35.x86_64/drivers/acpi/battery.c.orig 2010-12-23 10:42:09.291854595 -0500
|
||||
+++ linux-2.6.35.x86_64/drivers/acpi/battery.c 2010-12-23 10:44:30.996045838 -0500
|
||||
@@ -596,9 +596,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
-static int acpi_battery_update(struct acpi_battery *battery)
|
||||
+static int acpi_battery_update(struct acpi_battery *battery, bool get_info)
|
||||
{
|
||||
int result, old_present = acpi_battery_present(battery);
|
||||
+ int old_power_unit = battery->power_unit;
|
||||
result = acpi_battery_get_status(battery);
|
||||
if (result)
|
||||
return result;
|
||||
@@ -621,6 +622,16 @@
|
||||
if (!battery->bat.dev)
|
||||
sysfs_add_battery(battery);
|
||||
#endif
|
||||
+ if (get_info) {
|
||||
+ acpi_battery_get_info(battery);
|
||||
+#ifdef CONFIG_ACPI_SYSFS_POWER
|
||||
+ if (old_power_unit != battery->power_unit) {
|
||||
+ /* The battery has changed its reporting units */
|
||||
+ sysfs_remove_battery(battery);
|
||||
+ sysfs_add_battery(battery);
|
||||
+ }
|
||||
+#endif
|
||||
+ }
|
||||
result = acpi_battery_get_state(battery);
|
||||
acpi_battery_quirks2(battery);
|
||||
return result;
|
||||
@@ -798,7 +809,7 @@
|
||||
static int acpi_battery_read(int fid, struct seq_file *seq)
|
||||
{
|
||||
struct acpi_battery *battery = seq->private;
|
||||
- int result = acpi_battery_update(battery);
|
||||
+ int result = acpi_battery_update(battery, false);
|
||||
return acpi_print_funcs[fid](seq, result);
|
||||
}
|
||||
|
||||
@@ -913,7 +924,8 @@
|
||||
#ifdef CONFIG_ACPI_SYSFS_POWER
|
||||
old = battery->bat.dev;
|
||||
#endif
|
||||
- acpi_battery_update(battery);
|
||||
+ acpi_battery_update(battery, (event == ACPI_BATTERY_NOTIFY_INFO ? true
|
||||
+ : false));
|
||||
acpi_bus_generate_proc_event(device, event,
|
||||
acpi_battery_present(battery));
|
||||
acpi_bus_generate_netlink_event(device->pnp.device_class,
|
||||
@@ -944,7 +956,7 @@
|
||||
if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle,
|
||||
"_BIX", &handle)))
|
||||
set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
|
||||
- acpi_battery_update(battery);
|
||||
+ acpi_battery_update(battery, false);
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
result = acpi_battery_add_fs(device);
|
||||
#endif
|
||||
@@ -987,7 +999,7 @@
|
||||
return -EINVAL;
|
||||
battery = acpi_driver_data(device);
|
||||
battery->update_time = 0;
|
||||
- acpi_battery_update(battery);
|
||||
+ acpi_battery_update(battery, true);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,702 @@
|
|||
From 46fadae732d825141f45bf2fbd6381451da26ad7 Mon Sep 17 00:00:00 2001
|
||||
From: Bastien Nocera <hadess@hadess.net>
|
||||
Date: Fri, 10 Sep 2010 16:40:46 +0100
|
||||
Subject: [PATCH] Input: add appleir USB driver
|
||||
|
||||
This driver was originally written by James McKenzie, updated by
|
||||
Greg Kroah-Hartman, further updated by myself, with suspend support
|
||||
added.
|
||||
|
||||
More recent versions of the IR receiver are also supported through
|
||||
a patch by Alex Karpenko. The patch also adds support for the 2nd
|
||||
and 5th generation of the controller, and the menu key on newer
|
||||
brushed metal remotes.
|
||||
|
||||
Tested on a MacbookAir1,1
|
||||
|
||||
Signed-off-by: Bastien Nocera <hadess@hadess.net>
|
||||
---
|
||||
Documentation/input/appleir.txt | 46 ++++
|
||||
drivers/hid/hid-apple.c | 4 -
|
||||
drivers/hid/hid-core.c | 7 +-
|
||||
drivers/hid/hid-ids.h | 5 +-
|
||||
drivers/input/misc/Kconfig | 13 +
|
||||
drivers/input/misc/Makefile | 1 +
|
||||
drivers/input/misc/appleir.c | 519 +++++++++++++++++++++++++++++++++++++++
|
||||
7 files changed, 588 insertions(+), 7 deletions(-)
|
||||
create mode 100644 Documentation/input/appleir.txt
|
||||
create mode 100644 drivers/input/misc/appleir.c
|
||||
|
||||
diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt
|
||||
new file mode 100644
|
||||
index 0000000..db637fb
|
||||
--- /dev/null
|
||||
+++ b/Documentation/input/appleir.txt
|
||||
@@ -0,0 +1,46 @@
|
||||
+Apple IR receiver Driver (appleir)
|
||||
+----------------------------------
|
||||
+ Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
|
||||
+
|
||||
+The appleir driver is a kernel input driver to handle Apple's IR
|
||||
+receivers (and associated remotes) in the kernel.
|
||||
+
|
||||
+The driver is an input driver which only handles "official" remotes
|
||||
+as built and sold by Apple.
|
||||
+
|
||||
+Authors
|
||||
+-------
|
||||
+
|
||||
+James McKenzie (original driver)
|
||||
+Alex Karpenko (05ac:8242 support)
|
||||
+Greg Kroah-Hartman (cleanups and original submission)
|
||||
+Bastien Nocera (further cleanups, brushed metal "enter"
|
||||
+button support and suspend support)
|
||||
+
|
||||
+Supported hardware
|
||||
+------------------
|
||||
+
|
||||
+- All Apple laptops and desktops from 2005 onwards, except:
|
||||
+ - the unibody Macbook (2009)
|
||||
+ - Mac Pro (all versions)
|
||||
+- Apple TV (all revisions prior to September 2010)
|
||||
+
|
||||
+The remote will only support the 6 (old white) or 7 (brushed metal) buttons
|
||||
+of the remotes as sold by Apple. See the next section if you want to use
|
||||
+other remotes or want to use lirc with the device instead of the kernel driver.
|
||||
+
|
||||
+Using lirc (native) instead of the kernel driver
|
||||
+------------------------------------------------
|
||||
+
|
||||
+First, you will need to disable the kernel driver for the receiver.
|
||||
+
|
||||
+This can be achieved by passing quirks to the usbhid driver.
|
||||
+The quirk line would be:
|
||||
+usbhid.quirks=0x05ac:0x8242:0x40000010
|
||||
+
|
||||
+With 0x05ac being the vendor ID (Apple, you shouldn't need to change this)
|
||||
+With 0x8242 being the product ID (check the output of lsusb for your hardware)
|
||||
+And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE"
|
||||
+
|
||||
+This should force the creation of a hiddev device for the receiver, and
|
||||
+make it usable under lirc.
|
||||
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
|
||||
index bba05d0..0059d5a 100644
|
||||
--- a/drivers/hid/hid-apple.c
|
||||
+++ b/drivers/hid/hid-apple.c
|
||||
@@ -361,10 +361,6 @@ static void apple_remove(struct hid_device *hdev)
|
||||
}
|
||||
|
||||
static const struct hid_device_id apple_devices[] = {
|
||||
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
|
||||
- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
|
||||
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
|
||||
- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
|
||||
.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
|
||||
|
||||
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
||||
index 866e54e..1d5e284 100644
|
||||
--- a/drivers/hid/hid-core.c
|
||||
+++ b/drivers/hid/hid-core.c
|
||||
@@ -1239,8 +1239,6 @@ static const struct hid_device_id hid_blacklist[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
|
||||
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
|
||||
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
|
||||
@@ -1571,6 +1569,11 @@ static const struct hid_device_id hid_ignore_list[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
|
||||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
|
||||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
|
||||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
|
||||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
|
||||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
|
||||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
||||
index 31601ee..9afe3bc 100644
|
||||
--- a/drivers/hid/hid-ids.h
|
||||
+++ b/drivers/hid/hid-ids.h
|
||||
@@ -98,8 +98,11 @@
|
||||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
|
||||
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
|
||||
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
|
||||
-#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241
|
||||
+#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
|
||||
+#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440
|
||||
+#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
|
||||
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
|
||||
+#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243
|
||||
|
||||
#define USB_VENDOR_ID_ASUS 0x0486
|
||||
#define USB_DEVICE_ID_ASUS_T91MT 0x0185
|
||||
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
|
||||
index c44b9ea..76a12b7 100644
|
||||
--- a/drivers/input/misc/Kconfig
|
||||
+++ b/drivers/input/misc/Kconfig
|
||||
@@ -199,6 +199,19 @@ config INPUT_KEYSPAN_REMOTE
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called keyspan_remote.
|
||||
|
||||
+config INPUT_APPLEIR
|
||||
+ tristate "Apple infrared receiver (built in)"
|
||||
+ depends on USB_ARCH_HAS_HCD
|
||||
+ select USB
|
||||
+ help
|
||||
+ Say Y here if you want to use a Apple infrared remote control. All
|
||||
+ the Apple computers from 2005 onwards include such a port, except
|
||||
+ the unibody Macbook (2009), and Mac Pros. This receiver is also
|
||||
+ used in the Apple TV set-top box prior to the 2010 model.
|
||||
+
|
||||
+ To compile this driver as a module, choose M here: the module will
|
||||
+ be called appleir.
|
||||
+
|
||||
config INPUT_POWERMATE
|
||||
tristate "Griffin PowerMate and Contour Jog support"
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
|
||||
index 71fe57d..62a5c60 100644
|
||||
--- a/drivers/input/misc/Makefile
|
||||
+++ b/drivers/input/misc/Makefile
|
||||
@@ -9,6 +9,7 @@ obj-$(CONFIG_INPUT_AD714X) += ad714x.o
|
||||
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
|
||||
obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
|
||||
obj-$(CONFIG_INPUT_APANEL) += apanel.o
|
||||
+obj-$(CONFIG_INPUT_APPLEIR) += appleir.o
|
||||
obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
|
||||
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
|
||||
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
|
||||
diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c
|
||||
new file mode 100644
|
||||
index 0000000..3817a3c
|
||||
--- /dev/null
|
||||
+++ b/drivers/input/misc/appleir.c
|
||||
@@ -0,0 +1,519 @@
|
||||
+/*
|
||||
+ * appleir: USB driver for the apple ir device
|
||||
+ *
|
||||
+ * Original driver written by James McKenzie
|
||||
+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
|
||||
+ *
|
||||
+ * Copyright (C) 2006 James McKenzie
|
||||
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
|
||||
+ * Copyright (C) 2008 Novell Inc.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the Free
|
||||
+ * Software Foundation, version 2.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/input.h>
|
||||
+#include <linux/usb/input.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/usb.h>
|
||||
+#include <linux/usb/input.h>
|
||||
+#include <asm/unaligned.h>
|
||||
+#include <asm/byteorder.h>
|
||||
+
|
||||
+#define DRIVER_VERSION "v1.2"
|
||||
+#define DRIVER_AUTHOR "James McKenzie"
|
||||
+#define DRIVER_DESC "Apple infrared receiver driver"
|
||||
+#define DRIVER_LICENSE "GPL"
|
||||
+
|
||||
+MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
+MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
+MODULE_LICENSE(DRIVER_LICENSE);
|
||||
+
|
||||
+#define USB_VENDOR_ID_APPLE 0x05ac
|
||||
+#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
|
||||
+#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440
|
||||
+#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
|
||||
+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
|
||||
+#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243
|
||||
+
|
||||
+#define URB_SIZE 32
|
||||
+
|
||||
+#define MAX_KEYS 9
|
||||
+#define MAX_KEYS_MASK (MAX_KEYS - 1)
|
||||
+
|
||||
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
|
||||
+
|
||||
+static int debug;
|
||||
+module_param(debug, int, 0644);
|
||||
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
|
||||
+
|
||||
+/* I have two devices both of which report the following */
|
||||
+/* 25 87 ee 83 0a + */
|
||||
+/* 25 87 ee 83 0c - */
|
||||
+/* 25 87 ee 83 09 << */
|
||||
+/* 25 87 ee 83 06 >> */
|
||||
+/* 25 87 ee 83 05 >" */
|
||||
+/* 25 87 ee 83 03 menu */
|
||||
+/* 26 00 00 00 00 for key repeat*/
|
||||
+
|
||||
+/* Thomas Glanzmann reports the following responses */
|
||||
+/* 25 87 ee ca 0b + */
|
||||
+/* 25 87 ee ca 0d - */
|
||||
+/* 25 87 ee ca 08 << */
|
||||
+/* 25 87 ee ca 07 >> */
|
||||
+/* 25 87 ee ca 04 >" */
|
||||
+/* 25 87 ee ca 02 menu */
|
||||
+/* 26 00 00 00 00 for key repeat*/
|
||||
+/* He also observes the following event sometimes */
|
||||
+/* sent after a key is release, which I interpret */
|
||||
+/* as a flat battery message */
|
||||
+/* 25 87 e0 ca 06 flat battery */
|
||||
+
|
||||
+/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */
|
||||
+/* 25 87 ee 47 0b + */
|
||||
+/* 25 87 ee 47 0d - */
|
||||
+/* 25 87 ee 47 08 << */
|
||||
+/* 25 87 ee 47 07 >> */
|
||||
+/* 25 87 ee 47 04 >" */
|
||||
+/* 25 87 ee 47 02 menu */
|
||||
+/* 26 87 ee 47 ** for key repeat (** is the code of the key being held) */
|
||||
+
|
||||
+/* Bastien Nocera's "new" remote */
|
||||
+/* 25 87 ee 91 5f followed by
|
||||
+ * 25 87 ee 91 05 gives you >"
|
||||
+ *
|
||||
+ * 25 87 ee 91 5c followed by
|
||||
+ * 25 87 ee 91 05 gives you the middle button */
|
||||
+
|
||||
+static const unsigned short appleir_key_table[] = {
|
||||
+ KEY_RESERVED,
|
||||
+ KEY_MENU,
|
||||
+ KEY_PLAYPAUSE,
|
||||
+ KEY_FORWARD,
|
||||
+ KEY_BACK,
|
||||
+ KEY_VOLUMEUP,
|
||||
+ KEY_VOLUMEDOWN,
|
||||
+ KEY_ENTER,
|
||||
+ KEY_RESERVED,
|
||||
+};
|
||||
+
|
||||
+struct appleir {
|
||||
+ struct input_dev *input_dev;
|
||||
+ unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
|
||||
+ u8 *data;
|
||||
+ dma_addr_t dma_buf;
|
||||
+ struct usb_device *usbdev;
|
||||
+ unsigned int flags;
|
||||
+ struct urb *urb;
|
||||
+ struct timer_list key_up_timer;
|
||||
+ int current_key;
|
||||
+ int prev_key_idx;
|
||||
+ char phys[32];
|
||||
+};
|
||||
+
|
||||
+static DEFINE_MUTEX(appleir_mutex);
|
||||
+
|
||||
+enum {
|
||||
+ APPLEIR_OPENED = 0x1,
|
||||
+ APPLEIR_SUSPENDED = 0x2,
|
||||
+};
|
||||
+
|
||||
+static struct usb_device_id appleir_ids[] = {
|
||||
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
|
||||
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
|
||||
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
|
||||
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
|
||||
+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(usb, appleir_ids);
|
||||
+
|
||||
+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ printk(KERN_ERR "appleir: %s (%d bytes)", msg, len);
|
||||
+
|
||||
+ for (i = 0; i < len; ++i)
|
||||
+ printk(" %02x", data[i]);
|
||||
+ printk(" (should be command %d)\n", (data[4] >> 1) & MAX_KEYS_MASK);
|
||||
+}
|
||||
+
|
||||
+static int get_key(int data)
|
||||
+{
|
||||
+ switch (data) {
|
||||
+ case 0x02:
|
||||
+ case 0x03:
|
||||
+ /* menu */
|
||||
+ return 1;
|
||||
+ case 0x04:
|
||||
+ case 0x05:
|
||||
+ /* >" */
|
||||
+ return 2;
|
||||
+ case 0x06:
|
||||
+ case 0x07:
|
||||
+ /* >> */
|
||||
+ return 3;
|
||||
+ case 0x08:
|
||||
+ case 0x09:
|
||||
+ /* << */
|
||||
+ return 4;
|
||||
+ case 0x0a:
|
||||
+ case 0x0b:
|
||||
+ /* + */
|
||||
+ return 5;
|
||||
+ case 0x0c:
|
||||
+ case 0x0d:
|
||||
+ /* - */
|
||||
+ return 6;
|
||||
+ case 0x5c:
|
||||
+ /* Middle button, on newer remotes,
|
||||
+ * part of a 2 packet-command */
|
||||
+ return -7;
|
||||
+ default:
|
||||
+ return -1;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void key_up(struct appleir *appleir, int key)
|
||||
+{
|
||||
+ dbginfo(&appleir->input_dev->dev, "key %d up\n", key);
|
||||
+ input_report_key(appleir->input_dev, key, 0);
|
||||
+ input_sync(appleir->input_dev);
|
||||
+}
|
||||
+
|
||||
+static void key_down(struct appleir *appleir, int key)
|
||||
+{
|
||||
+ dbginfo(&appleir->input_dev->dev, "key %d down\n", key);
|
||||
+ input_report_key(appleir->input_dev, key, 1);
|
||||
+ input_sync(appleir->input_dev);
|
||||
+}
|
||||
+
|
||||
+static void battery_flat(struct appleir *appleir)
|
||||
+{
|
||||
+ dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
|
||||
+}
|
||||
+
|
||||
+static void key_up_tick(unsigned long data)
|
||||
+{
|
||||
+ struct appleir *appleir = (struct appleir *)data;
|
||||
+
|
||||
+ if (appleir->current_key) {
|
||||
+ key_up(appleir, appleir->current_key);
|
||||
+ appleir->current_key = 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void new_data(struct appleir *appleir, u8 *data, int len)
|
||||
+{
|
||||
+ static const u8 keydown[] = { 0x25, 0x87, 0xee };
|
||||
+ static const u8 keyrepeat[] = { 0x26, };
|
||||
+ static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
|
||||
+
|
||||
+ if (debug)
|
||||
+ dump_packet(appleir, "received", data, len);
|
||||
+
|
||||
+ if (len != 5)
|
||||
+ return;
|
||||
+
|
||||
+ if (!memcmp(data, keydown, sizeof(keydown))) {
|
||||
+ int index;
|
||||
+
|
||||
+ /* If we already have a key down, take it up before marking
|
||||
+ this one down */
|
||||
+ if (appleir->current_key)
|
||||
+ key_up(appleir, appleir->current_key);
|
||||
+
|
||||
+ /* Handle dual packet commands */
|
||||
+ if (appleir->prev_key_idx > 0)
|
||||
+ index = appleir->prev_key_idx;
|
||||
+ else
|
||||
+ index = get_key(data[4]);
|
||||
+
|
||||
+ if (index > 0) {
|
||||
+ appleir->current_key = appleir->keymap[index];
|
||||
+
|
||||
+ key_down(appleir, appleir->current_key);
|
||||
+ /* Remote doesn't do key up, either pull them up, in the test
|
||||
+ above, or here set a timer which pulls them up after 1/8 s */
|
||||
+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
|
||||
+ appleir->prev_key_idx = 0;
|
||||
+ return;
|
||||
+ } else if (index == -7) {
|
||||
+ /* Remember key for next packet */
|
||||
+ appleir->prev_key_idx = 0 - index;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ appleir->prev_key_idx = 0;
|
||||
+
|
||||
+ if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
|
||||
+ key_down(appleir, appleir->current_key);
|
||||
+ /* Remote doesn't do key up, either pull them up, in the test
|
||||
+ above, or here set a timer which pulls them up after 1/8 s */
|
||||
+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
|
||||
+ battery_flat(appleir);
|
||||
+ /* Fall through */
|
||||
+ }
|
||||
+
|
||||
+ dump_packet(appleir, "unknown packet", data, len);
|
||||
+}
|
||||
+
|
||||
+static void appleir_urb(struct urb *urb)
|
||||
+{
|
||||
+ struct appleir *appleir = urb->context;
|
||||
+ int status = urb->status;
|
||||
+ int retval;
|
||||
+
|
||||
+ switch (status) {
|
||||
+ case 0:
|
||||
+ new_data(appleir, urb->transfer_buffer, urb->actual_length);
|
||||
+ break;
|
||||
+ case -ECONNRESET:
|
||||
+ case -ENOENT:
|
||||
+ case -ESHUTDOWN:
|
||||
+ /* This urb is terminated, clean up */
|
||||
+ dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__,
|
||||
+ urb->status);
|
||||
+ return;
|
||||
+ default:
|
||||
+ dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__,
|
||||
+ urb->status);
|
||||
+ }
|
||||
+
|
||||
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
+ if (retval)
|
||||
+ err("%s - usb_submit_urb failed with result %d", __func__,
|
||||
+ retval);
|
||||
+}
|
||||
+
|
||||
+static int appleir_open(struct input_dev *dev)
|
||||
+{
|
||||
+ struct appleir *appleir = input_get_drvdata(dev);
|
||||
+ struct usb_interface *intf = usb_ifnum_to_if(appleir->usbdev, 0);
|
||||
+ int r;
|
||||
+
|
||||
+ r = usb_autopm_get_interface(intf);
|
||||
+ if (r) {
|
||||
+ dev_err(&intf->dev,
|
||||
+ "%s(): usb_autopm_get_interface() = %d\n", __func__, r);
|
||||
+ return r;
|
||||
+ }
|
||||
+
|
||||
+ mutex_lock(&appleir_mutex);
|
||||
+
|
||||
+ if (usb_submit_urb(appleir->urb, GFP_ATOMIC)) {
|
||||
+ r = -EIO;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ appleir->flags |= APPLEIR_OPENED;
|
||||
+
|
||||
+ mutex_unlock(&appleir_mutex);
|
||||
+
|
||||
+ usb_autopm_put_interface(intf);
|
||||
+
|
||||
+ return 0;
|
||||
+fail:
|
||||
+ mutex_unlock(&appleir_mutex);
|
||||
+ usb_autopm_put_interface(intf);
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+static void appleir_close(struct input_dev *dev)
|
||||
+{
|
||||
+ struct appleir *appleir = input_get_drvdata(dev);
|
||||
+
|
||||
+ mutex_lock(&appleir_mutex);
|
||||
+
|
||||
+ if (!(appleir->flags & APPLEIR_SUSPENDED)) {
|
||||
+ usb_kill_urb(appleir->urb);
|
||||
+ del_timer_sync(&appleir->key_up_timer);
|
||||
+ }
|
||||
+
|
||||
+ appleir->flags &= ~APPLEIR_OPENED;
|
||||
+
|
||||
+ mutex_unlock(&appleir_mutex);
|
||||
+}
|
||||
+
|
||||
+static int appleir_probe(struct usb_interface *intf,
|
||||
+ const struct usb_device_id *id)
|
||||
+{
|
||||
+ struct usb_device *dev = interface_to_usbdev(intf);
|
||||
+ struct usb_endpoint_descriptor *endpoint;
|
||||
+ struct appleir *appleir = NULL;
|
||||
+ struct input_dev *input_dev;
|
||||
+ int retval = -ENOMEM;
|
||||
+ int i;
|
||||
+
|
||||
+ appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
|
||||
+ if (!appleir)
|
||||
+ goto allocfail;
|
||||
+
|
||||
+ appleir->data = usb_alloc_coherent(dev, URB_SIZE, GFP_KERNEL,
|
||||
+ &appleir->dma_buf);
|
||||
+ if (!appleir->data)
|
||||
+ goto usbfail;
|
||||
+
|
||||
+ appleir->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
+ if (!appleir->urb)
|
||||
+ goto urbfail;
|
||||
+
|
||||
+ appleir->usbdev = dev;
|
||||
+
|
||||
+ input_dev = input_allocate_device();
|
||||
+ if (!input_dev)
|
||||
+ goto inputfail;
|
||||
+
|
||||
+ appleir->input_dev = input_dev;
|
||||
+
|
||||
+ usb_make_path(dev, appleir->phys, sizeof(appleir->phys));
|
||||
+ strlcpy(appleir->phys, "/input0", sizeof(appleir->phys));
|
||||
+
|
||||
+ input_dev->name = "Apple Infrared Remote Controller";
|
||||
+ input_dev->phys = appleir->phys;
|
||||
+ usb_to_input_id(dev, &input_dev->id);
|
||||
+ input_dev->dev.parent = &intf->dev;
|
||||
+ input_dev->keycode = appleir->keymap;
|
||||
+ input_dev->keycodesize = sizeof(unsigned short);
|
||||
+ input_dev->keycodemax = ARRAY_SIZE(appleir->keymap);
|
||||
+
|
||||
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
+
|
||||
+ memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap));
|
||||
+ for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
|
||||
+ set_bit(appleir->keymap[i], input_dev->keybit);
|
||||
+ clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
+
|
||||
+ input_set_drvdata(input_dev, appleir);
|
||||
+ input_dev->open = appleir_open;
|
||||
+ input_dev->close = appleir_close;
|
||||
+
|
||||
+ endpoint = &intf->cur_altsetting->endpoint[0].desc;
|
||||
+
|
||||
+ usb_fill_int_urb(appleir->urb, dev,
|
||||
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
|
||||
+ appleir->data, 8,
|
||||
+ appleir_urb, appleir, endpoint->bInterval);
|
||||
+
|
||||
+ appleir->urb->transfer_dma = appleir->dma_buf;
|
||||
+ appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
+
|
||||
+ setup_timer(&appleir->key_up_timer,
|
||||
+ key_up_tick, (unsigned long) appleir);
|
||||
+
|
||||
+ retval = input_register_device(appleir->input_dev);
|
||||
+ if (retval)
|
||||
+ goto inputfail;
|
||||
+
|
||||
+ usb_set_intfdata(intf, appleir);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+inputfail:
|
||||
+ input_free_device(appleir->input_dev);
|
||||
+
|
||||
+urbfail:
|
||||
+ usb_free_urb(appleir->urb);
|
||||
+
|
||||
+usbfail:
|
||||
+ usb_free_coherent(dev, URB_SIZE, appleir->data,
|
||||
+ appleir->dma_buf);
|
||||
+
|
||||
+allocfail:
|
||||
+ kfree(appleir);
|
||||
+
|
||||
+ return retval;
|
||||
+}
|
||||
+
|
||||
+static void appleir_disconnect(struct usb_interface *intf)
|
||||
+{
|
||||
+ struct appleir *appleir = usb_get_intfdata(intf);
|
||||
+
|
||||
+ usb_set_intfdata(intf, NULL);
|
||||
+ input_unregister_device(appleir->input_dev);
|
||||
+ usb_free_urb(appleir->urb);
|
||||
+ usb_free_coherent(interface_to_usbdev(intf), URB_SIZE,
|
||||
+ appleir->data, appleir->dma_buf);
|
||||
+ kfree(appleir);
|
||||
+}
|
||||
+
|
||||
+static int appleir_suspend(struct usb_interface *interface,
|
||||
+ pm_message_t message)
|
||||
+{
|
||||
+ struct appleir *appleir = usb_get_intfdata(interface);
|
||||
+
|
||||
+ mutex_lock(&appleir_mutex);
|
||||
+ if (appleir->flags & APPLEIR_OPENED)
|
||||
+ usb_kill_urb(appleir->urb);
|
||||
+
|
||||
+ appleir->flags |= APPLEIR_SUSPENDED;
|
||||
+
|
||||
+ mutex_unlock(&appleir_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int appleir_resume(struct usb_interface *interface)
|
||||
+{
|
||||
+ struct appleir *appleir;
|
||||
+ int r = 0;
|
||||
+
|
||||
+ appleir = usb_get_intfdata(interface);
|
||||
+
|
||||
+ mutex_lock(&appleir_mutex);
|
||||
+ if (appleir->flags & APPLEIR_OPENED) {
|
||||
+ struct usb_endpoint_descriptor *endpoint;
|
||||
+
|
||||
+ endpoint = &interface->cur_altsetting->endpoint[0].desc;
|
||||
+ usb_fill_int_urb(appleir->urb, appleir->usbdev,
|
||||
+ usb_rcvintpipe(appleir->usbdev, endpoint->bEndpointAddress),
|
||||
+ appleir->data, 8,
|
||||
+ appleir_urb, appleir, endpoint->bInterval);
|
||||
+ appleir->urb->transfer_dma = appleir->dma_buf;
|
||||
+ appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
+
|
||||
+ /* And reset the USB device */
|
||||
+ if (usb_submit_urb(appleir->urb, GFP_ATOMIC))
|
||||
+ r = -EIO;
|
||||
+ }
|
||||
+
|
||||
+ appleir->flags &= ~APPLEIR_SUSPENDED;
|
||||
+
|
||||
+ mutex_unlock(&appleir_mutex);
|
||||
+
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+static struct usb_driver appleir_driver = {
|
||||
+ .name = "appleir",
|
||||
+ .probe = appleir_probe,
|
||||
+ .disconnect = appleir_disconnect,
|
||||
+ .suspend = appleir_suspend,
|
||||
+ .resume = appleir_resume,
|
||||
+ .reset_resume = appleir_resume,
|
||||
+ .id_table = appleir_ids,
|
||||
+};
|
||||
+
|
||||
+static int __init appleir_init(void)
|
||||
+{
|
||||
+ return usb_register(&appleir_driver);
|
||||
+}
|
||||
+
|
||||
+static void __exit appleir_exit(void)
|
||||
+{
|
||||
+ usb_deregister(&appleir_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(appleir_init);
|
||||
+module_exit(appleir_exit);
|
||||
--
|
||||
1.7.2.2
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
From: Eric W. Biederman <ebiederm@xmission.com>
|
||||
Date: Sun, 13 Jun 2010 03:31:06 +0000 (+0000)
|
||||
Subject: af_netlink: Add needed scm_destroy after scm_send.
|
||||
X-Git-Tag: v2.6.36-rc1~571^2~552
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=b47030c71dfd6c8cd5cb6e551b6f7f7cfc96f6a6
|
||||
|
||||
af_netlink: Add needed scm_destroy after scm_send.
|
||||
|
||||
scm_send occasionally allocates state in the scm_cookie, so I have
|
||||
modified netlink_sendmsg to guarantee that when scm_send succeeds
|
||||
scm_destory will be called to free that state.
|
||||
|
||||
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
|
||||
Reviewed-by: Daniel Lezcano <daniel.lezcano@free.fr>
|
||||
Acked-by: Pavel Emelyanov <xemul@openvz.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
|
||||
index a2eb965..7aeaa83 100644
|
||||
--- a/net/netlink/af_netlink.c
|
||||
+++ b/net/netlink/af_netlink.c
|
||||
@@ -1323,19 +1323,23 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
|
||||
if (msg->msg_flags&MSG_OOB)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
- if (NULL == siocb->scm)
|
||||
+ if (NULL == siocb->scm) {
|
||||
siocb->scm = &scm;
|
||||
+ memset(&scm, 0, sizeof(scm));
|
||||
+ }
|
||||
err = scm_send(sock, msg, siocb->scm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (msg->msg_namelen) {
|
||||
+ err = -EINVAL;
|
||||
if (addr->nl_family != AF_NETLINK)
|
||||
- return -EINVAL;
|
||||
+ goto out;
|
||||
dst_pid = addr->nl_pid;
|
||||
dst_group = ffs(addr->nl_groups);
|
||||
+ err = -EPERM;
|
||||
if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND))
|
||||
- return -EPERM;
|
||||
+ goto out;
|
||||
} else {
|
||||
dst_pid = nlk->dst_pid;
|
||||
dst_group = nlk->dst_group;
|
||||
@@ -1387,6 +1391,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
|
||||
err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT);
|
||||
|
||||
out:
|
||||
+ scm_destroy(siocb->scm);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
From f4680d3db71f13d2764340a9880745bf54f2469d Mon Sep 17 00:00:00 2001
|
||||
From: Arnaud Ebalard <arno@natisbad.org>
|
||||
Date: Wed, 15 Dec 2010 12:16:30 +0000
|
||||
Subject: [PATCH] asix: add USB ID for Logitec LAN-GTJ U2A
|
||||
|
||||
Logitec LAN-GTJ U2A (http://www.pro.logitec.co.jp/pro/g/gLAN-GTJU2A/)
|
||||
USB 2.0 10/10/1000 Ethernet adapter is based on ASIX AX88178 chipset.
|
||||
|
||||
This patch adds missing USB ID for the device.
|
||||
|
||||
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/usb/asix.c | 4 ++++
|
||||
1 files changed, 4 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
|
||||
index aea4645..6140b56 100644
|
||||
--- a/drivers/net/usb/asix.c
|
||||
+++ b/drivers/net/usb/asix.c
|
||||
@@ -1508,6 +1508,10 @@ static const struct usb_device_id products [] = {
|
||||
USB_DEVICE (0x0b95, 0x1780),
|
||||
.driver_info = (unsigned long) &ax88178_info,
|
||||
}, {
|
||||
+ // Logitec LAN-GTJ/U2A
|
||||
+ USB_DEVICE (0x0789, 0x0160),
|
||||
+ .driver_info = (unsigned long) &ax88178_info,
|
||||
+}, {
|
||||
// Linksys USB200M Rev 2
|
||||
USB_DEVICE (0x13b1, 0x0018),
|
||||
.driver_info = (unsigned long) &ax88772_info,
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
From 338d0f0a6fbc82407864606f5b64b75aeb3c70f2 Mon Sep 17 00:00:00 2001
|
||||
From: Timo Warns <Warns@pre-sense.de>
|
||||
Date: Wed, 17 Aug 2011 17:59:56 +0200
|
||||
Subject: [PATCH] befs: Validate length of long symbolic links.
|
||||
|
||||
Signed-off-by: Timo Warns <warns@pre-sense.de>
|
||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
---
|
||||
fs/befs/linuxvfs.c | 23 ++++++++++++++---------
|
||||
1 files changed, 14 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
|
||||
index 54b8c28..720d885 100644
|
||||
--- a/fs/befs/linuxvfs.c
|
||||
+++ b/fs/befs/linuxvfs.c
|
||||
@@ -474,17 +474,22 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
befs_data_stream *data = &befs_ino->i_data.ds;
|
||||
befs_off_t len = data->size;
|
||||
|
||||
- befs_debug(sb, "Follow long symlink");
|
||||
-
|
||||
- link = kmalloc(len, GFP_NOFS);
|
||||
- if (!link) {
|
||||
- link = ERR_PTR(-ENOMEM);
|
||||
- } else if (befs_read_lsymlink(sb, data, link, len) != len) {
|
||||
- kfree(link);
|
||||
- befs_error(sb, "Failed to read entire long symlink");
|
||||
+ if (len == 0) {
|
||||
+ befs_error(sb, "Long symlink with illegal length");
|
||||
link = ERR_PTR(-EIO);
|
||||
} else {
|
||||
- link[len - 1] = '\0';
|
||||
+ befs_debug(sb, "Follow long symlink");
|
||||
+
|
||||
+ link = kmalloc(len, GFP_NOFS);
|
||||
+ if (!link) {
|
||||
+ link = ERR_PTR(-ENOMEM);
|
||||
+ } else if (befs_read_lsymlink(sb, data, link, len) != len) {
|
||||
+ kfree(link);
|
||||
+ befs_error(sb, "Failed to read entire long symlink");
|
||||
+ link = ERR_PTR(-EIO);
|
||||
+ } else {
|
||||
+ link[len - 1] = '\0';
|
||||
+ }
|
||||
}
|
||||
} else {
|
||||
link = befs_ino->i_data.symlink;
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
From: Xiaotian Feng <dfeng@redhat.com>
|
||||
Date: Mon, 29 Nov 2010 09:03:55 +0000 (+0100)
|
||||
Subject: block: check for proper length of iov entries earlier in blk_rq_map_user_iov()
|
||||
X-Git-Tag: v2.6.37-rc7~10^2~5
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=54787556
|
||||
|
||||
block: check for proper length of iov entries earlier in blk_rq_map_user_iov()
|
||||
|
||||
commit 9284bcf checks for proper length of iov entries in
|
||||
blk_rq_map_user_iov(). But if the map is unaligned, kernel
|
||||
will break out the loop without checking for the proper length.
|
||||
So we need to check the proper length before the unalign check.
|
||||
|
||||
Signed-off-by: Xiaotian Feng <dfeng@redhat.com>
|
||||
Cc: stable@kernel.org
|
||||
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
|
||||
---
|
||||
|
||||
diff --git a/block/blk-map.c b/block/blk-map.c
|
||||
index 5d5dbe4..e663ac2 100644
|
||||
--- a/block/blk-map.c
|
||||
+++ b/block/blk-map.c
|
||||
@@ -201,12 +201,13 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
|
||||
for (i = 0; i < iov_count; i++) {
|
||||
unsigned long uaddr = (unsigned long)iov[i].iov_base;
|
||||
|
||||
+ if (!iov[i].iov_len)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
if (uaddr & queue_dma_alignment(q)) {
|
||||
unaligned = 1;
|
||||
break;
|
||||
}
|
||||
- if (!iov[i].iov_len)
|
||||
- return -EINVAL;
|
||||
}
|
||||
|
||||
if (unaligned || (q->dma_pad_mask & len) || map_data)
|
|
@ -0,0 +1,32 @@
|
|||
From: Dan Rosenberg <drosenberg@vsecurity.com>
|
||||
Date: Fri, 24 Jun 2011 12:38:05 +0000 (-0400)
|
||||
Subject: Bluetooth: Prevent buffer overflow in l2cap config request
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fpadovan%2Fbluetooth-2.6.git;a=commitdiff_plain;h=7ac28817536797fd40e9646452183606f9e17f71
|
||||
|
||||
Bluetooth: Prevent buffer overflow in l2cap config request
|
||||
[ backport to 2.6.35 ]
|
||||
|
||||
A remote user can provide a small value for the command size field in
|
||||
the command header of an l2cap configuration request, resulting in an
|
||||
integer underflow when subtracting the size of the configuration request
|
||||
header. This results in copying a very large amount of data via
|
||||
memcpy() and destroying the kernel heap. Check for underflow.
|
||||
|
||||
Signed-off-by: Dan Rosenberg <drosenberg@vsecurity.com>
|
||||
Cc: stable <stable@kernel.org>
|
||||
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
|
||||
---
|
||||
|
||||
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
|
||||
index 56fdd91..7d8a66b 100644
|
||||
--- a/net/bluetooth/l2cap.c
|
||||
+++ b/net/bluetooth/l2cap.c
|
||||
@@ -2962,7 +2962,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
|
||||
|
||||
/* Reject if config buffer is too small. */
|
||||
len = cmd_len - sizeof(*req);
|
||||
- if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) {
|
||||
+ if (len < 0 || l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) {
|
||||
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
|
||||
l2cap_build_conf_rsp(sk, rsp,
|
||||
L2CAP_CONF_REJECT, flags), rsp);
|
|
@ -0,0 +1,42 @@
|
|||
bridge: Fix mglist corruption that leads to memory corruption
|
||||
|
||||
The list mp->mglist is used to indicate whether a multicast group
|
||||
is active on the bridge interface itself as opposed to one of the
|
||||
constituent interfaces in the bridge.
|
||||
|
||||
Unfortunately the operation that adds the mp->mglist node to the
|
||||
list neglected to check whether it has already been added. This
|
||||
leads to list corruption in the form of nodes pointing to itself.
|
||||
|
||||
Normally this would be quite obvious as it would cause an infinite
|
||||
loop when walking the list. However, as this list is never actually
|
||||
walked (which means that we don't really need it, I'll get rid of
|
||||
it in a subsequent patch), this instead is hidden until we perform
|
||||
a delete operation on the affected nodes.
|
||||
|
||||
As the same node may now be pointed to by more than one node, the
|
||||
delete operations can then cause modification of freed memory.
|
||||
|
||||
This was observed in practice to cause corruption in 512-byte slabs,
|
||||
most commonly leading to crashes in jbd2.
|
||||
|
||||
Thanks to Josef Bacik for pointing me in the right direction.
|
||||
|
||||
Reported-by: Ian Page Hands <ihands@redhat.com>
|
||||
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
|
||||
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
|
||||
index f701a21..802d3f8 100644
|
||||
--- a/net/bridge/br_multicast.c
|
||||
+++ b/net/bridge/br_multicast.c
|
||||
@@ -719,7 +719,8 @@ static int br_multicast_add_group(struct net_bridge *br,
|
||||
goto err;
|
||||
|
||||
if (!port) {
|
||||
- hlist_add_head(&mp->mglist, &br->mglist);
|
||||
+ if (hlist_unhashed(&mp->mglist))
|
||||
+ hlist_add_head(&mp->mglist, &br->mglist);
|
||||
mod_timer(&mp->timer, now + br->multicast_membership_interval);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
From 8f172904b45a6b530eaa345b23956682629bddee Mon Sep 17 00:00:00 2001
|
||||
From: Josef Bacik <josef@redhat.com>
|
||||
Date: Fri, 22 Oct 2010 15:26:53 -0400
|
||||
Subject: Btrfs: fix error handling in btrfs_get_sb
|
||||
|
||||
If we failed to find the root subvol id, or the subvol=<name>, we would
|
||||
deactivate the locked super and close the devices. The problem is at this point
|
||||
we have gotten the SB all setup, which includes setting super_operations, so
|
||||
when we'd deactiveate the super, we'd do a close_ctree() which closes the
|
||||
devices, so we'd end up closing the devices twice. So if you do something like
|
||||
this
|
||||
|
||||
mount /dev/sda1 /mnt/test1
|
||||
mount /dev/sda1 /mnt/test2 -o subvol=xxx
|
||||
umount /mnt/test1
|
||||
|
||||
it would blow up (if subvol xxx doesn't exist). This patch fixes that problem.
|
||||
Thanks,
|
||||
|
||||
Signed-off-by: Josef Bacik <josef@redhat.com>
|
||||
---
|
||||
fs/btrfs/super.c | 7 +++----
|
||||
1 files changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
|
||||
index f2393b3..c246f25 100644
|
||||
--- a/fs/btrfs/super.c
|
||||
+++ b/fs/btrfs/super.c
|
||||
@@ -629,7 +629,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
if (IS_ERR(root)) {
|
||||
error = PTR_ERR(root);
|
||||
deactivate_locked_super(s);
|
||||
- goto error;
|
||||
+ goto error_free_subvol_name;
|
||||
}
|
||||
/* if they gave us a subvolume name bind mount into that */
|
||||
if (strcmp(subvol_name, ".")) {
|
||||
@@ -643,14 +643,14 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
deactivate_locked_super(s);
|
||||
error = PTR_ERR(new_root);
|
||||
dput(root);
|
||||
- goto error_close_devices;
|
||||
+ goto error_free_subvol_name;
|
||||
}
|
||||
if (!new_root->d_inode) {
|
||||
dput(root);
|
||||
dput(new_root);
|
||||
deactivate_locked_super(s);
|
||||
error = -ENXIO;
|
||||
- goto error_close_devices;
|
||||
+ goto error_free_subvol_name;
|
||||
}
|
||||
dput(root);
|
||||
root = new_root;
|
||||
@@ -668,7 +668,6 @@ error_close_devices:
|
||||
btrfs_close_devices(fs_devices);
|
||||
error_free_subvol_name:
|
||||
kfree(subvol_name);
|
||||
-error:
|
||||
return error;
|
||||
}
|
||||
|
||||
--
|
||||
1.7.3.3
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
From 3d07b06c5d62e98b46ef21980e5c2a904990149f Mon Sep 17 00:00:00 2001
|
||||
From: Kyle McMartin <kyle@mcmartin.ca>
|
||||
Date: Fri, 10 Dec 2010 10:32:29 -0500
|
||||
Subject: [PATCH] Btrfs - fix race between btrfs_get_sb() and umount
|
||||
|
||||
When mounting a btrfs file system btrfs_test_super() may attempt to
|
||||
use sb->s_fs_info, the btrfs root, of a super block that is going away
|
||||
and that has had the btrfs root set to NULL in its ->put_super(). But
|
||||
if the super block is going away it cannot be an existing super block
|
||||
so we can return false in this case.
|
||||
|
||||
Signed-off-by: Ian Kent <raven@themaw.net>
|
||||
Signed-off-by: Chris Mason <chris.mason@oracle.com>
|
||||
|
||||
Conflicts:
|
||||
|
||||
fs/btrfs/super.c
|
||||
---
|
||||
fs/btrfs/super.c | 6 ++++++
|
||||
1 files changed, 6 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
|
||||
index 89e299f..f4a4dd3 100644
|
||||
--- a/fs/btrfs/super.c
|
||||
+++ b/fs/btrfs/super.c
|
||||
@@ -551,6 +551,12 @@ static int btrfs_test_super(struct super_block *s, void *data)
|
||||
struct btrfs_root *test_root = data;
|
||||
struct btrfs_root *root = btrfs_sb(s);
|
||||
|
||||
+ /*
|
||||
+ * If this super block is going away, return false as it
|
||||
+ * can't match as an existing super block.
|
||||
+ */
|
||||
+ if (!atomic_read(&s->s_active))
|
||||
+ return 0;
|
||||
return root->fs_info->fs_devices == test_root->fs_info->fs_devices;
|
||||
}
|
||||
|
||||
--
|
||||
1.7.3.3
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
From: Josef Bacik <josef@redhat.com>
|
||||
Date: Mon, 22 Nov 2010 18:50:32 +0000 (+0000)
|
||||
Subject: Btrfs: fix typo in fallocate to make it honor actual size
|
||||
X-Git-Tag: v2.6.37-rc4~6^2~7
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=55a61d1d06a3dc443d0db8aaa613365dcb83b98a
|
||||
|
||||
Btrfs: fix typo in fallocate to make it honor actual size
|
||||
|
||||
[ Trivial backport to 2.6.35/2.6.36 ]
|
||||
|
||||
There is a typo in __btrfs_prealloc_file_range() where we set the i_size to
|
||||
actual_len/cur_offset, and then just set it to cur_offset again, and do the same
|
||||
with btrfs_ordered_update_i_size(). This fixes it back to keeping i_size in a
|
||||
local variable and then updating i_size properly. Tested this with
|
||||
|
||||
xfs_io -F -f -c "falloc 0 1" -c "pwrite 0 1" foo
|
||||
|
||||
stat'ing foo gives us a size of 1 instead of 4096 like it was. Thanks,
|
||||
|
||||
Signed-off-by: Josef Bacik <josef@redhat.com>
|
||||
Signed-off-by: Chris Mason <chris.mason@oracle.com>
|
||||
---
|
||||
|
||||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
|
||||
index 37cc177..0058fb3 100644
|
||||
--- a/fs/btrfs/inode.c
|
||||
+++ b/fs/btrfs/inode.c
|
||||
@@ -7002,6 +7002,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_key ins;
|
||||
u64 cur_offset = start;
|
||||
+ u64 i_size;
|
||||
int ret = 0;
|
||||
|
||||
while (num_bytes > 0) {
|
||||
@@ -7043,11 +7044,11 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
|
||||
(actual_len > inode->i_size) &&
|
||||
(cur_offset > inode->i_size)) {
|
||||
if (cur_offset > actual_len)
|
||||
- i_size_write(inode, actual_len);
|
||||
+ i_size = actual_len;
|
||||
else
|
||||
- i_size_write(inode, cur_offset);
|
||||
- i_size_write(inode, cur_offset);
|
||||
- btrfs_ordered_update_i_size(inode, cur_offset, NULL);
|
||||
+ i_size = cur_offset;
|
||||
+ i_size_write(inode, i_size);
|
||||
+ btrfs_ordered_update_i_size(inode, i_size, NULL);
|
||||
}
|
||||
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
|
@ -0,0 +1,117 @@
|
|||
From 2049a8887f699650cd66c3da220e84d5c140c546 Mon Sep 17 00:00:00 2001
|
||||
From: Kyle McMartin <kyle@mcmartin.ca>
|
||||
Date: Fri, 10 Dec 2010 10:09:15 -0500
|
||||
Subject: [PATCH] Btrfs: setup blank root and fs_info for mount time
|
||||
|
||||
There is a problem with how we use sget, it searches through the list of supers
|
||||
attached to the fs_type looking for a super with the same fs_devices as what
|
||||
we're trying to mount. This depends on sb->s_fs_info being filled, but we don't
|
||||
fill that in until we get to btrfs_fill_super, so we could hit supers on the
|
||||
fs_type super list that have a null s_fs_info. In order to fix that we need to
|
||||
go ahead and setup a blank root with a blank fs_info to hold fs_devices, that
|
||||
way our test will work out right and then we can set s_fs_info in
|
||||
btrfs_set_super, and then open_ctree will simply use our pre-allocated root and
|
||||
fs_info when setting everything up. Thanks,
|
||||
|
||||
Signed-off-by: Josef Bacik <josef@redhat.com>
|
||||
Signed-off-by: Chris Mason <chris.mason@oracle.com>
|
||||
|
||||
Conflicts:
|
||||
|
||||
fs/btrfs/super.c
|
||||
---
|
||||
fs/btrfs/disk-io.c | 6 ++----
|
||||
fs/btrfs/super.c | 34 +++++++++++++++++++++++++++++++---
|
||||
2 files changed, 33 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
|
||||
index 34f7c37..b6c3dad 100644
|
||||
--- a/fs/btrfs/disk-io.c
|
||||
+++ b/fs/btrfs/disk-io.c
|
||||
@@ -1539,10 +1539,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
GFP_NOFS);
|
||||
struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root),
|
||||
GFP_NOFS);
|
||||
- struct btrfs_root *tree_root = kzalloc(sizeof(struct btrfs_root),
|
||||
- GFP_NOFS);
|
||||
- struct btrfs_fs_info *fs_info = kzalloc(sizeof(*fs_info),
|
||||
- GFP_NOFS);
|
||||
+ struct btrfs_root *tree_root = btrfs_sb(sb);
|
||||
+ struct btrfs_fs_info *fs_info = tree_root->fs_info;
|
||||
struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
|
||||
GFP_NOFS);
|
||||
struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
|
||||
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
|
||||
index f2393b3..89e299f 100644
|
||||
--- a/fs/btrfs/super.c
|
||||
+++ b/fs/btrfs/super.c
|
||||
@@ -548,12 +548,20 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
||||
|
||||
static int btrfs_test_super(struct super_block *s, void *data)
|
||||
{
|
||||
- struct btrfs_fs_devices *test_fs_devices = data;
|
||||
+ struct btrfs_root *test_root = data;
|
||||
struct btrfs_root *root = btrfs_sb(s);
|
||||
|
||||
- return root->fs_info->fs_devices == test_fs_devices;
|
||||
+ return root->fs_info->fs_devices == test_root->fs_info->fs_devices;
|
||||
}
|
||||
|
||||
+static int btrfs_set_super(struct super_block *s, void *data)
|
||||
+{
|
||||
+ s->s_fs_info = data;
|
||||
+
|
||||
+ return set_anon_super(s, data);
|
||||
+}
|
||||
+
|
||||
+
|
||||
/*
|
||||
* Find a superblock for the given device / mount point.
|
||||
*
|
||||
@@ -567,6 +575,8 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
struct super_block *s;
|
||||
struct dentry *root;
|
||||
struct btrfs_fs_devices *fs_devices = NULL;
|
||||
+ struct btrfs_root *tree_root = NULL;
|
||||
+ struct btrfs_fs_info *fs_info = NULL;
|
||||
fmode_t mode = FMODE_READ;
|
||||
char *subvol_name = NULL;
|
||||
u64 subvol_objectid = 0;
|
||||
@@ -595,8 +605,24 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
goto error_close_devices;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * Setup a dummy root and fs_info for test/set super. This is because
|
||||
+ * we don't actually fill this stuff out until open_ctree, but we need
|
||||
+ * it for searching for existing supers, so this lets us do that and
|
||||
+ * then open_ctree will properly initialize everything later.
|
||||
+ */
|
||||
+ fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS);
|
||||
+ tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
|
||||
+ if (!fs_info || !tree_root) {
|
||||
+ error = -ENOMEM;
|
||||
+ goto error_close_devices;
|
||||
+ }
|
||||
+ fs_info->tree_root = tree_root;
|
||||
+ fs_info->fs_devices = fs_devices;
|
||||
+ tree_root->fs_info = fs_info;
|
||||
+
|
||||
bdev = fs_devices->latest_bdev;
|
||||
- s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices);
|
||||
+ s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root);
|
||||
if (IS_ERR(s))
|
||||
goto error_s;
|
||||
|
||||
@@ -666,6 +692,8 @@ error_s:
|
||||
error = PTR_ERR(s);
|
||||
error_close_devices:
|
||||
btrfs_close_devices(fs_devices);
|
||||
+ kfree(fs_info);
|
||||
+ kfree(tree_root);
|
||||
error_free_subvol_name:
|
||||
kfree(subvol_name);
|
||||
error:
|
||||
--
|
||||
1.7.3.3
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
Path: news.gmane.org!not-for-mail
|
||||
From: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
|
||||
Newsgroups: gmane.linux.kernel.cifs
|
||||
Subject: [PATCH] cifs: fix possible memory corruption in CIFSFindNext
|
||||
Date: Tue, 23 Aug 2011 07:21:28 -0400
|
||||
Lines: 37
|
||||
Approved: news@gmane.org
|
||||
Message-ID: <1314098488-1547-1-git-send-email-jlayton@redhat.com>
|
||||
NNTP-Posting-Host: lo.gmane.org
|
||||
X-Trace: dough.gmane.org 1314098501 27164 80.91.229.12 (23 Aug 2011 11:21:41 GMT)
|
||||
X-Complaints-To: usenet@dough.gmane.org
|
||||
NNTP-Posting-Date: Tue, 23 Aug 2011 11:21:41 +0000 (UTC)
|
||||
Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, dcl-HN4QTLPn1qTvY7RNz7mR4EEOCMrvLtNR@public.gmane.org
|
||||
To: smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
|
||||
Original-X-From: linux-cifs-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org Tue Aug 23 13:21:37 2011
|
||||
Return-path: <linux-cifs-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
|
||||
Envelope-to: glkc-linux-cifs-1dZseelyfdZg9hUCZPvPmw@public.gmane.org
|
||||
Original-Received: from vger.kernel.org ([209.132.180.67])
|
||||
by lo.gmane.org with esmtp (Exim 4.69)
|
||||
(envelope-from <linux-cifs-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>)
|
||||
id 1Qvp33-0003JC-05
|
||||
for glkc-linux-cifs-1dZseelyfdZg9hUCZPvPmw@public.gmane.org; Tue, 23 Aug 2011 13:21:37 +0200
|
||||
Original-Received: (majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org) by vger.kernel.org via listexpand
|
||||
id S1752435Ab1HWLVg (ORCPT <rfc822;glkc-linux-cifs@m.gmane.org>);
|
||||
Tue, 23 Aug 2011 07:21:36 -0400
|
||||
Original-Received: from mail-gy0-f174.google.com ([209.85.160.174]:43114 "EHLO
|
||||
mail-gy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S1751065Ab1HWLVf (ORCPT
|
||||
<rfc822;linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>); Tue, 23 Aug 2011 07:21:35 -0400
|
||||
Original-Received: by gya6 with SMTP id 6so4228912gya.19
|
||||
for <linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>; Tue, 23 Aug 2011 04:21:35 -0700 (PDT)
|
||||
Original-Received: by 10.101.144.18 with SMTP id w18mr3505731ann.133.1314098494691;
|
||||
Tue, 23 Aug 2011 04:21:34 -0700 (PDT)
|
||||
Original-Received: from salusa.poochiereds.net (cpe-075-177-182-191.nc.res.rr.com [75.177.182.191])
|
||||
by mx.google.com with ESMTPS id d33sm48355ano.35.2011.08.23.04.21.32
|
||||
(version=SSLv3 cipher=OTHER);
|
||||
Tue, 23 Aug 2011 04:21:33 -0700 (PDT)
|
||||
X-Mailer: git-send-email 1.7.6
|
||||
Original-Sender: linux-cifs-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
|
||||
Precedence: bulk
|
||||
List-ID: <linux-cifs.vger.kernel.org>
|
||||
X-Mailing-List: linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
|
||||
Xref: news.gmane.org gmane.linux.kernel.cifs:4006
|
||||
Archived-At: <http://permalink.gmane.org/gmane.linux.kernel.cifs/4006>
|
||||
|
||||
The name_len variable in CIFSFindNext is a signed int that gets set to
|
||||
the resume_name_len in the cifs_search_info. The resume_name_len however
|
||||
is unsigned and for some infolevels is populated directly from a 32 bit
|
||||
value sent by the server.
|
||||
|
||||
If the server sends a very large value for this, then that value could
|
||||
look negative when converted to a signed int. That would make that
|
||||
value pass the PATH_MAX check later in CIFSFindNext. The name_len would
|
||||
then be used as a length value for a memcpy. It would then be treated
|
||||
as unsigned again, and the memcpy scribbles over a ton of memory.
|
||||
|
||||
Fix this by making the name_len an unsigned value in CIFSFindNext.
|
||||
|
||||
Cc: <stable-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
|
||||
Reported-by: Darren Lavender <dcl-HN4QTLPn1qTvY7RNz7mR4EEOCMrvLtNR@public.gmane.org>
|
||||
Signed-off-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
|
||||
---
|
||||
fs/cifs/cifssmb.c | 3 ++-
|
||||
1 files changed, 2 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
|
||||
index f4d0988..950464d 100644
|
||||
--- a/fs/cifs/cifssmb.c
|
||||
+++ b/fs/cifs/cifssmb.c
|
||||
@@ -4089,7 +4089,8 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
|
||||
T2_FNEXT_RSP_PARMS *parms;
|
||||
char *response_data;
|
||||
int rc = 0;
|
||||
- int bytes_returned, name_len;
|
||||
+ int bytes_returned;
|
||||
+ unsigned int name_len;
|
||||
__u16 params, byte_count;
|
||||
|
||||
cFYI(1, "In FindNext");
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -87,5 +87,7 @@ CONFIG_PM_ADVANCED_DEBUG=y
|
|||
CONFIG_CEPH_FS_PRETTYDEBUG=y
|
||||
CONFIG_QUOTA_DEBUG=y
|
||||
|
||||
# CONFIG_PCI_DEFAULT_USE_CRS is not set
|
||||
|
||||
CONFIG_KGDB_KDB=y
|
||||
CONFIG_KDB_KEYBOARD=y
|
||||
|
|
|
@ -684,7 +684,7 @@ CONFIG_MD_RAID0=m
|
|||
CONFIG_MD_RAID1=m
|
||||
CONFIG_MD_RAID10=m
|
||||
CONFIG_MD_RAID456=m
|
||||
CONFIG_MULTICORE_RAID456=y
|
||||
# CONFIG_MULTICORE_RAID456 is not set
|
||||
CONFIG_ASYNC_RAID6_TEST=m
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
CONFIG_DM_CRYPT=m
|
||||
|
@ -1423,11 +1423,11 @@ CONFIG_ATMEL=m
|
|||
CONFIG_B43=m
|
||||
CONFIG_B43_PCMCIA=y
|
||||
CONFIG_B43_SDIO=y
|
||||
CONFIG_B43_DEBUG=y
|
||||
# CONFIG_B43_DEBUG is not set
|
||||
CONFIG_B43_PHY_LP=y
|
||||
# CONFIG_B43_FORCE_PIO is not set
|
||||
CONFIG_B43LEGACY=m
|
||||
CONFIG_B43LEGACY_DEBUG=y
|
||||
# CONFIG_B43LEGACY_DEBUG is not set
|
||||
CONFIG_B43LEGACY_DMA=y
|
||||
CONFIG_B43LEGACY_PIO=y
|
||||
CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y
|
||||
|
@ -2193,7 +2193,7 @@ CONFIG_WDTPCI=m
|
|||
# CONFIG_ACQUIRE_WDT is not set
|
||||
# CONFIG_ADVANTECH_WDT is not set
|
||||
# CONFIG_EUROTECH_WDT is not set
|
||||
# CONFIG_IB700_WDT is not set
|
||||
CONFIG_IB700_WDT=m
|
||||
# CONFIG_MIXCOMWD is not set
|
||||
# CONFIG_SCx200_WDT is not set
|
||||
# CONFIG_60XX_WDT is not set
|
||||
|
@ -2308,6 +2308,7 @@ CONFIG_DRM_NOUVEAU=m
|
|||
CONFIG_DRM_NOUVEAU_BACKLIGHT=y
|
||||
CONFIG_DRM_NOUVEAU_DEBUG=y
|
||||
CONFIG_DRM_I2C_CH7006=m
|
||||
CONFIG_DRM_I2C_SIL164=m
|
||||
CONFIG_DRM_VMWGFX=m
|
||||
|
||||
#
|
||||
|
@ -2366,6 +2367,7 @@ CONFIG_VIDEO_EM28XX_DVB=m
|
|||
CONFIG_VIDEO_CX231XX=m
|
||||
CONFIG_VIDEO_CX231XX_ALSA=m
|
||||
CONFIG_VIDEO_CX231XX_DVB=m
|
||||
CONFIG_VIDEO_CX231XX_RC=y
|
||||
CONFIG_VIDEO_HEXIUM_ORION=m
|
||||
CONFIG_VIDEO_HEXIUM_GEMINI=m
|
||||
CONFIG_VIDEO_IVTV=m
|
||||
|
@ -2380,6 +2382,7 @@ CONFIG_VIDEO_SAA6588=m
|
|||
CONFIG_VIDEO_SAA7134=m
|
||||
CONFIG_VIDEO_SAA7134_ALSA=m
|
||||
CONFIG_VIDEO_SAA7134_DVB=m
|
||||
CONFIG_VIDEO_SAA7134_RC=y
|
||||
CONFIG_VIDEO_STRADIS=m
|
||||
CONFIG_VIDEO_USBVISION=m
|
||||
CONFIG_VIDEO_W9966=m
|
||||
|
@ -2394,6 +2397,11 @@ CONFIG_VIDEO_ZORAN_ZR36060=m
|
|||
CONFIG_VIDEO_FB_IVTV=m
|
||||
CONFIG_VIDEO_SAA7164=m
|
||||
CONFIG_VIDEO_TLG2300=m
|
||||
# CONFIG_VIDEO_TIMBERDALE is not set
|
||||
CONFIG_VIDEO_SR030PC30=m
|
||||
# Doesn't build on 2.6.35
|
||||
# CONFIG_VIDEO_VIA_CAMERA is not set
|
||||
# CONFIG_VIDEO_NOON010PC30 is not set
|
||||
|
||||
CONFIG_USB_VIDEO_CLASS=m
|
||||
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
|
||||
|
@ -2409,6 +2417,7 @@ CONFIG_MEDIA_ATTACH=y
|
|||
CONFIG_MEDIA_TUNER_CUSTOMISE=y
|
||||
CONFIG_MEDIA_TUNER_SIMPLE=m
|
||||
CONFIG_MEDIA_TUNER_TDA8290=m
|
||||
CONFIG_MEDIA_TUNER_TDA18218=m
|
||||
CONFIG_MEDIA_TUNER_TEA5761=m
|
||||
CONFIG_MEDIA_TUNER_TEA5767=m
|
||||
CONFIG_MEDIA_TUNER_MT20XX=m
|
||||
|
@ -2491,6 +2500,10 @@ CONFIG_DVB_ATBM8830=m
|
|||
CONFIG_DVB_TDA665x=m
|
||||
CONFIG_DVB_STV0299=m
|
||||
CONFIG_DVB_MB86A16=m
|
||||
CONFIG_DVB_USB_LME2510=m
|
||||
CONFIG_DVB_S5H1432=m
|
||||
CONFIG_DVB_MB86A20S=m
|
||||
CONFIG_DVB_IX2505V=m
|
||||
|
||||
#
|
||||
# Supported Frontend Modules
|
||||
|
@ -2517,6 +2530,7 @@ CONFIG_DVB_LGS8GL5=m
|
|||
CONFIG_DVB_DUMMY_FE=m
|
||||
CONFIG_DVB_FIREDTV=m
|
||||
CONFIG_DVB_NGENE=m
|
||||
# CONFIG_DVB_CXD2099 is not set
|
||||
|
||||
#
|
||||
# Supported SAA7146 based PCI Adapters
|
||||
|
@ -2571,6 +2585,8 @@ CONFIG_DVB_PT1=m
|
|||
CONFIG_MANTIS_CORE=m
|
||||
CONFIG_DVB_MANTIS=m
|
||||
CONFIG_DVB_HOPPER=m
|
||||
CONFIG_DVB_USB_TECHNISAT_USB2=m
|
||||
CONFIG_DVB_DIB9000=m
|
||||
|
||||
CONFIG_VIDEO_SAA7146=m
|
||||
CONFIG_VIDEO_SAA7146_VV=m
|
||||
|
@ -2581,14 +2597,22 @@ CONFIG_VIDEO_PVRUSB2_SYSFS=y
|
|||
# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
|
||||
|
||||
CONFIG_RC_MAP=m
|
||||
CONFIG_RC_CORE=m
|
||||
CONFIG_IR_NEC_DECODER=m
|
||||
CONFIG_IR_RC5_DECODER=m
|
||||
CONFIG_IR_RC6_DECODER=m
|
||||
CONFIG_IR_JVC_DECODER=m
|
||||
CONFIG_IR_SONY_DECODER=m
|
||||
CONFIG_IR_RC5_SZ_DECODER=m
|
||||
CONFIG_IR_LIRC_CODEC=m
|
||||
CONFIG_IR_ENE=m
|
||||
CONFIG_IR_IMON=m
|
||||
CONFIG_IR_ITE_CIR=m
|
||||
CONFIG_IR_MCEUSB=m
|
||||
CONFIG_IR_NUVOTON=m
|
||||
CONFIG_IR_STREAMZAP=m
|
||||
CONFIG_IR_WINBOND_CIR=m
|
||||
CONFIG_RC_LOOPBACK=m
|
||||
|
||||
CONFIG_V4L_MEM2MEM_DRIVERS=y
|
||||
# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set
|
||||
|
@ -3031,6 +3055,8 @@ CONFIG_USB_GL860=m
|
|||
CONFIG_USB_GSPCA_JEILINJ=m
|
||||
CONFIG_USB_GSPCA_SPCA1528=m
|
||||
CONFIG_USB_GSPCA_SQ930X=m
|
||||
CONFIG_USB_GSPCA_KONICA=m
|
||||
CONFIG_USB_GSPCA_XIRLINK_CIT=m
|
||||
|
||||
CONFIG_USB_IBMCAM=m
|
||||
CONFIG_USB_KONICAWC=m
|
||||
|
@ -3038,6 +3064,7 @@ CONFIG_USB_KONICAWC=m
|
|||
CONFIG_USB_S2255=m
|
||||
CONFIG_USB_SE401=m
|
||||
# CONFIG_VIDEO_SH_MOBILE_CEU is not set
|
||||
# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set
|
||||
# CONFIG_USB_STV680 is not set
|
||||
# CONFIG_USB_SN9C102 is not set
|
||||
CONFIG_USB_ZR364XX=m
|
||||
|
@ -3052,6 +3079,9 @@ CONFIG_SOC_CAMERA_OV772X=m
|
|||
CONFIG_SOC_CAMERA_MT9T112=m
|
||||
CONFIG_SOC_CAMERA_RJ54N1=m
|
||||
CONFIG_SOC_CAMERA_OV9640=m
|
||||
CONFIG_SOC_CAMERA_IMX074=m
|
||||
CONFIG_SOC_CAMERA_OV6650=m
|
||||
CONFIG_SOC_CAMERA_OV2640=m
|
||||
|
||||
#
|
||||
# USB Network adaptors
|
||||
|
@ -3321,7 +3351,8 @@ CONFIG_QUOTACTL=y
|
|||
CONFIG_DNOTIFY=y
|
||||
# Autofsv3 is obsolete.
|
||||
# CONFIG_AUTOFS_FS is not set
|
||||
CONFIG_AUTOFS4_FS=m
|
||||
# systemd is dependant upon AUTOFS, so build it in.
|
||||
CONFIG_AUTOFS4_FS=y
|
||||
CONFIG_EXOFS_FS=m
|
||||
# CONFIG_EXOFS_DEBUG is not set
|
||||
CONFIG_NILFS2_FS=m
|
||||
|
@ -3601,6 +3632,7 @@ CONFIG_CRYPTO_FIPS=y
|
|||
CONFIG_CRYPTO_HW=y
|
||||
CONFIG_CRYPTO_BLKCIPHER=y
|
||||
CONFIG_CRYPTO_MANAGER=m
|
||||
CONFIG_CRYPTO_MANAGER_TESTS=y
|
||||
# CONFIG_CRYPTO_CRYPTD is not set
|
||||
CONFIG_CRYPTO_AES=m
|
||||
CONFIG_CRYPTO_ARC4=m
|
||||
|
@ -3722,7 +3754,7 @@ CONFIG_BLK_CGROUP=y
|
|||
# CONFIG_SYSFS_DEPRECATED_V2 is not set
|
||||
|
||||
CONFIG_RELAY=y
|
||||
# CONFIG_PRINTK_TIME is not set
|
||||
CONFIG_PRINTK_TIME=y
|
||||
|
||||
CONFIG_ENABLE_MUST_CHECK=y
|
||||
# CONFIG_ENABLE_WARN_DEPRECATED is not set
|
||||
|
@ -3742,7 +3774,7 @@ CONFIG_IBMASR=m
|
|||
CONFIG_PM_DEBUG=y
|
||||
CONFIG_PM_TRACE=y
|
||||
# CONFIG_PM_VERBOSE is not set
|
||||
CONFIG_PM_TEST_SUSPEND=y
|
||||
# CONFIG_PM_TEST_SUSPEND is not set
|
||||
CONFIG_PM_RUNTIME=y
|
||||
|
||||
## BEGIN ISA Junk.
|
||||
|
@ -3851,6 +3883,7 @@ CONFIG_RADIO_ADAPTERS=y
|
|||
# CONFIG_RADIO_TYPHOON is not set
|
||||
# CONFIG_RADIO_ZOLTRIX is not set
|
||||
# CONFIG_RADIO_SAA7706H is not set
|
||||
# CONFIG_RADIO_WL1273 is not set
|
||||
|
||||
# CONFIG_SND_OPL4_LIB is not set
|
||||
# CONFIG_SND_AD1816A is not set
|
||||
|
@ -3987,8 +4020,8 @@ CONFIG_AUXDISPLAY=y
|
|||
CONFIG_UIO=m
|
||||
CONFIG_UIO_CIF=m
|
||||
CONFIG_UIO_SMX=m
|
||||
CONFIG_UIO_PDRV=m
|
||||
CONFIG_UIO_PDRV_GENIRQ=m
|
||||
# CONFIG_UIO_PDRV is not set
|
||||
# CONFIG_UIO_PDRV_GENIRQ is not set
|
||||
CONFIG_UIO_AEC=m
|
||||
CONFIG_UIO_SERCOS3=m
|
||||
CONFIG_UIO_PCI_GENERIC=m
|
||||
|
@ -4000,20 +4033,16 @@ CONFIG_UIO_PCI_GENERIC=m
|
|||
# LIRC
|
||||
CONFIG_LIRC_STAGING=y
|
||||
CONFIG_LIRC_BT829=m
|
||||
CONFIG_LIRC_ENE0100=m
|
||||
CONFIG_LIRC_I2C=m
|
||||
CONFIG_LIRC_IGORPLUGUSB=m
|
||||
CONFIG_LIRC_IMON=m
|
||||
CONFIG_LIRC_IT87=m
|
||||
CONFIG_LIRC_ITE8709=m
|
||||
CONFIG_LIRC_MCEUSB=m
|
||||
CONFIG_LIRC_ZILOG=m
|
||||
CONFIG_LIRC_PARALLEL=m
|
||||
CONFIG_LIRC_SERIAL=m
|
||||
CONFIG_LIRC_SERIAL_TRANSMITTER=y
|
||||
CONFIG_LIRC_SASEM=m
|
||||
CONFIG_LIRC_SIR=m
|
||||
CONFIG_LIRC_STREAMZAP=m
|
||||
# CONFIG_LIRC_STREAMZAP is not set
|
||||
CONFIG_LIRC_TTUSBIR=m
|
||||
|
||||
# CONFIG_SAMPLES is not set
|
||||
|
@ -4175,7 +4204,7 @@ CONFIG_USB_ATMEL=m
|
|||
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
|
||||
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
|
||||
# CONFIG_FUNCTION_GRAPH_TRACER is not set
|
||||
CONFIG_BOOT_TRACER=y
|
||||
# CONFIG_BOOT_TRACER is not set
|
||||
CONFIG_EARLY_PRINTK_DBGP=y
|
||||
|
||||
CONFIG_SECURITYFS=y
|
||||
|
@ -4253,7 +4282,7 @@ CONFIG_DEBUG_NX_TEST=m
|
|||
CONFIG_DEBUG_BOOT_PARAMS=y
|
||||
CONFIG_DETECT_SOFTLOCKUP=y
|
||||
# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
# CONFIG_DETECT_HUNG_TASK is not set
|
||||
# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
|
||||
CONFIG_ATOMIC64_SELFTEST=y
|
||||
|
||||
|
@ -4269,7 +4298,7 @@ CONFIG_BLK_DEV_DRBD=m
|
|||
# CONFIG_DEBUG_GPIO is not set
|
||||
# CONFIG_W1_MASTER_GPIO is not set
|
||||
# CONFIG_LEDS_GPIO is not set
|
||||
# CONFIG_GPIO_SYSFS is not set
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
# CONFIG_GPIO_MAX732X is not set
|
||||
# CONFIG_GPIO_PCA953X is not set
|
||||
# CONFIG_GPIO_PCF857X is not set
|
||||
|
|
|
@ -3,3 +3,6 @@ CONFIG_HIGHMEM64G=y
|
|||
|
||||
CONFIG_XEN_DEV_EVTCHN=m
|
||||
CONFIG_XEN_SYS_HYPERVISOR=y
|
||||
|
||||
# I2O only works on non-PAE 32-bit x86
|
||||
# CONFIG_I2O is not set
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# This file is intentionally left empty in the stock kernel. Its a nicety
|
||||
# added for those wanting to do custom rebuilds with altered config opts.
|
|
@ -2,90 +2,92 @@ CONFIG_SND_VERBOSE_PRINTK=y
|
|||
CONFIG_SND_DEBUG=y
|
||||
CONFIG_SND_PCM_XRUN_DEBUG=y
|
||||
|
||||
CONFIG_DEBUG_MUTEXES=y
|
||||
CONFIG_DEBUG_RT_MUTEXES=y
|
||||
CONFIG_DEBUG_LOCK_ALLOC=y
|
||||
CONFIG_PROVE_LOCKING=y
|
||||
CONFIG_DEBUG_VM=y
|
||||
CONFIG_DEBUG_SPINLOCK=y
|
||||
CONFIG_PROVE_RCU=y
|
||||
# CONFIG_DEBUG_MUTEXES is not set
|
||||
# CONFIG_DEBUG_RT_MUTEXES is not set
|
||||
# CONFIG_DEBUG_LOCK_ALLOC is not set
|
||||
# CONFIG_PROVE_LOCKING is not set
|
||||
# CONFIG_DEBUG_VM is not set
|
||||
# CONFIG_DEBUG_SPINLOCK is not set
|
||||
# CONFIG_PROVE_RCU is not set
|
||||
# CONFIG_PROVE_RCU_REPEATEDLY is not set
|
||||
CONFIG_DEBUG_PER_CPU_MAPS=y
|
||||
# CONFIG_DEBUG_PER_CPU_MAPS is not set
|
||||
CONFIG_CPUMASK_OFFSTACK=y
|
||||
|
||||
CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
|
||||
# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
|
||||
|
||||
CONFIG_FAULT_INJECTION=y
|
||||
CONFIG_FAILSLAB=y
|
||||
CONFIG_FAIL_PAGE_ALLOC=y
|
||||
CONFIG_FAIL_MAKE_REQUEST=y
|
||||
CONFIG_FAULT_INJECTION_DEBUG_FS=y
|
||||
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
|
||||
CONFIG_FAIL_IO_TIMEOUT=y
|
||||
# CONFIG_FAULT_INJECTION is not set
|
||||
# CONFIG_FAILSLAB is not set
|
||||
# CONFIG_FAIL_PAGE_ALLOC is not set
|
||||
# CONFIG_FAIL_MAKE_REQUEST is not set
|
||||
# CONFIG_FAULT_INJECTION_DEBUG_FS is not set
|
||||
# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set
|
||||
# CONFIG_FAIL_IO_TIMEOUT is not set
|
||||
|
||||
CONFIG_SLUB_DEBUG_ON=y
|
||||
# CONFIG_SLUB_DEBUG_ON is not set
|
||||
|
||||
CONFIG_LOCK_STAT=y
|
||||
# CONFIG_LOCK_STAT is not set
|
||||
|
||||
CONFIG_DEBUG_STACK_USAGE=y
|
||||
# CONFIG_DEBUG_STACK_USAGE is not set
|
||||
|
||||
CONFIG_ACPI_DEBUG=y
|
||||
# CONFIG_ACPI_DEBUG is not set
|
||||
# CONFIG_ACPI_DEBUG_FUNC_TRACE is not set
|
||||
|
||||
CONFIG_DEBUG_SG=y
|
||||
# CONFIG_DEBUG_SG is not set
|
||||
|
||||
# CONFIG_DEBUG_PAGEALLOC is not set
|
||||
|
||||
CONFIG_DEBUG_WRITECOUNT=y
|
||||
CONFIG_DEBUG_OBJECTS=y
|
||||
# CONFIG_DEBUG_WRITECOUNT is not set
|
||||
# CONFIG_DEBUG_OBJECTS is not set
|
||||
# CONFIG_DEBUG_OBJECTS_SELFTEST is not set
|
||||
CONFIG_DEBUG_OBJECTS_FREE=y
|
||||
CONFIG_DEBUG_OBJECTS_TIMERS=y
|
||||
# CONFIG_DEBUG_OBJECTS_FREE is not set
|
||||
# CONFIG_DEBUG_OBJECTS_TIMERS is not set
|
||||
CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
|
||||
|
||||
CONFIG_X86_PTDUMP=y
|
||||
# CONFIG_X86_PTDUMP is not set
|
||||
|
||||
CONFIG_CAN_DEBUG_DEVICES=y
|
||||
# CONFIG_CAN_DEBUG_DEVICES is not set
|
||||
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
# CONFIG_MODULE_FORCE_UNLOAD is not set
|
||||
|
||||
CONFIG_SYSCTL_SYSCALL_CHECK=y
|
||||
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
|
||||
|
||||
CONFIG_DEBUG_NOTIFIERS=y
|
||||
# CONFIG_DEBUG_NOTIFIERS is not set
|
||||
|
||||
CONFIG_DMA_API_DEBUG=y
|
||||
# CONFIG_DMA_API_DEBUG is not set
|
||||
|
||||
CONFIG_MMIOTRACE=y
|
||||
# CONFIG_MMIOTRACE is not set
|
||||
|
||||
CONFIG_DEBUG_CREDENTIALS=y
|
||||
# CONFIG_DEBUG_CREDENTIALS is not set
|
||||
|
||||
# off in both production debug and nodebug builds,
|
||||
# on in rawhide nodebug builds
|
||||
CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
|
||||
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
|
||||
|
||||
CONFIG_EXT4_DEBUG=y
|
||||
# CONFIG_EXT4_DEBUG is not set
|
||||
|
||||
CONFIG_DEBUG_PERF_USE_VMALLOC=y
|
||||
# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
|
||||
|
||||
CONFIG_JBD2_DEBUG=y
|
||||
# CONFIG_JBD2_DEBUG is not set
|
||||
|
||||
CONFIG_DEBUG_CFQ_IOSCHED=y
|
||||
# CONFIG_DEBUG_CFQ_IOSCHED is not set
|
||||
|
||||
CONFIG_DRBD_FAULT_INJECTION=y
|
||||
# CONFIG_DRBD_FAULT_INJECTION is not set
|
||||
|
||||
CONFIG_ATH_DEBUG=y
|
||||
CONFIG_IWLWIFI_DEVICE_TRACING=y
|
||||
# CONFIG_ATH_DEBUG is not set
|
||||
# CONFIG_IWLWIFI_DEVICE_TRACING is not set
|
||||
|
||||
CONFIG_DEBUG_OBJECTS_WORK=y
|
||||
CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
|
||||
# CONFIG_DEBUG_OBJECTS_WORK is not set
|
||||
# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
|
||||
|
||||
CONFIG_DMADEVICES_DEBUG=y
|
||||
CONFIG_DMADEVICES_VDEBUG=y
|
||||
# CONFIG_DMADEVICES_DEBUG is not set
|
||||
# CONFIG_DMADEVICES_VDEBUG is not set
|
||||
|
||||
CONFIG_PM_ADVANCED_DEBUG=y
|
||||
|
||||
CONFIG_CEPH_FS_PRETTYDEBUG=y
|
||||
CONFIG_QUOTA_DEBUG=y
|
||||
# CONFIG_CEPH_FS_PRETTYDEBUG is not set
|
||||
# CONFIG_QUOTA_DEBUG is not set
|
||||
|
||||
# CONFIG_PCI_DEFAULT_USE_CRS is not set
|
||||
|
||||
CONFIG_KGDB_KDB=y
|
||||
CONFIG_KDB_KEYBOARD=y
|
||||
|
|
|
@ -200,4 +200,9 @@ CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m
|
|||
CONFIG_GRETH=m
|
||||
CONFIG_FB_XVR1000=y
|
||||
|
||||
CONFIG_CRYPTO_DEV_NIAGARA2=y
|
||||
CONFIG_CRYPTO_DEV_NIAGARA2=m
|
||||
|
||||
# Bellow is changes made to get the kernel building on sparc again, they need to have upstream fixes
|
||||
# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
|
||||
# CONFIG_ATA_OVER_ETH is not set
|
||||
# CONFIG_INFINIBAND is not set
|
||||
|
|
|
@ -37,7 +37,7 @@ CONFIG_M686=y
|
|||
# CONFIG_MCYRIXIII is not set
|
||||
# CONFIG_MVIAC3_2 is not set
|
||||
CONFIG_SMP=y
|
||||
CONFIG_NR_CPUS=32
|
||||
CONFIG_NR_CPUS=64
|
||||
CONFIG_X86_GENERIC=y
|
||||
# CONFIG_X86_PPRO_FENCE is not set
|
||||
CONFIG_HPET=y
|
||||
|
@ -100,6 +100,16 @@ CONFIG_SECCOMP=y
|
|||
|
||||
CONFIG_CAPI_EICON=y
|
||||
|
||||
# I2O enabled only for 32-bit x86, disabled for PAE kernel
|
||||
CONFIG_I2O=m
|
||||
CONFIG_I2O_BLOCK=m
|
||||
CONFIG_I2O_SCSI=m
|
||||
CONFIG_I2O_PROC=m
|
||||
CONFIG_I2O_CONFIG=y
|
||||
CONFIG_I2O_EXT_ADAPTEC=y
|
||||
CONFIG_I2O_CONFIG_OLD_IOCTL=y
|
||||
CONFIG_I2O_BUS=m
|
||||
|
||||
#
|
||||
# APM (Advanced Power Management) BIOS Support
|
||||
#
|
||||
|
@ -479,6 +489,8 @@ CONFIG_TOSHIBA_BT_RFKILL=m
|
|||
CONFIG_VGA_SWITCHEROO=y
|
||||
CONFIG_LPC_SCH=m
|
||||
|
||||
CONFIG_INTEL_IDLE=m
|
||||
CONFIG_INTEL_IDLE=y
|
||||
|
||||
CONFIG_PCI_CNB20LE_QUIRK=y
|
||||
|
||||
CONFIG_IRQ_TIME_ACCOUNTING=y
|
||||
|
|
|
@ -15,7 +15,7 @@ CONFIG_NUMA=y
|
|||
CONFIG_K8_NUMA=y
|
||||
CONFIG_X86_64_ACPI_NUMA=y
|
||||
# CONFIG_NUMA_EMU is not set
|
||||
CONFIG_NR_CPUS=512
|
||||
CONFIG_NR_CPUS=256
|
||||
CONFIG_X86_POWERNOW_K8=m
|
||||
CONFIG_X86_P4_CLOCKMOD=m
|
||||
CONFIG_IA32_EMULATION=y
|
||||
|
@ -403,7 +403,11 @@ CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m
|
|||
CONFIG_VGA_SWITCHEROO=y
|
||||
CONFIG_LPC_SCH=m
|
||||
|
||||
CONFIG_INTEL_IDLE=m
|
||||
CONFIG_INTEL_IDLE=y
|
||||
CONFIG_I7300_IDLE=m
|
||||
|
||||
CONFIG_PCI_CNB20LE_QUIRK=y
|
||||
|
||||
CONFIG_HP_ILO=m
|
||||
|
||||
CONFIG_IRQ_TIME_ACCOUNTING=y
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
From: Greg KH <gregkh@suse.de>
|
||||
Date: Thu, 5 Aug 2010 20:53:35 +0000 (-0700)
|
||||
Subject: cgroupfs: create /sys/fs/cgroup to mount cgroupfs on
|
||||
X-Git-Tag: v2.6.36-rc1~521^2~7
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=676db4af043014e852f67ba0349dae0071bd11f3
|
||||
|
||||
cgroupfs: create /sys/fs/cgroup to mount cgroupfs on
|
||||
|
||||
We really shouldn't be asking userspace to create new root filesystems.
|
||||
So follow along with all of the other in-kernel filesystems, and provide
|
||||
a mount point in sysfs.
|
||||
|
||||
For cgroupfs, this should be in /sys/fs/cgroup/ This change provides
|
||||
that mount point when the cgroup filesystem is registered in the kernel.
|
||||
|
||||
Acked-by: Paul Menage <menage@google.com>
|
||||
Acked-by: Dhaval Giani <dhaval.giani@gmail.com>
|
||||
Cc: Li Zefan <lizf@cn.fujitsu.com>
|
||||
Cc: Lennart Poettering <lennart@poettering.net>
|
||||
Cc: Kay Sievers <kay.sievers@vrfy.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
---
|
||||
|
||||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
|
||||
index a8ce099..d83cab0 100644
|
||||
--- a/kernel/cgroup.c
|
||||
+++ b/kernel/cgroup.c
|
||||
@@ -1623,6 +1623,8 @@ static struct file_system_type cgroup_fs_type = {
|
||||
.kill_sb = cgroup_kill_sb,
|
||||
};
|
||||
|
||||
+static struct kobject *cgroup_kobj;
|
||||
+
|
||||
static inline struct cgroup *__d_cgrp(struct dentry *dentry)
|
||||
{
|
||||
return dentry->d_fsdata;
|
||||
@@ -3894,9 +3896,18 @@ int __init cgroup_init(void)
|
||||
hhead = css_set_hash(init_css_set.subsys);
|
||||
hlist_add_head(&init_css_set.hlist, hhead);
|
||||
BUG_ON(!init_root_id(&rootnode));
|
||||
+
|
||||
+ cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj);
|
||||
+ if (!cgroup_kobj) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
err = register_filesystem(&cgroup_fs_type);
|
||||
- if (err < 0)
|
||||
+ if (err < 0) {
|
||||
+ kobject_put(cgroup_kobj);
|
||||
goto out;
|
||||
+ }
|
||||
|
||||
proc_create("cgroups", 0, NULL, &proc_cgroupstats_operations);
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
From 44c943562c2e204cddf46db131c53c326b47bd47 Mon Sep 17 00:00:00 2001
|
||||
From: "David S. Miller" <davem@davemloft.net>
|
||||
Date: Fri, 16 Sep 2011 17:10:29 -0400
|
||||
Subject: [PATCH 1/2] crypto: Move md5_transform to lib/md5.c
|
||||
|
||||
We are going to use this for TCP/IP sequence number and fragment ID
|
||||
generation.
|
||||
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
|
||||
Backported to 2.6.25.14 by Josh Boyer <jwboyer@redhat.com>
|
||||
---
|
||||
crypto/md5.c | 92 +------------------------------------------
|
||||
include/linux/cryptohash.h | 5 ++
|
||||
lib/Makefile | 2 +-
|
||||
lib/md5.c | 95 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 102 insertions(+), 92 deletions(-)
|
||||
create mode 100644 lib/md5.c
|
||||
|
||||
diff --git a/crypto/md5.c b/crypto/md5.c
|
||||
index 30efc7d..7febeaa 100644
|
||||
--- a/crypto/md5.c
|
||||
+++ b/crypto/md5.c
|
||||
@@ -21,99 +21,9 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
+#include <linux/cryptohash.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
-#define F2(x, y, z) F1(z, x, y)
|
||||
-#define F3(x, y, z) (x ^ y ^ z)
|
||||
-#define F4(x, y, z) (y ^ (x | ~z))
|
||||
-
|
||||
-#define MD5STEP(f, w, x, y, z, in, s) \
|
||||
- (w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)
|
||||
-
|
||||
-static void md5_transform(u32 *hash, u32 const *in)
|
||||
-{
|
||||
- u32 a, b, c, d;
|
||||
-
|
||||
- a = hash[0];
|
||||
- b = hash[1];
|
||||
- c = hash[2];
|
||||
- d = hash[3];
|
||||
-
|
||||
- MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||
- MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||
- MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||
- MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||
- MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||
- MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||
- MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||
- MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||
- MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||
- MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||
- MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
- MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
- MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
- MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
- MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
- MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
-
|
||||
- MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||
- MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||
- MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
- MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||
- MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||
- MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
- MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
- MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||
- MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||
- MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
- MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||
- MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||
- MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
- MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||
- MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||
- MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
-
|
||||
- MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||
- MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||
- MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
- MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
- MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||
- MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||
- MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||
- MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
- MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
- MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||
- MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||
- MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||
- MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||
- MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
- MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
- MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||
-
|
||||
- MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||
- MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||
- MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
- MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||
- MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
- MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||
- MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
- MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||
- MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||
- MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
- MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||
- MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
- MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||
- MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
- MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||
- MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||
-
|
||||
- hash[0] += a;
|
||||
- hash[1] += b;
|
||||
- hash[2] += c;
|
||||
- hash[3] += d;
|
||||
-}
|
||||
-
|
||||
/* XXX: this stuff can be optimized */
|
||||
static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
|
||||
{
|
||||
diff --git a/include/linux/cryptohash.h b/include/linux/cryptohash.h
|
||||
index ec78a4b..d2984fb 100644
|
||||
--- a/include/linux/cryptohash.h
|
||||
+++ b/include/linux/cryptohash.h
|
||||
@@ -8,6 +8,11 @@
|
||||
void sha_init(__u32 *buf);
|
||||
void sha_transform(__u32 *digest, const char *data, __u32 *W);
|
||||
|
||||
+#define MD5_DIGEST_WORDS 4
|
||||
+#define MD5_MESSAGE_BYTES 64
|
||||
+
|
||||
+void md5_transform(__u32 *hash, __u32 const *in);
|
||||
+
|
||||
__u32 half_md4_transform(__u32 buf[4], __u32 const in[8]);
|
||||
|
||||
#endif
|
||||
diff --git a/lib/Makefile b/lib/Makefile
|
||||
index 0bfabba..d07eef3 100644
|
||||
--- a/lib/Makefile
|
||||
+++ b/lib/Makefile
|
||||
@@ -10,7 +10,7 @@ endif
|
||||
lib-y := ctype.o string.o vsprintf.o cmdline.o \
|
||||
rbtree.o radix-tree.o dump_stack.o \
|
||||
idr.o int_sqrt.o extable.o prio_tree.o \
|
||||
- sha1.o irq_regs.o reciprocal_div.o argv_split.o \
|
||||
+ sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
|
||||
proportions.o prio_heap.o ratelimit.o show_mem.o \
|
||||
is_single_threaded.o plist.o decompress.o flex_array.o
|
||||
|
||||
diff --git a/lib/md5.c b/lib/md5.c
|
||||
new file mode 100644
|
||||
index 0000000..c777180
|
||||
--- /dev/null
|
||||
+++ b/lib/md5.c
|
||||
@@ -0,0 +1,95 @@
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/cryptohash.h>
|
||||
+
|
||||
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
+#define F2(x, y, z) F1(z, x, y)
|
||||
+#define F3(x, y, z) (x ^ y ^ z)
|
||||
+#define F4(x, y, z) (y ^ (x | ~z))
|
||||
+
|
||||
+#define MD5STEP(f, w, x, y, z, in, s) \
|
||||
+ (w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)
|
||||
+
|
||||
+void md5_transform(__u32 *hash, __u32 const *in)
|
||||
+{
|
||||
+ u32 a, b, c, d;
|
||||
+
|
||||
+ a = hash[0];
|
||||
+ b = hash[1];
|
||||
+ c = hash[2];
|
||||
+ d = hash[3];
|
||||
+
|
||||
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
+
|
||||
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
+
|
||||
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||
+
|
||||
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||
+
|
||||
+ hash[0] += a;
|
||||
+ hash[1] += b;
|
||||
+ hash[2] += c;
|
||||
+ hash[3] += d;
|
||||
+}
|
||||
+EXPORT_SYMBOL(md5_transform);
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
From 3e65dd9e26cf5ba791f44c5e15e29d07b84824aa Mon Sep 17 00:00:00 2001
|
||||
From: Nick Bowler <nbowler@elliptictech.com>
|
||||
Date: Thu, 20 Oct 2011 14:16:55 +0200
|
||||
Subject: [PATCH] crypto: ghash - Avoid null pointer dereference if no key is
|
||||
set
|
||||
|
||||
commit 7ed47b7d142ec99ad6880bbbec51e9f12b3af74c upstream.
|
||||
|
||||
The ghash_update function passes a pointer to gf128mul_4k_lle which will
|
||||
be NULL if ghash_setkey is not called or if the most recent call to
|
||||
ghash_setkey failed to allocate memory. This causes an oops. Fix this
|
||||
up by returning an error code in the null case.
|
||||
|
||||
This is trivially triggered from unprivileged userspace through the
|
||||
AF_ALG interface by simply writing to the socket without setting a key.
|
||||
|
||||
The ghash_final function has a similar issue, but triggering it requires
|
||||
a memory allocation failure in ghash_setkey _after_ at least one
|
||||
successful call to ghash_update.
|
||||
|
||||
BUG: unable to handle kernel NULL pointer dereference at 00000670
|
||||
IP: [<d88c92d4>] gf128mul_4k_lle+0x23/0x60 [gf128mul]
|
||||
*pde = 00000000
|
||||
Oops: 0000 [#1] PREEMPT SMP
|
||||
Modules linked in: ghash_generic gf128mul algif_hash af_alg nfs lockd nfs_acl sunrpc bridge ipv6 stp llc
|
||||
|
||||
Pid: 1502, comm: hashatron Tainted: G W 3.1.0-rc9-00085-ge9308cf #32 Bochs Bochs
|
||||
EIP: 0060:[<d88c92d4>] EFLAGS: 00000202 CPU: 0
|
||||
EIP is at gf128mul_4k_lle+0x23/0x60 [gf128mul]
|
||||
EAX: d69db1f0 EBX: d6b8ddac ECX: 00000004 EDX: 00000000
|
||||
ESI: 00000670 EDI: d6b8ddac EBP: d6b8ddc8 ESP: d6b8dda4
|
||||
DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
|
||||
Process hashatron (pid: 1502, ti=d6b8c000 task=d6810000 task.ti=d6b8c000)
|
||||
Stack:
|
||||
00000000 d69db1f0 00000163 00000000 d6b8ddc8 c101a520 d69db1f0 d52aa000
|
||||
00000ff0 d6b8dde8 d88d310f d6b8a3f8 d52aa000 00001000 d88d502c d6b8ddfc
|
||||
00001000 d6b8ddf4 c11676ed d69db1e8 d6b8de24 c11679ad d52aa000 00000000
|
||||
Call Trace:
|
||||
[<c101a520>] ? kmap_atomic_prot+0x37/0xa6
|
||||
[<d88d310f>] ghash_update+0x85/0xbe [ghash_generic]
|
||||
[<c11676ed>] crypto_shash_update+0x18/0x1b
|
||||
[<c11679ad>] shash_ahash_update+0x22/0x36
|
||||
[<c11679cc>] shash_async_update+0xb/0xd
|
||||
[<d88ce0ba>] hash_sendpage+0xba/0xf2 [algif_hash]
|
||||
[<c121b24c>] kernel_sendpage+0x39/0x4e
|
||||
[<d88ce000>] ? 0xd88cdfff
|
||||
[<c121b298>] sock_sendpage+0x37/0x3e
|
||||
[<c121b261>] ? kernel_sendpage+0x4e/0x4e
|
||||
[<c10b4dbc>] pipe_to_sendpage+0x56/0x61
|
||||
[<c10b4e1f>] splice_from_pipe_feed+0x58/0xcd
|
||||
[<c10b4d66>] ? splice_from_pipe_begin+0x10/0x10
|
||||
[<c10b51f5>] __splice_from_pipe+0x36/0x55
|
||||
[<c10b4d66>] ? splice_from_pipe_begin+0x10/0x10
|
||||
[<c10b6383>] splice_from_pipe+0x51/0x64
|
||||
[<c10b63c2>] ? default_file_splice_write+0x2c/0x2c
|
||||
[<c10b63d5>] generic_splice_sendpage+0x13/0x15
|
||||
[<c10b4d66>] ? splice_from_pipe_begin+0x10/0x10
|
||||
[<c10b527f>] do_splice_from+0x5d/0x67
|
||||
[<c10b6865>] sys_splice+0x2bf/0x363
|
||||
[<c129373b>] ? sysenter_exit+0xf/0x16
|
||||
[<c104dc1e>] ? trace_hardirqs_on_caller+0x10e/0x13f
|
||||
[<c129370c>] sysenter_do_call+0x12/0x32
|
||||
Code: 83 c4 0c 5b 5e 5f c9 c3 55 b9 04 00 00 00 89 e5 57 8d 7d e4 56 53 8d 5d e4 83 ec 18 89 45 e0 89 55 dc 0f b6 70 0f c1 e6 04 01 d6 <f3> a5 be 0f 00 00 00 4e 89 d8 e8 48 ff ff ff 8b 45 e0 89 da 0f
|
||||
EIP: [<d88c92d4>] gf128mul_4k_lle+0x23/0x60 [gf128mul] SS:ESP 0068:d6b8dda4
|
||||
CR2: 0000000000000670
|
||||
---[ end trace 4eaa2a86a8e2da24 ]---
|
||||
note: hashatron[1502] exited with preempt_count 1
|
||||
BUG: scheduling while atomic: hashatron/1502/0x10000002
|
||||
INFO: lockdep is turned off.
|
||||
[...]
|
||||
|
||||
Signed-off-by: Nick Bowler <nbowler@elliptictech.com>
|
||||
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
---
|
||||
crypto/ghash-generic.c | 6 ++++++
|
||||
1 files changed, 6 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c
|
||||
index be44256..7835b8f 100644
|
||||
--- a/crypto/ghash-generic.c
|
||||
+++ b/crypto/ghash-generic.c
|
||||
@@ -67,6 +67,9 @@ static int ghash_update(struct shash_desc *desc,
|
||||
struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
|
||||
u8 *dst = dctx->buffer;
|
||||
|
||||
+ if (!ctx->gf128)
|
||||
+ return -ENOKEY;
|
||||
+
|
||||
if (dctx->bytes) {
|
||||
int n = min(srclen, dctx->bytes);
|
||||
u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
|
||||
@@ -119,6 +122,9 @@ static int ghash_final(struct shash_desc *desc, u8 *dst)
|
||||
struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
|
||||
u8 *buf = dctx->buffer;
|
||||
|
||||
+ if (!ctx->gf128)
|
||||
+ return -ENOKEY;
|
||||
+
|
||||
ghash_flush(ctx, dctx);
|
||||
memcpy(dst, buf, GHASH_BLOCK_SIZE);
|
||||
|
||||
--
|
||||
1.7.6.4
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
From 799c10559d60f159ab2232203f222f18fa3c4a5f Mon Sep 17 00:00:00 2001
|
||||
From: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
Date: Fri, 15 Oct 2010 11:09:28 -0700
|
||||
Subject: [PATCH] De-pessimize rds_page_copy_user
|
||||
|
||||
Don't try to "optimize" rds_page_copy_user() by using kmap_atomic() and
|
||||
the unsafe atomic user mode accessor functions. It's actually slower
|
||||
than the straightforward code on any reasonable modern CPU.
|
||||
|
||||
Back when the code was written (although probably not by the time it was
|
||||
actually merged, though), 32-bit x86 may have been the dominant
|
||||
architecture. And there kmap_atomic() can be a lot faster than kmap()
|
||||
(unless you have very good locality, in which case the virtual address
|
||||
caching by kmap() can overcome all the downsides).
|
||||
|
||||
But these days, x86-64 may not be more populous, but it's getting there
|
||||
(and if you care about performance, it's definitely already there -
|
||||
you'd have upgraded your CPU's already in the last few years). And on
|
||||
x86-64, the non-kmap_atomic() version is faster, simply because the code
|
||||
is simpler and doesn't have the "re-try page fault" case.
|
||||
|
||||
People with old hardware are not likely to care about RDS anyway, and
|
||||
the optimization for the 32-bit case is simply buggy, since it doesn't
|
||||
verify the user addresses properly.
|
||||
|
||||
Reported-by: Dan Rosenberg <drosenberg@vsecurity.com>
|
||||
Acked-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
Cc: stable@kernel.org
|
||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
---
|
||||
net/rds/page.c | 27 +++++++--------------------
|
||||
1 files changed, 7 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/net/rds/page.c b/net/rds/page.c
|
||||
index 595a952..1dfbfea 100644
|
||||
--- a/net/rds/page.c
|
||||
+++ b/net/rds/page.c
|
||||
@@ -57,30 +57,17 @@ int rds_page_copy_user(struct page *page, unsigned long offset,
|
||||
unsigned long ret;
|
||||
void *addr;
|
||||
|
||||
- if (to_user)
|
||||
+ addr = kmap(page);
|
||||
+ if (to_user) {
|
||||
rds_stats_add(s_copy_to_user, bytes);
|
||||
- else
|
||||
+ ret = copy_to_user(ptr, addr + offset, bytes);
|
||||
+ } else {
|
||||
rds_stats_add(s_copy_from_user, bytes);
|
||||
-
|
||||
- addr = kmap_atomic(page, KM_USER0);
|
||||
- if (to_user)
|
||||
- ret = __copy_to_user_inatomic(ptr, addr + offset, bytes);
|
||||
- else
|
||||
- ret = __copy_from_user_inatomic(addr + offset, ptr, bytes);
|
||||
- kunmap_atomic(addr, KM_USER0);
|
||||
-
|
||||
- if (ret) {
|
||||
- addr = kmap(page);
|
||||
- if (to_user)
|
||||
- ret = copy_to_user(ptr, addr + offset, bytes);
|
||||
- else
|
||||
- ret = copy_from_user(addr + offset, ptr, bytes);
|
||||
- kunmap(page);
|
||||
- if (ret)
|
||||
- return -EFAULT;
|
||||
+ ret = copy_from_user(addr + offset, ptr, bytes);
|
||||
}
|
||||
+ kunmap(page);
|
||||
|
||||
- return 0;
|
||||
+ return ret ? -EFAULT : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rds_page_copy_user);
|
||||
|
||||
--
|
||||
1.7.3.2
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
|
||||
index 11482b6..b05ff9c 100644
|
||||
--- a/drivers/usb/host/xhci-pci.c
|
||||
+++ b/drivers/usb/host/xhci-pci.c
|
||||
@@ -179,9 +179,25 @@ static struct pci_driver xhci_pci_driver = {
|
||||
.shutdown = usb_hcd_pci_shutdown,
|
||||
};
|
||||
|
||||
+
|
||||
+static int enable;
|
||||
+module_param(enable, int, S_IRUGO);
|
||||
+MODULE_PARM_DESC(enable, "Enable XHCI host controller");
|
||||
+
|
||||
int xhci_register_pci(void)
|
||||
{
|
||||
- return pci_register_driver(&xhci_pci_driver);
|
||||
+ /* xhci will prevent suspend/resume if it's loaded.
|
||||
+ * force user to pass xhci.enable=1 to the kernel in order
|
||||
+ * to get usb3.0 support for the time being.
|
||||
+ *
|
||||
+ * ugly yes, but there's few enough users out there using
|
||||
+ * usb3.0, and a lot who just have the hardware breaking
|
||||
+ * their suspend.
|
||||
+ */
|
||||
+ if (enable)
|
||||
+ return pci_register_driver(&xhci_pci_driver);
|
||||
+ else
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
void xhci_unregister_pci(void)
|
|
@ -0,0 +1,205 @@
|
|||
From ce5fa9851090cc5f3de4139bf0f343eb78d1c568 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Jones <pjones@redhat.com>
|
||||
Date: Mon, 11 Oct 2010 15:49:28 -0400
|
||||
Subject: [PATCH] device-mapper: Allow setting of UUID via rename if not already set
|
||||
|
||||
This makes it possible to use DM_DEV_RENAME to add a uuid to a device so
|
||||
long as one has not been previously set either with DM_DEV_CREATE or
|
||||
with DM_DEV_RENAME. This is needed because sometimes in it's necessary
|
||||
to create the device before the uuid is known, and in such cases the
|
||||
uuid must be filled in after the creation.
|
||||
|
||||
Also bump the minor number to 19.
|
||||
|
||||
Signed-off-by: Peter Jones <pjones@redhat.com>
|
||||
---
|
||||
drivers/md/dm-ioctl.c | 95 ++++++++++++++++++++++++++++++++--------------
|
||||
include/linux/dm-ioctl.h | 11 ++++-
|
||||
2 files changed, 74 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
|
||||
index bb6bdc8..d102269 100644
|
||||
--- a/drivers/md/dm-ioctl.c
|
||||
+++ b/drivers/md/dm-ioctl.c
|
||||
@@ -298,15 +298,15 @@ retry:
|
||||
static int dm_hash_rename(uint32_t cookie, uint32_t *flags, const char *old,
|
||||
const char *new)
|
||||
{
|
||||
- char *new_name, *old_name;
|
||||
+ char *new_data, *old_data;
|
||||
struct hash_cell *hc;
|
||||
struct dm_table *table;
|
||||
|
||||
/*
|
||||
* duplicate new.
|
||||
*/
|
||||
- new_name = kstrdup(new, GFP_KERNEL);
|
||||
- if (!new_name)
|
||||
+ new_data = kstrdup(new, GFP_KERNEL);
|
||||
+ if (!new_data)
|
||||
return -ENOMEM;
|
||||
|
||||
down_write(&_hash_lock);
|
||||
@@ -314,13 +314,18 @@ static int dm_hash_rename(uint32_t cookie, uint32_t *flags, const char *old,
|
||||
/*
|
||||
* Is new free ?
|
||||
*/
|
||||
- hc = __get_name_cell(new);
|
||||
+ if (*flags & DM_NEW_UUID_FLAG)
|
||||
+ hc = __get_uuid_cell(new);
|
||||
+ else
|
||||
+ hc = __get_name_cell(new);
|
||||
if (hc) {
|
||||
- DMWARN("asked to rename to an already existing name %s -> %s",
|
||||
+ DMWARN("Unable to change %s on device, %s to one that "
|
||||
+ "already exists: %s",
|
||||
+ (*flags & DM_NEW_UUID_FLAG) ? "uuid" : "name",
|
||||
old, new);
|
||||
dm_put(hc->md);
|
||||
up_write(&_hash_lock);
|
||||
- kfree(new_name);
|
||||
+ kfree(new_data);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -329,22 +334,46 @@ static int dm_hash_rename(uint32_t cookie, uint32_t *flags, const char *old,
|
||||
*/
|
||||
hc = __get_name_cell(old);
|
||||
if (!hc) {
|
||||
- DMWARN("asked to rename a non existent device %s -> %s",
|
||||
+ DMWARN("Unable to rename non-existent device, %s to %s",
|
||||
old, new);
|
||||
up_write(&_hash_lock);
|
||||
- kfree(new_name);
|
||||
+ kfree(new_data);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * rename and move the name cell.
|
||||
- */
|
||||
- list_del(&hc->name_list);
|
||||
- old_name = hc->name;
|
||||
- mutex_lock(&dm_hash_cells_mutex);
|
||||
- hc->name = new_name;
|
||||
- mutex_unlock(&dm_hash_cells_mutex);
|
||||
- list_add(&hc->name_list, _name_buckets + hash_str(new_name));
|
||||
+ if (*flags & DM_NEW_UUID_FLAG) {
|
||||
+ /*
|
||||
+ * Does this device already have a uuid?
|
||||
+ */
|
||||
+ if (hc->uuid) {
|
||||
+ DMWARN("Unable to change uuid of device, %s because "
|
||||
+ "uuid is already set to %s",
|
||||
+ old, hc->uuid);
|
||||
+ dm_put(hc->md);
|
||||
+ up_write(&_hash_lock);
|
||||
+ kfree(new_data);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ /*
|
||||
+ * change uuid and move the uuid cell.
|
||||
+ */
|
||||
+ list_del(&hc->uuid_list);
|
||||
+ old_data = hc->uuid;
|
||||
+ mutex_lock(&dm_hash_cells_mutex);
|
||||
+ hc->uuid = new_data;
|
||||
+ mutex_unlock(&dm_hash_cells_mutex);
|
||||
+ list_add(&hc->uuid_list, _uuid_buckets + hash_str(new_data));
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * rename and move the name cell.
|
||||
+ */
|
||||
+ list_del(&hc->name_list);
|
||||
+ old_data = hc->name;
|
||||
+ mutex_lock(&dm_hash_cells_mutex);
|
||||
+ hc->name = new_data;
|
||||
+ mutex_unlock(&dm_hash_cells_mutex);
|
||||
+ list_add(&hc->name_list, _name_buckets + hash_str(new_data));
|
||||
+ }
|
||||
|
||||
/*
|
||||
* Wake up any dm event waiters.
|
||||
@@ -360,7 +388,7 @@ static int dm_hash_rename(uint32_t cookie, uint32_t *flags, const char *old,
|
||||
|
||||
dm_put(hc->md);
|
||||
up_write(&_hash_lock);
|
||||
- kfree(old_name);
|
||||
+ kfree(old_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -773,23 +801,32 @@ static int invalid_str(char *str, void *end)
|
||||
static int dev_rename(struct dm_ioctl *param, size_t param_size)
|
||||
{
|
||||
int r;
|
||||
- char *new_name = (char *) param + param->data_start;
|
||||
+ char *new_data = (char *) param + param->data_start;
|
||||
|
||||
- if (new_name < param->data ||
|
||||
- invalid_str(new_name, (void *) param + param_size) ||
|
||||
- strlen(new_name) > DM_NAME_LEN - 1) {
|
||||
- DMWARN("Invalid new logical volume name supplied.");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
+ if (param->flags & DM_NEW_UUID_FLAG) {
|
||||
+ if (new_data < param->data ||
|
||||
+ invalid_str(new_data, (void *) param + param_size) ||
|
||||
+ strlen(new_data) > DM_UUID_LEN - 1) {
|
||||
+ DMWARN("Invalid new device uuid supplied.");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (new_data < param->data ||
|
||||
+ invalid_str(new_data, (void *) param + param_size) ||
|
||||
+ strlen(new_data) > DM_NAME_LEN - 1) {
|
||||
+ DMWARN("Invalid new device name supplied.");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
- r = check_name(new_name);
|
||||
- if (r)
|
||||
- return r;
|
||||
+ r = check_name(new_data);
|
||||
+ if (r)
|
||||
+ return r;
|
||||
+ }
|
||||
|
||||
param->data_size = 0;
|
||||
|
||||
return dm_hash_rename(param->event_nr, ¶m->flags, param->name,
|
||||
- new_name);
|
||||
+ new_data);
|
||||
}
|
||||
|
||||
static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
|
||||
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
|
||||
index 2c445e1..3bbcb3a 100644
|
||||
--- a/include/linux/dm-ioctl.h
|
||||
+++ b/include/linux/dm-ioctl.h
|
||||
@@ -266,9 +266,9 @@ enum {
|
||||
#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_VERSION_MAJOR 4
|
||||
-#define DM_VERSION_MINOR 17
|
||||
-#define DM_VERSION_PATCHLEVEL 0
|
||||
-#define DM_VERSION_EXTRA "-ioctl (2010-03-05)"
|
||||
+#define DM_VERSION_MINOR 19
|
||||
+#define DM_VERSION_PATCHLEVEL 1
|
||||
+#define DM_VERSION_EXTRA "-ioctl (2010-10-12)"
|
||||
|
||||
/* Status bits */
|
||||
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
|
||||
@@ -321,4 +321,9 @@ enum {
|
||||
*/
|
||||
#define DM_UEVENT_GENERATED_FLAG (1 << 13) /* Out */
|
||||
|
||||
+/*
|
||||
+ * If set, rename operates on uuid, not name.
|
||||
+ */
|
||||
+#define DM_NEW_UUID_FLAG (1 << 14) /* In */
|
||||
+
|
||||
#endif /* _LINUX_DM_IOCTL_H */
|
||||
--
|
||||
1.7.2.3
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
From 8d2f6746f7f82e1aee2dc40a937b5954cfc73414 Mon Sep 17 00:00:00 2001
|
||||
From: Kyle McMartin <kyle@mcmartin.ca>
|
||||
Date: Sun, 17 Oct 2010 15:55:32 -0400
|
||||
Subject: [PATCH] dmar: disable if ricoh multifunction detected
|
||||
|
||||
---
|
||||
drivers/pci/intel-iommu.c | 10 ++++++++++
|
||||
1 files changed, 10 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
|
||||
index 8e499e8..076c5de 100644
|
||||
--- a/drivers/pci/intel-iommu.c
|
||||
+++ b/drivers/pci/intel-iommu.c
|
||||
@@ -3755,6 +3755,18 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
|
||||
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
|
||||
|
||||
+/* https://bugzilla.redhat.com/show_bug.cgi?id=605888 */
|
||||
+static void __devinit quirk_ricoh_multifunction(struct pci_dev *dev)
|
||||
+{
|
||||
+ printk(KERN_INFO "intel_iommu: broken Ricoh device %04X detected, disabling...\n",
|
||||
+ dev->device);
|
||||
+ dmar_disabled = 1;
|
||||
+}
|
||||
+DECLARE_PCI_FIXUP_HEADER(0x1180, 0xe822, quirk_ricoh_multifunction);
|
||||
+DECLARE_PCI_FIXUP_HEADER(0x1180, 0xe230, quirk_ricoh_multifunction);
|
||||
+DECLARE_PCI_FIXUP_HEADER(0x1180, 0xe832, quirk_ricoh_multifunction);
|
||||
+DECLARE_PCI_FIXUP_HEADER(0x1180, 0xe476, quirk_ricoh_multifunction);
|
||||
+
|
||||
/* On Tylersburg chipsets, some BIOSes have been known to enable the
|
||||
ISOCH DMAR unit for the Azalia sound device, but not give it any
|
||||
TLB entries, which causes it to deadlock. Check for that. We do
|
||||
--
|
||||
1.7.3.1
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
diff -up linux-2.6.35.x86_64/drivers/gpu/drm/drm_edid.c.da linux-2.6.35.x86_64/drivers/gpu/drm/drm_edid.c
|
||||
--- linux-2.6.35.x86_64/drivers/gpu/drm/drm_edid.c.da 2010-08-01 18:11:14.000000000 -0400
|
||||
+++ linux-2.6.35.x86_64/drivers/gpu/drm/drm_edid.c 2010-11-11 20:46:10.000000000 -0500
|
||||
@@ -229,7 +229,7 @@ drm_do_probe_ddc_edid(struct i2c_adapter
|
||||
.addr = DDC_ADDR,
|
||||
.flags = I2C_M_RD,
|
||||
.len = len,
|
||||
- .buf = buf + start,
|
||||
+ .buf = buf,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -242,7 +242,7 @@ drm_do_probe_ddc_edid(struct i2c_adapter
|
||||
static u8 *
|
||||
drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
|
||||
{
|
||||
- int i, j = 0;
|
||||
+ int i, j = 0, valid_extensions = 0;
|
||||
u8 *block, *new;
|
||||
|
||||
if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
|
||||
@@ -269,14 +269,28 @@ drm_do_get_edid(struct drm_connector *co
|
||||
|
||||
for (j = 1; j <= block[0x7e]; j++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
- if (drm_do_probe_ddc_edid(adapter, block, j,
|
||||
- EDID_LENGTH))
|
||||
+ if (drm_do_probe_ddc_edid(adapter,
|
||||
+ block + (valid_extensions + 1) * EDID_LENGTH,
|
||||
+ j, EDID_LENGTH))
|
||||
goto out;
|
||||
- if (drm_edid_block_valid(block + j * EDID_LENGTH))
|
||||
+ if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) {
|
||||
+ valid_extensions++;
|
||||
break;
|
||||
+ }
|
||||
}
|
||||
if (i == 4)
|
||||
- goto carp;
|
||||
+ printk(KERN_WARNING
|
||||
+ "%s: Ignoring invalid EDID block %d.\n",
|
||||
+ drm_get_connector_name(connector), j);
|
||||
+ }
|
||||
+
|
||||
+ if (valid_extensions != block[0x7e]) {
|
||||
+ block[EDID_LENGTH-1] += block[0x7e] - valid_extensions;
|
||||
+ block[0x7e] = valid_extensions;
|
||||
+ new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
|
||||
+ if (!new)
|
||||
+ goto out;
|
||||
+ block = new;
|
||||
}
|
||||
|
||||
return block;
|
|
@ -0,0 +1,57 @@
|
|||
From 9fa9e790eb301bade8fe4ea0fd9ecb72617f0928 Mon Sep 17 00:00:00 2001
|
||||
From: Francisco Jerez <currojerez@riseup.net>
|
||||
Date: Thu, 5 Aug 2010 22:57:08 +0200
|
||||
Subject: [PATCH 3/5] drm-i2c-ch7006-fix
|
||||
|
||||
drm/i2c/ch7006: Don't use POWER_LEVEL_FULL_POWER_OFF on early chip versions.
|
||||
|
||||
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
||||
---
|
||||
drivers/gpu/drm/i2c/ch7006_drv.c | 1 +
|
||||
drivers/gpu/drm/i2c/ch7006_mode.c | 5 ++++-
|
||||
drivers/gpu/drm/i2c/ch7006_priv.h | 1 +
|
||||
3 files changed, 6 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
|
||||
index 81681a0..8c760c7 100644
|
||||
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
|
||||
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
|
||||
@@ -454,6 +454,7 @@ static int ch7006_encoder_init(struct i2c_client *client,
|
||||
priv->hmargin = 50;
|
||||
priv->vmargin = 50;
|
||||
priv->last_dpms = -1;
|
||||
+ priv->chip_version = ch7006_read(client, CH7006_VERSION_ID);
|
||||
|
||||
if (ch7006_tv_norm) {
|
||||
for (i = 0; i < NUM_TV_NORMS; i++) {
|
||||
diff --git a/drivers/gpu/drm/i2c/ch7006_mode.c b/drivers/gpu/drm/i2c/ch7006_mode.c
|
||||
index e447dfb..c860f24 100644
|
||||
--- a/drivers/gpu/drm/i2c/ch7006_mode.c
|
||||
+++ b/drivers/gpu/drm/i2c/ch7006_mode.c
|
||||
@@ -316,7 +316,10 @@ void ch7006_setup_power_state(struct drm_encoder *encoder)
|
||||
}
|
||||
|
||||
} else {
|
||||
- *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
|
||||
+ if (priv->chip_version >= 0x20)
|
||||
+ *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
|
||||
+ else
|
||||
+ *power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h
|
||||
index b06d3d9..9487123 100644
|
||||
--- a/drivers/gpu/drm/i2c/ch7006_priv.h
|
||||
+++ b/drivers/gpu/drm/i2c/ch7006_priv.h
|
||||
@@ -95,6 +95,7 @@ struct ch7006_priv {
|
||||
int flicker;
|
||||
int scale;
|
||||
|
||||
+ int chip_version;
|
||||
int last_dpms;
|
||||
};
|
||||
|
||||
--
|
||||
1.7.2
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
https://bugzilla.redhat.com/show_bug.cgi?id=639146
|
||||
|
||||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
|
||||
index ce8ff0e..3bbd2c4 100644
|
||||
--- a/drivers/gpu/drm/i915/i915_dma.c
|
||||
+++ b/drivers/gpu/drm/i915/i915_dma.c
|
||||
@@ -1353,6 +1353,27 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
|
||||
return can_switch;
|
||||
}
|
||||
|
||||
+/* check the VBT to see whether the eDP is on DP-D port */
|
||||
+static bool intel_dpd_is_edp(struct drm_device *dev)
|
||||
+{
|
||||
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
+ struct child_device_config *p_child;
|
||||
+ int i;
|
||||
+
|
||||
+ if (!dev_priv->child_dev_num)
|
||||
+ return false;
|
||||
+
|
||||
+ for (i = 0; i < dev_priv->child_dev_num; i++) {
|
||||
+ p_child = dev_priv->child_dev + i;
|
||||
+
|
||||
+ if (p_child->dvo_port == PORT_IDPD &&
|
||||
+ p_child->device_type == DEVICE_TYPE_eDP)
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static int i915_load_modeset_init(struct drm_device *dev,
|
||||
unsigned long prealloc_start,
|
||||
unsigned long prealloc_size,
|
||||
@@ -1409,6 +1430,15 @@ static int i915_load_modeset_init(struct drm_device *dev,
|
||||
if (ret)
|
||||
DRM_INFO("failed to find VBIOS tables\n");
|
||||
|
||||
+ /* XXX: eDP doesn't even work in git HEAD,
|
||||
+ * bail out and pray that text mode still works...
|
||||
+ */
|
||||
+ if (intel_dpd_is_edp(dev)) {
|
||||
+ DRM_ERROR("eDP support is currently non-functional, please boot with \"nomodeset xdriver=vesa\"\n");
|
||||
+ ret = -EINVAL;
|
||||
+ goto cleanup_ringbuffer;
|
||||
+ }
|
||||
+
|
||||
/* if we have > 1 VGA cards, then disable the radeon VGA resources */
|
||||
ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
|
||||
if (ret)
|
|
@ -0,0 +1,70 @@
|
|||
From ab7959dd389be36c0bc63e3e883b7891d2c1bfc4 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Date: Wed, 8 Sep 2010 09:45:11 +0100
|
||||
Subject: [PATCH] drm/i915: Disable output polling across suspend & resume
|
||||
|
||||
Suspending (especially hibernating) may take a finite amount of time,
|
||||
during which a hotplug event may trigger and we will attempt to handle
|
||||
it with inconsistent state. Disable hotplug polling around suspend and
|
||||
resume.
|
||||
|
||||
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30070
|
||||
Reported-by: Rui Tiago Matos <tiagomatos@gmail.com>
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
---
|
||||
drivers/gpu/drm/i915/i915_dma.c | 2 --
|
||||
drivers/gpu/drm/i915/i915_drv.c | 11 ++++++++++-
|
||||
2 files changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
|
||||
index ce8ff0e..c569617 100644
|
||||
--- a/drivers/gpu/drm/i915/i915_dma.c
|
||||
+++ b/drivers/gpu/drm/i915/i915_dma.c
|
||||
@@ -1334,10 +1334,8 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
|
||||
/* i915 resume handler doesn't set to D0 */
|
||||
pci_set_power_state(dev->pdev, PCI_D0);
|
||||
i915_resume(dev);
|
||||
- drm_kms_helper_poll_enable(dev);
|
||||
} else {
|
||||
printk(KERN_ERR "i915: switched off\n");
|
||||
- drm_kms_helper_poll_disable(dev);
|
||||
i915_suspend(dev, pmm);
|
||||
}
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
|
||||
index 194e0c4..3ad3ebe 100644
|
||||
--- a/drivers/gpu/drm/i915/i915_drv.c
|
||||
+++ b/drivers/gpu/drm/i915/i915_drv.c
|
||||
@@ -263,6 +263,8 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
|
||||
if (state.event == PM_EVENT_PRETHAW)
|
||||
return 0;
|
||||
|
||||
+ drm_kms_helper_poll_disable(dev);
|
||||
+
|
||||
error = i915_drm_freeze(dev);
|
||||
if (error)
|
||||
return error;
|
||||
@@ -306,12 +308,19 @@ static int i915_drm_thaw(struct drm_device *dev)
|
||||
|
||||
int i915_resume(struct drm_device *dev)
|
||||
{
|
||||
+ int ret;
|
||||
+
|
||||
if (pci_enable_device(dev->pdev))
|
||||
return -EIO;
|
||||
|
||||
pci_set_master(dev->pdev);
|
||||
|
||||
- return i915_drm_thaw(dev);
|
||||
+ ret = i915_drm_thaw(dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ drm_kms_helper_poll_enable(dev);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
--
|
||||
1.7.2.3
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
From ce9d419dbecc292cc3e06e8b1d6d123d3fa813a4 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Date: Sun, 26 Sep 2010 20:50:05 +0100
|
||||
Subject: drm/i915: Sanity check pread/pwrite
|
||||
|
||||
From: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
|
||||
commit ce9d419dbecc292cc3e06e8b1d6d123d3fa813a4 upstream.
|
||||
|
||||
Move the access control up from the fast paths, which are no longer
|
||||
universally taken first, up into the caller. This then duplicates some
|
||||
sanity checking along the slow paths, but is much simpler.
|
||||
Tracked as CVE-2010-2962.
|
||||
|
||||
Reported-by: Kees Cook <kees@ubuntu.com>
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
|
||||
---
|
||||
drivers/gpu/drm/i915/i915_gem.c | 28 ++++++++++++++++++++--------
|
||||
1 file changed, 20 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/i915/i915_gem.c
|
||||
+++ b/drivers/gpu/drm/i915/i915_gem.c
|
||||
@@ -465,8 +465,15 @@ i915_gem_pread_ioctl(struct drm_device *
|
||||
*/
|
||||
if (args->offset > obj->size || args->size > obj->size ||
|
||||
args->offset + args->size > obj->size) {
|
||||
- drm_gem_object_unreference_unlocked(obj);
|
||||
- return -EINVAL;
|
||||
+ ret = -EINVAL;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ if (!access_ok(VERIFY_WRITE,
|
||||
+ (char __user *)(uintptr_t)args->data_ptr,
|
||||
+ args->size)) {
|
||||
+ ret = -EFAULT;
|
||||
+ goto err;
|
||||
}
|
||||
|
||||
if (i915_gem_object_needs_bit17_swizzle(obj)) {
|
||||
@@ -478,8 +485,8 @@ i915_gem_pread_ioctl(struct drm_device *
|
||||
file_priv);
|
||||
}
|
||||
|
||||
+err:
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
-
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -568,8 +575,6 @@ i915_gem_gtt_pwrite_fast(struct drm_devi
|
||||
|
||||
user_data = (char __user *) (uintptr_t) args->data_ptr;
|
||||
remain = args->size;
|
||||
- if (!access_ok(VERIFY_READ, user_data, remain))
|
||||
- return -EFAULT;
|
||||
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
@@ -928,8 +933,15 @@ i915_gem_pwrite_ioctl(struct drm_device
|
||||
*/
|
||||
if (args->offset > obj->size || args->size > obj->size ||
|
||||
args->offset + args->size > obj->size) {
|
||||
- drm_gem_object_unreference_unlocked(obj);
|
||||
- return -EINVAL;
|
||||
+ ret = -EINVAL;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ if (!access_ok(VERIFY_READ,
|
||||
+ (char __user *)(uintptr_t)args->data_ptr,
|
||||
+ args->size)) {
|
||||
+ ret = -EFAULT;
|
||||
+ goto err;
|
||||
}
|
||||
|
||||
/* We can only do the GTT pwrite on untiled buffers, as otherwise
|
||||
@@ -963,8 +975,8 @@ i915_gem_pwrite_ioctl(struct drm_device
|
||||
DRM_INFO("pwrite failed %d\n", ret);
|
||||
#endif
|
||||
|
||||
+err:
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
-
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
--- linux-2.6.35.noarch/drivers/gpu/drm/radeon/radeon_fence.c~ 2011-10-21 14:08:15.229351796 -0400
|
||||
+++ linux-2.6.35.noarch/drivers/gpu/drm/radeon/radeon_fence.c 2011-10-21 14:08:35.140287089 -0400
|
||||
@@ -232,7 +232,7 @@ retry:
|
||||
*/
|
||||
if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
|
||||
/* good news we believe it's a lockup */
|
||||
- WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq);
|
||||
+ printk(KERN_WARNING, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq);
|
||||
/* FIXME: what should we do ? marking everyone
|
||||
* as signaled for now
|
||||
*/
|
|
@ -0,0 +1,21 @@
|
|||
diff -up linux-2.6.35.x86_64/drivers/gpu/drm/nouveau/nouveau_connector.c.da linux-2.6.35.x86_64/drivers/gpu/drm/nouveau/nouveau_connector.c
|
||||
--- linux-2.6.35.x86_64/drivers/gpu/drm/nouveau/nouveau_connector.c.da 2010-11-08 19:55:42.000000000 -0500
|
||||
+++ linux-2.6.35.x86_64/drivers/gpu/drm/nouveau/nouveau_connector.c 2010-11-08 19:55:49.000000000 -0500
|
||||
@@ -298,7 +298,7 @@ detect_analog:
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
-nouveau_connector_detect_lvds(struct drm_connector *connector)
|
||||
+nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
@@ -319,7 +319,7 @@ nouveau_connector_detect_lvds(struct drm
|
||||
|
||||
/* Try retrieving EDID via DDC */
|
||||
if (!dev_priv->vbios.fp_no_ddc) {
|
||||
- status = nouveau_connector_detect(connector);
|
||||
+ status = nouveau_connector_detect(connector, force);
|
||||
if (status == connector_status_connected)
|
||||
goto out;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
From d0301ece9e093c484f880893dc86d97848360892 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Skeggs <bskeggs@redhat.com>
|
||||
Date: Fri, 19 Nov 2010 18:50:57 +1000
|
||||
Subject: [PATCH 2/2] drm-nouveau-evo-hang
|
||||
|
||||
On some GF8+ boards, the display engine will stop processing its push
|
||||
buffer if a wrap-around occurs at a certain point. The exact cause
|
||||
is not known.
|
||||
|
||||
This patch by David Dillow (rhbz#537065) is a safe enough work-around
|
||||
until it can be solved properly.
|
||||
|
||||
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/nouveau/nv50_display.c | 1 +
|
||||
1 files changed, 1 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
|
||||
index 11d366a..4e5402c 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nv50_display.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
|
||||
@@ -364,6 +364,7 @@ nv50_display_init(struct drm_device *dev)
|
||||
nv_wr32(dev, 0x610300, nv_rd32(dev, 0x610300) & ~1);
|
||||
|
||||
evo->dma.max = (4096/4) - 2;
|
||||
+ evo->dma.max &= ~7;
|
||||
evo->dma.put = 0;
|
||||
evo->dma.cur = evo->dma.put;
|
||||
evo->dma.free = evo->dma.max - evo->dma.cur;
|
||||
--
|
||||
1.7.3.2
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
From b4166db6d1f951a460e5e7f52bb4b4d96f27f55a Mon Sep 17 00:00:00 2001
|
||||
From: Francisco Jerez <currojerez@riseup.net>
|
||||
Date: Fri, 19 Nov 2010 18:08:47 +1000
|
||||
Subject: [PATCH 1/2] drm-nouveau-imac-g4
|
||||
|
||||
drm/nouveau: fabricate DCB encoder table for iMac G4
|
||||
|
||||
In typical Apple fashion there's no standard information about what
|
||||
encoders are present on this machine, this patch adds a quirk to
|
||||
provide it.
|
||||
|
||||
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
||||
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/nouveau/nouveau_bios.c | 102 ++++++++++++--------------------
|
||||
1 files changed, 38 insertions(+), 64 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
|
||||
index 72905c9..8c287f8 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
|
||||
@@ -5985,52 +5985,17 @@ static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb)
|
||||
return entry;
|
||||
}
|
||||
|
||||
-static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads)
|
||||
+static void fabricate_dcb_output(struct dcb_table *dcb, int type, int i2c,
|
||||
+ int heads, int or)
|
||||
{
|
||||
struct dcb_entry *entry = new_dcb_entry(dcb);
|
||||
|
||||
- entry->type = 0;
|
||||
+ entry->type = type;
|
||||
entry->i2c_index = i2c;
|
||||
entry->heads = heads;
|
||||
- entry->location = DCB_LOC_ON_CHIP;
|
||||
- entry->or = 1;
|
||||
-}
|
||||
-
|
||||
-static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads)
|
||||
-{
|
||||
- struct dcb_entry *entry = new_dcb_entry(dcb);
|
||||
-
|
||||
- entry->type = 2;
|
||||
- entry->i2c_index = LEGACY_I2C_PANEL;
|
||||
- entry->heads = twoHeads ? 3 : 1;
|
||||
- entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */
|
||||
- entry->or = 1; /* means |0x10 gets set on CRE_LCD__INDEX */
|
||||
- entry->duallink_possible = false; /* SiI164 and co. are single link */
|
||||
-
|
||||
-#if 0
|
||||
- /*
|
||||
- * For dvi-a either crtc probably works, but my card appears to only
|
||||
- * support dvi-d. "nvidia" still attempts to program it for dvi-a,
|
||||
- * doing the full fp output setup (program 0x6808.. fp dimension regs,
|
||||
- * setting 0x680848 to 0x10000111 to enable, maybe setting 0x680880);
|
||||
- * the monitor picks up the mode res ok and lights up, but no pixel
|
||||
- * data appears, so the board manufacturer probably connected up the
|
||||
- * sync lines, but missed the video traces / components
|
||||
- *
|
||||
- * with this introduction, dvi-a left as an exercise for the reader.
|
||||
- */
|
||||
- fabricate_vga_output(dcb, LEGACY_I2C_PANEL, entry->heads);
|
||||
-#endif
|
||||
-}
|
||||
-
|
||||
-static void fabricate_tv_output(struct dcb_table *dcb, bool twoHeads)
|
||||
-{
|
||||
- struct dcb_entry *entry = new_dcb_entry(dcb);
|
||||
-
|
||||
- entry->type = 1;
|
||||
- entry->i2c_index = LEGACY_I2C_TV;
|
||||
- entry->heads = twoHeads ? 3 : 1;
|
||||
- entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */
|
||||
+ if (type != OUTPUT_ANALOG)
|
||||
+ entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */
|
||||
+ entry->or = or;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -6297,8 +6262,36 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
|
||||
return true;
|
||||
}
|
||||
|
||||
+static void
|
||||
+fabricate_dcb_encoder_table(struct drm_device *dev, struct nvbios *bios)
|
||||
+{
|
||||
+ struct dcb_table *dcb = &bios->dcb;
|
||||
+ int all_heads = (nv_two_heads(dev) ? 3 : 1);
|
||||
+
|
||||
+#ifdef __powerpc__
|
||||
+ /* Apple iMac G4 NV17 */
|
||||
+ if (of_machine_is_compatible("PowerMac4,5")) {
|
||||
+ fabricate_dcb_output(dcb, OUTPUT_TMDS, 0, all_heads, 1);
|
||||
+ fabricate_dcb_output(dcb, OUTPUT_ANALOG, 1, all_heads, 2);
|
||||
+ return;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ /* Make up some sane defaults */
|
||||
+ fabricate_dcb_output(dcb, OUTPUT_ANALOG, LEGACY_I2C_CRT, 1, 1);
|
||||
+
|
||||
+ if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0)
|
||||
+ fabricate_dcb_output(dcb, OUTPUT_TV, LEGACY_I2C_TV,
|
||||
+ all_heads, 0);
|
||||
+
|
||||
+ else if (bios->tmds.output0_script_ptr ||
|
||||
+ bios->tmds.output1_script_ptr)
|
||||
+ fabricate_dcb_output(dcb, OUTPUT_TMDS, LEGACY_I2C_PANEL,
|
||||
+ all_heads, 1);
|
||||
+}
|
||||
+
|
||||
static int
|
||||
-parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
|
||||
+parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct dcb_table *dcb = &bios->dcb;
|
||||
@@ -6318,12 +6311,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
|
||||
|
||||
/* this situation likely means a really old card, pre DCB */
|
||||
if (dcbptr == 0x0) {
|
||||
- NV_INFO(dev, "Assuming a CRT output exists\n");
|
||||
- fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1);
|
||||
-
|
||||
- if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0)
|
||||
- fabricate_tv_output(dcb, twoHeads);
|
||||
-
|
||||
+ fabricate_dcb_encoder_table(dev, bios);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6383,21 +6371,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
|
||||
*/
|
||||
NV_TRACEWARN(dev, "No useful information in BIOS output table; "
|
||||
"adding all possible outputs\n");
|
||||
- fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1);
|
||||
-
|
||||
- /*
|
||||
- * Attempt to detect TV before DVI because the test
|
||||
- * for the former is more accurate and it rules the
|
||||
- * latter out.
|
||||
- */
|
||||
- if (nv04_tv_identify(dev,
|
||||
- bios->legacy.i2c_indices.tv) >= 0)
|
||||
- fabricate_tv_output(dcb, twoHeads);
|
||||
-
|
||||
- else if (bios->tmds.output0_script_ptr ||
|
||||
- bios->tmds.output1_script_ptr)
|
||||
- fabricate_dvi_i_output(dcb, twoHeads);
|
||||
-
|
||||
+ fabricate_dcb_encoder_table(dev, bios);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6787,7 +6761,7 @@ nouveau_bios_init(struct drm_device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- ret = parse_dcb_table(dev, bios, nv_two_heads(dev));
|
||||
+ ret = parse_dcb_table(dev, bios);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
--
|
||||
1.7.3.2
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
From 2120b3b32d96d523b18c82beb99a2d1c6135eb49 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Skeggs <bskeggs@redhat.com>
|
||||
Date: Mon, 21 Mar 2011 21:31:21 +1000
|
||||
Subject: [PATCH] drm/nouveau: implement init table opcode 0x5c
|
||||
|
||||
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/nouveau/nouveau_bios.c | 27 ++++++++++++++++++++++++---
|
||||
1 files changed, 24 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
|
||||
index 8314a49..eca191a 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
|
||||
@@ -269,7 +269,7 @@ struct init_tbl_entry {
|
||||
int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
|
||||
};
|
||||
|
||||
-static int parse_init_table(struct nvbios *, unsigned int, struct init_exec *);
|
||||
+static int parse_init_table(struct nvbios *, uint16_t, struct init_exec *);
|
||||
|
||||
#define MACRO_INDEX_SIZE 2
|
||||
#define MACRO_SIZE 8
|
||||
@@ -2011,6 +2011,27 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
||||
}
|
||||
|
||||
static int
|
||||
+init_jump(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
||||
+{
|
||||
+ /*
|
||||
+ * INIT_JUMP opcode: 0x5C ('\')
|
||||
+ *
|
||||
+ * offset (8 bit): opcode
|
||||
+ * offset + 1 (16 bit): offset (in bios)
|
||||
+ *
|
||||
+ * Continue execution of init table from 'offset'
|
||||
+ */
|
||||
+
|
||||
+ uint16_t jmp_offset = ROM16(bios->data[offset + 1]);
|
||||
+
|
||||
+ if (!iexec->execute)
|
||||
+ return 3;
|
||||
+
|
||||
+ BIOSLOG(bios, "0x%04X: Jump to 0x%04X\n", offset, jmp_offset);
|
||||
+ return jmp_offset - offset;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
||||
{
|
||||
/*
|
||||
@@ -3659,6 +3680,7 @@ static struct init_tbl_entry itbl_entry[] = {
|
||||
{ "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence },
|
||||
/* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
|
||||
{ "INIT_SUB_DIRECT" , 0x5B, init_sub_direct },
|
||||
+ { "INIT_JUMP" , 0x5C, init_jump },
|
||||
{ "INIT_I2C_IF" , 0x5E, init_i2c_if },
|
||||
{ "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg },
|
||||
{ "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io },
|
||||
@@ -3700,8 +3722,7 @@ static struct init_tbl_entry itbl_entry[] = {
|
||||
#define MAX_TABLE_OPS 1000
|
||||
|
||||
static int
|
||||
-parse_init_table(struct nvbios *bios, unsigned int offset,
|
||||
- struct init_exec *iexec)
|
||||
+parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
||||
{
|
||||
/*
|
||||
* Parses all commands in an init table.
|
||||
--
|
||||
1.7.4.1
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
From 8f51b07995c55369bfd27921ef10b76c2b203fe8 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Skeggs <bskeggs@redhat.com>
|
||||
Date: Tue, 17 Aug 2010 14:20:29 +1000
|
||||
Subject: [PATCH] drm-nouveau-nv50-crtc-update-delay
|
||||
|
||||
rhbz#614552
|
||||
|
||||
Adds a short delay before doing framebuffer-only CRTC updates. Fixes
|
||||
an issue that effects some cards (Quadro NVS295/FX580) where two of
|
||||
these updates in quick succession hangs the display engine.
|
||||
|
||||
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/nouveau/nv50_crtc.c | 3 +++
|
||||
1 files changed, 3 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
|
||||
index 2423c92..5c2aa1e 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
|
||||
@@ -540,6 +540,9 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
nouveau_bo_unpin(ofb->nvbo);
|
||||
}
|
||||
|
||||
+ if (update)
|
||||
+ mdelay(1);
|
||||
+
|
||||
nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base;
|
||||
nv_crtc->fb.tile_flags = fb->nvbo->tile_flags;
|
||||
nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
|
||||
--
|
||||
1.7.3.1
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
From e7e3837f6395e44b5b5fb7cdbcccaba5baf76803 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Skeggs <bskeggs@redhat.com>
|
||||
Date: Fri, 22 Oct 2010 10:26:24 +1000
|
||||
Subject: [PATCH] drm-nouveau-nv86-bug
|
||||
|
||||
drm/nv50: implement possible workaround for NV86 PGRAPH TLB flush hang
|
||||
|
||||
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/nouveau/nouveau_drv.h | 5 +++
|
||||
drivers/gpu/drm/nouveau/nouveau_mem.c | 14 +++-----
|
||||
drivers/gpu/drm/nouveau/nouveau_sgdma.c | 8 ++--
|
||||
drivers/gpu/drm/nouveau/nouveau_state.c | 10 ++++++
|
||||
drivers/gpu/drm/nouveau/nv50_fifo.c | 5 +++
|
||||
drivers/gpu/drm/nouveau/nv50_graph.c | 52 +++++++++++++++++++++++++++++++
|
||||
drivers/gpu/drm/nouveau/nv50_instmem.c | 1 -
|
||||
7 files changed, 82 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
|
||||
index be53e92..4273390 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
|
||||
@@ -304,6 +304,7 @@ struct nouveau_fifo_engine {
|
||||
void (*destroy_context)(struct nouveau_channel *);
|
||||
int (*load_context)(struct nouveau_channel *);
|
||||
int (*unload_context)(struct drm_device *);
|
||||
+ void (*tlb_flush)(struct drm_device *dev);
|
||||
};
|
||||
|
||||
struct nouveau_pgraph_object_method {
|
||||
@@ -336,6 +337,7 @@ struct nouveau_pgraph_engine {
|
||||
void (*destroy_context)(struct nouveau_channel *);
|
||||
int (*load_context)(struct nouveau_channel *);
|
||||
int (*unload_context)(struct drm_device *);
|
||||
+ void (*tlb_flush)(struct drm_device *dev);
|
||||
|
||||
void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
|
||||
uint32_t size, uint32_t pitch);
|
||||
@@ -944,6 +946,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *);
|
||||
extern void nv50_fifo_destroy_context(struct nouveau_channel *);
|
||||
extern int nv50_fifo_load_context(struct nouveau_channel *);
|
||||
extern int nv50_fifo_unload_context(struct drm_device *);
|
||||
+extern void nv50_fifo_tlb_flush(struct drm_device *dev);
|
||||
|
||||
/* nvc0_fifo.c */
|
||||
extern int nvc0_fifo_init(struct drm_device *);
|
||||
@@ -1021,6 +1024,8 @@ extern int nv50_graph_load_context(struct nouveau_channel *);
|
||||
extern int nv50_graph_unload_context(struct drm_device *);
|
||||
extern void nv50_graph_context_switch(struct drm_device *);
|
||||
extern int nv50_grctx_init(struct nouveau_grctx *);
|
||||
+extern void nv50_graph_tlb_flush(struct drm_device *dev);
|
||||
+extern void nv86_graph_tlb_flush(struct drm_device *dev);
|
||||
|
||||
/* nvc0_graph.c */
|
||||
extern int nvc0_graph_init(struct drm_device *);
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
|
||||
index 4f0ae39..514ad9f 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
|
||||
@@ -173,11 +173,10 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
|
||||
}
|
||||
}
|
||||
}
|
||||
- dev_priv->engine.instmem.flush(dev);
|
||||
|
||||
- nv50_vm_flush(dev, 5);
|
||||
- nv50_vm_flush(dev, 0);
|
||||
- nv50_vm_flush(dev, 4);
|
||||
+ dev_priv->engine.instmem.flush(dev);
|
||||
+ dev_priv->engine.fifo.tlb_flush(dev);
|
||||
+ dev_priv->engine.graph.tlb_flush(dev);
|
||||
nv50_vm_flush(dev, 6);
|
||||
return 0;
|
||||
}
|
||||
@@ -207,11 +206,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
|
||||
pte++;
|
||||
}
|
||||
}
|
||||
- dev_priv->engine.instmem.flush(dev);
|
||||
|
||||
- nv50_vm_flush(dev, 5);
|
||||
- nv50_vm_flush(dev, 0);
|
||||
- nv50_vm_flush(dev, 4);
|
||||
+ dev_priv->engine.instmem.flush(dev);
|
||||
+ dev_priv->engine.fifo.tlb_flush(dev);
|
||||
+ dev_priv->engine.graph.tlb_flush(dev);
|
||||
nv50_vm_flush(dev, 6);
|
||||
}
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
|
||||
index 7f028fe..d55a583 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
|
||||
@@ -120,8 +120,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
|
||||
dev_priv->engine.instmem.flush(nvbe->dev);
|
||||
|
||||
if (dev_priv->card_type == NV_50) {
|
||||
- nv50_vm_flush(dev, 5); /* PGRAPH */
|
||||
- nv50_vm_flush(dev, 0); /* PFIFO */
|
||||
+ dev_priv->engine.fifo.tlb_flush(dev);
|
||||
+ dev_priv->engine.graph.tlb_flush(dev);
|
||||
}
|
||||
|
||||
nvbe->bound = true;
|
||||
@@ -162,8 +162,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
|
||||
dev_priv->engine.instmem.flush(nvbe->dev);
|
||||
|
||||
if (dev_priv->card_type == NV_50) {
|
||||
- nv50_vm_flush(dev, 5);
|
||||
- nv50_vm_flush(dev, 0);
|
||||
+ dev_priv->engine.fifo.tlb_flush(dev);
|
||||
+ dev_priv->engine.graph.tlb_flush(dev);
|
||||
}
|
||||
|
||||
nvbe->bound = false;
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
|
||||
index be85960..47c353c 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
|
||||
@@ -333,6 +333,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
||||
engine->graph.destroy_context = nv50_graph_destroy_context;
|
||||
engine->graph.load_context = nv50_graph_load_context;
|
||||
engine->graph.unload_context = nv50_graph_unload_context;
|
||||
+ if (dev_priv->chipset != 0x86)
|
||||
+ engine->graph.tlb_flush = nv50_graph_tlb_flush;
|
||||
+ else {
|
||||
+ /* from what i can see nvidia do this on every
|
||||
+ * pre-NVA3 board except NVAC, but, we've only
|
||||
+ * ever seen problems on NV86
|
||||
+ */
|
||||
+ engine->graph.tlb_flush = nv86_graph_tlb_flush;
|
||||
+ }
|
||||
engine->fifo.channels = 128;
|
||||
engine->fifo.init = nv50_fifo_init;
|
||||
engine->fifo.takedown = nv50_fifo_takedown;
|
||||
@@ -344,6 +353,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
||||
engine->fifo.destroy_context = nv50_fifo_destroy_context;
|
||||
engine->fifo.load_context = nv50_fifo_load_context;
|
||||
engine->fifo.unload_context = nv50_fifo_unload_context;
|
||||
+ engine->fifo.tlb_flush = nv50_fifo_tlb_flush;
|
||||
engine->display.early_init = nv50_display_early_init;
|
||||
engine->display.late_takedown = nv50_display_late_takedown;
|
||||
engine->display.create = nv50_display_create;
|
||||
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
|
||||
index a46a961..1da65bd 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
|
||||
@@ -464,3 +464,8 @@ nv50_fifo_unload_context(struct drm_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+void
|
||||
+nv50_fifo_tlb_flush(struct drm_device *dev)
|
||||
+{
|
||||
+ nv50_vm_flush(dev, 5);
|
||||
+}
|
||||
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
|
||||
index cbf5ae2..8b669d0 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
|
||||
@@ -402,3 +402,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = {
|
||||
{ 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */
|
||||
{}
|
||||
};
|
||||
+
|
||||
+void
|
||||
+nv50_graph_tlb_flush(struct drm_device *dev)
|
||||
+{
|
||||
+ nv50_vm_flush(dev, 0);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+nv86_graph_tlb_flush(struct drm_device *dev)
|
||||
+{
|
||||
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
+ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
|
||||
+ bool idle, timeout = false;
|
||||
+ unsigned long flags;
|
||||
+ u64 start;
|
||||
+ u32 tmp;
|
||||
+
|
||||
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
||||
+ nv_mask(dev, 0x400500, 0x00000001, 0x00000000);
|
||||
+
|
||||
+ start = ptimer->read(dev);
|
||||
+ do {
|
||||
+ idle = true;
|
||||
+
|
||||
+ for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) {
|
||||
+ if ((tmp & 7) == 1)
|
||||
+ idle = false;
|
||||
+ }
|
||||
+
|
||||
+ for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) {
|
||||
+ if ((tmp & 7) == 1)
|
||||
+ idle = false;
|
||||
+ }
|
||||
+
|
||||
+ for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) {
|
||||
+ if ((tmp & 7) == 1)
|
||||
+ idle = false;
|
||||
+ }
|
||||
+ } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000));
|
||||
+
|
||||
+ if (timeout) {
|
||||
+ NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: "
|
||||
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
+ nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380),
|
||||
+ nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388));
|
||||
+ }
|
||||
+
|
||||
+ nv50_vm_flush(dev, 0);
|
||||
+
|
||||
+ nv_mask(dev, 0x400500, 0x00000001, 0x00000001);
|
||||
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
||||
+}
|
||||
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
|
||||
index ac3de05..c836ddc 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
|
||||
@@ -402,7 +402,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
|
||||
}
|
||||
dev_priv->engine.instmem.flush(dev);
|
||||
|
||||
- nv50_vm_flush(dev, 4);
|
||||
nv50_vm_flush(dev, 6);
|
||||
|
||||
gpuobj->im_bound = 1;
|
||||
--
|
||||
1.7.3.1
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
From 07a51882863d9e45b0715dcffbb66491adf2fb4e Mon Sep 17 00:00:00 2001
|
||||
From: Ben Skeggs <bskeggs@redhat.com>
|
||||
Date: Wed, 30 Jun 2010 13:34:05 +1000
|
||||
Subject: [PATCH] drm/nouveau: disable acceleration on NVA3/NVA5/NVA8 by default
|
||||
|
||||
There's an GPU lockup problem for which the cause is currently unknown
|
||||
on these chipsets.
|
||||
|
||||
Until it's resolved, it's better to leave the user with a working system
|
||||
without acceleration than to have random lockups.
|
||||
|
||||
With this patch, acceleration will be off by default if a known problem
|
||||
chipset is detected, but can be re-enabled with nouveau.noaccel=0 on
|
||||
the kernel commandline.
|
||||
|
||||
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/nouveau/nouveau_drv.c | 2 +-
|
||||
drivers/gpu/drm/nouveau/nouveau_drv.h | 1 +
|
||||
drivers/gpu/drm/nouveau/nouveau_state.c | 23 +++++++++++++++++++----
|
||||
3 files changed, 21 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
|
||||
index 946748a..9b69328 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
|
||||
@@ -72,7 +72,7 @@ int nouveau_ignorelid = 0;
|
||||
module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
|
||||
|
||||
MODULE_PARM_DESC(noaccel, "Disable all acceleration");
|
||||
-int nouveau_noaccel = 0;
|
||||
+int nouveau_noaccel = -1;
|
||||
module_param_named(noaccel, nouveau_noaccel, int, 0400);
|
||||
|
||||
MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
|
||||
index 24b3d03..0cf1bee 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
|
||||
@@ -504,6 +504,7 @@ enum nouveau_card_type {
|
||||
|
||||
struct drm_nouveau_private {
|
||||
struct drm_device *dev;
|
||||
+ bool noaccel;
|
||||
|
||||
/* the card type, takes NV_* as values */
|
||||
enum nouveau_card_type card_type;
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
|
||||
index be85960..896f6ae 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
|
||||
@@ -563,7 +563,7 @@ nouveau_card_init(struct drm_device *dev)
|
||||
if (ret)
|
||||
goto out_timer;
|
||||
|
||||
- if (nouveau_noaccel)
|
||||
+ if (dev_priv->noaccel)
|
||||
engine->graph.accel_blocked = true;
|
||||
else {
|
||||
/* PGRAPH */
|
||||
@@ -613,10 +613,10 @@ out_irq:
|
||||
out_display:
|
||||
engine->display.destroy(dev);
|
||||
out_fifo:
|
||||
- if (!nouveau_noaccel)
|
||||
+ if (!dev_priv->noaccel)
|
||||
engine->fifo.takedown(dev);
|
||||
out_graph:
|
||||
- if (!nouveau_noaccel)
|
||||
+ if (!dev_priv->noaccel)
|
||||
engine->graph.takedown(dev);
|
||||
out_fb:
|
||||
engine->fb.takedown(dev);
|
||||
@@ -655,7 +655,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
|
||||
dev_priv->channel = NULL;
|
||||
}
|
||||
|
||||
- if (!nouveau_noaccel) {
|
||||
+ if (!dev_priv->noaccel) {
|
||||
engine->fifo.takedown(dev);
|
||||
engine->graph.takedown(dev);
|
||||
}
|
||||
@@ -861,6 +861,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
|
||||
if (ret)
|
||||
goto err_mmio;
|
||||
|
||||
+ if (nouveau_noaccel == -1) {
|
||||
+ switch (dev_priv->chipset) {
|
||||
+ case 0xa3:
|
||||
+ case 0xa5:
|
||||
+ case 0xa8:
|
||||
+ dev_priv->noaccel = true;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_priv->noaccel = false;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ dev_priv->noaccel = (nouveau_noaccel != 0);
|
||||
+ }
|
||||
+
|
||||
/* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
|
||||
if (dev_priv->card_type >= NV_40) {
|
||||
int ramin_bar = 2;
|
||||
--
|
||||
1.7.2.2
|
|
@ -0,0 +1,25 @@
|
|||
From 7abba51e3fc9e3fdd43c63eeb1a680a2e258a833 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Skeggs <bskeggs@redhat.com>
|
||||
Date: Fri, 19 Nov 2010 18:59:15 +1000
|
||||
Subject: [PATCH] drm-nouveau-nvaf-grclass
|
||||
|
||||
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/nouveau/nv50_graph.c | 1 +
|
||||
1 files changed, 1 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
|
||||
index 8b669d0..235be5f 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
|
||||
@@ -400,6 +400,7 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = {
|
||||
{ 0x8297, false, NULL }, /* tesla (nv8x/nv9x) */
|
||||
{ 0x8397, false, NULL }, /* tesla (nva0, nvaa, nvac) */
|
||||
{ 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */
|
||||
+ { 0x8697, false, NULL }, /* tesla (nvaf) */
|
||||
{}
|
||||
};
|
||||
|
||||
--
|
||||
1.7.3.2
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
From 4733f633c4bfb0672d5bd88a8d19a03e27a3c1d0 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Skeggs <bskeggs@redhat.com>
|
||||
Date: Fri, 23 Jul 2010 09:06:52 +1000
|
||||
Subject: [PATCH 2/2] drm-nouveau-race-fix
|
||||
|
||||
drm/nouveau: fix race condition when under memory pressure
|
||||
|
||||
rhbz#602663
|
||||
|
||||
When VRAM is running out it's possible that the client's push buffers get
|
||||
evicted to main memory. When they're validated back in, the GPU may
|
||||
be used for the copy back to VRAM, but the existing synchronisation code
|
||||
only deals with inter-channel sync, not sync between PFIFO and PGRAPH on
|
||||
the same channel. This leads to PFIFO fetching from command buffers that
|
||||
haven't quite been copied by PGRAPH yet.
|
||||
|
||||
This patch marks push buffers as so, and forces any GPU-assisted buffer
|
||||
moves to be done on a different channel, which triggers the correct
|
||||
synchronisation to happen before we submit them.
|
||||
|
||||
After discussion with another nouveau developer, it was agreed that while
|
||||
this patch is fine in itself, that we'd prefer to work out a nicer, but
|
||||
likely much more invasive, fix upstream.
|
||||
|
||||
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/nouveau/nouveau_bo.c | 15 +++++++++++++
|
||||
drivers/gpu/drm/nouveau/nouveau_drv.h | 1 +
|
||||
drivers/gpu/drm/nouveau/nouveau_gem.c | 36 +++++++++++++++++++++++---------
|
||||
3 files changed, 42 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
|
||||
index 553a01d..5e62d1b 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
|
||||
@@ -36,6 +36,21 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
+int
|
||||
+nouveau_bo_sync_gpu(struct nouveau_bo *nvbo, struct nouveau_channel *chan)
|
||||
+{
|
||||
+ struct nouveau_fence *prev_fence = nvbo->bo.sync_obj;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!prev_fence || nouveau_fence_channel(prev_fence) == chan)
|
||||
+ return 0;
|
||||
+
|
||||
+ spin_lock(&nvbo->bo.lock);
|
||||
+ ret = ttm_bo_wait(&nvbo->bo, false, false, false);
|
||||
+ spin_unlock(&nvbo->bo.lock);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
|
||||
{
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
|
||||
index 2eb622b..70a16f3 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
|
||||
@@ -1167,6 +1167,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index);
|
||||
extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
|
||||
extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
|
||||
extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val);
|
||||
+extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
|
||||
|
||||
/* nouveau_fence.c */
|
||||
struct nouveau_fence;
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
|
||||
index 62ac673..613f878 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
|
||||
@@ -361,16 +361,11 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
|
||||
|
||||
list_for_each_entry(nvbo, list, entry) {
|
||||
struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
|
||||
- struct nouveau_fence *prev_fence = nvbo->bo.sync_obj;
|
||||
|
||||
- if (prev_fence && nouveau_fence_channel(prev_fence) != chan) {
|
||||
- spin_lock(&nvbo->bo.lock);
|
||||
- ret = ttm_bo_wait(&nvbo->bo, false, false, false);
|
||||
- spin_unlock(&nvbo->bo.lock);
|
||||
- if (unlikely(ret)) {
|
||||
- NV_ERROR(dev, "fail wait other chan\n");
|
||||
- return ret;
|
||||
- }
|
||||
+ ret = nouveau_bo_sync_gpu(nvbo, chan);
|
||||
+ if (unlikely(ret)) {
|
||||
+ NV_ERROR(dev, "fail pre-validate sync\n");
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains,
|
||||
@@ -381,7 +376,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
|
||||
return ret;
|
||||
}
|
||||
|
||||
- nvbo->channel = chan;
|
||||
+ nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan;
|
||||
ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement,
|
||||
false, false, false);
|
||||
nvbo->channel = NULL;
|
||||
@@ -390,6 +385,12 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ ret = nouveau_bo_sync_gpu(nvbo, chan);
|
||||
+ if (unlikely(ret)) {
|
||||
+ NV_ERROR(dev, "fail post-validate sync\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
if (nvbo->bo.offset == b->presumed.offset &&
|
||||
((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
|
||||
b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
|
||||
@@ -615,6 +616,21 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
+ /* Mark push buffers as being used on PFIFO, the validation code
|
||||
+ * will then make sure that if the pushbuf bo moves, that they
|
||||
+ * happen on the kernel channel, which will in turn cause a sync
|
||||
+ * to happen before we try and submit the push buffer.
|
||||
+ */
|
||||
+ for (i = 0; i < req->nr_push; i++) {
|
||||
+ if (push[i].bo_index >= req->nr_buffers) {
|
||||
+ NV_ERROR(dev, "push %d buffer not in list\n", i);
|
||||
+ ret = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ bo[push[i].bo_index].read_domains |= (1 << 31);
|
||||
+ }
|
||||
+
|
||||
/* Validate buffer list */
|
||||
ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers,
|
||||
req->nr_buffers, &op, &do_reloc);
|
||||
--
|
||||
1.7.2.2
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,601 @@
|
|||
commit 879d56da9b89b52de2109cadf1369967522428e8
|
||||
Author: Dave Airlie <airlied@redhat.com>
|
||||
Date: Tue Oct 26 12:55:52 2010 +1000
|
||||
|
||||
drm/radeon/kms: don't poll dac load detect.
|
||||
|
||||
This is slightly destructive, cpu intensive and can cause lockups.
|
||||
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit 2563a90cdda1fe490947dc032ce17bf1118afc39
|
||||
Author: Dave Airlie <airlied@redhat.com>
|
||||
Date: Tue Nov 9 10:26:00 2010 +1000
|
||||
|
||||
drm: Use a nondestructive mode for output detect when polling (v2)
|
||||
|
||||
v2: Julien Cristau pointed out that @nondestructive results in
|
||||
double-negatives and confusion when trying to interpret the parameter,
|
||||
so use @force instead. Much easier to type as well. ;-)
|
||||
|
||||
And fix the miscompilation of vmgfx reported by Sedat Dilek.
|
||||
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Cc: stable@kernel.org
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
|
||||
drivers/gpu/drm/i915/intel_tv.c
|
||||
drivers/gpu/drm/nouveau/nouveau_connector.c
|
||||
|
||||
commit deb557bbbcaa7fa8281d51490c73b51f579bc84d
|
||||
Author: Dave Airlie <airlied@redhat.com>
|
||||
Date: Tue Nov 9 10:24:06 2010 +1000
|
||||
|
||||
drm: Use a nondestructive mode for output detect when polling
|
||||
|
||||
Destructive load-detection is very expensive and due to failings
|
||||
elsewhere can trigger system wide stalls of up to 600ms. A simple
|
||||
first step to correcting this is not to invoke such an expensive
|
||||
and destructive load-detection operation automatically.
|
||||
|
||||
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29536
|
||||
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=16265
|
||||
Reported-by: Bruno Prémont <bonbons@linux-vserver.org>
|
||||
Tested-by: Sitsofe Wheeler <sitsofe@yahoo.com>
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Cc: stable@kernel.org
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
|
||||
drivers/gpu/drm/i915/intel_tv.c
|
||||
drivers/gpu/drm/nouveau/nouveau_connector.c
|
||||
|
||||
commit 8d5d3cd3612618a3c2214048788f0b2cc463ce0f
|
||||
Author: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Date: Mon Sep 6 23:53:47 2010 +0100
|
||||
|
||||
drm: Fix regression in disable polling e58f637
|
||||
|
||||
I broke out my trusty i845 and found a new boot failure, which upon
|
||||
inspection turned out to be a recursion within:
|
||||
|
||||
drm_helper_probe_single_connector_modes() -> drm_helper_hpd_irq_event()
|
||||
-> intel_crt_detect() -> drm_helper_probe_single_connector_modes()
|
||||
|
||||
Calling drm_kms_helper_poll_enable() instead performs the desired
|
||||
re-initialisation of the polling should the user have toggled the
|
||||
parameter, without the recursive side-effect.
|
||||
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Cc: Dave Airlie <airlied@redhat.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit ec0becade1eae9b0f40b12ea4fcc3ea36e993ba3
|
||||
Author: Dave Airlie <airlied@redhat.com>
|
||||
Date: Tue Nov 9 09:48:34 2010 +1000
|
||||
|
||||
drm/kms: Add a module parameter to disable polling
|
||||
|
||||
Polling for a VGA device on an old system can be quite expensive,
|
||||
causing latencies on the order of 600ms. As we hold the mode mutex for
|
||||
this time and also need the same mutex to move the cursor, we trigger a
|
||||
user-visible stall.
|
||||
|
||||
The real solution would involve improving the granulatity of the
|
||||
locking and so perhaps performing some of the probing not under the lock
|
||||
or some other updates can be done under different locks. Also reducing the
|
||||
cost of probing for a non-existent monitor would be worthwhile. However,
|
||||
exposing a parameter to disable polling is a simple workaround in the
|
||||
meantime.
|
||||
|
||||
In order to accommodate users turning polling on and off at runtime, the
|
||||
polling is potentially re-enabled on every probe. This is coupled to
|
||||
the user calling xrandr, which seems to be a vaild time to reset the
|
||||
polling timeout since the information on the connection has just been
|
||||
updated. (The presumption being that all connections are probed in a
|
||||
single xrandr pass, which is currently valid.)
|
||||
|
||||
References:
|
||||
|
||||
Bug 29536 - 2.6.35 causes ~600ms latency every 10s
|
||||
https://bugs.freedesktop.org/show_bug.cgi?id=29536
|
||||
|
||||
Bug 16265 - Why is kslowd accumulating so much CPU time?
|
||||
https://bugzilla.kernel.org/show_bug.cgi?id=16265
|
||||
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Reported-and-tested-by: Bruno Prémont <bonbons@linux-vserver.org>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
|
||||
drivers/gpu/drm/drm_crtc_helper.c
|
||||
|
||||
commit 77e90256db2f7e6424717f7cc984b22d2832243f
|
||||
Author: Dan Carpenter <error27@gmail.com>
|
||||
Date: Thu Aug 19 11:46:29 2010 +0200
|
||||
|
||||
drm: move dereference below check
|
||||
|
||||
"fb_helper_conn" is dereferenced before the check for NULL. It's never
|
||||
actually NULL here, so this is mostly to keep the static checkers happy.
|
||||
|
||||
Signed-off-by: Dan Carpenter <error27@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit 86e25290d9df7a84d185dfc037851d72d270a6c0
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Tue Jul 20 03:24:11 2010 -0400
|
||||
|
||||
drm/radeon/kms: make sure HPD is set to NONE on analog-only connectors
|
||||
|
||||
HPD is digital only.
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
|
||||
index 25d70d6..d537039 100644
|
||||
--- a/drivers/gpu/drm/drm_crtc_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_crtc_helper.c
|
||||
@@ -34,6 +34,9 @@
|
||||
#include "drm_crtc_helper.h"
|
||||
#include "drm_fb_helper.h"
|
||||
|
||||
+static bool drm_kms_helper_poll = true;
|
||||
+module_param_named(poll, drm_kms_helper_poll, bool, 0600);
|
||||
+
|
||||
static void drm_mode_validate_flag(struct drm_connector *connector,
|
||||
int flags)
|
||||
{
|
||||
@@ -98,8 +101,10 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
||||
connector->status = connector_status_disconnected;
|
||||
if (connector->funcs->force)
|
||||
connector->funcs->force(connector);
|
||||
- } else
|
||||
- connector->status = connector->funcs->detect(connector);
|
||||
+ } else {
|
||||
+ connector->status = connector->funcs->detect(connector, true);
|
||||
+ drm_kms_helper_poll_enable(dev);
|
||||
+ }
|
||||
|
||||
if (connector->status == connector_status_disconnected) {
|
||||
DRM_DEBUG_KMS("%s is disconnected\n",
|
||||
@@ -820,6 +825,9 @@ static void output_poll_execute(struct slow_work *work)
|
||||
bool repoll = false, changed = false;
|
||||
int ret;
|
||||
|
||||
+ if (!drm_kms_helper_poll)
|
||||
+ return;
|
||||
+
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
|
||||
@@ -839,7 +847,7 @@ static void output_poll_execute(struct slow_work *work)
|
||||
!(connector->polled & DRM_CONNECTOR_POLL_HPD))
|
||||
continue;
|
||||
|
||||
- status = connector->funcs->detect(connector);
|
||||
+ status = connector->funcs->detect(connector, false);
|
||||
if (old_status != status)
|
||||
changed = true;
|
||||
}
|
||||
@@ -874,6 +882,9 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
|
||||
struct drm_connector *connector;
|
||||
int ret;
|
||||
|
||||
+ if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll)
|
||||
+ return;
|
||||
+
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->polled)
|
||||
poll = true;
|
||||
@@ -909,9 +920,12 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
|
||||
{
|
||||
if (!dev->mode_config.poll_enabled)
|
||||
return;
|
||||
+
|
||||
delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
|
||||
/* schedule a slow work asap */
|
||||
- delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
|
||||
+ if (drm_kms_helper_poll)
|
||||
+ delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
|
||||
+
|
||||
}
|
||||
EXPORT_SYMBOL(drm_helper_hpd_irq_event);
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
|
||||
index 7196620..cef8d8d 100644
|
||||
--- a/drivers/gpu/drm/drm_fb_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_fb_helper.c
|
||||
@@ -94,10 +94,11 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_conn
|
||||
int i;
|
||||
enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
|
||||
struct drm_fb_helper_cmdline_mode *cmdline_mode;
|
||||
- struct drm_connector *connector = fb_helper_conn->connector;
|
||||
+ struct drm_connector *connector;
|
||||
|
||||
if (!fb_helper_conn)
|
||||
return false;
|
||||
+ connector = fb_helper_conn->connector;
|
||||
|
||||
cmdline_mode = &fb_helper_conn->cmdline_mode;
|
||||
if (!mode_option)
|
||||
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
|
||||
index 101d381..9500af1 100644
|
||||
--- a/drivers/gpu/drm/drm_sysfs.c
|
||||
+++ b/drivers/gpu/drm/drm_sysfs.c
|
||||
@@ -159,7 +159,7 @@ static ssize_t status_show(struct device *device,
|
||||
struct drm_connector *connector = to_drm_connector(device);
|
||||
enum drm_connector_status status;
|
||||
|
||||
- status = connector->funcs->detect(connector);
|
||||
+ status = connector->funcs->detect(connector, true);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
drm_get_connector_status_name(status));
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
|
||||
index ee0732b..3886b47 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_crt.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_crt.c
|
||||
@@ -402,7 +402,8 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
|
||||
return status;
|
||||
}
|
||||
|
||||
-static enum drm_connector_status intel_crt_detect(struct drm_connector *connector)
|
||||
+static enum drm_connector_status
|
||||
+intel_crt_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||
@@ -421,6 +422,9 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto
|
||||
if (intel_crt_detect_ddc(encoder))
|
||||
return connector_status_connected;
|
||||
|
||||
+ if (!force)
|
||||
+ return connector->status;
|
||||
+
|
||||
/* for pre-945g platforms use load detect */
|
||||
if (encoder->crtc && encoder->crtc->enabled) {
|
||||
status = intel_crt_load_detect(encoder->crtc, intel_encoder);
|
||||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
|
||||
index d9de8f1..b58249d 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_dp.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_dp.c
|
||||
@@ -1287,7 +1287,7 @@ ironlake_dp_detect(struct drm_connector *connector)
|
||||
* \return false if DP port is disconnected.
|
||||
*/
|
||||
static enum drm_connector_status
|
||||
-intel_dp_detect(struct drm_connector *connector)
|
||||
+intel_dp_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
|
||||
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
|
||||
index 227feca..48a1889 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_dvo.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_dvo.c
|
||||
@@ -211,7 +211,8 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
|
||||
*
|
||||
* Unimplemented.
|
||||
*/
|
||||
-static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector)
|
||||
+static enum drm_connector_status
|
||||
+intel_dvo_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
|
||||
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
|
||||
index 83bd764..d1decfc 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_hdmi.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
|
||||
@@ -134,7 +134,7 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
-intel_hdmi_detect(struct drm_connector *connector)
|
||||
+intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
|
||||
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
|
||||
index 7d42ff1..9ad3425 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_lvds.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_lvds.c
|
||||
@@ -546,7 +546,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
|
||||
* connected and closed means disconnected. We also send hotplug events as
|
||||
* needed, using lid status notification from the input layer.
|
||||
*/
|
||||
-static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector)
|
||||
+static enum drm_connector_status
|
||||
+intel_lvds_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
enum drm_connector_status status = connector_status_connected;
|
||||
@@ -641,7 +642,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||
* the LID nofication event.
|
||||
*/
|
||||
if (connector)
|
||||
- connector->status = connector->funcs->detect(connector);
|
||||
+ connector->status = connector->funcs->detect(connector,
|
||||
+ false);
|
||||
+
|
||||
/* Don't force modeset on machines where it causes a GPU lockup */
|
||||
if (dmi_check_system(intel_no_modeset_on_lid))
|
||||
return NOTIFY_OK;
|
||||
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
|
||||
index 76993ac..76c9b3d 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_sdvo.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
|
||||
@@ -1496,7 +1496,7 @@ intel_analog_is_connected(struct drm_device *dev)
|
||||
if (!analog_connector)
|
||||
return false;
|
||||
|
||||
- if (analog_connector->funcs->detect(analog_connector) ==
|
||||
+ if (analog_connector->funcs->detect(analog_connector, false) ==
|
||||
connector_status_disconnected)
|
||||
return false;
|
||||
|
||||
@@ -1567,7 +1567,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
|
||||
return status;
|
||||
}
|
||||
|
||||
-static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
|
||||
+static enum drm_connector_status
|
||||
+intel_sdvo_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
uint16_t response;
|
||||
u8 status;
|
||||
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
|
||||
index 6d553c2..ad40f1b 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_tv.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_tv.c
|
||||
@@ -1336,7 +1336,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector)
|
||||
* we have a pipe programmed in order to probe the TV.
|
||||
*/
|
||||
static enum drm_connector_status
|
||||
-intel_tv_detect(struct drm_connector *connector)
|
||||
+intel_tv_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_display_mode mode;
|
||||
@@ -1351,7 +1351,7 @@ intel_tv_detect(struct drm_connector *connector)
|
||||
|
||||
if (encoder->crtc && encoder->crtc->enabled) {
|
||||
type = intel_tv_detect_type(encoder->crtc, intel_encoder);
|
||||
- } else {
|
||||
+ } else if (force) {
|
||||
crtc = intel_get_load_detect_pipe(intel_encoder, connector,
|
||||
&mode, &dpms_mode);
|
||||
if (crtc) {
|
||||
@@ -1359,8 +1359,9 @@ intel_tv_detect(struct drm_connector *connector)
|
||||
intel_release_load_detect_pipe(intel_encoder, connector,
|
||||
dpms_mode);
|
||||
} else
|
||||
- type = -1;
|
||||
- }
|
||||
+ return connector_status_unknown;
|
||||
+ } else
|
||||
+ return connector->status;
|
||||
|
||||
tv_priv->type = type;
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
|
||||
index 149ed22..1085376 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
|
||||
@@ -228,7 +228,7 @@ nouveau_connector_set_encoder(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
-nouveau_connector_detect(struct drm_connector *connector)
|
||||
+nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
||||
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
|
||||
index adccbc2..1680600 100644
|
||||
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
|
||||
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
|
||||
@@ -467,7 +467,8 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector,
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
-static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector)
|
||||
+static enum drm_connector_status
|
||||
+radeon_lvds_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||
struct drm_encoder *encoder = radeon_best_single_encoder(connector);
|
||||
@@ -582,7 +583,8 @@ static int radeon_vga_mode_valid(struct drm_connector *connector,
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
-static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector)
|
||||
+static enum drm_connector_status
|
||||
+radeon_vga_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||
struct drm_encoder *encoder;
|
||||
@@ -621,6 +623,11 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect
|
||||
ret = connector_status_connected;
|
||||
}
|
||||
} else {
|
||||
+
|
||||
+ /* if we aren't forcing don't do destructive polling */
|
||||
+ if (!force)
|
||||
+ return connector->status;
|
||||
+
|
||||
if (radeon_connector->dac_load_detect && encoder) {
|
||||
encoder_funcs = encoder->helper_private;
|
||||
ret = encoder_funcs->detect(encoder, connector);
|
||||
@@ -679,7 +686,8 @@ static int radeon_tv_mode_valid(struct drm_connector *connector,
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
-static enum drm_connector_status radeon_tv_detect(struct drm_connector *connector)
|
||||
+static enum drm_connector_status
|
||||
+radeon_tv_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
@@ -736,7 +744,8 @@ static int radeon_dvi_get_modes(struct drm_connector *connector)
|
||||
* we have to check if this analog encoder is shared with anyone else (TV)
|
||||
* if its shared we have to set the other connector to disconnected.
|
||||
*/
|
||||
-static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector)
|
||||
+static enum drm_connector_status
|
||||
+radeon_dvi_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||
struct drm_encoder *encoder = NULL;
|
||||
@@ -806,6 +815,11 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
|
||||
if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
|
||||
goto out;
|
||||
|
||||
+ if (!force) {
|
||||
+ ret = connector->status;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
/* find analog encoder */
|
||||
if (radeon_connector->dac_load_detect) {
|
||||
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
|
||||
@@ -962,7 +976,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static enum drm_connector_status radeon_dp_detect(struct drm_connector *connector)
|
||||
+static enum drm_connector_status
|
||||
+radeon_dp_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||
enum drm_connector_status ret = connector_status_disconnected;
|
||||
@@ -1082,6 +1097,8 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.load_detect_property,
|
||||
1);
|
||||
+ /* no HPD on analog connectors */
|
||||
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
|
||||
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
connector->interlace_allowed = true;
|
||||
connector->doublescan_allowed = true;
|
||||
@@ -1096,6 +1113,8 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.load_detect_property,
|
||||
1);
|
||||
+ /* no HPD on analog connectors */
|
||||
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
|
||||
connector->interlace_allowed = true;
|
||||
connector->doublescan_allowed = true;
|
||||
break;
|
||||
@@ -1186,6 +1205,8 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.tv_std_property,
|
||||
radeon_atombios_get_tv_info(rdev));
|
||||
+ /* no HPD on analog connectors */
|
||||
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
|
||||
}
|
||||
connector->interlace_allowed = false;
|
||||
connector->doublescan_allowed = false;
|
||||
@@ -1209,7 +1230,7 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
- if (hpd->hpd == RADEON_HPD_NONE) {
|
||||
+ if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
|
||||
if (i2c_bus->valid)
|
||||
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
} else
|
||||
@@ -1276,6 +1297,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.load_detect_property,
|
||||
1);
|
||||
+ /* no HPD on analog connectors */
|
||||
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
|
||||
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
connector->interlace_allowed = true;
|
||||
connector->doublescan_allowed = true;
|
||||
@@ -1290,6 +1313,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.load_detect_property,
|
||||
1);
|
||||
+ /* no HPD on analog connectors */
|
||||
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
|
||||
connector->interlace_allowed = true;
|
||||
connector->doublescan_allowed = true;
|
||||
break;
|
||||
@@ -1328,6 +1353,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.tv_std_property,
|
||||
radeon_combios_get_tv_info(rdev));
|
||||
+ /* no HPD on analog connectors */
|
||||
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
|
||||
}
|
||||
connector->interlace_allowed = false;
|
||||
connector->doublescan_allowed = false;
|
||||
@@ -1345,7 +1372,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
- if (hpd->hpd == RADEON_HPD_NONE) {
|
||||
+ if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
|
||||
if (i2c_bus->valid)
|
||||
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
} else
|
||||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
|
||||
index cfaf690..5b638cb 100644
|
||||
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
|
||||
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
|
||||
@@ -335,7 +335,8 @@ static void vmw_ldu_connector_restore(struct drm_connector *connector)
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
- vmw_ldu_connector_detect(struct drm_connector *connector)
|
||||
+ vmw_ldu_connector_detect(struct drm_connector *connector,
|
||||
+ bool force)
|
||||
{
|
||||
if (vmw_connector_to_ldu(connector)->pref_active)
|
||||
return connector_status_connected;
|
||||
@@ -516,7 +517,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
|
||||
drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
- connector->status = vmw_ldu_connector_detect(connector);
|
||||
+ connector->status = vmw_ldu_connector_detect(connector, true);
|
||||
|
||||
drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
@@ -610,7 +611,7 @@ int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num,
|
||||
ldu->pref_height = 600;
|
||||
ldu->pref_active = false;
|
||||
}
|
||||
- con->status = vmw_ldu_connector_detect(con);
|
||||
+ con->status = vmw_ldu_connector_detect(con, true);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
|
||||
index 93a1a31..afbb578 100644
|
||||
--- a/include/drm/drm_crtc.h
|
||||
+++ b/include/drm/drm_crtc.h
|
||||
@@ -420,7 +420,15 @@ struct drm_connector_funcs {
|
||||
void (*dpms)(struct drm_connector *connector, int mode);
|
||||
void (*save)(struct drm_connector *connector);
|
||||
void (*restore)(struct drm_connector *connector);
|
||||
- enum drm_connector_status (*detect)(struct drm_connector *connector);
|
||||
+
|
||||
+ /* Check to see if anything is attached to the connector.
|
||||
+ * @force is set to false whilst polling, true when checking the
|
||||
+ * connector due to user request. @force can be used by the driver
|
||||
+ * to avoid expensive, destructive operations during automated
|
||||
+ * probing.
|
||||
+ */
|
||||
+ enum drm_connector_status (*detect)(struct drm_connector *connector,
|
||||
+ bool force);
|
||||
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
|
||||
int (*set_property)(struct drm_connector *connector, struct drm_property *property,
|
||||
uint64_t val);
|
|
@ -0,0 +1,854 @@
|
|||
commit 4adf332cc24ee2d46064aaafd8216169d29566d5
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Sun Nov 14 20:24:35 2010 -0500
|
||||
|
||||
drm/radeon/kms: fix and unify tiled buffer alignment checking for r6xx/7xx
|
||||
|
||||
Tiled buffers have the same alignment requirements regardless of
|
||||
whether the surface is for db, cb, or textures. Previously, the
|
||||
calculations where inconsistent for each buffer type.
|
||||
|
||||
- Unify the alignment calculations in a common function
|
||||
- Standardize the alignment units (pixels for pitch/height/depth,
|
||||
bytes for base)
|
||||
- properly check the buffer base alignments
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit c37cb9e61dce7437f63280d9347a9ffdf4ec34e7
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Wed Oct 27 01:44:35 2010 -0400
|
||||
|
||||
drm/radeon/kms: fix tiled db height calculation on 6xx/7xx
|
||||
|
||||
Calculate height based on the slice bitfield rather than the size.
|
||||
Same as Dave's CB fix.
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit b80c8fdc2fadd8182b958e91a10f2fa287f993e4
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Tue Oct 26 20:22:42 2010 -0400
|
||||
|
||||
drm/radeon/kms: fix r6xx/7xx 1D tiling CS checker v2
|
||||
|
||||
broken by:
|
||||
drm/radeon/r600: fix tiling issues in CS checker.
|
||||
|
||||
v2: only apply it to 1D tiling case.
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit 4336ac5c0a4e5dfbb51631ad680d6a5d0b295cd3
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Mon Oct 18 23:45:39 2010 -0400
|
||||
|
||||
drm/radeon/kms: fix 2D tile height alignment in the r600 CS checker
|
||||
|
||||
macro tile heights are aligned to num channels, not num banks.
|
||||
|
||||
Noticed by Dave Airlie.
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Cc: stable@kernel.org
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit 5c76976a1419a633f9f33c6547bae00348b855d2
|
||||
Author: Dave Airlie <airlied@redhat.com>
|
||||
Date: Thu Oct 21 13:55:40 2010 +1000
|
||||
|
||||
drm/radeon/r600: fix tiling issues in CS checker.
|
||||
|
||||
The CS checker had some incorrect alignment requirements for 2D surfaces,
|
||||
this made rendering to mipmap levels that were 2D broken.
|
||||
|
||||
Also the CB height was being worked out from the BO size, this doesn't work
|
||||
at all when rendering mipmap levels, instead we work out what height userspace
|
||||
wanted from slice max and use that to check it fits inside the BO, however
|
||||
the DDX send the wrong slice max for an unaligned buffer so we have to workaround
|
||||
for that even though its a userspace bug.
|
||||
|
||||
Reviewed-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit fa479e9df4558af6f091c45be37f713e64b836a1
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Tue Sep 14 10:10:47 2010 -0400
|
||||
|
||||
drm/radeon/kms: only warn on mipmap size checks in r600 cs checker (v2)
|
||||
|
||||
The texture base address registers are in units of 256 bytes.
|
||||
The original CS checker treated these offsets as bytes, so the
|
||||
original check was wrong. I fixed the units in a patch during
|
||||
the 2.6.36 cycle, but this ended up breaking some existing
|
||||
userspace (probably due to a bug in either userspace texture allocation
|
||||
or the drm texture mipmap checker). So for now, until we come
|
||||
up with a better fix, just warn if the mipmap size it too large.
|
||||
This will keep existing userspace working and it should be just
|
||||
as safe as before when we were checking the wrong units. These
|
||||
are GPU MC addresses, so if they fall outside of the VRAM or
|
||||
GART apertures, they end up at the GPU default page, so this should
|
||||
be safe from a security perspective.
|
||||
|
||||
v2: Just disable the warning. It just spams the log and there's
|
||||
nothing the user can do about it.
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Cc: Jerome Glisse <glisse@freedesktop.org>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit 6e8df81d43d5c95fe37db7f0ef55332de1a4b698
|
||||
Author: Dave Airlie <airlied@redhat.com>
|
||||
Date: Thu Aug 12 09:40:05 2010 +1000
|
||||
|
||||
drm/radeon: drop old and broken mesa warning
|
||||
|
||||
This never really got fixed in mesa, and the kernel deals with the problem
|
||||
just fine, so don't got reporting things that confuse people.
|
||||
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit 23f012fb9a0633f2f8901440e314d6276255b1c0
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Wed Aug 11 11:54:25 2010 -0400
|
||||
|
||||
drm/radeon/kms: another r6xx/r7xx CS checker fix
|
||||
|
||||
add default case for buffer formats
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Cc: Andre Maasikas <amaasikas@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit 2c7e76decda2d437f0ca064fef1a2d5d8892288e
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Fri Aug 6 02:54:05 2010 -0400
|
||||
|
||||
drm/radeon/kms: r600 CS parser fixes
|
||||
|
||||
- buffer offsets in the base regs are 256b aligned so
|
||||
shift properly when comparing, fixed by Andre Maasikas
|
||||
- mipmap size was calculated wrong when nlevel=0
|
||||
- texture bo offsets were used after the bo base address was added
|
||||
- vertex resource size register is size - 1, not size
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Cc: Andre Maasikas <amaasikas@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit 85d1363c9f15b5d4303b635142cee0ba9d1473fc
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Fri Jun 4 18:41:42 2010 -0400
|
||||
|
||||
drm/radeon/kms: fix CS alignment checking for tiling (v2)
|
||||
|
||||
Covers depth, cb, and textures. Hopefully I got this right.
|
||||
|
||||
v2: - fix bugs:
|
||||
https://bugs.freedesktop.org/show_bug.cgi?id=28327
|
||||
https://bugs.freedesktop.org/show_bug.cgi?id=28381
|
||||
- use ALIGNED(), IS_ALIGNED() macros
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
commit b956b6e7c7fb207daf32520c0a72c8c06ef1d5f5
|
||||
Author: Alex Deucher <alexdeucher@gmail.com>
|
||||
Date: Thu May 20 12:43:52 2010 -0400
|
||||
|
||||
drm/radeon/kms: add tiling support to the cs checker for r6xx/r7xx
|
||||
|
||||
Check for relocs for DB_DEPTH_INFO, CB_COLOR*_INFO, and texture
|
||||
resources.
|
||||
|
||||
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
|
||||
drivers/gpu/drm/radeon/r600_cs.c | 391 ++++++++++++++++++++++++++++++--------
|
||||
drivers/gpu/drm/radeon/r600d.h | 12 ++
|
||||
2 files changed, 324 insertions(+), 79 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
|
||||
index 144c32d..0f90fc3 100644
|
||||
--- a/drivers/gpu/drm/radeon/r600_cs.c
|
||||
+++ b/drivers/gpu/drm/radeon/r600_cs.c
|
||||
@@ -25,6 +25,7 @@
|
||||
* Alex Deucher
|
||||
* Jerome Glisse
|
||||
*/
|
||||
+#include <linux/kernel.h>
|
||||
#include "drmP.h"
|
||||
#include "radeon.h"
|
||||
#include "r600d.h"
|
||||
@@ -49,6 +50,7 @@ struct r600_cs_track {
|
||||
u32 nsamples;
|
||||
u32 cb_color_base_last[8];
|
||||
struct radeon_bo *cb_color_bo[8];
|
||||
+ u64 cb_color_bo_mc[8];
|
||||
u32 cb_color_bo_offset[8];
|
||||
struct radeon_bo *cb_color_frag_bo[8];
|
||||
struct radeon_bo *cb_color_tile_bo[8];
|
||||
@@ -66,6 +68,7 @@ struct r600_cs_track {
|
||||
u32 db_depth_size;
|
||||
u32 db_offset;
|
||||
struct radeon_bo *db_bo;
|
||||
+ u64 db_bo_mc;
|
||||
};
|
||||
|
||||
static inline int r600_bpe_from_format(u32 *bpe, u32 format)
|
||||
@@ -132,12 +135,75 @@ static inline int r600_bpe_from_format(u32 *bpe, u32 format)
|
||||
case V_038004_FMT_GB_GR:
|
||||
case V_038004_FMT_BG_RG:
|
||||
case V_038004_COLOR_INVALID:
|
||||
+ default:
|
||||
*bpe = 16;
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+struct array_mode_checker {
|
||||
+ int array_mode;
|
||||
+ u32 group_size;
|
||||
+ u32 nbanks;
|
||||
+ u32 npipes;
|
||||
+ u32 nsamples;
|
||||
+ u32 bpe;
|
||||
+};
|
||||
+
|
||||
+/* returns alignment in pixels for pitch/height/depth and bytes for base */
|
||||
+static inline int r600_get_array_mode_alignment(struct array_mode_checker *values,
|
||||
+ u32 *pitch_align,
|
||||
+ u32 *height_align,
|
||||
+ u32 *depth_align,
|
||||
+ u64 *base_align)
|
||||
+{
|
||||
+ u32 tile_width = 8;
|
||||
+ u32 tile_height = 8;
|
||||
+ u32 macro_tile_width = values->nbanks;
|
||||
+ u32 macro_tile_height = values->npipes;
|
||||
+ u32 tile_bytes = tile_width * tile_height * values->bpe * values->nsamples;
|
||||
+ u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes;
|
||||
+
|
||||
+ switch (values->array_mode) {
|
||||
+ case ARRAY_LINEAR_GENERAL:
|
||||
+ /* technically tile_width/_height for pitch/height */
|
||||
+ *pitch_align = 1; /* tile_width */
|
||||
+ *height_align = 1; /* tile_height */
|
||||
+ *depth_align = 1;
|
||||
+ *base_align = 1;
|
||||
+ break;
|
||||
+ case ARRAY_LINEAR_ALIGNED:
|
||||
+ *pitch_align = max((u32)64, (u32)(values->group_size / values->bpe));
|
||||
+ *height_align = tile_height;
|
||||
+ *depth_align = 1;
|
||||
+ *base_align = values->group_size;
|
||||
+ break;
|
||||
+ case ARRAY_1D_TILED_THIN1:
|
||||
+ *pitch_align = max((u32)tile_width,
|
||||
+ (u32)(values->group_size /
|
||||
+ (tile_height * values->bpe * values->nsamples)));
|
||||
+ *height_align = tile_height;
|
||||
+ *depth_align = 1;
|
||||
+ *base_align = values->group_size;
|
||||
+ break;
|
||||
+ case ARRAY_2D_TILED_THIN1:
|
||||
+ *pitch_align = max((u32)macro_tile_width,
|
||||
+ (u32)(((values->group_size / tile_height) /
|
||||
+ (values->bpe * values->nsamples)) *
|
||||
+ values->nbanks)) * tile_width;
|
||||
+ *height_align = macro_tile_height * tile_height;
|
||||
+ *depth_align = 1;
|
||||
+ *base_align = max(macro_tile_bytes,
|
||||
+ (*pitch_align) * values->bpe * (*height_align) * values->nsamples);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static void r600_cs_track_init(struct r600_cs_track *track)
|
||||
{
|
||||
int i;
|
||||
@@ -151,10 +217,12 @@ static void r600_cs_track_init(struct r600_cs_track *track)
|
||||
track->cb_color_info[i] = 0;
|
||||
track->cb_color_bo[i] = NULL;
|
||||
track->cb_color_bo_offset[i] = 0xFFFFFFFF;
|
||||
+ track->cb_color_bo_mc[i] = 0xFFFFFFFF;
|
||||
}
|
||||
track->cb_target_mask = 0xFFFFFFFF;
|
||||
track->cb_shader_mask = 0xFFFFFFFF;
|
||||
track->db_bo = NULL;
|
||||
+ track->db_bo_mc = 0xFFFFFFFF;
|
||||
/* assume the biggest format and that htile is enabled */
|
||||
track->db_depth_info = 7 | (1 << 25);
|
||||
track->db_depth_view = 0xFFFFC000;
|
||||
@@ -166,70 +234,58 @@ static void r600_cs_track_init(struct r600_cs_track *track)
|
||||
static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
|
||||
{
|
||||
struct r600_cs_track *track = p->track;
|
||||
- u32 bpe = 0, pitch, slice_tile_max, size, tmp, height;
|
||||
+ u32 bpe = 0, slice_tile_max, size, tmp;
|
||||
+ u32 height, height_align, pitch, pitch_align, depth_align;
|
||||
+ u64 base_offset, base_align;
|
||||
+ struct array_mode_checker array_check;
|
||||
volatile u32 *ib = p->ib->ptr;
|
||||
+ unsigned array_mode;
|
||||
|
||||
if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
|
||||
dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
- size = radeon_bo_size(track->cb_color_bo[i]);
|
||||
+ size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];
|
||||
if (r600_bpe_from_format(&bpe, G_0280A0_FORMAT(track->cb_color_info[i]))) {
|
||||
dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n",
|
||||
__func__, __LINE__, G_0280A0_FORMAT(track->cb_color_info[i]),
|
||||
i, track->cb_color_info[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
- pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) << 3;
|
||||
+ /* pitch in pixels */
|
||||
+ pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8;
|
||||
slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
|
||||
- if (!pitch) {
|
||||
- dev_warn(p->dev, "%s:%d cb pitch (%d) for %d invalid (0x%08X)\n",
|
||||
- __func__, __LINE__, pitch, i, track->cb_color_size[i]);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- height = size / (pitch * bpe);
|
||||
+ slice_tile_max *= 64;
|
||||
+ height = slice_tile_max / pitch;
|
||||
if (height > 8192)
|
||||
height = 8192;
|
||||
- switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
|
||||
+ array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]);
|
||||
+
|
||||
+ base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i];
|
||||
+ array_check.array_mode = array_mode;
|
||||
+ array_check.group_size = track->group_size;
|
||||
+ array_check.nbanks = track->nbanks;
|
||||
+ array_check.npipes = track->npipes;
|
||||
+ array_check.nsamples = track->nsamples;
|
||||
+ array_check.bpe = bpe;
|
||||
+ if (r600_get_array_mode_alignment(&array_check,
|
||||
+ &pitch_align, &height_align, &depth_align, &base_align)) {
|
||||
+ dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
|
||||
+ G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i,
|
||||
+ track->cb_color_info[i]);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ switch (array_mode) {
|
||||
case V_0280A0_ARRAY_LINEAR_GENERAL:
|
||||
+ break;
|
||||
case V_0280A0_ARRAY_LINEAR_ALIGNED:
|
||||
- if (pitch & 0x3f) {
|
||||
- dev_warn(p->dev, "%s:%d cb pitch (%d x %d = %d) invalid\n",
|
||||
- __func__, __LINE__, pitch, bpe, pitch * bpe);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- if ((pitch * bpe) & (track->group_size - 1)) {
|
||||
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
||||
- __func__, __LINE__, pitch);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
break;
|
||||
case V_0280A0_ARRAY_1D_TILED_THIN1:
|
||||
- if ((pitch * 8 * bpe * track->nsamples) & (track->group_size - 1)) {
|
||||
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
||||
- __func__, __LINE__, pitch);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- height &= ~0x7;
|
||||
- if (!height)
|
||||
- height = 8;
|
||||
+ /* avoid breaking userspace */
|
||||
+ if (height > 7)
|
||||
+ height &= ~0x7;
|
||||
break;
|
||||
case V_0280A0_ARRAY_2D_TILED_THIN1:
|
||||
- if (pitch & ((8 * track->nbanks) - 1)) {
|
||||
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
||||
- __func__, __LINE__, pitch);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- tmp = pitch * 8 * bpe * track->nsamples;
|
||||
- tmp = tmp / track->nbanks;
|
||||
- if (tmp & (track->group_size - 1)) {
|
||||
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
||||
- __func__, __LINE__, pitch);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- height &= ~((16 * track->npipes) - 1);
|
||||
- if (!height)
|
||||
- height = 16 * track->npipes;
|
||||
break;
|
||||
default:
|
||||
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
|
||||
@@ -237,17 +293,43 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
|
||||
track->cb_color_info[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
+
|
||||
+ if (!IS_ALIGNED(pitch, pitch_align)) {
|
||||
+ dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
||||
+ __func__, __LINE__, pitch);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (!IS_ALIGNED(height, height_align)) {
|
||||
+ dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
|
||||
+ __func__, __LINE__, height);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (!IS_ALIGNED(base_offset, base_align)) {
|
||||
+ dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
/* check offset */
|
||||
- tmp = height * pitch;
|
||||
+ tmp = height * pitch * bpe;
|
||||
if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
|
||||
- dev_warn(p->dev, "%s offset[%d] %d to big\n", __func__, i, track->cb_color_bo_offset[i]);
|
||||
- return -EINVAL;
|
||||
+ if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
|
||||
+ /* the initial DDX does bad things with the CB size occasionally */
|
||||
+ /* it rounds up height too far for slice tile max but the BO is smaller */
|
||||
+ tmp = (height - 7) * 8 * bpe;
|
||||
+ if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
|
||||
+ dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ } else {
|
||||
+ dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
}
|
||||
/* limit max tile */
|
||||
tmp = (height * pitch) >> 6;
|
||||
if (tmp < slice_tile_max)
|
||||
slice_tile_max = tmp;
|
||||
- tmp = S_028060_PITCH_TILE_MAX((pitch >> 3) - 1) |
|
||||
+ tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) |
|
||||
S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
|
||||
ib[track->cb_color_size_idx[i]] = tmp;
|
||||
return 0;
|
||||
@@ -289,7 +371,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
|
||||
/* Check depth buffer */
|
||||
if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
|
||||
G_028800_Z_ENABLE(track->db_depth_control)) {
|
||||
- u32 nviews, bpe, ntiles;
|
||||
+ u32 nviews, bpe, ntiles, size, slice_tile_max;
|
||||
+ u32 height, height_align, pitch, pitch_align, depth_align;
|
||||
+ u64 base_offset, base_align;
|
||||
+ struct array_mode_checker array_check;
|
||||
+ int array_mode;
|
||||
+
|
||||
if (track->db_bo == NULL) {
|
||||
dev_warn(p->dev, "z/stencil with no depth buffer\n");
|
||||
return -EINVAL;
|
||||
@@ -321,7 +408,6 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
|
||||
dev_warn(p->dev, "z/stencil buffer size not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
- printk_once(KERN_WARNING "You have old & broken userspace please consider updating mesa\n");
|
||||
tmp = radeon_bo_size(track->db_bo) - track->db_offset;
|
||||
tmp = (tmp / bpe) >> 6;
|
||||
if (!tmp) {
|
||||
@@ -332,11 +418,63 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
|
||||
}
|
||||
ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
|
||||
} else {
|
||||
+ size = radeon_bo_size(track->db_bo);
|
||||
+ /* pitch in pixels */
|
||||
+ pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
|
||||
+ slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
|
||||
+ slice_tile_max *= 64;
|
||||
+ height = slice_tile_max / pitch;
|
||||
+ if (height > 8192)
|
||||
+ height = 8192;
|
||||
+ base_offset = track->db_bo_mc + track->db_offset;
|
||||
+ array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
|
||||
+ array_check.array_mode = array_mode;
|
||||
+ array_check.group_size = track->group_size;
|
||||
+ array_check.nbanks = track->nbanks;
|
||||
+ array_check.npipes = track->npipes;
|
||||
+ array_check.nsamples = track->nsamples;
|
||||
+ array_check.bpe = bpe;
|
||||
+ if (r600_get_array_mode_alignment(&array_check,
|
||||
+ &pitch_align, &height_align, &depth_align, &base_align)) {
|
||||
+ dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
|
||||
+ G_028010_ARRAY_MODE(track->db_depth_info),
|
||||
+ track->db_depth_info);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ switch (array_mode) {
|
||||
+ case V_028010_ARRAY_1D_TILED_THIN1:
|
||||
+ /* don't break userspace */
|
||||
+ height &= ~0x7;
|
||||
+ break;
|
||||
+ case V_028010_ARRAY_2D_TILED_THIN1:
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
|
||||
+ G_028010_ARRAY_MODE(track->db_depth_info),
|
||||
+ track->db_depth_info);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (!IS_ALIGNED(pitch, pitch_align)) {
|
||||
+ dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
|
||||
+ __func__, __LINE__, pitch);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (!IS_ALIGNED(height, height_align)) {
|
||||
+ dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
|
||||
+ __func__, __LINE__, height);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (!IS_ALIGNED(base_offset, base_align)) {
|
||||
+ dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
|
||||
nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
|
||||
tmp = ntiles * bpe * 64 * nviews;
|
||||
if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
|
||||
- dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n",
|
||||
+ dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n",
|
||||
track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
|
||||
radeon_bo_size(track->db_bo));
|
||||
return -EINVAL;
|
||||
@@ -724,7 +862,25 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
|
||||
track->db_depth_control = radeon_get_ib_value(p, idx);
|
||||
break;
|
||||
case R_028010_DB_DEPTH_INFO:
|
||||
- track->db_depth_info = radeon_get_ib_value(p, idx);
|
||||
+ if (r600_cs_packet_next_is_pkt3_nop(p)) {
|
||||
+ r = r600_cs_packet_next_reloc(p, &reloc);
|
||||
+ if (r) {
|
||||
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
|
||||
+ "0x%04X\n", reg);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ track->db_depth_info = radeon_get_ib_value(p, idx);
|
||||
+ ib[idx] &= C_028010_ARRAY_MODE;
|
||||
+ track->db_depth_info &= C_028010_ARRAY_MODE;
|
||||
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
|
||||
+ ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1);
|
||||
+ track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1);
|
||||
+ } else {
|
||||
+ ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1);
|
||||
+ track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1);
|
||||
+ }
|
||||
+ } else
|
||||
+ track->db_depth_info = radeon_get_ib_value(p, idx);
|
||||
break;
|
||||
case R_028004_DB_DEPTH_VIEW:
|
||||
track->db_depth_view = radeon_get_ib_value(p, idx);
|
||||
@@ -757,8 +913,25 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
|
||||
case R_0280B4_CB_COLOR5_INFO:
|
||||
case R_0280B8_CB_COLOR6_INFO:
|
||||
case R_0280BC_CB_COLOR7_INFO:
|
||||
- tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
|
||||
- track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
|
||||
+ if (r600_cs_packet_next_is_pkt3_nop(p)) {
|
||||
+ r = r600_cs_packet_next_reloc(p, &reloc);
|
||||
+ if (r) {
|
||||
+ dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
|
||||
+ track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
|
||||
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
|
||||
+ ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1);
|
||||
+ track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1);
|
||||
+ } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
|
||||
+ ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1);
|
||||
+ track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
|
||||
+ track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
|
||||
+ }
|
||||
break;
|
||||
case R_028060_CB_COLOR0_SIZE:
|
||||
case R_028064_CB_COLOR1_SIZE:
|
||||
@@ -796,8 +969,6 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
|
||||
return -EINVAL;
|
||||
}
|
||||
ib[idx] = track->cb_color_base_last[tmp];
|
||||
- printk_once(KERN_WARNING "You have old & broken userspace "
|
||||
- "please consider updating mesa & xf86-video-ati\n");
|
||||
track->cb_color_frag_bo[tmp] = track->cb_color_bo[tmp];
|
||||
} else {
|
||||
r = r600_cs_packet_next_reloc(p, &reloc);
|
||||
@@ -824,8 +995,6 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
|
||||
return -EINVAL;
|
||||
}
|
||||
ib[idx] = track->cb_color_base_last[tmp];
|
||||
- printk_once(KERN_WARNING "You have old & broken userspace "
|
||||
- "please consider updating mesa & xf86-video-ati\n");
|
||||
track->cb_color_tile_bo[tmp] = track->cb_color_bo[tmp];
|
||||
} else {
|
||||
r = r600_cs_packet_next_reloc(p, &reloc);
|
||||
@@ -852,10 +1021,11 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
|
||||
return -EINVAL;
|
||||
}
|
||||
tmp = (reg - CB_COLOR0_BASE) / 4;
|
||||
- track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
|
||||
+ track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
|
||||
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
|
||||
track->cb_color_base_last[tmp] = ib[idx];
|
||||
track->cb_color_bo[tmp] = reloc->robj;
|
||||
+ track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset;
|
||||
break;
|
||||
case DB_DEPTH_BASE:
|
||||
r = r600_cs_packet_next_reloc(p, &reloc);
|
||||
@@ -864,9 +1034,10 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
|
||||
"0x%04X\n", reg);
|
||||
return -EINVAL;
|
||||
}
|
||||
- track->db_offset = radeon_get_ib_value(p, idx);
|
||||
+ track->db_offset = radeon_get_ib_value(p, idx) << 8;
|
||||
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
|
||||
track->db_bo = reloc->robj;
|
||||
+ track->db_bo_mc = reloc->lobj.gpu_offset;
|
||||
break;
|
||||
case DB_HTILE_DATA_BASE:
|
||||
case SQ_PGM_START_FS:
|
||||
@@ -946,8 +1117,9 @@ static inline unsigned minify(unsigned size, unsigned levels)
|
||||
}
|
||||
|
||||
static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels,
|
||||
- unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
|
||||
- unsigned *l0_size, unsigned *mipmap_size)
|
||||
+ unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
|
||||
+ unsigned pitch_align,
|
||||
+ unsigned *l0_size, unsigned *mipmap_size)
|
||||
{
|
||||
unsigned offset, i, level, face;
|
||||
unsigned width, height, depth, rowstride, size;
|
||||
@@ -960,18 +1132,18 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels
|
||||
height = minify(h0, i);
|
||||
depth = minify(d0, i);
|
||||
for(face = 0; face < nfaces; face++) {
|
||||
- rowstride = ((width * bpe) + 255) & ~255;
|
||||
+ rowstride = ALIGN((width * bpe), pitch_align);
|
||||
size = height * rowstride * depth;
|
||||
offset += size;
|
||||
offset = (offset + 0x1f) & ~0x1f;
|
||||
}
|
||||
}
|
||||
- *l0_size = (((w0 * bpe) + 255) & ~255) * h0 * d0;
|
||||
+ *l0_size = ALIGN((w0 * bpe), pitch_align) * h0 * d0;
|
||||
*mipmap_size = offset;
|
||||
- if (!blevel)
|
||||
- *mipmap_size -= *l0_size;
|
||||
if (!nlevels)
|
||||
*mipmap_size = *l0_size;
|
||||
+ if (!blevel)
|
||||
+ *mipmap_size -= *l0_size;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -985,16 +1157,32 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels
|
||||
* the texture and mipmap bo object are big enough to cover this resource.
|
||||
*/
|
||||
static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
|
||||
- struct radeon_bo *texture,
|
||||
- struct radeon_bo *mipmap)
|
||||
+ struct radeon_bo *texture,
|
||||
+ struct radeon_bo *mipmap,
|
||||
+ u64 base_offset,
|
||||
+ u64 mip_offset,
|
||||
+ u32 tiling_flags)
|
||||
{
|
||||
+ struct r600_cs_track *track = p->track;
|
||||
u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
|
||||
u32 word0, word1, l0_size, mipmap_size;
|
||||
+ u32 height_align, pitch, pitch_align, depth_align;
|
||||
+ u64 base_align;
|
||||
+ struct array_mode_checker array_check;
|
||||
|
||||
/* on legacy kernel we don't perform advanced check */
|
||||
if (p->rdev == NULL)
|
||||
return 0;
|
||||
+
|
||||
+ /* convert to bytes */
|
||||
+ base_offset <<= 8;
|
||||
+ mip_offset <<= 8;
|
||||
+
|
||||
word0 = radeon_get_ib_value(p, idx + 0);
|
||||
+ if (tiling_flags & RADEON_TILING_MACRO)
|
||||
+ word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
|
||||
+ else if (tiling_flags & RADEON_TILING_MICRO)
|
||||
+ word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);
|
||||
word1 = radeon_get_ib_value(p, idx + 1);
|
||||
w0 = G_038000_TEX_WIDTH(word0) + 1;
|
||||
h0 = G_038004_TEX_HEIGHT(word1) + 1;
|
||||
@@ -1021,24 +1209,59 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i
|
||||
__func__, __LINE__, G_038004_DATA_FORMAT(word1));
|
||||
return -EINVAL;
|
||||
}
|
||||
+
|
||||
+ /* pitch in texels */
|
||||
+ pitch = (G_038000_PITCH(word0) + 1) * 8;
|
||||
+ array_check.array_mode = G_038000_TILE_MODE(word0);
|
||||
+ array_check.group_size = track->group_size;
|
||||
+ array_check.nbanks = track->nbanks;
|
||||
+ array_check.npipes = track->npipes;
|
||||
+ array_check.nsamples = 1;
|
||||
+ array_check.bpe = bpe;
|
||||
+ if (r600_get_array_mode_alignment(&array_check,
|
||||
+ &pitch_align, &height_align, &depth_align, &base_align)) {
|
||||
+ dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n",
|
||||
+ __func__, __LINE__, G_038000_TILE_MODE(word0));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* XXX check height as well... */
|
||||
+
|
||||
+ if (!IS_ALIGNED(pitch, pitch_align)) {
|
||||
+ dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
|
||||
+ __func__, __LINE__, pitch);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (!IS_ALIGNED(base_offset, base_align)) {
|
||||
+ dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n",
|
||||
+ __func__, __LINE__, base_offset);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (!IS_ALIGNED(mip_offset, base_align)) {
|
||||
+ dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n",
|
||||
+ __func__, __LINE__, mip_offset);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
word0 = radeon_get_ib_value(p, idx + 4);
|
||||
word1 = radeon_get_ib_value(p, idx + 5);
|
||||
blevel = G_038010_BASE_LEVEL(word0);
|
||||
nlevels = G_038014_LAST_LEVEL(word1);
|
||||
- r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe, &l0_size, &mipmap_size);
|
||||
+ r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe,
|
||||
+ (pitch_align * bpe),
|
||||
+ &l0_size, &mipmap_size);
|
||||
/* using get ib will give us the offset into the texture bo */
|
||||
- word0 = radeon_get_ib_value(p, idx + 2);
|
||||
+ word0 = radeon_get_ib_value(p, idx + 2) << 8;
|
||||
if ((l0_size + word0) > radeon_bo_size(texture)) {
|
||||
dev_warn(p->dev, "texture bo too small (%d %d %d %d -> %d have %ld)\n",
|
||||
w0, h0, bpe, word0, l0_size, radeon_bo_size(texture));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* using get ib will give us the offset into the mipmap bo */
|
||||
- word0 = radeon_get_ib_value(p, idx + 3);
|
||||
+ word0 = radeon_get_ib_value(p, idx + 3) << 8;
|
||||
if ((mipmap_size + word0) > radeon_bo_size(mipmap)) {
|
||||
- dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
|
||||
- w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture));
|
||||
- return -EINVAL;
|
||||
+ /*dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
|
||||
+ w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture));*/
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1228,7 +1451,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
|
||||
}
|
||||
for (i = 0; i < (pkt->count / 7); i++) {
|
||||
struct radeon_bo *texture, *mipmap;
|
||||
- u32 size, offset;
|
||||
+ u32 size, offset, base_offset, mip_offset;
|
||||
|
||||
switch (G__SQ_VTX_CONSTANT_TYPE(radeon_get_ib_value(p, idx+(i*7)+6+1))) {
|
||||
case SQ_TEX_VTX_VALID_TEXTURE:
|
||||
@@ -1238,7 +1461,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
|
||||
DRM_ERROR("bad SET_RESOURCE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
- ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
|
||||
+ base_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
|
||||
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
|
||||
+ ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
|
||||
+ else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
|
||||
+ ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);
|
||||
texture = reloc->robj;
|
||||
/* tex mip base */
|
||||
r = r600_cs_packet_next_reloc(p, &reloc);
|
||||
@@ -1246,12 +1473,17 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
|
||||
DRM_ERROR("bad SET_RESOURCE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
- ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
|
||||
+ mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
|
||||
mipmap = reloc->robj;
|
||||
r = r600_check_texture_resource(p, idx+(i*7)+1,
|
||||
- texture, mipmap);
|
||||
+ texture, mipmap,
|
||||
+ base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2),
|
||||
+ mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3),
|
||||
+ reloc->lobj.tiling_flags);
|
||||
if (r)
|
||||
return r;
|
||||
+ ib[idx+1+(i*7)+2] += base_offset;
|
||||
+ ib[idx+1+(i*7)+3] += mip_offset;
|
||||
break;
|
||||
case SQ_TEX_VTX_VALID_BUFFER:
|
||||
/* vtx base */
|
||||
@@ -1261,10 +1493,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
|
||||
return -EINVAL;
|
||||
}
|
||||
offset = radeon_get_ib_value(p, idx+1+(i*7)+0);
|
||||
- size = radeon_get_ib_value(p, idx+1+(i*7)+1);
|
||||
+ size = radeon_get_ib_value(p, idx+1+(i*7)+1) + 1;
|
||||
if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) {
|
||||
/* force size to size of the buffer */
|
||||
- dev_warn(p->dev, "vbo resource seems too big for the bo\n");
|
||||
+ dev_warn(p->dev, "vbo resource seems too big (%d) for the bo (%ld)\n",
|
||||
+ size + offset, radeon_bo_size(reloc->robj));
|
||||
ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj);
|
||||
}
|
||||
ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff);
|
||||
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
|
||||
index 84bc28e..9577945 100644
|
||||
--- a/drivers/gpu/drm/radeon/r600d.h
|
||||
+++ b/drivers/gpu/drm/radeon/r600d.h
|
||||
@@ -51,6 +51,12 @@
|
||||
#define PTE_READABLE (1 << 5)
|
||||
#define PTE_WRITEABLE (1 << 6)
|
||||
|
||||
+/* tiling bits */
|
||||
+#define ARRAY_LINEAR_GENERAL 0x00000000
|
||||
+#define ARRAY_LINEAR_ALIGNED 0x00000001
|
||||
+#define ARRAY_1D_TILED_THIN1 0x00000002
|
||||
+#define ARRAY_2D_TILED_THIN1 0x00000004
|
||||
+
|
||||
/* Registers */
|
||||
#define ARB_POP 0x2418
|
||||
#define ENABLE_TC128 (1 << 30)
|
||||
@@ -1155,6 +1161,10 @@
|
||||
#define S_038000_TILE_MODE(x) (((x) & 0xF) << 3)
|
||||
#define G_038000_TILE_MODE(x) (((x) >> 3) & 0xF)
|
||||
#define C_038000_TILE_MODE 0xFFFFFF87
|
||||
+#define V_038000_ARRAY_LINEAR_GENERAL 0x00000000
|
||||
+#define V_038000_ARRAY_LINEAR_ALIGNED 0x00000001
|
||||
+#define V_038000_ARRAY_1D_TILED_THIN1 0x00000002
|
||||
+#define V_038000_ARRAY_2D_TILED_THIN1 0x00000004
|
||||
#define S_038000_TILE_TYPE(x) (((x) & 0x1) << 7)
|
||||
#define G_038000_TILE_TYPE(x) (((x) >> 7) & 0x1)
|
||||
#define C_038000_TILE_TYPE 0xFFFFFF7F
|
||||
@@ -1358,6 +1368,8 @@
|
||||
#define S_028010_ARRAY_MODE(x) (((x) & 0xF) << 15)
|
||||
#define G_028010_ARRAY_MODE(x) (((x) >> 15) & 0xF)
|
||||
#define C_028010_ARRAY_MODE 0xFFF87FFF
|
||||
+#define V_028010_ARRAY_1D_TILED_THIN1 0x00000002
|
||||
+#define V_028010_ARRAY_2D_TILED_THIN1 0x00000004
|
||||
#define S_028010_TILE_SURFACE_ENABLE(x) (((x) & 0x1) << 25)
|
||||
#define G_028010_TILE_SURFACE_ENABLE(x) (((x) >> 25) & 0x1)
|
||||
#define C_028010_TILE_SURFACE_ENABLE 0xFDFFFFFF
|
|
@ -1,958 +0,0 @@
|
|||
From 5b904034b0ab5195d971b139d0c0b67ab21b063c Mon Sep 17 00:00:00 2001
|
||||
From: Kyle McMartin <kyle@dreadnought.i.jkkm.org>
|
||||
Date: Mon, 21 Jun 2010 20:33:16 +0100
|
||||
Subject: Revert "drm/fbdev: rework output polling to be back in the core. (v4)"
|
||||
|
||||
This reverts commit eb1f8e4f3be898df808e2dfc131099f5831d491d.
|
||||
|
||||
Conflicts:
|
||||
|
||||
drivers/gpu/drm/drm_crtc_helper.c
|
||||
drivers/gpu/drm/i915/i915_dma.c
|
||||
drivers/gpu/drm/i915/intel_fb.c
|
||||
drivers/gpu/drm/nouveau/nouveau_fbcon.c
|
||||
drivers/gpu/drm/radeon/radeon_fb.c
|
||||
include/drm/drm_crtc_helper.h
|
||||
---
|
||||
drivers/gpu/drm/Kconfig | 2 +-
|
||||
drivers/gpu/drm/drm_crtc_helper.c | 111 ------------------------
|
||||
drivers/gpu/drm/drm_fb_helper.c | 123 +++++++++++++++++++++++----
|
||||
drivers/gpu/drm/i915/i915_dma.c | 1 -
|
||||
drivers/gpu/drm/i915/i915_irq.c | 3 +-
|
||||
drivers/gpu/drm/i915/intel_crt.c | 5 -
|
||||
drivers/gpu/drm/i915/intel_display.c | 2 -
|
||||
drivers/gpu/drm/i915/intel_dp.c | 2 -
|
||||
drivers/gpu/drm/i915/intel_drv.h | 2 +-
|
||||
drivers/gpu/drm/i915/intel_fb.c | 14 ++--
|
||||
drivers/gpu/drm/i915/intel_hdmi.c | 1 -
|
||||
drivers/gpu/drm/i915/intel_sdvo.c | 2 -
|
||||
drivers/gpu/drm/nouveau/nouveau_connector.c | 12 ---
|
||||
drivers/gpu/drm/nouveau/nouveau_display.c | 1 -
|
||||
drivers/gpu/drm/nouveau/nouveau_fbcon.c | 13 ++-
|
||||
drivers/gpu/drm/nouveau/nouveau_fbcon.h | 2 +-
|
||||
drivers/gpu/drm/nouveau/nouveau_state.c | 5 +-
|
||||
drivers/gpu/drm/nouveau/nv50_display.c | 2 +-
|
||||
drivers/gpu/drm/radeon/radeon_connectors.c | 13 ---
|
||||
drivers/gpu/drm/radeon/radeon_display.c | 10 --
|
||||
drivers/gpu/drm/radeon/radeon_fb.c | 15 +++-
|
||||
drivers/gpu/drm/radeon/radeon_irq_kms.c | 5 +-
|
||||
drivers/gpu/drm/radeon/radeon_mode.h | 3 +-
|
||||
include/drm/drm_crtc.h | 17 ----
|
||||
include/drm/drm_crtc_helper.h | 6 --
|
||||
include/drm/drm_fb_helper.h | 13 +++-
|
||||
26 files changed, 155 insertions(+), 230 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
|
||||
index c2711c6..a51a1e4 100644
|
||||
--- a/drivers/gpu/drm/Kconfig
|
||||
+++ b/drivers/gpu/drm/Kconfig
|
||||
@@ -9,7 +9,6 @@ menuconfig DRM
|
||||
depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU
|
||||
select I2C
|
||||
select I2C_ALGOBIT
|
||||
- select SLOW_WORK
|
||||
help
|
||||
Kernel-level support for the Direct Rendering Infrastructure (DRI)
|
||||
introduced in XFree86 4.0. If you say Y here, you need to select
|
||||
@@ -24,6 +23,7 @@ config DRM_KMS_HELPER
|
||||
depends on DRM
|
||||
select FB
|
||||
select FRAMEBUFFER_CONSOLE if !EMBEDDED
|
||||
+ select SLOW_WORK
|
||||
help
|
||||
FB and CRTC helpers for KMS drivers.
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
|
||||
index 9b2a541..b142ac2 100644
|
||||
--- a/drivers/gpu/drm/drm_crtc_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_crtc_helper.c
|
||||
@@ -807,114 +807,3 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_helper_resume_force_mode);
|
||||
-
|
||||
-static struct slow_work_ops output_poll_ops;
|
||||
-
|
||||
-#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
|
||||
-static void output_poll_execute(struct slow_work *work)
|
||||
-{
|
||||
- struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
|
||||
- struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work);
|
||||
- struct drm_connector *connector;
|
||||
- enum drm_connector_status old_status, status;
|
||||
- bool repoll = false, changed = false;
|
||||
- int ret;
|
||||
-
|
||||
- mutex_lock(&dev->mode_config.mutex);
|
||||
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
-
|
||||
- /* if this is HPD or polled don't check it -
|
||||
- TV out for instance */
|
||||
- if (!connector->polled)
|
||||
- continue;
|
||||
-
|
||||
- else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
|
||||
- repoll = true;
|
||||
-
|
||||
- old_status = connector->status;
|
||||
- /* if we are connected and don't want to poll for disconnect
|
||||
- skip it */
|
||||
- if (old_status == connector_status_connected &&
|
||||
- !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&
|
||||
- !(connector->polled & DRM_CONNECTOR_POLL_HPD))
|
||||
- continue;
|
||||
-
|
||||
- status = connector->funcs->detect(connector);
|
||||
- if (old_status != status)
|
||||
- changed = true;
|
||||
- }
|
||||
-
|
||||
- mutex_unlock(&dev->mode_config.mutex);
|
||||
-
|
||||
- if (changed) {
|
||||
- /* send a uevent + call fbdev */
|
||||
- drm_sysfs_hotplug_event(dev);
|
||||
- if (dev->mode_config.funcs->output_poll_changed)
|
||||
- dev->mode_config.funcs->output_poll_changed(dev);
|
||||
- }
|
||||
-
|
||||
- if (repoll) {
|
||||
- ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD);
|
||||
- if (ret)
|
||||
- DRM_ERROR("delayed enqueue failed %d\n", ret);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-void drm_kms_helper_poll_disable(struct drm_device *dev)
|
||||
-{
|
||||
- if (!dev->mode_config.poll_enabled)
|
||||
- return;
|
||||
- delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
|
||||
-}
|
||||
-EXPORT_SYMBOL(drm_kms_helper_poll_disable);
|
||||
-
|
||||
-void drm_kms_helper_poll_enable(struct drm_device *dev)
|
||||
-{
|
||||
- bool poll = false;
|
||||
- struct drm_connector *connector;
|
||||
- int ret;
|
||||
-
|
||||
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
- if (connector->polled)
|
||||
- poll = true;
|
||||
- }
|
||||
-
|
||||
- if (poll) {
|
||||
- ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD);
|
||||
- if (ret)
|
||||
- DRM_ERROR("delayed enqueue failed %d\n", ret);
|
||||
- }
|
||||
-}
|
||||
-EXPORT_SYMBOL(drm_kms_helper_poll_enable);
|
||||
-
|
||||
-void drm_kms_helper_poll_init(struct drm_device *dev)
|
||||
-{
|
||||
- slow_work_register_user(THIS_MODULE);
|
||||
- delayed_slow_work_init(&dev->mode_config.output_poll_slow_work,
|
||||
- &output_poll_ops);
|
||||
- dev->mode_config.poll_enabled = true;
|
||||
-
|
||||
- drm_kms_helper_poll_enable(dev);
|
||||
-}
|
||||
-EXPORT_SYMBOL(drm_kms_helper_poll_init);
|
||||
-
|
||||
-void drm_kms_helper_poll_fini(struct drm_device *dev)
|
||||
-{
|
||||
- drm_kms_helper_poll_disable(dev);
|
||||
- slow_work_unregister_user(THIS_MODULE);
|
||||
-}
|
||||
-EXPORT_SYMBOL(drm_kms_helper_poll_fini);
|
||||
-
|
||||
-void drm_helper_hpd_irq_event(struct drm_device *dev)
|
||||
-{
|
||||
- if (!dev->mode_config.poll_enabled)
|
||||
- return;
|
||||
- delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
|
||||
- /* schedule a slow work asap */
|
||||
- delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
|
||||
-}
|
||||
-EXPORT_SYMBOL(drm_helper_hpd_irq_event);
|
||||
-
|
||||
-static struct slow_work_ops output_poll_ops = {
|
||||
- .execute = output_poll_execute,
|
||||
-};
|
||||
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
|
||||
index 08c4c92..dcc6601 100644
|
||||
--- a/drivers/gpu/drm/drm_fb_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_fb_helper.c
|
||||
@@ -42,6 +42,8 @@ MODULE_LICENSE("GPL and additional rights");
|
||||
|
||||
static LIST_HEAD(kernel_fb_helper_list);
|
||||
|
||||
+static struct slow_work_ops output_status_change_ops;
|
||||
+
|
||||
/* simple single crtc case helper function */
|
||||
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
@@ -423,13 +425,19 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
|
||||
|
||||
int drm_fb_helper_init(struct drm_device *dev,
|
||||
struct drm_fb_helper *fb_helper,
|
||||
- int crtc_count, int max_conn_count)
|
||||
+ int crtc_count, int max_conn_count,
|
||||
+ bool polled)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
fb_helper->dev = dev;
|
||||
+ fb_helper->poll_enabled = polled;
|
||||
+
|
||||
+ slow_work_register_user(THIS_MODULE);
|
||||
+ delayed_slow_work_init(&fb_helper->output_status_change_slow_work,
|
||||
+ &output_status_change_ops);
|
||||
|
||||
INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
|
||||
|
||||
@@ -486,6 +494,8 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
|
||||
|
||||
drm_fb_helper_crtc_free(fb_helper);
|
||||
|
||||
+ delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
|
||||
+ slow_work_unregister_user(THIS_MODULE);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_fini);
|
||||
|
||||
@@ -703,7 +713,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
|
||||
|
||||
if (fb_helper->delayed_hotplug) {
|
||||
fb_helper->delayed_hotplug = false;
|
||||
- drm_fb_helper_hotplug_event(fb_helper);
|
||||
+ delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -816,7 +826,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||
if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
|
||||
/* hmm everyone went away - assume VGA cable just fell out
|
||||
and will come back later. */
|
||||
- DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n");
|
||||
+ DRM_ERROR("Cannot find any crtc or sizes - going 1024x768\n");
|
||||
sizes.fb_width = sizes.surface_width = 1024;
|
||||
sizes.fb_height = sizes.surface_height = 768;
|
||||
}
|
||||
@@ -1362,7 +1372,12 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
|
||||
* we shouldn't end up with no modes here.
|
||||
*/
|
||||
if (count == 0) {
|
||||
- printk(KERN_INFO "No connectors reported connected with modes\n");
|
||||
+ if (fb_helper->poll_enabled) {
|
||||
+ delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work,
|
||||
+ 5*HZ);
|
||||
+ printk(KERN_INFO "No connectors reported connected with modes - started polling\n");
|
||||
+ } else
|
||||
+ printk(KERN_INFO "No connectors reported connected with modes\n");
|
||||
}
|
||||
drm_setup_crtcs(fb_helper);
|
||||
|
||||
@@ -1370,16 +1385,71 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_initial_config);
|
||||
|
||||
-bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
|
||||
+/* we got a hotplug irq - need to update fbcon */
|
||||
+void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper)
|
||||
+{
|
||||
+ /* if we don't have the fbdev registered yet do nothing */
|
||||
+ if (!fb_helper->fbdev)
|
||||
+ return;
|
||||
+
|
||||
+ /* schedule a slow work asap */
|
||||
+ delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event);
|
||||
+
|
||||
+bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled)
|
||||
{
|
||||
int count = 0;
|
||||
+ int ret;
|
||||
u32 max_width, max_height, bpp_sel;
|
||||
- bool bound = false, crtcs_bound = false;
|
||||
- struct drm_crtc *crtc;
|
||||
|
||||
if (!fb_helper->fb)
|
||||
return false;
|
||||
+ DRM_DEBUG_KMS("\n");
|
||||
+
|
||||
+ max_width = fb_helper->fb->width;
|
||||
+ max_height = fb_helper->fb->height;
|
||||
+ bpp_sel = fb_helper->fb->bits_per_pixel;
|
||||
+
|
||||
+ count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
|
||||
+ max_height);
|
||||
+ if (fb_helper->poll_enabled && !polled) {
|
||||
+ if (count) {
|
||||
+ delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
|
||||
+ } else {
|
||||
+ ret = delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 5*HZ);
|
||||
+ }
|
||||
+ }
|
||||
+ drm_setup_crtcs(fb_helper);
|
||||
+
|
||||
+ return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_helper_fb_hotplug_event);
|
||||
+
|
||||
+/*
|
||||
+ * delayed work queue execution function
|
||||
+ * - check if fbdev is actually in use on the gpu
|
||||
+ * - if not set delayed flag and repoll if necessary
|
||||
+ * - check for connector status change
|
||||
+ * - repoll if 0 modes found
|
||||
+ *- call driver output status changed notifier
|
||||
+ */
|
||||
+static void output_status_change_execute(struct slow_work *work)
|
||||
+{
|
||||
+ struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
|
||||
+ struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_status_change_slow_work);
|
||||
+ struct drm_connector *connector;
|
||||
+ enum drm_connector_status old_status, status;
|
||||
+ bool repoll, changed = false;
|
||||
+ int ret;
|
||||
+ int i;
|
||||
+ bool bound = false, crtcs_bound = false;
|
||||
+ struct drm_crtc *crtc;
|
||||
|
||||
+ repoll = fb_helper->poll_enabled;
|
||||
+
|
||||
+ /* first of all check the fbcon framebuffer is actually bound to any crtc */
|
||||
+ /* take into account that no crtc at all maybe bound */
|
||||
list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
|
||||
if (crtc->fb)
|
||||
crtcs_bound = true;
|
||||
@@ -1387,21 +1457,38 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
|
||||
bound = true;
|
||||
}
|
||||
|
||||
- if (!bound && crtcs_bound) {
|
||||
+ if (bound == false && crtcs_bound) {
|
||||
fb_helper->delayed_hotplug = true;
|
||||
- return false;
|
||||
+ goto requeue;
|
||||
}
|
||||
- DRM_DEBUG_KMS("\n");
|
||||
|
||||
- max_width = fb_helper->fb->width;
|
||||
- max_height = fb_helper->fb->height;
|
||||
- bpp_sel = fb_helper->fb->bits_per_pixel;
|
||||
+ for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
+ connector = fb_helper->connector_info[i]->connector;
|
||||
+ old_status = connector->status;
|
||||
+ status = connector->funcs->detect(connector);
|
||||
+ if (old_status != status) {
|
||||
+ changed = true;
|
||||
+ }
|
||||
+ if (status == connector_status_connected && repoll) {
|
||||
+ DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector));
|
||||
+ repoll = false;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
|
||||
- max_height);
|
||||
- drm_setup_crtcs(fb_helper);
|
||||
+ if (changed) {
|
||||
+ if (fb_helper->funcs->fb_output_status_changed)
|
||||
+ fb_helper->funcs->fb_output_status_changed(fb_helper);
|
||||
+ }
|
||||
|
||||
- return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
|
||||
+requeue:
|
||||
+ if (repoll) {
|
||||
+ ret = delayed_slow_work_enqueue(delayed_work, 5*HZ);
|
||||
+ if (ret)
|
||||
+ DRM_ERROR("delayed enqueue failed %d\n", ret);
|
||||
+ }
|
||||
}
|
||||
-EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
|
||||
+
|
||||
+static struct slow_work_ops output_status_change_ops = {
|
||||
+ .execute = output_status_change_execute,
|
||||
+};
|
||||
|
||||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
|
||||
index 59a2bf8..76ace2d 100644
|
||||
--- a/drivers/gpu/drm/i915/i915_dma.c
|
||||
+++ b/drivers/gpu/drm/i915/i915_dma.c
|
||||
@@ -1430,7 +1430,6 @@ static int i915_load_modeset_init(struct drm_device *dev,
|
||||
if (ret)
|
||||
goto cleanup_irq;
|
||||
|
||||
- drm_kms_helper_poll_init(dev);
|
||||
return 0;
|
||||
|
||||
cleanup_irq:
|
||||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
|
||||
index 2479be0..6350bd3 100644
|
||||
--- a/drivers/gpu/drm/i915/i915_irq.c
|
||||
+++ b/drivers/gpu/drm/i915/i915_irq.c
|
||||
@@ -271,7 +271,8 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
/* Just fire off a uevent and let userspace tell us what to do */
|
||||
- drm_helper_hpd_irq_event(dev);
|
||||
+ intelfb_hotplug(dev, false);
|
||||
+ drm_sysfs_hotplug_event(dev);
|
||||
}
|
||||
|
||||
static void i915_handle_rps_change(struct drm_device *dev)
|
||||
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
|
||||
index 22ff384..125eded 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_crt.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_crt.c
|
||||
@@ -584,10 +584,5 @@ void intel_crt_init(struct drm_device *dev)
|
||||
|
||||
drm_sysfs_connector_add(connector);
|
||||
|
||||
- if (I915_HAS_HOTPLUG(dev))
|
||||
- connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
- else
|
||||
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
-
|
||||
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
|
||||
index d753257..70537cf 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_display.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_display.c
|
||||
@@ -5036,7 +5036,6 @@ intel_user_framebuffer_create(struct drm_device *dev,
|
||||
|
||||
static const struct drm_mode_config_funcs intel_mode_funcs = {
|
||||
.fb_create = intel_user_framebuffer_create,
|
||||
- .output_poll_changed = intel_fb_output_poll_changed,
|
||||
};
|
||||
|
||||
static struct drm_gem_object *
|
||||
@@ -5538,7 +5537,6 @@ void intel_modeset_cleanup(struct drm_device *dev)
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
- drm_kms_helper_poll_fini(dev);
|
||||
intel_fbdev_fini(dev);
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
|
||||
index 49b54f0..1815df5 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_dp.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_dp.c
|
||||
@@ -1393,8 +1393,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
||||
DRM_MODE_CONNECTOR_DisplayPort);
|
||||
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
|
||||
|
||||
- connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
-
|
||||
if (output_reg == DP_A)
|
||||
intel_encoder->type = INTEL_OUTPUT_EDP;
|
||||
else
|
||||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
|
||||
index df931f7..3230e8d 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_drv.h
|
||||
+++ b/drivers/gpu/drm/i915/intel_drv.h
|
||||
@@ -235,5 +235,5 @@ extern int intel_overlay_put_image(struct drm_device *dev, void *data,
|
||||
extern int intel_overlay_attrs(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
-extern void intel_fb_output_poll_changed(struct drm_device *dev);
|
||||
+void intelfb_hotplug(struct drm_device *dev, bool polled);
|
||||
#endif /* __INTEL_DRV_H__ */
|
||||
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
|
||||
index c3c5052..79098b3 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_fb.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_fb.c
|
||||
@@ -211,6 +211,12 @@ static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
|
||||
return new_fb;
|
||||
}
|
||||
|
||||
+void intelfb_hotplug(struct drm_device *dev, bool polled)
|
||||
+{
|
||||
+ drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
+ drm_helper_fb_hpd_irq_event(&dev_priv->fbdev->helper);
|
||||
+}
|
||||
+
|
||||
static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
|
||||
.gamma_set = intel_crtc_fb_gamma_set,
|
||||
.gamma_get = intel_crtc_fb_gamma_get,
|
||||
@@ -256,7 +262,7 @@ int intel_fbdev_init(struct drm_device *dev)
|
||||
|
||||
ret = drm_fb_helper_init(dev, &ifbdev->helper,
|
||||
dev_priv->num_pipe,
|
||||
- INTELFB_CONN_LIMIT);
|
||||
+ INTELFB_CONN_LIMIT, false);
|
||||
if (ret) {
|
||||
kfree(ifbdev);
|
||||
return ret;
|
||||
@@ -278,9 +284,3 @@ void intel_fbdev_fini(struct drm_device *dev)
|
||||
dev_priv->fbdev = NULL;
|
||||
}
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
-
|
||||
-void intel_fb_output_poll_changed(struct drm_device *dev)
|
||||
-{
|
||||
- drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
- drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
|
||||
-}
|
||||
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
|
||||
index 83bd764..acaca07 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_hdmi.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
|
||||
@@ -240,7 +240,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
||||
|
||||
intel_encoder->type = INTEL_OUTPUT_HDMI;
|
||||
|
||||
- connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
connector->interlace_allowed = 0;
|
||||
connector->doublescan_allowed = 0;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
|
||||
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
|
||||
index 76993ac..1c716b5 100644
|
||||
--- a/drivers/gpu/drm/i915/intel_sdvo.c
|
||||
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
|
||||
@@ -2218,7 +2218,6 @@ intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device)
|
||||
}
|
||||
|
||||
connector = &intel_connector->base;
|
||||
- connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
|
||||
|
||||
@@ -2285,7 +2284,6 @@ intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device)
|
||||
return false;
|
||||
|
||||
connector = &intel_connector->base;
|
||||
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
|
||||
sdvo_connector = intel_connector->dev_priv;
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
|
||||
index 149ed22..9a61f3c 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
|
||||
@@ -846,7 +846,6 @@ nouveau_connector_create(struct drm_device *dev,
|
||||
|
||||
switch (dcb->type) {
|
||||
case DCB_CONNECTOR_VGA:
|
||||
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
if (dev_priv->card_type >= NV_50) {
|
||||
drm_connector_attach_property(connector,
|
||||
dev->mode_config.scaling_mode_property,
|
||||
@@ -858,17 +857,6 @@ nouveau_connector_create(struct drm_device *dev,
|
||||
case DCB_CONNECTOR_TV_3:
|
||||
nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
|
||||
break;
|
||||
- case DCB_CONNECTOR_DP:
|
||||
- case DCB_CONNECTOR_eDP:
|
||||
- case DCB_CONNECTOR_HDMI_0:
|
||||
- case DCB_CONNECTOR_HDMI_1:
|
||||
- case DCB_CONNECTOR_DVI_I:
|
||||
- case DCB_CONNECTOR_DVI_D:
|
||||
- if (dev_priv->card_type >= NV_50)
|
||||
- connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
- else
|
||||
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
- /* fall-through */
|
||||
default:
|
||||
nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
|
||||
index 74e6b4e..9d7928f 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
|
||||
@@ -101,6 +101,5 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
|
||||
|
||||
const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
|
||||
.fb_create = nouveau_user_framebuffer_create,
|
||||
- .output_poll_changed = nouveau_fbcon_output_poll_changed,
|
||||
};
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
|
||||
index c9a4a0d..0a59f96 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
|
||||
@@ -326,11 +326,15 @@ nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper,
|
||||
return new_fb;
|
||||
}
|
||||
|
||||
-void
|
||||
-nouveau_fbcon_output_poll_changed(struct drm_device *dev)
|
||||
+void nouveau_fbcon_hotplug(struct drm_device *dev)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
- drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper);
|
||||
+ drm_helper_fb_hpd_irq_event(&dev_priv->nfbdev->helper);
|
||||
+}
|
||||
+
|
||||
+static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper)
|
||||
+{
|
||||
+ drm_helper_fb_hotplug_event(fb_helper, true);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -370,6 +374,7 @@ static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
|
||||
.gamma_set = nouveau_fbcon_gamma_set,
|
||||
.gamma_get = nouveau_fbcon_gamma_get,
|
||||
.fb_probe = nouveau_fbcon_find_or_create_single,
|
||||
+ .fb_output_status_changed = nouveau_fbcon_output_status_changed,
|
||||
};
|
||||
|
||||
|
||||
@@ -387,7 +392,7 @@ int nouveau_fbcon_init(struct drm_device *dev)
|
||||
dev_priv->nfbdev = nfbdev;
|
||||
nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
|
||||
|
||||
- ret = drm_fb_helper_init(dev, &nfbdev->helper, 2, 4);
|
||||
+ ret = drm_fb_helper_init(dev, &nfbdev->helper, 2, 4, true);
|
||||
if (ret) {
|
||||
kfree(nfbdev);
|
||||
return ret;
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
|
||||
index e7e1268..bf8e00d 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
|
||||
@@ -58,6 +58,6 @@ void nouveau_fbcon_zfill_all(struct drm_device *dev);
|
||||
void nouveau_fbcon_save_disable_accel(struct drm_device *dev);
|
||||
void nouveau_fbcon_restore_accel(struct drm_device *dev);
|
||||
|
||||
-void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
|
||||
+void nouveau_fbcon_hotplug(struct drm_device *dev);
|
||||
#endif /* __NV50_FBCON_H__ */
|
||||
|
||||
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
|
||||
index b02a231..4dcb976 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
|
||||
@@ -519,10 +519,8 @@ nouveau_card_init(struct drm_device *dev)
|
||||
|
||||
dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
|
||||
|
||||
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
nouveau_fbcon_init(dev);
|
||||
- drm_kms_helper_poll_init(dev);
|
||||
- }
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -844,7 +842,6 @@ int nouveau_unload(struct drm_device *dev)
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
- drm_kms_helper_poll_fini(dev);
|
||||
nouveau_fbcon_fini(dev);
|
||||
if (dev_priv->card_type >= NV_50)
|
||||
nv50_display_destroy(dev);
|
||||
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
|
||||
index 580a5d1..e6a44af 100644
|
||||
--- a/drivers/gpu/drm/nouveau/nv50_display.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
|
||||
@@ -980,7 +980,7 @@ nv50_display_irq_hotplug_bh(struct work_struct *work)
|
||||
if (dev_priv->chipset >= 0x90)
|
||||
nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
|
||||
|
||||
- drm_helper_hpd_irq_event(dev);
|
||||
+ nouveau_fbcon_hotplug(dev);
|
||||
}
|
||||
|
||||
void
|
||||
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
|
||||
index 0c7ccc6..40a24c9 100644
|
||||
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
|
||||
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
|
||||
@@ -1085,7 +1085,6 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.load_detect_property,
|
||||
1);
|
||||
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_DVIA:
|
||||
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
|
||||
@@ -1212,12 +1211,6 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
- if (hpd->hpd == RADEON_HPD_NONE) {
|
||||
- if (i2c_bus->valid)
|
||||
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
- } else
|
||||
- connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
-
|
||||
connector->display_info.subpixel_order = subpixel_order;
|
||||
drm_sysfs_connector_add(connector);
|
||||
return;
|
||||
@@ -1279,7 +1272,6 @@ radeon_add_legacy_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.load_detect_property,
|
||||
1);
|
||||
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_DVIA:
|
||||
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
|
||||
@@ -1348,11 +1340,6 @@ radeon_add_legacy_connector(struct drm_device *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
- if (hpd->hpd == RADEON_HPD_NONE) {
|
||||
- if (i2c_bus->valid)
|
||||
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
- } else
|
||||
- connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
connector->display_info.subpixel_order = subpixel_order;
|
||||
drm_sysfs_connector_add(connector);
|
||||
return;
|
||||
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
|
||||
index c73444a..ed756be 100644
|
||||
--- a/drivers/gpu/drm/radeon/radeon_display.c
|
||||
+++ b/drivers/gpu/drm/radeon/radeon_display.c
|
||||
@@ -887,15 +887,8 @@ radeon_user_framebuffer_create(struct drm_device *dev,
|
||||
return &radeon_fb->base;
|
||||
}
|
||||
|
||||
-static void radeon_output_poll_changed(struct drm_device *dev)
|
||||
-{
|
||||
- struct radeon_device *rdev = dev->dev_private;
|
||||
- radeon_fb_output_poll_changed(rdev);
|
||||
-}
|
||||
-
|
||||
static const struct drm_mode_config_funcs radeon_mode_funcs = {
|
||||
.fb_create = radeon_user_framebuffer_create,
|
||||
- .output_poll_changed = radeon_output_poll_changed
|
||||
};
|
||||
|
||||
struct drm_prop_enum_list {
|
||||
@@ -1044,8 +1037,6 @@ int radeon_modeset_init(struct radeon_device *rdev)
|
||||
radeon_pm_init(rdev);
|
||||
|
||||
radeon_fbdev_init(rdev);
|
||||
- drm_kms_helper_poll_init(rdev->ddev);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1058,7 +1049,6 @@ void radeon_modeset_fini(struct radeon_device *rdev)
|
||||
radeon_pm_fini(rdev);
|
||||
|
||||
if (rdev->mode_info.mode_config_initialized) {
|
||||
- drm_kms_helper_poll_fini(rdev->ddev);
|
||||
radeon_hpd_fini(rdev);
|
||||
drm_mode_config_cleanup(rdev->ddev);
|
||||
rdev->mode_info.mode_config_initialized = false;
|
||||
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
|
||||
index dc1634b..7dc38f6 100644
|
||||
--- a/drivers/gpu/drm/radeon/radeon_fb.c
|
||||
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
|
||||
@@ -316,9 +316,16 @@ int radeon_parse_options(char *options)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-void radeon_fb_output_poll_changed(struct radeon_device *rdev)
|
||||
+void radeonfb_hotplug(struct drm_device *dev, bool polled)
|
||||
{
|
||||
- drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper);
|
||||
+ struct radeon_device *rdev = dev->dev_private;
|
||||
+
|
||||
+ drm_helper_fb_hpd_irq_event(&rdev->mode_info.rfbdev->helper);
|
||||
+}
|
||||
+
|
||||
+static void radeon_fb_output_status_changed(struct drm_fb_helper *fb_helper)
|
||||
+{
|
||||
+ drm_helper_fb_hotplug_event(fb_helper, true);
|
||||
}
|
||||
|
||||
static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
|
||||
@@ -357,6 +364,7 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
|
||||
.gamma_set = radeon_crtc_fb_gamma_set,
|
||||
.gamma_get = radeon_crtc_fb_gamma_get,
|
||||
.fb_probe = radeon_fb_find_or_create_single,
|
||||
+ .fb_output_status_changed = radeon_fb_output_status_changed,
|
||||
};
|
||||
|
||||
int radeon_fbdev_init(struct radeon_device *rdev)
|
||||
@@ -379,7 +387,7 @@ int radeon_fbdev_init(struct radeon_device *rdev)
|
||||
|
||||
ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
|
||||
rdev->num_crtc,
|
||||
- RADEONFB_CONN_LIMIT);
|
||||
+ RADEONFB_CONN_LIMIT, true);
|
||||
if (ret) {
|
||||
kfree(rfbdev);
|
||||
return ret;
|
||||
@@ -388,6 +396,7 @@ int radeon_fbdev_init(struct radeon_device *rdev)
|
||||
drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
|
||||
drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
|
||||
return 0;
|
||||
+
|
||||
}
|
||||
|
||||
void radeon_fbdev_fini(struct radeon_device *rdev)
|
||||
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
|
||||
index 059bfa4..b0178de 100644
|
||||
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
|
||||
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
|
||||
@@ -26,7 +26,6 @@
|
||||
* Jerome Glisse
|
||||
*/
|
||||
#include "drmP.h"
|
||||
-#include "drm_crtc_helper.h"
|
||||
#include "radeon_drm.h"
|
||||
#include "radeon_reg.h"
|
||||
#include "radeon.h"
|
||||
@@ -56,7 +55,9 @@ static void radeon_hotplug_work_func(struct work_struct *work)
|
||||
radeon_connector_hotplug(connector);
|
||||
}
|
||||
/* Just fire off a uevent and let userspace tell us what to do */
|
||||
- drm_helper_hpd_irq_event(dev);
|
||||
+ radeonfb_hotplug(dev, false);
|
||||
+
|
||||
+ drm_sysfs_hotplug_event(dev);
|
||||
}
|
||||
|
||||
void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
|
||||
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
|
||||
index 67358ba..fdd1611 100644
|
||||
--- a/drivers/gpu/drm/radeon/radeon_mode.h
|
||||
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
|
||||
@@ -588,6 +588,5 @@ void radeon_fbdev_fini(struct radeon_device *rdev);
|
||||
void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
|
||||
int radeon_fbdev_total_size(struct radeon_device *rdev);
|
||||
bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
|
||||
-
|
||||
-void radeon_fb_output_poll_changed(struct radeon_device *rdev);
|
||||
+void radeonfb_hotplug(struct drm_device *dev, bool polled);
|
||||
#endif
|
||||
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
|
||||
index 93a1a31..a7148d2 100644
|
||||
--- a/include/drm/drm_crtc.h
|
||||
+++ b/include/drm/drm_crtc.h
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <linux/idr.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
-#include <linux/slow-work.h>
|
||||
|
||||
struct drm_device;
|
||||
struct drm_mode_set;
|
||||
@@ -461,15 +460,6 @@ enum drm_connector_force {
|
||||
DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */
|
||||
};
|
||||
|
||||
-/* should we poll this connector for connects and disconnects */
|
||||
-/* hot plug detectable */
|
||||
-#define DRM_CONNECTOR_POLL_HPD (1 << 0)
|
||||
-/* poll for connections */
|
||||
-#define DRM_CONNECTOR_POLL_CONNECT (1 << 1)
|
||||
-/* can cleanly poll for disconnections without flickering the screen */
|
||||
-/* DACs should rarely do this without a lot of testing */
|
||||
-#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)
|
||||
-
|
||||
/**
|
||||
* drm_connector - central DRM connector control structure
|
||||
* @crtc: CRTC this connector is currently connected to, NULL if none
|
||||
@@ -514,8 +504,6 @@ struct drm_connector {
|
||||
u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY];
|
||||
uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY];
|
||||
|
||||
- uint8_t polled; /* DRM_CONNECTOR_POLL_* */
|
||||
-
|
||||
/* requested DPMS state */
|
||||
int dpms;
|
||||
|
||||
@@ -555,7 +543,6 @@ struct drm_mode_set {
|
||||
*/
|
||||
struct drm_mode_config_funcs {
|
||||
struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd);
|
||||
- void (*output_poll_changed)(struct drm_device *dev);
|
||||
};
|
||||
|
||||
struct drm_mode_group {
|
||||
@@ -593,10 +580,6 @@ struct drm_mode_config {
|
||||
struct drm_mode_config_funcs *funcs;
|
||||
resource_size_t fb_base;
|
||||
|
||||
- /* output poll support */
|
||||
- bool poll_enabled;
|
||||
- struct delayed_slow_work output_poll_slow_work;
|
||||
-
|
||||
/* pointers to standard properties */
|
||||
struct list_head property_blob_list;
|
||||
struct drm_property *edid_property;
|
||||
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
|
||||
index 1121f77..b1fa0f8 100644
|
||||
--- a/include/drm/drm_crtc_helper.h
|
||||
+++ b/include/drm/drm_crtc_helper.h
|
||||
@@ -127,10 +127,4 @@ static inline void drm_connector_helper_add(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
extern int drm_helper_resume_force_mode(struct drm_device *dev);
|
||||
-extern void drm_kms_helper_poll_init(struct drm_device *dev);
|
||||
-extern void drm_kms_helper_poll_fini(struct drm_device *dev);
|
||||
-extern void drm_helper_hpd_irq_event(struct drm_device *dev);
|
||||
-
|
||||
-extern void drm_kms_helper_poll_disable(struct drm_device *dev);
|
||||
-extern void drm_kms_helper_poll_enable(struct drm_device *dev);
|
||||
#endif
|
||||
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
|
||||
index f0a6afc..9b55a94 100644
|
||||
--- a/include/drm/drm_fb_helper.h
|
||||
+++ b/include/drm/drm_fb_helper.h
|
||||
@@ -30,6 +30,8 @@
|
||||
#ifndef DRM_FB_HELPER_H
|
||||
#define DRM_FB_HELPER_H
|
||||
|
||||
+#include <linux/slow-work.h>
|
||||
+
|
||||
struct drm_fb_helper;
|
||||
|
||||
struct drm_fb_helper_crtc {
|
||||
@@ -69,6 +71,9 @@ struct drm_fb_helper_funcs {
|
||||
|
||||
int (*fb_probe)(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes);
|
||||
+
|
||||
+ void (*fb_output_status_changed)(struct drm_fb_helper *helper);
|
||||
+
|
||||
};
|
||||
|
||||
struct drm_fb_helper_connector {
|
||||
@@ -90,6 +95,8 @@ struct drm_fb_helper {
|
||||
u32 pseudo_palette[17];
|
||||
struct list_head kernel_fb_list;
|
||||
|
||||
+ struct delayed_slow_work output_status_change_slow_work;
|
||||
+ bool poll_enabled;
|
||||
/* we got a hotplug but fbdev wasn't running the console
|
||||
delay until next set_par */
|
||||
bool delayed_hotplug;
|
||||
@@ -100,7 +107,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper,
|
||||
|
||||
int drm_fb_helper_init(struct drm_device *dev,
|
||||
struct drm_fb_helper *helper, int crtc_count,
|
||||
- int max_conn);
|
||||
+ int max_conn, bool polled);
|
||||
void drm_fb_helper_fini(struct drm_fb_helper *helper);
|
||||
int drm_fb_helper_blank(int blank, struct fb_info *info);
|
||||
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
|
||||
@@ -123,8 +130,10 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
|
||||
|
||||
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
|
||||
|
||||
-bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
|
||||
+bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
|
||||
+ bool polled);
|
||||
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
|
||||
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
|
||||
|
||||
+void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper);
|
||||
#endif
|
||||
--
|
||||
1.7.0.1
|
||||
|
|
@ -0,0 +1,592 @@
|
|||
From f1719f0dcd68ca4de42c7b00ef2b37658007dda7 Mon Sep 17 00:00:00 2001
|
||||
From: Francisco Jerez <currojerez@riseup.net>
|
||||
Date: Thu, 22 Jul 2010 17:06:18 +0200
|
||||
Subject: [PATCH 2/5] drm-sil164-module
|
||||
|
||||
drm: Import driver for the sil164 I2C TMDS transmitter.
|
||||
|
||||
sil164 transmitters are used for DVI outputs on Intel/nvidia and ATI setups.
|
||||
|
||||
So far only nouveau can use this driver.
|
||||
|
||||
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
||||
Tested-by: Patrice Mandin <patmandin@gmail.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/i2c/Makefile | 3 +
|
||||
drivers/gpu/drm/i2c/sil164_drv.c | 462 ++++++++++++++++++++++++++++++++++++++
|
||||
drivers/gpu/drm/nouveau/Kconfig | 9 +
|
||||
include/drm/i2c/sil164.h | 63 +++++
|
||||
4 files changed, 537 insertions(+), 0 deletions(-)
|
||||
create mode 100644 drivers/gpu/drm/i2c/sil164_drv.c
|
||||
create mode 100644 include/drm/i2c/sil164.h
|
||||
|
||||
diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
|
||||
index 6d2abaf..9286256 100644
|
||||
--- a/drivers/gpu/drm/i2c/Makefile
|
||||
+++ b/drivers/gpu/drm/i2c/Makefile
|
||||
@@ -2,3 +2,6 @@ ccflags-y := -Iinclude/drm
|
||||
|
||||
ch7006-y := ch7006_drv.o ch7006_mode.o
|
||||
obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
|
||||
+
|
||||
+sil164-y := sil164_drv.o
|
||||
+obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o
|
||||
diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c
|
||||
new file mode 100644
|
||||
index 0000000..0b67732
|
||||
--- /dev/null
|
||||
+++ b/drivers/gpu/drm/i2c/sil164_drv.c
|
||||
@@ -0,0 +1,462 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2010 Francisco Jerez.
|
||||
+ * All Rights Reserved.
|
||||
+ *
|
||||
+ * Permission is hereby granted, free of charge, to any person obtaining
|
||||
+ * a copy of this software and associated documentation files (the
|
||||
+ * "Software"), to deal in the Software without restriction, including
|
||||
+ * without limitation the rights to use, copy, modify, merge, publish,
|
||||
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
||||
+ * permit persons to whom the Software is furnished to do so, subject to
|
||||
+ * the following conditions:
|
||||
+ *
|
||||
+ * The above copyright notice and this permission notice (including the
|
||||
+ * next paragraph) shall be included in all copies or substantial
|
||||
+ * portions of the Software.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
|
||||
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include "drmP.h"
|
||||
+#include "drm_crtc_helper.h"
|
||||
+#include "drm_encoder_slave.h"
|
||||
+#include "i2c/sil164.h"
|
||||
+
|
||||
+struct sil164_priv {
|
||||
+ struct sil164_encoder_params config;
|
||||
+ struct i2c_client *duallink_slave;
|
||||
+
|
||||
+ uint8_t saved_state[0x10];
|
||||
+ uint8_t saved_slave_state[0x10];
|
||||
+};
|
||||
+
|
||||
+#define to_sil164_priv(x) \
|
||||
+ ((struct sil164_priv *)to_encoder_slave(x)->slave_priv)
|
||||
+
|
||||
+#define sil164_dbg(client, format, ...) do { \
|
||||
+ if (drm_debug & DRM_UT_KMS) \
|
||||
+ dev_printk(KERN_DEBUG, &client->dev, \
|
||||
+ "%s: " format, __func__, ## __VA_ARGS__); \
|
||||
+ } while (0)
|
||||
+#define sil164_info(client, format, ...) \
|
||||
+ dev_info(&client->dev, format, __VA_ARGS__)
|
||||
+#define sil164_err(client, format, ...) \
|
||||
+ dev_err(&client->dev, format, __VA_ARGS__)
|
||||
+
|
||||
+#define SIL164_I2C_ADDR_MASTER 0x38
|
||||
+#define SIL164_I2C_ADDR_SLAVE 0x39
|
||||
+
|
||||
+/* HW register definitions */
|
||||
+
|
||||
+#define SIL164_VENDOR_LO 0x0
|
||||
+#define SIL164_VENDOR_HI 0x1
|
||||
+#define SIL164_DEVICE_LO 0x2
|
||||
+#define SIL164_DEVICE_HI 0x3
|
||||
+#define SIL164_REVISION 0x4
|
||||
+#define SIL164_FREQ_MIN 0x6
|
||||
+#define SIL164_FREQ_MAX 0x7
|
||||
+#define SIL164_CONTROL0 0x8
|
||||
+# define SIL164_CONTROL0_POWER_ON 0x01
|
||||
+# define SIL164_CONTROL0_EDGE_RISING 0x02
|
||||
+# define SIL164_CONTROL0_INPUT_24BIT 0x04
|
||||
+# define SIL164_CONTROL0_DUAL_EDGE 0x08
|
||||
+# define SIL164_CONTROL0_HSYNC_ON 0x10
|
||||
+# define SIL164_CONTROL0_VSYNC_ON 0x20
|
||||
+#define SIL164_DETECT 0x9
|
||||
+# define SIL164_DETECT_INTR_STAT 0x01
|
||||
+# define SIL164_DETECT_HOTPLUG_STAT 0x02
|
||||
+# define SIL164_DETECT_RECEIVER_STAT 0x04
|
||||
+# define SIL164_DETECT_INTR_MODE_RECEIVER 0x00
|
||||
+# define SIL164_DETECT_INTR_MODE_HOTPLUG 0x08
|
||||
+# define SIL164_DETECT_OUT_MODE_HIGH 0x00
|
||||
+# define SIL164_DETECT_OUT_MODE_INTR 0x10
|
||||
+# define SIL164_DETECT_OUT_MODE_RECEIVER 0x20
|
||||
+# define SIL164_DETECT_OUT_MODE_HOTPLUG 0x30
|
||||
+# define SIL164_DETECT_VSWING_STAT 0x80
|
||||
+#define SIL164_CONTROL1 0xa
|
||||
+# define SIL164_CONTROL1_DESKEW_ENABLE 0x10
|
||||
+# define SIL164_CONTROL1_DESKEW_INCR_SHIFT 5
|
||||
+#define SIL164_GPIO 0xb
|
||||
+#define SIL164_CONTROL2 0xc
|
||||
+# define SIL164_CONTROL2_FILTER_ENABLE 0x01
|
||||
+# define SIL164_CONTROL2_FILTER_SETTING_SHIFT 1
|
||||
+# define SIL164_CONTROL2_DUALLINK_MASTER 0x40
|
||||
+# define SIL164_CONTROL2_SYNC_CONT 0x80
|
||||
+#define SIL164_DUALLINK 0xd
|
||||
+# define SIL164_DUALLINK_ENABLE 0x10
|
||||
+# define SIL164_DUALLINK_SKEW_SHIFT 5
|
||||
+#define SIL164_PLLZONE 0xe
|
||||
+# define SIL164_PLLZONE_STAT 0x08
|
||||
+# define SIL164_PLLZONE_FORCE_ON 0x10
|
||||
+# define SIL164_PLLZONE_FORCE_HIGH 0x20
|
||||
+
|
||||
+/* HW access functions */
|
||||
+
|
||||
+static void
|
||||
+sil164_write(struct i2c_client *client, uint8_t addr, uint8_t val)
|
||||
+{
|
||||
+ uint8_t buf[] = {addr, val};
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
|
||||
+ if (ret < 0)
|
||||
+ sil164_err(client, "Error %d writing to subaddress 0x%x\n",
|
||||
+ ret, addr);
|
||||
+}
|
||||
+
|
||||
+static uint8_t
|
||||
+sil164_read(struct i2c_client *client, uint8_t addr)
|
||||
+{
|
||||
+ uint8_t val;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = i2c_master_send(client, &addr, sizeof(addr));
|
||||
+ if (ret < 0)
|
||||
+ goto fail;
|
||||
+
|
||||
+ ret = i2c_master_recv(client, &val, sizeof(val));
|
||||
+ if (ret < 0)
|
||||
+ goto fail;
|
||||
+
|
||||
+ return val;
|
||||
+
|
||||
+fail:
|
||||
+ sil164_err(client, "Error %d reading from subaddress 0x%x\n",
|
||||
+ ret, addr);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+sil164_save_state(struct i2c_client *client, uint8_t *state)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0x8; i <= 0xe; i++)
|
||||
+ state[i] = sil164_read(client, i);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+sil164_restore_state(struct i2c_client *client, uint8_t *state)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0x8; i <= 0xe; i++)
|
||||
+ sil164_write(client, i, state[i]);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+sil164_set_power_state(struct i2c_client *client, bool on)
|
||||
+{
|
||||
+ uint8_t control0 = sil164_read(client, SIL164_CONTROL0);
|
||||
+
|
||||
+ if (on)
|
||||
+ control0 |= SIL164_CONTROL0_POWER_ON;
|
||||
+ else
|
||||
+ control0 &= ~SIL164_CONTROL0_POWER_ON;
|
||||
+
|
||||
+ sil164_write(client, SIL164_CONTROL0, control0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+sil164_init_state(struct i2c_client *client,
|
||||
+ struct sil164_encoder_params *config,
|
||||
+ bool duallink)
|
||||
+{
|
||||
+ sil164_write(client, SIL164_CONTROL0,
|
||||
+ SIL164_CONTROL0_HSYNC_ON |
|
||||
+ SIL164_CONTROL0_VSYNC_ON |
|
||||
+ (config->input_edge ? SIL164_CONTROL0_EDGE_RISING : 0) |
|
||||
+ (config->input_width ? SIL164_CONTROL0_INPUT_24BIT : 0) |
|
||||
+ (config->input_dual ? SIL164_CONTROL0_DUAL_EDGE : 0));
|
||||
+
|
||||
+ sil164_write(client, SIL164_DETECT,
|
||||
+ SIL164_DETECT_INTR_STAT |
|
||||
+ SIL164_DETECT_OUT_MODE_RECEIVER);
|
||||
+
|
||||
+ sil164_write(client, SIL164_CONTROL1,
|
||||
+ (config->input_skew ? SIL164_CONTROL1_DESKEW_ENABLE : 0) |
|
||||
+ (((config->input_skew + 4) & 0x7)
|
||||
+ << SIL164_CONTROL1_DESKEW_INCR_SHIFT));
|
||||
+
|
||||
+ sil164_write(client, SIL164_CONTROL2,
|
||||
+ SIL164_CONTROL2_SYNC_CONT |
|
||||
+ (config->pll_filter ? 0 : SIL164_CONTROL2_FILTER_ENABLE) |
|
||||
+ (4 << SIL164_CONTROL2_FILTER_SETTING_SHIFT));
|
||||
+
|
||||
+ sil164_write(client, SIL164_PLLZONE, 0);
|
||||
+
|
||||
+ if (duallink)
|
||||
+ sil164_write(client, SIL164_DUALLINK,
|
||||
+ SIL164_DUALLINK_ENABLE |
|
||||
+ (((config->duallink_skew + 4) & 0x7)
|
||||
+ << SIL164_DUALLINK_SKEW_SHIFT));
|
||||
+ else
|
||||
+ sil164_write(client, SIL164_DUALLINK, 0);
|
||||
+}
|
||||
+
|
||||
+/* DRM encoder functions */
|
||||
+
|
||||
+static void
|
||||
+sil164_encoder_set_config(struct drm_encoder *encoder, void *params)
|
||||
+{
|
||||
+ struct sil164_priv *priv = to_sil164_priv(encoder);
|
||||
+
|
||||
+ priv->config = *(struct sil164_encoder_params *)params;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+sil164_encoder_dpms(struct drm_encoder *encoder, int mode)
|
||||
+{
|
||||
+ struct sil164_priv *priv = to_sil164_priv(encoder);
|
||||
+ bool on = (mode == DRM_MODE_DPMS_ON);
|
||||
+ bool duallink = (on && encoder->crtc->mode.clock > 165000);
|
||||
+
|
||||
+ sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on);
|
||||
+
|
||||
+ if (priv->duallink_slave)
|
||||
+ sil164_set_power_state(priv->duallink_slave, duallink);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+sil164_encoder_save(struct drm_encoder *encoder)
|
||||
+{
|
||||
+ struct sil164_priv *priv = to_sil164_priv(encoder);
|
||||
+
|
||||
+ sil164_save_state(drm_i2c_encoder_get_client(encoder),
|
||||
+ priv->saved_state);
|
||||
+
|
||||
+ if (priv->duallink_slave)
|
||||
+ sil164_save_state(priv->duallink_slave,
|
||||
+ priv->saved_slave_state);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+sil164_encoder_restore(struct drm_encoder *encoder)
|
||||
+{
|
||||
+ struct sil164_priv *priv = to_sil164_priv(encoder);
|
||||
+
|
||||
+ sil164_restore_state(drm_i2c_encoder_get_client(encoder),
|
||||
+ priv->saved_state);
|
||||
+
|
||||
+ if (priv->duallink_slave)
|
||||
+ sil164_restore_state(priv->duallink_slave,
|
||||
+ priv->saved_slave_state);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+sil164_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
+ struct drm_display_mode *mode,
|
||||
+ struct drm_display_mode *adjusted_mode)
|
||||
+{
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+sil164_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
+ struct drm_display_mode *mode)
|
||||
+{
|
||||
+ struct sil164_priv *priv = to_sil164_priv(encoder);
|
||||
+
|
||||
+ if (mode->clock < 32000)
|
||||
+ return MODE_CLOCK_LOW;
|
||||
+
|
||||
+ if (mode->clock > 330000 ||
|
||||
+ (mode->clock > 165000 && !priv->duallink_slave))
|
||||
+ return MODE_CLOCK_HIGH;
|
||||
+
|
||||
+ return MODE_OK;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+sil164_encoder_mode_set(struct drm_encoder *encoder,
|
||||
+ struct drm_display_mode *mode,
|
||||
+ struct drm_display_mode *adjusted_mode)
|
||||
+{
|
||||
+ struct sil164_priv *priv = to_sil164_priv(encoder);
|
||||
+ bool duallink = adjusted_mode->clock > 165000;
|
||||
+
|
||||
+ sil164_init_state(drm_i2c_encoder_get_client(encoder),
|
||||
+ &priv->config, duallink);
|
||||
+
|
||||
+ if (priv->duallink_slave)
|
||||
+ sil164_init_state(priv->duallink_slave,
|
||||
+ &priv->config, duallink);
|
||||
+
|
||||
+ sil164_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
|
||||
+}
|
||||
+
|
||||
+static enum drm_connector_status
|
||||
+sil164_encoder_detect(struct drm_encoder *encoder,
|
||||
+ struct drm_connector *connector)
|
||||
+{
|
||||
+ struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
|
||||
+
|
||||
+ if (sil164_read(client, SIL164_DETECT) & SIL164_DETECT_HOTPLUG_STAT)
|
||||
+ return connector_status_connected;
|
||||
+ else
|
||||
+ return connector_status_disconnected;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+sil164_encoder_get_modes(struct drm_encoder *encoder,
|
||||
+ struct drm_connector *connector)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+sil164_encoder_create_resources(struct drm_encoder *encoder,
|
||||
+ struct drm_connector *connector)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+sil164_encoder_set_property(struct drm_encoder *encoder,
|
||||
+ struct drm_connector *connector,
|
||||
+ struct drm_property *property,
|
||||
+ uint64_t val)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+sil164_encoder_destroy(struct drm_encoder *encoder)
|
||||
+{
|
||||
+ struct sil164_priv *priv = to_sil164_priv(encoder);
|
||||
+
|
||||
+ if (priv->duallink_slave)
|
||||
+ i2c_unregister_device(priv->duallink_slave);
|
||||
+
|
||||
+ kfree(priv);
|
||||
+ drm_i2c_encoder_destroy(encoder);
|
||||
+}
|
||||
+
|
||||
+static struct drm_encoder_slave_funcs sil164_encoder_funcs = {
|
||||
+ .set_config = sil164_encoder_set_config,
|
||||
+ .destroy = sil164_encoder_destroy,
|
||||
+ .dpms = sil164_encoder_dpms,
|
||||
+ .save = sil164_encoder_save,
|
||||
+ .restore = sil164_encoder_restore,
|
||||
+ .mode_fixup = sil164_encoder_mode_fixup,
|
||||
+ .mode_valid = sil164_encoder_mode_valid,
|
||||
+ .mode_set = sil164_encoder_mode_set,
|
||||
+ .detect = sil164_encoder_detect,
|
||||
+ .get_modes = sil164_encoder_get_modes,
|
||||
+ .create_resources = sil164_encoder_create_resources,
|
||||
+ .set_property = sil164_encoder_set_property,
|
||||
+};
|
||||
+
|
||||
+/* I2C driver functions */
|
||||
+
|
||||
+static int
|
||||
+sil164_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
+{
|
||||
+ int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 |
|
||||
+ sil164_read(client, SIL164_VENDOR_LO);
|
||||
+ int device = sil164_read(client, SIL164_DEVICE_HI) << 8 |
|
||||
+ sil164_read(client, SIL164_DEVICE_LO);
|
||||
+ int rev = sil164_read(client, SIL164_REVISION);
|
||||
+
|
||||
+ if (vendor != 0x1 || device != 0x6) {
|
||||
+ sil164_dbg(client, "Unknown device %x:%x.%x\n",
|
||||
+ vendor, device, rev);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ sil164_info(client, "Detected device %x:%x.%x\n",
|
||||
+ vendor, device, rev);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+sil164_remove(struct i2c_client *client)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct i2c_client *
|
||||
+sil164_detect_slave(struct i2c_client *client)
|
||||
+{
|
||||
+ struct i2c_adapter *adap = client->adapter;
|
||||
+ struct i2c_msg msg = {
|
||||
+ .addr = SIL164_I2C_ADDR_SLAVE,
|
||||
+ .len = 0,
|
||||
+ };
|
||||
+ const struct i2c_board_info info = {
|
||||
+ I2C_BOARD_INFO("sil164", SIL164_I2C_ADDR_SLAVE)
|
||||
+ };
|
||||
+
|
||||
+ if (i2c_transfer(adap, &msg, 1) != 1) {
|
||||
+ sil164_dbg(adap, "No dual-link slave found.");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ return i2c_new_device(adap, &info);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+sil164_encoder_init(struct i2c_client *client,
|
||||
+ struct drm_device *dev,
|
||||
+ struct drm_encoder_slave *encoder)
|
||||
+{
|
||||
+ struct sil164_priv *priv;
|
||||
+
|
||||
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ encoder->slave_priv = priv;
|
||||
+ encoder->slave_funcs = &sil164_encoder_funcs;
|
||||
+
|
||||
+ priv->duallink_slave = sil164_detect_slave(client);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct i2c_device_id sil164_ids[] = {
|
||||
+ { "sil164", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, sil164_ids);
|
||||
+
|
||||
+static struct drm_i2c_encoder_driver sil164_driver = {
|
||||
+ .i2c_driver = {
|
||||
+ .probe = sil164_probe,
|
||||
+ .remove = sil164_remove,
|
||||
+ .driver = {
|
||||
+ .name = "sil164",
|
||||
+ },
|
||||
+ .id_table = sil164_ids,
|
||||
+ },
|
||||
+ .encoder_init = sil164_encoder_init,
|
||||
+};
|
||||
+
|
||||
+/* Module initialization */
|
||||
+
|
||||
+static int __init
|
||||
+sil164_init(void)
|
||||
+{
|
||||
+ return drm_i2c_encoder_register(THIS_MODULE, &sil164_driver);
|
||||
+}
|
||||
+
|
||||
+static void __exit
|
||||
+sil164_exit(void)
|
||||
+{
|
||||
+ drm_i2c_encoder_unregister(&sil164_driver);
|
||||
+}
|
||||
+
|
||||
+MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>");
|
||||
+MODULE_DESCRIPTION("Silicon Image sil164 TMDS transmitter driver");
|
||||
+MODULE_LICENSE("GPL and additional rights");
|
||||
+
|
||||
+module_init(sil164_init);
|
||||
+module_exit(sil164_exit);
|
||||
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
|
||||
index 1175429..6b8967a 100644
|
||||
--- a/drivers/gpu/drm/nouveau/Kconfig
|
||||
+++ b/drivers/gpu/drm/nouveau/Kconfig
|
||||
@@ -41,4 +41,13 @@ config DRM_I2C_CH7006
|
||||
|
||||
This driver is currently only useful if you're also using
|
||||
the nouveau driver.
|
||||
+
|
||||
+config DRM_I2C_SIL164
|
||||
+ tristate "Silicon Image sil164 TMDS transmitter"
|
||||
+ default m if DRM_NOUVEAU
|
||||
+ help
|
||||
+ Support for sil164 and similar single-link (or dual-link
|
||||
+ when used in pairs) TMDS transmitters, used in some nVidia
|
||||
+ video cards.
|
||||
+
|
||||
endmenu
|
||||
diff --git a/include/drm/i2c/sil164.h b/include/drm/i2c/sil164.h
|
||||
new file mode 100644
|
||||
index 0000000..205e273
|
||||
--- /dev/null
|
||||
+++ b/include/drm/i2c/sil164.h
|
||||
@@ -0,0 +1,63 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2010 Francisco Jerez.
|
||||
+ * All Rights Reserved.
|
||||
+ *
|
||||
+ * Permission is hereby granted, free of charge, to any person obtaining
|
||||
+ * a copy of this software and associated documentation files (the
|
||||
+ * "Software"), to deal in the Software without restriction, including
|
||||
+ * without limitation the rights to use, copy, modify, merge, publish,
|
||||
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
||||
+ * permit persons to whom the Software is furnished to do so, subject to
|
||||
+ * the following conditions:
|
||||
+ *
|
||||
+ * The above copyright notice and this permission notice (including the
|
||||
+ * next paragraph) shall be included in all copies or substantial
|
||||
+ * portions of the Software.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
|
||||
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#ifndef __DRM_I2C_SIL164_H__
|
||||
+#define __DRM_I2C_SIL164_H__
|
||||
+
|
||||
+/**
|
||||
+ * struct sil164_encoder_params
|
||||
+ *
|
||||
+ * Describes how the sil164 is connected to the GPU. It should be used
|
||||
+ * as the @params parameter of its @set_config method.
|
||||
+ *
|
||||
+ * See "http://www.siliconimage.com/docs/SiI-DS-0021-E-164.pdf".
|
||||
+ */
|
||||
+struct sil164_encoder_params {
|
||||
+ enum {
|
||||
+ SIL164_INPUT_EDGE_FALLING = 0,
|
||||
+ SIL164_INPUT_EDGE_RISING
|
||||
+ } input_edge;
|
||||
+
|
||||
+ enum {
|
||||
+ SIL164_INPUT_WIDTH_12BIT = 0,
|
||||
+ SIL164_INPUT_WIDTH_24BIT
|
||||
+ } input_width;
|
||||
+
|
||||
+ enum {
|
||||
+ SIL164_INPUT_SINGLE_EDGE = 0,
|
||||
+ SIL164_INPUT_DUAL_EDGE
|
||||
+ } input_dual;
|
||||
+
|
||||
+ enum {
|
||||
+ SIL164_PLL_FILTER_ON = 0,
|
||||
+ SIL164_PLL_FILTER_OFF,
|
||||
+ } pll_filter;
|
||||
+
|
||||
+ int input_skew; /** < Allowed range [-4, 3], use 0 for no de-skew. */
|
||||
+ int duallink_skew; /** < Allowed range [-4, 3]. */
|
||||
+};
|
||||
+
|
||||
+#endif
|
||||
--
|
||||
1.7.2
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
From 74ef65374ae6d0eead4a631aea3aca80d016ff0f Mon Sep 17 00:00:00 2001
|
||||
From: Francisco Jerez <currojerez@riseup.net>
|
||||
Date: Thu, 22 Jul 2010 17:07:38 +0200
|
||||
Subject: [PATCH 1/5] drm-simplify-i2c-config
|
||||
|
||||
drm/kms: Simplify setup of the initial I2C encoder config.
|
||||
|
||||
In most use cases the driver will be using the same static config all
|
||||
the time: interpreting i2c_board_info::platform_data as the default
|
||||
config we can can save the GPU driver a redundant set_config() call.
|
||||
|
||||
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/drm_encoder_slave.c | 7 +++++++
|
||||
1 files changed, 7 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c
|
||||
index f018469..d62c064 100644
|
||||
--- a/drivers/gpu/drm/drm_encoder_slave.c
|
||||
+++ b/drivers/gpu/drm/drm_encoder_slave.c
|
||||
@@ -41,6 +41,9 @@
|
||||
* &drm_encoder_slave. The @slave_funcs field will be initialized with
|
||||
* the hooks provided by the slave driver.
|
||||
*
|
||||
+ * If @info->platform_data is non-NULL it will be used as the initial
|
||||
+ * slave config.
|
||||
+ *
|
||||
* Returns 0 on success or a negative errno on failure, in particular,
|
||||
* -ENODEV is returned when no matching driver is found.
|
||||
*/
|
||||
@@ -85,6 +88,10 @@ int drm_i2c_encoder_init(struct drm_device *dev,
|
||||
if (err)
|
||||
goto fail_unregister;
|
||||
|
||||
+ if (info->platform_data)
|
||||
+ encoder->slave_funcs->set_config(&encoder->base,
|
||||
+ info->platform_data);
|
||||
+
|
||||
return 0;
|
||||
|
||||
fail_unregister:
|
||||
--
|
||||
1.7.2
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
From 08ae078a33245bc01dcf895bd886f30103cc6178 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Hellstrom <thellstrom@vmware.com>
|
||||
Date: Thu, 30 Sep 2010 12:36:45 +0200
|
||||
Subject: drm/ttm: Fix two race conditions + fix busy codepaths
|
||||
|
||||
This fixes a race pointed out by Dave Airlie where we don't take a buffer
|
||||
object about to be destroyed off the LRU lists properly. It also fixes a rare
|
||||
case where a buffer object could be destroyed in the middle of an
|
||||
accelerated eviction.
|
||||
|
||||
The patch also adds a utility function that can be used to prematurely
|
||||
release GPU memory space usage of an object waiting to be destroyed.
|
||||
For example during eviction or swapout.
|
||||
|
||||
The above mentioned commit didn't queue the buffer on the delayed destroy
|
||||
list under some rare circumstances. It also didn't completely honor the
|
||||
remove_all parameter.
|
||||
|
||||
Fixes:
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=615505
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591061
|
||||
|
||||
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/ttm/ttm_bo.c | 84 +++++++++++++++++++++++++++++++++++------
|
||||
include/drm/ttm/ttm_bo_api.h | 4 +-
|
||||
2 files changed, 74 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
|
||||
index 555ebb1..77f22ba 100644
|
||||
--- a/drivers/gpu/drm/ttm/ttm_bo.c
|
||||
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
|
||||
@@ -442,6 +442,43 @@ out_err:
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Call bo::reserved and with the lru lock held.
|
||||
+ * Will release GPU memory type usage on destruction.
|
||||
+ * This is the place to put in driver specific hooks.
|
||||
+ * Will release the bo::reserved lock and the
|
||||
+ * lru lock on exit.
|
||||
+ */
|
||||
+
|
||||
+static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
|
||||
+{
|
||||
+ struct ttm_bo_global *glob = bo->glob;
|
||||
+
|
||||
+ if (bo->ttm) {
|
||||
+
|
||||
+ /**
|
||||
+ * Release the lru_lock, since we don't want to have
|
||||
+ * an atomic requirement on ttm_tt[unbind|destroy].
|
||||
+ */
|
||||
+
|
||||
+ spin_unlock(&glob->lru_lock);
|
||||
+ ttm_tt_unbind(bo->ttm);
|
||||
+ ttm_tt_destroy(bo->ttm);
|
||||
+ bo->ttm = NULL;
|
||||
+ spin_lock(&glob->lru_lock);
|
||||
+ }
|
||||
+
|
||||
+ if (bo->mem.mm_node) {
|
||||
+ drm_mm_put_block(bo->mem.mm_node);
|
||||
+ bo->mem.mm_node = NULL;
|
||||
+ }
|
||||
+
|
||||
+ atomic_set(&bo->reserved, 0);
|
||||
+ wake_up_all(&bo->event_queue);
|
||||
+ spin_unlock(&glob->lru_lock);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/**
|
||||
* If bo idle, remove from delayed- and lru lists, and unref.
|
||||
* If not idle, and already on delayed list, do nothing.
|
||||
* If not idle, and not on delayed list, put on delayed list,
|
||||
@@ -456,6 +493,7 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
|
||||
int ret;
|
||||
|
||||
spin_lock(&bo->lock);
|
||||
+retry:
|
||||
(void) ttm_bo_wait(bo, false, false, !remove_all);
|
||||
|
||||
if (!bo->sync_obj) {
|
||||
@@ -464,32 +502,52 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
|
||||
spin_unlock(&bo->lock);
|
||||
|
||||
spin_lock(&glob->lru_lock);
|
||||
- put_count = ttm_bo_del_from_lru(bo);
|
||||
+ ret = ttm_bo_reserve_locked(bo, false, !remove_all, false, 0);
|
||||
+
|
||||
+ /**
|
||||
+ * Someone else has the object reserved. Bail and retry.
|
||||
+ */
|
||||
|
||||
- ret = ttm_bo_reserve_locked(bo, false, false, false, 0);
|
||||
- BUG_ON(ret);
|
||||
- if (bo->ttm)
|
||||
- ttm_tt_unbind(bo->ttm);
|
||||
+ if (unlikely(ret == -EBUSY)) {
|
||||
+ spin_unlock(&glob->lru_lock);
|
||||
+ spin_lock(&bo->lock);
|
||||
+ goto requeue;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * We can re-check for sync object without taking
|
||||
+ * the bo::lock since setting the sync object requires
|
||||
+ * also bo::reserved. A busy object at this point may
|
||||
+ * be caused by another thread starting an accelerated
|
||||
+ * eviction.
|
||||
+ */
|
||||
+
|
||||
+ if (unlikely(bo->sync_obj)) {
|
||||
+ atomic_set(&bo->reserved, 0);
|
||||
+ wake_up_all(&bo->event_queue);
|
||||
+ spin_unlock(&glob->lru_lock);
|
||||
+ spin_lock(&bo->lock);
|
||||
+ if (remove_all)
|
||||
+ goto retry;
|
||||
+ else
|
||||
+ goto requeue;
|
||||
+ }
|
||||
+
|
||||
+ put_count = ttm_bo_del_from_lru(bo);
|
||||
|
||||
if (!list_empty(&bo->ddestroy)) {
|
||||
list_del_init(&bo->ddestroy);
|
||||
++put_count;
|
||||
}
|
||||
- if (bo->mem.mm_node) {
|
||||
- bo->mem.mm_node->private = NULL;
|
||||
- drm_mm_put_block(bo->mem.mm_node);
|
||||
- bo->mem.mm_node = NULL;
|
||||
- }
|
||||
- spin_unlock(&glob->lru_lock);
|
||||
|
||||
- atomic_set(&bo->reserved, 0);
|
||||
+ ttm_bo_cleanup_memtype_use(bo);
|
||||
|
||||
while (put_count--)
|
||||
kref_put(&bo->list_kref, ttm_bo_ref_bug);
|
||||
|
||||
return 0;
|
||||
}
|
||||
-
|
||||
+requeue:
|
||||
spin_lock(&glob->lru_lock);
|
||||
if (list_empty(&bo->ddestroy)) {
|
||||
void *sync_obj = bo->sync_obj;
|
||||
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
|
||||
index 267a86c..2040e6c 100644
|
||||
--- a/include/drm/ttm/ttm_bo_api.h
|
||||
+++ b/include/drm/ttm/ttm_bo_api.h
|
||||
@@ -246,9 +246,11 @@ struct ttm_buffer_object {
|
||||
|
||||
atomic_t reserved;
|
||||
|
||||
-
|
||||
/**
|
||||
* Members protected by the bo::lock
|
||||
+ * In addition, setting sync_obj to anything else
|
||||
+ * than NULL requires bo::reserved to be held. This allows for
|
||||
+ * checking NULL while reserved but not holding bo::lock.
|
||||
*/
|
||||
|
||||
void *sync_obj_arg;
|
||||
--
|
||||
1.7.3.2
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
From 0fbecd400dd0a82d465b3086f209681e8c54cb0f Mon Sep 17 00:00:00 2001
|
||||
From: Francisco Jerez <currojerez@riseup.net>
|
||||
Date: Tue, 21 Sep 2010 02:15:15 +0200
|
||||
Subject: [PATCH] drm/ttm: Clear the ghost cpu_writers flag on ttm_buffer_object_transfer.
|
||||
|
||||
It makes sense for a BO to move after a process has requested
|
||||
exclusive RW access on it (e.g. because the BO used to be located in
|
||||
unmappable VRAM and we intercepted the CPU access from the fault
|
||||
handler).
|
||||
|
||||
If we let the ghost object inherit cpu_writers from the original
|
||||
object, ttm_bo_release_list() will raise a kernel BUG when the ghost
|
||||
object is destroyed. This can be reproduced with the nouveau driver on
|
||||
nv5x.
|
||||
|
||||
Reported-by: Marcin Slusarz <marcin.slusarz@gmail.com>
|
||||
Reviewed-by: Jerome Glisse <jglisse@redhat.com>
|
||||
Tested-by: Marcin Slusarz <marcin.slusarz@gmail.com>
|
||||
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
||||
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
||||
---
|
||||
drivers/gpu/drm/ttm/ttm_bo_util.c | 1 +
|
||||
1 files changed, 1 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
|
||||
index 7cffb3e..3451a82 100644
|
||||
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
|
||||
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
|
||||
@@ -351,6 +351,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
|
||||
INIT_LIST_HEAD(&fbo->lru);
|
||||
INIT_LIST_HEAD(&fbo->swap);
|
||||
fbo->vm_node = NULL;
|
||||
+ atomic_set(&fbo->cpu_writers, 0);
|
||||
|
||||
fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
|
||||
kref_init(&fbo->list_kref);
|
||||
--
|
||||
1.7.3.1
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
From: Bruce Allan <bruce.w.allan@intel.com>
|
||||
Date: Wed, 22 Sep 2010 17:15:54 +0000 (+0000)
|
||||
Subject: e1000e: 82566DC fails to get link
|
||||
X-Git-Tag: v2.6.36-rc6~6^2~23
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=5f3eed6fe0e36e4b56c8dd9160241a868ee0de2a
|
||||
|
||||
e1000e: 82566DC fails to get link
|
||||
|
||||
Two recent patches to cleanup the reset[1] and initial PHY configuration[2]
|
||||
code paths for ICH/PCH devices inadvertently left out a 10msec delay and
|
||||
device ID check respectively which are necessary for the 82566DC (device id
|
||||
0x104b) to be configured properly, otherwise it will not get link.
|
||||
|
||||
[1] commit e98cac447cc1cc418dff1d610a5c79c4f2bdec7f
|
||||
[2] commit 3f0c16e84438d657d29446f85fe375794a93f159
|
||||
|
||||
CC: stable@kernel.org
|
||||
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
|
||||
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
|
||||
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
|
||||
index fc8c3ce..6f9cb0d 100644
|
||||
--- a/drivers/net/e1000e/ich8lan.c
|
||||
+++ b/drivers/net/e1000e/ich8lan.c
|
||||
@@ -932,7 +932,6 @@ out:
|
||||
**/
|
||||
static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
|
||||
{
|
||||
- struct e1000_adapter *adapter = hw->adapter;
|
||||
struct e1000_phy_info *phy = &hw->phy;
|
||||
u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
|
||||
s32 ret_val = 0;
|
||||
@@ -950,7 +949,8 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
|
||||
if (phy->type != e1000_phy_igp_3)
|
||||
return ret_val;
|
||||
|
||||
- if (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_AMT) {
|
||||
+ if ((hw->adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_AMT) ||
|
||||
+ (hw->adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_C)) {
|
||||
sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
|
||||
break;
|
||||
}
|
||||
@@ -1626,6 +1626,9 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
|
||||
if (e1000_check_reset_block(hw))
|
||||
goto out;
|
||||
|
||||
+ /* Allow time for h/w to get to quiescent state after reset */
|
||||
+ msleep(10);
|
||||
+
|
||||
/* Perform any necessary post-reset workarounds */
|
||||
switch (hw->mac.type) {
|
||||
case e1000_pchlan:
|
|
@ -0,0 +1,68 @@
|
|||
From: Bruce Allan <bruce.w.allan@intel.com>
|
||||
Date: Wed, 16 Jun 2010 13:26:17 +0000 (+0000)
|
||||
Subject: e1000e: cleanup e1000_sw_lcd_config_ich8lan()
|
||||
X-Git-Tag: v2.6.36-rc1~571^2~529
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=3f0c16e84438d657d29446f85fe375794a93f159
|
||||
|
||||
e1000e: cleanup e1000_sw_lcd_config_ich8lan()
|
||||
|
||||
Do not acquire and release the PHY unnecessarily for parts that return
|
||||
from this workaround without actually accessing the PHY registers.
|
||||
|
||||
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
|
||||
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
|
||||
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
|
||||
index b2507d9..5d8fad3 100644
|
||||
--- a/drivers/net/e1000e/ich8lan.c
|
||||
+++ b/drivers/net/e1000e/ich8lan.c
|
||||
@@ -820,14 +820,6 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
|
||||
s32 ret_val = 0;
|
||||
u16 word_addr, reg_data, reg_addr, phy_page = 0;
|
||||
|
||||
- if (!(hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) &&
|
||||
- !(hw->mac.type == e1000_pchlan))
|
||||
- return ret_val;
|
||||
-
|
||||
- ret_val = hw->phy.ops.acquire(hw);
|
||||
- if (ret_val)
|
||||
- return ret_val;
|
||||
-
|
||||
/*
|
||||
* Initialize the PHY from the NVM on ICH platforms. This
|
||||
* is needed due to an issue where the NVM configuration is
|
||||
@@ -835,12 +827,26 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
|
||||
* Therefore, after each PHY reset, we will load the
|
||||
* configuration data out of the NVM manually.
|
||||
*/
|
||||
- if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
|
||||
- (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M) ||
|
||||
- (hw->mac.type == e1000_pchlan))
|
||||
+ switch (hw->mac.type) {
|
||||
+ case e1000_ich8lan:
|
||||
+ if (phy->type != e1000_phy_igp_3)
|
||||
+ return ret_val;
|
||||
+
|
||||
+ if (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_AMT) {
|
||||
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
|
||||
+ break;
|
||||
+ }
|
||||
+ /* Fall-thru */
|
||||
+ case e1000_pchlan:
|
||||
sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
|
||||
- else
|
||||
- sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return ret_val;
|
||||
+ }
|
||||
+
|
||||
+ ret_val = hw->phy.ops.acquire(hw);
|
||||
+ if (ret_val)
|
||||
+ return ret_val;
|
||||
|
||||
data = er32(FEXTNVM);
|
||||
if (!(data & sw_cfg_mask))
|
|
@ -0,0 +1,124 @@
|
|||
commit a5757c2a474a15f87e5baa9a4caacc31cde2bae6
|
||||
Author: Luke Macken <lmacken@redhat.com>
|
||||
Date: Wed Sep 22 13:05:04 2010 -0700
|
||||
|
||||
efifb: support the EFI framebuffer on more Apple hardware
|
||||
|
||||
Enable the EFI framebuffer on 14 more Macs, including the iMac11,1
|
||||
iMac10,1 iMac8,1 Macmini3,1 Macmini4,1 MacBook5,1 MacBook6,1 MacBook7,1
|
||||
MacBookPro2,2 MacBookPro5,2 MacBookPro5,3 MacBookPro6,1 MacBookPro6,2 and
|
||||
MacBookPro7,1
|
||||
|
||||
Information gathered from various user submissions.
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=528232
|
||||
http://ubuntuforums.org/showthread.php?t=1557326
|
||||
|
||||
[akpm@linux-foundation.org: coding-style fixes]
|
||||
Signed-off-by: Luke Macken <lmacken@redhat.com>
|
||||
Signed-off-by: Peter Jones <pjones@redhat.com>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
|
||||
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
|
||||
index c082b61..70477c2 100644
|
||||
--- a/drivers/video/efifb.c
|
||||
+++ b/drivers/video/efifb.c
|
||||
@@ -39,17 +39,31 @@ enum {
|
||||
M_I20, /* 20-Inch iMac */
|
||||
M_I20_SR, /* 20-Inch iMac (Santa Rosa) */
|
||||
M_I24, /* 24-Inch iMac */
|
||||
+ M_I24_8_1, /* 24-Inch iMac, 8,1th gen */
|
||||
+ M_I24_10_1, /* 24-Inch iMac, 10,1th gen */
|
||||
+ M_I27_11_1, /* 27-Inch iMac, 11,1th gen */
|
||||
M_MINI, /* Mac Mini */
|
||||
+ M_MINI_3_1, /* Mac Mini, 3,1th gen */
|
||||
+ M_MINI_4_1, /* Mac Mini, 4,1th gen */
|
||||
M_MB, /* MacBook */
|
||||
M_MB_2, /* MacBook, 2nd rev. */
|
||||
M_MB_3, /* MacBook, 3rd rev. */
|
||||
+ M_MB_5_1, /* MacBook, 5th rev. */
|
||||
+ M_MB_6_1, /* MacBook, 6th rev. */
|
||||
+ M_MB_7_1, /* MacBook, 7th rev. */
|
||||
M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */
|
||||
M_MBA, /* MacBook Air */
|
||||
M_MBP, /* MacBook Pro */
|
||||
M_MBP_2, /* MacBook Pro 2nd gen */
|
||||
+ M_MBP_2_2, /* MacBook Pro 2,2nd gen */
|
||||
M_MBP_SR, /* MacBook Pro (Santa Rosa) */
|
||||
M_MBP_4, /* MacBook Pro, 4th gen */
|
||||
M_MBP_5_1, /* MacBook Pro, 5,1th gen */
|
||||
+ M_MBP_5_2, /* MacBook Pro, 5,2th gen */
|
||||
+ M_MBP_5_3, /* MacBook Pro, 5,3rd gen */
|
||||
+ M_MBP_6_1, /* MacBook Pro, 6,1th gen */
|
||||
+ M_MBP_6_2, /* MacBook Pro, 6,2th gen */
|
||||
+ M_MBP_7_1, /* MacBook Pro, 7,1th gen */
|
||||
M_UNKNOWN /* placeholder */
|
||||
};
|
||||
|
||||
@@ -64,14 +78,28 @@ static struct efifb_dmi_info {
|
||||
[M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */
|
||||
[M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 },
|
||||
[M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */
|
||||
+ [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200 },
|
||||
+ [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080 },
|
||||
+ [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440 },
|
||||
[M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 },
|
||||
+ [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768 },
|
||||
+ [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200 },
|
||||
[M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 },
|
||||
+ [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800 },
|
||||
+ [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800 },
|
||||
+ [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800 },
|
||||
[M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 },
|
||||
[M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 },
|
||||
[M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */
|
||||
+ [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900 },
|
||||
[M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 },
|
||||
[M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 },
|
||||
[M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900 },
|
||||
+ [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200 },
|
||||
+ [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900 },
|
||||
+ [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200 },
|
||||
+ [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050 },
|
||||
+ [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800 },
|
||||
[M_UNKNOWN] = { NULL, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -92,7 +120,12 @@ static const struct dmi_system_id dmi_system_table[] __initconst = {
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
|
||||
/* At least one of these two will be right; maybe both? */
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
|
||||
@@ -101,14 +134,23 @@ static const struct dmi_system_id dmi_system_table[] __initconst = {
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
|
||||
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2),
|
||||
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1),
|
||||
{},
|
||||
};
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
commit 85a00d9bbfb4704fbf368944b1cb9fed8f1598c5
|
||||
Author: Peter Jones <pjones@redhat.com>
|
||||
Date: Wed Sep 22 13:05:04 2010 -0700
|
||||
|
||||
efifb: check that the base address is plausible on pci systems
|
||||
|
||||
Some Apple machines have identical DMI data but different memory
|
||||
configurations for the video. Given that, check that the address in our
|
||||
table is actually within the range of a PCI BAR on a VGA device in the
|
||||
machine.
|
||||
|
||||
This also fixes up the return value from set_system(), which has always
|
||||
been wrong, but never resulted in bad behavior since there's only ever
|
||||
been one matching entry in the dmi table.
|
||||
|
||||
The patch
|
||||
|
||||
1) stops people's machines from crashing when we get their display wrong,
|
||||
which seems to be unfortunately inevitable,
|
||||
|
||||
2) allows us to support identical dmi data with differing video memory
|
||||
configurations
|
||||
|
||||
This also adds me as the efifb maintainer, since I've effectively been
|
||||
acting as such for quite some time.
|
||||
|
||||
Signed-off-by: Peter Jones <pjones@redhat.com>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 726433a..4d4881d 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -2199,6 +2199,12 @@ W: http://acpi4asus.sf.net
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/eeepc-laptop.c
|
||||
|
||||
+EFIFB FRAMEBUFFER DRIVER
|
||||
+L: linux-fbdev@vger.kernel.org
|
||||
+M: Peter Jones <pjones@redhat.com>
|
||||
+S: Maintained
|
||||
+F: drivers/video/efifb.c
|
||||
+
|
||||
EFS FILESYSTEM
|
||||
W: http://aeschi.ch.eu.org/efs/
|
||||
S: Orphan
|
||||
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
|
||||
index 815f84b..c082b61 100644
|
||||
--- a/drivers/video/efifb.c
|
||||
+++ b/drivers/video/efifb.c
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/screen_info.h>
|
||||
#include <linux/dmi.h>
|
||||
-
|
||||
+#include <linux/pci.h>
|
||||
#include <video/vga.h>
|
||||
|
||||
static struct fb_var_screeninfo efifb_defined __devinitdata = {
|
||||
@@ -116,7 +116,7 @@ static int set_system(const struct dmi_system_id *id)
|
||||
{
|
||||
struct efifb_dmi_info *info = id->driver_data;
|
||||
if (info->base == 0)
|
||||
- return -ENODEV;
|
||||
+ return 0;
|
||||
|
||||
printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
|
||||
"(%dx%d, stride %d)\n", id->ident,
|
||||
@@ -124,18 +124,55 @@ static int set_system(const struct dmi_system_id *id)
|
||||
info->stride);
|
||||
|
||||
/* Trust the bootloader over the DMI tables */
|
||||
- if (screen_info.lfb_base == 0)
|
||||
+ if (screen_info.lfb_base == 0) {
|
||||
+#if defined(CONFIG_PCI)
|
||||
+ struct pci_dev *dev = NULL;
|
||||
+ int found_bar = 0;
|
||||
+#endif
|
||||
screen_info.lfb_base = info->base;
|
||||
- if (screen_info.lfb_linelength == 0)
|
||||
- screen_info.lfb_linelength = info->stride;
|
||||
- if (screen_info.lfb_width == 0)
|
||||
- screen_info.lfb_width = info->width;
|
||||
- if (screen_info.lfb_height == 0)
|
||||
- screen_info.lfb_height = info->height;
|
||||
- if (screen_info.orig_video_isVGA == 0)
|
||||
- screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
|
||||
|
||||
- return 0;
|
||||
+#if defined(CONFIG_PCI)
|
||||
+ /* make sure that the address in the table is actually on a
|
||||
+ * VGA device's PCI BAR */
|
||||
+
|
||||
+ for_each_pci_dev(dev) {
|
||||
+ int i;
|
||||
+ if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
|
||||
+ continue;
|
||||
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
|
||||
+ resource_size_t start, end;
|
||||
+
|
||||
+ start = pci_resource_start(dev, i);
|
||||
+ if (start == 0)
|
||||
+ break;
|
||||
+ end = pci_resource_end(dev, i);
|
||||
+ if (screen_info.lfb_base >= start &&
|
||||
+ screen_info.lfb_base < end) {
|
||||
+ found_bar = 1;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (!found_bar)
|
||||
+ screen_info.lfb_base = 0;
|
||||
+#endif
|
||||
+ }
|
||||
+ if (screen_info.lfb_base) {
|
||||
+ if (screen_info.lfb_linelength == 0)
|
||||
+ screen_info.lfb_linelength = info->stride;
|
||||
+ if (screen_info.lfb_width == 0)
|
||||
+ screen_info.lfb_width = info->width;
|
||||
+ if (screen_info.lfb_height == 0)
|
||||
+ screen_info.lfb_height = info->height;
|
||||
+ if (screen_info.orig_video_isVGA == 0)
|
||||
+ screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
|
||||
+ } else {
|
||||
+ screen_info.lfb_linelength = 0;
|
||||
+ screen_info.lfb_width = 0;
|
||||
+ screen_info.lfb_height = 0;
|
||||
+ screen_info.orig_video_isVGA = 0;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
|
|
@ -0,0 +1,116 @@
|
|||
epoll can acquire multiple ep->mutex on multiple "struct eventpoll"s
|
||||
at once in the case where one epoll fd is monitoring another epoll
|
||||
fd. This is perfectly OK, since we're careful about the lock ordering,
|
||||
but causes spurious lockdep warnings. Annotate the recursion using
|
||||
mutex_lock_nested, and add a comment explaining the nesting rules for
|
||||
good measure.
|
||||
|
||||
Reported-by: Paul Bolle <pebolle@tiscali.nl>
|
||||
Signed-off-by: Nelson Elhage <nelhage@nelhage.com>
|
||||
---
|
||||
I've tested this on a synthetic epoll test case, that just adds e1 to
|
||||
e2 and then does an epoll_wait(). I verified that it caused lockdep
|
||||
problems on 3.0 and that this patch fixed it, but I haven't done more
|
||||
extensive testing. Paul, are you able to test systemd against this?
|
||||
|
||||
fs/eventpoll.c | 25 ++++++++++++++++++-------
|
||||
1 files changed, 18 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index f9cfd16..0cb7bc6 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -76,6 +76,15 @@
|
||||
* Events that require holding "epmutex" are very rare, while for
|
||||
* normal operations the epoll private "ep->mtx" will guarantee
|
||||
* a better scalability.
|
||||
+ * It is possible to acquire multiple "ep->mtx"es at once in the case
|
||||
+ * when one epoll fd is added to another. In this case, we always
|
||||
+ * acquire the locks in the order of nesting (i.e. after epoll_ctl(e1,
|
||||
+ * EPOLL_CTL_ADD, e2), e1->mtx will always be acquired before
|
||||
+ * e2->mtx). Since we disallow cycles of epoll file descriptors, this
|
||||
+ * ensures that the mutexes are well-ordered. In order to communicate
|
||||
+ * this nesting to lockdep, when walking a tree of epoll file
|
||||
+ * descriptors, we use the current recursion depth as the lockdep
|
||||
+ * subkey.
|
||||
*/
|
||||
|
||||
/* Epoll private bits inside the event mask */
|
||||
@@ -464,13 +473,15 @@ static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
|
||||
* @ep: Pointer to the epoll private data structure.
|
||||
* @sproc: Pointer to the scan callback.
|
||||
* @priv: Private opaque data passed to the @sproc callback.
|
||||
+ * @depth: The current depth of recursive f_op->poll calls.
|
||||
*
|
||||
* Returns: The same integer error code returned by the @sproc callback.
|
||||
*/
|
||||
static int ep_scan_ready_list(struct eventpoll *ep,
|
||||
int (*sproc)(struct eventpoll *,
|
||||
struct list_head *, void *),
|
||||
- void *priv)
|
||||
+ void *priv,
|
||||
+ int depth)
|
||||
{
|
||||
int error, pwake = 0;
|
||||
unsigned long flags;
|
||||
@@ -481,7 +492,7 @@ static int ep_scan_ready_list(struct eventpoll *ep,
|
||||
* We need to lock this because we could be hit by
|
||||
* eventpoll_release_file() and epoll_ctl().
|
||||
*/
|
||||
- mutex_lock(&ep->mtx);
|
||||
+ mutex_lock_nested(&ep->mtx, depth);
|
||||
|
||||
/*
|
||||
* Steal the ready list, and re-init the original one to the
|
||||
@@ -670,7 +681,7 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
|
||||
|
||||
static int ep_poll_readyevents_proc(void *priv, void *cookie, int call_nests)
|
||||
{
|
||||
- return ep_scan_ready_list(priv, ep_read_events_proc, NULL);
|
||||
+ return ep_scan_ready_list(priv, ep_read_events_proc, NULL, call_nests + 1);
|
||||
}
|
||||
|
||||
static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
|
||||
@@ -737,7 +748,7 @@ void eventpoll_release_file(struct file *file)
|
||||
|
||||
ep = epi->ep;
|
||||
list_del_init(&epi->fllink);
|
||||
- mutex_lock(&ep->mtx);
|
||||
+ mutex_lock_nested(&ep->mtx, 0);
|
||||
ep_remove(ep, epi);
|
||||
mutex_unlock(&ep->mtx);
|
||||
}
|
||||
@@ -1134,7 +1145,7 @@ static int ep_send_events(struct eventpoll *ep,
|
||||
esed.maxevents = maxevents;
|
||||
esed.events = events;
|
||||
|
||||
- return ep_scan_ready_list(ep, ep_send_events_proc, &esed);
|
||||
+ return ep_scan_ready_list(ep, ep_send_events_proc, &esed, 0);
|
||||
}
|
||||
|
||||
static inline struct timespec ep_set_mstimeout(long ms)
|
||||
@@ -1267,7 +1278,7 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
|
||||
struct rb_node *rbp;
|
||||
struct epitem *epi;
|
||||
|
||||
- mutex_lock(&ep->mtx);
|
||||
+ mutex_lock_nested(&ep->mtx, call_nests + 1);
|
||||
for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
|
||||
epi = rb_entry(rbp, struct epitem, rbn);
|
||||
if (unlikely(is_file_epoll(epi->ffd.file))) {
|
||||
@@ -1409,7 +1420,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
||||
}
|
||||
|
||||
|
||||
- mutex_lock(&ep->mtx);
|
||||
+ mutex_lock_nested(&ep->mtx, 0);
|
||||
|
||||
/*
|
||||
* Try to lookup the file inside our RB tree, Since we grabbed "mtx"
|
||||
--
|
||||
1.7.4.1
|
||||
|
||||
--
|
||||
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
|
||||
the body of a message to majordomo@vger.kernel.org
|
||||
More majordomo info at http://vger.kernel.org/majordomo-info.html
|
|
@ -0,0 +1,465 @@
|
|||
From 6a4ca79652219cf22da800d990e5b46feaea1ad9 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Baron <jbaron@redhat.com>
|
||||
Date: Mon, 24 Oct 2011 14:59:02 +1100
|
||||
Subject: [PATCH] epoll: limit paths
|
||||
|
||||
epoll: limit paths
|
||||
|
||||
The current epoll code can be tickled to run basically indefinitely in
|
||||
both loop detection path check (on ep_insert()), and in the wakeup paths.
|
||||
The programs that tickle this behavior set up deeply linked networks of
|
||||
epoll file descriptors that cause the epoll algorithms to traverse them
|
||||
indefinitely. A couple of these sample programs have been previously
|
||||
posted in this thread: https://lkml.org/lkml/2011/2/25/297.
|
||||
|
||||
To fix the loop detection path check algorithms, I simply keep track of
|
||||
the epoll nodes that have been already visited. Thus, the loop detection
|
||||
becomes proportional to the number of epoll file descriptor and links.
|
||||
This dramatically decreases the run-time of the loop check algorithm. In
|
||||
one diabolical case I tried it reduced the run-time from 15 mintues (all
|
||||
in kernel time) to .3 seconds.
|
||||
|
||||
Fixing the wakeup paths could be done at wakeup time in a similar manner
|
||||
by keeping track of nodes that have already been visited, but the
|
||||
complexity is harder, since there can be multiple wakeups on different
|
||||
cpus...Thus, I've opted to limit the number of possible wakeup paths when
|
||||
the paths are created.
|
||||
|
||||
This is accomplished, by noting that the end file descriptor points that
|
||||
are found during the loop detection pass (from the newly added link), are
|
||||
actually the sources for wakeup events. I keep a list of these file
|
||||
descriptors and limit the number and length of these paths that emanate
|
||||
from these 'source file descriptors'. In the current implemetation I
|
||||
allow 1000 paths of length 1, 500 of length 2, 100 of length 3, 50 of
|
||||
length 4 and 10 of length 5. Note that it is sufficient to check the
|
||||
'source file descriptors' reachable from the newly added link, since no
|
||||
other 'source file descriptors' will have newly added links. This allows
|
||||
us to check only the wakeup paths that may have gotten too long, and not
|
||||
re-check all possible wakeup paths on the system.
|
||||
|
||||
In terms of the path limit selection, I think its first worth noting that
|
||||
the most common case for epoll, is probably the model where you have 1
|
||||
epoll file descriptor that is monitoring n number of 'source file
|
||||
descriptors'. In this case, each 'source file descriptor' has a 1 path of
|
||||
length 1. Thus, I believe that the limits I'm proposing are quite
|
||||
reasonable and in fact may be too generous. Thus, I'm hoping that the
|
||||
proposed limits will not prevent any workloads that currently work to
|
||||
fail.
|
||||
|
||||
In terms of locking, I have extended the use of the 'epmutex' to all
|
||||
epoll_ctl add and remove operations. Currently its only used in a subset
|
||||
of the add paths. I need to hold the epmutex, so that we can correctly
|
||||
traverse a coherent graph, to check the number of paths. I believe that
|
||||
this additional locking is probably ok, since its in the setup/teardown
|
||||
paths, and doesn't affect the running paths, but it certainly is going to
|
||||
add some extra overhead. Also, worth noting is that the epmuex was
|
||||
recently added to the ep_ctl add operations in the initial path loop
|
||||
detection code using the argument that it was not on a critical path.
|
||||
|
||||
Another thing to note here, is the length of epoll chains that is allowed.
|
||||
Currently, eventpoll.c defines:
|
||||
|
||||
/* Maximum number of nesting allowed inside epoll sets */
|
||||
#define EP_MAX_NESTS 4
|
||||
|
||||
This basically means that I am limited to a graph depth of 5 (EP_MAX_NESTS
|
||||
+ 1). However, this limit is currently only enforced during the loop
|
||||
check detection code, and only when the epoll file descriptors are added
|
||||
in a certain order. Thus, this limit is currently easily bypassed. The
|
||||
newly added check for wakeup paths, stricly limits the wakeup paths to a
|
||||
length of 5, regardless of the order in which ep's are linked together.
|
||||
Thus, a side-effect of the new code is a more consistent enforcement of
|
||||
the graph depth.
|
||||
|
||||
Thus far, I've tested this, using the sample programs previously
|
||||
mentioned, which now either return quickly or return -EINVAL. I've also
|
||||
testing using the piptest.c epoll tester, which showed no difference in
|
||||
performance. I've also created a number of different epoll networks and
|
||||
tested that they behave as expectded.
|
||||
|
||||
I believe this solves the original diabolical test cases, while still
|
||||
preserving the sane epoll nesting.
|
||||
|
||||
Signed-off-by: Jason Baron <jbaron@redhat.com>
|
||||
Cc: Nelson Elhage <nelhage@ksplice.com>
|
||||
Cc: Davide Libenzi <davidel@xmailserver.org>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
---
|
||||
fs/eventpoll.c | 226 ++++++++++++++++++++++++++++++++++++++++-----
|
||||
include/linux/eventpoll.h | 1 +
|
||||
include/linux/fs.h | 1 +
|
||||
3 files changed, 203 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 4a53743..414ac74 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -197,6 +197,12 @@ struct eventpoll {
|
||||
|
||||
/* The user that created the eventpoll descriptor */
|
||||
struct user_struct *user;
|
||||
+
|
||||
+ struct file *file;
|
||||
+
|
||||
+ /* used to optimize loop detection check */
|
||||
+ int visited;
|
||||
+ struct list_head visitedllink;
|
||||
};
|
||||
|
||||
/* Wait structure used by the poll hooks */
|
||||
@@ -255,6 +261,12 @@ static struct kmem_cache *epi_cache __read_mostly;
|
||||
/* Slab cache used to allocate "struct eppoll_entry" */
|
||||
static struct kmem_cache *pwq_cache __read_mostly;
|
||||
|
||||
+/* Visited nodes during ep_loop_check(), so we can unset them when we finish */
|
||||
+LIST_HEAD(visited_list);
|
||||
+
|
||||
+/* Files with newly added links, which need a limit on emanating paths */
|
||||
+LIST_HEAD(tfile_check_list);
|
||||
+
|
||||
#ifdef CONFIG_SYSCTL
|
||||
|
||||
#include <linux/sysctl.h>
|
||||
@@ -276,6 +288,12 @@ ctl_table epoll_table[] = {
|
||||
};
|
||||
#endif /* CONFIG_SYSCTL */
|
||||
|
||||
+static const struct file_operations eventpoll_fops;
|
||||
+
|
||||
+static inline int is_file_epoll(struct file *f)
|
||||
+{
|
||||
+ return f->f_op == &eventpoll_fops;
|
||||
+}
|
||||
|
||||
/* Setup the structure that is used as key for the RB tree */
|
||||
static inline void ep_set_ffd(struct epoll_filefd *ffd,
|
||||
@@ -711,12 +729,6 @@ static const struct file_operations eventpoll_fops = {
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
-/* Fast test to see if the file is an evenpoll file */
|
||||
-static inline int is_file_epoll(struct file *f)
|
||||
-{
|
||||
- return f->f_op == &eventpoll_fops;
|
||||
-}
|
||||
-
|
||||
/*
|
||||
* This is called from eventpoll_release() to unlink files from the eventpoll
|
||||
* interface. We need to have this facility to cleanup correctly files that are
|
||||
@@ -926,6 +938,96 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
|
||||
rb_insert_color(&epi->rbn, &ep->rbr);
|
||||
}
|
||||
|
||||
+
|
||||
+
|
||||
+#define PATH_ARR_SIZE 5
|
||||
+/* These are the number paths of length 1 to 5, that we are allowing to emanate
|
||||
+ * from a single file of interest. For example, we allow 1000 paths of length
|
||||
+ * 1, to emanate from each file of interest. This essentially represents the
|
||||
+ * potential wakeup paths, which need to be limited in order to avoid massive
|
||||
+ * uncontrolled wakeup storms. The common use case should be a single ep which
|
||||
+ * is connected to n file sources. In this case each file source has 1 path
|
||||
+ * of length 1. Thus, the numbers below should be more than sufficient.
|
||||
+ */
|
||||
+int path_limits[PATH_ARR_SIZE] = { 1000, 500, 100, 50, 10 };
|
||||
+int path_count[PATH_ARR_SIZE];
|
||||
+
|
||||
+static int path_count_inc(int nests)
|
||||
+{
|
||||
+ if (++path_count[nests] > path_limits[nests])
|
||||
+ return -1;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void path_count_init(void)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < PATH_ARR_SIZE; i++)
|
||||
+ path_count[i] = 0;
|
||||
+}
|
||||
+
|
||||
+static int reverse_path_check_proc(void *priv, void *cookie, int call_nests)
|
||||
+{
|
||||
+ int error = 0;
|
||||
+ struct file *file = priv;
|
||||
+ struct file *child_file;
|
||||
+ struct epitem *epi;
|
||||
+
|
||||
+ list_for_each_entry(epi, &file->f_ep_links, fllink) {
|
||||
+ child_file = epi->ep->file;
|
||||
+ if (is_file_epoll(child_file)) {
|
||||
+ if (list_empty(&child_file->f_ep_links)) {
|
||||
+ if (path_count_inc(call_nests)) {
|
||||
+ error = -1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ error = ep_call_nested(&poll_loop_ncalls,
|
||||
+ EP_MAX_NESTS,
|
||||
+ reverse_path_check_proc,
|
||||
+ child_file, child_file,
|
||||
+ current);
|
||||
+ }
|
||||
+ if (error != 0)
|
||||
+ break;
|
||||
+ } else {
|
||||
+ printk(KERN_ERR "reverse_path_check_proc: "
|
||||
+ "file is not an ep!\n");
|
||||
+ }
|
||||
+ }
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * reverse_path_check - The tfile_check_list is list of file *, which have
|
||||
+ * links that are proposed to be newly added. We need to
|
||||
+ * make sure that those added links don't add too many
|
||||
+ * paths such that we will spend all our time waking up
|
||||
+ * eventpoll objects.
|
||||
+ *
|
||||
+ * Returns: Returns zero if the proposed links don't create too many paths,
|
||||
+ * -1 otherwise.
|
||||
+ */
|
||||
+static int reverse_path_check(void)
|
||||
+{
|
||||
+ int length = 0;
|
||||
+ int error = 0;
|
||||
+ struct file *current_file;
|
||||
+
|
||||
+ /* let's call this for all tfiles */
|
||||
+ list_for_each_entry(current_file, &tfile_check_list, f_tfile_llink) {
|
||||
+ length++;
|
||||
+ path_count_init();
|
||||
+ error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
|
||||
+ reverse_path_check_proc, current_file,
|
||||
+ current_file, current);
|
||||
+ if (error)
|
||||
+ break;
|
||||
+ }
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Must be called with "mtx" held.
|
||||
*/
|
||||
@@ -987,6 +1089,11 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
|
||||
*/
|
||||
ep_rbtree_insert(ep, epi);
|
||||
|
||||
+ /* now check if we've created too many backpaths */
|
||||
+ error = -EINVAL;
|
||||
+ if (reverse_path_check())
|
||||
+ goto error_remove_epi;
|
||||
+
|
||||
/* We have to drop the new item inside our item list to keep track of it */
|
||||
spin_lock_irqsave(&ep->lock, flags);
|
||||
|
||||
@@ -1011,6 +1118,14 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
|
||||
|
||||
return 0;
|
||||
|
||||
+error_remove_epi:
|
||||
+ spin_lock(&tfile->f_lock);
|
||||
+ if (ep_is_linked(&epi->fllink))
|
||||
+ list_del_init(&epi->fllink);
|
||||
+ spin_unlock(&tfile->f_lock);
|
||||
+
|
||||
+ rb_erase(&epi->rbn, &ep->rbr);
|
||||
+
|
||||
error_unregister:
|
||||
ep_unregister_pollwait(ep, epi);
|
||||
|
||||
@@ -1275,18 +1390,35 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
|
||||
int error = 0;
|
||||
struct file *file = priv;
|
||||
struct eventpoll *ep = file->private_data;
|
||||
+ struct eventpoll *ep_tovisit;
|
||||
struct rb_node *rbp;
|
||||
struct epitem *epi;
|
||||
|
||||
mutex_lock_nested(&ep->mtx, call_nests + 1);
|
||||
+ ep->visited = 1;
|
||||
+ list_add(&ep->visitedllink, &visited_list);
|
||||
for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
|
||||
epi = rb_entry(rbp, struct epitem, rbn);
|
||||
if (unlikely(is_file_epoll(epi->ffd.file))) {
|
||||
+ ep_tovisit = epi->ffd.file->private_data;
|
||||
+ if (ep_tovisit->visited)
|
||||
+ continue;
|
||||
error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
|
||||
- ep_loop_check_proc, epi->ffd.file,
|
||||
- epi->ffd.file->private_data, current);
|
||||
+ ep_loop_check_proc, epi->ffd.file,
|
||||
+ ep_tovisit, current);
|
||||
if (error != 0)
|
||||
break;
|
||||
+ } else {
|
||||
+ /* if we've reached a file that is not associated with
|
||||
+ * an ep, then then we need to check if the newly added
|
||||
+ * links are going to add too many wakeup paths. We do
|
||||
+ * this by adding it to the tfile_check_list, if it's
|
||||
+ * not already there, and calling reverse_path_check()
|
||||
+ * during ep_insert()
|
||||
+ */
|
||||
+ if (list_empty(&epi->ffd.file->f_tfile_llink))
|
||||
+ list_add(&epi->ffd.file->f_tfile_llink,
|
||||
+ &tfile_check_list);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ep->mtx);
|
||||
@@ -1307,8 +1439,30 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
|
||||
*/
|
||||
static int ep_loop_check(struct eventpoll *ep, struct file *file)
|
||||
{
|
||||
- return ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
|
||||
+ int ret;
|
||||
+ struct eventpoll *ep_cur, *ep_next;
|
||||
+
|
||||
+ ret = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
|
||||
ep_loop_check_proc, file, ep, current);
|
||||
+ /* clear visited list */
|
||||
+ list_for_each_entry_safe(ep_cur, ep_next, &visited_list, visitedllink) {
|
||||
+ ep_cur->visited = 0;
|
||||
+ list_del(&ep_cur->visitedllink);
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void clear_tfile_check_list(void)
|
||||
+{
|
||||
+ struct file *file;
|
||||
+
|
||||
+ /* first clear the tfile_check_list */
|
||||
+ while (!list_empty(&tfile_check_list)) {
|
||||
+ file = list_first_entry(&tfile_check_list, struct file,
|
||||
+ f_tfile_llink);
|
||||
+ list_del_init(&file->f_tfile_llink);
|
||||
+ }
|
||||
+ INIT_LIST_HEAD(&tfile_check_list);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1316,8 +1470,9 @@ static int ep_loop_check(struct eventpoll *ep, struct file *file)
|
||||
*/
|
||||
SYSCALL_DEFINE1(epoll_create1, int, flags)
|
||||
{
|
||||
- int error;
|
||||
+ int error, fd;
|
||||
struct eventpoll *ep = NULL;
|
||||
+ struct file *file;
|
||||
|
||||
/* Check the EPOLL_* constant for consistency. */
|
||||
BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
|
||||
@@ -1334,11 +1489,25 @@ SYSCALL_DEFINE1(epoll_create1, int, flags)
|
||||
* Creates all the items needed to setup an eventpoll file. That is,
|
||||
* a file structure and a free file descriptor.
|
||||
*/
|
||||
- error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
|
||||
+ fd = get_unused_fd_flags(O_RDWR | (flags & O_CLOEXEC));
|
||||
+ if (fd < 0) {
|
||||
+ error = fd;
|
||||
+ goto out_free_ep;
|
||||
+ }
|
||||
+ file = anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep,
|
||||
O_RDWR | (flags & O_CLOEXEC));
|
||||
- if (error < 0)
|
||||
- ep_free(ep);
|
||||
-
|
||||
+ if (IS_ERR(file)) {
|
||||
+ error = PTR_ERR(file);
|
||||
+ goto out_free_fd;
|
||||
+ }
|
||||
+ fd_install(fd, file);
|
||||
+ ep->file = file;
|
||||
+ return fd;
|
||||
+
|
||||
+out_free_fd:
|
||||
+ put_unused_fd(fd);
|
||||
+out_free_ep:
|
||||
+ ep_free(ep);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -1404,21 +1573,27 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
||||
/*
|
||||
* When we insert an epoll file descriptor, inside another epoll file
|
||||
* descriptor, there is the change of creating closed loops, which are
|
||||
- * better be handled here, than in more critical paths.
|
||||
+ * better be handled here, than in more critical paths. While we are
|
||||
+ * checking for loops we also determine the list of files reachable
|
||||
+ * and hang them on the tfile_check_list, so we can check that we
|
||||
+ * haven't created too many possible wakeup paths.
|
||||
*
|
||||
- * We hold epmutex across the loop check and the insert in this case, in
|
||||
- * order to prevent two separate inserts from racing and each doing the
|
||||
- * insert "at the same time" such that ep_loop_check passes on both
|
||||
- * before either one does the insert, thereby creating a cycle.
|
||||
+ * We need to hold the epmutex across both ep_insert and ep_remove
|
||||
+ * b/c we want to make sure we are looking at a coherent view of
|
||||
+ * epoll network.
|
||||
*/
|
||||
- if (unlikely(is_file_epoll(tfile) && op == EPOLL_CTL_ADD)) {
|
||||
+ if (op == EPOLL_CTL_ADD || op == EPOLL_CTL_DEL) {
|
||||
mutex_lock(&epmutex);
|
||||
did_lock_epmutex = 1;
|
||||
- error = -ELOOP;
|
||||
- if (ep_loop_check(ep, tfile) != 0)
|
||||
- goto error_tgt_fput;
|
||||
}
|
||||
-
|
||||
+ if (op == EPOLL_CTL_ADD) {
|
||||
+ if (is_file_epoll(tfile)) {
|
||||
+ error = -ELOOP;
|
||||
+ if (ep_loop_check(ep, tfile) != 0)
|
||||
+ goto error_tgt_fput;
|
||||
+ } else
|
||||
+ list_add(&tfile->f_tfile_llink, &tfile_check_list);
|
||||
+ }
|
||||
|
||||
mutex_lock_nested(&ep->mtx, 0);
|
||||
|
||||
@@ -1437,6 +1612,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
||||
error = ep_insert(ep, &epds, tfile, fd);
|
||||
} else
|
||||
error = -EEXIST;
|
||||
+ clear_tfile_check_list();
|
||||
break;
|
||||
case EPOLL_CTL_DEL:
|
||||
if (epi)
|
||||
@@ -1455,7 +1631,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
||||
mutex_unlock(&ep->mtx);
|
||||
|
||||
error_tgt_fput:
|
||||
- if (unlikely(did_lock_epmutex))
|
||||
+ if (did_lock_epmutex)
|
||||
mutex_unlock(&epmutex);
|
||||
|
||||
fput(tfile);
|
||||
diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h
|
||||
index f362733..657ab55 100644
|
||||
--- a/include/linux/eventpoll.h
|
||||
+++ b/include/linux/eventpoll.h
|
||||
@@ -61,6 +61,7 @@ struct file;
|
||||
static inline void eventpoll_init_file(struct file *file)
|
||||
{
|
||||
INIT_LIST_HEAD(&file->f_ep_links);
|
||||
+ INIT_LIST_HEAD(&file->f_tfile_llink);
|
||||
}
|
||||
|
||||
|
||||
diff --git a/include/linux/fs.h b/include/linux/fs.h
|
||||
index 277f497..93778e0 100644
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -985,6 +985,7 @@ struct file {
|
||||
#ifdef CONFIG_EPOLL
|
||||
/* Used by fs/eventpoll.c to link all the hooks to this file */
|
||||
struct list_head f_ep_links;
|
||||
+ struct list_head f_tfile_llink;
|
||||
#endif /* #ifdef CONFIG_EPOLL */
|
||||
struct address_space *f_mapping;
|
||||
#ifdef CONFIG_DEBUG_WRITECOUNT
|
||||
--
|
||||
1.7.6.4
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
From be31c919e6ff27f1a08bc3e0725c51935313b002 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Kara <jack@suse.cz>
|
||||
Date: Tue, 27 Jul 2010 11:56:07 -0400
|
||||
Subject: ext4: Always journal quota file modifications
|
||||
|
||||
When journaled quota options are not specified, we do writes
|
||||
to quota files just in data=ordered mode. This actually causes
|
||||
warnings from JBD2 about dirty journaled buffer because ext4_getblk
|
||||
unconditionally treats a block allocated by it as metadata. Since
|
||||
quota actually is filesystem metadata, the easiest way to get rid
|
||||
of the warning is to always treat quota writes as metadata...
|
||||
|
||||
Signed-off-by: Jan Kara <jack@suse.cz>
|
||||
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
|
||||
---
|
||||
fs/ext4/super.c | 19 +++++--------------
|
||||
1 files changed, 5 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
|
||||
index a45ced9..f12daa7 100644
|
||||
--- a/fs/ext4/super.c
|
||||
+++ b/fs/ext4/super.c
|
||||
@@ -4030,7 +4030,6 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
|
||||
ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
|
||||
int err = 0;
|
||||
int offset = off & (sb->s_blocksize - 1);
|
||||
- int journal_quota = EXT4_SB(sb)->s_qf_names[type] != NULL;
|
||||
struct buffer_head *bh;
|
||||
handle_t *handle = journal_current_handle();
|
||||
|
||||
@@ -4055,24 +4054,16 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
|
||||
bh = ext4_bread(handle, inode, blk, 1, &err);
|
||||
if (!bh)
|
||||
goto out;
|
||||
- if (journal_quota) {
|
||||
- err = ext4_journal_get_write_access(handle, bh);
|
||||
- if (err) {
|
||||
- brelse(bh);
|
||||
- goto out;
|
||||
- }
|
||||
+ err = ext4_journal_get_write_access(handle, bh);
|
||||
+ if (err) {
|
||||
+ brelse(bh);
|
||||
+ goto out;
|
||||
}
|
||||
lock_buffer(bh);
|
||||
memcpy(bh->b_data+offset, data, len);
|
||||
flush_dcache_page(bh->b_page);
|
||||
unlock_buffer(bh);
|
||||
- if (journal_quota)
|
||||
- err = ext4_handle_dirty_metadata(handle, NULL, bh);
|
||||
- else {
|
||||
- /* Always do at least ordered writes for quotas */
|
||||
- err = ext4_jbd2_file_inode(handle, inode);
|
||||
- mark_buffer_dirty(bh);
|
||||
- }
|
||||
+ err = ext4_handle_dirty_metadata(handle, NULL, bh);
|
||||
brelse(bh);
|
||||
out:
|
||||
if (err) {
|
||||
--
|
||||
1.7.3.3
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
BZ 742091
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=742091
|
||||
|
||||
This bug was never properly fixed upstream since the code got
|
||||
reorganized in:
|
||||
|
||||
667eff35a1f56fa74ce98a0c7c29a40adc1ba4e3 ext4: reimplement convert and
|
||||
split_unwritten
|
||||
|
||||
This fix has proposed by Zheng Liu <wenqing.lz@taobao.com>, then updated,
|
||||
reviewed and tested by me.
|
||||
|
||||
We will meet with a BUG_ON() if following script is run.
|
||||
|
||||
mkfs.ext4 -b 4096 /dev/sdb1 1000000
|
||||
mount -t ext4 /dev/sdb1 /mnt/sdb1
|
||||
fallocate -l 100M /mnt/sdb1/test
|
||||
sync
|
||||
for((i=0;i<170;i++))
|
||||
do
|
||||
dd if=/dev/zero of=/mnt/sdb1/test conv=notrunc bs=256k count=1 seek=`expr $i \* 2`
|
||||
done
|
||||
umount /mnt/sdb1
|
||||
mount -t ext4 /dev/sdb1 /mnt/sdb1
|
||||
dd if=/dev/zero of=/mnt/sdb1/test conv=notrunc bs=256k count=1 seek=341
|
||||
umount /mnt/sdb1
|
||||
mount /dev/sdb1 /mnt/sdb1
|
||||
dd if=/dev/zero of=/mnt/sdb1/test conv=notrunc bs=256k count=1 seek=340
|
||||
sync
|
||||
|
||||
The reason is that it forgot to mark dirty when splitting two extents in
|
||||
ext4_ext_convert_to_initialized(). Althrough ex has been updated in memory,
|
||||
it is not dirtied both in ext4_ext_convert_to_initialized() and
|
||||
ext4_ext_insert_extent(). The disk layout is corrupted. Then it will meet with
|
||||
a BUG_ON() when writting at the start of that extent again.
|
||||
|
||||
Originally-from: Zheng Liu <wenqing.lz@taobao.com>
|
||||
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
|
||||
---
|
||||
fs/ext4/extents.c | 2 ++
|
||||
1 files changed, 2 insertions(+), 0 deletions(-)
|
||||
|
||||
Index: linux-2.6.35.noarch/fs/ext4/extents.c
|
||||
===================================================================
|
||||
--- linux-2.6.35.noarch.orig/fs/ext4/extents.c
|
||||
+++ linux-2.6.35.noarch/fs/ext4/extents.c
|
||||
@@ -2687,6 +2687,7 @@ static int ext4_ext_convert_to_initializ
|
||||
ex1 = ex;
|
||||
ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
|
||||
ext4_ext_mark_uninitialized(ex1);
|
||||
+ ext4_ext_dirty(handle, inode, path + depth);
|
||||
ex2 = &newex;
|
||||
}
|
||||
/*
|
||||
@@ -2850,6 +2851,7 @@ static int ext4_ext_convert_to_initializ
|
||||
ex1 = ex;
|
||||
ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
|
||||
ext4_ext_mark_uninitialized(ex1);
|
||||
+ ext4_ext_dirty(handle, inode, path + depth);
|
||||
ex2 = &newex;
|
||||
}
|
||||
/* ex2: map->m_lblk to map->m_lblk + maxblocks-1 : initialised */
|
|
@ -0,0 +1,258 @@
|
|||
From: Lukas Czerner <lczerner@redhat.com>
|
||||
Date: Mon, 6 Jun 2011 04:05:17 +0000 (-0400)
|
||||
Subject: ext4: Fix max file size and logical block counting of extent format file
|
||||
X-Git-Tag: v3.0-rc5~53^2~4
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=f17722f917b2f21497deb6edc62fb1683daa08e6
|
||||
|
||||
ext4: Fix max file size and logical block counting of extent format file
|
||||
|
||||
[ backport for 2.6.35 ]
|
||||
|
||||
Kazuya Mio reported that he was able to hit BUG_ON(next == lblock)
|
||||
in ext4_ext_put_gap_in_cache() while creating a sparse file in extent
|
||||
format and fill the tail of file up to its end. We will hit the BUG_ON
|
||||
when we write the last block (2^32-1) into the sparse file.
|
||||
|
||||
The root cause of the problem lies in the fact that we specifically set
|
||||
s_maxbytes so that block at s_maxbytes fit into on-disk extent format,
|
||||
which is 32 bit long. However, we are not storing start and end block
|
||||
number, but rather start block number and length in blocks. It means
|
||||
that in order to cover extent from 0 to EXT_MAX_BLOCK we need
|
||||
EXT_MAX_BLOCK+1 to fit into len (because we counting block 0 as well) -
|
||||
and it does not.
|
||||
|
||||
The only way to fix it without changing the meaning of the struct
|
||||
ext4_extent members is, as Kazuya Mio suggested, to lower s_maxbytes
|
||||
by one fs block so we can cover the whole extent we can get by the
|
||||
on-disk extent format.
|
||||
|
||||
Also in many places EXT_MAX_BLOCK is used as length instead of maximum
|
||||
logical block number as the name suggests, it is all a bit messy. So
|
||||
this commit renames it to EXT_MAX_BLOCKS and change its usage in some
|
||||
places to actually be maximum number of blocks in the extent.
|
||||
|
||||
The bug which this commit fixes can be reproduced as follows:
|
||||
|
||||
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-2))
|
||||
sync
|
||||
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-1))
|
||||
|
||||
Reported-by: Kazuya Mio <k-mio@sx.jp.nec.com>
|
||||
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
|
||||
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
|
||||
---
|
||||
|
||||
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
|
||||
index 2e29abb..4764146 100644
|
||||
--- a/fs/ext4/ext4_extents.h
|
||||
+++ b/fs/ext4/ext4_extents.h
|
||||
@@ -133,8 +133,11 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
|
||||
#define EXT_BREAK 1
|
||||
#define EXT_REPEAT 2
|
||||
|
||||
-/* Maximum logical block in a file; ext4_extent's ee_block is __le32 */
|
||||
-#define EXT_MAX_BLOCK 0xffffffff
|
||||
+/*
|
||||
+ * Maximum number of logical blocks in a file; ext4_extent's ee_block is
|
||||
+ * __le32.
|
||||
+ */
|
||||
+#define EXT_MAX_BLOCKS 0xffffffff
|
||||
|
||||
/*
|
||||
* EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
|
||||
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
|
||||
index 5199bac..4157570 100644
|
||||
--- a/fs/ext4/extents.c
|
||||
+++ b/fs/ext4/extents.c
|
||||
@@ -1408,7 +1408,7 @@ got_index:
|
||||
|
||||
/*
|
||||
* ext4_ext_next_allocated_block:
|
||||
- * returns allocated block in subsequent extent or EXT_MAX_BLOCK.
|
||||
+ * returns allocated block in subsequent extent or EXT_MAX_BLOCKS.
|
||||
* NOTE: it considers block number from index entry as
|
||||
* allocated block. Thus, index entries have to be consistent
|
||||
* with leaves.
|
||||
@@ -1422,7 +1422,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path)
|
||||
depth = path->p_depth;
|
||||
|
||||
if (depth == 0 && path->p_ext == NULL)
|
||||
- return EXT_MAX_BLOCK;
|
||||
+ return EXT_MAX_BLOCKS;
|
||||
|
||||
while (depth >= 0) {
|
||||
if (depth == path->p_depth) {
|
||||
@@ -1439,12 +1439,12 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path)
|
||||
depth--;
|
||||
}
|
||||
|
||||
- return EXT_MAX_BLOCK;
|
||||
+ return EXT_MAX_BLOCKS;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_ext_next_leaf_block:
|
||||
- * returns first allocated block from next leaf or EXT_MAX_BLOCK
|
||||
+ * returns first allocated block from next leaf or EXT_MAX_BLOCKS
|
||||
*/
|
||||
static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,
|
||||
struct ext4_ext_path *path)
|
||||
@@ -1456,7 +1456,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,
|
||||
|
||||
/* zero-tree has no leaf blocks at all */
|
||||
if (depth == 0)
|
||||
- return EXT_MAX_BLOCK;
|
||||
+ return EXT_MAX_BLOCKS;
|
||||
|
||||
/* go to index block */
|
||||
depth--;
|
||||
@@ -1469,7 +1469,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,
|
||||
depth--;
|
||||
}
|
||||
|
||||
- return EXT_MAX_BLOCK;
|
||||
+ return EXT_MAX_BLOCKS;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1677,13 +1677,13 @@ static unsigned int ext4_ext_check_overlap(struct inode *inode,
|
||||
*/
|
||||
if (b2 < b1) {
|
||||
b2 = ext4_ext_next_allocated_block(path);
|
||||
- if (b2 == EXT_MAX_BLOCK)
|
||||
+ if (b2 == EXT_MAX_BLOCKS)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check for wrap through zero on extent logical start block*/
|
||||
if (b1 + len1 < b1) {
|
||||
- len1 = EXT_MAX_BLOCK - b1;
|
||||
+ len1 = EXT_MAX_BLOCKS - b1;
|
||||
newext->ee_len = cpu_to_le16(len1);
|
||||
ret = 1;
|
||||
}
|
||||
@@ -1767,7 +1767,7 @@ repeat:
|
||||
fex = EXT_LAST_EXTENT(eh);
|
||||
next = ext4_ext_next_leaf_block(inode, path);
|
||||
if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block)
|
||||
- && next != EXT_MAX_BLOCK) {
|
||||
+ && next != EXT_MAX_BLOCKS) {
|
||||
ext_debug("next leaf block - %d\n", next);
|
||||
BUG_ON(npath != NULL);
|
||||
npath = ext4_ext_find_extent(inode, next, NULL);
|
||||
@@ -1887,7 +1887,7 @@ static int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
|
||||
BUG_ON(func == NULL);
|
||||
BUG_ON(inode == NULL);
|
||||
|
||||
- while (block < last && block != EXT_MAX_BLOCK) {
|
||||
+ while (block < last && block != EXT_MAX_BLOCKS) {
|
||||
num = last - block;
|
||||
/* find extent for this block */
|
||||
down_read(&EXT4_I(inode)->i_data_sem);
|
||||
@@ -2020,7 +2020,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
|
||||
if (ex == NULL) {
|
||||
/* there is no extent yet, so gap is [0;-] */
|
||||
lblock = 0;
|
||||
- len = EXT_MAX_BLOCK;
|
||||
+ len = EXT_MAX_BLOCKS;
|
||||
ext_debug("cache gap(whole file):");
|
||||
} else if (block < le32_to_cpu(ex->ee_block)) {
|
||||
lblock = block;
|
||||
@@ -2239,8 +2239,8 @@ ext4_ext_rm_leaf(handle_t *handle, struc
|
||||
path[depth].p_ext = ex;
|
||||
|
||||
a = ex_ee_block > start ? ex_ee_block : start;
|
||||
- b = ex_ee_block + ex_ee_len - 1 < EXT_MAX_BLOCK ?
|
||||
- ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCK;
|
||||
+ b = ex_ee_block + ex_ee_len - 1 < EXT_MAX_BLOCKS ?
|
||||
+ ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCKS;
|
||||
|
||||
ext_debug(" border %u:%u\n", a, b);
|
||||
|
||||
@@ -3869,15 +3869,15 @@ static int ext4_ext_fiemap_cb(struct ino
|
||||
flags |= FIEMAP_EXTENT_UNWRITTEN;
|
||||
|
||||
/*
|
||||
- * If this extent reaches EXT_MAX_BLOCK, it must be last.
|
||||
+ * If this extent reaches EXT_MAX_BLOCKS, it must be last.
|
||||
*
|
||||
- * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK,
|
||||
+ * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCKS,
|
||||
* this also indicates no more allocated blocks.
|
||||
*
|
||||
* XXX this might miss a single-block extent at EXT_MAX_BLOCK
|
||||
*/
|
||||
- if (ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK ||
|
||||
- newex->ec_block + newex->ec_len - 1 == EXT_MAX_BLOCK) {
|
||||
+ if (ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCKS ||
|
||||
+ newex->ec_block + newex->ec_len == EXT_MAX_BLOCKS) {
|
||||
loff_t size = i_size_read(inode);
|
||||
loff_t bs = EXT4_BLOCK_SIZE(inode->i_sb);
|
||||
|
||||
@@ -4347,8 +4347,8 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
|
||||
start_blk = start >> inode->i_sb->s_blocksize_bits;
|
||||
last_blk = (start + len - 1) >> inode->i_sb->s_blocksize_bits;
|
||||
- if (last_blk >= EXT_MAX_BLOCK)
|
||||
- last_blk = EXT_MAX_BLOCK-1;
|
||||
+ if (last_blk >= EXT_MAX_BLOCKS)
|
||||
+ last_blk = EXT_MAX_BLOCKS-1;
|
||||
len_blks = ((ext4_lblk_t) last_blk) - start_blk + 1;
|
||||
|
||||
/*
|
||||
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
|
||||
index 2b8304b..f57455a 100644
|
||||
--- a/fs/ext4/move_extent.c
|
||||
+++ b/fs/ext4/move_extent.c
|
||||
@@ -1002,12 +1002,12 @@ mext_check_arguments(struct inode *orig_inode,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- if ((orig_start > EXT_MAX_BLOCK) ||
|
||||
- (donor_start > EXT_MAX_BLOCK) ||
|
||||
- (*len > EXT_MAX_BLOCK) ||
|
||||
- (orig_start + *len > EXT_MAX_BLOCK)) {
|
||||
+ if ((orig_start >= EXT_MAX_BLOCKS) ||
|
||||
+ (donor_start >= EXT_MAX_BLOCKS) ||
|
||||
+ (*len > EXT_MAX_BLOCKS) ||
|
||||
+ (orig_start + *len >= EXT_MAX_BLOCKS)) {
|
||||
ext4_debug("ext4 move extent: Can't handle over [%u] blocks "
|
||||
- "[ino:orig %lu, donor %lu]\n", EXT_MAX_BLOCK,
|
||||
+ "[ino:orig %lu, donor %lu]\n", EXT_MAX_BLOCKS,
|
||||
orig_inode->i_ino, donor_inode->i_ino);
|
||||
return -EINVAL;
|
||||
}
|
||||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
|
||||
index cc5c157..9ea71aa 100644
|
||||
--- a/fs/ext4/super.c
|
||||
+++ b/fs/ext4/super.c
|
||||
@@ -2243,6 +2243,12 @@ static void ext4_orphan_cleanup(struct super_block *sb,
|
||||
* in the vfs. ext4 inode has 48 bits of i_block in fsblock units,
|
||||
* so that won't be a limiting factor.
|
||||
*
|
||||
+ * However there is other limiting factor. We do store extents in the form
|
||||
+ * of starting block and length, hence the resulting length of the extent
|
||||
+ * covering maximum file size must fit into on-disk format containers as
|
||||
+ * well. Given that length is always by 1 unit bigger than max unit (because
|
||||
+ * we count 0 as well) we have to lower the s_maxbytes by one fs block.
|
||||
+ *
|
||||
* Note, this does *not* consider any metadata overhead for vfs i_blocks.
|
||||
*/
|
||||
static loff_t ext4_max_size(int blkbits, int has_huge_files)
|
||||
@@ -2264,10 +2270,13 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files)
|
||||
upper_limit <<= blkbits;
|
||||
}
|
||||
|
||||
- /* 32-bit extent-start container, ee_block */
|
||||
- res = 1LL << 32;
|
||||
+ /*
|
||||
+ * 32-bit extent-start container, ee_block. We lower the maxbytes
|
||||
+ * by one fs block, so ee_len can cover the extent of maximum file
|
||||
+ * size
|
||||
+ */
|
||||
+ res = (1LL << 32) - 1;
|
||||
res <<= blkbits;
|
||||
- res -= 1;
|
||||
|
||||
/* Sanity check against vm- & vfs- imposed limits */
|
||||
if (res > upper_limit)
|
|
@ -0,0 +1,27 @@
|
|||
diff --git a/kernel/sched.c b/kernel/sched.c
|
||||
index 6d0dbeb..3640c20 100644
|
||||
--- a/kernel/sched.c
|
||||
+++ b/kernel/sched.c
|
||||
@@ -5155,9 +5155,11 @@ void __cpuinit init_idle_bootup_task(struct task_struct *idle)
|
||||
void __cpuinit init_idle(struct task_struct *idle, int cpu)
|
||||
{
|
||||
struct rq *rq = cpu_rq(cpu);
|
||||
+ struct rq *oldrq = task_rq(idle);
|
||||
unsigned long flags;
|
||||
|
||||
- raw_spin_lock_irqsave(&rq->lock, flags);
|
||||
+ local_irq_save(flags);
|
||||
+ double_rq_lock(oldrq, rq);
|
||||
|
||||
__sched_fork(idle);
|
||||
idle->state = TASK_RUNNING;
|
||||
@@ -5170,7 +5172,8 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
|
||||
#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
|
||||
idle->oncpu = 1;
|
||||
#endif
|
||||
- raw_spin_unlock_irqrestore(&rq->lock, flags);
|
||||
+ double_rq_unlock(oldrq, rq);
|
||||
+ local_irq_restore(flags);
|
||||
|
||||
/* Set the preempt count _outside_ the spinlocks! */
|
||||
#if defined(CONFIG_PREEMPT)
|
|
@ -0,0 +1,34 @@
|
|||
From 6a7fc984c7bd3c98839e28c47f4a9a27af024ca7 Mon Sep 17 00:00:00 2001
|
||||
From: Miklos Szeredi <mszeredi@suse.cz>
|
||||
Date: Wed, 24 Aug 2011 10:20:17 +0200
|
||||
Subject: [PATCH] fuse: check size of FUSE_NOTIFY_INVAL_ENTRY message
|
||||
|
||||
FUSE_NOTIFY_INVAL_ENTRY didn't check the length of the write so the
|
||||
message processing could overrun and result in a "kernel BUG at
|
||||
fs/fuse/dev.c:629!"
|
||||
|
||||
Reported-by: Han-Wen Nienhuys <hanwenn@gmail.com>
|
||||
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
|
||||
CC: stable@kernel.org
|
||||
---
|
||||
fs/fuse/dev.c | 4 ++++
|
||||
1 files changed, 4 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
|
||||
index e5cdabf..517430a 100644
|
||||
--- a/fs/fuse/dev.c
|
||||
+++ b/fs/fuse/dev.c
|
||||
@@ -1208,6 +1208,10 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
|
||||
if (outarg.namelen > FUSE_NAME_MAX)
|
||||
goto err;
|
||||
|
||||
+ err = -EINVAL;
|
||||
+ if (size != sizeof(outarg) + outarg.namelen + 1)
|
||||
+ goto err;
|
||||
+
|
||||
name.name = buf;
|
||||
name.len = outarg.namelen;
|
||||
err = fuse_copy_one(cs, buf, outarg.namelen + 1);
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
From 17dd759c67f21e34f2156abcf415e1f60605a188 Mon Sep 17 00:00:00 2001
|
||||
From: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Date: Wed, 27 Jul 2011 06:16:28 -0700
|
||||
Subject: [PATCH] gro: Only reset frag0 when skb can be pulled
|
||||
|
||||
Currently skb_gro_header_slow unconditionally resets frag0 and
|
||||
frag0_len. However, when we can't pull on the skb this leaves
|
||||
the GRO fields in an inconsistent state.
|
||||
|
||||
This patch fixes this by only resetting those fields after the
|
||||
pskb_may_pull test.
|
||||
|
||||
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/netdevice.h | 5 ++++-
|
||||
1 files changed, 4 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
||||
index 1d92acc..661a077 100644
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -1649,9 +1649,12 @@ static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen)
|
||||
static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
|
||||
unsigned int offset)
|
||||
{
|
||||
+ if (!pskb_may_pull(skb, hlen))
|
||||
+ return NULL;
|
||||
+
|
||||
NAPI_GRO_CB(skb)->frag0 = NULL;
|
||||
NAPI_GRO_CB(skb)->frag0_len = 0;
|
||||
- return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
|
||||
+ return skb->data + offset;
|
||||
}
|
||||
|
||||
static inline void *skb_gro_mac_header(struct sk_buff *skb)
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
From: Hendrik Iben <Hendrik_Iben@web.de>
|
||||
Date: Mon, 4 Oct 2010 13:39:49 +0000 (+0200)
|
||||
Subject: HID: force feedback support for Logitech RumblePad gamepad
|
||||
X-Git-Tag: v2.6.37-rc1~144^2~3^4
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=2c6118e43040034d80894daeba41960bf0035b31
|
||||
|
||||
HID: force feedback support for Logitech RumblePad gamepad
|
||||
|
||||
This patch adds force feedback support for Logitech WingMan RumblePad
|
||||
gamepads by extending the Logitech Rumblepad 2 force feedback code.
|
||||
|
||||
Signed-off-by: Hendrik Iben <Hendrik_Iben@web.de>
|
||||
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
|
||||
---
|
||||
|
||||
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
|
||||
index 6664c57..3892ff5 100644
|
||||
--- a/drivers/hid/Kconfig
|
||||
+++ b/drivers/hid/Kconfig
|
||||
@@ -220,12 +220,12 @@ config LOGITECH_FF
|
||||
force feedback.
|
||||
|
||||
config LOGIRUMBLEPAD2_FF
|
||||
- bool "Logitech Rumblepad 2 force feedback support"
|
||||
+ bool "Logitech RumblePad/Rumblepad 2 force feedback support"
|
||||
depends on HID_LOGITECH
|
||||
select INPUT_FF_MEMLESS
|
||||
help
|
||||
Say Y here if you want to enable force feedback support for Logitech
|
||||
- Rumblepad 2 devices.
|
||||
+ RumblePad and Rumblepad 2 devices.
|
||||
|
||||
config LOGIG940_FF
|
||||
bool "Logitech Flight System G940 force feedback support"
|
||||
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
||||
index 19d4547..0120557 100644
|
||||
--- a/drivers/hid/hid-core.c
|
||||
+++ b/drivers/hid/hid-core.c
|
||||
@@ -1326,6 +1326,7 @@ static const struct hid_device_id hid_blacklist[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
|
||||
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
|
||||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
||||
index 6b111e1..79f0304 100644
|
||||
--- a/drivers/hid/hid-ids.h
|
||||
+++ b/drivers/hid/hid-ids.h
|
||||
@@ -339,6 +339,7 @@
|
||||
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
|
||||
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
|
||||
#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
|
||||
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a
|
||||
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211
|
||||
#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
|
||||
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
|
||||
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
|
||||
index 8989f15..9e92c27 100644
|
||||
--- a/drivers/hid/hid-lg.c
|
||||
+++ b/drivers/hid/hid-lg.c
|
||||
@@ -7,6 +7,7 @@
|
||||
* Copyright (c) 2006-2007 Jiri Kosina
|
||||
* Copyright (c) 2007 Paul Walmsley
|
||||
* Copyright (c) 2008 Jiri Slaby
|
||||
+ * Copyright (c) 2010 Hendrik Iben
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -361,6 +362,8 @@ static const struct hid_device_id lg_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
|
||||
.driver_data = LG_NOGET | LG_FF },
|
||||
|
||||
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
|
||||
+ .driver_data = LG_FF2 },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
|
||||
.driver_data = LG_FF },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
|
||||
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
|
||||
index d888f1e..4258253 100644
|
||||
--- a/drivers/hid/hid-lg2ff.c
|
||||
+++ b/drivers/hid/hid-lg2ff.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
- * Force feedback support for Logitech Rumblepad 2
|
||||
+ * Force feedback support for Logitech RumblePad and Rumblepad 2
|
||||
*
|
||||
* Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com>
|
||||
*/
|
||||
@@ -110,7 +110,7 @@ int lg2ff_init(struct hid_device *hid)
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
|
||||
- dev_info(&hid->dev, "Force feedback for Logitech Rumblepad 2 by "
|
||||
+ dev_info(&hid->dev, "Force feedback for Logitech RumblePad/Rumblepad 2 by "
|
||||
"Anssi Hannula <anssi.hannula@gmail.com>\n");
|
||||
|
||||
return 0;
|
|
@ -0,0 +1,163 @@
|
|||
[PATCH] hid: support for bluetooth tivo slide remote and usb dongle
|
||||
|
||||
This patch adds full support for the TiVo Slide Remote, primarily by way
|
||||
of extending the existing generic HID support. Only four keys are not
|
||||
usages within a standard usage page, but they're easily handled by the
|
||||
addition of a HID_UP_TIVOVENDOR usage page. Note that the UP is 0xffff,
|
||||
which matches the mask, but its also a valid vendor-specific UP, according
|
||||
to the spec.
|
||||
|
||||
What's actually connected to the computer is a Broadcom-made usb dongle,
|
||||
which has an embedded hub, bluetooth adapter, mouse and keyboard devices.
|
||||
You pair with the dongle, then the remote sends data that its converted
|
||||
into HID on the keyboard interface (the mouse interface doesn't do anything
|
||||
interesting right now, so far as I can tell).
|
||||
|
||||
lsusb for this device:
|
||||
Bus 004 Device 005: ID 0a5c:2190 Broadcom Corp.
|
||||
Bus 004 Device 004: ID 0a5c:4503 Broadcom Corp.
|
||||
Bus 004 Device 003: ID 150a:1201
|
||||
Bus 004 Device 002: ID 0a5c:4500 Broadcom Corp. BCM2046B1 USB 2.0 Hub (part of BCM2046 Bluetooth)
|
||||
|
||||
Speaking of the keyboard interface, the remote actually does contain a
|
||||
keyboard as well. The top slides away, revealing a reasonably functional
|
||||
qwerty keyboard (not unlike many slide cell phones), thus the product
|
||||
name.
|
||||
|
||||
Now for some caveats... This device seems to report 0xc (consumer usage
|
||||
page) 0x20 ("+10") after most key presses. At the moment, this will simply
|
||||
be ignored, but if a mapping for that usage is added, the remote behaves
|
||||
very badly (we end up w/a repeating/stuck key until another key is pressed).
|
||||
Not quite sure what to do about that one, if that usage does get mapped. I
|
||||
guess a device-specific quirk to just ignore it would work.
|
||||
|
||||
Anyway, the thing is working 100% as expected with this patch right now.
|
||||
|
||||
Three more things to note... This patch fixes an incorrect mapping of 0xc 0x45,
|
||||
which was mapped to KEY_RADIO, which is definitely wrong, but may cause some
|
||||
existing device to now report KEY_RIGHT there. Second, there's also an
|
||||
unrelated fix for a redundant KERN_DEBUG in a dbg_hid call. Third, the
|
||||
additions to HID_UP_GENDESK aren't strictly needed by the remote, but the
|
||||
dongle does try to register those, and they're all technically correct, so
|
||||
I've included them for the benefit of a device that comes along and
|
||||
actually does try to use them.
|
||||
|
||||
Applies cleanly to hid master, tested w/a 2.6.35.4-based Fedora kernel.
|
||||
|
||||
Signed-off-by: Jarod Wilson <jarod@redhat.com>
|
||||
|
||||
---
|
||||
drivers/hid/hid-input.c | 45 ++++++++++++++++++++++++++++++++++++++++-----
|
||||
include/linux/hid.h | 1 +
|
||||
2 files changed, 41 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
|
||||
index 6c03dcc..bd1479e 100644
|
||||
--- a/drivers/hid/hid-input.c
|
||||
+++ b/drivers/hid/hid-input.c
|
||||
@@ -44,11 +44,11 @@ static const unsigned char hid_keyboard[256] = {
|
||||
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
|
||||
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
|
||||
115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
|
||||
- 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
|
||||
+ 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,
|
||||
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
|
||||
unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
|
||||
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
|
||||
- unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
|
||||
+ unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk,
|
||||
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
|
||||
150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
|
||||
};
|
||||
@@ -136,7 +136,7 @@ static int hidinput_setkeycode(struct input_dev *dev,
|
||||
|
||||
clear_bit(old_keycode, dev->keybit);
|
||||
set_bit(usage->code, dev->keybit);
|
||||
- dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
|
||||
+ dbg_hid("Assigned keycode %d to HID usage code %x\n", keycode, scancode);
|
||||
/* Set the keybit for the old keycode if the old keycode is used
|
||||
* by another key */
|
||||
if (hidinput_find_key (hid, 0, old_keycode))
|
||||
@@ -235,6 +235,18 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
case 0x1: map_key_clear(KEY_POWER); break;
|
||||
case 0x2: map_key_clear(KEY_SLEEP); break;
|
||||
case 0x3: map_key_clear(KEY_WAKEUP); break;
|
||||
+ case 0x4: map_key_clear(KEY_CONTEXT_MENU); break;
|
||||
+ case 0x5: map_key_clear(KEY_MENU); break;
|
||||
+ case 0x6: map_key_clear(KEY_PROG1); break;
|
||||
+ case 0x7: map_key_clear(KEY_HELP); break;
|
||||
+ case 0x8: map_key_clear(KEY_EXIT); break;
|
||||
+ case 0x9: map_key_clear(KEY_SELECT); break;
|
||||
+ case 0xa: map_key_clear(KEY_RIGHT); break;
|
||||
+ case 0xb: map_key_clear(KEY_LEFT); break;
|
||||
+ case 0xc: map_key_clear(KEY_UP); break;
|
||||
+ case 0xd: map_key_clear(KEY_DOWN); break;
|
||||
+ case 0xe: map_key_clear(KEY_POWER2); break;
|
||||
+ case 0xf: map_key_clear(KEY_RESTART); break;
|
||||
default: goto unknown;
|
||||
}
|
||||
break;
|
||||
@@ -343,12 +355,24 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
case 0x000: goto ignore;
|
||||
+ case 0x030: map_key_clear(KEY_POWER); break;
|
||||
case 0x034: map_key_clear(KEY_SLEEP); break;
|
||||
case 0x036: map_key_clear(BTN_MISC); break;
|
||||
|
||||
case 0x040: map_key_clear(KEY_MENU); break;
|
||||
- case 0x045: map_key_clear(KEY_RADIO); break;
|
||||
-
|
||||
+ case 0x041: map_key_clear(KEY_SELECT); break;
|
||||
+ case 0x042: map_key_clear(KEY_UP); break;
|
||||
+ case 0x043: map_key_clear(KEY_DOWN); break;
|
||||
+ case 0x044: map_key_clear(KEY_LEFT); break;
|
||||
+ case 0x045: map_key_clear(KEY_RIGHT); break;
|
||||
+
|
||||
+ case 0x069: map_key_clear(KEY_RED); break;
|
||||
+ case 0x06a: map_key_clear(KEY_GREEN); break;
|
||||
+ case 0x06b: map_key_clear(KEY_BLUE); break;
|
||||
+ case 0x06c: map_key_clear(KEY_YELLOW); break;
|
||||
+ case 0x06d: map_key_clear(KEY_ZOOM); break;
|
||||
+
|
||||
+ case 0x082: map_key_clear(KEY_VIDEO_NEXT); break;
|
||||
case 0x083: map_key_clear(KEY_LAST); break;
|
||||
case 0x088: map_key_clear(KEY_PC); break;
|
||||
case 0x089: map_key_clear(KEY_TV); break;
|
||||
@@ -390,6 +414,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
|
||||
case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
|
||||
case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
|
||||
+ case 0x0f5: map_key_clear(KEY_SLOW); break;
|
||||
|
||||
case 0x182: map_key_clear(KEY_BOOKMARKS); break;
|
||||
case 0x183: map_key_clear(KEY_CONFIG); break;
|
||||
@@ -491,6 +516,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
}
|
||||
break;
|
||||
|
||||
+ case HID_UP_TIVOVENDOR:
|
||||
+ switch (usage->hid & HID_USAGE) {
|
||||
+ case 0x3d: map_key_clear(KEY_PROG1); break;
|
||||
+ case 0x3e: map_key_clear(KEY_TV); break;
|
||||
+ case 0x41: map_key_clear(KEY_PAGEDOWN); break;
|
||||
+ case 0x42: map_key_clear(KEY_PAGEUP); break;
|
||||
+ default: goto unknown;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
default:
|
||||
unknown:
|
||||
if (field->report_size == 1) {
|
||||
diff --git a/include/linux/hid.h b/include/linux/hid.h
|
||||
index 42a0f1d..083cfb2 100644
|
||||
--- a/include/linux/hid.h
|
||||
+++ b/include/linux/hid.h
|
||||
@@ -200,6 +200,7 @@ struct hid_item {
|
||||
#define HID_UP_MSVENDOR 0xff000000
|
||||
#define HID_UP_CUSTOM 0x00ff0000
|
||||
#define HID_UP_LOGIVENDOR 0xffbc0000
|
||||
+#define HID_UP_TIVOVENDOR 0xffff0000
|
||||
|
||||
#define HID_USAGE 0x0000ffff
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
From 785465d9cffd65b5a69dd2f465d2f7c917713220 Mon Sep 17 00:00:00 2001
|
||||
From: Kyle McMartin <kyle@mcmartin.ca>
|
||||
Date: Mon, 18 Oct 2010 13:30:39 -0400
|
||||
Subject: [PATCH] ima: provide a toggle to disable it entirely
|
||||
|
||||
Signed-off-by: Kyle McMartin <kyle@redhat.com>
|
||||
---
|
||||
security/integrity/ima/ima.h | 1 +
|
||||
security/integrity/ima/ima_iint.c | 9 +++++++++
|
||||
security/integrity/ima/ima_main.c | 24 +++++++++++++++++++++---
|
||||
3 files changed, 31 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
|
||||
index 3fbcd1d..65c3977 100644
|
||||
--- a/security/integrity/ima/ima.h
|
||||
+++ b/security/integrity/ima/ima.h
|
||||
@@ -37,6 +37,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
|
||||
/* set during initialization */
|
||||
extern int iint_initialized;
|
||||
extern int ima_initialized;
|
||||
+extern int ima_enabled;
|
||||
extern int ima_used_chip;
|
||||
extern char *ima_hash;
|
||||
|
||||
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
|
||||
index afba4ae..3d191ef 100644
|
||||
--- a/security/integrity/ima/ima_iint.c
|
||||
+++ b/security/integrity/ima/ima_iint.c
|
||||
@@ -54,6 +54,9 @@ int ima_inode_alloc(struct inode *inode)
|
||||
struct ima_iint_cache *iint = NULL;
|
||||
int rc = 0;
|
||||
|
||||
+ if (!ima_enabled)
|
||||
+ return 0;
|
||||
+
|
||||
iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
|
||||
if (!iint)
|
||||
return -ENOMEM;
|
||||
@@ -116,6 +119,9 @@ void ima_inode_free(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
+ if (!ima_enabled)
|
||||
+ return;
|
||||
+
|
||||
spin_lock(&ima_iint_lock);
|
||||
iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
|
||||
spin_unlock(&ima_iint_lock);
|
||||
@@ -139,6 +145,9 @@ static void init_once(void *foo)
|
||||
|
||||
static int __init ima_iintcache_init(void)
|
||||
{
|
||||
+ if (!ima_enabled)
|
||||
+ return 0;
|
||||
+
|
||||
iint_cache =
|
||||
kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
|
||||
SLAB_PANIC, init_once);
|
||||
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
|
||||
index e662b89..6e91905 100644
|
||||
--- a/security/integrity/ima/ima_main.c
|
||||
+++ b/security/integrity/ima/ima_main.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ima.h"
|
||||
|
||||
int ima_initialized;
|
||||
+int ima_enabled;
|
||||
|
||||
char *ima_hash = "sha1";
|
||||
static int __init hash_setup(char *str)
|
||||
@@ -36,6 +37,14 @@ static int __init hash_setup(char *str)
|
||||
}
|
||||
__setup("ima_hash=", hash_setup);
|
||||
|
||||
+static int __init ima_enable(char *str)
|
||||
+{
|
||||
+ if (strncmp(str, "on", 2) == 0)
|
||||
+ ima_enabled = 1;
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("ima=", ima_enable);
|
||||
+
|
||||
struct ima_imbalance {
|
||||
struct hlist_node node;
|
||||
unsigned long fsmagic;
|
||||
@@ -148,7 +157,7 @@ void ima_counts_get(struct file *file)
|
||||
struct ima_iint_cache *iint;
|
||||
int rc;
|
||||
|
||||
- if (!iint_initialized || !S_ISREG(inode->i_mode))
|
||||
+ if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode))
|
||||
return;
|
||||
iint = ima_iint_find_get(inode);
|
||||
if (!iint)
|
||||
@@ -215,7 +224,7 @@ void ima_file_free(struct file *file)
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
- if (!iint_initialized || !S_ISREG(inode->i_mode))
|
||||
+ if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode))
|
||||
return;
|
||||
iint = ima_iint_find_get(inode);
|
||||
if (!iint)
|
||||
@@ -269,7 +278,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
- if (!file)
|
||||
+ if (!ima_enabled || !file)
|
||||
return 0;
|
||||
if (prot & PROT_EXEC)
|
||||
rc = process_measurement(file, file->f_dentry->d_name.name,
|
||||
@@ -294,6 +303,9 @@ int ima_bprm_check(struct linux_binprm *bprm)
|
||||
{
|
||||
int rc;
|
||||
|
||||
+ if (!ima_enabled)
|
||||
+ return 0;
|
||||
+
|
||||
rc = process_measurement(bprm->file, bprm->filename,
|
||||
MAY_EXEC, BPRM_CHECK);
|
||||
return 0;
|
||||
@@ -313,6 +325,9 @@ int ima_file_check(struct file *file, int mask)
|
||||
{
|
||||
int rc;
|
||||
|
||||
+ if (!ima_enabled)
|
||||
+ return 0;
|
||||
+
|
||||
rc = process_measurement(file, file->f_dentry->d_name.name,
|
||||
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
|
||||
FILE_CHECK);
|
||||
@@ -324,6 +339,9 @@ static int __init init_ima(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
+ if (!ima_enabled)
|
||||
+ return 0;
|
||||
+
|
||||
error = ima_init();
|
||||
ima_initialized = 1;
|
||||
return error;
|
||||
--
|
||||
1.7.3.1
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
From: Jarod Wilson <jarod@redhat.com>
|
||||
Date: Sat, 23 Oct 2010 14:54:06 -0400
|
||||
Subject: [PATCH] imon: add back modparam for default protocol
|
||||
|
||||
The latest imon devices support both imon and mce remotes, but we
|
||||
default to using the imon native protocol. Upstream, ir-keytable
|
||||
can be used to change protocol and upload the mce keytable, but it
|
||||
isn't functional with the input layer interfaces in 2.6.35. As a
|
||||
work-around for now, add back a modparam so people can have the
|
||||
driver load the mce keytable by default.
|
||||
|
||||
Note, this patch won't be going upstream. Upstream, we're moving
|
||||
towards all keytables being in userspace, uploaded at driver init
|
||||
time by ir-keytable (triggered by udev events).
|
||||
|
||||
Signed-off-by: Jarod Wilson <jarod@redhat.com>
|
||||
---
|
||||
drivers/media/rc/imon.c | 14 ++++++++++++++
|
||||
1 files changed, 14 insertions(+), 0 deletions(-)
|
||||
|
||||
Index: linux-2.6.35.x86_64/drivers/media/rc/imon.c
|
||||
===================================================================
|
||||
--- linux-2.6.35.x86_64.orig/drivers/media/rc/imon.c
|
||||
+++ linux-2.6.35.x86_64/drivers/media/rc/imon.c
|
||||
@@ -328,6 +328,17 @@ MODULE_PARM_DESC(pad_stabilize, "Apply s
|
||||
"presses in arrow key mode. 0=disable, 1=enable (default).");
|
||||
|
||||
/*
|
||||
+ * The latest imon devices support both imon and mce remotes, but we default
|
||||
+ * to using the imon native protocol. Rather than require people to have and
|
||||
+ * run ir-keytable to switch every module load, they can add mce=1 to their
|
||||
+ * modparams to default to mce/rc6 instead.
|
||||
+ */
|
||||
+static bool mce;
|
||||
+module_param(mce, bool, S_IRUGO);
|
||||
+MODULE_PARM_DESC(mce, "Configure for mce/rc6 protocol instead of imon native, "
|
||||
+ "if supported: 0=no, 1=yes (default: no)");
|
||||
+
|
||||
+/*
|
||||
* In certain use cases, mouse mode isn't really helpful, and could actually
|
||||
* cause confusion, so allow disabling it when the IR device is open.
|
||||
*/
|
||||
@@ -1851,6 +1862,9 @@ static struct rc_dev *imon_init_rdev(str
|
||||
|
||||
imon_set_display_type(ictx);
|
||||
|
||||
+ if (mce && ((rdev->allowed_protos & RC_TYPE_RC6) == RC_TYPE_RC6))
|
||||
+ ictx->rc_type = RC_TYPE_RC6;
|
||||
+
|
||||
if (ictx->rc_type == RC_TYPE_RC6)
|
||||
rdev->map_name = RC_MAP_IMON_MCE;
|
||||
else
|
|
@ -0,0 +1,103 @@
|
|||
From jasowang@redhat.com Sat Oct 8 20:56:54 2011
|
||||
Subject: ipv6: fix NULL dereference in udp6_ufo_fragment()
|
||||
To: gregkh@suse.de, stable@kernel.org
|
||||
From: Jason Wang <jasowang@redhat.com>
|
||||
Cc: davem@davemloft.net, eric.dumazet@gmail.com
|
||||
Date: Sun, 09 Oct 2011 10:56:44 +0800
|
||||
Message-ID: <20111009025644.9437.53281.stgit@dhcp-8-146.nay.redhat.com>
|
||||
|
||||
From: Jason Wang <jasowang@redhat.com>
|
||||
|
||||
This patch fixes the issue caused by ef81bb40bf15f350fe865f31fa42f1082772a576
|
||||
which is a backport of upstream 87c48fa3b4630905f98268dde838ee43626a060c. The
|
||||
problem does not exist in upstream.
|
||||
|
||||
We do not check whether route is attached before trying to assign ip
|
||||
identification through route dest which lead NULL pointer dereference. This
|
||||
happens when host bridge transmit a packet from guest.
|
||||
|
||||
This patch changes ipv6_select_ident() to accept in6_addr as its paramter and
|
||||
fix the issue by using the destination address in ipv6 header when no route is
|
||||
attached.
|
||||
|
||||
Signed-off-by: Jason Wang <jasowang@redhat.com>
|
||||
Acked-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
---
|
||||
include/net/ipv6.h | 2 +-
|
||||
net/ipv6/ip6_output.c | 10 +++++-----
|
||||
net/ipv6/udp.c | 4 +++-
|
||||
3 files changed, 9 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/include/net/ipv6.h
|
||||
+++ b/include/net/ipv6.h
|
||||
@@ -463,7 +463,7 @@ static inline int ipv6_addr_diff(const s
|
||||
return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
-extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
|
||||
+extern void ipv6_select_ident(struct frag_hdr *fhdr, struct in6_addr *addr);
|
||||
|
||||
/*
|
||||
* Prototypes exported by ipv6
|
||||
--- a/net/ipv6/ip6_output.c
|
||||
+++ b/net/ipv6/ip6_output.c
|
||||
@@ -620,9 +620,9 @@ static u32 __ipv6_select_ident(const str
|
||||
return hash + newid;
|
||||
}
|
||||
|
||||
-void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
|
||||
+void ipv6_select_ident(struct frag_hdr *fhdr, struct in6_addr *addr)
|
||||
{
|
||||
- fhdr->identification = htonl(__ipv6_select_ident(&rt->rt6i_dst.addr));
|
||||
+ fhdr->identification = htonl(__ipv6_select_ident(addr));
|
||||
}
|
||||
|
||||
static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
||||
@@ -709,7 +709,7 @@ int ip6_fragment(struct sk_buff *skb, in
|
||||
skb_reset_network_header(skb);
|
||||
memcpy(skb_network_header(skb), tmp_hdr, hlen);
|
||||
|
||||
- ipv6_select_ident(fh, rt);
|
||||
+ ipv6_select_ident(fh, &rt->rt6i_dst.addr);
|
||||
fh->nexthdr = nexthdr;
|
||||
fh->reserved = 0;
|
||||
fh->frag_off = htons(IP6_MF);
|
||||
@@ -855,7 +855,7 @@ slow_path:
|
||||
fh->nexthdr = nexthdr;
|
||||
fh->reserved = 0;
|
||||
if (!frag_id) {
|
||||
- ipv6_select_ident(fh, rt);
|
||||
+ ipv6_select_ident(fh, &rt->rt6i_dst.addr);
|
||||
frag_id = fh->identification;
|
||||
} else
|
||||
fh->identification = frag_id;
|
||||
@@ -1146,7 +1146,7 @@ static inline int ip6_ufo_append_data(st
|
||||
skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
|
||||
sizeof(struct frag_hdr)) & ~7;
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
|
||||
- ipv6_select_ident(&fhdr, rt);
|
||||
+ ipv6_select_ident(&fhdr, &rt->rt6i_dst.addr);
|
||||
skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
|
||||
__skb_queue_tail(&sk->sk_write_queue, skb);
|
||||
|
||||
--- a/net/ipv6/udp.c
|
||||
+++ b/net/ipv6/udp.c
|
||||
@@ -1309,6 +1309,7 @@ static struct sk_buff *udp6_ufo_fragment
|
||||
u8 frag_hdr_sz = sizeof(struct frag_hdr);
|
||||
int offset;
|
||||
__wsum csum;
|
||||
+ struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
|
||||
|
||||
mss = skb_shinfo(skb)->gso_size;
|
||||
if (unlikely(skb->len <= mss))
|
||||
@@ -1359,7 +1360,8 @@ static struct sk_buff *udp6_ufo_fragment
|
||||
fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
|
||||
fptr->nexthdr = nexthdr;
|
||||
fptr->reserved = 0;
|
||||
- ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
|
||||
+ ipv6_select_ident(fptr,
|
||||
+ rt ? &rt->rt6i_dst.addr : &ipv6_hdr(skb)->daddr);
|
||||
|
||||
/* Fragment the skb. ipv6 header and the remaining fields of the
|
||||
* fragment header are updated in ipv6_gso_segment()
|
|
@ -0,0 +1,172 @@
|
|||
From d8d972876c51f7344367414bef3682bcf97e4e87 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Dumazet <eric.dumazet@gmail.com>
|
||||
Date: Mon, 8 Aug 2011 23:44:00 -0700
|
||||
Subject: ipv6: make fragment identifications less predictable
|
||||
|
||||
|
||||
From: Eric Dumazet <eric.dumazet@gmail.com>
|
||||
|
||||
[ Backport of upstream commit 87c48fa3b4630905f98268dde838ee43626a060c for 2.6.35 ]
|
||||
|
||||
Fernando Gont reported current IPv6 fragment identification generation
|
||||
was not secure, because using a very predictable system-wide generator,
|
||||
allowing various attacks.
|
||||
|
||||
IPv4 uses inetpeer cache to address this problem and to get good
|
||||
performance. We'll use this mechanism when IPv6 inetpeer is stable
|
||||
enough in linux-3.1
|
||||
|
||||
For the time being, we use jhash on destination address to provide less
|
||||
predictable identifications. Also remove a spinlock and use cmpxchg() to
|
||||
get better SMP performance.
|
||||
|
||||
Reported-by: Fernando Gont <fernando@gont.com.ar>
|
||||
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
---
|
||||
include/net/ipv6.h | 12 +-----------
|
||||
include/net/transp_v6.h | 2 ++
|
||||
net/ipv6/af_inet6.c | 2 ++
|
||||
net/ipv6/ip6_output.c | 40 +++++++++++++++++++++++++++++++++++-----
|
||||
net/ipv6/udp.c | 2 +-
|
||||
5 files changed, 41 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/include/net/ipv6.h
|
||||
+++ b/include/net/ipv6.h
|
||||
@@ -463,17 +463,7 @@ static inline int ipv6_addr_diff(const s
|
||||
return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
-static __inline__ void ipv6_select_ident(struct frag_hdr *fhdr)
|
||||
-{
|
||||
- static u32 ipv6_fragmentation_id = 1;
|
||||
- static DEFINE_SPINLOCK(ip6_id_lock);
|
||||
-
|
||||
- spin_lock_bh(&ip6_id_lock);
|
||||
- fhdr->identification = htonl(ipv6_fragmentation_id);
|
||||
- if (++ipv6_fragmentation_id == 0)
|
||||
- ipv6_fragmentation_id = 1;
|
||||
- spin_unlock_bh(&ip6_id_lock);
|
||||
-}
|
||||
+extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
|
||||
|
||||
/*
|
||||
* Prototypes exported by ipv6
|
||||
--- a/include/net/transp_v6.h
|
||||
+++ b/include/net/transp_v6.h
|
||||
@@ -14,6 +14,8 @@ extern struct proto tcpv6_prot;
|
||||
|
||||
struct flowi;
|
||||
|
||||
+extern void initialize_hashidentrnd(void);
|
||||
+
|
||||
/* extention headers */
|
||||
extern int ipv6_exthdrs_init(void);
|
||||
extern void ipv6_exthdrs_exit(void);
|
||||
--- a/net/ipv6/af_inet6.c
|
||||
+++ b/net/ipv6/af_inet6.c
|
||||
@@ -1078,6 +1078,8 @@ static int __init inet6_init(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ initialize_hashidentrnd();
|
||||
+
|
||||
err = proto_register(&tcpv6_prot, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
--- a/net/ipv6/ip6_output.c
|
||||
+++ b/net/ipv6/ip6_output.c
|
||||
@@ -596,6 +596,35 @@ int ip6_find_1stfragopt(struct sk_buff *
|
||||
return offset;
|
||||
}
|
||||
|
||||
+static u32 hashidentrnd __read_mostly;
|
||||
+#define FID_HASH_SZ 16
|
||||
+static u32 ipv6_fragmentation_id[FID_HASH_SZ];
|
||||
+
|
||||
+void __init initialize_hashidentrnd(void)
|
||||
+{
|
||||
+ get_random_bytes(&hashidentrnd, sizeof(hashidentrnd));
|
||||
+}
|
||||
+
|
||||
+static u32 __ipv6_select_ident(const struct in6_addr *addr)
|
||||
+{
|
||||
+ u32 newid, oldid, hash = jhash2((u32 *)addr, 4, hashidentrnd);
|
||||
+ u32 *pid = &ipv6_fragmentation_id[hash % FID_HASH_SZ];
|
||||
+
|
||||
+ do {
|
||||
+ oldid = *pid;
|
||||
+ newid = oldid + 1;
|
||||
+ if (!(hash + newid))
|
||||
+ newid++;
|
||||
+ } while (cmpxchg(pid, oldid, newid) != oldid);
|
||||
+
|
||||
+ return hash + newid;
|
||||
+}
|
||||
+
|
||||
+void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
|
||||
+{
|
||||
+ fhdr->identification = htonl(__ipv6_select_ident(&rt->rt6i_dst.addr));
|
||||
+}
|
||||
+
|
||||
static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
||||
{
|
||||
struct sk_buff *frag;
|
||||
@@ -680,7 +709,7 @@ int ip6_fragment(struct sk_buff *skb, in
|
||||
skb_reset_network_header(skb);
|
||||
memcpy(skb_network_header(skb), tmp_hdr, hlen);
|
||||
|
||||
- ipv6_select_ident(fh);
|
||||
+ ipv6_select_ident(fh, rt);
|
||||
fh->nexthdr = nexthdr;
|
||||
fh->reserved = 0;
|
||||
fh->frag_off = htons(IP6_MF);
|
||||
@@ -826,7 +855,7 @@ slow_path:
|
||||
fh->nexthdr = nexthdr;
|
||||
fh->reserved = 0;
|
||||
if (!frag_id) {
|
||||
- ipv6_select_ident(fh);
|
||||
+ ipv6_select_ident(fh, rt);
|
||||
frag_id = fh->identification;
|
||||
} else
|
||||
fh->identification = frag_id;
|
||||
@@ -1072,7 +1101,8 @@ static inline int ip6_ufo_append_data(st
|
||||
int getfrag(void *from, char *to, int offset, int len,
|
||||
int odd, struct sk_buff *skb),
|
||||
void *from, int length, int hh_len, int fragheaderlen,
|
||||
- int transhdrlen, int mtu,unsigned int flags)
|
||||
+ int transhdrlen, int mtu,unsigned int flags,
|
||||
+ struct rt6_info *rt)
|
||||
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@@ -1116,7 +1146,7 @@ static inline int ip6_ufo_append_data(st
|
||||
skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
|
||||
sizeof(struct frag_hdr)) & ~7;
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
|
||||
- ipv6_select_ident(&fhdr);
|
||||
+ ipv6_select_ident(&fhdr, rt);
|
||||
skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
|
||||
__skb_queue_tail(&sk->sk_write_queue, skb);
|
||||
|
||||
@@ -1282,7 +1312,7 @@ int ip6_append_data(struct sock *sk, int
|
||||
|
||||
err = ip6_ufo_append_data(sk, getfrag, from, length,
|
||||
hh_len, fragheaderlen,
|
||||
- transhdrlen, mtu, flags);
|
||||
+ transhdrlen, mtu, flags, rt);
|
||||
if (err)
|
||||
goto error;
|
||||
return 0;
|
||||
--- a/net/ipv6/udp.c
|
||||
+++ b/net/ipv6/udp.c
|
||||
@@ -1359,7 +1359,7 @@ static struct sk_buff *udp6_ufo_fragment
|
||||
fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
|
||||
fptr->nexthdr = nexthdr;
|
||||
fptr->reserved = 0;
|
||||
- ipv6_select_ident(fptr);
|
||||
+ ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
|
||||
|
||||
/* Fragment the skb. ipv6 header and the remaining fields of the
|
||||
* fragment header are updated in ipv6_gso_segment()
|
|
@ -0,0 +1,38 @@
|
|||
From 33710d0cfda2e00144acf7b6c58bb86ea4fcbbac Mon Sep 17 00:00:00 2001
|
||||
From: Shan Wei <shanwei@cn.fujitsu.com>
|
||||
Date: Tue, 19 Apr 2011 22:52:49 +0000
|
||||
Subject: [PATCH] ipv6: udp: fix the wrong headroom check
|
||||
|
||||
At this point, skb->data points to skb_transport_header.
|
||||
So, headroom check is wrong.
|
||||
|
||||
For some case:bridge(UFO is on) + eth device(UFO is off),
|
||||
there is no enough headroom for IPv6 frag head.
|
||||
But headroom check is always false.
|
||||
|
||||
This will bring about data be moved to there prior to skb->head,
|
||||
when adding IPv6 frag header to skb.
|
||||
|
||||
Signed-off-by: Shan Wei <shanwei@cn.fujitsu.com>
|
||||
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/ipv6/udp.c | 2 +-
|
||||
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
|
||||
index 8a72f58..4aaae95 100644
|
||||
--- a/net/ipv6/udp.c
|
||||
+++ b/net/ipv6/udp.c
|
||||
@@ -1339,7 +1339,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, int features)
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
|
||||
/* Check if there is enough headroom to insert fragment header. */
|
||||
- if ((skb_headroom(skb) < frag_hdr_sz) &&
|
||||
+ if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) &&
|
||||
pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
|
||||
goto out;
|
||||
|
||||
--
|
||||
1.7.7.1
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
From sgruszka@redhat.com Mon Jun 20 10:14:55 2011
|
||||
From: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||
To: kernel@lists.fedoraproject.org
|
||||
Subject: [PATCH 2.6.35 2/3] iwlagn: fix "Received BA when not expected"
|
||||
Date: Mon, 20 Jun 2011 16:15:13 +0200
|
||||
Message-Id: <1308579314-19348-3-git-send-email-sgruszka@redhat.com>
|
||||
|
||||
commit bfd36103ec26599557c2bd3225a1f1c9267f8fcb upstream.
|
||||
|
||||
Need to use broadcast sta_id for management frames, otherwise we broke
|
||||
BA session in the firmware and get messages like that:
|
||||
|
||||
"Received BA when not expected"
|
||||
|
||||
or (on older kernels):
|
||||
|
||||
"BA scd_flow 0 does not match txq_id 10"
|
||||
|
||||
This fix regression introduced in 2.6.35 during station management
|
||||
code rewrite by:
|
||||
|
||||
commit 2a87c26bbe9587baeb9e56d3ce0b4971bd777643
|
||||
Author: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Fri Apr 30 11:30:45 2010 -0700
|
||||
|
||||
iwlwifi: use iwl_find_station less
|
||||
|
||||
Patch partially resolve:
|
||||
https://bugzilla.kernel.org/show_bug.cgi?id=16691
|
||||
However, there are still 11n performance problems on 4965 and 5xxx
|
||||
devices that need to be investigated.
|
||||
|
||||
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||
---
|
||||
drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 5 +++--
|
||||
1 files changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
|
||||
index cf64575..6df61b4 100644
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
|
||||
@@ -548,10 +548,11 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
||||
|
||||
hdr_len = ieee80211_hdrlen(fc);
|
||||
|
||||
- /* Find index into station table for destination station */
|
||||
- if (!info->control.sta)
|
||||
+ /* For management frames use broadcast id to do not break aggregation */
|
||||
+ if (!ieee80211_is_data(fc) || !info->control.sta)
|
||||
sta_id = priv->hw_params.bcast_sta_id;
|
||||
else
|
||||
+ /* Find index into station table for destination station */
|
||||
sta_id = iwl_sta_id(info->control.sta);
|
||||
if (sta_id == IWL_INVALID_STATION) {
|
||||
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
|
||||
--
|
||||
1.7.1
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
From sgruszka@redhat.com Mon Jun 20 10:14:57 2011
|
||||
From: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||
To: kernel@lists.fedoraproject.org
|
||||
Subject: [PATCH 2.6.35 3/3] iwlagn: use cts-to-self protection on 5000 adapters series
|
||||
Date: Mon, 20 Jun 2011 16:15:14 +0200
|
||||
Message-Id: <1308579314-19348-4-git-send-email-sgruszka@redhat.com>
|
||||
|
||||
This patch fixes 802.11n stability and performance regression we have
|
||||
since 2.6.35. It boost performance on my 5GHz N-only network from about
|
||||
5MB/s to 8MB/s. Similar percentage boost can be observed on 2.4 GHz.
|
||||
|
||||
These are test results of 5x downloading of approximately 700MB iso
|
||||
image:
|
||||
|
||||
vanilla: 5.27 5.22 4.94 4.47 5.31 ; avr 5.0420 std 0.35110
|
||||
patched: 8.07 7.95 8.06 7.99 7.96 ; avr 8.0060 std 0.055946
|
||||
|
||||
This was achieved with NetworkManager configured to do not perform
|
||||
periodical scans, by configuring constant BSSID. With periodical scans,
|
||||
after some time, performance downgrade to unpatched driver level, like
|
||||
in example below:
|
||||
|
||||
patched: 7.40 7.61 4.28 4.37 4.80 avr 5.6920 std 1.6683
|
||||
|
||||
However patch still make better here, since similar test on unpatched
|
||||
driver make link disconnects with below messages after some time:
|
||||
|
||||
wlan1: authenticate with 00:23:69:35:d1:3f (try 1)
|
||||
wlan1: authenticate with 00:23:69:35:d1:3f (try 2)
|
||||
wlan1: authenticate with 00:23:69:35:d1:3f (try 3)
|
||||
wlan1: authentication with 00:23:69:35:d1:3f timed out
|
||||
|
||||
On 2.6.35 kernel patch helps against connection hangs with messages:
|
||||
|
||||
iwlagn 0000:20:00.0: queue 10 stuck 3 time. Fw reload.
|
||||
iwlagn 0000:20:00.0: On demand firmware reload
|
||||
iwlagn 0000:20:00.0: Stopping AGG while state not ON or starting
|
||||
|
||||
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||
---
|
||||
drivers/net/wireless/iwlwifi/iwl-5000.c | 5 -----
|
||||
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c | 11 ++---------
|
||||
drivers/net/wireless/iwlwifi/iwl-agn.c | 7 +++++++
|
||||
3 files changed, 9 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
|
||||
index 0a67558..8270ed6 100644
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
|
||||
@@ -458,7 +458,6 @@ struct iwl_cfg iwl5300_agn_cfg = {
|
||||
.use_bsm = false,
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
- .use_rts_for_ht = true, /* use rts/cts protection */
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
@@ -489,7 +488,6 @@ struct iwl_cfg iwl5100_bgn_cfg = {
|
||||
.use_bsm = false,
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
- .use_rts_for_ht = true, /* use rts/cts protection */
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
@@ -549,7 +547,6 @@ struct iwl_cfg iwl5100_agn_cfg = {
|
||||
.use_bsm = false,
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
- .use_rts_for_ht = true, /* use rts/cts protection */
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
@@ -580,7 +577,6 @@ struct iwl_cfg iwl5350_agn_cfg = {
|
||||
.use_bsm = false,
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
- .use_rts_for_ht = true, /* use rts/cts protection */
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
@@ -611,7 +607,6 @@ struct iwl_cfg iwl5150_agn_cfg = {
|
||||
.use_bsm = false,
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
- .use_rts_for_ht = true, /* use rts/cts protection */
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
|
||||
index 2a30397..44e91af 100644
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
|
||||
@@ -214,16 +214,9 @@ static void iwlagn_rts_tx_cmd_flag(struct iwl_priv *priv,
|
||||
__le16 fc, __le32 *tx_flags)
|
||||
{
|
||||
if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
|
||||
- info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
|
||||
+ info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT ||
|
||||
+ info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||
*tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (priv->cfg->use_rts_for_ht &&
|
||||
- info->flags & IEEE80211_TX_CTL_AMPDU) {
|
||||
- *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
|
||||
- return;
|
||||
- }
|
||||
}
|
||||
|
||||
/* Calc max signal level (dBm) among 3 possible receivers */
|
||||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
|
||||
index 6bd11c7..20ffe4b 100644
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
|
||||
@@ -103,6 +103,13 @@ int iwl_commit_rxon(struct iwl_priv *priv)
|
||||
if (!iwl_is_alive(priv))
|
||||
return -EBUSY;
|
||||
|
||||
+ /*
|
||||
+ * force CTS-to-self frames protection if RTS-CTS is not preferred
|
||||
+ * one aggregation protection method
|
||||
+ */
|
||||
+ if (!priv->cfg->use_rts_for_ht)
|
||||
+ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
|
||||
+
|
||||
/* always get timestamp with Rx frame */
|
||||
priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
|
||||
|
||||
--
|
||||
1.7.1
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
From sgruszka@redhat.com Mon Jun 20 10:14:54 2011
|
||||
From: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||
To: kernel@lists.fedoraproject.org
|
||||
Subject: [PATCH 2.6.35 1/3] iwlwifi: add {ack, plpc}_check module parameters
|
||||
Date: Mon, 20 Jun 2011 16:15:12 +0200
|
||||
Message-Id: <1308579314-19348-2-git-send-email-sgruszka@redhat.com>
|
||||
|
||||
commit b7977ffaab5187ad75edaf04ac854615cea93828 upstream.
|
||||
|
||||
Add module ack_check, and plcp_check parameters. Ack_check is disabled
|
||||
by default since is proved that check ack health can cause troubles.
|
||||
Plcp_check is enabled by default.
|
||||
|
||||
This prevent connection hangs with "low ack count detected" messages.
|
||||
|
||||
Resolves:
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=666646
|
||||
|
||||
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||
---
|
||||
drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 1 +
|
||||
drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++++++
|
||||
drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++
|
||||
drivers/net/wireless/iwlwifi/iwl-rx.c | 8 ++++++--
|
||||
4 files changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
|
||||
index 0f292a2..3a79907 100644
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
|
||||
@@ -387,6 +387,7 @@ const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
|
||||
struct iwl_mod_params iwlagn_mod_params = {
|
||||
.amsdu_size_8K = 1,
|
||||
.restart_fw = 1,
|
||||
+ .plcp_check = true,
|
||||
/* the rest are 0 by default */
|
||||
};
|
||||
|
||||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
|
||||
index 8a2c4d7..6bd11c7 100644
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
|
||||
@@ -4180,3 +4180,9 @@ module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
|
||||
S_IRUGO);
|
||||
MODULE_PARM_DESC(ucode_alternative,
|
||||
"specify ucode alternative to use from ucode file");
|
||||
+
|
||||
+module_param_named(plcp_check, iwlagn_mod_params.plcp_check, bool, S_IRUGO);
|
||||
+MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])");
|
||||
+
|
||||
+module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO);
|
||||
+MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])");
|
||||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
|
||||
index e8ef317..ef03c24 100644
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
|
||||
@@ -226,6 +226,8 @@ struct iwl_mod_params {
|
||||
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
|
||||
int antenna; /* def: 0 = both antennas (use diversity) */
|
||||
int restart_fw; /* def: 1 = restart firmware */
|
||||
+ bool plcp_check; /* def: true = enable plcp health check */
|
||||
+ bool ack_check; /* def: false = disable ack health check */
|
||||
};
|
||||
|
||||
/**
|
||||
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
|
||||
index 0a5d7cf..d6c5927 100644
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
|
||||
@@ -401,10 +401,13 @@ EXPORT_SYMBOL(iwl_good_plcp_health);
|
||||
void iwl_recover_from_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
+ const struct iwl_mod_params *mod_params = priv->cfg->mod_params;
|
||||
+
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
if (iwl_is_associated(priv)) {
|
||||
- if (priv->cfg->ops->lib->check_ack_health) {
|
||||
+ if (mod_params->ack_check &&
|
||||
+ priv->cfg->ops->lib->check_ack_health) {
|
||||
if (!priv->cfg->ops->lib->check_ack_health(
|
||||
priv, pkt)) {
|
||||
/*
|
||||
@@ -417,7 +420,8 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
|
||||
return;
|
||||
}
|
||||
}
|
||||
- if (priv->cfg->ops->lib->check_plcp_health) {
|
||||
+ if (mod_params->plcp_check &&
|
||||
+ priv->cfg->ops->lib->check_plcp_health) {
|
||||
if (!priv->cfg->ops->lib->check_plcp_health(
|
||||
priv, pkt)) {
|
||||
/*
|
||||
--
|
||||
1.7.1
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
From 8762202dd0d6e46854f786bdb6fb3780a1625efe Mon Sep 17 00:00:00 2001
|
||||
From: Eryu Guan <guaneryu@gmail.com>
|
||||
Date: Tue, 1 Nov 2011 19:04:59 -0400
|
||||
Subject: [PATCH] jbd/jbd2: validate sb->s_first in journal_get_superblock()
|
||||
|
||||
I hit a J_ASSERT(blocknr != 0) failure in cleanup_journal_tail() when
|
||||
mounting a fsfuzzed ext3 image. It turns out that the corrupted ext3
|
||||
image has s_first = 0 in journal superblock, and the 0 is passed to
|
||||
journal->j_head in journal_reset(), then to blocknr in
|
||||
cleanup_journal_tail(), in the end the J_ASSERT failed.
|
||||
|
||||
So validate s_first after reading journal superblock from disk in
|
||||
journal_get_superblock() to ensure s_first is valid.
|
||||
|
||||
The following script could reproduce it:
|
||||
|
||||
fstype=ext3
|
||||
blocksize=1024
|
||||
img=$fstype.img
|
||||
offset=0
|
||||
found=0
|
||||
magic="c0 3b 39 98"
|
||||
|
||||
dd if=/dev/zero of=$img bs=1M count=8
|
||||
mkfs -t $fstype -b $blocksize -F $img
|
||||
filesize=`stat -c %s $img`
|
||||
while [ $offset -lt $filesize ]
|
||||
do
|
||||
if od -j $offset -N 4 -t x1 $img | grep -i "$magic";then
|
||||
echo "Found journal: $offset"
|
||||
found=1
|
||||
break
|
||||
fi
|
||||
offset=`echo "$offset+$blocksize" | bc`
|
||||
done
|
||||
|
||||
if [ $found -ne 1 ];then
|
||||
echo "Magic \"$magic\" not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dd if=/dev/zero of=$img seek=$(($offset+23)) conv=notrunc bs=1 count=1
|
||||
|
||||
mkdir -p ./mnt
|
||||
mount -o loop $img ./mnt
|
||||
|
||||
Cc: Jan Kara <jack@suse.cz>
|
||||
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
|
||||
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
|
||||
---
|
||||
fs/jbd/journal.c | 8 ++++++++
|
||||
fs/jbd2/journal.c | 8 ++++++++
|
||||
2 files changed, 16 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
|
||||
index 9fe061f..fea8dd6 100644
|
||||
--- a/fs/jbd/journal.c
|
||||
+++ b/fs/jbd/journal.c
|
||||
@@ -1135,6 +1135,14 @@ static int journal_get_superblock(journal_t *journal)
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ if (be32_to_cpu(sb->s_first) == 0 ||
|
||||
+ be32_to_cpu(sb->s_first) >= journal->j_maxlen) {
|
||||
+ printk(KERN_WARNING
|
||||
+ "JBD: Invalid start block of journal: %u\n",
|
||||
+ be32_to_cpu(sb->s_first));
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
|
||||
out:
|
||||
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
|
||||
index f24df13..d6e93d0 100644
|
||||
--- a/fs/jbd2/journal.c
|
||||
+++ b/fs/jbd2/journal.c
|
||||
@@ -1251,6 +1251,14 @@ static int journal_get_superblock(journal_t *journal)
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ if (be32_to_cpu(sb->s_first) == 0 ||
|
||||
+ be32_to_cpu(sb->s_first) >= journal->j_maxlen) {
|
||||
+ printk(KERN_WARNING
|
||||
+ "JBD2: Invalid start block of journal: %u\n",
|
||||
+ be32_to_cpu(sb->s_first));
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
|
||||
out:
|
||||
--
|
||||
1.7.7.1
|
||||
|
1351
kernel.spec
1351
kernel.spec
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,98 @@
|
|||
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
|
||||
Date: Tue, 29 Jun 2010 05:53:50 +0000 (+0900)
|
||||
Subject: kprobes/x86: Fix kprobes to skip prefixes correctly
|
||||
X-Git-Tag: v2.6.36-rc1~41^2~53
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=567a9fd86735ccdc897768ed2dacdd5e83a13509
|
||||
|
||||
kprobes/x86: Fix kprobes to skip prefixes correctly
|
||||
|
||||
Fix resume_execution() and is_IF_modifier() to skip x86
|
||||
instruction prefixes correctly by using x86 instruction
|
||||
attribute.
|
||||
|
||||
Without this fix, resume_execution() can't handle instructions
|
||||
which have non-REX prefixes (REX prefixes are skipped). This
|
||||
will cause unexpected kernel panic by hitting bad address when a
|
||||
kprobe hits on two-byte ret (e.g. "repz ret" generated for
|
||||
Athlon/K8 optimization), because it just checks "repz" and can't
|
||||
recognize the "ret" instruction.
|
||||
|
||||
These prefixes can be found easily with x86 instruction
|
||||
attribute. This patch introduces skip_prefixes() and uses it in
|
||||
resume_execution() and is_IF_modifier() to skip prefixes.
|
||||
|
||||
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
|
||||
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
|
||||
LKML-Reference: <4C298A6E.8070609@hitachi.com>
|
||||
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||
---
|
||||
|
||||
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
|
||||
index 345a4b1..175f85c 100644
|
||||
--- a/arch/x86/kernel/kprobes.c
|
||||
+++ b/arch/x86/kernel/kprobes.c
|
||||
@@ -126,16 +126,22 @@ static void __kprobes synthesize_reljump(void *from, void *to)
|
||||
}
|
||||
|
||||
/*
|
||||
- * Check for the REX prefix which can only exist on X86_64
|
||||
- * X86_32 always returns 0
|
||||
+ * Skip the prefixes of the instruction.
|
||||
*/
|
||||
-static int __kprobes is_REX_prefix(kprobe_opcode_t *insn)
|
||||
+static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn)
|
||||
{
|
||||
+ insn_attr_t attr;
|
||||
+
|
||||
+ attr = inat_get_opcode_attribute((insn_byte_t)*insn);
|
||||
+ while (inat_is_legacy_prefix(attr)) {
|
||||
+ insn++;
|
||||
+ attr = inat_get_opcode_attribute((insn_byte_t)*insn);
|
||||
+ }
|
||||
#ifdef CONFIG_X86_64
|
||||
- if ((*insn & 0xf0) == 0x40)
|
||||
- return 1;
|
||||
+ if (inat_is_rex_prefix(attr))
|
||||
+ insn++;
|
||||
#endif
|
||||
- return 0;
|
||||
+ return insn;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -272,6 +278,9 @@ static int __kprobes can_probe(unsigned long paddr)
|
||||
*/
|
||||
static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
|
||||
{
|
||||
+ /* Skip prefixes */
|
||||
+ insn = skip_prefixes(insn);
|
||||
+
|
||||
switch (*insn) {
|
||||
case 0xfa: /* cli */
|
||||
case 0xfb: /* sti */
|
||||
@@ -280,13 +289,6 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
|
||||
return 1;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * on X86_64, 0x40-0x4f are REX prefixes so we need to look
|
||||
- * at the next byte instead.. but of course not recurse infinitely
|
||||
- */
|
||||
- if (is_REX_prefix(insn))
|
||||
- return is_IF_modifier(++insn);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -803,9 +805,8 @@ static void __kprobes resume_execution(struct kprobe *p,
|
||||
unsigned long orig_ip = (unsigned long)p->addr;
|
||||
kprobe_opcode_t *insn = p->ainsn.insn;
|
||||
|
||||
- /*skip the REX prefix*/
|
||||
- if (is_REX_prefix(insn))
|
||||
- insn++;
|
||||
+ /* Skip prefixes */
|
||||
+ insn = skip_prefixes(insn);
|
||||
|
||||
regs->flags &= ~X86_EFLAGS_TF;
|
||||
switch (*insn) {
|
|
@ -0,0 +1,50 @@
|
|||
From: Joerg Roedel <joerg.roedel@amd.com>
|
||||
Date: Thu, 2 Sep 2010 15:29:45 +0000 (+0200)
|
||||
Subject: KVM: MMU: Fix 32 bit legacy paging with NPT
|
||||
X-Git-Tag: v2.6.37-rc1~142^2~75
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=f87f928882d080eaec8b0d76aecff003d664697d
|
||||
|
||||
KVM: MMU: Fix 32 bit legacy paging with NPT
|
||||
|
||||
This patch fixes 32 bit legacy paging with NPT enabled. The
|
||||
mmu_check_root call on the top-level of the loop causes
|
||||
root_gfn to take values (in the tdp_enabled path) which are
|
||||
outside of guest memory. So the mmu_check_root call fails at
|
||||
some point in the loop interation causing the guest to
|
||||
tiple-fault.
|
||||
This patch changes the mmu_check_root calls to the places
|
||||
where they are really necessary. As a side-effect it
|
||||
introduces a check for the root of a pae page table too.
|
||||
|
||||
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
|
||||
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
---
|
||||
|
||||
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
|
||||
index d2dad65..b2136f9 100644
|
||||
--- a/arch/x86/kvm/mmu.c
|
||||
+++ b/arch/x86/kvm/mmu.c
|
||||
@@ -2387,6 +2387,10 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
|
||||
return 0;
|
||||
}
|
||||
direct = !is_paging(vcpu);
|
||||
+
|
||||
+ if (mmu_check_root(vcpu, root_gfn))
|
||||
+ return 1;
|
||||
+
|
||||
for (i = 0; i < 4; ++i) {
|
||||
hpa_t root = vcpu->arch.mmu.pae_root[i];
|
||||
|
||||
@@ -2398,10 +2402,10 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
|
||||
continue;
|
||||
}
|
||||
root_gfn = pdptr >> PAGE_SHIFT;
|
||||
+ if (mmu_check_root(vcpu, root_gfn))
|
||||
+ return 1;
|
||||
} else if (vcpu->arch.mmu.root_level == 0)
|
||||
root_gfn = 0;
|
||||
- if (mmu_check_root(vcpu, root_gfn))
|
||||
- return 1;
|
||||
if (tdp_enabled) {
|
||||
direct = 1;
|
||||
root_gfn = i << 30;
|
|
@ -0,0 +1,30 @@
|
|||
Dump stack once on unsupported commands to see who is submitting them.
|
||||
(#632753)
|
||||
|
||||
--- linux-2.6.34.noarch.orig/drivers/ata/pata_it821x.c
|
||||
+++ linux-2.6.34.noarch/drivers/ata/pata_it821x.c
|
||||
@@ -399,6 +399,16 @@ static void it821x_passthru_dev_select(s
|
||||
ata_sff_dev_select(ap, device);
|
||||
}
|
||||
|
||||
+static void it821x_dump_stack_once(void)
|
||||
+{
|
||||
+ static int dumped = 0;
|
||||
+
|
||||
+ if (!dumped) {
|
||||
+ dump_stack();
|
||||
+ dumped = 1;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* it821x_smart_qc_issue - wrap qc issue prot
|
||||
* @qc: command
|
||||
@@ -433,6 +443,7 @@ static unsigned int it821x_smart_qc_issu
|
||||
return ata_sff_qc_issue(qc);
|
||||
}
|
||||
printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);
|
||||
+ it821x_dump_stack_once();
|
||||
return AC_ERR_DEV;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
diff -up linux-2.6.34.x86_64/drivers/acpi/acpica/dsobject.c.mjg59 linux-2.6.34.x86_64/drivers/acpi/acpica/dsobject.c
|
||||
--- linux-2.6.34.x86_64/drivers/acpi/acpica/dsobject.c.mjg59 2010-05-16 17:17:36.000000000 -0400
|
||||
+++ linux-2.6.34.x86_64/drivers/acpi/acpica/dsobject.c 2011-02-09 12:08:58.430275518 -0500
|
||||
@@ -81,6 +81,7 @@ acpi_ds_build_internal_object(struct acp
|
||||
{
|
||||
union acpi_operand_object *obj_desc;
|
||||
acpi_status status;
|
||||
+ acpi_object_type type;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ds_build_internal_object);
|
||||
|
||||
@@ -172,7 +173,20 @@ acpi_ds_build_internal_object(struct acp
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
- switch (op->common.node->type) {
|
||||
+ /*
|
||||
+ * Special handling for Alias objects. We need to setup the type
|
||||
+ * and the Op->Common.Node to point to the Alias target. Note,
|
||||
+ * Alias has at most one level of indirection internally.
|
||||
+ */
|
||||
+ type = op->common.node->type;
|
||||
+ if (type == ACPI_TYPE_LOCAL_ALIAS) {
|
||||
+ type = obj_desc->common.type;
|
||||
+ op->common.node =
|
||||
+ ACPI_CAST_PTR(struct acpi_namespace_node,
|
||||
+ op->common.node->object);
|
||||
+ }
|
||||
+
|
||||
+ switch (type) {
|
||||
/*
|
||||
* For these types, we need the actual node, not the subobject.
|
||||
* However, the subobject did not get an extra reference count above.
|
|
@ -0,0 +1,71 @@
|
|||
From: Neil Horman <nhorman@tuxdriver.com>
|
||||
Date: Tue, 5 Oct 2010 03:39:21 +0000 (+0000)
|
||||
Subject: bonding: fix WARN_ON when writing to bond_master sysfs file
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fdavem%2Fnet-2.6.git;a=commitdiff_plain;h=27e6f065df132b5270014d3285889b15185e9da9
|
||||
|
||||
bonding: fix WARN_ON when writing to bond_master sysfs file
|
||||
|
||||
Fix a WARN_ON failure in bond_masters sysfs file
|
||||
|
||||
Got a report of this warning recently
|
||||
|
||||
bonding: bond0 is being created...
|
||||
------------[ cut here ]------------
|
||||
WARNING: at fs/proc/generic.c:590 proc_register+0x14d/0x185()
|
||||
Hardware name: ProLiant BL465c G1
|
||||
proc_dir_entry 'bonding/bond0' already registered
|
||||
Modules linked in: bonding ipv6 tg3 bnx2 shpchp amd64_edac_mod edac_core
|
||||
ipmi_si
|
||||
ipmi_msghandler serio_raw i2c_piix4 k8temp edac_mce_amd hpwdt microcode hpsa
|
||||
cc
|
||||
iss radeon ttm drm_kms_helper drm i2c_algo_bit i2c_core [last unloaded:
|
||||
scsi_wai
|
||||
t_scan]
|
||||
Pid: 935, comm: ifup-eth Not tainted 2.6.33.5-124.fc13.x86_64 #1
|
||||
Call Trace:
|
||||
[<ffffffff8104b54c>] warn_slowpath_common+0x77/0x8f
|
||||
[<ffffffff8104b5b1>] warn_slowpath_fmt+0x3c/0x3e
|
||||
[<ffffffff8114bf0b>] proc_register+0x14d/0x185
|
||||
[<ffffffff8114c20c>] proc_create_data+0x87/0xa1
|
||||
[<ffffffffa0211e9b>] bond_create_proc_entry+0x55/0x95 [bonding]
|
||||
[<ffffffffa0215e5d>] bond_init+0x95/0xd0 [bonding]
|
||||
[<ffffffff8138cd97>] register_netdevice+0xdd/0x29e
|
||||
[<ffffffffa021240b>] bond_create+0x8e/0xb8 [bonding]
|
||||
[<ffffffffa021c4be>] bonding_store_bonds+0xb3/0x1c1 [bonding]
|
||||
[<ffffffff812aec85>] class_attr_store+0x27/0x29
|
||||
[<ffffffff8115423d>] sysfs_write_file+0x10f/0x14b
|
||||
[<ffffffff81101acf>] vfs_write+0xa9/0x106
|
||||
[<ffffffff81101be2>] sys_write+0x45/0x69
|
||||
[<ffffffff81009b02>] system_call_fastpath+0x16/0x1b
|
||||
---[ end trace a677c3f7f8b16b1e ]---
|
||||
bonding: Bond creation failed.
|
||||
|
||||
It happens because a user space writer to bond_master can try to
|
||||
register an already existing bond interface name. Fix it by teaching
|
||||
bond_create to check for the existance of devices with that name first
|
||||
in cases where a non-NULL name parameter has been passed in
|
||||
|
||||
Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
|
||||
index 3b16f62..e953c6a 100644
|
||||
--- a/drivers/net/bonding/bond_main.c
|
||||
+++ b/drivers/net/bonding/bond_main.c
|
||||
@@ -5164,6 +5164,15 @@ int bond_create(struct net *net, const char *name)
|
||||
res = dev_alloc_name(bond_dev, "bond%d");
|
||||
if (res < 0)
|
||||
goto out;
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * If we're given a name to register
|
||||
+ * we need to ensure that its not already
|
||||
+ * registered
|
||||
+ */
|
||||
+ res = -EEXIST;
|
||||
+ if (__dev_get_by_name(net, name) != NULL)
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
res = register_netdevice(bond_dev);
|
|
@ -0,0 +1,47 @@
|
|||
Message-ID: <4C805293.1020305@cn.fujitsu.com>
|
||||
Date: Fri, 03 Sep 2010 09:42:43 +0800
|
||||
From: Li Zefan <lizf@cn.fujitsu.com>
|
||||
To: David Miller <davem@davemloft.net>
|
||||
CC: Herbert Xu <herbert@gondor.hengli.com.au>, Dave Jones <davej@redhat.com>,
|
||||
netdev <netdev@vger.kernel.org>, LKML <linux-kernel@vger.kernel.org>,
|
||||
Peter Zijlstra <peterz@infradead.org>, Paul Menage <menage@google.com>
|
||||
Subject: [PATCH v2] cls_cgroup: Fix rcu lockdep warning
|
||||
|
||||
Dave reported an rcu lockdep warning on 2.6.35.4 kernel
|
||||
|
||||
task->cgroups and task->cgroups->subsys[i] are protected by RCU.
|
||||
So we avoid accessing invalid pointers here. This might happen,
|
||||
for example, when you are deref-ing those pointers while someone
|
||||
move @task from one cgroup to another.
|
||||
|
||||
Reported-by: Dave Jones <davej@redhat.com>
|
||||
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
|
||||
---
|
||||
include/net/cls_cgroup.h | 10 ++++++++--
|
||||
1 files changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
|
||||
index dd1fdb8..a4dc5b0 100644
|
||||
--- a/include/net/cls_cgroup.h
|
||||
+++ b/include/net/cls_cgroup.h
|
||||
@@ -27,11 +27,17 @@ struct cgroup_cls_state
|
||||
#ifdef CONFIG_NET_CLS_CGROUP
|
||||
static inline u32 task_cls_classid(struct task_struct *p)
|
||||
{
|
||||
+ int classid;
|
||||
+
|
||||
if (in_interrupt())
|
||||
return 0;
|
||||
|
||||
- return container_of(task_subsys_state(p, net_cls_subsys_id),
|
||||
- struct cgroup_cls_state, css)->classid;
|
||||
+ rcu_read_lock();
|
||||
+ classid = container_of(task_subsys_state(p, net_cls_subsys_id),
|
||||
+ struct cgroup_cls_state, css)->classid;
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ return classid;
|
||||
}
|
||||
#else
|
||||
extern int net_cls_subsys_id;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
--- linux-2.6.34.noarch.orig/kernel/power/main.c
|
||||
+++ linux-2.6.34.noarch/kernel/power/main.c
|
||||
@@ -45,7 +45,7 @@ int pm_notifier_call_chain(unsigned long
|
||||
}
|
||||
|
||||
/* If set, devices may be suspended and resumed asynchronously. */
|
||||
-int pm_async_enabled = 1;
|
||||
+int pm_async_enabled;
|
||||
|
||||
static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
|
@ -0,0 +1,29 @@
|
|||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
||||
index cea0cd9..c326065 100644
|
||||
--- a/arch/x86/Kconfig
|
||||
+++ b/arch/x86/Kconfig
|
||||
@@ -2142,3 +2142,8 @@ source "crypto/Kconfig"
|
||||
source "arch/x86/kvm/Kconfig"
|
||||
|
||||
source "lib/Kconfig"
|
||||
+
|
||||
+config PCI_DEFAULT_USE_CRS
|
||||
+ def_bool y
|
||||
+ prompt "Use PCI Host Bridge Windows from ACPI by default?"
|
||||
+ depends on ACPI
|
||||
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
|
||||
index 15466c0..3099406 100644
|
||||
--- a/arch/x86/pci/acpi.c
|
||||
+++ b/arch/x86/pci/acpi.c
|
||||
@@ -16,7 +16,11 @@ struct pci_root_info {
|
||||
int busnum;
|
||||
};
|
||||
|
||||
+#ifdef CONFIG_PCI_DEFAULT_USE_CRS
|
||||
static bool pci_use_crs = true;
|
||||
+#else
|
||||
+static bool pci_use_crs = false;
|
||||
+#endif
|
||||
|
||||
static int __init set_use_crs(const struct dmi_system_id *id)
|
||||
{
|
|
@ -0,0 +1,30 @@
|
|||
This only showed up in one SDV (Montevina).
|
||||
The PCIE slots don't seem to like network cards, so this is the only hope
|
||||
to get networking working. It's never going upstream, but it's low impact
|
||||
enough to carry just to keep those SDVs working.
|
||||
|
||||
--- linux-2.6.35.noarch/drivers/net/e1000e/ich8lan.c~ 2010-09-29 17:53:13.000000000 -0400
|
||||
+++ linux-2.6.35.noarch/drivers/net/e1000e/ich8lan.c 2010-09-29 17:54:00.000000000 -0400
|
||||
@@ -424,6 +424,12 @@ static s32 e1000_init_phy_params_ich8lan
|
||||
|
||||
/* Verify phy id */
|
||||
switch (phy->id) {
|
||||
+ case 0:
|
||||
+ if (hw->adapter->pdev->device == 0x10be)
|
||||
+ e_dbg("got 0 phy id, trying anyway");
|
||||
+ /* Fall through to IGP03E1000 case below */
|
||||
+ else
|
||||
+ return -E1000_ERR_PHY;
|
||||
case IGP03E1000_E_PHY_ID:
|
||||
phy->type = e1000_phy_igp_3;
|
||||
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
|
||||
--- linux-2.6.35.noarch/drivers/net/e1000e/netdev.c~ 2010-09-29 17:54:07.000000000 -0400
|
||||
+++ linux-2.6.35.noarch/drivers/net/e1000e/netdev.c 2010-09-29 17:54:29.000000000 -0400
|
||||
@@ -5994,6 +5994,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan },
|
||||
+ { PCI_VDEVICE(INTEL, 0x10be), board_ich9lan },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan },
|
|
@ -1,46 +0,0 @@
|
|||
[PATCH] ext4: fix freeze deadlock under IO
|
||||
|
||||
Commit 6b0310fbf087ad6 caused a regression resulting in deadlocks
|
||||
when freezing a filesystem which had active IO; the vfs_check_frozen
|
||||
level (SB_FREEZE_WRITE) did not let the freeze-related IO syncing
|
||||
through. Duh.
|
||||
|
||||
Changing the test to FREEZE_TRANS should let the normal freeze
|
||||
syncing get through the fs, but still block any transactions from
|
||||
starting once the fs is completely frozen.
|
||||
|
||||
I tested this by running fsstress in the background while periodically
|
||||
snapshotting the fs and running fsck on the result. I ran into
|
||||
occasional deadlocks, but different ones. I think this is a
|
||||
fine fix for the problem at hand, and the other deadlocky things
|
||||
will need more investigation.
|
||||
|
||||
Reported-by: Phillip Susi <psusi@cfl.rr.com>
|
||||
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
|
||||
---
|
||||
|
||||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
|
||||
index 4e8983a..a45ced9 100644
|
||||
--- a/fs/ext4/super.c
|
||||
+++ b/fs/ext4/super.c
|
||||
@@ -241,7 +241,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
return ERR_PTR(-EROFS);
|
||||
|
||||
- vfs_check_frozen(sb, SB_FREEZE_WRITE);
|
||||
+ vfs_check_frozen(sb, SB_FREEZE_TRANS);
|
||||
/* Special case here: if the journal has aborted behind our
|
||||
* backs (eg. EIO in the commit thread), then we still need to
|
||||
* take the FS itself readonly cleanly. */
|
||||
@@ -3491,7 +3491,7 @@ int ext4_force_commit(struct super_block *sb)
|
||||
|
||||
journal = EXT4_SB(sb)->s_journal;
|
||||
if (journal) {
|
||||
- vfs_check_frozen(sb, SB_FREEZE_WRITE);
|
||||
+ vfs_check_frozen(sb, SB_FREEZE_TRANS);
|
||||
ret = ext4_journal_force_commit(journal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -141,8 +141,8 @@
|
|||
set_user_gs(regs, 0);
|
||||
+
|
||||
regs->fs = 0;
|
||||
set_fs(USER_DS);
|
||||
regs->ds = __USER_DS;
|
||||
regs->es = __USER_DS;
|
||||
@@ -252,6 +255,11 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
|
||||
regs->cs = __USER_CS;
|
||||
regs->ip = new_ip;
|
||||
|
@ -538,15 +538,16 @@
|
|||
static void unmap_region(struct mm_struct *mm,
|
||||
struct vm_area_struct *vma, struct vm_area_struct *prev,
|
||||
unsigned long start, unsigned long end);
|
||||
@@ -388,6 +401,8 @@
|
||||
__vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||
struct vm_area_struct *prev, struct rb_node *rb_parent)
|
||||
@@ -388,6 +401,9 @@
|
||||
{
|
||||
struct vm_area_struct *next;
|
||||
|
||||
+ if (vma->vm_flags & VM_EXEC)
|
||||
+ arch_add_exec_range(mm, vma->vm_end);
|
||||
+
|
||||
vma->vm_prev = prev;
|
||||
if (prev) {
|
||||
vma->vm_next = prev->vm_next;
|
||||
prev->vm_next = vma;
|
||||
next = prev->vm_next;
|
||||
@@ -489,6 +504,8 @@
|
||||
rb_erase(&vma->vm_rb, &mm->mm_rb);
|
||||
if (mm->mmap_cache == vma)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
|
||||
index 9fbc54a..435c502 100644
|
||||
--- a/include/linux/rcupdate.h
|
||||
+++ b/include/linux/rcupdate.h
|
||||
@@ -454,7 +454,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
|
||||
* Makes rcu_dereference_check() do the dirty work.
|
||||
*/
|
||||
#define rcu_dereference_bh(p) \
|
||||
- rcu_dereference_check(p, rcu_read_lock_bh_held())
|
||||
+ rcu_dereference_check(p, rcu_read_lock_bh_held() || irqs_disabled())
|
||||
|
||||
/**
|
||||
* rcu_dereference_sched - fetch RCU-protected pointer, checking for RCU-sched
|
||||
|
||||
|
|
@ -1 +1,332 @@
|
|||
nil
|
||||
From c6c14330717f9850b4b4c054b81424b9979cd07d Mon Sep 17 00:00:00 2001
|
||||
From: Jean-Francois Moine <moinejf@free.fr>
|
||||
Date: Tue, 14 Dec 2010 16:15:37 -0300
|
||||
Subject: [media] gspca - sonixj: Add a flag in the driver_info table
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
From: Jean-Francois Moine <moinejf@free.fr>
|
||||
|
||||
commit c6c14330717f9850b4b4c054b81424b9979cd07d upstream.
|
||||
|
||||
Signed-off-by: Jean-François Moine <moinejf@free.fr>
|
||||
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
|
||||
---
|
||||
drivers/media/video/gspca/sonixj.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
Index: linux-2.6.35.y/drivers/media/video/gspca/sonixj.c
|
||||
===================================================================
|
||||
--- linux-2.6.35.y.orig/drivers/media/video/gspca/sonixj.c
|
||||
+++ linux-2.6.35.y/drivers/media/video/gspca/sonixj.c
|
||||
@@ -57,6 +57,7 @@ struct sd {
|
||||
u8 jpegqual; /* webcam quality */
|
||||
|
||||
u8 reg18;
|
||||
+ u8 flags;
|
||||
|
||||
s8 ag_cnt;
|
||||
#define AG_CNT_START 13
|
||||
@@ -1777,7 +1778,8 @@ static int sd_config(struct gspca_dev *g
|
||||
struct cam *cam;
|
||||
|
||||
sd->bridge = id->driver_info >> 16;
|
||||
- sd->sensor = id->driver_info;
|
||||
+ sd->sensor = id->driver_info >> 8;
|
||||
+ sd->flags = id->driver_info;
|
||||
|
||||
cam = &gspca_dev->cam;
|
||||
if (sd->sensor == SENSOR_ADCM1700) {
|
||||
@@ -3001,7 +3003,11 @@ static const struct sd_desc sd_desc = {
|
||||
/* -- module initialisation -- */
|
||||
#define BS(bridge, sensor) \
|
||||
.driver_info = (BRIDGE_ ## bridge << 16) \
|
||||
- | SENSOR_ ## sensor
|
||||
+ | (SENSOR_ ## sensor << 8)
|
||||
+#define BSF(bridge, sensor, flags) \
|
||||
+ .driver_info = (BRIDGE_ ## bridge << 16) \
|
||||
+ | (SENSOR_ ## sensor << 8) \
|
||||
+ | (flags)
|
||||
static const __devinitdata struct usb_device_id device_table[] = {
|
||||
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
|
||||
{USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)},
|
||||
From b2272a49e7df37732d73988f00468ce31e1ebc92 Mon Sep 17 00:00:00 2001
|
||||
From: Jean-Francois Moine <moinejf@free.fr>
|
||||
Date: Tue, 14 Dec 2010 16:16:16 -0300
|
||||
Subject: [media] gspca - sonixj: Set the flag for some devices
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
From: Jean-Francois Moine <moinejf@free.fr>
|
||||
|
||||
commit b2272a49e7df37732d73988f00468ce31e1ebc92 upstream.
|
||||
|
||||
The flag PDN_INV indicates that the sensor pin S_PWR_DN has not the same
|
||||
value as other webcams with the same sensor. For now, only two webcams have
|
||||
been so detected: the Microsoft's VX1000 and VX3000.
|
||||
|
||||
Signed-off-by: Jean-François Moine <moinejf@free.fr>
|
||||
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
|
||||
---
|
||||
drivers/media/video/gspca/sonixj.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
Index: linux-2.6.35.y/drivers/media/video/gspca/sonixj.c
|
||||
===================================================================
|
||||
--- linux-2.6.35.y.orig/drivers/media/video/gspca/sonixj.c
|
||||
+++ linux-2.6.35.y/drivers/media/video/gspca/sonixj.c
|
||||
@@ -88,6 +88,9 @@ enum {
|
||||
u8 jpeg_hdr[JPEG_HDR_SZ];
|
||||
};
|
||||
|
||||
+/* device flags */
|
||||
+#define PDN_INV 1 /* inverse pin S_PWR_DN / sn_xxx tables */
|
||||
+
|
||||
/* V4L2 controls supported by the driver */
|
||||
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
|
||||
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
@@ -3004,8 +3007,8 @@ static const __devinitdata struct usb_de
|
||||
{USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)},
|
||||
{USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)},
|
||||
#endif
|
||||
- {USB_DEVICE(0x045e, 0x00f5), BS(SN9C105, OV7660)},
|
||||
- {USB_DEVICE(0x045e, 0x00f7), BS(SN9C105, OV7660)},
|
||||
+ {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)},
|
||||
+ {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, PDN_INV)},
|
||||
{USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)},
|
||||
{USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)},
|
||||
{USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)},
|
||||
From 615661f3948a066fd22a36fe8ea0c528b75ee373 Mon Sep 17 00:00:00 2001
|
||||
From: Marcin Slusarz <marcin.slusarz@gmail.com>
|
||||
Date: Sun, 22 Aug 2010 20:54:08 +0200
|
||||
Subject: drm/nv50: initialize ramht_refs list for faked 0 channel
|
||||
|
||||
From: Marcin Slusarz <marcin.slusarz@gmail.com>
|
||||
|
||||
commit 615661f3948a066fd22a36fe8ea0c528b75ee373 upstream.
|
||||
|
||||
We need it for PFIFO_INTR_CACHE_ERROR interrupt handling,
|
||||
because nouveau_fifo_swmthd looks for matching gpuobj in
|
||||
ramht_refs list.
|
||||
It fixes kernel panic in nouveau_gpuobj_ref_find.
|
||||
|
||||
Signed-off-by: Marcin Slusarz <marcin.slusarz@gmail.com>
|
||||
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
|
||||
---
|
||||
drivers/gpu/drm/nouveau/nv50_instmem.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
|
||||
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
|
||||
@@ -141,6 +141,8 @@ nv50_instmem_init(struct drm_device *dev
|
||||
chan->file_priv = (struct drm_file *)-2;
|
||||
dev_priv->fifos[0] = dev_priv->fifos[127] = chan;
|
||||
|
||||
+ INIT_LIST_HEAD(&chan->ramht_refs);
|
||||
+
|
||||
/* Channel's PRAMIN object + heap */
|
||||
ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0,
|
||||
NULL, &chan->ramin);
|
||||
|
||||
commit 6f1b1e1384b23cfab30c2bc02a8f94927274c10d
|
||||
Author: Geert Uytterhoeven <geert@linux-m68k.org>
|
||||
Date: Sun Jan 16 10:09:13 2011 -0300
|
||||
|
||||
radio-aimslab.c needs #include <linux/delay.h>
|
||||
|
||||
commit 2400982a2e8a8e4e95f0a0e1517bbe63cc88038f upstream.
|
||||
|
||||
Commit e3c92215198cb6aa00ad38db2780faa6b72e0a3f ("[media] radio-aimslab.c: Fix
|
||||
gcc 4.5+ bug") removed the include, but introduced new callers of msleep():
|
||||
|
||||
| drivers/media/radio/radio-aimslab.c: In function ‘rt_decvol’:
|
||||
| drivers/media/radio/radio-aimslab.c:76: error: implicit declaration of function ‘msleep’
|
||||
|
||||
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
|
||||
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
Cc: dann frazier <dannf@debian.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
|
||||
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
|
||||
index 1944814..a91642c 100644
|
||||
--- a/drivers/media/radio/radio-aimslab.c
|
||||
+++ b/drivers/media/radio/radio-aimslab.c
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/module.h> /* Modules */
|
||||
#include <linux/init.h> /* Initdata */
|
||||
#include <linux/ioport.h> /* request_region */
|
||||
+#include <linux/delay.h> /* msleep */
|
||||
#include <linux/videodev2.h> /* kernel radio structs */
|
||||
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
|
||||
#include <linux/io.h> /* outb, outb_p */
|
||||
|
||||
commit 9c198dad83c19a05a11b5a195242f3e8dcbe55f4
|
||||
Author: Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
Date: Thu Jan 6 08:16:04 2011 -0200
|
||||
|
||||
radio-aimslab.c: Fix gcc 4.5+ bug
|
||||
|
||||
commit e3c92215198cb6aa00ad38db2780faa6b72e0a3f upstream.
|
||||
|
||||
gcc 4.5+ doesn't properly evaluate some inlined expressions.
|
||||
A previous patch were proposed by Andrew Morton using noinline.
|
||||
However, the entire inlined function is bogus, so let's just
|
||||
remove it and be happy.
|
||||
|
||||
Reported-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
|
||||
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
|
||||
index 5bf4985..1944814 100644
|
||||
--- a/drivers/media/radio/radio-aimslab.c
|
||||
+++ b/drivers/media/radio/radio-aimslab.c
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <linux/module.h> /* Modules */
|
||||
#include <linux/init.h> /* Initdata */
|
||||
#include <linux/ioport.h> /* request_region */
|
||||
-#include <linux/delay.h> /* udelay */
|
||||
#include <linux/videodev2.h> /* kernel radio structs */
|
||||
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
|
||||
#include <linux/io.h> /* outb, outb_p */
|
||||
@@ -71,27 +70,17 @@ static struct rtrack rtrack_card;
|
||||
|
||||
/* local things */
|
||||
|
||||
-static void sleep_delay(long n)
|
||||
-{
|
||||
- /* Sleep nicely for 'n' uS */
|
||||
- int d = n / msecs_to_jiffies(1000);
|
||||
- if (!d)
|
||||
- udelay(n);
|
||||
- else
|
||||
- msleep(jiffies_to_msecs(d));
|
||||
-}
|
||||
-
|
||||
static void rt_decvol(struct rtrack *rt)
|
||||
{
|
||||
outb(0x58, rt->io); /* volume down + sigstr + on */
|
||||
- sleep_delay(100000);
|
||||
+ msleep(100);
|
||||
outb(0xd8, rt->io); /* volume steady + sigstr + on */
|
||||
}
|
||||
|
||||
static void rt_incvol(struct rtrack *rt)
|
||||
{
|
||||
outb(0x98, rt->io); /* volume up + sigstr + on */
|
||||
- sleep_delay(100000);
|
||||
+ msleep(100);
|
||||
outb(0xd8, rt->io); /* volume steady + sigstr + on */
|
||||
}
|
||||
|
||||
@@ -120,7 +109,7 @@ static int rt_setvol(struct rtrack *rt, int vol)
|
||||
|
||||
if (vol == 0) { /* volume = 0 means mute the card */
|
||||
outb(0x48, rt->io); /* volume down but still "on" */
|
||||
- sleep_delay(2000000); /* make sure it's totally down */
|
||||
+ msleep(2000); /* make sure it's totally down */
|
||||
outb(0xd0, rt->io); /* volume steady, off */
|
||||
rt->curvol = 0; /* track the volume state! */
|
||||
mutex_unlock(&rt->lock);
|
||||
@@ -155,7 +144,7 @@ static void send_0_byte(struct rtrack *rt)
|
||||
outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */
|
||||
outb_p(128+64+16+8+2+1, rt->io); /* clock */
|
||||
}
|
||||
- sleep_delay(1000);
|
||||
+ msleep(1);
|
||||
}
|
||||
|
||||
static void send_1_byte(struct rtrack *rt)
|
||||
@@ -169,7 +158,7 @@ static void send_1_byte(struct rtrack *rt)
|
||||
outb_p(128+64+16+8+4+2+1, rt->io); /* clock */
|
||||
}
|
||||
|
||||
- sleep_delay(1000);
|
||||
+ msleep(1);
|
||||
}
|
||||
|
||||
static int rt_setfreq(struct rtrack *rt, unsigned long freq)
|
||||
@@ -427,7 +416,7 @@ static int __init rtrack_init(void)
|
||||
|
||||
/* this ensures that the volume is all the way down */
|
||||
outb(0x48, rt->io); /* volume down but still "on" */
|
||||
- sleep_delay(2000000); /* make sure it's totally down */
|
||||
+ msleep(2000); /* make sure it's totally down */
|
||||
outb(0xc0, rt->io); /* steady volume, mute card */
|
||||
|
||||
return 0;
|
||||
|
||||
commit 515884e98dc4f1c99387000d420394c3bc47c0d7
|
||||
Author: Dan Carpenter <error27@gmail.com>
|
||||
Date: Fri Jan 7 16:41:54 2011 -0300
|
||||
|
||||
av7110: check for negative array offset
|
||||
|
||||
commit cb26a24ee9706473f31d34cc259f4dcf45cd0644 upstream.
|
||||
|
||||
info->num comes from the user. It's type int. If the user passes
|
||||
in a negative value that would cause memory corruption.
|
||||
|
||||
Signed-off-by: Dan Carpenter <error27@gmail.com>
|
||||
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
|
||||
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
|
||||
index 4eba35a..c38dd67 100644
|
||||
--- a/drivers/media/dvb/ttpci/av7110_ca.c
|
||||
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
|
||||
@@ -277,7 +277,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
|
||||
{
|
||||
ca_slot_info_t *info=(ca_slot_info_t *)parg;
|
||||
|
||||
- if (info->num > 1)
|
||||
+ if (info->num < 0 || info->num > 1)
|
||||
return -EINVAL;
|
||||
av7110->ci_slot[info->num].num = info->num;
|
||||
av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
|
||||
|
||||
commit 9e5ad61f8d81da0b58535ac2cf60d36e26ca567a
|
||||
Author: Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
Date: Mon Oct 25 17:51:15 2010 -0300
|
||||
|
||||
em28xx: Fix audio input for Terratec Grabby
|
||||
|
||||
commit a3fa904ec79b94f0db7faed010ff94d42f7d1d47 upstream.
|
||||
|
||||
The audio input line was wrong. Fix it.
|
||||
|
||||
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
|
||||
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
|
||||
index 3a4fd85..2fa5bb4 100644
|
||||
--- a/drivers/media/video/em28xx/em28xx-cards.c
|
||||
+++ b/drivers/media/video/em28xx/em28xx-cards.c
|
||||
@@ -1605,11 +1605,11 @@ struct em28xx_board em28xx_boards[] = {
|
||||
.input = { {
|
||||
.type = EM28XX_VMUX_COMPOSITE1,
|
||||
.vmux = SAA7115_COMPOSITE0,
|
||||
- .amux = EM28XX_AMUX_VIDEO2,
|
||||
+ .amux = EM28XX_AMUX_LINE_IN,
|
||||
}, {
|
||||
.type = EM28XX_VMUX_SVIDEO,
|
||||
.vmux = SAA7115_SVIDEO3,
|
||||
- .amux = EM28XX_AMUX_VIDEO2,
|
||||
+ .amux = EM28XX_AMUX_LINE_IN,
|
||||
} },
|
||||
},
|
||||
[EM2860_BOARD_TERRATEC_AV350] = {
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
commit 611225f5e7f9d11c4b119fac224f1bd6903b0150
|
||||
Author: Jarod Wilson <jarod@redhat.com>
|
||||
Date: Sun Mar 7 17:55:43 2010 -0300
|
||||
|
||||
V4L/DVB: dvb: add support for kworld 340u and ub435-q to em28xx-dvb
|
||||
|
||||
This adds support for the KWorld PlusTV 340U and KWorld UB345-Q ATSC
|
||||
sticks, which are really the same device. The sticks have an eMPIA
|
||||
em2870 usb bridge chipset, an LG Electronics LGDT3304 ATSC/QAM
|
||||
demodulator and an NXP TDA18271HD tuner -- early versions of the 340U
|
||||
have a a TDA18271HD/C1, later models and the UB435-Q have a C2.
|
||||
|
||||
The stick has been tested succesfully with both VSB_8 and QAM_256 signals.
|
||||
Its using lgdt3304 support added to the lgdt3305 driver by a prior patch,
|
||||
rather than the current lgdt3304 driver, as its severely lacking in
|
||||
functionality by comparison (see said patch for details).
|
||||
|
||||
Signed-off-by: Jarod Wilson <jarod@redhat.com>
|
||||
Signed-off-by: Michael Krufky <mkrufky@kernellabs.com>
|
||||
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
|
||||
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
|
||||
index 3a623aa..5c56875 100644
|
||||
--- a/Documentation/video4linux/CARDLIST.em28xx
|
||||
+++ b/Documentation/video4linux/CARDLIST.em28xx
|
||||
@@ -72,3 +72,4 @@
|
||||
73 -> Reddo DVB-C USB TV Box (em2870)
|
||||
74 -> Actionmaster/LinXcel/Digitus VC211A (em2800)
|
||||
75 -> Dikom DK300 (em2882)
|
||||
+ 76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340]
|
||||
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
|
||||
index 3a4fd85..ffbe544 100644
|
||||
--- a/drivers/media/video/em28xx/em28xx-cards.c
|
||||
+++ b/drivers/media/video/em28xx/em28xx-cards.c
|
||||
@@ -158,6 +158,22 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
|
||||
{ -1, -1, -1, -1},
|
||||
};
|
||||
|
||||
+/*
|
||||
+ * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map:
|
||||
+ * EM_GPIO_0 - currently unknown
|
||||
+ * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on)
|
||||
+ * EM_GPIO_2 - currently unknown
|
||||
+ * EM_GPIO_3 - currently unknown
|
||||
+ * EM_GPIO_4 - TDA18271HD/C1 tuner (1 = active, 0 = in reset)
|
||||
+ * EM_GPIO_5 - LGDT3304 ATSC/QAM demod (1 = active, 0 = in reset)
|
||||
+ * EM_GPIO_6 - currently unknown
|
||||
+ * EM_GPIO_7 - currently unknown
|
||||
+ */
|
||||
+static struct em28xx_reg_seq kworld_a340_digital[] = {
|
||||
+ {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
|
||||
+ { -1, -1, -1, -1},
|
||||
+};
|
||||
+
|
||||
/* Pinnacle Hybrid Pro eb1a:2881 */
|
||||
static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
|
||||
{EM28XX_R08_GPIO, 0xfd, ~EM_GPIO_4, 10},
|
||||
@@ -1667,6 +1683,16 @@ struct em28xx_board em28xx_boards[] = {
|
||||
.tuner_gpio = reddo_dvb_c_usb_box,
|
||||
.has_dvb = 1,
|
||||
},
|
||||
+ /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold
|
||||
+ * initially as the KWorld PlusTV 340U, then as the UB435-Q.
|
||||
+ * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */
|
||||
+ [EM2870_BOARD_KWORLD_A340] = {
|
||||
+ .name = "KWorld PlusTV 340U or UB435-Q (ATSC)",
|
||||
+ .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */
|
||||
+ .has_dvb = 1,
|
||||
+ .dvb_gpio = kworld_a340_digital,
|
||||
+ .tuner_gpio = default_tuner_gpio,
|
||||
+ },
|
||||
};
|
||||
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
|
||||
|
||||
@@ -1788,6 +1814,8 @@ struct usb_device_id em28xx_id_table[] = {
|
||||
.driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
|
||||
{ USB_DEVICE(0xeb1a, 0x50a6),
|
||||
.driver_info = EM2860_BOARD_GADMEI_UTV330 },
|
||||
+ { USB_DEVICE(0x1b80, 0xa340),
|
||||
+ .driver_info = EM2870_BOARD_KWORLD_A340 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
|
||||
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
|
||||
index cf1d8c3..3ac8d30 100644
|
||||
--- a/drivers/media/video/em28xx/em28xx-dvb.c
|
||||
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
|
||||
@@ -30,11 +30,13 @@
|
||||
#include "tuner-simple.h"
|
||||
|
||||
#include "lgdt330x.h"
|
||||
+#include "lgdt3305.h"
|
||||
#include "zl10353.h"
|
||||
#include "s5h1409.h"
|
||||
#include "mt352.h"
|
||||
#include "mt352_priv.h" /* FIXME */
|
||||
#include "tda1002x.h"
|
||||
+#include "tda18271.h"
|
||||
|
||||
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
|
||||
@@ -231,6 +233,18 @@ static struct lgdt330x_config em2880_lgdt3303_dev = {
|
||||
.demod_chip = LGDT3303,
|
||||
};
|
||||
|
||||
+static struct lgdt3305_config em2870_lgdt3304_dev = {
|
||||
+ .i2c_addr = 0x0e,
|
||||
+ .demod_chip = LGDT3304,
|
||||
+ .spectral_inversion = 1,
|
||||
+ .deny_i2c_rptr = 1,
|
||||
+ .mpeg_mode = LGDT3305_MPEG_PARALLEL,
|
||||
+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
|
||||
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
|
||||
+ .vsb_if_khz = 3250,
|
||||
+ .qam_if_khz = 4000,
|
||||
+};
|
||||
+
|
||||
static struct zl10353_config em28xx_zl10353_with_xc3028 = {
|
||||
.demod_address = (0x1e >> 1),
|
||||
.no_tuner = 1,
|
||||
@@ -247,6 +261,17 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
|
||||
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
|
||||
};
|
||||
|
||||
+static struct tda18271_std_map kworld_a340_std_map = {
|
||||
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 0,
|
||||
+ .if_lvl = 1, .rfagc_top = 0x37, },
|
||||
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 1,
|
||||
+ .if_lvl = 1, .rfagc_top = 0x37, },
|
||||
+};
|
||||
+
|
||||
+static struct tda18271_config kworld_a340_config = {
|
||||
+ .std_map = &kworld_a340_std_map,
|
||||
+};
|
||||
+
|
||||
static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
|
||||
.demod_address = (0x1e >> 1),
|
||||
.no_tuner = 1,
|
||||
@@ -572,6 +597,14 @@ static int dvb_init(struct em28xx *dev)
|
||||
}
|
||||
}
|
||||
break;
|
||||
+ case EM2870_BOARD_KWORLD_A340:
|
||||
+ dvb->frontend = dvb_attach(lgdt3305_attach,
|
||||
+ &em2870_lgdt3304_dev,
|
||||
+ &dev->i2c_adap);
|
||||
+ if (dvb->frontend != NULL)
|
||||
+ dvb_attach(tda18271_attach, dvb->frontend, 0x60,
|
||||
+ &dev->i2c_adap, &kworld_a340_config);
|
||||
+ break;
|
||||
default:
|
||||
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
|
||||
" isn't supported yet\n");
|
||||
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
|
||||
index 6216786..1c61a6b 100644
|
||||
--- a/drivers/media/video/em28xx/em28xx.h
|
||||
+++ b/drivers/media/video/em28xx/em28xx.h
|
||||
@@ -114,6 +114,7 @@
|
||||
#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
|
||||
#define EM2800_BOARD_VC211A 74
|
||||
#define EM2882_BOARD_DIKOM_DK300 75
|
||||
+#define EM2870_BOARD_KWORLD_A340 76
|
||||
|
||||
/* Limits minimum and default number of buffers */
|
||||
#define EM28XX_MIN_BUF 4
|
|
@ -1,350 +0,0 @@
|
|||
From b71e18093e2e7f240797875c50c49552722f8825 Mon Sep 17 00:00:00 2001
|
||||
From: Jarod Wilson <jarod@redhat.com>
|
||||
Date: Mon, 15 Feb 2010 17:13:25 -0500
|
||||
Subject: [PATCH 1/2] dvb: add lgdt3304 support to lgdt3305 driver
|
||||
|
||||
There's a currently-unused lgdt3304 demod driver, which leaves a lot to
|
||||
be desired as far as functionality. The 3304 is unsurprisingly quite
|
||||
similar to the 3305, and empirical testing yeilds far better results
|
||||
and more complete functionality by merging 3304 support into the 3305
|
||||
driver. (For example, the current lgdt3304 driver lacks support for
|
||||
signal strength, snr, ucblocks, etc., which we get w/the lgdt3305).
|
||||
|
||||
For the moment, not dropping the lgdt3304 driver, and its still up to
|
||||
a given device's config setup to choose which demod driver to use, but
|
||||
I'd suggest dropping the 3304 driver entirely.
|
||||
|
||||
As a follow-up to this patch, I've got another patch that adds support
|
||||
for the KWorld PlusTV 340U (ATSC) em2870-based tuner stick, driving
|
||||
its lgdt3304 demod via this lgdt3305 driver, which is what I used to
|
||||
successfully test this patch with both VSB_8 and QAM_256 signals.
|
||||
|
||||
A few pieces are still a touch crude, but I think its a solid start,
|
||||
as well as much cleaner and more feature-complete than the existing
|
||||
lgdt3304 driver.
|
||||
|
||||
Signed-off-by: Jarod Wilson <jarod@redhat.com>
|
||||
---
|
||||
drivers/media/dvb/frontends/lgdt3305.c | 206 ++++++++++++++++++++++++++++++--
|
||||
drivers/media/dvb/frontends/lgdt3305.h | 6 +
|
||||
2 files changed, 203 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c
|
||||
index fde8c59..40695e6 100644
|
||||
--- a/drivers/media/dvb/frontends/lgdt3305.c
|
||||
+++ b/drivers/media/dvb/frontends/lgdt3305.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
- * Support for LGDT3305 - VSB/QAM
|
||||
+ * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
|
||||
*
|
||||
* Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
@@ -357,7 +357,10 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
|
||||
case QAM_256:
|
||||
agcdelay = 0x046b;
|
||||
rfbw = 0x8889;
|
||||
- ifbw = 0x8888;
|
||||
+ if (state->cfg->demod_chip == LGDT3305)
|
||||
+ ifbw = 0x8888;
|
||||
+ else
|
||||
+ ifbw = 0x6666;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -409,8 +412,18 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state,
|
||||
lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
|
||||
|
||||
/* control agc function */
|
||||
- lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
|
||||
- lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
|
||||
+ switch (state->cfg->demod_chip) {
|
||||
+ case LGDT3304:
|
||||
+ lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);
|
||||
+ lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);
|
||||
+ break;
|
||||
+ case LGDT3305:
|
||||
+ lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
|
||||
+ lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
return lgdt3305_rfagc_loop(state, param);
|
||||
}
|
||||
@@ -543,6 +556,11 @@ static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||
enable ? 0 : 1);
|
||||
}
|
||||
|
||||
+static int lgdt3304_sleep(struct dvb_frontend *fe)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int lgdt3305_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct lgdt3305_state *state = fe->demodulator_priv;
|
||||
@@ -571,6 +589,55 @@ static int lgdt3305_sleep(struct dvb_frontend *fe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int lgdt3304_init(struct dvb_frontend *fe)
|
||||
+{
|
||||
+ struct lgdt3305_state *state = fe->demodulator_priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ static struct lgdt3305_reg lgdt3304_init_data[] = {
|
||||
+ { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, },
|
||||
+ { .reg = 0x000d, .val = 0x02, },
|
||||
+ { .reg = 0x000e, .val = 0x02, },
|
||||
+ { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, },
|
||||
+ { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, },
|
||||
+ { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, },
|
||||
+ { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, },
|
||||
+ { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, },
|
||||
+ { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, },
|
||||
+ { .reg = LGDT3305_CR_CTRL_7, .val = 0xf9, },
|
||||
+ { .reg = 0x0112, .val = 0x17, },
|
||||
+ { .reg = 0x0113, .val = 0x15, },
|
||||
+ { .reg = 0x0114, .val = 0x18, },
|
||||
+ { .reg = 0x0115, .val = 0xff, },
|
||||
+ { .reg = 0x0116, .val = 0x3c, },
|
||||
+ { .reg = 0x0214, .val = 0x67, },
|
||||
+ { .reg = 0x0424, .val = 0x8d, },
|
||||
+ { .reg = 0x0427, .val = 0x12, },
|
||||
+ { .reg = 0x0428, .val = 0x4f, },
|
||||
+ { .reg = LGDT3305_IFBW_1, .val = 0x80, },
|
||||
+ { .reg = LGDT3305_IFBW_2, .val = 0x00, },
|
||||
+ { .reg = 0x030a, .val = 0x08, },
|
||||
+ { .reg = 0x030b, .val = 0x9b, },
|
||||
+ { .reg = 0x030d, .val = 0x00, },
|
||||
+ { .reg = 0x030e, .val = 0x1c, },
|
||||
+ { .reg = 0x0314, .val = 0xe1, },
|
||||
+ { .reg = 0x000d, .val = 0x82, },
|
||||
+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, },
|
||||
+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, },
|
||||
+ };
|
||||
+
|
||||
+ lg_dbg("\n");
|
||||
+
|
||||
+ ret = lgdt3305_write_regs(state, lgdt3304_init_data,
|
||||
+ ARRAY_SIZE(lgdt3304_init_data));
|
||||
+ if (lg_fail(ret))
|
||||
+ goto fail;
|
||||
+
|
||||
+ ret = lgdt3305_soft_reset(state);
|
||||
+fail:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int lgdt3305_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct lgdt3305_state *state = fe->demodulator_priv;
|
||||
@@ -639,6 +706,88 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int lgdt3304_set_parameters(struct dvb_frontend *fe,
|
||||
+ struct dvb_frontend_parameters *param)
|
||||
+{
|
||||
+ struct lgdt3305_state *state = fe->demodulator_priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
|
||||
+
|
||||
+ if (fe->ops.tuner_ops.set_params) {
|
||||
+ ret = fe->ops.tuner_ops.set_params(fe, param);
|
||||
+ if (fe->ops.i2c_gate_ctrl)
|
||||
+ fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
+ if (lg_fail(ret))
|
||||
+ goto fail;
|
||||
+ state->current_frequency = param->frequency;
|
||||
+ }
|
||||
+
|
||||
+ ret = lgdt3305_set_modulation(state, param);
|
||||
+ if (lg_fail(ret))
|
||||
+ goto fail;
|
||||
+
|
||||
+ ret = lgdt3305_passband_digital_agc(state, param);
|
||||
+ if (lg_fail(ret))
|
||||
+ goto fail;
|
||||
+
|
||||
+ ret = lgdt3305_agc_setup(state, param);
|
||||
+ if (lg_fail(ret))
|
||||
+ goto fail;
|
||||
+
|
||||
+ /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
|
||||
+ switch (param->u.vsb.modulation) {
|
||||
+ case VSB_8:
|
||||
+ lgdt3305_write_reg(state, 0x030d, 0x00);
|
||||
+#if 1
|
||||
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
|
||||
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);
|
||||
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);
|
||||
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);
|
||||
+#endif
|
||||
+ break;
|
||||
+ case QAM_64:
|
||||
+ case QAM_256:
|
||||
+ lgdt3305_write_reg(state, 0x030d, 0x14);
|
||||
+#if 1
|
||||
+ ret = lgdt3305_set_if(state, param);
|
||||
+ if (lg_fail(ret))
|
||||
+ goto fail;
|
||||
+#endif
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+#if 0
|
||||
+ /* the set_if vsb formula doesn't work for the 3304, we end up sending
|
||||
+ * 0x40851e07 instead of 0x4f0cacba (which works back to 94050, rather
|
||||
+ * than 3250, in the case of the kworld 340u) */
|
||||
+ ret = lgdt3305_set_if(state, param);
|
||||
+ if (lg_fail(ret))
|
||||
+ goto fail;
|
||||
+#endif
|
||||
+
|
||||
+ ret = lgdt3305_spectral_inversion(state, param,
|
||||
+ state->cfg->spectral_inversion
|
||||
+ ? 1 : 0);
|
||||
+ if (lg_fail(ret))
|
||||
+ goto fail;
|
||||
+
|
||||
+ state->current_modulation = param->u.vsb.modulation;
|
||||
+
|
||||
+ ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
|
||||
+ if (lg_fail(ret))
|
||||
+ goto fail;
|
||||
+
|
||||
+ /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
|
||||
+ ret = lgdt3305_mpeg_mode_polarity(state,
|
||||
+ state->cfg->tpclk_edge,
|
||||
+ state->cfg->tpvalid_polarity);
|
||||
+fail:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int lgdt3305_set_parameters(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *param)
|
||||
{
|
||||
@@ -847,6 +996,10 @@ static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
switch (state->current_modulation) {
|
||||
case QAM_256:
|
||||
case QAM_64:
|
||||
+#if 0 /* needed w/3304 to set FE_HAS_SIGNAL */
|
||||
+ if (cr_lock)
|
||||
+ *status |= FE_HAS_SIGNAL;
|
||||
+#endif
|
||||
ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
|
||||
if (lg_fail(ret))
|
||||
goto fail;
|
||||
@@ -992,6 +1145,7 @@ static void lgdt3305_release(struct dvb_frontend *fe)
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
+static struct dvb_frontend_ops lgdt3304_ops;
|
||||
static struct dvb_frontend_ops lgdt3305_ops;
|
||||
|
||||
struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
|
||||
@@ -1012,11 +1166,21 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
|
||||
state->cfg = config;
|
||||
state->i2c_adap = i2c_adap;
|
||||
|
||||
- memcpy(&state->frontend.ops, &lgdt3305_ops,
|
||||
- sizeof(struct dvb_frontend_ops));
|
||||
+ switch (config->demod_chip) {
|
||||
+ case LGDT3304:
|
||||
+ memcpy(&state->frontend.ops, &lgdt3304_ops,
|
||||
+ sizeof(struct dvb_frontend_ops));
|
||||
+ break;
|
||||
+ case LGDT3305:
|
||||
+ memcpy(&state->frontend.ops, &lgdt3305_ops,
|
||||
+ sizeof(struct dvb_frontend_ops));
|
||||
+ break;
|
||||
+ default:
|
||||
+ goto fail;
|
||||
+ }
|
||||
state->frontend.demodulator_priv = state;
|
||||
|
||||
- /* verify that we're talking to a lg dt3305 */
|
||||
+ /* verify that we're talking to a lg dt3304/5 */
|
||||
ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
|
||||
if ((lg_fail(ret)) | (val == 0))
|
||||
goto fail;
|
||||
@@ -1035,12 +1199,36 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
|
||||
|
||||
return &state->frontend;
|
||||
fail:
|
||||
- lg_warn("unable to detect LGDT3305 hardware\n");
|
||||
+ lg_warn("unable to detect %s hardware\n",
|
||||
+ config->demod_chip ? "LGDT3304" : "LGDT3305");
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(lgdt3305_attach);
|
||||
|
||||
+static struct dvb_frontend_ops lgdt3304_ops = {
|
||||
+ .info = {
|
||||
+ .name = "LG Electronics LGDT3304 VSB/QAM Frontend",
|
||||
+ .type = FE_ATSC,
|
||||
+ .frequency_min = 54000000,
|
||||
+ .frequency_max = 858000000,
|
||||
+ .frequency_stepsize = 62500,
|
||||
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
|
||||
+ },
|
||||
+ .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl,
|
||||
+ .init = lgdt3304_init,
|
||||
+ .sleep = lgdt3304_sleep,
|
||||
+ .set_frontend = lgdt3304_set_parameters,
|
||||
+ .get_frontend = lgdt3305_get_frontend,
|
||||
+ .get_tune_settings = lgdt3305_get_tune_settings,
|
||||
+ .read_status = lgdt3305_read_status,
|
||||
+ .read_ber = lgdt3305_read_ber,
|
||||
+ .read_signal_strength = lgdt3305_read_signal_strength,
|
||||
+ .read_snr = lgdt3305_read_snr,
|
||||
+ .read_ucblocks = lgdt3305_read_ucblocks,
|
||||
+ .release = lgdt3305_release,
|
||||
+};
|
||||
+
|
||||
static struct dvb_frontend_ops lgdt3305_ops = {
|
||||
.info = {
|
||||
.name = "LG Electronics LGDT3305 VSB/QAM Frontend",
|
||||
@@ -1064,7 +1252,7 @@ static struct dvb_frontend_ops lgdt3305_ops = {
|
||||
.release = lgdt3305_release,
|
||||
};
|
||||
|
||||
-MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver");
|
||||
+MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
|
||||
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("0.1");
|
||||
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
|
||||
index 9cb11c9..a7f30c2 100644
|
||||
--- a/drivers/media/dvb/frontends/lgdt3305.h
|
||||
+++ b/drivers/media/dvb/frontends/lgdt3305.h
|
||||
@@ -41,6 +41,11 @@ enum lgdt3305_tp_valid_polarity {
|
||||
LGDT3305_TP_VALID_HIGH = 1,
|
||||
};
|
||||
|
||||
+enum lgdt_demod_chip_type {
|
||||
+ LGDT3305 = 0,
|
||||
+ LGDT3304 = 1,
|
||||
+};
|
||||
+
|
||||
struct lgdt3305_config {
|
||||
u8 i2c_addr;
|
||||
|
||||
@@ -65,6 +70,7 @@ struct lgdt3305_config {
|
||||
enum lgdt3305_mpeg_mode mpeg_mode;
|
||||
enum lgdt3305_tp_clock_edge tpclk_edge;
|
||||
enum lgdt3305_tp_valid_polarity tpvalid_polarity;
|
||||
+ enum lgdt_demod_chip_type demod_chip;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
|
||||
--
|
||||
1.6.6
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue