Compare commits
169 Commits
master
...
f14-user-k
Author | SHA1 | Date |
---|---|---|
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 |
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_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_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_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
|
@# 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
|
@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 debugbuildsenabled 1/%define debugbuildsenabled 0/' kernel.spec
|
||||||
@perl -pi -e 's/^%define rawhide_skip_docs 0/%define rawhide_skip_docs 1/' 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:
|
release:
|
||||||
@perl -pi -e 's/CONFIG_SLUB_DEBUG_ON=y/# CONFIG_SLUB_DEBUG_ON is not set/' config-nodebug
|
@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
|
@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_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_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_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-debug
|
||||||
@perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-nodebug
|
@perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-nodebug
|
||||||
|
|
|
@ -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,263 @@
|
||||||
|
diff -uNrp kernel-2.6.35.fc14.orig/drivers/bluetooth/btusb.c kernel-2.6.35.fc14.new/drivers/bluetooth/btusb.c
|
||||||
|
--- kernel-2.6.35.fc14.orig/drivers/bluetooth/btusb.c 2010-11-12 12:35:49.390791080 +0100
|
||||||
|
+++ kernel-2.6.35.fc14.new/drivers/bluetooth/btusb.c 2010-11-12 12:48:22.090611963 +0100
|
||||||
|
@@ -68,6 +68,9 @@ static struct usb_device_id btusb_table[
|
||||||
|
/* Apple MacBookPro6,2 */
|
||||||
|
{ USB_DEVICE(0x05ac, 0x8218) },
|
||||||
|
|
||||||
|
+ /* Apple MacBookAir3,1, MacBookAir3,2 */
|
||||||
|
+ { USB_DEVICE(0x05ac, 0x821b) },
|
||||||
|
+
|
||||||
|
/* AVM BlueFRITZ! USB v2.0 */
|
||||||
|
{ USB_DEVICE(0x057c, 0x3800) },
|
||||||
|
|
||||||
|
diff -uNrp kernel-2.6.35.fc14.orig/drivers/hid/hid-apple.c kernel-2.6.35.fc14.new/drivers/hid/hid-apple.c
|
||||||
|
--- kernel-2.6.35.fc14.orig/drivers/hid/hid-apple.c 2010-11-12 12:35:49.153805968 +0100
|
||||||
|
+++ kernel-2.6.35.fc14.new/drivers/hid/hid-apple.c 2010-11-12 12:48:35.689816431 +0100
|
||||||
|
@@ -59,6 +59,27 @@ struct apple_key_translation {
|
||||||
|
u8 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
+static const struct apple_key_translation macbookair_fn_keys[] = {
|
||||||
|
+ { KEY_BACKSPACE, KEY_DELETE },
|
||||||
|
+ { KEY_ENTER, KEY_INSERT },
|
||||||
|
+ { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F6, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F7, KEY_PLAYPAUSE, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F8, KEY_NEXTSONG, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F9, KEY_MUTE, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F10, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F11, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_F12, KEY_EJECTCD, APPLE_FLAG_FKEY },
|
||||||
|
+ { KEY_UP, KEY_PAGEUP },
|
||||||
|
+ { KEY_DOWN, KEY_PAGEDOWN },
|
||||||
|
+ { KEY_LEFT, KEY_HOME },
|
||||||
|
+ { KEY_RIGHT, KEY_END },
|
||||||
|
+ { }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static const struct apple_key_translation apple_fn_keys[] = {
|
||||||
|
{ KEY_BACKSPACE, KEY_DELETE },
|
||||||
|
{ KEY_ENTER, KEY_INSERT },
|
||||||
|
@@ -157,10 +178,14 @@ static int hidinput_apple_event(struct h
|
||||||
|
if (fnmode) {
|
||||||
|
int do_translate;
|
||||||
|
|
||||||
|
- trans = apple_find_translation((hid->product < 0x21d ||
|
||||||
|
+ if(hid->product >= 0x023f && hid->product <= 0x0244 ) {
|
||||||
|
+ trans = apple_find_translation(macbookair_fn_keys, usage->code);
|
||||||
|
+ } else {
|
||||||
|
+ trans = apple_find_translation((hid->product < 0x21d ||
|
||||||
|
hid->product >= 0x300) ?
|
||||||
|
powerbook_fn_keys : apple_fn_keys,
|
||||||
|
usage->code);
|
||||||
|
+ }
|
||||||
|
if (trans) {
|
||||||
|
if (test_bit(usage->code, asc->pressed_fn))
|
||||||
|
do_translate = 1;
|
||||||
|
@@ -435,6 +460,18 @@ static const struct hid_device_id apple_
|
||||||
|
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
|
||||||
|
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
|
||||||
|
+ .driver_data = APPLE_HAS_FN },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
|
||||||
|
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
|
||||||
|
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
|
||||||
|
+ .driver_data = APPLE_HAS_FN },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
|
||||||
|
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
|
||||||
|
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
|
||||||
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
|
||||||
|
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
|
||||||
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
|
||||||
|
diff -uNrp kernel-2.6.35.fc14.orig/drivers/hid/hid-core.c kernel-2.6.35.fc14.new/drivers/hid/hid-core.c
|
||||||
|
--- kernel-2.6.35.fc14.orig/drivers/hid/hid-core.c 2010-11-12 12:35:49.153805968 +0100
|
||||||
|
+++ kernel-2.6.35.fc14.new/drivers/hid/hid-core.c 2010-11-12 12:48:35.690816373 +0100
|
||||||
|
@@ -1273,6 +1273,12 @@ static const struct hid_device_id hid_bl
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
|
||||||
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
|
||||||
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
|
||||||
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
|
||||||
|
@@ -1738,6 +1744,12 @@ static const struct hid_device_id hid_mo
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
|
||||||
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
|
||||||
|
{ }
|
||||||
|
diff -uNrp kernel-2.6.35.fc14.orig/drivers/hid/hid-ids.h kernel-2.6.35.fc14.new/drivers/hid/hid-ids.h
|
||||||
|
--- kernel-2.6.35.fc14.orig/drivers/hid/hid-ids.h 2010-11-12 12:35:49.153805968 +0100
|
||||||
|
+++ kernel-2.6.35.fc14.new/drivers/hid/hid-ids.h 2010-11-12 12:48:35.691816314 +0100
|
||||||
|
@@ -93,6 +93,12 @@
|
||||||
|
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236
|
||||||
|
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237
|
||||||
|
#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244
|
||||||
|
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239
|
||||||
|
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a
|
||||||
|
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
|
||||||
|
diff -uNrp kernel-2.6.35.fc14.orig/drivers/hwmon/applesmc.c kernel-2.6.35.fc14.new/drivers/hwmon/applesmc.c
|
||||||
|
--- kernel-2.6.35.fc14.orig/drivers/hwmon/applesmc.c 2010-11-12 12:35:49.618776754 +0100
|
||||||
|
+++ kernel-2.6.35.fc14.new/drivers/hwmon/applesmc.c 2010-11-13 12:25:05.810472278 +0100
|
||||||
|
@@ -162,6 +162,10 @@ static const char *temperature_sensors_s
|
||||||
|
/* Set 22: MacBook Pro 7,1 */
|
||||||
|
{ "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S",
|
||||||
|
"TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL },
|
||||||
|
+/* Set 23: MacBook Air 3,1 */
|
||||||
|
+ { "TB0T", "TB1T", "TB2T", "TC0D", "TC0E", "TC0P", "TC1E", "TCZ3",
|
||||||
|
+ "TCZ4", "TCZ5", "TG0E", "TG1E", "TG2E", "TGZ3", "TGZ4", "TGZ5",
|
||||||
|
+ "TH0F", "TH0O", "TM0P" },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* List of keys used to read/write fan speeds */
|
||||||
|
@@ -1524,11 +1528,21 @@ static __initdata struct dmi_match_data
|
||||||
|
{ .accelerometer = 1, .light = 1, .temperature_set = 21 },
|
||||||
|
/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */
|
||||||
|
{ .accelerometer = 1, .light = 1, .temperature_set = 22 },
|
||||||
|
+/* MacBook Air 3,1: accelerometer, backlight and temperature set 15 */
|
||||||
|
+ { .accelerometer = 0, .light = 0, .temperature_set = 23 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
|
||||||
|
* So we need to put "Apple MacBook Pro" before "Apple MacBook". */
|
||||||
|
static __initdata struct dmi_system_id applesmc_whitelist[] = {
|
||||||
|
+ { applesmc_dmi_match, "Apple MacBook Air 3", {
|
||||||
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
|
||||||
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2") },
|
||||||
|
+ &applesmc_dmi_data[23]},
|
||||||
|
+ { applesmc_dmi_match, "Apple MacBook Air 3", {
|
||||||
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
|
||||||
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1") },
|
||||||
|
+ &applesmc_dmi_data[23]},
|
||||||
|
{ applesmc_dmi_match, "Apple MacBook Air 2", {
|
||||||
|
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
|
||||||
|
diff -uNrp kernel-2.6.35.fc14.orig/drivers/input/mouse/bcm5974.c kernel-2.6.35.fc14.new/drivers/input/mouse/bcm5974.c
|
||||||
|
--- kernel-2.6.35.fc14.orig/drivers/input/mouse/bcm5974.c 2010-11-12 12:35:50.004752503 +0100
|
||||||
|
+++ kernel-2.6.35.fc14.new/drivers/input/mouse/bcm5974.c 2010-11-12 12:48:13.140136374 +0100
|
||||||
|
@@ -55,6 +55,14 @@
|
||||||
|
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236
|
||||||
|
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237
|
||||||
|
#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238
|
||||||
|
+/* MacbookAir3,2 (unibody), aka wellspring5 */
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241
|
||||||
|
+/* MacbookAir3,1 (unibody), aka wellspring4 */
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243
|
||||||
|
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244
|
||||||
|
|
||||||
|
#define BCM5974_DEVICE(prod) { \
|
||||||
|
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
|
||||||
|
@@ -80,6 +88,14 @@ static const struct usb_device_id bcm597
|
||||||
|
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI),
|
||||||
|
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO),
|
||||||
|
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
|
||||||
|
+ /* MacbookAir3,2 */
|
||||||
|
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
|
||||||
|
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
|
||||||
|
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
|
||||||
|
+ /* MacbookAir3,1 */
|
||||||
|
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
|
||||||
|
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
|
||||||
|
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
|
||||||
|
/* Terminating entry */
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
@@ -234,6 +250,30 @@ static const struct bcm5974_config bcm59
|
||||||
|
{ DIM_X, DIM_X / SN_COORD, -4460, 5166 },
|
||||||
|
{ DIM_Y, DIM_Y / SN_COORD, -75, 6700 }
|
||||||
|
},
|
||||||
|
+ {
|
||||||
|
+ USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI,
|
||||||
|
+ USB_DEVICE_ID_APPLE_WELLSPRING4_ISO,
|
||||||
|
+ USB_DEVICE_ID_APPLE_WELLSPRING4_JIS,
|
||||||
|
+ HAS_INTEGRATED_BUTTON,
|
||||||
|
+ 0x84, sizeof(struct bt_data),
|
||||||
|
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||||
|
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||||
|
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||||
|
+ { DIM_X, DIM_X / SN_COORD, -4460, 5166 },
|
||||||
|
+ { DIM_Y, DIM_Y / SN_COORD, -75, 6700 }
|
||||||
|
+ },
|
||||||
|
+ {
|
||||||
|
+ USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI,
|
||||||
|
+ USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO,
|
||||||
|
+ USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS,
|
||||||
|
+ HAS_INTEGRATED_BUTTON,
|
||||||
|
+ 0x84, sizeof(struct bt_data),
|
||||||
|
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||||
|
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||||
|
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||||
|
+ { DIM_X, DIM_X / SN_COORD, -4460, 5166 },
|
||||||
|
+ { DIM_Y, DIM_Y / SN_COORD, -75, 6700 }
|
||||||
|
+ },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
diff -uNrp kernel-2.6.35.fc14.orig/drivers/video/backlight/mbp_nvidia_bl.c kernel-2.6.35.fc14.new/drivers/video/backlight/mbp_nvidia_bl.c
|
||||||
|
--- kernel-2.6.35.fc14.orig/drivers/video/backlight/mbp_nvidia_bl.c 2010-11-12 12:35:49.159805591 +0100
|
||||||
|
+++ kernel-2.6.35.fc14.new/drivers/video/backlight/mbp_nvidia_bl.c 2010-11-12 12:48:47.412131884 +0100
|
||||||
|
@@ -335,6 +335,24 @@ static const struct dmi_system_id __init
|
||||||
|
},
|
||||||
|
.driver_data = (void *)&nvidia_chipset_data,
|
||||||
|
},
|
||||||
|
+ {
|
||||||
|
+ .callback = mbp_dmi_match,
|
||||||
|
+ .ident = "MacBookAir 3,1",
|
||||||
|
+ .matches = {
|
||||||
|
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||||
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"),
|
||||||
|
+ },
|
||||||
|
+ .driver_data = (void *)&nvidia_chipset_data,
|
||||||
|
+ },
|
||||||
|
+ {
|
||||||
|
+ .callback = mbp_dmi_match,
|
||||||
|
+ .ident = "MacBookAir 3,2",
|
||||||
|
+ .matches = {
|
||||||
|
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||||
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"),
|
||||||
|
+ },
|
||||||
|
+ .driver_data = (void *)&nvidia_chipset_data,
|
||||||
|
+ },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
diff -uNrp kernel-2.6.35.fc14.orig/sound/pci/hda/patch_cirrus.c kernel-2.6.35.fc14.new/sound/pci/hda/patch_cirrus.c
|
||||||
|
--- kernel-2.6.35.fc14.orig/sound/pci/hda/patch_cirrus.c 2010-11-12 12:35:49.005815268 +0100
|
||||||
|
+++ kernel-2.6.35.fc14.new/sound/pci/hda/patch_cirrus.c 2010-11-12 12:48:40.379542432 +0100
|
||||||
|
@@ -1139,6 +1139,7 @@ static const char *cs420x_models[CS420X_
|
||||||
|
static struct snd_pci_quirk cs420x_cfg_tbl[] = {
|
||||||
|
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
|
||||||
|
SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
|
||||||
|
+ SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
|
||||||
|
{} /* terminator */
|
||||||
|
};
|
||||||
|
|
|
@ -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,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,41 @@
|
||||||
|
From kernel-bounces@lists.fedoraproject.org Fri Sep 17 17:09:15 2010
|
||||||
|
From: Will Woods <wwoods@redhat.com>
|
||||||
|
To: Marcel Holtmann <marcel@holtmann.org>
|
||||||
|
Subject: [PATCH 2/2] bluetooth: add support for controller in MacBookPro6,2
|
||||||
|
Date: Fri, 17 Sep 2010 17:09:21 -0400
|
||||||
|
|
||||||
|
Once again the device class is ff(vend.) instead of e0(wlcon).
|
||||||
|
|
||||||
|
output from 'usb-devices':
|
||||||
|
T: Bus=01 Lev=03 Prnt=03 Port=02 Cnt=03 Dev#= 8 Spd=12 MxCh= 0
|
||||||
|
D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
|
||||||
|
P: Vendor=05ac ProdID=8218 Rev=00.22
|
||||||
|
S: Manufacturer=Apple Inc.
|
||||||
|
S: Product=Bluetooth USB Host Controller
|
||||||
|
C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA
|
||||||
|
I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
|
||||||
|
I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
|
||||||
|
I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
|
||||||
|
I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
|
||||||
|
|
||||||
|
Signed-off-by: Will Woods <wwoods@redhat.com>
|
||||||
|
---
|
||||||
|
drivers/bluetooth/btusb.c | 3 +++
|
||||||
|
1 files changed, 3 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
|
||||||
|
index eac44e4..320e798 100644
|
||||||
|
--- a/drivers/bluetooth/btusb.c
|
||||||
|
+++ b/drivers/bluetooth/btusb.c
|
||||||
|
@@ -65,6 +65,9 @@ static struct usb_device_id btusb_table[] = {
|
||||||
|
/* Apple iMac11,1 */
|
||||||
|
{ USB_DEVICE(0x05ac, 0x8215) },
|
||||||
|
|
||||||
|
+ /* Apple MacBookPro6,2 */
|
||||||
|
+ { USB_DEVICE(0x05ac, 0x8218) },
|
||||||
|
+
|
||||||
|
/* AVM BlueFRITZ! USB v2.0 */
|
||||||
|
{ USB_DEVICE(0x057c, 0x3800) },
|
||||||
|
|
||||||
|
--
|
||||||
|
1.7.2.3
|
|
@ -0,0 +1,42 @@
|
||||||
|
From kernel-bounces@lists.fedoraproject.org Fri Sep 17 17:09:18 2010
|
||||||
|
From: Will Woods <wwoods@redhat.com>
|
||||||
|
To: Marcel Holtmann <marcel@holtmann.org>
|
||||||
|
Subject: [PATCH 1/2] bluetooth: add support for controller in MacBookPro7,1
|
||||||
|
Date: Fri, 17 Sep 2010 17:09:20 -0400
|
||||||
|
|
||||||
|
As with iMac11,1 the device class is ff(vend.) instead of e0(wlcon).
|
||||||
|
|
||||||
|
output from 'usb-devices':
|
||||||
|
T: Bus=04 Lev=02 Prnt=04 Port=00 Cnt=01 Dev#= 5 Spd=12 MxCh= 0
|
||||||
|
D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
|
||||||
|
P: Vendor=05ac ProdID=8213 Rev=01.86
|
||||||
|
S: Manufacturer=Apple Inc.
|
||||||
|
S: Product=Bluetooth USB Host Controller
|
||||||
|
S: SerialNumber=58B0359C28ED
|
||||||
|
C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA
|
||||||
|
I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
|
||||||
|
I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
|
||||||
|
I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
|
||||||
|
I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=00 Driver=(none)
|
||||||
|
|
||||||
|
Signed-off-by: Will Woods <wwoods@redhat.com>
|
||||||
|
---
|
||||||
|
drivers/bluetooth/btusb.c | 3 +++
|
||||||
|
1 files changed, 3 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
|
||||||
|
index d22ce3c..eac44e4 100644
|
||||||
|
--- a/drivers/bluetooth/btusb.c
|
||||||
|
+++ b/drivers/bluetooth/btusb.c
|
||||||
|
@@ -59,6 +59,9 @@ static struct usb_device_id btusb_table[] = {
|
||||||
|
/* Generic Bluetooth USB device */
|
||||||
|
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
||||||
|
|
||||||
|
+ /* Apple MacBookPro7,1 */
|
||||||
|
+ { USB_DEVICE(0x05ac, 0x8213) },
|
||||||
|
+
|
||||||
|
/* Apple iMac11,1 */
|
||||||
|
{ USB_DEVICE(0x05ac, 0x8215) },
|
||||||
|
|
||||||
|
--
|
||||||
|
1.7.2.3
|
|
@ -87,5 +87,7 @@ CONFIG_PM_ADVANCED_DEBUG=y
|
||||||
CONFIG_CEPH_FS_PRETTYDEBUG=y
|
CONFIG_CEPH_FS_PRETTYDEBUG=y
|
||||||
CONFIG_QUOTA_DEBUG=y
|
CONFIG_QUOTA_DEBUG=y
|
||||||
|
|
||||||
|
# CONFIG_PCI_DEFAULT_USE_CRS is not set
|
||||||
|
|
||||||
CONFIG_KGDB_KDB=y
|
CONFIG_KGDB_KDB=y
|
||||||
CONFIG_KDB_KEYBOARD=y
|
CONFIG_KDB_KEYBOARD=y
|
||||||
|
|
|
@ -684,7 +684,7 @@ CONFIG_MD_RAID0=m
|
||||||
CONFIG_MD_RAID1=m
|
CONFIG_MD_RAID1=m
|
||||||
CONFIG_MD_RAID10=m
|
CONFIG_MD_RAID10=m
|
||||||
CONFIG_MD_RAID456=m
|
CONFIG_MD_RAID456=m
|
||||||
CONFIG_MULTICORE_RAID456=y
|
# CONFIG_MULTICORE_RAID456 is not set
|
||||||
CONFIG_ASYNC_RAID6_TEST=m
|
CONFIG_ASYNC_RAID6_TEST=m
|
||||||
CONFIG_BLK_DEV_DM=y
|
CONFIG_BLK_DEV_DM=y
|
||||||
CONFIG_DM_CRYPT=m
|
CONFIG_DM_CRYPT=m
|
||||||
|
@ -1423,11 +1423,11 @@ CONFIG_ATMEL=m
|
||||||
CONFIG_B43=m
|
CONFIG_B43=m
|
||||||
CONFIG_B43_PCMCIA=y
|
CONFIG_B43_PCMCIA=y
|
||||||
CONFIG_B43_SDIO=y
|
CONFIG_B43_SDIO=y
|
||||||
CONFIG_B43_DEBUG=y
|
# CONFIG_B43_DEBUG is not set
|
||||||
CONFIG_B43_PHY_LP=y
|
CONFIG_B43_PHY_LP=y
|
||||||
# CONFIG_B43_FORCE_PIO is not set
|
# CONFIG_B43_FORCE_PIO is not set
|
||||||
CONFIG_B43LEGACY=m
|
CONFIG_B43LEGACY=m
|
||||||
CONFIG_B43LEGACY_DEBUG=y
|
# CONFIG_B43LEGACY_DEBUG is not set
|
||||||
CONFIG_B43LEGACY_DMA=y
|
CONFIG_B43LEGACY_DMA=y
|
||||||
CONFIG_B43LEGACY_PIO=y
|
CONFIG_B43LEGACY_PIO=y
|
||||||
CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y
|
CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y
|
||||||
|
@ -2193,7 +2193,7 @@ CONFIG_WDTPCI=m
|
||||||
# CONFIG_ACQUIRE_WDT is not set
|
# CONFIG_ACQUIRE_WDT is not set
|
||||||
# CONFIG_ADVANTECH_WDT is not set
|
# CONFIG_ADVANTECH_WDT is not set
|
||||||
# CONFIG_EUROTECH_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_MIXCOMWD is not set
|
||||||
# CONFIG_SCx200_WDT is not set
|
# CONFIG_SCx200_WDT is not set
|
||||||
# CONFIG_60XX_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_BACKLIGHT=y
|
||||||
CONFIG_DRM_NOUVEAU_DEBUG=y
|
CONFIG_DRM_NOUVEAU_DEBUG=y
|
||||||
CONFIG_DRM_I2C_CH7006=m
|
CONFIG_DRM_I2C_CH7006=m
|
||||||
|
CONFIG_DRM_I2C_SIL164=m
|
||||||
CONFIG_DRM_VMWGFX=m
|
CONFIG_DRM_VMWGFX=m
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -2366,6 +2367,7 @@ CONFIG_VIDEO_EM28XX_DVB=m
|
||||||
CONFIG_VIDEO_CX231XX=m
|
CONFIG_VIDEO_CX231XX=m
|
||||||
CONFIG_VIDEO_CX231XX_ALSA=m
|
CONFIG_VIDEO_CX231XX_ALSA=m
|
||||||
CONFIG_VIDEO_CX231XX_DVB=m
|
CONFIG_VIDEO_CX231XX_DVB=m
|
||||||
|
CONFIG_VIDEO_CX231XX_RC=y
|
||||||
CONFIG_VIDEO_HEXIUM_ORION=m
|
CONFIG_VIDEO_HEXIUM_ORION=m
|
||||||
CONFIG_VIDEO_HEXIUM_GEMINI=m
|
CONFIG_VIDEO_HEXIUM_GEMINI=m
|
||||||
CONFIG_VIDEO_IVTV=m
|
CONFIG_VIDEO_IVTV=m
|
||||||
|
@ -2380,6 +2382,7 @@ CONFIG_VIDEO_SAA6588=m
|
||||||
CONFIG_VIDEO_SAA7134=m
|
CONFIG_VIDEO_SAA7134=m
|
||||||
CONFIG_VIDEO_SAA7134_ALSA=m
|
CONFIG_VIDEO_SAA7134_ALSA=m
|
||||||
CONFIG_VIDEO_SAA7134_DVB=m
|
CONFIG_VIDEO_SAA7134_DVB=m
|
||||||
|
CONFIG_VIDEO_SAA7134_RC=y
|
||||||
CONFIG_VIDEO_STRADIS=m
|
CONFIG_VIDEO_STRADIS=m
|
||||||
CONFIG_VIDEO_USBVISION=m
|
CONFIG_VIDEO_USBVISION=m
|
||||||
CONFIG_VIDEO_W9966=m
|
CONFIG_VIDEO_W9966=m
|
||||||
|
@ -2394,6 +2397,10 @@ CONFIG_VIDEO_ZORAN_ZR36060=m
|
||||||
CONFIG_VIDEO_FB_IVTV=m
|
CONFIG_VIDEO_FB_IVTV=m
|
||||||
CONFIG_VIDEO_SAA7164=m
|
CONFIG_VIDEO_SAA7164=m
|
||||||
CONFIG_VIDEO_TLG2300=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_USB_VIDEO_CLASS=m
|
CONFIG_USB_VIDEO_CLASS=m
|
||||||
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
|
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
|
||||||
|
@ -2409,6 +2416,7 @@ CONFIG_MEDIA_ATTACH=y
|
||||||
CONFIG_MEDIA_TUNER_CUSTOMISE=y
|
CONFIG_MEDIA_TUNER_CUSTOMISE=y
|
||||||
CONFIG_MEDIA_TUNER_SIMPLE=m
|
CONFIG_MEDIA_TUNER_SIMPLE=m
|
||||||
CONFIG_MEDIA_TUNER_TDA8290=m
|
CONFIG_MEDIA_TUNER_TDA8290=m
|
||||||
|
CONFIG_MEDIA_TUNER_TDA18218=m
|
||||||
CONFIG_MEDIA_TUNER_TEA5761=m
|
CONFIG_MEDIA_TUNER_TEA5761=m
|
||||||
CONFIG_MEDIA_TUNER_TEA5767=m
|
CONFIG_MEDIA_TUNER_TEA5767=m
|
||||||
CONFIG_MEDIA_TUNER_MT20XX=m
|
CONFIG_MEDIA_TUNER_MT20XX=m
|
||||||
|
@ -2491,6 +2499,10 @@ CONFIG_DVB_ATBM8830=m
|
||||||
CONFIG_DVB_TDA665x=m
|
CONFIG_DVB_TDA665x=m
|
||||||
CONFIG_DVB_STV0299=m
|
CONFIG_DVB_STV0299=m
|
||||||
CONFIG_DVB_MB86A16=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
|
# Supported Frontend Modules
|
||||||
|
@ -2581,14 +2593,21 @@ CONFIG_VIDEO_PVRUSB2_SYSFS=y
|
||||||
# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
|
# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
|
||||||
|
|
||||||
CONFIG_RC_MAP=m
|
CONFIG_RC_MAP=m
|
||||||
|
CONFIG_RC_CORE=m
|
||||||
CONFIG_IR_NEC_DECODER=m
|
CONFIG_IR_NEC_DECODER=m
|
||||||
CONFIG_IR_RC5_DECODER=m
|
CONFIG_IR_RC5_DECODER=m
|
||||||
CONFIG_IR_RC6_DECODER=m
|
CONFIG_IR_RC6_DECODER=m
|
||||||
CONFIG_IR_JVC_DECODER=m
|
CONFIG_IR_JVC_DECODER=m
|
||||||
CONFIG_IR_SONY_DECODER=m
|
CONFIG_IR_SONY_DECODER=m
|
||||||
|
CONFIG_IR_RC5_SZ_DECODER=m
|
||||||
CONFIG_IR_LIRC_CODEC=m
|
CONFIG_IR_LIRC_CODEC=m
|
||||||
|
CONFIG_IR_ENE=m
|
||||||
CONFIG_IR_IMON=m
|
CONFIG_IR_IMON=m
|
||||||
CONFIG_IR_MCEUSB=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_V4L_MEM2MEM_DRIVERS=y
|
||||||
# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set
|
# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set
|
||||||
|
@ -3031,6 +3050,8 @@ CONFIG_USB_GL860=m
|
||||||
CONFIG_USB_GSPCA_JEILINJ=m
|
CONFIG_USB_GSPCA_JEILINJ=m
|
||||||
CONFIG_USB_GSPCA_SPCA1528=m
|
CONFIG_USB_GSPCA_SPCA1528=m
|
||||||
CONFIG_USB_GSPCA_SQ930X=m
|
CONFIG_USB_GSPCA_SQ930X=m
|
||||||
|
CONFIG_USB_GSPCA_KONICA=m
|
||||||
|
CONFIG_USB_GSPCA_XIRLINK_CIT=m
|
||||||
|
|
||||||
CONFIG_USB_IBMCAM=m
|
CONFIG_USB_IBMCAM=m
|
||||||
CONFIG_USB_KONICAWC=m
|
CONFIG_USB_KONICAWC=m
|
||||||
|
@ -3038,6 +3059,7 @@ CONFIG_USB_KONICAWC=m
|
||||||
CONFIG_USB_S2255=m
|
CONFIG_USB_S2255=m
|
||||||
CONFIG_USB_SE401=m
|
CONFIG_USB_SE401=m
|
||||||
# CONFIG_VIDEO_SH_MOBILE_CEU is not set
|
# CONFIG_VIDEO_SH_MOBILE_CEU is not set
|
||||||
|
# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set
|
||||||
# CONFIG_USB_STV680 is not set
|
# CONFIG_USB_STV680 is not set
|
||||||
# CONFIG_USB_SN9C102 is not set
|
# CONFIG_USB_SN9C102 is not set
|
||||||
CONFIG_USB_ZR364XX=m
|
CONFIG_USB_ZR364XX=m
|
||||||
|
@ -3052,6 +3074,8 @@ CONFIG_SOC_CAMERA_OV772X=m
|
||||||
CONFIG_SOC_CAMERA_MT9T112=m
|
CONFIG_SOC_CAMERA_MT9T112=m
|
||||||
CONFIG_SOC_CAMERA_RJ54N1=m
|
CONFIG_SOC_CAMERA_RJ54N1=m
|
||||||
CONFIG_SOC_CAMERA_OV9640=m
|
CONFIG_SOC_CAMERA_OV9640=m
|
||||||
|
CONFIG_SOC_CAMERA_IMX074=m
|
||||||
|
CONFIG_SOC_CAMERA_OV6650=m
|
||||||
|
|
||||||
#
|
#
|
||||||
# USB Network adaptors
|
# USB Network adaptors
|
||||||
|
@ -3321,7 +3345,8 @@ CONFIG_QUOTACTL=y
|
||||||
CONFIG_DNOTIFY=y
|
CONFIG_DNOTIFY=y
|
||||||
# Autofsv3 is obsolete.
|
# Autofsv3 is obsolete.
|
||||||
# CONFIG_AUTOFS_FS is not set
|
# 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_FS=m
|
||||||
# CONFIG_EXOFS_DEBUG is not set
|
# CONFIG_EXOFS_DEBUG is not set
|
||||||
CONFIG_NILFS2_FS=m
|
CONFIG_NILFS2_FS=m
|
||||||
|
@ -3601,6 +3626,7 @@ CONFIG_CRYPTO_FIPS=y
|
||||||
CONFIG_CRYPTO_HW=y
|
CONFIG_CRYPTO_HW=y
|
||||||
CONFIG_CRYPTO_BLKCIPHER=y
|
CONFIG_CRYPTO_BLKCIPHER=y
|
||||||
CONFIG_CRYPTO_MANAGER=m
|
CONFIG_CRYPTO_MANAGER=m
|
||||||
|
CONFIG_CRYPTO_MANAGER_TESTS=y
|
||||||
# CONFIG_CRYPTO_CRYPTD is not set
|
# CONFIG_CRYPTO_CRYPTD is not set
|
||||||
CONFIG_CRYPTO_AES=m
|
CONFIG_CRYPTO_AES=m
|
||||||
CONFIG_CRYPTO_ARC4=m
|
CONFIG_CRYPTO_ARC4=m
|
||||||
|
@ -3722,7 +3748,7 @@ CONFIG_BLK_CGROUP=y
|
||||||
# CONFIG_SYSFS_DEPRECATED_V2 is not set
|
# CONFIG_SYSFS_DEPRECATED_V2 is not set
|
||||||
|
|
||||||
CONFIG_RELAY=y
|
CONFIG_RELAY=y
|
||||||
# CONFIG_PRINTK_TIME is not set
|
CONFIG_PRINTK_TIME=y
|
||||||
|
|
||||||
CONFIG_ENABLE_MUST_CHECK=y
|
CONFIG_ENABLE_MUST_CHECK=y
|
||||||
# CONFIG_ENABLE_WARN_DEPRECATED is not set
|
# CONFIG_ENABLE_WARN_DEPRECATED is not set
|
||||||
|
@ -3742,7 +3768,7 @@ CONFIG_IBMASR=m
|
||||||
CONFIG_PM_DEBUG=y
|
CONFIG_PM_DEBUG=y
|
||||||
CONFIG_PM_TRACE=y
|
CONFIG_PM_TRACE=y
|
||||||
# CONFIG_PM_VERBOSE is not set
|
# CONFIG_PM_VERBOSE is not set
|
||||||
CONFIG_PM_TEST_SUSPEND=y
|
# CONFIG_PM_TEST_SUSPEND is not set
|
||||||
CONFIG_PM_RUNTIME=y
|
CONFIG_PM_RUNTIME=y
|
||||||
|
|
||||||
## BEGIN ISA Junk.
|
## BEGIN ISA Junk.
|
||||||
|
@ -3987,8 +4013,8 @@ CONFIG_AUXDISPLAY=y
|
||||||
CONFIG_UIO=m
|
CONFIG_UIO=m
|
||||||
CONFIG_UIO_CIF=m
|
CONFIG_UIO_CIF=m
|
||||||
CONFIG_UIO_SMX=m
|
CONFIG_UIO_SMX=m
|
||||||
CONFIG_UIO_PDRV=m
|
# CONFIG_UIO_PDRV is not set
|
||||||
CONFIG_UIO_PDRV_GENIRQ=m
|
# CONFIG_UIO_PDRV_GENIRQ is not set
|
||||||
CONFIG_UIO_AEC=m
|
CONFIG_UIO_AEC=m
|
||||||
CONFIG_UIO_SERCOS3=m
|
CONFIG_UIO_SERCOS3=m
|
||||||
CONFIG_UIO_PCI_GENERIC=m
|
CONFIG_UIO_PCI_GENERIC=m
|
||||||
|
@ -4013,7 +4039,7 @@ CONFIG_LIRC_SERIAL=m
|
||||||
CONFIG_LIRC_SERIAL_TRANSMITTER=y
|
CONFIG_LIRC_SERIAL_TRANSMITTER=y
|
||||||
CONFIG_LIRC_SASEM=m
|
CONFIG_LIRC_SASEM=m
|
||||||
CONFIG_LIRC_SIR=m
|
CONFIG_LIRC_SIR=m
|
||||||
CONFIG_LIRC_STREAMZAP=m
|
# CONFIG_LIRC_STREAMZAP is not set
|
||||||
CONFIG_LIRC_TTUSBIR=m
|
CONFIG_LIRC_TTUSBIR=m
|
||||||
|
|
||||||
# CONFIG_SAMPLES is not set
|
# CONFIG_SAMPLES is not set
|
||||||
|
@ -4175,7 +4201,7 @@ CONFIG_USB_ATMEL=m
|
||||||
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
|
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
|
||||||
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
|
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
|
||||||
# CONFIG_FUNCTION_GRAPH_TRACER 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_EARLY_PRINTK_DBGP=y
|
||||||
|
|
||||||
CONFIG_SECURITYFS=y
|
CONFIG_SECURITYFS=y
|
||||||
|
@ -4253,7 +4279,7 @@ CONFIG_DEBUG_NX_TEST=m
|
||||||
CONFIG_DEBUG_BOOT_PARAMS=y
|
CONFIG_DEBUG_BOOT_PARAMS=y
|
||||||
CONFIG_DETECT_SOFTLOCKUP=y
|
CONFIG_DETECT_SOFTLOCKUP=y
|
||||||
# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
|
# 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_BOOTPARAM_HUNG_TASK_PANIC is not set
|
||||||
CONFIG_ATOMIC64_SELFTEST=y
|
CONFIG_ATOMIC64_SELFTEST=y
|
||||||
|
|
||||||
|
@ -4269,7 +4295,7 @@ CONFIG_BLK_DEV_DRBD=m
|
||||||
# CONFIG_DEBUG_GPIO is not set
|
# CONFIG_DEBUG_GPIO is not set
|
||||||
# CONFIG_W1_MASTER_GPIO is not set
|
# CONFIG_W1_MASTER_GPIO is not set
|
||||||
# CONFIG_LEDS_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_MAX732X is not set
|
||||||
# CONFIG_GPIO_PCA953X is not set
|
# CONFIG_GPIO_PCA953X is not set
|
||||||
# CONFIG_GPIO_PCF857X is not set
|
# CONFIG_GPIO_PCF857X is not set
|
||||||
|
|
|
@ -3,3 +3,6 @@ CONFIG_HIGHMEM64G=y
|
||||||
|
|
||||||
CONFIG_XEN_DEV_EVTCHN=m
|
CONFIG_XEN_DEV_EVTCHN=m
|
||||||
CONFIG_XEN_SYS_HYPERVISOR=y
|
CONFIG_XEN_SYS_HYPERVISOR=y
|
||||||
|
|
||||||
|
# I2O only works on non-PAE 32-bit x86
|
||||||
|
# CONFIG_I2O is not set
|
||||||
|
|
|
@ -2,90 +2,92 @@ CONFIG_SND_VERBOSE_PRINTK=y
|
||||||
CONFIG_SND_DEBUG=y
|
CONFIG_SND_DEBUG=y
|
||||||
CONFIG_SND_PCM_XRUN_DEBUG=y
|
CONFIG_SND_PCM_XRUN_DEBUG=y
|
||||||
|
|
||||||
CONFIG_DEBUG_MUTEXES=y
|
# CONFIG_DEBUG_MUTEXES is not set
|
||||||
CONFIG_DEBUG_RT_MUTEXES=y
|
# CONFIG_DEBUG_RT_MUTEXES is not set
|
||||||
CONFIG_DEBUG_LOCK_ALLOC=y
|
# CONFIG_DEBUG_LOCK_ALLOC is not set
|
||||||
CONFIG_PROVE_LOCKING=y
|
# CONFIG_PROVE_LOCKING is not set
|
||||||
CONFIG_DEBUG_VM=y
|
# CONFIG_DEBUG_VM is not set
|
||||||
CONFIG_DEBUG_SPINLOCK=y
|
# CONFIG_DEBUG_SPINLOCK is not set
|
||||||
CONFIG_PROVE_RCU=y
|
# CONFIG_PROVE_RCU is not set
|
||||||
# CONFIG_PROVE_RCU_REPEATEDLY 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_CPUMASK_OFFSTACK=y
|
||||||
|
|
||||||
CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
|
# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
|
||||||
|
|
||||||
CONFIG_FAULT_INJECTION=y
|
# CONFIG_FAULT_INJECTION is not set
|
||||||
CONFIG_FAILSLAB=y
|
# CONFIG_FAILSLAB is not set
|
||||||
CONFIG_FAIL_PAGE_ALLOC=y
|
# CONFIG_FAIL_PAGE_ALLOC is not set
|
||||||
CONFIG_FAIL_MAKE_REQUEST=y
|
# CONFIG_FAIL_MAKE_REQUEST is not set
|
||||||
CONFIG_FAULT_INJECTION_DEBUG_FS=y
|
# CONFIG_FAULT_INJECTION_DEBUG_FS is not set
|
||||||
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
|
# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set
|
||||||
CONFIG_FAIL_IO_TIMEOUT=y
|
# 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_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_PAGEALLOC is not set
|
||||||
|
|
||||||
CONFIG_DEBUG_WRITECOUNT=y
|
# CONFIG_DEBUG_WRITECOUNT is not set
|
||||||
CONFIG_DEBUG_OBJECTS=y
|
# CONFIG_DEBUG_OBJECTS is not set
|
||||||
# CONFIG_DEBUG_OBJECTS_SELFTEST is not set
|
# CONFIG_DEBUG_OBJECTS_SELFTEST is not set
|
||||||
CONFIG_DEBUG_OBJECTS_FREE=y
|
# CONFIG_DEBUG_OBJECTS_FREE is not set
|
||||||
CONFIG_DEBUG_OBJECTS_TIMERS=y
|
# CONFIG_DEBUG_OBJECTS_TIMERS is not set
|
||||||
CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
|
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,
|
# off in both production debug and nodebug builds,
|
||||||
# on in rawhide 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_ATH_DEBUG is not set
|
||||||
CONFIG_IWLWIFI_DEVICE_TRACING=y
|
# CONFIG_IWLWIFI_DEVICE_TRACING is not set
|
||||||
|
|
||||||
CONFIG_DEBUG_OBJECTS_WORK=y
|
# CONFIG_DEBUG_OBJECTS_WORK is not set
|
||||||
CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
|
# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
|
||||||
|
|
||||||
CONFIG_DMADEVICES_DEBUG=y
|
# CONFIG_DMADEVICES_DEBUG is not set
|
||||||
CONFIG_DMADEVICES_VDEBUG=y
|
# CONFIG_DMADEVICES_VDEBUG is not set
|
||||||
|
|
||||||
CONFIG_PM_ADVANCED_DEBUG=y
|
CONFIG_PM_ADVANCED_DEBUG=y
|
||||||
|
|
||||||
CONFIG_CEPH_FS_PRETTYDEBUG=y
|
# CONFIG_CEPH_FS_PRETTYDEBUG is not set
|
||||||
CONFIG_QUOTA_DEBUG=y
|
# CONFIG_QUOTA_DEBUG is not set
|
||||||
|
|
||||||
|
# CONFIG_PCI_DEFAULT_USE_CRS is not set
|
||||||
|
|
||||||
CONFIG_KGDB_KDB=y
|
CONFIG_KGDB_KDB=y
|
||||||
CONFIG_KDB_KEYBOARD=y
|
CONFIG_KDB_KEYBOARD=y
|
||||||
|
|
|
@ -200,4 +200,9 @@ CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m
|
||||||
CONFIG_GRETH=m
|
CONFIG_GRETH=m
|
||||||
CONFIG_FB_XVR1000=y
|
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_MCYRIXIII is not set
|
||||||
# CONFIG_MVIAC3_2 is not set
|
# CONFIG_MVIAC3_2 is not set
|
||||||
CONFIG_SMP=y
|
CONFIG_SMP=y
|
||||||
CONFIG_NR_CPUS=32
|
CONFIG_NR_CPUS=64
|
||||||
CONFIG_X86_GENERIC=y
|
CONFIG_X86_GENERIC=y
|
||||||
# CONFIG_X86_PPRO_FENCE is not set
|
# CONFIG_X86_PPRO_FENCE is not set
|
||||||
CONFIG_HPET=y
|
CONFIG_HPET=y
|
||||||
|
@ -100,6 +100,16 @@ CONFIG_SECCOMP=y
|
||||||
|
|
||||||
CONFIG_CAPI_EICON=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
|
# APM (Advanced Power Management) BIOS Support
|
||||||
#
|
#
|
||||||
|
@ -479,6 +489,6 @@ CONFIG_TOSHIBA_BT_RFKILL=m
|
||||||
CONFIG_VGA_SWITCHEROO=y
|
CONFIG_VGA_SWITCHEROO=y
|
||||||
CONFIG_LPC_SCH=m
|
CONFIG_LPC_SCH=m
|
||||||
|
|
||||||
CONFIG_INTEL_IDLE=m
|
CONFIG_INTEL_IDLE=y
|
||||||
|
|
||||||
CONFIG_PCI_CNB20LE_QUIRK=y
|
CONFIG_PCI_CNB20LE_QUIRK=y
|
||||||
|
|
|
@ -15,7 +15,7 @@ CONFIG_NUMA=y
|
||||||
CONFIG_K8_NUMA=y
|
CONFIG_K8_NUMA=y
|
||||||
CONFIG_X86_64_ACPI_NUMA=y
|
CONFIG_X86_64_ACPI_NUMA=y
|
||||||
# CONFIG_NUMA_EMU is not set
|
# CONFIG_NUMA_EMU is not set
|
||||||
CONFIG_NR_CPUS=512
|
CONFIG_NR_CPUS=256
|
||||||
CONFIG_X86_POWERNOW_K8=m
|
CONFIG_X86_POWERNOW_K8=m
|
||||||
CONFIG_X86_P4_CLOCKMOD=m
|
CONFIG_X86_P4_CLOCKMOD=m
|
||||||
CONFIG_IA32_EMULATION=y
|
CONFIG_IA32_EMULATION=y
|
||||||
|
@ -403,7 +403,9 @@ CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m
|
||||||
CONFIG_VGA_SWITCHEROO=y
|
CONFIG_VGA_SWITCHEROO=y
|
||||||
CONFIG_LPC_SCH=m
|
CONFIG_LPC_SCH=m
|
||||||
|
|
||||||
CONFIG_INTEL_IDLE=m
|
CONFIG_INTEL_IDLE=y
|
||||||
CONFIG_I7300_IDLE=m
|
CONFIG_I7300_IDLE=m
|
||||||
|
|
||||||
CONFIG_PCI_CNB20LE_QUIRK=y
|
CONFIG_PCI_CNB20LE_QUIRK=y
|
||||||
|
|
||||||
|
CONFIG_HP_ILO=m
|
||||||
|
|
|
@ -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,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,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,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,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,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,84 @@
|
||||||
|
commit 22d3243de86bc92d874abb7c5b185d5c47aba323
|
||||||
|
Author: Jim Bos <jim876@xs4all.nl>
|
||||||
|
Date: Mon Nov 15 21:22:37 2010 +0100
|
||||||
|
|
||||||
|
Fix gcc 4.5.1 miscompiling drivers/char/i8k.c (again)
|
||||||
|
|
||||||
|
The fix in commit 6b4e81db2552 ("i8k: Tell gcc that *regs gets
|
||||||
|
clobbered") to work around the gcc miscompiling i8k.c to add "+m
|
||||||
|
(*regs)" caused register pressure problems and a build failure.
|
||||||
|
|
||||||
|
Changing the 'asm' statement to 'asm volatile' instead should prevent
|
||||||
|
that and works around the gcc bug as well, so we can remove the "+m".
|
||||||
|
|
||||||
|
[ Background on the gcc bug: a memory clobber fails to mark the function
|
||||||
|
the asm resides in as non-pure (aka "__attribute__((const))"), so if
|
||||||
|
the function does nothing else that triggers the non-pure logic, gcc
|
||||||
|
will think that that function has no side effects at all. As a result,
|
||||||
|
callers will be mis-compiled.
|
||||||
|
|
||||||
|
Adding the "+m" made gcc see that it's not a pure function, and so
|
||||||
|
does "asm volatile". The problem was never really the need to mark
|
||||||
|
"*regs" as changed, since the memory clobber did that part - the
|
||||||
|
problem was just a bug in the gcc "pure" function analysis - Linus ]
|
||||||
|
|
||||||
|
Signed-off-by: Jim Bos <jim876@xs4all.nl>
|
||||||
|
Acked-by: Jakub Jelinek <jakub@redhat.com>
|
||||||
|
Cc: Andi Kleen <andi@firstfloor.org>
|
||||||
|
Cc: Andreas Schwab <schwab@linux-m68k.org>
|
||||||
|
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||||
|
|
||||||
|
commit 6b4e81db2552bad04100e7d5ddeed7e848f53b48
|
||||||
|
Author: Jim Bos <jim876@xs4all.nl>
|
||||||
|
Date: Sat Nov 13 12:13:53 2010 +0100
|
||||||
|
|
||||||
|
i8k: Tell gcc that *regs gets clobbered
|
||||||
|
|
||||||
|
More recent GCC caused the i8k driver to stop working, on Slackware
|
||||||
|
compiler was upgraded from gcc-4.4.4 to gcc-4.5.1 after which it didn't
|
||||||
|
work anymore, meaning the driver didn't load or gave total nonsensical
|
||||||
|
output.
|
||||||
|
|
||||||
|
As it turned out the asm(..) statement forgot to mention it modifies the
|
||||||
|
*regs variable.
|
||||||
|
|
||||||
|
Credits to Andi Kleen and Andreas Schwab for providing the fix.
|
||||||
|
|
||||||
|
Signed-off-by: Jim Bos <jim876@xs4all.nl>
|
||||||
|
Cc: Andi Kleen <andi@firstfloor.org>
|
||||||
|
Cc: Andreas Schwab <schwab@linux-m68k.org>
|
||||||
|
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||||
|
|
||||||
|
---
|
||||||
|
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
|
||||||
|
index 3bc0eef..d72433f 100644
|
||||||
|
--- a/drivers/char/i8k.c
|
||||||
|
+++ b/drivers/char/i8k.c
|
||||||
|
@@ -120,7 +120,7 @@ static int i8k_smm(struct smm_regs *regs)
|
||||||
|
int eax = regs->eax;
|
||||||
|
|
||||||
|
#if defined(CONFIG_X86_64)
|
||||||
|
- asm("pushq %%rax\n\t"
|
||||||
|
+ asm volatile("pushq %%rax\n\t"
|
||||||
|
"movl 0(%%rax),%%edx\n\t"
|
||||||
|
"pushq %%rdx\n\t"
|
||||||
|
"movl 4(%%rax),%%ebx\n\t"
|
||||||
|
@@ -146,7 +146,7 @@ static int i8k_smm(struct smm_regs *regs)
|
||||||
|
: "a"(regs)
|
||||||
|
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
|
||||||
|
#else
|
||||||
|
- asm("pushl %%eax\n\t"
|
||||||
|
+ asm volatile("pushl %%eax\n\t"
|
||||||
|
"movl 0(%%eax),%%edx\n\t"
|
||||||
|
"push %%edx\n\t"
|
||||||
|
"movl 4(%%eax),%%ebx\n\t"
|
||||||
|
@@ -167,7 +167,8 @@ static int i8k_smm(struct smm_regs *regs)
|
||||||
|
"movl %%edx,0(%%eax)\n\t"
|
||||||
|
"lahf\n\t"
|
||||||
|
"shrl $8,%%eax\n\t"
|
||||||
|
- "andl $1,%%eax\n":"=a"(rc)
|
||||||
|
+ "andl $1,%%eax\n"
|
||||||
|
+ :"=a"(rc)
|
||||||
|
: "a"(regs)
|
||||||
|
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
|
||||||
|
#endif
|
|
@ -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,30 @@
|
||||||
|
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
|
||||||
|
index 227c020..7465308 100644
|
||||||
|
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
|
||||||
|
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
|
||||||
|
@@ -39,6 +39,7 @@ MODULE_PARM_DESC(debug,
|
||||||
|
|
||||||
|
#define DRIVER_VERSION "0.1"
|
||||||
|
#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
|
||||||
|
+#define FLEXCOP_MODULE_NAME "b2c2-flexcop"
|
||||||
|
#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
|
||||||
|
|
||||||
|
struct flexcop_pci {
|
||||||
|
@@ -299,7 +300,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
|
||||||
|
return ret;
|
||||||
|
pci_set_master(fc_pci->pdev);
|
||||||
|
|
||||||
|
- if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0)
|
||||||
|
+ if ((ret = pci_request_regions(fc_pci->pdev, FLEXCOP_MODULE_NAME)) != 0)
|
||||||
|
goto err_pci_disable_device;
|
||||||
|
|
||||||
|
fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800);
|
||||||
|
@@ -313,7 +314,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
|
||||||
|
pci_set_drvdata(fc_pci->pdev, fc_pci);
|
||||||
|
spin_lock_init(&fc_pci->irq_lock);
|
||||||
|
if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
|
||||||
|
- IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
|
||||||
|
+ IRQF_SHARED, FLEXCOP_MODULE_NAME, fc_pci)) != 0)
|
||||||
|
goto err_pci_iounmap;
|
||||||
|
|
||||||
|
fc_pci->init_state |= FC_PCI_INIT;
|
|
@ -0,0 +1,65 @@
|
||||||
|
From linux-fsdevel-owner@vger.kernel.org Thu Nov 18 21:03:11 2010
|
||||||
|
From: Josef Bacik <josef@redhat.com>
|
||||||
|
To: linux-fsdevel@vger.kernel.org, eparis@redhat.com,
|
||||||
|
linux-kernel@vger.kernel.org, sds@tycho.nsa.gov,
|
||||||
|
selinux@tycho.nsa.gov, bfields@fieldses.org
|
||||||
|
Subject: [PATCH] fs: call security_d_instantiate in d_obtain_alias V2
|
||||||
|
Date: Thu, 18 Nov 2010 20:52:55 -0500
|
||||||
|
Message-Id: <1290131575-2489-1-git-send-email-josef@redhat.com>
|
||||||
|
X-Mailing-List: linux-fsdevel@vger.kernel.org
|
||||||
|
|
||||||
|
While trying to track down some NFS problems with BTRFS, I kept noticing I was
|
||||||
|
getting -EACCESS for no apparent reason. Eric Paris and printk() helped me
|
||||||
|
figure out that it was SELinux that was giving me grief, with the following
|
||||||
|
denial
|
||||||
|
|
||||||
|
type=AVC msg=audit(1290013638.413:95): avc: denied { 0x800000 } for pid=1772
|
||||||
|
comm="nfsd" name="" dev=sda1 ino=256 scontext=system_u:system_r:kernel_t:s0
|
||||||
|
tcontext=system_u:object_r:unlabeled_t:s0 tclass=file
|
||||||
|
|
||||||
|
Turns out this is because in d_obtain_alias if we can't find an alias we create
|
||||||
|
one and do all the normal instantiation stuff, but we don't do the
|
||||||
|
security_d_instantiate.
|
||||||
|
|
||||||
|
Usually we are protected from getting a hashed dentry that hasn't yet run
|
||||||
|
security_d_instantiate() by the parent's i_mutex, but obviously this isn't an
|
||||||
|
option there, so in order to deal with the case that a second thread comes in
|
||||||
|
and finds our new dentry before we get to run security_d_instantiate(), we go
|
||||||
|
ahead and call it if we find a dentry already. Eric assures me that this is ok
|
||||||
|
as the code checks to see if the dentry has been initialized already so calling
|
||||||
|
security_d_instantiate() against the same dentry multiple times is ok. With
|
||||||
|
this patch I'm no longer getting errant -EACCESS values.
|
||||||
|
|
||||||
|
Signed-off-by: Josef Bacik <josef@redhat.com>
|
||||||
|
---
|
||||||
|
V1->V2:
|
||||||
|
-added second security_d_instantiate() call
|
||||||
|
|
||||||
|
fs/dcache.c | 3 +++
|
||||||
|
1 files changed, 3 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/fs/dcache.c b/fs/dcache.c
|
||||||
|
index 23702a9..119d489 100644
|
||||||
|
--- a/fs/dcache.c
|
||||||
|
+++ b/fs/dcache.c
|
||||||
|
@@ -1201,9 +1201,12 @@ struct dentry *d_obtain_alias(struct inode *inode)
|
||||||
|
spin_unlock(&tmp->d_lock);
|
||||||
|
|
||||||
|
spin_unlock(&dcache_lock);
|
||||||
|
+ security_d_instantiate(tmp, inode);
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
out_iput:
|
||||||
|
+ if (res && !IS_ERR(res))
|
||||||
|
+ security_d_instantiate(res, inode);
|
||||||
|
iput(inode);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
--
|
||||||
|
1.6.6.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,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,105 @@
|
||||||
|
From 56e0d4414e5eeacd9eaf68ce93dcb80f9c62bfb4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Nelson Elhage <nelhage@ksplice.com>
|
||||||
|
Date: Wed, 3 Nov 2010 16:35:41 +0000
|
||||||
|
Subject: inet_diag: Make sure we actually run the same bytecode we audited.
|
||||||
|
|
||||||
|
We were using nlmsg_find_attr() to look up the bytecode by attribute when
|
||||||
|
auditing, but then just using the first attribute when actually running
|
||||||
|
bytecode. So, if we received a message with two attribute elements, where only
|
||||||
|
the second had type INET_DIAG_REQ_BYTECODE, we would validate and run different
|
||||||
|
bytecode strings.
|
||||||
|
|
||||||
|
Fix this by consistently using nlmsg_find_attr everywhere.
|
||||||
|
|
||||||
|
Signed-off-by: Nelson Elhage <nelhage@ksplice.com>
|
||||||
|
Signed-off-by: Thomas Graf <tgraf@infradead.org>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
net/ipv4/inet_diag.c | 27 ++++++++++++++++-----------
|
||||||
|
1 files changed, 16 insertions(+), 11 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
|
||||||
|
index e5fa2dd..7403b9b 100644
|
||||||
|
--- a/net/ipv4/inet_diag.c
|
||||||
|
+++ b/net/ipv4/inet_diag.c
|
||||||
|
@@ -490,9 +490,11 @@ static int inet_csk_diag_dump(struct sock *sk,
|
||||||
|
{
|
||||||
|
struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
|
||||||
|
|
||||||
|
- if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
|
||||||
|
+ if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
|
||||||
|
struct inet_diag_entry entry;
|
||||||
|
- struct rtattr *bc = (struct rtattr *)(r + 1);
|
||||||
|
+ const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
|
||||||
|
+ sizeof(*r),
|
||||||
|
+ INET_DIAG_REQ_BYTECODE);
|
||||||
|
struct inet_sock *inet = inet_sk(sk);
|
||||||
|
|
||||||
|
entry.family = sk->sk_family;
|
||||||
|
@@ -512,7 +514,7 @@ static int inet_csk_diag_dump(struct sock *sk,
|
||||||
|
entry.dport = ntohs(inet->inet_dport);
|
||||||
|
entry.userlocks = sk->sk_userlocks;
|
||||||
|
|
||||||
|
- if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
|
||||||
|
+ if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -527,9 +529,11 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
|
||||||
|
{
|
||||||
|
struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
|
||||||
|
|
||||||
|
- if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
|
||||||
|
+ if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
|
||||||
|
struct inet_diag_entry entry;
|
||||||
|
- struct rtattr *bc = (struct rtattr *)(r + 1);
|
||||||
|
+ const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
|
||||||
|
+ sizeof(*r),
|
||||||
|
+ INET_DIAG_REQ_BYTECODE);
|
||||||
|
|
||||||
|
entry.family = tw->tw_family;
|
||||||
|
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
|
||||||
|
@@ -548,7 +552,7 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
|
||||||
|
entry.dport = ntohs(tw->tw_dport);
|
||||||
|
entry.userlocks = 0;
|
||||||
|
|
||||||
|
- if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
|
||||||
|
+ if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -618,7 +622,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
|
||||||
|
struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
|
||||||
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||||
|
struct listen_sock *lopt;
|
||||||
|
- struct rtattr *bc = NULL;
|
||||||
|
+ const struct nlattr *bc = NULL;
|
||||||
|
struct inet_sock *inet = inet_sk(sk);
|
||||||
|
int j, s_j;
|
||||||
|
int reqnum, s_reqnum;
|
||||||
|
@@ -638,8 +642,9 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
|
||||||
|
if (!lopt || !lopt->qlen)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
- if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
|
||||||
|
- bc = (struct rtattr *)(r + 1);
|
||||||
|
+ if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
|
||||||
|
+ bc = nlmsg_find_attr(cb->nlh, sizeof(*r),
|
||||||
|
+ INET_DIAG_REQ_BYTECODE);
|
||||||
|
entry.sport = inet->inet_num;
|
||||||
|
entry.userlocks = sk->sk_userlocks;
|
||||||
|
}
|
||||||
|
@@ -672,8 +677,8 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
|
||||||
|
&ireq->rmt_addr;
|
||||||
|
entry.dport = ntohs(ireq->rmt_port);
|
||||||
|
|
||||||
|
- if (!inet_diag_bc_run(RTA_DATA(bc),
|
||||||
|
- RTA_PAYLOAD(bc), &entry))
|
||||||
|
+ if (!inet_diag_bc_run(nla_data(bc),
|
||||||
|
+ nla_len(bc), &entry))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
842
kernel.spec
842
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,161 @@
|
||||||
|
From: Avi Kivity <avi@redhat.com>
|
||||||
|
Date: Tue, 19 Oct 2010 14:46:55 +0000 (+0200)
|
||||||
|
Subject: KVM: Fix fs/gs reload oops with invalid ldt
|
||||||
|
X-Git-Tag: v2.6.36~4^2
|
||||||
|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9581d442b9058d3699b4be568b6e5eae38a41493
|
||||||
|
|
||||||
|
KVM: Fix fs/gs reload oops with invalid ldt
|
||||||
|
|
||||||
|
kvm reloads the host's fs and gs blindly, however the underlying segment
|
||||||
|
descriptors may be invalid due to the user modifying the ldt after loading
|
||||||
|
them.
|
||||||
|
|
||||||
|
Fix by using the safe accessors (loadsegment() and load_gs_index()) instead
|
||||||
|
of home grown unsafe versions.
|
||||||
|
|
||||||
|
This is CVE-2010-3698.
|
||||||
|
|
||||||
|
KVM-Stable-Tag.
|
||||||
|
Signed-off-by: Avi Kivity <avi@redhat.com>
|
||||||
|
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
|
||||||
|
index 502e53f..c52e2eb 100644
|
||||||
|
--- a/arch/x86/include/asm/kvm_host.h
|
||||||
|
+++ b/arch/x86/include/asm/kvm_host.h
|
||||||
|
@@ -652,20 +652,6 @@ static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
|
||||||
|
return (struct kvm_mmu_page *)page_private(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static inline u16 kvm_read_fs(void)
|
||||||
|
-{
|
||||||
|
- u16 seg;
|
||||||
|
- asm("mov %%fs, %0" : "=g"(seg));
|
||||||
|
- return seg;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static inline u16 kvm_read_gs(void)
|
||||||
|
-{
|
||||||
|
- u16 seg;
|
||||||
|
- asm("mov %%gs, %0" : "=g"(seg));
|
||||||
|
- return seg;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static inline u16 kvm_read_ldt(void)
|
||||||
|
{
|
||||||
|
u16 ldt;
|
||||||
|
@@ -673,16 +659,6 @@ static inline u16 kvm_read_ldt(void)
|
||||||
|
return ldt;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static inline void kvm_load_fs(u16 sel)
|
||||||
|
-{
|
||||||
|
- asm("mov %0, %%fs" : : "rm"(sel));
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static inline void kvm_load_gs(u16 sel)
|
||||||
|
-{
|
||||||
|
- asm("mov %0, %%gs" : : "rm"(sel));
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static inline void kvm_load_ldt(u16 sel)
|
||||||
|
{
|
||||||
|
asm("lldt %0" : : "rm"(sel));
|
||||||
|
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
|
||||||
|
index 81ed28c..8a3f9f6 100644
|
||||||
|
--- a/arch/x86/kvm/svm.c
|
||||||
|
+++ b/arch/x86/kvm/svm.c
|
||||||
|
@@ -3163,8 +3163,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
|
||||||
|
sync_lapic_to_cr8(vcpu);
|
||||||
|
|
||||||
|
save_host_msrs(vcpu);
|
||||||
|
- fs_selector = kvm_read_fs();
|
||||||
|
- gs_selector = kvm_read_gs();
|
||||||
|
+ savesegment(fs, fs_selector);
|
||||||
|
+ savesegment(gs, gs_selector);
|
||||||
|
ldt_selector = kvm_read_ldt();
|
||||||
|
svm->vmcb->save.cr2 = vcpu->arch.cr2;
|
||||||
|
/* required for live migration with NPT */
|
||||||
|
@@ -3251,10 +3251,15 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
|
||||||
|
vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
|
||||||
|
vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
|
||||||
|
|
||||||
|
- kvm_load_ldt(ldt_selector);
|
||||||
|
- kvm_load_fs(fs_selector);
|
||||||
|
- kvm_load_gs(gs_selector);
|
||||||
|
load_host_msrs(vcpu);
|
||||||
|
+ kvm_load_ldt(ldt_selector);
|
||||||
|
+ loadsegment(fs, fs_selector);
|
||||||
|
+#ifdef CONFIG_X86_64
|
||||||
|
+ load_gs_index(gs_selector);
|
||||||
|
+ wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
|
||||||
|
+#else
|
||||||
|
+ loadsegment(gs, gs_selector);
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
reload_tss(vcpu);
|
||||||
|
|
||||||
|
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
|
||||||
|
index 49b25ee..7bddfab 100644
|
||||||
|
--- a/arch/x86/kvm/vmx.c
|
||||||
|
+++ b/arch/x86/kvm/vmx.c
|
||||||
|
@@ -803,7 +803,7 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
|
||||||
|
*/
|
||||||
|
vmx->host_state.ldt_sel = kvm_read_ldt();
|
||||||
|
vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel;
|
||||||
|
- vmx->host_state.fs_sel = kvm_read_fs();
|
||||||
|
+ savesegment(fs, vmx->host_state.fs_sel);
|
||||||
|
if (!(vmx->host_state.fs_sel & 7)) {
|
||||||
|
vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel);
|
||||||
|
vmx->host_state.fs_reload_needed = 0;
|
||||||
|
@@ -811,7 +811,7 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
|
||||||
|
vmcs_write16(HOST_FS_SELECTOR, 0);
|
||||||
|
vmx->host_state.fs_reload_needed = 1;
|
||||||
|
}
|
||||||
|
- vmx->host_state.gs_sel = kvm_read_gs();
|
||||||
|
+ savesegment(gs, vmx->host_state.gs_sel);
|
||||||
|
if (!(vmx->host_state.gs_sel & 7))
|
||||||
|
vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel);
|
||||||
|
else {
|
||||||
|
@@ -841,25 +841,19 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
|
static void __vmx_load_host_state(struct vcpu_vmx *vmx)
|
||||||
|
{
|
||||||
|
- unsigned long flags;
|
||||||
|
-
|
||||||
|
if (!vmx->host_state.loaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
++vmx->vcpu.stat.host_state_reload;
|
||||||
|
vmx->host_state.loaded = 0;
|
||||||
|
if (vmx->host_state.gs_ldt_reload_needed) {
|
||||||
|
kvm_load_ldt(vmx->host_state.ldt_sel);
|
||||||
|
- /*
|
||||||
|
- * If we have to reload gs, we must take care to
|
||||||
|
- * preserve our gs base.
|
||||||
|
- */
|
||||||
|
- local_irq_save(flags);
|
||||||
|
- kvm_load_gs(vmx->host_state.gs_sel);
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
- wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
|
||||||
|
+ load_gs_index(vmx->host_state.gs_sel);
|
||||||
|
+ wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
|
||||||
|
+#else
|
||||||
|
+ loadsegment(gs, vmx->host_state.gs_sel);
|
||||||
|
#endif
|
||||||
|
- local_irq_restore(flags);
|
||||||
|
}
|
||||||
|
if (vmx->host_state.fs_reload_needed)
|
||||||
|
loadsegment(fs, vmx->host_state.fs_sel);
|
||||||
|
@@ -2589,8 +2583,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
|
||||||
|
vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */
|
||||||
|
vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */
|
||||||
|
vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */
|
||||||
|
- vmcs_write16(HOST_FS_SELECTOR, kvm_read_fs()); /* 22.2.4 */
|
||||||
|
- vmcs_write16(HOST_GS_SELECTOR, kvm_read_gs()); /* 22.2.4 */
|
||||||
|
+ vmcs_write16(HOST_FS_SELECTOR, 0); /* 22.2.4 */
|
||||||
|
+ vmcs_write16(HOST_GS_SELECTOR, 0); /* 22.2.4 */
|
||||||
|
vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
rdmsrl(MSR_FS_BASE, a);
|
|
@ -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,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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -538,15 +538,16 @@
|
||||||
static void unmap_region(struct mm_struct *mm,
|
static void unmap_region(struct mm_struct *mm,
|
||||||
struct vm_area_struct *vma, struct vm_area_struct *prev,
|
struct vm_area_struct *vma, struct vm_area_struct *prev,
|
||||||
unsigned long start, unsigned long end);
|
unsigned long start, unsigned long end);
|
||||||
@@ -388,6 +401,8 @@
|
@@ -388,6 +401,9 @@
|
||||||
__vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
||||||
struct vm_area_struct *prev, struct rb_node *rb_parent)
|
|
||||||
{
|
{
|
||||||
|
struct vm_area_struct *next;
|
||||||
|
|
||||||
+ if (vma->vm_flags & VM_EXEC)
|
+ if (vma->vm_flags & VM_EXEC)
|
||||||
+ arch_add_exec_range(mm, vma->vm_end);
|
+ arch_add_exec_range(mm, vma->vm_end);
|
||||||
|
+
|
||||||
|
vma->vm_prev = prev;
|
||||||
if (prev) {
|
if (prev) {
|
||||||
vma->vm_next = prev->vm_next;
|
next = prev->vm_next;
|
||||||
prev->vm_next = vma;
|
|
||||||
@@ -489,6 +504,8 @@
|
@@ -489,6 +504,8 @@
|
||||||
rb_erase(&vma->vm_rb, &mm->mm_rb);
|
rb_erase(&vma->vm_rb, &mm->mm_rb);
|
||||||
if (mm->mmap_cache == vma)
|
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,33 @@
|
||||||
nil
|
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);
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -1,142 +0,0 @@
|
||||||
drivers/media/IR/imon.c | 20 +-------------------
|
|
||||||
drivers/media/IR/mceusb.c | 15 +--------------
|
|
||||||
2 files changed, 2 insertions(+), 33 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c
|
|
||||||
index 65c125e..c185422 100644
|
|
||||||
--- a/drivers/media/IR/imon.c
|
|
||||||
+++ b/drivers/media/IR/imon.c
|
|
||||||
@@ -87,7 +87,6 @@ static ssize_t lcd_write(struct file *file, const char *buf,
|
|
||||||
struct imon_context {
|
|
||||||
struct device *dev;
|
|
||||||
struct ir_dev_props *props;
|
|
||||||
- struct ir_input_dev *ir;
|
|
||||||
/* Newer devices have two interfaces */
|
|
||||||
struct usb_device *usbdev_intf0;
|
|
||||||
struct usb_device *usbdev_intf1;
|
|
||||||
@@ -1656,7 +1655,6 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
|
|
||||||
{
|
|
||||||
struct input_dev *idev;
|
|
||||||
struct ir_dev_props *props;
|
|
||||||
- struct ir_input_dev *ir;
|
|
||||||
int ret, i;
|
|
||||||
|
|
||||||
idev = input_allocate_device();
|
|
||||||
@@ -1671,12 +1669,6 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
|
|
||||||
goto props_alloc_failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
- ir = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL);
|
|
||||||
- if (!ir) {
|
|
||||||
- dev_err(ictx->dev, "remote ir input dev allocation failed\n");
|
|
||||||
- goto ir_dev_alloc_failed;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
snprintf(ictx->name_idev, sizeof(ictx->name_idev),
|
|
||||||
"iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
|
|
||||||
idev->name = ictx->name_idev;
|
|
||||||
@@ -1706,14 +1698,9 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
|
|
||||||
props->change_protocol = imon_ir_change_protocol;
|
|
||||||
ictx->props = props;
|
|
||||||
|
|
||||||
- ictx->ir = ir;
|
|
||||||
- memcpy(&ir->dev, ictx->dev, sizeof(struct device));
|
|
||||||
-
|
|
||||||
usb_to_input_id(ictx->usbdev_intf0, &idev->id);
|
|
||||||
idev->dev.parent = ictx->dev;
|
|
||||||
|
|
||||||
- input_set_drvdata(idev, ir);
|
|
||||||
-
|
|
||||||
ret = ir_input_register(idev, RC_MAP_IMON_PAD, props, MOD_NAME);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(ictx->dev, "remote input dev register failed\n");
|
|
||||||
@@ -1723,8 +1710,6 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
|
|
||||||
return idev;
|
|
||||||
|
|
||||||
idev_register_failed:
|
|
||||||
- kfree(ir);
|
|
||||||
-ir_dev_alloc_failed:
|
|
||||||
kfree(props);
|
|
||||||
props_alloc_failed:
|
|
||||||
input_free_device(idev);
|
|
||||||
@@ -1944,7 +1929,6 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
|
|
||||||
|
|
||||||
urb_submit_failed:
|
|
||||||
ir_input_unregister(ictx->idev);
|
|
||||||
- input_free_device(ictx->idev);
|
|
||||||
idev_setup_failed:
|
|
||||||
find_endpoint_failed:
|
|
||||||
mutex_unlock(&ictx->lock);
|
|
||||||
@@ -2014,10 +1998,8 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
|
|
||||||
return ictx;
|
|
||||||
|
|
||||||
urb_submit_failed:
|
|
||||||
- if (ictx->touch) {
|
|
||||||
+ if (ictx->touch)
|
|
||||||
input_unregister_device(ictx->touch);
|
|
||||||
- input_free_device(ictx->touch);
|
|
||||||
- }
|
|
||||||
touch_setup_failed:
|
|
||||||
find_endpoint_failed:
|
|
||||||
mutex_unlock(&ictx->lock);
|
|
||||||
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c
|
|
||||||
index 78bf7f7..65b0738 100644
|
|
||||||
--- a/drivers/media/IR/mceusb.c
|
|
||||||
+++ b/drivers/media/IR/mceusb.c
|
|
||||||
@@ -228,7 +228,6 @@ static struct usb_device_id std_tx_mask_list[] = {
|
|
||||||
/* data structure for each usb transceiver */
|
|
||||||
struct mceusb_dev {
|
|
||||||
/* ir-core bits */
|
|
||||||
- struct ir_input_dev *irdev;
|
|
||||||
struct ir_dev_props *props;
|
|
||||||
struct ir_raw_event rawir;
|
|
||||||
|
|
||||||
@@ -739,7 +738,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
|
|
||||||
|
|
||||||
if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
|
|
||||||
ir->send_flags = SEND_FLAG_COMPLETE;
|
|
||||||
- dev_dbg(&ir->irdev->dev, "setup answer received %d bytes\n",
|
|
||||||
+ dev_dbg(ir->dev, "setup answer received %d bytes\n",
|
|
||||||
buf_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -861,7 +860,6 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
|
|
||||||
{
|
|
||||||
struct input_dev *idev;
|
|
||||||
struct ir_dev_props *props;
|
|
||||||
- struct ir_input_dev *irdev;
|
|
||||||
struct device *dev = ir->dev;
|
|
||||||
int ret = -ENODEV;
|
|
||||||
|
|
||||||
@@ -878,12 +876,6 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
|
|
||||||
goto props_alloc_failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
- irdev = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL);
|
|
||||||
- if (!irdev) {
|
|
||||||
- dev_err(dev, "remote ir input dev allocation failed\n");
|
|
||||||
- goto ir_dev_alloc_failed;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome "
|
|
||||||
"Infrared Remote Transceiver (%04x:%04x)",
|
|
||||||
le16_to_cpu(ir->usbdev->descriptor.idVendor),
|
|
||||||
@@ -902,9 +894,6 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
|
|
||||||
props->tx_ir = mceusb_tx_ir;
|
|
||||||
|
|
||||||
ir->props = props;
|
|
||||||
- ir->irdev = irdev;
|
|
||||||
-
|
|
||||||
- input_set_drvdata(idev, irdev);
|
|
||||||
|
|
||||||
ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME);
|
|
||||||
if (ret < 0) {
|
|
||||||
@@ -915,8 +904,6 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
|
|
||||||
return idev;
|
|
||||||
|
|
||||||
irdev_failed:
|
|
||||||
- kfree(irdev);
|
|
||||||
-ir_dev_alloc_failed:
|
|
||||||
kfree(props);
|
|
||||||
props_alloc_failed:
|
|
||||||
input_free_device(idev);
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,362 +0,0 @@
|
||||||
From: Martin Rubli <martin_rubli@logitech.com>
|
|
||||||
Date: Wed, 19 May 2010 22:51:56 +0000 (+0200)
|
|
||||||
Subject: uvcvideo: Add support for absolute pan/tilt controls
|
|
||||||
X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=d3c2f664ec76aff14c3841c99e84cd78d7227f79
|
|
||||||
|
|
||||||
uvcvideo: Add support for absolute pan/tilt controls
|
|
||||||
|
|
||||||
Signed-off-by: Martin Rubli <martin_rubli@logitech.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
|
|
||||||
index aa0720a..5ec2f4a 100644
|
|
||||||
--- a/drivers/media/video/uvc/uvc_ctrl.c
|
|
||||||
+++ b/drivers/media/video/uvc/uvc_ctrl.c
|
|
||||||
@@ -606,6 +606,26 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
|
|
||||||
.set = uvc_ctrl_set_zoom,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
+ .id = V4L2_CID_PAN_ABSOLUTE,
|
|
||||||
+ .name = "Pan (Absolute)",
|
|
||||||
+ .entity = UVC_GUID_UVC_CAMERA,
|
|
||||||
+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
|
|
||||||
+ .size = 32,
|
|
||||||
+ .offset = 0,
|
|
||||||
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ .id = V4L2_CID_TILT_ABSOLUTE,
|
|
||||||
+ .name = "Tilt (Absolute)",
|
|
||||||
+ .entity = UVC_GUID_UVC_CAMERA,
|
|
||||||
+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
|
|
||||||
+ .size = 32,
|
|
||||||
+ .offset = 32,
|
|
||||||
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
.id = V4L2_CID_PRIVACY,
|
|
||||||
.name = "Privacy",
|
|
||||||
.entity = UVC_GUID_UVC_CAMERA,
|
|
||||||
From: Hans de Goede <hdegoede@redhat.com>
|
|
||||||
Date: Wed, 19 May 2010 23:15:00 +0000 (+0200)
|
|
||||||
Subject: uvcvideo: Make button controls work properly
|
|
||||||
X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=2bd47ad4894bfaf1a97660b821cbc46439a614d6
|
|
||||||
|
|
||||||
uvcvideo: Make button controls work properly
|
|
||||||
|
|
||||||
According to the v4l2 spec, writing any value to a button control should
|
|
||||||
result in the action belonging to the button control being triggered.
|
|
||||||
UVC cams however want to see a 1 written, this patch fixes this by
|
|
||||||
overriding whatever value user space passed in with -1 (0xffffffff) when
|
|
||||||
the control is a button control.
|
|
||||||
|
|
||||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
|
|
||||||
index 5ec2f4a..8bb825d 100644
|
|
||||||
--- a/drivers/media/video/uvc/uvc_ctrl.c
|
|
||||||
+++ b/drivers/media/video/uvc/uvc_ctrl.c
|
|
||||||
@@ -698,6 +698,14 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
|
|
||||||
int offset = mapping->offset;
|
|
||||||
__u8 mask;
|
|
||||||
|
|
||||||
+ /* According to the v4l2 spec, writing any value to a button control
|
|
||||||
+ * should result in the action belonging to the button control being
|
|
||||||
+ * triggered. UVC devices however want to see a 1 written -> override
|
|
||||||
+ * value.
|
|
||||||
+ */
|
|
||||||
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON)
|
|
||||||
+ value = -1;
|
|
||||||
+
|
|
||||||
data += offset / 8;
|
|
||||||
offset &= 7;
|
|
||||||
|
|
||||||
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
||||||
Date: Thu, 18 Feb 2010 19:38:52 +0000 (+0100)
|
|
||||||
Subject: uvcvideo: Support menu controls in the control mapping API
|
|
||||||
X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=4930f2662e47d33e5baedac620da401a225bc3a8
|
|
||||||
|
|
||||||
uvcvideo: Support menu controls in the control mapping API
|
|
||||||
|
|
||||||
The UVCIOC_CTRL_MAP ioctl doesn't support menu entries for menu
|
|
||||||
controls. As the uvc_xu_control_mapping structure has no reserved
|
|
||||||
fields, this can't be fixed while keeping ABI compatibility.
|
|
||||||
|
|
||||||
Modify the UVCIOC_CTRL_MAP ioctl to add menu entries support, and define
|
|
||||||
UVCIOC_CTRL_MAP_OLD that supports the old ABI without any ability to add
|
|
||||||
menu controls.
|
|
||||||
|
|
||||||
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
|
|
||||||
index 8bb825d..c88d72e 100644
|
|
||||||
--- a/drivers/media/video/uvc/uvc_ctrl.c
|
|
||||||
+++ b/drivers/media/video/uvc/uvc_ctrl.c
|
|
||||||
@@ -1606,6 +1606,28 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+void uvc_ctrl_cleanup(void)
|
|
||||||
+{
|
|
||||||
+ struct uvc_control_info *info;
|
|
||||||
+ struct uvc_control_info *ni;
|
|
||||||
+ struct uvc_control_mapping *mapping;
|
|
||||||
+ struct uvc_control_mapping *nm;
|
|
||||||
+
|
|
||||||
+ list_for_each_entry_safe(info, ni, &uvc_driver.controls, list) {
|
|
||||||
+ if (!(info->flags & UVC_CONTROL_EXTENSION))
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ list_for_each_entry_safe(mapping, nm, &info->mappings, list) {
|
|
||||||
+ list_del(&mapping->list);
|
|
||||||
+ kfree(mapping->menu_info);
|
|
||||||
+ kfree(mapping);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ list_del(&info->list);
|
|
||||||
+ kfree(info);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void uvc_ctrl_init(void)
|
|
||||||
{
|
|
||||||
struct uvc_control_info *ctrl = uvc_ctrls;
|
|
||||||
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
|
|
||||||
index 838b56f..34818c1 100644
|
|
||||||
--- a/drivers/media/video/uvc/uvc_driver.c
|
|
||||||
+++ b/drivers/media/video/uvc/uvc_driver.c
|
|
||||||
@@ -2261,6 +2261,7 @@ static int __init uvc_init(void)
|
|
||||||
static void __exit uvc_cleanup(void)
|
|
||||||
{
|
|
||||||
usb_deregister(&uvc_driver.driver);
|
|
||||||
+ uvc_ctrl_cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(uvc_init);
|
|
||||||
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
|
|
||||||
index 7c9ab29..485a899 100644
|
|
||||||
--- a/drivers/media/video/uvc/uvc_v4l2.c
|
|
||||||
+++ b/drivers/media/video/uvc/uvc_v4l2.c
|
|
||||||
@@ -29,6 +29,71 @@
|
|
||||||
#include "uvcvideo.h"
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------
|
|
||||||
+ * UVC ioctls
|
|
||||||
+ */
|
|
||||||
+static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
|
|
||||||
+{
|
|
||||||
+ struct uvc_control_mapping *map;
|
|
||||||
+ unsigned int size;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ map = kzalloc(sizeof *map, GFP_KERNEL);
|
|
||||||
+ if (map == NULL)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+
|
|
||||||
+ map->id = xmap->id;
|
|
||||||
+ memcpy(map->name, xmap->name, sizeof map->name);
|
|
||||||
+ memcpy(map->entity, xmap->entity, sizeof map->entity);
|
|
||||||
+ map->selector = xmap->selector;
|
|
||||||
+ map->size = xmap->size;
|
|
||||||
+ map->offset = xmap->offset;
|
|
||||||
+ map->v4l2_type = xmap->v4l2_type;
|
|
||||||
+ map->data_type = xmap->data_type;
|
|
||||||
+
|
|
||||||
+ switch (xmap->v4l2_type) {
|
|
||||||
+ case V4L2_CTRL_TYPE_INTEGER:
|
|
||||||
+ case V4L2_CTRL_TYPE_BOOLEAN:
|
|
||||||
+ case V4L2_CTRL_TYPE_BUTTON:
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case V4L2_CTRL_TYPE_MENU:
|
|
||||||
+ if (old) {
|
|
||||||
+ ret = -EINVAL;
|
|
||||||
+ goto done;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ size = xmap->menu_count * sizeof(*map->menu_info);
|
|
||||||
+ map->menu_info = kmalloc(size, GFP_KERNEL);
|
|
||||||
+ if (map->menu_info == NULL) {
|
|
||||||
+ ret = -ENOMEM;
|
|
||||||
+ goto done;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (copy_from_user(map->menu_info, xmap->menu_info, size)) {
|
|
||||||
+ ret = -EFAULT;
|
|
||||||
+ goto done;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ map->menu_count = xmap->menu_count;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ ret = -EINVAL;
|
|
||||||
+ goto done;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ret = uvc_ctrl_add_mapping(map);
|
|
||||||
+
|
|
||||||
+done:
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ kfree(map->menu_info);
|
|
||||||
+ kfree(map);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/* ------------------------------------------------------------------------
|
|
||||||
* V4L2 interface
|
|
||||||
*/
|
|
||||||
|
|
||||||
@@ -974,7 +1039,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
|
||||||
info->flags = xinfo->flags;
|
|
||||||
|
|
||||||
info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
|
|
||||||
- UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
|
|
||||||
+ UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF |
|
|
||||||
+ UVC_CONTROL_EXTENSION;
|
|
||||||
|
|
||||||
ret = uvc_ctrl_add_info(info);
|
|
||||||
if (ret < 0)
|
|
||||||
@@ -982,32 +1048,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ case UVCIOC_CTRL_MAP_OLD:
|
|
||||||
case UVCIOC_CTRL_MAP:
|
|
||||||
- {
|
|
||||||
- struct uvc_xu_control_mapping *xmap = arg;
|
|
||||||
- struct uvc_control_mapping *map;
|
|
||||||
-
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
|
||||||
return -EPERM;
|
|
||||||
|
|
||||||
- map = kzalloc(sizeof *map, GFP_KERNEL);
|
|
||||||
- if (map == NULL)
|
|
||||||
- return -ENOMEM;
|
|
||||||
-
|
|
||||||
- map->id = xmap->id;
|
|
||||||
- memcpy(map->name, xmap->name, sizeof map->name);
|
|
||||||
- memcpy(map->entity, xmap->entity, sizeof map->entity);
|
|
||||||
- map->selector = xmap->selector;
|
|
||||||
- map->size = xmap->size;
|
|
||||||
- map->offset = xmap->offset;
|
|
||||||
- map->v4l2_type = xmap->v4l2_type;
|
|
||||||
- map->data_type = xmap->data_type;
|
|
||||||
-
|
|
||||||
- ret = uvc_ctrl_add_mapping(map);
|
|
||||||
- if (ret < 0)
|
|
||||||
- kfree(map);
|
|
||||||
- break;
|
|
||||||
- }
|
|
||||||
+ return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD);
|
|
||||||
|
|
||||||
case UVCIOC_CTRL_GET:
|
|
||||||
return uvc_xu_ctrl_query(chain, arg, 0);
|
|
||||||
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
|
|
||||||
index d1f8840..14f77e4 100644
|
|
||||||
--- a/drivers/media/video/uvc/uvcvideo.h
|
|
||||||
+++ b/drivers/media/video/uvc/uvcvideo.h
|
|
||||||
@@ -27,6 +27,8 @@
|
|
||||||
#define UVC_CONTROL_RESTORE (1 << 6)
|
|
||||||
/* Control can be updated by the camera. */
|
|
||||||
#define UVC_CONTROL_AUTO_UPDATE (1 << 7)
|
|
||||||
+/* Control is an extension unit control. */
|
|
||||||
+#define UVC_CONTROL_EXTENSION (1 << 8)
|
|
||||||
|
|
||||||
#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
|
|
||||||
UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
|
|
||||||
@@ -40,6 +42,15 @@ struct uvc_xu_control_info {
|
|
||||||
__u32 flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
+struct uvc_menu_info {
|
|
||||||
+ __u32 value;
|
|
||||||
+ __u8 name[32];
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct uvc_xu_control_mapping_old {
|
|
||||||
+ __u8 reserved[64];
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
struct uvc_xu_control_mapping {
|
|
||||||
__u32 id;
|
|
||||||
__u8 name[32];
|
|
||||||
@@ -50,6 +61,11 @@ struct uvc_xu_control_mapping {
|
|
||||||
__u8 offset;
|
|
||||||
enum v4l2_ctrl_type v4l2_type;
|
|
||||||
__u32 data_type;
|
|
||||||
+
|
|
||||||
+ struct uvc_menu_info __user *menu_info;
|
|
||||||
+ __u32 menu_count;
|
|
||||||
+
|
|
||||||
+ __u32 reserved[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct uvc_xu_control {
|
|
||||||
@@ -60,6 +76,7 @@ struct uvc_xu_control {
|
|
||||||
};
|
|
||||||
|
|
||||||
#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
|
|
||||||
+#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old)
|
|
||||||
#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
|
|
||||||
#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
|
|
||||||
#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
|
|
||||||
@@ -198,11 +215,6 @@ struct uvc_streaming_control {
|
|
||||||
__u8 bMaxVersion;
|
|
||||||
};
|
|
||||||
|
|
||||||
-struct uvc_menu_info {
|
|
||||||
- __u32 value;
|
|
||||||
- __u8 name[32];
|
|
||||||
-};
|
|
||||||
-
|
|
||||||
struct uvc_control_info {
|
|
||||||
struct list_head list;
|
|
||||||
struct list_head mappings;
|
|
||||||
@@ -625,6 +637,7 @@ extern int uvc_ctrl_init_device(struct uvc_device *dev);
|
|
||||||
extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
|
|
||||||
extern int uvc_ctrl_resume_device(struct uvc_device *dev);
|
|
||||||
extern void uvc_ctrl_init(void);
|
|
||||||
+extern void uvc_ctrl_cleanup(void);
|
|
||||||
|
|
||||||
extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
|
|
||||||
extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
|
|
||||||
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
||||||
Date: Fri, 25 Jun 2010 07:58:43 +0000 (+0200)
|
|
||||||
Subject: uvcvideo: Add support for Manta MM-353 Plako
|
|
||||||
X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=352e661e1f347390a86cf34bc5e41adbdd1caa41
|
|
||||||
|
|
||||||
uvcvideo: Add support for Manta MM-353 Plako
|
|
||||||
|
|
||||||
The camera requires the PROBE_MINMAX quirk. Add a corresponding entry
|
|
||||||
in the device IDs list
|
|
||||||
|
|
||||||
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
|
|
||||||
index 34818c1..1a89384 100644
|
|
||||||
--- a/drivers/media/video/uvc/uvc_driver.c
|
|
||||||
+++ b/drivers/media/video/uvc/uvc_driver.c
|
|
||||||
@@ -2174,6 +2174,15 @@ static struct usb_device_id uvc_ids[] = {
|
|
||||||
.bInterfaceSubClass = 1,
|
|
||||||
.bInterfaceProtocol = 0,
|
|
||||||
.driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
|
|
||||||
+ /* Manta MM-353 Plako */
|
|
||||||
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
|
|
||||||
+ | USB_DEVICE_ID_MATCH_INT_INFO,
|
|
||||||
+ .idVendor = 0x18ec,
|
|
||||||
+ .idProduct = 0x3188,
|
|
||||||
+ .bInterfaceClass = USB_CLASS_VIDEO,
|
|
||||||
+ .bInterfaceSubClass = 1,
|
|
||||||
+ .bInterfaceProtocol = 0,
|
|
||||||
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
|
|
||||||
/* FSC WebCam V30S */
|
|
||||||
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
|
|
||||||
| USB_DEVICE_ID_MATCH_INT_INFO,
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
Date: Wed, 01 Sep 2010 13:37:33 -0700 (PDT)
|
||||||
|
Message-Id: <20100901.133733.223467599.davem@davemloft.net>
|
||||||
|
To: davej@redhat.com
|
||||||
|
Cc: simon.kagstrom@netinsight.net, netdev@vger.kernel.org
|
||||||
|
Subject: Re: via-velocity dma-debug warnings again. (2.6.35.2)
|
||||||
|
From: David Miller <davem@davemloft.net>
|
||||||
|
In-Reply-To: <20100901.133547.236248297.davem@davemloft.net>
|
||||||
|
References: <20100901200555.GA30689@redhat.com>
|
||||||
|
<20100901.133414.24593005.davem@davemloft.net>
|
||||||
|
<20100901.133547.236248297.davem@davemloft.net>
|
||||||
|
|
||||||
|
|
||||||
|
Ok, this is becomming hopeless. Let's just try turning off SG support
|
||||||
|
for now, the length calculations are correct in those cases.
|
||||||
|
|
||||||
|
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
|
||||||
|
index fd69095..f534123 100644
|
||||||
|
--- a/drivers/net/via-velocity.c
|
||||||
|
+++ b/drivers/net/via-velocity.c
|
||||||
|
@@ -2824,7 +2824,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
|
||||||
|
netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT);
|
||||||
|
|
||||||
|
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
|
||||||
|
- NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM | NETIF_F_SG;
|
||||||
|
+ NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM;
|
||||||
|
|
||||||
|
ret = register_netdev(dev);
|
||||||
|
if (ret < 0)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,390 @@
|
||||||
|
From 9ced9810f0450a7f05eccb40dce4f9e4616c0fb6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Mel Gorman <mel@csn.ul.ie>
|
||||||
|
Date: Wed, 24 Nov 2010 22:18:23 -0500
|
||||||
|
Subject: [PATCH 1/2] mm: page allocator: Adjust the per-cpu counter threshold when memory is low
|
||||||
|
|
||||||
|
Commit aa45484 ("calculate a better estimate of NR_FREE_PAGES when memory
|
||||||
|
is low") noted that watermarks were based on the vmstat NR_FREE_PAGES. To
|
||||||
|
avoid synchronization overhead, these counters are maintained on a per-cpu
|
||||||
|
basis and drained both periodically and when a threshold is above a
|
||||||
|
threshold. On large CPU systems, the difference between the estimate and
|
||||||
|
real value of NR_FREE_PAGES can be very high. The system can get into a
|
||||||
|
case where pages are allocated far below the min watermark potentially
|
||||||
|
causing livelock issues. The commit solved the problem by taking a better
|
||||||
|
reading of NR_FREE_PAGES when memory was low.
|
||||||
|
|
||||||
|
Unfortately, as reported by Shaohua Li this accurate reading can consume a
|
||||||
|
large amount of CPU time on systems with many sockets due to cache line
|
||||||
|
bouncing. This patch takes a different approach. For large machines
|
||||||
|
where counter drift might be unsafe and while kswapd is awake, the per-cpu
|
||||||
|
thresholds for the target pgdat are reduced to limit the level of drift to
|
||||||
|
what should be a safe level. This incurs a performance penalty in heavy
|
||||||
|
memory pressure by a factor that depends on the workload and the machine
|
||||||
|
but the machine should function correctly without accidentally exhausting
|
||||||
|
all memory on a node. There is an additional cost when kswapd wakes and
|
||||||
|
sleeps but the event is not expected to be frequent - in Shaohua's test
|
||||||
|
case, there was one recorded sleep and wake event at least.
|
||||||
|
|
||||||
|
To ensure that kswapd wakes up, a safe version of zone_watermark_ok() is
|
||||||
|
introduced that takes a more accurate reading of NR_FREE_PAGES when called
|
||||||
|
from wakeup_kswapd, when deciding whether it is really safe to go back to
|
||||||
|
sleep in sleeping_prematurely() and when deciding if a zone is really
|
||||||
|
balanced or not in balance_pgdat(). We are still using an expensive
|
||||||
|
function but limiting how often it is called.
|
||||||
|
|
||||||
|
When the test case is reproduced, the time spent in the watermark
|
||||||
|
functions is reduced. The following report is on the percentage of time
|
||||||
|
spent cumulatively spent in the functions zone_nr_free_pages(),
|
||||||
|
zone_watermark_ok(), __zone_watermark_ok(), zone_watermark_ok_safe(),
|
||||||
|
zone_page_state_snapshot(), zone_page_state().
|
||||||
|
|
||||||
|
vanilla 11.6615%
|
||||||
|
disable-threshold 0.2584%
|
||||||
|
|
||||||
|
Reported-by: Shaohua Li <shaohua.li@intel.com>
|
||||||
|
Signed-off-by: Mel Gorman <mel@csn.ul.ie>
|
||||||
|
Reviewed-by: Christoph Lameter <cl@linux.com>
|
||||||
|
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||||
|
---
|
||||||
|
include/linux/mmzone.h | 10 ++-----
|
||||||
|
include/linux/vmstat.h | 5 +++
|
||||||
|
mm/mmzone.c | 21 ---------------
|
||||||
|
mm/page_alloc.c | 35 +++++++++++++++++++-----
|
||||||
|
mm/vmscan.c | 26 ++++++++++--------
|
||||||
|
mm/vmstat.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++-
|
||||||
|
6 files changed, 117 insertions(+), 48 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
|
||||||
|
index 8b2db3d..1e3d0b4 100644
|
||||||
|
--- a/include/linux/mmzone.h
|
||||||
|
+++ b/include/linux/mmzone.h
|
||||||
|
@@ -463,12 +463,6 @@ static inline int zone_is_oom_locked(const struct zone *zone)
|
||||||
|
return test_bit(ZONE_OOM_LOCKED, &zone->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
-#ifdef CONFIG_SMP
|
||||||
|
-unsigned long zone_nr_free_pages(struct zone *zone);
|
||||||
|
-#else
|
||||||
|
-#define zone_nr_free_pages(zone) zone_page_state(zone, NR_FREE_PAGES)
|
||||||
|
-#endif /* CONFIG_SMP */
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* The "priority" of VM scanning is how much of the queues we will scan in one
|
||||||
|
* go. A value of 12 for DEF_PRIORITY implies that we will scan 1/4096th of the
|
||||||
|
@@ -668,7 +662,9 @@ void get_zone_counts(unsigned long *active, unsigned long *inactive,
|
||||||
|
unsigned long *free);
|
||||||
|
void build_all_zonelists(void *data);
|
||||||
|
void wakeup_kswapd(struct zone *zone, int order);
|
||||||
|
-int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
|
||||||
|
+bool zone_watermark_ok(struct zone *z, int order, unsigned long mark,
|
||||||
|
+ int classzone_idx, int alloc_flags);
|
||||||
|
+bool zone_watermark_ok_safe(struct zone *z, int order, unsigned long mark,
|
||||||
|
int classzone_idx, int alloc_flags);
|
||||||
|
enum memmap_context {
|
||||||
|
MEMMAP_EARLY,
|
||||||
|
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
|
||||||
|
index eaaea37..e4cc21c 100644
|
||||||
|
--- a/include/linux/vmstat.h
|
||||||
|
+++ b/include/linux/vmstat.h
|
||||||
|
@@ -254,6 +254,8 @@ extern void dec_zone_state(struct zone *, enum zone_stat_item);
|
||||||
|
extern void __dec_zone_state(struct zone *, enum zone_stat_item);
|
||||||
|
|
||||||
|
void refresh_cpu_vm_stats(int);
|
||||||
|
+void reduce_pgdat_percpu_threshold(pg_data_t *pgdat);
|
||||||
|
+void restore_pgdat_percpu_threshold(pg_data_t *pgdat);
|
||||||
|
#else /* CONFIG_SMP */
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -298,6 +300,9 @@ static inline void __dec_zone_page_state(struct page *page,
|
||||||
|
#define dec_zone_page_state __dec_zone_page_state
|
||||||
|
#define mod_zone_page_state __mod_zone_page_state
|
||||||
|
|
||||||
|
+static inline void reduce_pgdat_percpu_threshold(pg_data_t *pgdat) { }
|
||||||
|
+static inline void restore_pgdat_percpu_threshold(pg_data_t *pgdat) { }
|
||||||
|
+
|
||||||
|
static inline void refresh_cpu_vm_stats(int cpu) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
diff --git a/mm/mmzone.c b/mm/mmzone.c
|
||||||
|
index e35bfb8..f5b7d17 100644
|
||||||
|
--- a/mm/mmzone.c
|
||||||
|
+++ b/mm/mmzone.c
|
||||||
|
@@ -87,24 +87,3 @@ int memmap_valid_within(unsigned long pfn,
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ARCH_HAS_HOLES_MEMORYMODEL */
|
||||||
|
-
|
||||||
|
-#ifdef CONFIG_SMP
|
||||||
|
-/* Called when a more accurate view of NR_FREE_PAGES is needed */
|
||||||
|
-unsigned long zone_nr_free_pages(struct zone *zone)
|
||||||
|
-{
|
||||||
|
- unsigned long nr_free_pages = zone_page_state(zone, NR_FREE_PAGES);
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * While kswapd is awake, it is considered the zone is under some
|
||||||
|
- * memory pressure. Under pressure, there is a risk that
|
||||||
|
- * per-cpu-counter-drift will allow the min watermark to be breached
|
||||||
|
- * potentially causing a live-lock. While kswapd is awake and
|
||||||
|
- * free pages are low, get a better estimate for free pages
|
||||||
|
- */
|
||||||
|
- if (nr_free_pages < zone->percpu_drift_mark &&
|
||||||
|
- !waitqueue_active(&zone->zone_pgdat->kswapd_wait))
|
||||||
|
- return zone_page_state_snapshot(zone, NR_FREE_PAGES);
|
||||||
|
-
|
||||||
|
- return nr_free_pages;
|
||||||
|
-}
|
||||||
|
-#endif /* CONFIG_SMP */
|
||||||
|
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
|
||||||
|
index f7cc624..cf5d4c0 100644
|
||||||
|
--- a/mm/page_alloc.c
|
||||||
|
+++ b/mm/page_alloc.c
|
||||||
|
@@ -1454,24 +1454,24 @@ static inline int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
|
||||||
|
#endif /* CONFIG_FAIL_PAGE_ALLOC */
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * Return 1 if free pages are above 'mark'. This takes into account the order
|
||||||
|
+ * Return true if free pages are above 'mark'. This takes into account the order
|
||||||
|
* of the allocation.
|
||||||
|
*/
|
||||||
|
-int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
|
||||||
|
- int classzone_idx, int alloc_flags)
|
||||||
|
+static bool __zone_watermark_ok(struct zone *z, int order, unsigned long mark,
|
||||||
|
+ int classzone_idx, int alloc_flags, long free_pages)
|
||||||
|
{
|
||||||
|
/* free_pages my go negative - that's OK */
|
||||||
|
long min = mark;
|
||||||
|
- long free_pages = zone_nr_free_pages(z) - (1 << order) + 1;
|
||||||
|
int o;
|
||||||
|
|
||||||
|
+ free_pages -= (1 << order) + 1;
|
||||||
|
if (alloc_flags & ALLOC_HIGH)
|
||||||
|
min -= min / 2;
|
||||||
|
if (alloc_flags & ALLOC_HARDER)
|
||||||
|
min -= min / 4;
|
||||||
|
|
||||||
|
if (free_pages <= min + z->lowmem_reserve[classzone_idx])
|
||||||
|
- return 0;
|
||||||
|
+ return false;
|
||||||
|
for (o = 0; o < order; o++) {
|
||||||
|
/* At the next order, this order's pages become unavailable */
|
||||||
|
free_pages -= z->free_area[o].nr_free << o;
|
||||||
|
@@ -1480,9 +1480,28 @@ int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
|
||||||
|
min >>= 1;
|
||||||
|
|
||||||
|
if (free_pages <= min)
|
||||||
|
- return 0;
|
||||||
|
+ return false;
|
||||||
|
}
|
||||||
|
- return 1;
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool zone_watermark_ok(struct zone *z, int order, unsigned long mark,
|
||||||
|
+ int classzone_idx, int alloc_flags)
|
||||||
|
+{
|
||||||
|
+ return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
|
||||||
|
+ zone_page_state(z, NR_FREE_PAGES));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool zone_watermark_ok_safe(struct zone *z, int order, unsigned long mark,
|
||||||
|
+ int classzone_idx, int alloc_flags)
|
||||||
|
+{
|
||||||
|
+ long free_pages = zone_page_state(z, NR_FREE_PAGES);
|
||||||
|
+
|
||||||
|
+ if (z->percpu_drift_mark && free_pages < z->percpu_drift_mark)
|
||||||
|
+ free_pages = zone_page_state_snapshot(z, NR_FREE_PAGES);
|
||||||
|
+
|
||||||
|
+ return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
|
||||||
|
+ free_pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_NUMA
|
||||||
|
@@ -2425,7 +2444,7 @@ void show_free_areas(void)
|
||||||
|
" all_unreclaimable? %s"
|
||||||
|
"\n",
|
||||||
|
zone->name,
|
||||||
|
- K(zone_nr_free_pages(zone)),
|
||||||
|
+ K(zone_page_state(zone, NR_FREE_PAGES)),
|
||||||
|
K(min_wmark_pages(zone)),
|
||||||
|
K(low_wmark_pages(zone)),
|
||||||
|
K(high_wmark_pages(zone)),
|
||||||
|
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
||||||
|
index 9753626..18f4038 100644
|
||||||
|
--- a/mm/vmscan.c
|
||||||
|
+++ b/mm/vmscan.c
|
||||||
|
@@ -2007,7 +2007,7 @@ static int sleeping_prematurely(pg_data_t *pgdat, int order, long remaining)
|
||||||
|
if (zone->all_unreclaimable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
- if (!zone_watermark_ok(zone, order, high_wmark_pages(zone),
|
||||||
|
+ if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone),
|
||||||
|
0, 0))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
@@ -2104,7 +2104,7 @@ loop_again:
|
||||||
|
shrink_active_list(SWAP_CLUSTER_MAX, zone,
|
||||||
|
&sc, priority, 0);
|
||||||
|
|
||||||
|
- if (!zone_watermark_ok(zone, order,
|
||||||
|
+ if (!zone_watermark_ok_safe(zone, order,
|
||||||
|
high_wmark_pages(zone), 0, 0)) {
|
||||||
|
end_zone = i;
|
||||||
|
break;
|
||||||
|
@@ -2155,7 +2155,7 @@ loop_again:
|
||||||
|
* We put equal pressure on every zone, unless one
|
||||||
|
* zone has way too many pages free already.
|
||||||
|
*/
|
||||||
|
- if (!zone_watermark_ok(zone, order,
|
||||||
|
+ if (!zone_watermark_ok_safe(zone, order,
|
||||||
|
8*high_wmark_pages(zone), end_zone, 0))
|
||||||
|
shrink_zone(priority, zone, &sc);
|
||||||
|
reclaim_state->reclaimed_slab = 0;
|
||||||
|
@@ -2176,7 +2176,7 @@ loop_again:
|
||||||
|
total_scanned > sc.nr_reclaimed + sc.nr_reclaimed / 2)
|
||||||
|
sc.may_writepage = 1;
|
||||||
|
|
||||||
|
- if (!zone_watermark_ok(zone, order,
|
||||||
|
+ if (!zone_watermark_ok_safe(zone, order,
|
||||||
|
high_wmark_pages(zone), end_zone, 0)) {
|
||||||
|
all_zones_ok = 0;
|
||||||
|
/*
|
||||||
|
@@ -2184,7 +2184,7 @@ loop_again:
|
||||||
|
* means that we have a GFP_ATOMIC allocation
|
||||||
|
* failure risk. Hurry up!
|
||||||
|
*/
|
||||||
|
- if (!zone_watermark_ok(zone, order,
|
||||||
|
+ if (!zone_watermark_ok_safe(zone, order,
|
||||||
|
min_wmark_pages(zone), end_zone, 0))
|
||||||
|
has_under_min_watermark_zone = 1;
|
||||||
|
}
|
||||||
|
@@ -2326,9 +2326,11 @@ static int kswapd(void *p)
|
||||||
|
* premature sleep. If not, then go fully
|
||||||
|
* to sleep until explicitly woken up
|
||||||
|
*/
|
||||||
|
- if (!sleeping_prematurely(pgdat, order, remaining))
|
||||||
|
+ if (!sleeping_prematurely(pgdat, order, remaining)) {
|
||||||
|
+ restore_pgdat_percpu_threshold(pgdat);
|
||||||
|
schedule();
|
||||||
|
- else {
|
||||||
|
+ reduce_pgdat_percpu_threshold(pgdat);
|
||||||
|
+ } else {
|
||||||
|
if (remaining)
|
||||||
|
count_vm_event(KSWAPD_LOW_WMARK_HIT_QUICKLY);
|
||||||
|
else
|
||||||
|
@@ -2364,15 +2366,16 @@ void wakeup_kswapd(struct zone *zone, int order)
|
||||||
|
if (!populated_zone(zone))
|
||||||
|
return;
|
||||||
|
|
||||||
|
- pgdat = zone->zone_pgdat;
|
||||||
|
- if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0, 0))
|
||||||
|
+ if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
|
||||||
|
return;
|
||||||
|
+ pgdat = zone->zone_pgdat;
|
||||||
|
if (pgdat->kswapd_max_order < order)
|
||||||
|
pgdat->kswapd_max_order = order;
|
||||||
|
- if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
|
||||||
|
- return;
|
||||||
|
if (!waitqueue_active(&pgdat->kswapd_wait))
|
||||||
|
return;
|
||||||
|
+ if (zone_watermark_ok_safe(zone, order, low_wmark_pages(zone), 0, 0))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
wake_up_interruptible(&pgdat->kswapd_wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/mm/vmstat.c b/mm/vmstat.c
|
||||||
|
index 26d5716..41dc8cd 100644
|
||||||
|
--- a/mm/vmstat.c
|
||||||
|
+++ b/mm/vmstat.c
|
||||||
|
@@ -81,6 +81,30 @@ EXPORT_SYMBOL(vm_stat);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
|
+static int calculate_pressure_threshold(struct zone *zone)
|
||||||
|
+{
|
||||||
|
+ int threshold;
|
||||||
|
+ int watermark_distance;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * As vmstats are not up to date, there is drift between the estimated
|
||||||
|
+ * and real values. For high thresholds and a high number of CPUs, it
|
||||||
|
+ * is possible for the min watermark to be breached while the estimated
|
||||||
|
+ * value looks fine. The pressure threshold is a reduced value such
|
||||||
|
+ * that even the maximum amount of drift will not accidentally breach
|
||||||
|
+ * the min watermark
|
||||||
|
+ */
|
||||||
|
+ watermark_distance = low_wmark_pages(zone) - min_wmark_pages(zone);
|
||||||
|
+ threshold = max(1, (int)(watermark_distance / num_online_cpus()));
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Maximum threshold is 125
|
||||||
|
+ */
|
||||||
|
+ threshold = min(125, threshold);
|
||||||
|
+
|
||||||
|
+ return threshold;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int calculate_threshold(struct zone *zone)
|
||||||
|
{
|
||||||
|
int threshold;
|
||||||
|
@@ -159,6 +183,48 @@ static void refresh_zone_stat_thresholds(void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+void reduce_pgdat_percpu_threshold(pg_data_t *pgdat)
|
||||||
|
+{
|
||||||
|
+ struct zone *zone;
|
||||||
|
+ int cpu;
|
||||||
|
+ int threshold;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ get_online_cpus();
|
||||||
|
+ for (i = 0; i < pgdat->nr_zones; i++) {
|
||||||
|
+ zone = &pgdat->node_zones[i];
|
||||||
|
+ if (!zone->percpu_drift_mark)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ threshold = calculate_pressure_threshold(zone);
|
||||||
|
+ for_each_online_cpu(cpu)
|
||||||
|
+ per_cpu_ptr(zone->pageset, cpu)->stat_threshold
|
||||||
|
+ = threshold;
|
||||||
|
+ }
|
||||||
|
+ put_online_cpus();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void restore_pgdat_percpu_threshold(pg_data_t *pgdat)
|
||||||
|
+{
|
||||||
|
+ struct zone *zone;
|
||||||
|
+ int cpu;
|
||||||
|
+ int threshold;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ get_online_cpus();
|
||||||
|
+ for (i = 0; i < pgdat->nr_zones; i++) {
|
||||||
|
+ zone = &pgdat->node_zones[i];
|
||||||
|
+ if (!zone->percpu_drift_mark)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ threshold = calculate_threshold(zone);
|
||||||
|
+ for_each_online_cpu(cpu)
|
||||||
|
+ per_cpu_ptr(zone->pageset, cpu)->stat_threshold
|
||||||
|
+ = threshold;
|
||||||
|
+ }
|
||||||
|
+ put_online_cpus();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* For use when we know that interrupts are disabled.
|
||||||
|
*/
|
||||||
|
@@ -826,7 +892,7 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
|
||||||
|
"\n scanned %lu"
|
||||||
|
"\n spanned %lu"
|
||||||
|
"\n present %lu",
|
||||||
|
- zone_nr_free_pages(zone),
|
||||||
|
+ zone_page_state(zone, NR_FREE_PAGES),
|
||||||
|
min_wmark_pages(zone),
|
||||||
|
low_wmark_pages(zone),
|
||||||
|
high_wmark_pages(zone),
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
From 235d4a7af803e65d8fabdf9cd6d1445c11e2fd45 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Mel Gorman <mel@csn.ul.ie>
|
||||||
|
Date: Wed, 24 Nov 2010 22:24:24 -0500
|
||||||
|
Subject: [PATCH 2/2] mm: vmstat: Use a single setter function and callback for adjusting percpu thresholds
|
||||||
|
|
||||||
|
reduce_pgdat_percpu_threshold() and restore_pgdat_percpu_threshold() exist
|
||||||
|
to adjust the per-cpu vmstat thresholds while kswapd is awake to avoid
|
||||||
|
errors due to counter drift. The functions duplicate some code so this
|
||||||
|
patch replaces them with a single set_pgdat_percpu_threshold() that takes
|
||||||
|
a callback function to calculate the desired threshold as a parameter.
|
||||||
|
|
||||||
|
Signed-off-by: Mel Gorman <mel@csn.ul.ie>
|
||||||
|
Reviewed-by: Christoph Lameter <cl@linux.com>
|
||||||
|
Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
|
||||||
|
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||||
|
[the various mmotm patches updating this were rolled up. --kyle]
|
||||||
|
---
|
||||||
|
include/linux/vmstat.h | 10 ++++++----
|
||||||
|
mm/vmscan.c | 18 ++++++++++++++++--
|
||||||
|
mm/vmstat.c | 36 +++++++-----------------------------
|
||||||
|
3 files changed, 29 insertions(+), 35 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
|
||||||
|
index e4cc21c..833e676 100644
|
||||||
|
--- a/include/linux/vmstat.h
|
||||||
|
+++ b/include/linux/vmstat.h
|
||||||
|
@@ -254,8 +254,11 @@ extern void dec_zone_state(struct zone *, enum zone_stat_item);
|
||||||
|
extern void __dec_zone_state(struct zone *, enum zone_stat_item);
|
||||||
|
|
||||||
|
void refresh_cpu_vm_stats(int);
|
||||||
|
-void reduce_pgdat_percpu_threshold(pg_data_t *pgdat);
|
||||||
|
-void restore_pgdat_percpu_threshold(pg_data_t *pgdat);
|
||||||
|
+
|
||||||
|
+int calculate_pressure_threshold(struct zone *zone);
|
||||||
|
+int calculate_normal_threshold(struct zone *zone);
|
||||||
|
+void set_pgdat_percpu_threshold(pg_data_t *pgdat,
|
||||||
|
+ int (*calculate_pressure)(struct zone *));
|
||||||
|
#else /* CONFIG_SMP */
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -300,8 +303,7 @@ static inline void __dec_zone_page_state(struct page *page,
|
||||||
|
#define dec_zone_page_state __dec_zone_page_state
|
||||||
|
#define mod_zone_page_state __mod_zone_page_state
|
||||||
|
|
||||||
|
-static inline void reduce_pgdat_percpu_threshold(pg_data_t *pgdat) { }
|
||||||
|
-static inline void restore_pgdat_percpu_threshold(pg_data_t *pgdat) { }
|
||||||
|
+#define set_pgdat_percpu_threshold(pgdat, callback) { }
|
||||||
|
|
||||||
|
static inline void refresh_cpu_vm_stats(int cpu) { }
|
||||||
|
#endif
|
||||||
|
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
||||||
|
index 18f4038..e8df269 100644
|
||||||
|
--- a/mm/vmscan.c
|
||||||
|
+++ b/mm/vmscan.c
|
||||||
|
@@ -2327,9 +2327,23 @@ static int kswapd(void *p)
|
||||||
|
* to sleep until explicitly woken up
|
||||||
|
*/
|
||||||
|
if (!sleeping_prematurely(pgdat, order, remaining)) {
|
||||||
|
- restore_pgdat_percpu_threshold(pgdat);
|
||||||
|
+ /*
|
||||||
|
+ * vmstat counters are not perfectly
|
||||||
|
+ * accurate and the estimated value
|
||||||
|
+ * for counters such as NR_FREE_PAGES
|
||||||
|
+ * can deviate from the true value by
|
||||||
|
+ * nr_online_cpus * threshold. To
|
||||||
|
+ * avoid the zone watermarks being
|
||||||
|
+ * breached while under pressure, we
|
||||||
|
+ * reduce the per-cpu vmstat threshold
|
||||||
|
+ * while kswapd is awake and restore
|
||||||
|
+ * them before going back to sleep.
|
||||||
|
+ */
|
||||||
|
+ set_pgdat_percpu_threshold(pgdat,
|
||||||
|
+ calculate_normal_threshold);
|
||||||
|
schedule();
|
||||||
|
- reduce_pgdat_percpu_threshold(pgdat);
|
||||||
|
+ set_pgdat_percpu_threshold(pgdat,
|
||||||
|
+ calculate_pressure_threshold);
|
||||||
|
} else {
|
||||||
|
if (remaining)
|
||||||
|
count_vm_event(KSWAPD_LOW_WMARK_HIT_QUICKLY);
|
||||||
|
diff --git a/mm/vmstat.c b/mm/vmstat.c
|
||||||
|
index 41dc8cd..5b44b82 100644
|
||||||
|
--- a/mm/vmstat.c
|
||||||
|
+++ b/mm/vmstat.c
|
||||||
|
@@ -81,7 +81,7 @@ EXPORT_SYMBOL(vm_stat);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
|
-static int calculate_pressure_threshold(struct zone *zone)
|
||||||
|
+int calculate_pressure_threshold(struct zone *zone)
|
||||||
|
{
|
||||||
|
int threshold;
|
||||||
|
int watermark_distance;
|
||||||
|
@@ -105,7 +105,7 @@ static int calculate_pressure_threshold(struct zone *zone)
|
||||||
|
return threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int calculate_threshold(struct zone *zone)
|
||||||
|
+int calculate_normal_threshold(struct zone *zone)
|
||||||
|
{
|
||||||
|
int threshold;
|
||||||
|
int mem; /* memory in 128 MB units */
|
||||||
|
@@ -164,7 +164,7 @@ static void refresh_zone_stat_thresholds(void)
|
||||||
|
for_each_populated_zone(zone) {
|
||||||
|
unsigned long max_drift, tolerate_drift;
|
||||||
|
|
||||||
|
- threshold = calculate_threshold(zone);
|
||||||
|
+ threshold = calculate_normal_threshold(zone);
|
||||||
|
|
||||||
|
for_each_online_cpu(cpu)
|
||||||
|
per_cpu_ptr(zone->pageset, cpu)->stat_threshold
|
||||||
|
@@ -183,46 +183,24 @@ static void refresh_zone_stat_thresholds(void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-void reduce_pgdat_percpu_threshold(pg_data_t *pgdat)
|
||||||
|
+void set_pgdat_percpu_threshold(pg_data_t *pgdat,
|
||||||
|
+ int (*calculate_pressure)(struct zone *))
|
||||||
|
{
|
||||||
|
struct zone *zone;
|
||||||
|
int cpu;
|
||||||
|
int threshold;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
- get_online_cpus();
|
||||||
|
- for (i = 0; i < pgdat->nr_zones; i++) {
|
||||||
|
- zone = &pgdat->node_zones[i];
|
||||||
|
- if (!zone->percpu_drift_mark)
|
||||||
|
- continue;
|
||||||
|
-
|
||||||
|
- threshold = calculate_pressure_threshold(zone);
|
||||||
|
- for_each_online_cpu(cpu)
|
||||||
|
- per_cpu_ptr(zone->pageset, cpu)->stat_threshold
|
||||||
|
- = threshold;
|
||||||
|
- }
|
||||||
|
- put_online_cpus();
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-void restore_pgdat_percpu_threshold(pg_data_t *pgdat)
|
||||||
|
-{
|
||||||
|
- struct zone *zone;
|
||||||
|
- int cpu;
|
||||||
|
- int threshold;
|
||||||
|
- int i;
|
||||||
|
-
|
||||||
|
- get_online_cpus();
|
||||||
|
for (i = 0; i < pgdat->nr_zones; i++) {
|
||||||
|
zone = &pgdat->node_zones[i];
|
||||||
|
if (!zone->percpu_drift_mark)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
- threshold = calculate_threshold(zone);
|
||||||
|
- for_each_online_cpu(cpu)
|
||||||
|
+ threshold = (*calculate_pressure)(zone);
|
||||||
|
+ for_each_possible_cpu(cpu)
|
||||||
|
per_cpu_ptr(zone->pageset, cpu)->stat_threshold
|
||||||
|
= threshold;
|
||||||
|
}
|
||||||
|
- put_online_cpus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
From kernel-bounces@lists.fedoraproject.org Thu Sep 9 09:24:46 2010
|
||||||
|
From: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||||
|
Subject: [PATCH 3/3] mmc: add ricoh e822 pci id
|
||||||
|
Date: Thu, 9 Sep 2010 15:24:12 +0200
|
||||||
|
|
||||||
|
From: Pablo Castillo <CyberCastle@gmail.com>
|
||||||
|
|
||||||
|
Upstream 568133ebda39f7507759a744fa9cf4d5097bad2f commit.
|
||||||
|
|
||||||
|
Signed-off-by: Pablo Castillo <CyberCastle@gmail.com>
|
||||||
|
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||||
|
Tested-by: Gregg Lebovitz <gregg@lebovitz.net>
|
||||||
|
Cc: Maxim Levitsky <maximlevitsky@gmail.com>
|
||||||
|
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||||
|
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||||
|
---
|
||||||
|
drivers/mmc/host/sdhci-pci.c | 8 ++++++++
|
||||||
|
1 files changed, 8 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
|
||||||
|
index e021431..e8aa99d 100644
|
||||||
|
--- a/drivers/mmc/host/sdhci-pci.c
|
||||||
|
+++ b/drivers/mmc/host/sdhci-pci.c
|
||||||
|
@@ -415,6 +415,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
+ .vendor = PCI_VENDOR_ID_RICOH,
|
||||||
|
+ .device = 0xe822,
|
||||||
|
+ .subvendor = PCI_ANY_ID,
|
||||||
|
+ .subdevice = PCI_ANY_ID,
|
||||||
|
+ .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
|
||||||
|
+ },
|
||||||
|
+
|
||||||
|
+ {
|
||||||
|
.vendor = PCI_VENDOR_ID_ENE,
|
||||||
|
.device = PCI_DEVICE_ID_ENE_CB712_SD,
|
||||||
|
.subvendor = PCI_ANY_ID,
|
||||||
|
--
|
||||||
|
1.7.1
|
||||||
|
|
||||||
|
_______________________________________________
|
||||||
|
kernel mailing list
|
||||||
|
kernel@lists.fedoraproject.org
|
||||||
|
https://admin.fedoraproject.org/mailman/listinfo/kernel
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
From kernel-bounces@lists.fedoraproject.org Thu Sep 9 09:24:33 2010
|
||||||
|
From: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||||
|
Subject: [PATCH 2/3] mmc: make sdhci work with ricoh mmc controller
|
||||||
|
Date: Thu, 9 Sep 2010 15:24:11 +0200
|
||||||
|
|
||||||
|
From: Maxim Levitsky <maximlevitsky@gmail.com>
|
||||||
|
|
||||||
|
Upstream ccc92c23240cdf952ef7cc39ba563910dcbc9cbe commit.
|
||||||
|
|
||||||
|
The current way of disabling it is not well tested by vendor and has all
|
||||||
|
kinds of bugs that show up on resume from ram/disk. A very good example
|
||||||
|
is a dead SDHCI controller.
|
||||||
|
|
||||||
|
Old way of disabling is still supported by continuing to use
|
||||||
|
CONFIG_MMC_RICOH_MMC.
|
||||||
|
|
||||||
|
Based on 'http://list.drzeus.cx/pipermail/sdhci-devel/2007-December/002085.html'
|
||||||
|
Therefore most of the credit for this goes to Andrew de Quincey
|
||||||
|
|
||||||
|
Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
|
||||||
|
Cc: Andrew de Quincey <adq_dvb@lidskialf.net>
|
||||||
|
Acked-by: Philip Langdale <philipl@overt.org>
|
||||||
|
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
|
||||||
|
Cc: <linux-mmc@vger.kernel.org>
|
||||||
|
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||||
|
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||||
|
---
|
||||||
|
drivers/mmc/host/sdhci-pci.c | 41 +++++++++++++++++++++++++++++++++++++++++
|
||||||
|
drivers/mmc/host/sdhci.c | 3 ++-
|
||||||
|
drivers/mmc/host/sdhci.h | 4 ++++
|
||||||
|
3 files changed, 47 insertions(+), 1 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
|
||||||
|
index 65483fd..e021431 100644
|
||||||
|
--- a/drivers/mmc/host/sdhci-pci.c
|
||||||
|
+++ b/drivers/mmc/host/sdhci-pci.c
|
||||||
|
@@ -17,6 +17,7 @@
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
+#include <linux/device.h>
|
||||||
|
|
||||||
|
#include <linux/mmc/host.h>
|
||||||
|
|
||||||
|
@@ -84,7 +85,30 @@ static int ricoh_probe(struct sdhci_pci_chip *chip)
|
||||||
|
if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG ||
|
||||||
|
chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY)
|
||||||
|
chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
|
||||||
|
+{
|
||||||
|
+ slot->host->caps =
|
||||||
|
+ ((0x21 << SDHCI_TIMEOUT_CLK_SHIFT)
|
||||||
|
+ & SDHCI_TIMEOUT_CLK_MASK) |
|
||||||
|
+
|
||||||
|
+ ((0x21 << SDHCI_CLOCK_BASE_SHIFT)
|
||||||
|
+ & SDHCI_CLOCK_BASE_MASK) |
|
||||||
|
|
||||||
|
+ SDHCI_TIMEOUT_CLK_UNIT |
|
||||||
|
+ SDHCI_CAN_VDD_330 |
|
||||||
|
+ SDHCI_CAN_DO_SDMA;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ricoh_mmc_resume(struct sdhci_pci_chip *chip)
|
||||||
|
+{
|
||||||
|
+ /* Apply a delay to allow controller to settle */
|
||||||
|
+ /* Otherwise it becomes confused if card state changed
|
||||||
|
+ during suspend */
|
||||||
|
+ msleep(500);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -95,6 +119,15 @@ static const struct sdhci_pci_fixes sdhci_ricoh = {
|
||||||
|
SDHCI_QUIRK_CLOCK_BEFORE_RESET,
|
||||||
|
};
|
||||||
|
|
||||||
|
+static const struct sdhci_pci_fixes sdhci_ricoh_mmc = {
|
||||||
|
+ .probe_slot = ricoh_mmc_probe_slot,
|
||||||
|
+ .resume = ricoh_mmc_resume,
|
||||||
|
+ .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
|
||||||
|
+ SDHCI_QUIRK_CLOCK_BEFORE_RESET |
|
||||||
|
+ SDHCI_QUIRK_NO_CARD_NO_RESET |
|
||||||
|
+ SDHCI_QUIRK_MISSING_CAPS
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static const struct sdhci_pci_fixes sdhci_ene_712 = {
|
||||||
|
.quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
|
||||||
|
SDHCI_QUIRK_BROKEN_DMA,
|
||||||
|
@@ -374,6 +407,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
+ .vendor = PCI_VENDOR_ID_RICOH,
|
||||||
|
+ .device = 0x843,
|
||||||
|
+ .subvendor = PCI_ANY_ID,
|
||||||
|
+ .subdevice = PCI_ANY_ID,
|
||||||
|
+ .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
|
||||||
|
+ },
|
||||||
|
+
|
||||||
|
+ {
|
||||||
|
.vendor = PCI_VENDOR_ID_ENE,
|
||||||
|
.device = PCI_DEVICE_ID_ENE_CB712_SD,
|
||||||
|
.subvendor = PCI_ANY_ID,
|
||||||
|
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
|
||||||
|
index 955cad9..8e1dda3 100644
|
||||||
|
--- a/drivers/mmc/host/sdhci.c
|
||||||
|
+++ b/drivers/mmc/host/sdhci.c
|
||||||
|
@@ -1692,7 +1692,8 @@ int sdhci_add_host(struct sdhci_host *host)
|
||||||
|
host->version);
|
||||||
|
}
|
||||||
|
|
||||||
|
- caps = sdhci_readl(host, SDHCI_CAPABILITIES);
|
||||||
|
+ caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
|
||||||
|
+ sdhci_readl(host, SDHCI_CAPABILITIES);
|
||||||
|
|
||||||
|
if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
|
||||||
|
host->flags |= SDHCI_USE_SDMA;
|
||||||
|
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
|
||||||
|
index eb5efe0..030de49 100644
|
||||||
|
--- a/drivers/mmc/host/sdhci.h
|
||||||
|
+++ b/drivers/mmc/host/sdhci.h
|
||||||
|
@@ -241,6 +241,8 @@ struct sdhci_host {
|
||||||
|
#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25)
|
||||||
|
/* Controller cannot support End Attribute in NOP ADMA descriptor */
|
||||||
|
#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26)
|
||||||
|
+/* Controller is missing device caps. Use caps provided by host */
|
||||||
|
+#define SDHCI_QUIRK_MISSING_CAPS (1<<27)
|
||||||
|
|
||||||
|
int irq; /* Device IRQ */
|
||||||
|
void __iomem * ioaddr; /* Mapped address */
|
||||||
|
@@ -293,6 +295,8 @@ struct sdhci_host {
|
||||||
|
|
||||||
|
struct timer_list timer; /* Timer for timeouts */
|
||||||
|
|
||||||
|
+ unsigned int caps; /* Alternative capabilities */
|
||||||
|
+
|
||||||
|
unsigned long private[0] ____cacheline_aligned;
|
||||||
|
};
|
||||||
|
|
||||||
|
--
|
||||||
|
1.7.1
|
||||||
|
|
||||||
|
_______________________________________________
|
||||||
|
kernel mailing list
|
||||||
|
kernel@lists.fedoraproject.org
|
||||||
|
https://admin.fedoraproject.org/mailman/listinfo/kernel
|
||||||
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
Author: Neil Horman <nhorman@tuxdriver.com>
|
||||||
|
Date: Fri Dec 17 13:35:36 2010 -0500
|
||||||
|
|
||||||
|
Enhance AF_PACKET to support using non-contiguous memory when allocating ring
|
||||||
|
buffer space. This is a combined backport of the following commits from
|
||||||
|
net-next-2.6:
|
||||||
|
0e3125c755445664f00ad036e4fc2cd32fd52877
|
||||||
|
bbce5a59e4e0e6e1dbc85492caaf310ff6611309
|
||||||
|
0af55bb58f8fa7865004ac48d16affe125ac1b7f
|
||||||
|
920b8d913bd3d963d5c88bca160a272b71e0c95a
|
||||||
|
|
||||||
|
diff -up linux-2.6.34.x86_64/net/packet/af_packet.c.orig linux-2.6.34.x86_64/net/packet/af_packet.c
|
||||||
|
--- linux-2.6.34.x86_64/net/packet/af_packet.c.orig 2010-12-17 12:16:58.000000000 -0500
|
||||||
|
+++ linux-2.6.34.x86_64/net/packet/af_packet.c 2010-12-17 12:30:14.000000000 -0500
|
||||||
|
@@ -61,6 +61,7 @@
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kmod.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
+#include <linux/vmalloc.h>
|
||||||
|
#include <net/net_namespace.h>
|
||||||
|
#include <net/ip.h>
|
||||||
|
#include <net/protocol.h>
|
||||||
|
@@ -161,8 +162,14 @@ struct packet_mreq_max {
|
||||||
|
static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
|
||||||
|
int closing, int tx_ring);
|
||||||
|
|
||||||
|
+#define PGV_FROM_VMALLOC 1
|
||||||
|
+struct pgv {
|
||||||
|
+ char *buffer;
|
||||||
|
+ unsigned char flags;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
struct packet_ring_buffer {
|
||||||
|
- char **pg_vec;
|
||||||
|
+ struct pgv *pg_vec;
|
||||||
|
unsigned int head;
|
||||||
|
unsigned int frames_per_block;
|
||||||
|
unsigned int frame_size;
|
||||||
|
@@ -214,6 +221,13 @@ struct packet_skb_cb {
|
||||||
|
|
||||||
|
#define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb))
|
||||||
|
|
||||||
|
+static inline struct page *pgv_to_page(void *addr)
|
||||||
|
+{
|
||||||
|
+ if (is_vmalloc_addr(addr))
|
||||||
|
+ return vmalloc_to_page(addr);
|
||||||
|
+ return virt_to_page(addr);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void __packet_set_status(struct packet_sock *po, void *frame, int status)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
@@ -226,11 +240,11 @@ static void __packet_set_status(struct p
|
||||||
|
switch (po->tp_version) {
|
||||||
|
case TPACKET_V1:
|
||||||
|
h.h1->tp_status = status;
|
||||||
|
- flush_dcache_page(virt_to_page(&h.h1->tp_status));
|
||||||
|
+ flush_dcache_page(pgv_to_page(&h.h1->tp_status));
|
||||||
|
break;
|
||||||
|
case TPACKET_V2:
|
||||||
|
h.h2->tp_status = status;
|
||||||
|
- flush_dcache_page(virt_to_page(&h.h2->tp_status));
|
||||||
|
+ flush_dcache_page(pgv_to_page(&h.h2->tp_status));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("TPACKET version not supported\n");
|
||||||
|
@@ -253,10 +267,10 @@ static int __packet_get_status(struct pa
|
||||||
|
h.raw = frame;
|
||||||
|
switch (po->tp_version) {
|
||||||
|
case TPACKET_V1:
|
||||||
|
- flush_dcache_page(virt_to_page(&h.h1->tp_status));
|
||||||
|
+ flush_dcache_page(pgv_to_page(&h.h1->tp_status));
|
||||||
|
return h.h1->tp_status;
|
||||||
|
case TPACKET_V2:
|
||||||
|
- flush_dcache_page(virt_to_page(&h.h2->tp_status));
|
||||||
|
+ flush_dcache_page(pgv_to_page(&h.h2->tp_status));
|
||||||
|
return h.h2->tp_status;
|
||||||
|
default:
|
||||||
|
pr_err("TPACKET version not supported\n");
|
||||||
|
@@ -280,7 +294,8 @@ static void *packet_lookup_frame(struct
|
||||||
|
pg_vec_pos = position / rb->frames_per_block;
|
||||||
|
frame_offset = position % rb->frames_per_block;
|
||||||
|
|
||||||
|
- h.raw = rb->pg_vec[pg_vec_pos] + (frame_offset * rb->frame_size);
|
||||||
|
+ h.raw = rb->pg_vec[pg_vec_pos].buffer +
|
||||||
|
+ (frame_offset * rb->frame_size);
|
||||||
|
|
||||||
|
if (status != __packet_get_status(po, h.raw))
|
||||||
|
return NULL;
|
||||||
|
@@ -771,15 +786,11 @@ static int tpacket_rcv(struct sk_buff *s
|
||||||
|
__packet_set_status(po, h.raw, status);
|
||||||
|
smp_mb();
|
||||||
|
{
|
||||||
|
- struct page *p_start, *p_end;
|
||||||
|
- u8 *h_end = h.raw + macoff + snaplen - 1;
|
||||||
|
+ u8 *start, *end;
|
||||||
|
|
||||||
|
- p_start = virt_to_page(h.raw);
|
||||||
|
- p_end = virt_to_page(h_end);
|
||||||
|
- while (p_start <= p_end) {
|
||||||
|
- flush_dcache_page(p_start);
|
||||||
|
- p_start++;
|
||||||
|
- }
|
||||||
|
+ end = (u8 *)PAGE_ALIGN((unsigned long)h.raw + macoff + snaplen);
|
||||||
|
+ for (start = h.raw; start < end; start += PAGE_SIZE)
|
||||||
|
+ flush_dcache_page(pgv_to_page(start));
|
||||||
|
}
|
||||||
|
|
||||||
|
sk->sk_data_ready(sk, 0);
|
||||||
|
@@ -886,7 +897,6 @@ static int tpacket_fill_skb(struct packe
|
||||||
|
}
|
||||||
|
|
||||||
|
err = -EFAULT;
|
||||||
|
- page = virt_to_page(data);
|
||||||
|
offset = offset_in_page(data);
|
||||||
|
len_max = PAGE_SIZE - offset;
|
||||||
|
len = ((to_write > len_max) ? len_max : to_write);
|
||||||
|
@@ -905,11 +915,11 @@ static int tpacket_fill_skb(struct packe
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ page = pgv_to_page(data);
|
||||||
|
+ data += len;
|
||||||
|
flush_dcache_page(page);
|
||||||
|
get_page(page);
|
||||||
|
- skb_fill_page_desc(skb,
|
||||||
|
- nr_frags,
|
||||||
|
- page++, offset, len);
|
||||||
|
+ skb_fill_page_desc(skb, nr_frags, page, offset, len);
|
||||||
|
to_write -= len;
|
||||||
|
offset = 0;
|
||||||
|
len_max = PAGE_SIZE;
|
||||||
|
@@ -2230,37 +2240,76 @@ static const struct vm_operations_struct
|
||||||
|
.close = packet_mm_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
-static void free_pg_vec(char **pg_vec, unsigned int order, unsigned int len)
|
||||||
|
+static void free_pg_vec(struct pgv *pg_vec, unsigned int order,
|
||||||
|
+ unsigned int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
- if (likely(pg_vec[i]))
|
||||||
|
- free_pages((unsigned long) pg_vec[i], order);
|
||||||
|
+ if (likely(pg_vec[i].buffer)) {
|
||||||
|
+ if (pg_vec[i].flags & PGV_FROM_VMALLOC)
|
||||||
|
+ vfree(pg_vec[i].buffer);
|
||||||
|
+ else
|
||||||
|
+ free_pages((unsigned long)pg_vec[i].buffer,
|
||||||
|
+ order);
|
||||||
|
+ pg_vec[i].buffer = NULL;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
kfree(pg_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static inline char *alloc_one_pg_vec_page(unsigned long order)
|
||||||
|
+static inline char *alloc_one_pg_vec_page(unsigned long order,
|
||||||
|
+ unsigned char *flags)
|
||||||
|
{
|
||||||
|
- gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | __GFP_ZERO | __GFP_NOWARN;
|
||||||
|
+ char *buffer = NULL;
|
||||||
|
+ gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP |
|
||||||
|
+ __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY;
|
||||||
|
+
|
||||||
|
+ buffer = (char *) __get_free_pages(gfp_flags, order);
|
||||||
|
|
||||||
|
- return (char *) __get_free_pages(gfp_flags, order);
|
||||||
|
+ if (buffer)
|
||||||
|
+ return buffer;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * __get_free_pages failed, fall back to vmalloc
|
||||||
|
+ */
|
||||||
|
+ *flags |= PGV_FROM_VMALLOC;
|
||||||
|
+ buffer = vmalloc((1 << order) * PAGE_SIZE);
|
||||||
|
+
|
||||||
|
+ if (buffer) {
|
||||||
|
+ memset(buffer, 0, (1 << order) * PAGE_SIZE);
|
||||||
|
+ return buffer;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * vmalloc failed, lets dig into swap here
|
||||||
|
+ */
|
||||||
|
+ *flags = 0;
|
||||||
|
+ gfp_flags &= ~__GFP_NORETRY;
|
||||||
|
+ buffer = (char *)__get_free_pages(gfp_flags, order);
|
||||||
|
+ if (buffer)
|
||||||
|
+ return buffer;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * complete and utter failure
|
||||||
|
+ */
|
||||||
|
+ return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static char **alloc_pg_vec(struct tpacket_req *req, int order)
|
||||||
|
+static struct pgv *alloc_pg_vec(struct tpacket_req *req, int order)
|
||||||
|
{
|
||||||
|
unsigned int block_nr = req->tp_block_nr;
|
||||||
|
- char **pg_vec;
|
||||||
|
+ struct pgv *pg_vec;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
- pg_vec = kzalloc(block_nr * sizeof(char *), GFP_KERNEL);
|
||||||
|
+ pg_vec = kcalloc(block_nr, sizeof(struct pgv), GFP_KERNEL);
|
||||||
|
if (unlikely(!pg_vec))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
for (i = 0; i < block_nr; i++) {
|
||||||
|
- pg_vec[i] = alloc_one_pg_vec_page(order);
|
||||||
|
- if (unlikely(!pg_vec[i]))
|
||||||
|
+ pg_vec[i].buffer = alloc_one_pg_vec_page(order,
|
||||||
|
+ &pg_vec[i].flags);
|
||||||
|
+ if (unlikely(!pg_vec[i].buffer))
|
||||||
|
goto out_free_pgvec;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -2276,7 +2325,7 @@ out_free_pgvec:
|
||||||
|
static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
|
||||||
|
int closing, int tx_ring)
|
||||||
|
{
|
||||||
|
- char **pg_vec = NULL;
|
||||||
|
+ struct pgv *pg_vec = NULL;
|
||||||
|
struct packet_sock *po = pkt_sk(sk);
|
||||||
|
int was_running, order = 0;
|
||||||
|
struct packet_ring_buffer *rb;
|
||||||
|
@@ -2438,15 +2487,22 @@ static int packet_mmap(struct file *file
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; i < rb->pg_vec_len; i++) {
|
||||||
|
- struct page *page = virt_to_page(rb->pg_vec[i]);
|
||||||
|
+ struct page *page;
|
||||||
|
+ void *kaddr = rb->pg_vec[i].buffer;
|
||||||
|
int pg_num;
|
||||||
|
|
||||||
|
for (pg_num = 0; pg_num < rb->pg_vec_pages;
|
||||||
|
- pg_num++, page++) {
|
||||||
|
+ pg_num++) {
|
||||||
|
+ if (rb->pg_vec[i].flags & PGV_FROM_VMALLOC)
|
||||||
|
+ page = vmalloc_to_page(kaddr);
|
||||||
|
+ else
|
||||||
|
+ page = virt_to_page(kaddr);
|
||||||
|
+
|
||||||
|
err = vm_insert_page(vma, start, page);
|
||||||
|
if (unlikely(err))
|
||||||
|
goto out;
|
||||||
|
start += PAGE_SIZE;
|
||||||
|
+ kaddr += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
From 38f1f0db010ac5b981ae06f1fe2fd64095ebb171 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Nelson Elhage <nelhage@ksplice.com>
|
||||||
|
Date: Wed, 3 Nov 2010 16:35:40 +0000
|
||||||
|
Subject: [PATCH] netlink: Make nlmsg_find_attr take a const nlmsghdr*.
|
||||||
|
|
||||||
|
This will let us use it on a nlmsghdr stored inside a netlink_callback.
|
||||||
|
|
||||||
|
Signed-off-by: Nelson Elhage <nelhage@ksplice.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
include/net/netlink.h | 2 +-
|
||||||
|
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/net/netlink.h b/include/net/netlink.h
|
||||||
|
index a63b219..c344646 100644
|
||||||
|
--- a/include/net/netlink.h
|
||||||
|
+++ b/include/net/netlink.h
|
||||||
|
@@ -384,7 +384,7 @@ static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,
|
||||||
|
*
|
||||||
|
* Returns the first attribute which matches the specified type.
|
||||||
|
*/
|
||||||
|
-static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh,
|
||||||
|
+static inline struct nlattr *nlmsg_find_attr(const struct nlmsghdr *nlh,
|
||||||
|
int hdrlen, int attrtype)
|
||||||
|
{
|
||||||
|
return nla_find(nlmsg_attrdata(nlh, hdrlen),
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
From 1b3df4f489345b0fd6e83645ad5d464aee55f7de Mon Sep 17 00:00:00 2001
|
||||||
|
From: David Kilroy <kilroyd@googlemail.com>
|
||||||
|
Date: Sat, 4 Dec 2010 18:36:30 +0000
|
||||||
|
Subject: [PATCH] orinoco: initialise priv->hw before assigning the interrupt
|
||||||
|
|
||||||
|
The interrupt handler takes a lock - but since commit bcad6e80f3f this
|
||||||
|
lock goes through an indirection specified in the hermes_t structure.
|
||||||
|
We must therefore initialise the structure before setting up the
|
||||||
|
interrupt handler.
|
||||||
|
|
||||||
|
<https://bugzilla.kernel.org/show_bug.cgi?id=23932>
|
||||||
|
|
||||||
|
Fix both orinoco_cs and spectrum_cs
|
||||||
|
|
||||||
|
Bisected by: Matt Domsch <Matt_Domsch@dell.com>
|
||||||
|
Tested by: Matt Domsch <Matt_Domsch@dell.com>
|
||||||
|
Signed-off by: David Kilroy <kilroyd@googlemail.com>
|
||||||
|
---
|
||||||
|
drivers/net/wireless/orinoco/orinoco_cs.c | 12 ++++++------
|
||||||
|
drivers/net/wireless/orinoco/spectrum_cs.c | 12 ++++++------
|
||||||
|
2 files changed, 12 insertions(+), 12 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
|
||||||
|
index b16d5db..66c7bcc 100644
|
||||||
|
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
|
||||||
|
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
|
||||||
|
@@ -251,19 +251,19 @@ orinoco_cs_config(struct pcmcia_device *link)
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
- ret = pcmcia_request_irq(link, orinoco_interrupt);
|
||||||
|
- if (ret)
|
||||||
|
+ mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
|
||||||
|
+ if (!mem)
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
/* We initialize the hermes structure before completing PCMCIA
|
||||||
|
* configuration just in case the interrupt handler gets
|
||||||
|
* called. */
|
||||||
|
- mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
|
||||||
|
- if (!mem)
|
||||||
|
- goto failed;
|
||||||
|
-
|
||||||
|
hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
|
||||||
|
|
||||||
|
+ ret = pcmcia_request_irq(link, orinoco_interrupt);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto failed;
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* This actually configures the PCMCIA socket -- setting up
|
||||||
|
* the I/O windows and the interrupt mapping, and putting the
|
||||||
|
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
|
||||||
|
index b51a9ad..0148763 100644
|
||||||
|
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
|
||||||
|
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
|
||||||
|
@@ -325,20 +325,20 @@ spectrum_cs_config(struct pcmcia_device *link)
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
- ret = pcmcia_request_irq(link, orinoco_interrupt);
|
||||||
|
- if (ret)
|
||||||
|
+ mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
|
||||||
|
+ if (!mem)
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
/* We initialize the hermes structure before completing PCMCIA
|
||||||
|
* configuration just in case the interrupt handler gets
|
||||||
|
* called. */
|
||||||
|
- mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
|
||||||
|
- if (!mem)
|
||||||
|
- goto failed;
|
||||||
|
-
|
||||||
|
hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
|
||||||
|
hw->eeprom_pda = true;
|
||||||
|
|
||||||
|
+ ret = pcmcia_request_irq(link, orinoco_interrupt);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto failed;
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* This actually configures the PCMCIA socket -- setting up
|
||||||
|
* the I/O windows and the interrupt mapping, and putting the
|
||||||
|
--
|
||||||
|
1.7.2.2
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
From linux-kernel-owner@vger.kernel.org Mon Dec 6 14:01:17 2010
|
||||||
|
From: Matthew Garrett <mjg@redhat.com>
|
||||||
|
To: linux-pci@vger.kernel.org
|
||||||
|
Cc: linux-kernel@vger.kernel.org, jbarnes@virtuousgeek.org,
|
||||||
|
Matthew Garrett <mjg@redhat.com>
|
||||||
|
Subject: [PATCH v2] PCI: Disable ASPM if BIOS asks us to
|
||||||
|
Date: Mon, 6 Dec 2010 14:00:56 -0500
|
||||||
|
Message-Id: <1291662056-6055-1-git-send-email-mjg@redhat.com>
|
||||||
|
|
||||||
|
We currently refuse to touch the ASPM registers if the BIOS tells us that
|
||||||
|
ASPM isn't supported. This can cause problems if the BIOS has (for any
|
||||||
|
reason) enabled ASPM on some devices anyway. Change the code such that we
|
||||||
|
explicitly clear ASPM if the FADT indicates that ASPM isn't supported,
|
||||||
|
and make sure we tidy up appropriately on device removal in order to deal
|
||||||
|
with the hotplug case. If ASPM is disabled because the BIOS doesn't hand
|
||||||
|
over control then we won't touch the registers.
|
||||||
|
|
||||||
|
Signed-off-by: Matthew Garrett <mjg@redhat.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
Implement Rafael's suggestion to use two separate functions, and also
|
||||||
|
ensure that we clear the clkpm bit as well as the ASPM bits.
|
||||||
|
|
||||||
|
drivers/pci/pci-acpi.c | 1 +
|
||||||
|
drivers/pci/pcie/aspm.c | 21 +++++++++++++++++----
|
||||||
|
include/linux/pci-aspm.h | 5 ++++-
|
||||||
|
3 files changed, 22 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
|
||||||
|
index 24e19c5..d7ea699 100644
|
||||||
|
--- a/drivers/pci/pci-acpi.c
|
||||||
|
+++ b/drivers/pci/pci-acpi.c
|
||||||
|
@@ -399,6 +399,7 @@ static int __init acpi_pci_init(void)
|
||||||
|
|
||||||
|
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
|
||||||
|
printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
|
||||||
|
+ pcie_clear_aspm();
|
||||||
|
pcie_no_aspm();
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
|
||||||
|
index 7122281..8112415 100644
|
||||||
|
--- a/drivers/pci/pcie/aspm.c
|
||||||
|
+++ b/drivers/pci/pcie/aspm.c
|
||||||
|
@@ -68,7 +68,7 @@ struct pcie_link_state {
|
||||||
|
struct aspm_latency acceptable[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
-static int aspm_disabled, aspm_force;
|
||||||
|
+static int aspm_disabled, aspm_force, aspm_clear_state;
|
||||||
|
static DEFINE_MUTEX(aspm_lock);
|
||||||
|
static LIST_HEAD(link_list);
|
||||||
|
|
||||||
|
@@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
|
||||||
|
{
|
||||||
|
/* Don't enable Clock PM if the link is not Clock PM capable */
|
||||||
|
if (!link->clkpm_capable && enable)
|
||||||
|
- return;
|
||||||
|
+ enable = 0;
|
||||||
|
/* Need nothing if the specified equals to current state */
|
||||||
|
if (link->clkpm_enabled == enable)
|
||||||
|
return;
|
||||||
|
@@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
|
||||||
|
struct pci_dev *child;
|
||||||
|
int pos;
|
||||||
|
u32 reg32;
|
||||||
|
+
|
||||||
|
+ if (aspm_clear_state)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Some functions in a slot might not all be PCIe functions,
|
||||||
|
* very strange. Disable ASPM for the whole slot
|
||||||
|
@@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
||||||
|
struct pcie_link_state *link;
|
||||||
|
int blacklist = !!pcie_aspm_sanity_check(pdev);
|
||||||
|
|
||||||
|
- if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state)
|
||||||
|
+ if (!pci_is_pcie(pdev) || pdev->link_state)
|
||||||
|
return;
|
||||||
|
if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
|
||||||
|
pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
|
||||||
|
return;
|
||||||
|
|
||||||
|
+ if (aspm_disabled && !aspm_clear_state)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
/* VIA has a strange chipset, root port is under a bridge */
|
||||||
|
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
|
||||||
|
pdev->bus->self)
|
||||||
|
@@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
|
||||||
|
struct pci_dev *parent = pdev->bus->self;
|
||||||
|
struct pcie_link_state *link, *root, *parent_link;
|
||||||
|
|
||||||
|
- if (aspm_disabled || !pci_is_pcie(pdev) ||
|
||||||
|
+ if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
|
||||||
|
!parent || !parent->link_state)
|
||||||
|
return;
|
||||||
|
if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
|
||||||
|
@@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str)
|
||||||
|
|
||||||
|
__setup("pcie_aspm=", pcie_aspm_disable);
|
||||||
|
|
||||||
|
+void pcie_clear_aspm(void)
|
||||||
|
+{
|
||||||
|
+ if (!aspm_force)
|
||||||
|
+ aspm_clear_state = 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void pcie_no_aspm(void)
|
||||||
|
{
|
||||||
|
if (!aspm_force)
|
||||||
|
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
|
||||||
|
index 91ba0b3..ce68105 100644
|
||||||
|
--- a/include/linux/pci-aspm.h
|
||||||
|
+++ b/include/linux/pci-aspm.h
|
||||||
|
@@ -27,6 +27,7 @@ extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
|
||||||
|
extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
|
||||||
|
extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
|
||||||
|
extern void pci_disable_link_state(struct pci_dev *pdev, int state);
|
||||||
|
+extern void pcie_clear_aspm(void);
|
||||||
|
extern void pcie_no_aspm(void);
|
||||||
|
#else
|
||||||
|
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
||||||
|
@@ -41,7 +42,9 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
|
||||||
|
static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+static inline void pcie_clear_aspm(void)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
static inline void pcie_no_aspm(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
||||||
|
--
|
||||||
|
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
|
||||||
|
the body of a message to majordomo@vger.kernel.org
|
||||||
|
More majordomo info at http://vger.kernel.org/majordomo-info.html
|
||||||
|
Please read the FAQ at http://www.tux.org/lkml/
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
From 8ba192510be47fc327c59449a4b5d347e9669329 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||||
|
Date: Wed, 29 Sep 2010 12:24:23 -0600
|
||||||
|
Subject: PNP: log PNP resources, as we do for PCI
|
||||||
|
|
||||||
|
ACPI devices are often involved in address space conflicts with PCI devices,
|
||||||
|
so I think it's worth logging the resources they use. Otherwise we have to
|
||||||
|
depend on lspnp or groping around in sysfs to find them.
|
||||||
|
|
||||||
|
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||||
|
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||||
|
---
|
||||||
|
drivers/pnp/core.c | 5 +++--
|
||||||
|
drivers/pnp/resource.c | 10 +++++-----
|
||||||
|
2 files changed, 8 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
|
||||||
|
index 5dba909..e457f99 100644
|
||||||
|
--- a/drivers/pnp/core.c
|
||||||
|
+++ b/drivers/pnp/core.c
|
||||||
|
@@ -191,8 +191,9 @@ int pnp_add_device(struct pnp_dev *dev)
|
||||||
|
for (id = dev->id; id; id = id->next)
|
||||||
|
len += scnprintf(buf + len, sizeof(buf) - len, " %s", id->id);
|
||||||
|
|
||||||
|
- pnp_dbg(&dev->dev, "%s device, IDs%s (%s)\n",
|
||||||
|
- dev->protocol->name, buf, dev->active ? "active" : "disabled");
|
||||||
|
+ dev_printk(KERN_DEBUG, &dev->dev, "%s device, IDs%s (%s)\n",
|
||||||
|
+ dev->protocol->name, buf,
|
||||||
|
+ dev->active ? "active" : "disabled");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
|
||||||
|
index e3446ab..a925e6b 100644
|
||||||
|
--- a/drivers/pnp/resource.c
|
||||||
|
+++ b/drivers/pnp/resource.c
|
||||||
|
@@ -523,7 +523,7 @@ struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
|
||||||
|
res->start = irq;
|
||||||
|
res->end = irq;
|
||||||
|
|
||||||
|
- pnp_dbg(&dev->dev, " add %pr\n", res);
|
||||||
|
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
|
||||||
|
return pnp_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -544,7 +544,7 @@ struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
|
||||||
|
res->start = dma;
|
||||||
|
res->end = dma;
|
||||||
|
|
||||||
|
- pnp_dbg(&dev->dev, " add %pr\n", res);
|
||||||
|
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
|
||||||
|
return pnp_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -568,7 +568,7 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
|
||||||
|
res->start = start;
|
||||||
|
res->end = end;
|
||||||
|
|
||||||
|
- pnp_dbg(&dev->dev, " add %pr\n", res);
|
||||||
|
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
|
||||||
|
return pnp_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -592,7 +592,7 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
|
||||||
|
res->start = start;
|
||||||
|
res->end = end;
|
||||||
|
|
||||||
|
- pnp_dbg(&dev->dev, " add %pr\n", res);
|
||||||
|
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
|
||||||
|
return pnp_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -616,7 +616,7 @@ struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev,
|
||||||
|
res->start = start;
|
||||||
|
res->end = end;
|
||||||
|
|
||||||
|
- pnp_dbg(&dev->dev, " add %pr\n", res);
|
||||||
|
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
|
||||||
|
return pnp_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
From 2876b1571839c25ce5e7485ead8417506d720c73 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Oleg Nesterov <oleg@redhat.com>
|
||||||
|
Date: Fri, 5 Nov 2010 16:53:42 +0100
|
||||||
|
Subject: posix-cpu-timers: workaround to suppress the problems with mt exec
|
||||||
|
|
||||||
|
posix-cpu-timers.c correctly assumes that the dying process does
|
||||||
|
posix_cpu_timers_exit_group() and removes all !CPUCLOCK_PERTHREAD
|
||||||
|
timers from signal->cpu_timers list.
|
||||||
|
|
||||||
|
But, it also assumes that timer->it.cpu.task is always the group
|
||||||
|
leader, and thus the dead ->task means the dead thread group.
|
||||||
|
|
||||||
|
This is obviously not true after de_thread() changes the leader.
|
||||||
|
After that almost every posix_cpu_timer_ method has problems.
|
||||||
|
|
||||||
|
It is not simple to fix this bug correctly. First of all, I think
|
||||||
|
that timer->it.cpu should use struct pid instead of task_struct.
|
||||||
|
Also, the locking should be reworked completely. In particular,
|
||||||
|
tasklist_lock should not be used at all. This all needs a lot of
|
||||||
|
nontrivial and hard-to-test changes.
|
||||||
|
|
||||||
|
Change __exit_signal() to do posix_cpu_timers_exit_group() when
|
||||||
|
the old leader dies during exec. This is not the fix, just the
|
||||||
|
temporary hack to hide the problem for 2.6.37 and stable. IOW,
|
||||||
|
this is obviously wrong but this is what we currently have anyway:
|
||||||
|
cpu timers do not work after mt exec.
|
||||||
|
|
||||||
|
In theory this change adds another race. The exiting leader can
|
||||||
|
detach the timers which were attached to the new leader. However,
|
||||||
|
the window between de_thread() and release_task() is small, we
|
||||||
|
can pretend that sys_timer_create() was called before de_thread().
|
||||||
|
|
||||||
|
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
|
||||||
|
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||||
|
---
|
||||||
|
kernel/exit.c | 8 ++++++++
|
||||||
|
1 files changed, 8 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/kernel/exit.c b/kernel/exit.c
|
||||||
|
index ac90425..85daf1d 100644
|
||||||
|
--- a/kernel/exit.c
|
||||||
|
+++ b/kernel/exit.c
|
||||||
|
@@ -95,6 +95,14 @@ static void __exit_signal(struct task_struct *tsk)
|
||||||
|
sig->tty = NULL;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
+ * This can only happen if the caller is de_thread().
|
||||||
|
+ * FIXME: this is the temporary hack, we should teach
|
||||||
|
+ * posix-cpu-timers to handle this case correctly.
|
||||||
|
+ */
|
||||||
|
+ if (unlikely(has_group_leader_pid(tsk)))
|
||||||
|
+ posix_cpu_timers_exit_group(tsk);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
* If there is any task waiting for the group exit
|
||||||
|
* then notify it:
|
||||||
|
*/
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
From 69b711c0c5e3d9cb3a5b9f741fb4cdc96b5739cb Mon Sep 17 00:00:00 2001
|
|
||||||
From: Kyle McMartin <kyle@dreadnought.i.jkkm.org>
|
|
||||||
Subject: Revert "drm/kms: disable/enable poll around switcheroo on/off"
|
|
||||||
|
|
||||||
This reverts commit fbf81762e385d3d45acad057b654d56972acf58c, mostly.
|
|
||||||
---
|
|
||||||
drivers/gpu/drm/i915/i915_dma.c | 4 +---
|
|
||||||
drivers/gpu/drm/nouveau/nouveau_state.c | 3 ---
|
|
||||||
drivers/gpu/drm/radeon/radeon_device.c | 2 --
|
|
||||||
|
|
||||||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
|
|
||||||
index 59a2bf8..2df3286 100644
|
|
||||||
--- a/drivers/gpu/drm/i915/i915_dma.c
|
|
||||||
+++ b/drivers/gpu/drm/i915/i915_dma.c
|
|
||||||
@@ -1320,14 +1320,12 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
|
|
||||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
|
||||||
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
|
|
||||||
if (state == VGA_SWITCHEROO_ON) {
|
|
||||||
- printk(KERN_INFO "i915: switched on\n");
|
|
||||||
+ printk(KERN_INFO "i915: switched off\n");
|
|
||||||
/* 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/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
|
|
||||||
index b02a231..0c28266 100644
|
|
||||||
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
|
|
||||||
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
|
|
||||||
@@ -376,15 +376,12 @@ out_err:
|
|
||||||
static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
|
|
||||||
enum vga_switcheroo_state state)
|
|
||||||
{
|
|
||||||
- struct drm_device *dev = pci_get_drvdata(pdev);
|
|
||||||
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
|
|
||||||
if (state == VGA_SWITCHEROO_ON) {
|
|
||||||
printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
|
|
||||||
nouveau_pci_resume(pdev);
|
|
||||||
- drm_kms_helper_poll_enable(dev);
|
|
||||||
} else {
|
|
||||||
printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
|
|
||||||
- drm_kms_helper_poll_disable(dev);
|
|
||||||
nouveau_pci_suspend(pdev, pmm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
|
|
||||||
index f10faed..225a9f2 100644
|
|
||||||
--- a/drivers/gpu/drm/radeon/radeon_device.c
|
|
||||||
+++ b/drivers/gpu/drm/radeon/radeon_device.c
|
|
||||||
@@ -546,10 +546,8 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
|
|
||||||
/* don't suspend or resume card normally */
|
|
||||||
rdev->powered_down = false;
|
|
||||||
radeon_resume_kms(dev);
|
|
||||||
- drm_kms_helper_poll_enable(dev);
|
|
||||||
} else {
|
|
||||||
printk(KERN_INFO "radeon: switched off\n");
|
|
||||||
- drm_kms_helper_poll_disable(dev);
|
|
||||||
radeon_suspend_kms(dev, pmm);
|
|
||||||
/* don't suspend or resume card normally */
|
|
||||||
rdev->powered_down = true;
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
commit 8b73fb8e29e9ae0458d36cc0dc25e2717587dfd4
|
||||||
|
Author: John W. Linville <linville@tuxdriver.com>
|
||||||
|
Date: Wed Jul 21 16:26:40 2010 -0400
|
||||||
|
|
||||||
|
rtl8180: improve signal reporting for actual rtl8180 hardware
|
||||||
|
|
||||||
|
Adapted from Realtek-provided driver...
|
||||||
|
|
||||||
|
Signed-off-by: John W. Linville <linville@tuxdriver.com>
|
||||||
|
Tested-by: Pauli Nieminen <suokkos@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
|
||||||
|
index 31808f9..d8b186a 100644
|
||||||
|
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
|
||||||
|
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
|
||||||
|
@@ -103,7 +103,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
|
||||||
|
{
|
||||||
|
struct rtl8180_priv *priv = dev->priv;
|
||||||
|
unsigned int count = 32;
|
||||||
|
- u8 signal;
|
||||||
|
+ u8 signal, agc, sq;
|
||||||
|
|
||||||
|
while (count--) {
|
||||||
|
struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
|
||||||
|
@@ -132,12 +132,16 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
|
||||||
|
|
||||||
|
rx_status.antenna = (flags2 >> 15) & 1;
|
||||||
|
rx_status.rate_idx = (flags >> 20) & 0xF;
|
||||||
|
- /* TODO: improve signal/rssi reporting for !rtl8185 */
|
||||||
|
- signal = (flags2 >> 17) & 0x7F;
|
||||||
|
- if (rx_status.rate_idx > 3)
|
||||||
|
- signal = 90 - clamp_t(u8, signal, 25, 90);
|
||||||
|
- else
|
||||||
|
- signal = 95 - clamp_t(u8, signal, 30, 95);
|
||||||
|
+ agc = (flags2 >> 17) & 0x7F;
|
||||||
|
+ if (priv->r8185) {
|
||||||
|
+ if (rx_status.rate_idx > 3)
|
||||||
|
+ signal = 90 - clamp_t(u8, agc, 25, 90);
|
||||||
|
+ else
|
||||||
|
+ signal = 95 - clamp_t(u8, agc, 30, 95);
|
||||||
|
+ } else {
|
||||||
|
+ sq = flags2 & 0xff;
|
||||||
|
+ signal = priv->rf->calc_rssi(agc, sq);
|
||||||
|
+ }
|
||||||
|
rx_status.signal = signal;
|
||||||
|
rx_status.freq = dev->conf.channel->center_freq;
|
||||||
|
rx_status.band = dev->conf.channel->band;
|
||||||
|
diff --git a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
|
||||||
|
index 947ee55..5cab9df 100644
|
||||||
|
--- a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
|
||||||
|
+++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
|
||||||
|
@@ -69,6 +69,15 @@ static void grf5101_write_phy_antenna(struct ieee80211_hw *dev, short chan)
|
||||||
|
rtl8180_write_phy(dev, 0x10, ant);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static u8 grf5101_rf_calc_rssi(u8 agc, u8 sq)
|
||||||
|
+{
|
||||||
|
+ if (agc > 60)
|
||||||
|
+ return 65;
|
||||||
|
+
|
||||||
|
+ /* TODO(?): just return agc (or agc + 5) to avoid mult / div */
|
||||||
|
+ return 65 * agc / 60;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void grf5101_rf_set_channel(struct ieee80211_hw *dev,
|
||||||
|
struct ieee80211_conf *conf)
|
||||||
|
{
|
||||||
|
@@ -176,5 +185,6 @@ const struct rtl818x_rf_ops grf5101_rf_ops = {
|
||||||
|
.name = "GCT",
|
||||||
|
.init = grf5101_rf_init,
|
||||||
|
.stop = grf5101_rf_stop,
|
||||||
|
- .set_chan = grf5101_rf_set_channel
|
||||||
|
+ .set_chan = grf5101_rf_set_channel,
|
||||||
|
+ .calc_rssi = grf5101_rf_calc_rssi,
|
||||||
|
};
|
||||||
|
diff --git a/drivers/net/wireless/rtl818x/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c
|
||||||
|
index 6c825fd..16c4655 100644
|
||||||
|
--- a/drivers/net/wireless/rtl818x/rtl8180_max2820.c
|
||||||
|
+++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.c
|
||||||
|
@@ -74,6 +74,22 @@ static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan)
|
||||||
|
rtl8180_write_phy(dev, 0x10, ant);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static u8 max2820_rf_calc_rssi(u8 agc, u8 sq)
|
||||||
|
+{
|
||||||
|
+ bool odd;
|
||||||
|
+
|
||||||
|
+ odd = !!(agc & 1);
|
||||||
|
+
|
||||||
|
+ agc >>= 1;
|
||||||
|
+ if (odd)
|
||||||
|
+ agc += 76;
|
||||||
|
+ else
|
||||||
|
+ agc += 66;
|
||||||
|
+
|
||||||
|
+ /* TODO: change addends above to avoid mult / div below */
|
||||||
|
+ return 65 * agc / 100;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void max2820_rf_set_channel(struct ieee80211_hw *dev,
|
||||||
|
struct ieee80211_conf *conf)
|
||||||
|
{
|
||||||
|
@@ -148,5 +164,6 @@ const struct rtl818x_rf_ops max2820_rf_ops = {
|
||||||
|
.name = "Maxim",
|
||||||
|
.init = max2820_rf_init,
|
||||||
|
.stop = max2820_rf_stop,
|
||||||
|
- .set_chan = max2820_rf_set_channel
|
||||||
|
+ .set_chan = max2820_rf_set_channel,
|
||||||
|
+ .calc_rssi = max2820_rf_calc_rssi,
|
||||||
|
};
|
||||||
|
diff --git a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
|
||||||
|
index cea4e0c..d064fcc 100644
|
||||||
|
--- a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
|
||||||
|
+++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
|
||||||
|
@@ -76,6 +76,31 @@ static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
+static u8 sa2400_rf_rssi_map[] = {
|
||||||
|
+ 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e,
|
||||||
|
+ 0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50,
|
||||||
|
+ 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f,
|
||||||
|
+ 0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b,
|
||||||
|
+ 0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17,
|
||||||
|
+ 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13,
|
||||||
|
+ 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f,
|
||||||
|
+ 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
|
||||||
|
+ 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07,
|
||||||
|
+ 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static u8 sa2400_rf_calc_rssi(u8 agc, u8 sq)
|
||||||
|
+{
|
||||||
|
+ if (sq == 0x80)
|
||||||
|
+ return 1;
|
||||||
|
+
|
||||||
|
+ if (sq > 78)
|
||||||
|
+ return 32;
|
||||||
|
+
|
||||||
|
+ /* TODO: recalc sa2400_rf_rssi_map to avoid mult / div */
|
||||||
|
+ return 65 * sa2400_rf_rssi_map[sq] / 100;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void sa2400_rf_set_channel(struct ieee80211_hw *dev,
|
||||||
|
struct ieee80211_conf *conf)
|
||||||
|
{
|
||||||
|
@@ -198,5 +223,6 @@ const struct rtl818x_rf_ops sa2400_rf_ops = {
|
||||||
|
.name = "Philips",
|
||||||
|
.init = sa2400_rf_init,
|
||||||
|
.stop = sa2400_rf_stop,
|
||||||
|
- .set_chan = sa2400_rf_set_channel
|
||||||
|
+ .set_chan = sa2400_rf_set_channel,
|
||||||
|
+ .calc_rssi = sa2400_rf_calc_rssi,
|
||||||
|
};
|
||||||
|
diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
|
||||||
|
index 8522490..22d9384 100644
|
||||||
|
--- a/drivers/net/wireless/rtl818x/rtl818x.h
|
||||||
|
+++ b/drivers/net/wireless/rtl818x/rtl818x.h
|
||||||
|
@@ -193,6 +193,7 @@ struct rtl818x_rf_ops {
|
||||||
|
void (*stop)(struct ieee80211_hw *);
|
||||||
|
void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
|
||||||
|
void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *);
|
||||||
|
+ u8 (*calc_rssi)(u8 agc, u8 sq);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
|
@ -0,0 +1,43 @@
|
||||||
|
commit 8b74964c73ca9eed7078388d871cc7fae973cb63
|
||||||
|
Author: John W. Linville <linville@tuxdriver.com>
|
||||||
|
Date: Mon Jul 19 16:35:20 2010 -0400
|
||||||
|
|
||||||
|
rtl8180: improve signal reporting for rtl8185 hardware
|
||||||
|
|
||||||
|
The existing code seemed to be somewhat based on the datasheet, but
|
||||||
|
varied substantially from the vendor-provided driver. This mirrors the
|
||||||
|
handling of the rtl8185 case from that driver, but still neglects the
|
||||||
|
specifics for the rtl8180 hardware. Those details are a bit muddled...
|
||||||
|
|
||||||
|
Signed-off-by: John W. Linville <linville@tuxdriver.com>
|
||||||
|
|
||||||
|
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
|
||||||
|
index 4270502..31808f9 100644
|
||||||
|
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
|
||||||
|
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
|
||||||
|
@@ -103,6 +103,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
|
||||||
|
{
|
||||||
|
struct rtl8180_priv *priv = dev->priv;
|
||||||
|
unsigned int count = 32;
|
||||||
|
+ u8 signal;
|
||||||
|
|
||||||
|
while (count--) {
|
||||||
|
struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
|
||||||
|
@@ -130,10 +131,14 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
|
||||||
|
skb_put(skb, flags & 0xFFF);
|
||||||
|
|
||||||
|
rx_status.antenna = (flags2 >> 15) & 1;
|
||||||
|
- /* TODO: improve signal/rssi reporting */
|
||||||
|
- rx_status.signal = (flags2 >> 8) & 0x7F;
|
||||||
|
- /* XXX: is this correct? */
|
||||||
|
rx_status.rate_idx = (flags >> 20) & 0xF;
|
||||||
|
+ /* TODO: improve signal/rssi reporting for !rtl8185 */
|
||||||
|
+ signal = (flags2 >> 17) & 0x7F;
|
||||||
|
+ if (rx_status.rate_idx > 3)
|
||||||
|
+ signal = 90 - clamp_t(u8, signal, 25, 90);
|
||||||
|
+ else
|
||||||
|
+ signal = 95 - clamp_t(u8, signal, 30, 95);
|
||||||
|
+ rx_status.signal = signal;
|
||||||
|
rx_status.freq = dev->conf.channel->center_freq;
|
||||||
|
rx_status.band = dev->conf.channel->band;
|
||||||
|
rx_status.mactime = le64_to_cpu(entry->tsft);
|
|
@ -0,0 +1,276 @@
|
||||||
|
From: Venkatesh Pallipadi <venki@google.com>
|
||||||
|
Date: Tue, 18 May 2010 01:14:43 +0000 (-0700)
|
||||||
|
Subject: sched: Avoid side-effect of tickless idle on update_cpu_load
|
||||||
|
X-Git-Tag: v2.6.36-rc1~531^2~22
|
||||||
|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=fdf3e95d3916f18bf8703fb065499fdbc4dfe34c
|
||||||
|
|
||||||
|
sched: Avoid side-effect of tickless idle on update_cpu_load
|
||||||
|
|
||||||
|
tickless idle has a negative side effect on update_cpu_load(), which
|
||||||
|
in turn can affect load balancing behavior.
|
||||||
|
|
||||||
|
update_cpu_load() is supposed to be called every tick, to keep track
|
||||||
|
of various load indicies. With tickless idle, there are no scheduler
|
||||||
|
ticks called on the idle CPUs. Idle CPUs may still do load balancing
|
||||||
|
(with idle_load_balance CPU) using the stale cpu_load. It will also
|
||||||
|
cause problems when all CPUs go idle for a while and become active
|
||||||
|
again. In this case loads would not degrade as expected.
|
||||||
|
|
||||||
|
This is how rq->nr_load_updates change looks like under different
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
<cpu_num> <nr_load_updates change>
|
||||||
|
All CPUS idle for 10 seconds (HZ=1000)
|
||||||
|
0 1621
|
||||||
|
10 496
|
||||||
|
11 139
|
||||||
|
12 875
|
||||||
|
13 1672
|
||||||
|
14 12
|
||||||
|
15 21
|
||||||
|
1 1472
|
||||||
|
2 2426
|
||||||
|
3 1161
|
||||||
|
4 2108
|
||||||
|
5 1525
|
||||||
|
6 701
|
||||||
|
7 249
|
||||||
|
8 766
|
||||||
|
9 1967
|
||||||
|
|
||||||
|
One CPU busy rest idle for 10 seconds
|
||||||
|
0 10003
|
||||||
|
10 601
|
||||||
|
11 95
|
||||||
|
12 966
|
||||||
|
13 1597
|
||||||
|
14 114
|
||||||
|
15 98
|
||||||
|
1 3457
|
||||||
|
2 93
|
||||||
|
3 6679
|
||||||
|
4 1425
|
||||||
|
5 1479
|
||||||
|
6 595
|
||||||
|
7 193
|
||||||
|
8 633
|
||||||
|
9 1687
|
||||||
|
|
||||||
|
All CPUs busy for 10 seconds
|
||||||
|
0 10026
|
||||||
|
10 10026
|
||||||
|
11 10026
|
||||||
|
12 10026
|
||||||
|
13 10025
|
||||||
|
14 10025
|
||||||
|
15 10025
|
||||||
|
1 10026
|
||||||
|
2 10026
|
||||||
|
3 10026
|
||||||
|
4 10026
|
||||||
|
5 10026
|
||||||
|
6 10026
|
||||||
|
7 10026
|
||||||
|
8 10026
|
||||||
|
9 10026
|
||||||
|
|
||||||
|
That is update_cpu_load works properly only when all CPUs are busy.
|
||||||
|
If all are idle, all the CPUs get way lower updates. And when few
|
||||||
|
CPUs are busy and rest are idle, only busy and ilb CPU does proper
|
||||||
|
updates and rest of the idle CPUs will do lower updates.
|
||||||
|
|
||||||
|
The patch keeps track of when a last update was done and fixes up
|
||||||
|
the load avg based on current time.
|
||||||
|
|
||||||
|
On one of my test system SPECjbb with warehouse 1..numcpus, patch
|
||||||
|
improves throughput numbers by ~1% (average of 6 runs). On another
|
||||||
|
test system (with different domain hierarchy) there is no noticable
|
||||||
|
change in perf.
|
||||||
|
|
||||||
|
Signed-off-by: Venkatesh Pallipadi <venki@google.com>
|
||||||
|
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
Cc: Thomas Gleixner <tglx@linutronix.de>
|
||||||
|
LKML-Reference: <AANLkTilLtDWQsAUrIxJ6s04WTgmw9GuOODc5AOrYsaR5@mail.gmail.com>
|
||||||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/kernel/sched.c b/kernel/sched.c
|
||||||
|
index f37a961..a757f6b 100644
|
||||||
|
--- a/kernel/sched.c
|
||||||
|
+++ b/kernel/sched.c
|
||||||
|
@@ -457,6 +457,7 @@ struct rq {
|
||||||
|
unsigned long nr_running;
|
||||||
|
#define CPU_LOAD_IDX_MAX 5
|
||||||
|
unsigned long cpu_load[CPU_LOAD_IDX_MAX];
|
||||||
|
+ unsigned long last_load_update_tick;
|
||||||
|
#ifdef CONFIG_NO_HZ
|
||||||
|
u64 nohz_stamp;
|
||||||
|
unsigned char in_nohz_recently;
|
||||||
|
@@ -1803,6 +1804,7 @@ static void cfs_rq_set_shares(struct cfs_rq *cfs_rq, unsigned long shares)
|
||||||
|
static void calc_load_account_idle(struct rq *this_rq);
|
||||||
|
static void update_sysctl(void);
|
||||||
|
static int get_update_sysctl_factor(void);
|
||||||
|
+static void update_cpu_load(struct rq *this_rq);
|
||||||
|
|
||||||
|
static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
|
||||||
|
{
|
||||||
|
@@ -3050,23 +3052,102 @@ static void calc_load_account_active(struct rq *this_rq)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
+ * The exact cpuload at various idx values, calculated at every tick would be
|
||||||
|
+ * load = (2^idx - 1) / 2^idx * load + 1 / 2^idx * cur_load
|
||||||
|
+ *
|
||||||
|
+ * If a cpu misses updates for n-1 ticks (as it was idle) and update gets called
|
||||||
|
+ * on nth tick when cpu may be busy, then we have:
|
||||||
|
+ * load = ((2^idx - 1) / 2^idx)^(n-1) * load
|
||||||
|
+ * load = (2^idx - 1) / 2^idx) * load + 1 / 2^idx * cur_load
|
||||||
|
+ *
|
||||||
|
+ * decay_load_missed() below does efficient calculation of
|
||||||
|
+ * load = ((2^idx - 1) / 2^idx)^(n-1) * load
|
||||||
|
+ * avoiding 0..n-1 loop doing load = ((2^idx - 1) / 2^idx) * load
|
||||||
|
+ *
|
||||||
|
+ * The calculation is approximated on a 128 point scale.
|
||||||
|
+ * degrade_zero_ticks is the number of ticks after which load at any
|
||||||
|
+ * particular idx is approximated to be zero.
|
||||||
|
+ * degrade_factor is a precomputed table, a row for each load idx.
|
||||||
|
+ * Each column corresponds to degradation factor for a power of two ticks,
|
||||||
|
+ * based on 128 point scale.
|
||||||
|
+ * Example:
|
||||||
|
+ * row 2, col 3 (=12) says that the degradation at load idx 2 after
|
||||||
|
+ * 8 ticks is 12/128 (which is an approximation of exact factor 3^8/4^8).
|
||||||
|
+ *
|
||||||
|
+ * With this power of 2 load factors, we can degrade the load n times
|
||||||
|
+ * by looking at 1 bits in n and doing as many mult/shift instead of
|
||||||
|
+ * n mult/shifts needed by the exact degradation.
|
||||||
|
+ */
|
||||||
|
+#define DEGRADE_SHIFT 7
|
||||||
|
+static const unsigned char
|
||||||
|
+ degrade_zero_ticks[CPU_LOAD_IDX_MAX] = {0, 8, 32, 64, 128};
|
||||||
|
+static const unsigned char
|
||||||
|
+ degrade_factor[CPU_LOAD_IDX_MAX][DEGRADE_SHIFT + 1] = {
|
||||||
|
+ {0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
+ {64, 32, 8, 0, 0, 0, 0, 0},
|
||||||
|
+ {96, 72, 40, 12, 1, 0, 0},
|
||||||
|
+ {112, 98, 75, 43, 15, 1, 0},
|
||||||
|
+ {120, 112, 98, 76, 45, 16, 2} };
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Update cpu_load for any missed ticks, due to tickless idle. The backlog
|
||||||
|
+ * would be when CPU is idle and so we just decay the old load without
|
||||||
|
+ * adding any new load.
|
||||||
|
+ */
|
||||||
|
+static unsigned long
|
||||||
|
+decay_load_missed(unsigned long load, unsigned long missed_updates, int idx)
|
||||||
|
+{
|
||||||
|
+ int j = 0;
|
||||||
|
+
|
||||||
|
+ if (!missed_updates)
|
||||||
|
+ return load;
|
||||||
|
+
|
||||||
|
+ if (missed_updates >= degrade_zero_ticks[idx])
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ if (idx == 1)
|
||||||
|
+ return load >> missed_updates;
|
||||||
|
+
|
||||||
|
+ while (missed_updates) {
|
||||||
|
+ if (missed_updates % 2)
|
||||||
|
+ load = (load * degrade_factor[idx][j]) >> DEGRADE_SHIFT;
|
||||||
|
+
|
||||||
|
+ missed_updates >>= 1;
|
||||||
|
+ j++;
|
||||||
|
+ }
|
||||||
|
+ return load;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
* Update rq->cpu_load[] statistics. This function is usually called every
|
||||||
|
- * scheduler tick (TICK_NSEC).
|
||||||
|
+ * scheduler tick (TICK_NSEC). With tickless idle this will not be called
|
||||||
|
+ * every tick. We fix it up based on jiffies.
|
||||||
|
*/
|
||||||
|
static void update_cpu_load(struct rq *this_rq)
|
||||||
|
{
|
||||||
|
unsigned long this_load = this_rq->load.weight;
|
||||||
|
+ unsigned long curr_jiffies = jiffies;
|
||||||
|
+ unsigned long pending_updates;
|
||||||
|
int i, scale;
|
||||||
|
|
||||||
|
this_rq->nr_load_updates++;
|
||||||
|
|
||||||
|
+ /* Avoid repeated calls on same jiffy, when moving in and out of idle */
|
||||||
|
+ if (curr_jiffies == this_rq->last_load_update_tick)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ pending_updates = curr_jiffies - this_rq->last_load_update_tick;
|
||||||
|
+ this_rq->last_load_update_tick = curr_jiffies;
|
||||||
|
+
|
||||||
|
/* Update our load: */
|
||||||
|
- for (i = 0, scale = 1; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
|
||||||
|
+ this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */
|
||||||
|
+ for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
|
||||||
|
unsigned long old_load, new_load;
|
||||||
|
|
||||||
|
/* scale is effectively 1 << i now, and >> i divides by scale */
|
||||||
|
|
||||||
|
old_load = this_rq->cpu_load[i];
|
||||||
|
+ old_load = decay_load_missed(old_load, pending_updates - 1, i);
|
||||||
|
new_load = this_load;
|
||||||
|
/*
|
||||||
|
* Round up the averaging division if load is increasing. This
|
||||||
|
@@ -3074,9 +3155,15 @@ static void update_cpu_load(struct rq *this_rq)
|
||||||
|
* example.
|
||||||
|
*/
|
||||||
|
if (new_load > old_load)
|
||||||
|
- new_load += scale-1;
|
||||||
|
- this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i;
|
||||||
|
+ new_load += scale - 1;
|
||||||
|
+
|
||||||
|
+ this_rq->cpu_load[i] = (old_load * (scale - 1) + new_load) >> i;
|
||||||
|
}
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void update_cpu_load_active(struct rq *this_rq)
|
||||||
|
+{
|
||||||
|
+ update_cpu_load(this_rq);
|
||||||
|
|
||||||
|
calc_load_account_active(this_rq);
|
||||||
|
}
|
||||||
|
@@ -3464,7 +3551,7 @@ void scheduler_tick(void)
|
||||||
|
|
||||||
|
raw_spin_lock(&rq->lock);
|
||||||
|
update_rq_clock(rq);
|
||||||
|
- update_cpu_load(rq);
|
||||||
|
+ update_cpu_load_active(rq);
|
||||||
|
curr->sched_class->task_tick(rq, curr, 0);
|
||||||
|
raw_spin_unlock(&rq->lock);
|
||||||
|
|
||||||
|
@@ -7688,6 +7775,9 @@ void __init sched_init(void)
|
||||||
|
|
||||||
|
for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
|
||||||
|
rq->cpu_load[j] = 0;
|
||||||
|
+
|
||||||
|
+ rq->last_load_update_tick = jiffies;
|
||||||
|
+
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
rq->sd = NULL;
|
||||||
|
rq->rd = NULL;
|
||||||
|
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
|
||||||
|
index eed35ed..22b8b4f 100644
|
||||||
|
--- a/kernel/sched_fair.c
|
||||||
|
+++ b/kernel/sched_fair.c
|
||||||
|
@@ -3420,9 +3420,12 @@ static void run_rebalance_domains(struct softirq_action *h)
|
||||||
|
if (need_resched())
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ rq = cpu_rq(balance_cpu);
|
||||||
|
+ raw_spin_lock_irq(&rq->lock);
|
||||||
|
+ update_cpu_load(rq);
|
||||||
|
+ raw_spin_unlock_irq(&rq->lock);
|
||||||
|
rebalance_domains(balance_cpu, CPU_IDLE);
|
||||||
|
|
||||||
|
- rq = cpu_rq(balance_cpu);
|
||||||
|
if (time_after(this_rq->next_balance, rq->next_balance))
|
||||||
|
this_rq->next_balance = rq->next_balance;
|
||||||
|
}
|
|
@ -0,0 +1,651 @@
|
||||||
|
From: Venkatesh Pallipadi <venki@google.com>
|
||||||
|
Date: Sat, 22 May 2010 00:09:41 +0000 (-0700)
|
||||||
|
Subject: sched: Change nohz idle load balancing logic to push model
|
||||||
|
X-Git-Tag: v2.6.36-rc1~531^2~21
|
||||||
|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=83cd4fe27ad8446619b2e030b171b858501de87d
|
||||||
|
|
||||||
|
sched: Change nohz idle load balancing logic to push model
|
||||||
|
|
||||||
|
In the new push model, all idle CPUs indeed go into nohz mode. There is
|
||||||
|
still the concept of idle load balancer (performing the load balancing
|
||||||
|
on behalf of all the idle cpu's in the system). Busy CPU kicks the nohz
|
||||||
|
balancer when any of the nohz CPUs need idle load balancing.
|
||||||
|
The kickee CPU does the idle load balancing on behalf of all idle CPUs
|
||||||
|
instead of the normal idle balance.
|
||||||
|
|
||||||
|
This addresses the below two problems with the current nohz ilb logic:
|
||||||
|
* the idle load balancer continued to have periodic ticks during idle and
|
||||||
|
wokeup frequently, even though it did not have any rebalancing to do on
|
||||||
|
behalf of any of the idle CPUs.
|
||||||
|
* On x86 and CPUs that have APIC timer stoppage on idle CPUs, this
|
||||||
|
periodic wakeup can result in a periodic additional interrupt on a CPU
|
||||||
|
doing the timer broadcast.
|
||||||
|
|
||||||
|
Also currently we are migrating the unpinned timers from an idle to the cpu
|
||||||
|
doing idle load balancing (when all the cpus in the system are idle,
|
||||||
|
there is no idle load balancing cpu and timers get added to the same idle cpu
|
||||||
|
where the request was made. So the existing optimization works only on semi idle
|
||||||
|
system).
|
||||||
|
|
||||||
|
And In semi idle system, we no longer have periodic ticks on the idle load
|
||||||
|
balancer CPU. Using that cpu will add more delays to the timers than intended
|
||||||
|
(as that cpu's timer base may not be uptodate wrt jiffies etc). This was
|
||||||
|
causing mysterious slowdowns during boot etc.
|
||||||
|
|
||||||
|
For now, in the semi idle case, use the nearest busy cpu for migrating timers
|
||||||
|
from an idle cpu. This is good for power-savings anyway.
|
||||||
|
|
||||||
|
Signed-off-by: Venkatesh Pallipadi <venki@google.com>
|
||||||
|
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
|
||||||
|
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
Cc: Thomas Gleixner <tglx@linutronix.de>
|
||||||
|
LKML-Reference: <1274486981.2840.46.camel@sbs-t61.sc.intel.com>
|
||||||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||||
|
---
|
||||||
|
|
||||||
|
[ backported for 2.6.35 ]
|
||||||
|
|
||||||
|
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
||||||
|
index c2d4316..a3e5b1c 100644
|
||||||
|
--- a/include/linux/sched.h
|
||||||
|
+++ b/include/linux/sched.h
|
||||||
|
@@ -271,13 +271,10 @@ extern int runqueue_is_locked(int cpu);
|
||||||
|
|
||||||
|
extern cpumask_var_t nohz_cpu_mask;
|
||||||
|
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ)
|
||||||
|
-extern int select_nohz_load_balancer(int cpu);
|
||||||
|
-extern int get_nohz_load_balancer(void);
|
||||||
|
+extern void select_nohz_load_balancer(int stop_tick);
|
||||||
|
+extern int get_nohz_timer_target(void);
|
||||||
|
#else
|
||||||
|
-static inline int select_nohz_load_balancer(int cpu)
|
||||||
|
-{
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
+static inline void select_nohz_load_balancer(int stop_tick) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
|
||||||
|
index 5c69e99..e934339 100644
|
||||||
|
--- a/kernel/hrtimer.c
|
||||||
|
+++ b/kernel/hrtimer.c
|
||||||
|
@@ -144,12 +144,8 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
|
||||||
|
static int hrtimer_get_target(int this_cpu, int pinned)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_NO_HZ
|
||||||
|
- if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu)) {
|
||||||
|
- int preferred_cpu = get_nohz_load_balancer();
|
||||||
|
-
|
||||||
|
- if (preferred_cpu >= 0)
|
||||||
|
- return preferred_cpu;
|
||||||
|
- }
|
||||||
|
+ if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu))
|
||||||
|
+ return get_nohz_timer_target();
|
||||||
|
#endif
|
||||||
|
return this_cpu;
|
||||||
|
}
|
||||||
|
diff --git a/kernel/sched.c b/kernel/sched.c
|
||||||
|
index a757f6b..132950b 100644
|
||||||
|
--- a/kernel/sched.c
|
||||||
|
+++ b/kernel/sched.c
|
||||||
|
@@ -460,7 +460,7 @@ struct rq {
|
||||||
|
unsigned long last_load_update_tick;
|
||||||
|
#ifdef CONFIG_NO_HZ
|
||||||
|
u64 nohz_stamp;
|
||||||
|
- unsigned char in_nohz_recently;
|
||||||
|
+ unsigned char nohz_balance_kick;
|
||||||
|
#endif
|
||||||
|
unsigned int skip_clock_update;
|
||||||
|
|
||||||
|
@@ -1195,6 +1195,27 @@ static void resched_cpu(int cpu)
|
||||||
|
|
||||||
|
#ifdef CONFIG_NO_HZ
|
||||||
|
/*
|
||||||
|
+ * In the semi idle case, use the nearest busy cpu for migrating timers
|
||||||
|
+ * from an idle cpu. This is good for power-savings.
|
||||||
|
+ *
|
||||||
|
+ * We don't do similar optimization for completely idle system, as
|
||||||
|
+ * selecting an idle cpu will add more delays to the timers than intended
|
||||||
|
+ * (as that cpu's timer base may not be uptodate wrt jiffies etc).
|
||||||
|
+ */
|
||||||
|
+int get_nohz_timer_target(void)
|
||||||
|
+{
|
||||||
|
+ int cpu = smp_processor_id();
|
||||||
|
+ int i;
|
||||||
|
+ struct sched_domain *sd;
|
||||||
|
+
|
||||||
|
+ for_each_domain(cpu, sd) {
|
||||||
|
+ for_each_cpu(i, sched_domain_span(sd))
|
||||||
|
+ if (!idle_cpu(i))
|
||||||
|
+ return i;
|
||||||
|
+ }
|
||||||
|
+ return cpu;
|
||||||
|
+}
|
||||||
|
+/*
|
||||||
|
* When add_timer_on() enqueues a timer into the timer wheel of an
|
||||||
|
* idle CPU then this timer might expire before the next timer event
|
||||||
|
* which is scheduled to wake up that CPU. In case of a completely
|
||||||
|
@@ -7791,6 +7812,10 @@ void __init sched_init(void)
|
||||||
|
rq->idle_stamp = 0;
|
||||||
|
rq->avg_idle = 2*sysctl_sched_migration_cost;
|
||||||
|
rq_attach_root(rq, &def_root_domain);
|
||||||
|
+#ifdef CONFIG_NO_HZ
|
||||||
|
+ rq->nohz_balance_kick = 0;
|
||||||
|
+ init_sched_softirq_csd(&per_cpu(remote_sched_softirq_cb, i));
|
||||||
|
+#endif
|
||||||
|
#endif
|
||||||
|
init_rq_hrtick(rq);
|
||||||
|
atomic_set(&rq->nr_iowait, 0);
|
||||||
|
@@ -7835,8 +7860,11 @@ void __init sched_init(void)
|
||||||
|
zalloc_cpumask_var(&nohz_cpu_mask, GFP_NOWAIT);
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
#ifdef CONFIG_NO_HZ
|
||||||
|
- zalloc_cpumask_var(&nohz.cpu_mask, GFP_NOWAIT);
|
||||||
|
- alloc_cpumask_var(&nohz.ilb_grp_nohz_mask, GFP_NOWAIT);
|
||||||
|
+ zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT);
|
||||||
|
+ alloc_cpumask_var(&nohz.grp_idle_mask, GFP_NOWAIT);
|
||||||
|
+ atomic_set(&nohz.load_balancer, nr_cpu_ids);
|
||||||
|
+ atomic_set(&nohz.first_pick_cpu, nr_cpu_ids);
|
||||||
|
+ atomic_set(&nohz.second_pick_cpu, nr_cpu_ids);
|
||||||
|
#endif
|
||||||
|
/* May be allocated at isolcpus cmdline parse time */
|
||||||
|
if (cpu_isolated_map == NULL)
|
||||||
|
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
|
||||||
|
index 22b8b4f..6ee2e0a 100644
|
||||||
|
--- a/kernel/sched_fair.c
|
||||||
|
+++ b/kernel/sched_fair.c
|
||||||
|
@@ -3091,13 +3091,40 @@ out_unlock:
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_NO_HZ
|
||||||
|
+
|
||||||
|
+static DEFINE_PER_CPU(struct call_single_data, remote_sched_softirq_cb);
|
||||||
|
+
|
||||||
|
+static void trigger_sched_softirq(void *data)
|
||||||
|
+{
|
||||||
|
+ raise_softirq_irqoff(SCHED_SOFTIRQ);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void init_sched_softirq_csd(struct call_single_data *csd)
|
||||||
|
+{
|
||||||
|
+ csd->func = trigger_sched_softirq;
|
||||||
|
+ csd->info = NULL;
|
||||||
|
+ csd->flags = 0;
|
||||||
|
+ csd->priv = 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * idle load balancing details
|
||||||
|
+ * - One of the idle CPUs nominates itself as idle load_balancer, while
|
||||||
|
+ * entering idle.
|
||||||
|
+ * - This idle load balancer CPU will also go into tickless mode when
|
||||||
|
+ * it is idle, just like all other idle CPUs
|
||||||
|
+ * - When one of the busy CPUs notice that there may be an idle rebalancing
|
||||||
|
+ * needed, they will kick the idle load balancer, which then does idle
|
||||||
|
+ * load balancing for all the idle CPUs.
|
||||||
|
+ */
|
||||||
|
static struct {
|
||||||
|
atomic_t load_balancer;
|
||||||
|
- cpumask_var_t cpu_mask;
|
||||||
|
- cpumask_var_t ilb_grp_nohz_mask;
|
||||||
|
-} nohz ____cacheline_aligned = {
|
||||||
|
- .load_balancer = ATOMIC_INIT(-1),
|
||||||
|
-};
|
||||||
|
+ atomic_t first_pick_cpu;
|
||||||
|
+ atomic_t second_pick_cpu;
|
||||||
|
+ cpumask_var_t idle_cpus_mask;
|
||||||
|
+ cpumask_var_t grp_idle_mask;
|
||||||
|
+ unsigned long next_balance; /* in jiffy units */
|
||||||
|
+} nohz ____cacheline_aligned;
|
||||||
|
|
||||||
|
int get_nohz_load_balancer(void)
|
||||||
|
{
|
||||||
|
@@ -3151,17 +3178,17 @@ static inline struct sched_domain *lowest_flag_domain(int cpu, int flag)
|
||||||
|
*/
|
||||||
|
static inline int is_semi_idle_group(struct sched_group *ilb_group)
|
||||||
|
{
|
||||||
|
- cpumask_and(nohz.ilb_grp_nohz_mask, nohz.cpu_mask,
|
||||||
|
+ cpumask_and(nohz.grp_idle_mask, nohz.idle_cpus_mask,
|
||||||
|
sched_group_cpus(ilb_group));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A sched_group is semi-idle when it has atleast one busy cpu
|
||||||
|
* and atleast one idle cpu.
|
||||||
|
*/
|
||||||
|
- if (cpumask_empty(nohz.ilb_grp_nohz_mask))
|
||||||
|
+ if (cpumask_empty(nohz.grp_idle_mask))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- if (cpumask_equal(nohz.ilb_grp_nohz_mask, sched_group_cpus(ilb_group)))
|
||||||
|
+ if (cpumask_equal(nohz.grp_idle_mask, sched_group_cpus(ilb_group)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
@@ -3194,7 +3221,7 @@ static int find_new_ilb(int cpu)
|
||||||
|
* Optimize for the case when we have no idle CPUs or only one
|
||||||
|
* idle CPU. Don't walk the sched_domain hierarchy in such cases
|
||||||
|
*/
|
||||||
|
- if (cpumask_weight(nohz.cpu_mask) < 2)
|
||||||
|
+ if (cpumask_weight(nohz.idle_cpus_mask) < 2)
|
||||||
|
goto out_done;
|
||||||
|
|
||||||
|
for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) {
|
||||||
|
@@ -3202,7 +3229,7 @@ static int find_new_ilb(int cpu)
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (is_semi_idle_group(ilb_group))
|
||||||
|
- return cpumask_first(nohz.ilb_grp_nohz_mask);
|
||||||
|
+ return cpumask_first(nohz.grp_idle_mask);
|
||||||
|
|
||||||
|
ilb_group = ilb_group->next;
|
||||||
|
|
||||||
|
@@ -3210,98 +3237,116 @@ static int find_new_ilb(int cpu)
|
||||||
|
}
|
||||||
|
|
||||||
|
out_done:
|
||||||
|
- return cpumask_first(nohz.cpu_mask);
|
||||||
|
+ return nr_cpu_ids;
|
||||||
|
}
|
||||||
|
#else /* (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */
|
||||||
|
static inline int find_new_ilb(int call_cpu)
|
||||||
|
{
|
||||||
|
- return cpumask_first(nohz.cpu_mask);
|
||||||
|
+ return nr_cpu_ids;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
+ * Kick a CPU to do the nohz balancing, if it is time for it. We pick the
|
||||||
|
+ * nohz_load_balancer CPU (if there is one) otherwise fallback to any idle
|
||||||
|
+ * CPU (if there is one).
|
||||||
|
+ */
|
||||||
|
+static void nohz_balancer_kick(int cpu)
|
||||||
|
+{
|
||||||
|
+ int ilb_cpu;
|
||||||
|
+
|
||||||
|
+ nohz.next_balance++;
|
||||||
|
+
|
||||||
|
+ ilb_cpu = get_nohz_load_balancer();
|
||||||
|
+
|
||||||
|
+ if (ilb_cpu >= nr_cpu_ids) {
|
||||||
|
+ ilb_cpu = cpumask_first(nohz.idle_cpus_mask);
|
||||||
|
+ if (ilb_cpu >= nr_cpu_ids)
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!cpu_rq(ilb_cpu)->nohz_balance_kick) {
|
||||||
|
+ struct call_single_data *cp;
|
||||||
|
+
|
||||||
|
+ cpu_rq(ilb_cpu)->nohz_balance_kick = 1;
|
||||||
|
+ cp = &per_cpu(remote_sched_softirq_cb, cpu);
|
||||||
|
+ __smp_call_function_single(ilb_cpu, cp, 0);
|
||||||
|
+ }
|
||||||
|
+ return;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
* This routine will try to nominate the ilb (idle load balancing)
|
||||||
|
* owner among the cpus whose ticks are stopped. ilb owner will do the idle
|
||||||
|
- * load balancing on behalf of all those cpus. If all the cpus in the system
|
||||||
|
- * go into this tickless mode, then there will be no ilb owner (as there is
|
||||||
|
- * no need for one) and all the cpus will sleep till the next wakeup event
|
||||||
|
- * arrives...
|
||||||
|
- *
|
||||||
|
- * For the ilb owner, tick is not stopped. And this tick will be used
|
||||||
|
- * for idle load balancing. ilb owner will still be part of
|
||||||
|
- * nohz.cpu_mask..
|
||||||
|
+ * load balancing on behalf of all those cpus.
|
||||||
|
*
|
||||||
|
- * While stopping the tick, this cpu will become the ilb owner if there
|
||||||
|
- * is no other owner. And will be the owner till that cpu becomes busy
|
||||||
|
- * or if all cpus in the system stop their ticks at which point
|
||||||
|
- * there is no need for ilb owner.
|
||||||
|
+ * When the ilb owner becomes busy, we will not have new ilb owner until some
|
||||||
|
+ * idle CPU wakes up and goes back to idle or some busy CPU tries to kick
|
||||||
|
+ * idle load balancing by kicking one of the idle CPUs.
|
||||||
|
*
|
||||||
|
- * When the ilb owner becomes busy, it nominates another owner, during the
|
||||||
|
- * next busy scheduler_tick()
|
||||||
|
+ * Ticks are stopped for the ilb owner as well, with busy CPU kicking this
|
||||||
|
+ * ilb owner CPU in future (when there is a need for idle load balancing on
|
||||||
|
+ * behalf of all idle CPUs).
|
||||||
|
*/
|
||||||
|
-int select_nohz_load_balancer(int stop_tick)
|
||||||
|
+void select_nohz_load_balancer(int stop_tick)
|
||||||
|
{
|
||||||
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
|
if (stop_tick) {
|
||||||
|
- cpu_rq(cpu)->in_nohz_recently = 1;
|
||||||
|
-
|
||||||
|
if (!cpu_active(cpu)) {
|
||||||
|
if (atomic_read(&nohz.load_balancer) != cpu)
|
||||||
|
- return 0;
|
||||||
|
+ return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are going offline and still the leader,
|
||||||
|
* give up!
|
||||||
|
*/
|
||||||
|
- if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu)
|
||||||
|
+ if (atomic_cmpxchg(&nohz.load_balancer, cpu,
|
||||||
|
+ nr_cpu_ids) != cpu)
|
||||||
|
BUG();
|
||||||
|
|
||||||
|
- return 0;
|
||||||
|
+ return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- cpumask_set_cpu(cpu, nohz.cpu_mask);
|
||||||
|
+ cpumask_set_cpu(cpu, nohz.idle_cpus_mask);
|
||||||
|
|
||||||
|
- /* time for ilb owner also to sleep */
|
||||||
|
- if (cpumask_weight(nohz.cpu_mask) == num_active_cpus()) {
|
||||||
|
- if (atomic_read(&nohz.load_balancer) == cpu)
|
||||||
|
- atomic_set(&nohz.load_balancer, -1);
|
||||||
|
- return 0;
|
||||||
|
- }
|
||||||
|
+ if (atomic_read(&nohz.first_pick_cpu) == cpu)
|
||||||
|
+ atomic_cmpxchg(&nohz.first_pick_cpu, cpu, nr_cpu_ids);
|
||||||
|
+ if (atomic_read(&nohz.second_pick_cpu) == cpu)
|
||||||
|
+ atomic_cmpxchg(&nohz.second_pick_cpu, cpu, nr_cpu_ids);
|
||||||
|
|
||||||
|
- if (atomic_read(&nohz.load_balancer) == -1) {
|
||||||
|
- /* make me the ilb owner */
|
||||||
|
- if (atomic_cmpxchg(&nohz.load_balancer, -1, cpu) == -1)
|
||||||
|
- return 1;
|
||||||
|
- } else if (atomic_read(&nohz.load_balancer) == cpu) {
|
||||||
|
+ if (atomic_read(&nohz.load_balancer) >= nr_cpu_ids) {
|
||||||
|
int new_ilb;
|
||||||
|
|
||||||
|
- if (!(sched_smt_power_savings ||
|
||||||
|
- sched_mc_power_savings))
|
||||||
|
- return 1;
|
||||||
|
+ /* make me the ilb owner */
|
||||||
|
+ if (atomic_cmpxchg(&nohz.load_balancer, nr_cpu_ids,
|
||||||
|
+ cpu) != nr_cpu_ids)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Check to see if there is a more power-efficient
|
||||||
|
* ilb.
|
||||||
|
*/
|
||||||
|
new_ilb = find_new_ilb(cpu);
|
||||||
|
if (new_ilb < nr_cpu_ids && new_ilb != cpu) {
|
||||||
|
- atomic_set(&nohz.load_balancer, -1);
|
||||||
|
+ atomic_set(&nohz.load_balancer, nr_cpu_ids);
|
||||||
|
resched_cpu(new_ilb);
|
||||||
|
- return 0;
|
||||||
|
+ return;
|
||||||
|
}
|
||||||
|
- return 1;
|
||||||
|
+ return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
- if (!cpumask_test_cpu(cpu, nohz.cpu_mask))
|
||||||
|
- return 0;
|
||||||
|
+ if (!cpumask_test_cpu(cpu, nohz.idle_cpus_mask))
|
||||||
|
+ return;
|
||||||
|
|
||||||
|
- cpumask_clear_cpu(cpu, nohz.cpu_mask);
|
||||||
|
+ cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
|
||||||
|
|
||||||
|
if (atomic_read(&nohz.load_balancer) == cpu)
|
||||||
|
- if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu)
|
||||||
|
+ if (atomic_cmpxchg(&nohz.load_balancer, cpu,
|
||||||
|
+ nr_cpu_ids) != cpu)
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
- return 0;
|
||||||
|
+ return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -3383,11 +3428,101 @@ out:
|
||||||
|
rq->next_balance = next_balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
+#ifdef CONFIG_NO_HZ
|
||||||
|
/*
|
||||||
|
- * run_rebalance_domains is triggered when needed from the scheduler tick.
|
||||||
|
- * In CONFIG_NO_HZ case, the idle load balance owner will do the
|
||||||
|
+ * In CONFIG_NO_HZ case, the idle balance kickee will do the
|
||||||
|
* rebalancing for all the cpus for whom scheduler ticks are stopped.
|
||||||
|
*/
|
||||||
|
+static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle)
|
||||||
|
+{
|
||||||
|
+ struct rq *this_rq = cpu_rq(this_cpu);
|
||||||
|
+ struct rq *rq;
|
||||||
|
+ int balance_cpu;
|
||||||
|
+
|
||||||
|
+ if (idle != CPU_IDLE || !this_rq->nohz_balance_kick)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ for_each_cpu(balance_cpu, nohz.idle_cpus_mask) {
|
||||||
|
+ if (balance_cpu == this_cpu)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If this cpu gets work to do, stop the load balancing
|
||||||
|
+ * work being done for other cpus. Next load
|
||||||
|
+ * balancing owner will pick it up.
|
||||||
|
+ */
|
||||||
|
+ if (need_resched()) {
|
||||||
|
+ this_rq->nohz_balance_kick = 0;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ raw_spin_lock_irq(&this_rq->lock);
|
||||||
|
+ update_cpu_load(this_rq);
|
||||||
|
+ raw_spin_unlock_irq(&this_rq->lock);
|
||||||
|
+
|
||||||
|
+ rebalance_domains(balance_cpu, CPU_IDLE);
|
||||||
|
+
|
||||||
|
+ rq = cpu_rq(balance_cpu);
|
||||||
|
+ if (time_after(this_rq->next_balance, rq->next_balance))
|
||||||
|
+ this_rq->next_balance = rq->next_balance;
|
||||||
|
+ }
|
||||||
|
+ nohz.next_balance = this_rq->next_balance;
|
||||||
|
+ this_rq->nohz_balance_kick = 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Current heuristic for kicking the idle load balancer
|
||||||
|
+ * - first_pick_cpu is the one of the busy CPUs. It will kick
|
||||||
|
+ * idle load balancer when it has more than one process active. This
|
||||||
|
+ * eliminates the need for idle load balancing altogether when we have
|
||||||
|
+ * only one running process in the system (common case).
|
||||||
|
+ * - If there are more than one busy CPU, idle load balancer may have
|
||||||
|
+ * to run for active_load_balance to happen (i.e., two busy CPUs are
|
||||||
|
+ * SMT or core siblings and can run better if they move to different
|
||||||
|
+ * physical CPUs). So, second_pick_cpu is the second of the busy CPUs
|
||||||
|
+ * which will kick idle load balancer as soon as it has any load.
|
||||||
|
+ */
|
||||||
|
+static inline int nohz_kick_needed(struct rq *rq, int cpu)
|
||||||
|
+{
|
||||||
|
+ unsigned long now = jiffies;
|
||||||
|
+ int ret;
|
||||||
|
+ int first_pick_cpu, second_pick_cpu;
|
||||||
|
+
|
||||||
|
+ if (time_before(now, nohz.next_balance))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ if (!rq->nr_running)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ first_pick_cpu = atomic_read(&nohz.first_pick_cpu);
|
||||||
|
+ second_pick_cpu = atomic_read(&nohz.second_pick_cpu);
|
||||||
|
+
|
||||||
|
+ if (first_pick_cpu < nr_cpu_ids && first_pick_cpu != cpu &&
|
||||||
|
+ second_pick_cpu < nr_cpu_ids && second_pick_cpu != cpu)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ ret = atomic_cmpxchg(&nohz.first_pick_cpu, nr_cpu_ids, cpu);
|
||||||
|
+ if (ret == nr_cpu_ids || ret == cpu) {
|
||||||
|
+ atomic_cmpxchg(&nohz.second_pick_cpu, cpu, nr_cpu_ids);
|
||||||
|
+ if (rq->nr_running > 1)
|
||||||
|
+ return 1;
|
||||||
|
+ } else {
|
||||||
|
+ ret = atomic_cmpxchg(&nohz.second_pick_cpu, nr_cpu_ids, cpu);
|
||||||
|
+ if (ret == nr_cpu_ids || ret == cpu) {
|
||||||
|
+ if (rq->nr_running)
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+#else
|
||||||
|
+static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle) { }
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * run_rebalance_domains is triggered when needed from the scheduler tick.
|
||||||
|
+ * Also triggered for nohz idle balancing (with nohz_balancing_kick set).
|
||||||
|
+ */
|
||||||
|
static void run_rebalance_domains(struct softirq_action *h)
|
||||||
|
{
|
||||||
|
int this_cpu = smp_processor_id();
|
||||||
|
@@ -3397,40 +3532,12 @@ static void run_rebalance_domains(struct softirq_action *h)
|
||||||
|
|
||||||
|
rebalance_domains(this_cpu, idle);
|
||||||
|
|
||||||
|
-#ifdef CONFIG_NO_HZ
|
||||||
|
/*
|
||||||
|
- * If this cpu is the owner for idle load balancing, then do the
|
||||||
|
+ * If this cpu has a pending nohz_balance_kick, then do the
|
||||||
|
* balancing on behalf of the other idle cpus whose ticks are
|
||||||
|
* stopped.
|
||||||
|
*/
|
||||||
|
- if (this_rq->idle_at_tick &&
|
||||||
|
- atomic_read(&nohz.load_balancer) == this_cpu) {
|
||||||
|
- struct rq *rq;
|
||||||
|
- int balance_cpu;
|
||||||
|
-
|
||||||
|
- for_each_cpu(balance_cpu, nohz.cpu_mask) {
|
||||||
|
- if (balance_cpu == this_cpu)
|
||||||
|
- continue;
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * If this cpu gets work to do, stop the load balancing
|
||||||
|
- * work being done for other cpus. Next load
|
||||||
|
- * balancing owner will pick it up.
|
||||||
|
- */
|
||||||
|
- if (need_resched())
|
||||||
|
- break;
|
||||||
|
-
|
||||||
|
- rq = cpu_rq(balance_cpu);
|
||||||
|
- raw_spin_lock_irq(&rq->lock);
|
||||||
|
- update_cpu_load(rq);
|
||||||
|
- raw_spin_unlock_irq(&rq->lock);
|
||||||
|
- rebalance_domains(balance_cpu, CPU_IDLE);
|
||||||
|
-
|
||||||
|
- if (time_after(this_rq->next_balance, rq->next_balance))
|
||||||
|
- this_rq->next_balance = rq->next_balance;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-#endif
|
||||||
|
+ nohz_idle_balance(this_cpu, idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int on_null_domain(int cpu)
|
||||||
|
@@ -3440,57 +3547,17 @@ static inline int on_null_domain(int cpu)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing.
|
||||||
|
- *
|
||||||
|
- * In case of CONFIG_NO_HZ, this is the place where we nominate a new
|
||||||
|
- * idle load balancing owner or decide to stop the periodic load balancing,
|
||||||
|
- * if the whole system is idle.
|
||||||
|
*/
|
||||||
|
static inline void trigger_load_balance(struct rq *rq, int cpu)
|
||||||
|
{
|
||||||
|
-#ifdef CONFIG_NO_HZ
|
||||||
|
- /*
|
||||||
|
- * If we were in the nohz mode recently and busy at the current
|
||||||
|
- * scheduler tick, then check if we need to nominate new idle
|
||||||
|
- * load balancer.
|
||||||
|
- */
|
||||||
|
- if (rq->in_nohz_recently && !rq->idle_at_tick) {
|
||||||
|
- rq->in_nohz_recently = 0;
|
||||||
|
-
|
||||||
|
- if (atomic_read(&nohz.load_balancer) == cpu) {
|
||||||
|
- cpumask_clear_cpu(cpu, nohz.cpu_mask);
|
||||||
|
- atomic_set(&nohz.load_balancer, -1);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (atomic_read(&nohz.load_balancer) == -1) {
|
||||||
|
- int ilb = find_new_ilb(cpu);
|
||||||
|
-
|
||||||
|
- if (ilb < nr_cpu_ids)
|
||||||
|
- resched_cpu(ilb);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * If this cpu is idle and doing idle load balancing for all the
|
||||||
|
- * cpus with ticks stopped, is it time for that to stop?
|
||||||
|
- */
|
||||||
|
- if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) == cpu &&
|
||||||
|
- cpumask_weight(nohz.cpu_mask) == num_online_cpus()) {
|
||||||
|
- resched_cpu(cpu);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * If this cpu is idle and the idle load balancing is done by
|
||||||
|
- * someone else, then no need raise the SCHED_SOFTIRQ
|
||||||
|
- */
|
||||||
|
- if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) != cpu &&
|
||||||
|
- cpumask_test_cpu(cpu, nohz.cpu_mask))
|
||||||
|
- return;
|
||||||
|
-#endif
|
||||||
|
/* Don't need to rebalance while attached to NULL domain */
|
||||||
|
if (time_after_eq(jiffies, rq->next_balance) &&
|
||||||
|
likely(!on_null_domain(cpu)))
|
||||||
|
raise_softirq(SCHED_SOFTIRQ);
|
||||||
|
+#ifdef CONFIG_NO_HZ
|
||||||
|
+ else if (nohz_kick_needed(rq, cpu) && likely(!on_null_domain(cpu)))
|
||||||
|
+ nohz_balancer_kick(cpu);
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rq_online_fair(struct rq *rq)
|
||||||
|
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
|
||||||
|
index 1d7b9bc..5f171f0 100644
|
||||||
|
--- a/kernel/time/tick-sched.c
|
||||||
|
+++ b/kernel/time/tick-sched.c
|
||||||
|
@@ -408,13 +408,7 @@ void tick_nohz_stop_sched_tick(int inidle)
|
||||||
|
* the scheduler tick in nohz_restart_sched_tick.
|
||||||
|
*/
|
||||||
|
if (!ts->tick_stopped) {
|
||||||
|
- if (select_nohz_load_balancer(1)) {
|
||||||
|
- /*
|
||||||
|
- * sched tick not stopped!
|
||||||
|
- */
|
||||||
|
- cpumask_clear_cpu(cpu, nohz_cpu_mask);
|
||||||
|
- goto out;
|
||||||
|
- }
|
||||||
|
+ select_nohz_load_balancer(1);
|
||||||
|
|
||||||
|
ts->idle_tick = hrtimer_get_expires(&ts->sched_timer);
|
||||||
|
ts->tick_stopped = 1;
|
||||||
|
diff --git a/kernel/timer.c b/kernel/timer.c
|
||||||
|
index ee305c8..48d6aec 100644
|
||||||
|
--- a/kernel/timer.c
|
||||||
|
+++ b/kernel/timer.c
|
||||||
|
@@ -679,12 +679,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
|
||||||
|
cpu = smp_processor_id();
|
||||||
|
|
||||||
|
#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP)
|
||||||
|
- if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) {
|
||||||
|
- int preferred_cpu = get_nohz_load_balancer();
|
||||||
|
-
|
||||||
|
- if (preferred_cpu >= 0)
|
||||||
|
- cpu = preferred_cpu;
|
||||||
|
- }
|
||||||
|
+ if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu))
|
||||||
|
+ cpu = get_nohz_timer_target();
|
||||||
|
#endif
|
||||||
|
new_base = per_cpu(tvec_bases, cpu);
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
From: Suresh Siddha <suresh.b.siddha@intel.com>
|
||||||
|
Date: Fri, 9 Jul 2010 13:19:54 +0000 (+0200)
|
||||||
|
Subject: sched: Update rq->clock for nohz balanced cpus
|
||||||
|
X-Git-Tag: v2.6.36-rc1~531^2~5
|
||||||
|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=5343bdb8fd076f16edc9d113a9e35e2a1d1f4966
|
||||||
|
|
||||||
|
sched: Update rq->clock for nohz balanced cpus
|
||||||
|
|
||||||
|
Suresh spotted that we don't update the rq->clock in the nohz
|
||||||
|
load-balancer path.
|
||||||
|
|
||||||
|
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
LKML-Reference: <1278626014.2834.74.camel@sbs-t61.sc.intel.com>
|
||||||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
|
||||||
|
index b4da534..e44a591 100644
|
||||||
|
--- a/kernel/sched_fair.c
|
||||||
|
+++ b/kernel/sched_fair.c
|
||||||
|
@@ -3596,6 +3596,7 @@ static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle)
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_spin_lock_irq(&this_rq->lock);
|
||||||
|
+ update_rq_clock(this_rq);
|
||||||
|
update_cpu_load(this_rq);
|
||||||
|
raw_spin_unlock_irq(&this_rq->lock);
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
From: Peter Zijlstra <peterz@infradead.org>
|
||||||
|
Date: Thu, 19 Aug 2010 11:31:43 +0000 (+0200)
|
||||||
|
Subject: sched: Fix rq->clock synchronization when migrating tasks
|
||||||
|
X-Git-Tag: v2.6.36-rc3~25^2~1
|
||||||
|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=861d034ee814917a83bd5de4b26e3b8336ddeeb8
|
||||||
|
|
||||||
|
sched: Fix rq->clock synchronization when migrating tasks
|
||||||
|
|
||||||
|
sched_fork() -- we do task placement in ->task_fork_fair() ensure we
|
||||||
|
update_rq_clock() so we work with current time. We leave the vruntime
|
||||||
|
in relative state, so the time delay until wake_up_new_task() doesn't
|
||||||
|
matter.
|
||||||
|
|
||||||
|
wake_up_new_task() -- Since task_fork_fair() left p->vruntime in
|
||||||
|
relative state we can safely migrate, the activate_task() on the
|
||||||
|
remote rq will call update_rq_clock() and causes the clock to be
|
||||||
|
synced (enough).
|
||||||
|
|
||||||
|
Tested-by: Jack Daniel <wanders.thirst@gmail.com>
|
||||||
|
Tested-by: Philby John <pjohn@mvista.com>
|
||||||
|
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
LKML-Reference: <1281002322.1923.1708.camel@laptop>
|
||||||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
|
||||||
|
index 806d1b2..ab661eb 100644
|
||||||
|
--- a/kernel/sched_fair.c
|
||||||
|
+++ b/kernel/sched_fair.c
|
||||||
|
@@ -3752,6 +3752,8 @@ static void task_fork_fair(struct task_struct *p)
|
||||||
|
|
||||||
|
raw_spin_lock_irqsave(&rq->lock, flags);
|
||||||
|
|
||||||
|
+ update_rq_clock(rq);
|
||||||
|
+
|
||||||
|
if (unlikely(task_cpu(p) != this_cpu))
|
||||||
|
__set_task_cpu(p, this_cpu);
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
From: Suresh Siddha <suresh.b.siddha@intel.com>
|
||||||
|
Date: Mon, 23 Aug 2010 20:42:51 +0000 (-0700)
|
||||||
|
Subject: sched: Move sched_avg_update() to update_cpu_load()
|
||||||
|
X-Git-Tag: v2.6.36-rc4~8^2~1
|
||||||
|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=da2b71edd8a7db44fe1746261410a981f3e03632
|
||||||
|
|
||||||
|
sched: Move sched_avg_update() to update_cpu_load()
|
||||||
|
|
||||||
|
Currently sched_avg_update() (which updates rt_avg stats in the rq)
|
||||||
|
is getting called from scale_rt_power() (in the load balance context)
|
||||||
|
which doesn't take rq->lock.
|
||||||
|
|
||||||
|
Fix it by moving the sched_avg_update() to more appropriate
|
||||||
|
update_cpu_load() where the CFS load gets updated as well.
|
||||||
|
|
||||||
|
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
|
||||||
|
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
LKML-Reference: <1282596171.2694.3.camel@sbsiddha-MOBL3>
|
||||||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/kernel/sched.c b/kernel/sched.c
|
||||||
|
index 09b574e..ed09d4f 100644
|
||||||
|
--- a/kernel/sched.c
|
||||||
|
+++ b/kernel/sched.c
|
||||||
|
@@ -1294,6 +1294,10 @@ static void resched_task(struct task_struct *p)
|
||||||
|
static void sched_rt_avg_update(struct rq *rq, u64 rt_delta)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+static void sched_avg_update(struct rq *rq)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
#if BITS_PER_LONG == 32
|
||||||
|
@@ -3182,6 +3186,8 @@ static void update_cpu_load(struct rq *this_rq)
|
||||||
|
|
||||||
|
this_rq->cpu_load[i] = (old_load * (scale - 1) + new_load) >> i;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ sched_avg_update(this_rq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_cpu_load_active(struct rq *this_rq)
|
||||||
|
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
|
||||||
|
index ab661eb..f53ec75 100644
|
||||||
|
--- a/kernel/sched_fair.c
|
||||||
|
+++ b/kernel/sched_fair.c
|
||||||
|
@@ -2268,8 +2268,6 @@ unsigned long scale_rt_power(int cpu)
|
||||||
|
struct rq *rq = cpu_rq(cpu);
|
||||||
|
u64 total, available;
|
||||||
|
|
||||||
|
- sched_avg_update(rq);
|
||||||
|
-
|
||||||
|
total = sched_avg_period() + (rq->clock - rq->age_stamp);
|
||||||
|
available = total - rq->rt_avg;
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
From: Suresh Siddha <suresh.b.siddha@intel.com>
|
||||||
|
Date: Mon, 13 Sep 2010 18:02:21 +0000 (-0700)
|
||||||
|
Subject: sched: Fix nohz balance kick
|
||||||
|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=f6c3f1686e7ec1dd8725a9a3dcb857dfd0c7a5bf
|
||||||
|
|
||||||
|
sched: Fix nohz balance kick
|
||||||
|
|
||||||
|
There's a situation where the nohz balancer will try to wake itself:
|
||||||
|
|
||||||
|
cpu-x is idle which is also ilb_cpu
|
||||||
|
got a scheduler tick during idle
|
||||||
|
and the nohz_kick_needed() in trigger_load_balance() checks for
|
||||||
|
rq_x->nr_running which might not be zero (because of someone waking a
|
||||||
|
task on this rq etc) and this leads to the situation of the cpu-x
|
||||||
|
sending a kick to itself.
|
||||||
|
|
||||||
|
And this can cause a lockup.
|
||||||
|
|
||||||
|
Avoid this by not marking ourself eligible for kicking.
|
||||||
|
|
||||||
|
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
|
||||||
|
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
LKML-Reference: <1284400941.2684.19.camel@sbsiddha-MOBL3.sc.intel.com>
|
||||||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
|
||||||
|
index a171138..db3f674 100644
|
||||||
|
--- a/kernel/sched_fair.c
|
||||||
|
+++ b/kernel/sched_fair.c
|
||||||
|
@@ -3630,7 +3630,7 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu)
|
||||||
|
if (time_before(now, nohz.next_balance))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- if (!rq->nr_running)
|
||||||
|
+ if (rq->idle_at_tick)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
first_pick_cpu = atomic_read(&nohz.first_pick_cpu);
|
|
@ -0,0 +1,93 @@
|
||||||
|
From: Venkatesh Pallipadi <venki@google.com>
|
||||||
|
Date: Sat, 11 Sep 2010 01:19:17 +0000 (-0700)
|
||||||
|
Subject: sched: Increment cache_nice_tries only on periodic lb
|
||||||
|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fmingo%2Flinux-2.6-x86.git;a=commitdiff_plain;h=58b26c4c025778c09c7a1438ff185080e11b7d0a
|
||||||
|
|
||||||
|
sched: Increment cache_nice_tries only on periodic lb
|
||||||
|
|
||||||
|
scheduler uses cache_nice_tries as an indicator to do cache_hot and
|
||||||
|
active load balance, when normal load balance fails. Currently,
|
||||||
|
this value is changed on any failed load balance attempt. That ends
|
||||||
|
up being not so nice to workloads that enter/exit idle often, as
|
||||||
|
they do more frequent new_idle balance and that pretty soon results
|
||||||
|
in cache hot tasks being pulled in.
|
||||||
|
|
||||||
|
Making the cache_nice_tries ignore failed new_idle balance seems to
|
||||||
|
make better sense. With that only the failed load balance in
|
||||||
|
periodic load balance gets accounted and the rate of accumulation
|
||||||
|
of cache_nice_tries will not depend on idle entry/exit (short
|
||||||
|
running sleep-wakeup kind of tasks). This reduces movement of
|
||||||
|
cache_hot tasks.
|
||||||
|
|
||||||
|
schedstat diff (after-before) excerpt from a workload that has
|
||||||
|
frequent and short wakeup-idle pattern (:2 in cpu col below refers
|
||||||
|
to NEWIDLE idx) This snapshot was across ~400 seconds.
|
||||||
|
|
||||||
|
Without this change:
|
||||||
|
domainstats: domain0
|
||||||
|
cpu cnt bln fld imb gain hgain nobusyq nobusyg
|
||||||
|
0:2 306487 219575 73167 110069413 44583 19070 1172 218403
|
||||||
|
1:2 292139 194853 81421 120893383 50745 21902 1259 193594
|
||||||
|
2:2 283166 174607 91359 129699642 54931 23688 1287 173320
|
||||||
|
3:2 273998 161788 93991 132757146 57122 24351 1366 160422
|
||||||
|
4:2 289851 215692 62190 83398383 36377 13680 851 214841
|
||||||
|
5:2 316312 222146 77605 117582154 49948 20281 988 221158
|
||||||
|
6:2 297172 195596 83623 122133390 52801 21301 929 194667
|
||||||
|
7:2 283391 178078 86378 126622761 55122 22239 928 177150
|
||||||
|
8:2 297655 210359 72995 110246694 45798 19777 1125 209234
|
||||||
|
9:2 297357 202011 79363 119753474 50953 22088 1089 200922
|
||||||
|
10:2 278797 178703 83180 122514385 52969 22726 1128 177575
|
||||||
|
11:2 272661 167669 86978 127342327 55857 24342 1195 166474
|
||||||
|
12:2 293039 204031 73211 110282059 47285 19651 948 203083
|
||||||
|
13:2 289502 196762 76803 114712942 49339 20547 1016 195746
|
||||||
|
14:2 264446 169609 78292 115715605 50459 21017 982 168627
|
||||||
|
15:2 260968 163660 80142 116811793 51483 21281 1064 162596
|
||||||
|
|
||||||
|
With this change:
|
||||||
|
domainstats: domain0
|
||||||
|
cpu cnt bln fld imb gain hgain nobusyq nobusyg
|
||||||
|
0:2 272347 187380 77455 105420270 24975 1 953 186427
|
||||||
|
1:2 267276 172360 86234 116242264 28087 6 1028 171332
|
||||||
|
2:2 259769 156777 93281 123243134 30555 1 1043 155734
|
||||||
|
3:2 250870 143129 97627 127370868 32026 6 1188 141941
|
||||||
|
4:2 248422 177116 64096 78261112 22202 2 757 176359
|
||||||
|
5:2 275595 180683 84950 116075022 29400 6 778 179905
|
||||||
|
6:2 262418 162609 88944 119256898 31056 4 817 161792
|
||||||
|
7:2 252204 147946 92646 122388300 32879 4 824 147122
|
||||||
|
8:2 262335 172239 81631 110477214 26599 4 864 171375
|
||||||
|
9:2 261563 164775 88016 117203621 28331 3 849 163926
|
||||||
|
10:2 243389 140949 93379 121353071 29585 2 909 140040
|
||||||
|
11:2 242795 134651 98310 124768957 30895 2 1016 133635
|
||||||
|
12:2 255234 166622 79843 104696912 26483 4 746 165876
|
||||||
|
13:2 244944 151595 83855 109808099 27787 3 801 150794
|
||||||
|
14:2 241301 140982 89935 116954383 30403 6 845 140137
|
||||||
|
15:2 232271 128564 92821 119185207 31207 4 1416 127148
|
||||||
|
|
||||||
|
Signed-off-by: Venkatesh Pallipadi <venki@google.com>
|
||||||
|
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
LKML-Reference: <1284167957-3675-1-git-send-email-venki@google.com>
|
||||||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||||
|
---
|
||||||
|
|
||||||
|
[ 2.6.35.x backport ]
|
||||||
|
|
||||||
|
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
|
||||||
|
index a171138..aa16cf1 100644
|
||||||
|
--- a/kernel/sched_fair.c
|
||||||
|
+++ b/kernel/sched_fair.c
|
||||||
|
@@ -3031,7 +3031,14 @@ redo:
|
||||||
|
|
||||||
|
if (!ld_moved) {
|
||||||
|
schedstat_inc(sd, lb_failed[idle]);
|
||||||
|
- sd->nr_balance_failed++;
|
||||||
|
+ /*
|
||||||
|
+ * Increment the failure counter only on periodic balance.
|
||||||
|
+ * We do not want newidle balance, which can be very
|
||||||
|
+ * frequent, pollute the failure counter causing
|
||||||
|
+ * excessive cache_hot migrations and active balances.
|
||||||
|
+ */
|
||||||
|
+ if (idle != CPU_NEWLY_IDLE)
|
||||||
|
+ sd->nr_balance_failed++;
|
||||||
|
|
||||||
|
if (need_active_balance(sd, sd_idle, idle)) {
|
||||||
|
raw_spin_lock_irqsave(&busiest->lock, flags);
|
|
@ -0,0 +1,273 @@
|
||||||
|
From bounces.tip@hpa.at.zytor.com Wed Dec 8 15:40:48 2010
|
||||||
|
From: tip-bot for Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
In-Reply-To: <1291129145.32004.874.camel@laptop>
|
||||||
|
References: <1291129145.32004.874.camel@laptop>
|
||||||
|
Subject: [tip:sched/urgent] sched: Cure more NO_HZ load average woes
|
||||||
|
Message-ID: <tip-0f004f5a696a9434b7214d0d3cbd0525ee77d428@git.kernel.org>
|
||||||
|
Git-Commit-ID: 0f004f5a696a9434b7214d0d3cbd0525ee77d428
|
||||||
|
|
||||||
|
Commit-ID: 0f004f5a696a9434b7214d0d3cbd0525ee77d428
|
||||||
|
Gitweb: http://git.kernel.org/tip/0f004f5a696a9434b7214d0d3cbd0525ee77d428
|
||||||
|
Author: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
AuthorDate: Tue, 30 Nov 2010 19:48:45 +0100
|
||||||
|
Committer: Ingo Molnar <mingo@elte.hu>
|
||||||
|
CommitDate: Wed, 8 Dec 2010 20:15:04 +0100
|
||||||
|
|
||||||
|
sched: Cure more NO_HZ load average woes
|
||||||
|
|
||||||
|
There's a long-running regression that proved difficult to fix and
|
||||||
|
which is hitting certain people and is rather annoying in its effects.
|
||||||
|
|
||||||
|
Damien reported that after 74f5187ac8 (sched: Cure load average vs
|
||||||
|
NO_HZ woes) his load average is unnaturally high, he also noted that
|
||||||
|
even with that patch reverted the load avgerage numbers are not
|
||||||
|
correct.
|
||||||
|
|
||||||
|
The problem is that the previous patch only solved half the NO_HZ
|
||||||
|
problem, it addressed the part of going into NO_HZ mode, not of
|
||||||
|
comming out of NO_HZ mode. This patch implements that missing half.
|
||||||
|
|
||||||
|
When comming out of NO_HZ mode there are two important things to take
|
||||||
|
care of:
|
||||||
|
|
||||||
|
- Folding the pending idle delta into the global active count.
|
||||||
|
- Correctly aging the averages for the idle-duration.
|
||||||
|
|
||||||
|
So with this patch the NO_HZ interaction should be complete and
|
||||||
|
behaviour between CONFIG_NO_HZ=[yn] should be equivalent.
|
||||||
|
|
||||||
|
Furthermore, this patch slightly changes the load average computation
|
||||||
|
by adding a rounding term to the fixed point multiplication.
|
||||||
|
|
||||||
|
Reported-by: Damien Wyart <damien.wyart@free.fr>
|
||||||
|
Reported-by: Tim McGrath <tmhikaru@gmail.com>
|
||||||
|
Tested-by: Damien Wyart <damien.wyart@free.fr>
|
||||||
|
Tested-by: Orion Poplawski <orion@cora.nwra.com>
|
||||||
|
Tested-by: Kyle McMartin <kyle@mcmartin.ca>
|
||||||
|
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||||
|
Cc: stable@kernel.org
|
||||||
|
Cc: Chase Douglas <chase.douglas@canonical.com>
|
||||||
|
LKML-Reference: <1291129145.32004.874.camel@laptop>
|
||||||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||||
|
---
|
||||||
|
include/linux/sched.h | 2 +-
|
||||||
|
kernel/sched.c | 150 +++++++++++++++++++++++++++++++++++++++++++++----
|
||||||
|
kernel/timer.c | 2 +-
|
||||||
|
3 files changed, 141 insertions(+), 13 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
||||||
|
index 2c79e92..2238745 100644
|
||||||
|
--- a/include/linux/sched.h
|
||||||
|
+++ b/include/linux/sched.h
|
||||||
|
@@ -143,7 +143,7 @@ extern unsigned long nr_iowait_cpu(int cpu);
|
||||||
|
extern unsigned long this_cpu_load(void);
|
||||||
|
|
||||||
|
|
||||||
|
-extern void calc_global_load(void);
|
||||||
|
+extern void calc_global_load(unsigned long ticks);
|
||||||
|
|
||||||
|
extern unsigned long get_parent_ip(unsigned long addr);
|
||||||
|
|
||||||
|
diff --git a/kernel/sched.c b/kernel/sched.c
|
||||||
|
index dc91a4d..6b7c26a 100644
|
||||||
|
--- a/kernel/sched.c
|
||||||
|
+++ b/kernel/sched.c
|
||||||
|
@@ -3119,6 +3119,15 @@ static long calc_load_fold_active(struct rq *this_rq)
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static unsigned long
|
||||||
|
+calc_load(unsigned long load, unsigned long exp, unsigned long active)
|
||||||
|
+{
|
||||||
|
+ load *= exp;
|
||||||
|
+ load += active * (FIXED_1 - exp);
|
||||||
|
+ load += 1UL << (FSHIFT - 1);
|
||||||
|
+ return load >> FSHIFT;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#ifdef CONFIG_NO_HZ
|
||||||
|
/*
|
||||||
|
* For NO_HZ we delay the active fold to the next LOAD_FREQ update.
|
||||||
|
@@ -3148,6 +3157,128 @@ static long calc_load_fold_idle(void)
|
||||||
|
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * fixed_power_int - compute: x^n, in O(log n) time
|
||||||
|
+ *
|
||||||
|
+ * @x: base of the power
|
||||||
|
+ * @frac_bits: fractional bits of @x
|
||||||
|
+ * @n: power to raise @x to.
|
||||||
|
+ *
|
||||||
|
+ * By exploiting the relation between the definition of the natural power
|
||||||
|
+ * function: x^n := x*x*...*x (x multiplied by itself for n times), and
|
||||||
|
+ * the binary encoding of numbers used by computers: n := \Sum n_i * 2^i,
|
||||||
|
+ * (where: n_i \elem {0, 1}, the binary vector representing n),
|
||||||
|
+ * we find: x^n := x^(\Sum n_i * 2^i) := \Prod x^(n_i * 2^i), which is
|
||||||
|
+ * of course trivially computable in O(log_2 n), the length of our binary
|
||||||
|
+ * vector.
|
||||||
|
+ */
|
||||||
|
+static unsigned long
|
||||||
|
+fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n)
|
||||||
|
+{
|
||||||
|
+ unsigned long result = 1UL << frac_bits;
|
||||||
|
+
|
||||||
|
+ if (n) for (;;) {
|
||||||
|
+ if (n & 1) {
|
||||||
|
+ result *= x;
|
||||||
|
+ result += 1UL << (frac_bits - 1);
|
||||||
|
+ result >>= frac_bits;
|
||||||
|
+ }
|
||||||
|
+ n >>= 1;
|
||||||
|
+ if (!n)
|
||||||
|
+ break;
|
||||||
|
+ x *= x;
|
||||||
|
+ x += 1UL << (frac_bits - 1);
|
||||||
|
+ x >>= frac_bits;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return result;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * a1 = a0 * e + a * (1 - e)
|
||||||
|
+ *
|
||||||
|
+ * a2 = a1 * e + a * (1 - e)
|
||||||
|
+ * = (a0 * e + a * (1 - e)) * e + a * (1 - e)
|
||||||
|
+ * = a0 * e^2 + a * (1 - e) * (1 + e)
|
||||||
|
+ *
|
||||||
|
+ * a3 = a2 * e + a * (1 - e)
|
||||||
|
+ * = (a0 * e^2 + a * (1 - e) * (1 + e)) * e + a * (1 - e)
|
||||||
|
+ * = a0 * e^3 + a * (1 - e) * (1 + e + e^2)
|
||||||
|
+ *
|
||||||
|
+ * ...
|
||||||
|
+ *
|
||||||
|
+ * an = a0 * e^n + a * (1 - e) * (1 + e + ... + e^n-1) [1]
|
||||||
|
+ * = a0 * e^n + a * (1 - e) * (1 - e^n)/(1 - e)
|
||||||
|
+ * = a0 * e^n + a * (1 - e^n)
|
||||||
|
+ *
|
||||||
|
+ * [1] application of the geometric series:
|
||||||
|
+ *
|
||||||
|
+ * n 1 - x^(n+1)
|
||||||
|
+ * S_n := \Sum x^i = -------------
|
||||||
|
+ * i=0 1 - x
|
||||||
|
+ */
|
||||||
|
+static unsigned long
|
||||||
|
+calc_load_n(unsigned long load, unsigned long exp,
|
||||||
|
+ unsigned long active, unsigned int n)
|
||||||
|
+{
|
||||||
|
+
|
||||||
|
+ return calc_load(load, fixed_power_int(exp, FSHIFT, n), active);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * NO_HZ can leave us missing all per-cpu ticks calling
|
||||||
|
+ * calc_load_account_active(), but since an idle CPU folds its delta into
|
||||||
|
+ * calc_load_tasks_idle per calc_load_account_idle(), all we need to do is fold
|
||||||
|
+ * in the pending idle delta if our idle period crossed a load cycle boundary.
|
||||||
|
+ *
|
||||||
|
+ * Once we've updated the global active value, we need to apply the exponential
|
||||||
|
+ * weights adjusted to the number of cycles missed.
|
||||||
|
+ */
|
||||||
|
+static void calc_global_nohz(unsigned long ticks)
|
||||||
|
+{
|
||||||
|
+ long delta, active, n;
|
||||||
|
+
|
||||||
|
+ if (time_before(jiffies, calc_load_update))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If we crossed a calc_load_update boundary, make sure to fold
|
||||||
|
+ * any pending idle changes, the respective CPUs might have
|
||||||
|
+ * missed the tick driven calc_load_account_active() update
|
||||||
|
+ * due to NO_HZ.
|
||||||
|
+ */
|
||||||
|
+ delta = calc_load_fold_idle();
|
||||||
|
+ if (delta)
|
||||||
|
+ atomic_long_add(delta, &calc_load_tasks);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If we were idle for multiple load cycles, apply them.
|
||||||
|
+ */
|
||||||
|
+ if (ticks >= LOAD_FREQ) {
|
||||||
|
+ n = ticks / LOAD_FREQ;
|
||||||
|
+
|
||||||
|
+ active = atomic_long_read(&calc_load_tasks);
|
||||||
|
+ active = active > 0 ? active * FIXED_1 : 0;
|
||||||
|
+
|
||||||
|
+ avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
|
||||||
|
+ avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
|
||||||
|
+ avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
|
||||||
|
+
|
||||||
|
+ calc_load_update += n * LOAD_FREQ;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Its possible the remainder of the above division also crosses
|
||||||
|
+ * a LOAD_FREQ period, the regular check in calc_global_load()
|
||||||
|
+ * which comes after this will take care of that.
|
||||||
|
+ *
|
||||||
|
+ * Consider us being 11 ticks before a cycle completion, and us
|
||||||
|
+ * sleeping for 4*LOAD_FREQ + 22 ticks, then the above code will
|
||||||
|
+ * age us 4 cycles, and the test in calc_global_load() will
|
||||||
|
+ * pick up the final one.
|
||||||
|
+ */
|
||||||
|
+}
|
||||||
|
#else
|
||||||
|
static void calc_load_account_idle(struct rq *this_rq)
|
||||||
|
{
|
||||||
|
@@ -3157,6 +3288,10 @@ static inline long calc_load_fold_idle(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+static void calc_global_nohz(unsigned long ticks)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -3174,24 +3309,17 @@ void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
|
||||||
|
loads[2] = (avenrun[2] + offset) << shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static unsigned long
|
||||||
|
-calc_load(unsigned long load, unsigned long exp, unsigned long active)
|
||||||
|
-{
|
||||||
|
- load *= exp;
|
||||||
|
- load += active * (FIXED_1 - exp);
|
||||||
|
- return load >> FSHIFT;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* calc_load - update the avenrun load estimates 10 ticks after the
|
||||||
|
* CPUs have updated calc_load_tasks.
|
||||||
|
*/
|
||||||
|
-void calc_global_load(void)
|
||||||
|
+void calc_global_load(unsigned long ticks)
|
||||||
|
{
|
||||||
|
- unsigned long upd = calc_load_update + 10;
|
||||||
|
long active;
|
||||||
|
|
||||||
|
- if (time_before(jiffies, upd))
|
||||||
|
+ calc_global_nohz(ticks);
|
||||||
|
+
|
||||||
|
+ if (time_before(jiffies, calc_load_update + 10))
|
||||||
|
return;
|
||||||
|
|
||||||
|
active = atomic_long_read(&calc_load_tasks);
|
||||||
|
diff --git a/kernel/timer.c b/kernel/timer.c
|
||||||
|
index 68a9ae7..7bd715f 100644
|
||||||
|
--- a/kernel/timer.c
|
||||||
|
+++ b/kernel/timer.c
|
||||||
|
@@ -1319,7 +1319,7 @@ void do_timer(unsigned long ticks)
|
||||||
|
{
|
||||||
|
jiffies_64 += ticks;
|
||||||
|
update_wall_time();
|
||||||
|
- calc_global_load();
|
||||||
|
+ calc_global_load(ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __ARCH_WANT_SYS_ALARM
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
From kernel-bounces@lists.fedoraproject.org Thu Sep 9 09:23:49 2010
|
||||||
|
From: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||||
|
Subject: [PATCH 1/3] sdhci: 8-bit data transfer width support
|
||||||
|
Date: Thu, 9 Sep 2010 15:24:10 +0200
|
||||||
|
|
||||||
|
From: Kyungmin Park <kyungmin.park@samsung.com>
|
||||||
|
|
||||||
|
Upstream ae6d6c92212e94b12ab9365c23fb73acc2c3c2e7 commit.
|
||||||
|
|
||||||
|
Some host controllers such as s5pc110 support the WIDE8 feature.
|
||||||
|
|
||||||
|
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
|
||||||
|
Cc: Grant Likely <grant.likely@secretlab.ca>
|
||||||
|
Cc: <linux-mmc@vger.kernel.org>
|
||||||
|
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||||
|
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||||
|
---
|
||||||
|
drivers/mmc/host/sdhci.c | 5 +++++
|
||||||
|
drivers/mmc/host/sdhci.h | 1 +
|
||||||
|
2 files changed, 6 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
|
||||||
|
index c6d1bd8..955cad9 100644
|
||||||
|
--- a/drivers/mmc/host/sdhci.c
|
||||||
|
+++ b/drivers/mmc/host/sdhci.c
|
||||||
|
@@ -1159,6 +1159,11 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||||
|
|
||||||
|
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
|
||||||
|
|
||||||
|
+ if (ios->bus_width == MMC_BUS_WIDTH_8)
|
||||||
|
+ ctrl |= SDHCI_CTRL_8BITBUS;
|
||||||
|
+ else
|
||||||
|
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
|
||||||
|
+
|
||||||
|
if (ios->bus_width == MMC_BUS_WIDTH_4)
|
||||||
|
ctrl |= SDHCI_CTRL_4BITBUS;
|
||||||
|
else
|
||||||
|
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
|
||||||
|
index c846813..eb5efe0 100644
|
||||||
|
--- a/drivers/mmc/host/sdhci.h
|
||||||
|
+++ b/drivers/mmc/host/sdhci.h
|
||||||
|
@@ -72,6 +72,7 @@
|
||||||
|
#define SDHCI_CTRL_ADMA1 0x08
|
||||||
|
#define SDHCI_CTRL_ADMA32 0x10
|
||||||
|
#define SDHCI_CTRL_ADMA64 0x18
|
||||||
|
+#define SDHCI_CTRL_8BITBUS 0x20
|
||||||
|
|
||||||
|
#define SDHCI_POWER_CONTROL 0x29
|
||||||
|
#define SDHCI_POWER_ON 0x01
|
||||||
|
--
|
||||||
|
1.7.1
|
||||||
|
|
||||||
|
_______________________________________________
|
||||||
|
kernel mailing list
|
||||||
|
kernel@lists.fedoraproject.org
|
||||||
|
https://admin.fedoraproject.org/mailman/listinfo/kernel
|
||||||
|
|
1
sources
1
sources
|
@ -1 +1,2 @@
|
||||||
091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2
|
091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2
|
||||||
|
0741b3219a009fdfc41c766416007fcf patch-2.6.35.10.bz2
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
From 4d9d1ff88f920e9fcdde155c0a1366b7e0462d14 Mon Sep 17 00:00:00 2001
|
|
||||||
From: John W. Linville <linville@tuxdriver.com>
|
|
||||||
Date: Fri, 19 Mar 2010 14:58:01 -0400
|
|
||||||
Subject: [PATCH v4] ssb: do not read SPROM if it does not exist
|
|
||||||
|
|
||||||
Attempting to read registers that don't exist on the SSB bus can cause
|
|
||||||
hangs on some boxes. At least some b43 devices are 'in the wild' that
|
|
||||||
don't have SPROMs at all. When the SSB bus support loads, it attempts
|
|
||||||
to read these (non-existant) SPROMs and causes hard hangs on the box --
|
|
||||||
no console output, etc.
|
|
||||||
|
|
||||||
This patch adds some intelligence to determine whether or not the SPROM
|
|
||||||
is present before attempting to read it. This avoids those hard hangs
|
|
||||||
on those devices with no SPROM attached to their SSB bus. The
|
|
||||||
SSB-attached devices (e.g. b43, et al.) won't work, but at least the box
|
|
||||||
will survive to test further patches. :-)
|
|
||||||
|
|
||||||
Signed-off-by: John W. Linville <linville@tuxdriver.com>
|
|
||||||
Cc: Larry Finger <Larry.Finger@lwfinger.net>
|
|
||||||
Cc: Michael Buesch <mb@bu3sch.de>
|
|
||||||
Cc: stable@kernel.org
|
|
||||||
---
|
|
||||||
drivers/ssb/driver_chipcommon.c | 3 +++
|
|
||||||
drivers/ssb/pci.c | 3 +++
|
|
||||||
drivers/ssb/sprom.c | 26 ++++++++++++++++++++++++++
|
|
||||||
include/linux/ssb/ssb.h | 3 +++
|
|
||||||
include/linux/ssb/ssb_driver_chipcommon.h | 15 +++++++++++++++
|
|
||||||
5 files changed, 50 insertions(+), 0 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
|
|
||||||
index 9681536..6cf288d 100644
|
|
||||||
--- a/drivers/ssb/driver_chipcommon.c
|
|
||||||
+++ b/drivers/ssb/driver_chipcommon.c
|
|
||||||
@@ -233,6 +233,9 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
|
|
||||||
{
|
|
||||||
if (!cc->dev)
|
|
||||||
return; /* We don't have a ChipCommon */
|
|
||||||
+ if (cc->dev->id.revision >= 11) {
|
|
||||||
+ cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
|
|
||||||
+ }
|
|
||||||
ssb_pmu_init(cc);
|
|
||||||
chipco_powercontrol_init(cc);
|
|
||||||
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
|
|
||||||
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
|
|
||||||
index a8dbb06..89d7ab1 100644
|
|
||||||
--- a/drivers/ssb/pci.c
|
|
||||||
+++ b/drivers/ssb/pci.c
|
|
||||||
@@ -621,6 +621,9 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
|
|
||||||
int err = -ENOMEM;
|
|
||||||
u16 *buf;
|
|
||||||
|
|
||||||
+ if (!ssb_is_sprom_available(bus))
|
|
||||||
+ return -ENODEV;
|
|
||||||
+
|
|
||||||
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
|
|
||||||
if (!buf)
|
|
||||||
goto out;
|
|
||||||
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
|
|
||||||
index f2f920f..c690f58 100644
|
|
||||||
--- a/drivers/ssb/sprom.c
|
|
||||||
+++ b/drivers/ssb/sprom.c
|
|
||||||
@@ -176,3 +176,29 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void)
|
|
||||||
{
|
|
||||||
return fallback_sprom;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+bool ssb_is_sprom_available(struct ssb_bus *bus)
|
|
||||||
+{
|
|
||||||
+ /* some older devices don't have chipcommon, but they have sprom */
|
|
||||||
+ if (!bus->chipco.dev)
|
|
||||||
+ return true;
|
|
||||||
+
|
|
||||||
+ /* status register only exists on chipcomon rev >= 11 */
|
|
||||||
+ if (bus->chipco.dev->id.revision < 11)
|
|
||||||
+ return true;
|
|
||||||
+
|
|
||||||
+ switch (bus->chip_id) {
|
|
||||||
+ case 0x4312:
|
|
||||||
+ return SSB_CHIPCO_CHST_4312_SPROM_PRESENT(bus->chipco.status);
|
|
||||||
+ case 0x4322:
|
|
||||||
+ return SSB_CHIPCO_CHST_4322_SPROM_PRESENT(bus->chipco.status);
|
|
||||||
+ case 0x4325:
|
|
||||||
+ return SSB_CHIPCO_CHST_4325_SPROM_PRESENT(bus->chipco.status);
|
|
||||||
+ default:
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ if (bus->chipco.dev->id.revision >= 31)
|
|
||||||
+ return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
|
|
||||||
+
|
|
||||||
+ return true;
|
|
||||||
+}
|
|
||||||
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
|
|
||||||
index 24f9885..3b4da23 100644
|
|
||||||
--- a/include/linux/ssb/ssb.h
|
|
||||||
+++ b/include/linux/ssb/ssb.h
|
|
||||||
@@ -394,6 +394,9 @@ extern int ssb_bus_sdiobus_register(struct ssb_bus *bus,
|
|
||||||
|
|
||||||
extern void ssb_bus_unregister(struct ssb_bus *bus);
|
|
||||||
|
|
||||||
+/* Does the device have an SPROM? */
|
|
||||||
+extern bool ssb_is_sprom_available(struct ssb_bus *bus);
|
|
||||||
+
|
|
||||||
/* Set a fallback SPROM.
|
|
||||||
* See kdoc at the function definition for complete documentation. */
|
|
||||||
extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
|
|
||||||
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
|
|
||||||
index 4e27acf..2cdf249 100644
|
|
||||||
--- a/include/linux/ssb/ssb_driver_chipcommon.h
|
|
||||||
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
|
|
||||||
@@ -53,6 +53,7 @@
|
|
||||||
#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */
|
|
||||||
#define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */
|
|
||||||
#define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */
|
|
||||||
+#define SSB_CHIPCO_CAP_SPROM 0x40000000 /* SPROM present */
|
|
||||||
#define SSB_CHIPCO_CORECTL 0x0008
|
|
||||||
#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */
|
|
||||||
#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
|
|
||||||
@@ -385,6 +386,7 @@
|
|
||||||
|
|
||||||
|
|
||||||
/** Chip specific Chip-Status register contents. */
|
|
||||||
+#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS 0x00000040 /* SPROM present */
|
|
||||||
#define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL 0x00000003
|
|
||||||
#define SSB_CHIPCO_CHST_4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */
|
|
||||||
#define SSB_CHIPCO_CHST_4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */
|
|
||||||
@@ -398,6 +400,18 @@
|
|
||||||
#define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT 4
|
|
||||||
#define SSB_CHIPCO_CHST_4325_PMUTOP_2B 0x00000200 /* 1 for 2b, 0 for to 2a */
|
|
||||||
|
|
||||||
+/** Macros to determine SPROM presence based on Chip-Status register. */
|
|
||||||
+#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \
|
|
||||||
+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
|
|
||||||
+ SSB_CHIPCO_CHST_4325_OTP_SEL)
|
|
||||||
+#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \
|
|
||||||
+ (status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS)
|
|
||||||
+#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \
|
|
||||||
+ (((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
|
|
||||||
+ SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \
|
|
||||||
+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
|
|
||||||
+ SSB_CHIPCO_CHST_4325_OTP_SEL))
|
|
||||||
+
|
|
||||||
|
|
||||||
|
|
||||||
/** Clockcontrol masks and values **/
|
|
||||||
@@ -564,6 +578,7 @@ struct ssb_chipcommon_pmu {
|
|
||||||
struct ssb_chipcommon {
|
|
||||||
struct ssb_device *dev;
|
|
||||||
u32 capabilities;
|
|
||||||
+ u32 status;
|
|
||||||
/* Fast Powerup Delay constant */
|
|
||||||
u16 fast_pwrup_delay;
|
|
||||||
struct ssb_chipcommon_pmu pmu;
|
|
||||||
--
|
|
||||||
1.7.0.1
|
|
||||||
|
|
|
@ -1,21 +1,46 @@
|
||||||
diff -up linux-2.6.34.noarch/drivers/platform/x86/thinkpad_acpi.c.orig linux-2.6.34.noarch/drivers/platform/x86/thinkpad_acpi.c
|
From baa7ac7527ee3990007fb28b59ec1d73b922ddaa Mon Sep 17 00:00:00 2001
|
||||||
--- linux-2.6.34.noarch/drivers/platform/x86/thinkpad_acpi.c.orig 2010-05-17 16:28:13.254200070 -0400
|
From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
|
||||||
+++ linux-2.6.34.noarch/drivers/platform/x86/thinkpad_acpi.c 2010-05-17 16:29:56.471200083 -0400
|
Date: Mon, 9 Aug 2010 23:48:19 -0300
|
||||||
@@ -3397,7 +3397,7 @@ static int __init hotkey_init(struct ibm
|
Subject: [PATCH] thinkpad-acpi: untangle ACPI/vendor backlight selection
|
||||||
/* update bright_acpimode... */
|
|
||||||
tpacpi_check_std_acpi_brightness_support();
|
acpi_video_backlight_support() already tells us if ACPI is handling
|
||||||
|
backlight control through the generic ACPI handle. It is better to just
|
||||||
|
trust it.
|
||||||
|
|
||||||
|
While at it, adjust down a printk priority, and test earlier for
|
||||||
|
brightness_enable=0.
|
||||||
|
|
||||||
|
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
|
||||||
|
Signed-off-by: Matthew Garrett <mjg@redhat.com>
|
||||||
|
---
|
||||||
|
Documentation/laptops/thinkpad-acpi.txt | 4 +++
|
||||||
|
drivers/platform/x86/thinkpad_acpi.c | 42 ++++++++++++++----------------
|
||||||
|
2 files changed, 24 insertions(+), 22 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
|
||||||
|
index fc15538..720ba04 100644
|
||||||
|
--- a/Documentation/laptops/thinkpad-acpi.txt
|
||||||
|
+++ b/Documentation/laptops/thinkpad-acpi.txt
|
||||||
|
@@ -1073,6 +1073,10 @@ ThinkPad-specific interface. The driver will disable its native
|
||||||
|
backlight brightness control interface if it detects that the standard
|
||||||
|
ACPI interface is available in the ThinkPad.
|
||||||
|
|
||||||
- if (tp_features.bright_acpimode && acpi_video_backlight_support()) {
|
+If you want to use the thinkpad-acpi backlight brightness control
|
||||||
+ if (acpi_video_backlight_support()) {
|
+instead of the generic ACPI video backlight brightness control for some
|
||||||
printk(TPACPI_INFO
|
+reason, you should use the acpi_backlight=vendor kernel parameter.
|
||||||
"This ThinkPad has standard ACPI backlight "
|
+
|
||||||
"brightness control, supported by the ACPI "
|
The brightness_enable module parameter can be used to control whether
|
||||||
@@ -6189,26 +6189,24 @@ static int __init brightness_init(struct
|
the LCD brightness control feature will be enabled when available.
|
||||||
* going to publish a backlight interface
|
brightness_enable=0 forces it to be disabled. brightness_enable=1
|
||||||
*/
|
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
|
||||||
b = tpacpi_check_std_acpi_brightness_support();
|
index 4bdb137..b383cc6 100644
|
||||||
- if (b > 0) {
|
--- a/drivers/platform/x86/thinkpad_acpi.c
|
||||||
|
+++ b/drivers/platform/x86/thinkpad_acpi.c
|
||||||
|
@@ -6313,28 +6313,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
||||||
|
if (tp_features.bright_unkfw)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
- if (tp_features.bright_acpimode) {
|
||||||
- if (acpi_video_backlight_support()) {
|
- if (acpi_video_backlight_support()) {
|
||||||
- if (brightness_enable > 1) {
|
- if (brightness_enable > 1) {
|
||||||
- printk(TPACPI_NOTICE
|
- printk(TPACPI_NOTICE
|
||||||
|
@ -34,23 +59,39 @@ diff -up linux-2.6.34.noarch/drivers/platform/x86/thinkpad_acpi.c.orig linux-2.6
|
||||||
- "available, thinkpad_acpi native "
|
- "available, thinkpad_acpi native "
|
||||||
- "brightness control enabled\n");
|
- "brightness control enabled\n");
|
||||||
- }
|
- }
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
if (!brightness_enable) {
|
||||||
|
dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
|
||||||
|
"brightness support disabled by "
|
||||||
|
@@ -6342,6 +6320,26 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
+ if (acpi_video_backlight_support()) {
|
+ if (acpi_video_backlight_support()) {
|
||||||
+ if (brightness_enable > 1) {
|
+ if (brightness_enable > 1) {
|
||||||
+ printk(TPACPI_NOTICE
|
+ printk(TPACPI_INFO
|
||||||
+ "Standard ACPI backlight interface "
|
+ "Standard ACPI backlight interface "
|
||||||
+ "available, not loading native one.\n");
|
+ "available, not loading native one.\n");
|
||||||
+ return 1;
|
+ return 1;
|
||||||
+ } else if (brightness_enable == 1) {
|
+ } else if (brightness_enable == 1) {
|
||||||
+ printk(TPACPI_NOTICE
|
+ printk(TPACPI_WARN
|
||||||
+ "Backlight control force enabled, even if standard "
|
+ "Cannot enable backlight brightness support, "
|
||||||
+ "ACPI backlight interface is available\n");
|
+ "ACPI is already handling it. Refer to the "
|
||||||
|
+ "acpi_backlight kernel parameter\n");
|
||||||
|
+ return 1;
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else if (tp_features.bright_acpimode && brightness_enable > 1) {
|
||||||
+ if (brightness_enable > 1) {
|
+ printk(TPACPI_NOTICE
|
||||||
+ printk(TPACPI_NOTICE
|
+ "Standard ACPI backlight interface not "
|
||||||
+ "Standard ACPI backlight interface not "
|
+ "available, thinkpad_acpi native "
|
||||||
+ "available, thinkpad_acpi native "
|
+ "brightness control enabled\n");
|
||||||
+ "brightness control enabled\n");
|
+ }
|
||||||
}
|
+
|
||||||
}
|
/*
|
||||||
|
* Check for module parameter bogosity, note that we
|
||||||
|
* init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
commit 8cf5102c84dba60b2ea29b7e89f1a65100e20bb9
|
||||||
|
Author: Matthew Garrett <mjg@redhat.com>
|
||||||
|
Date: Thu Oct 21 17:31:56 2010 -0400
|
||||||
|
|
||||||
|
tpm: Autodetect itpm devices
|
||||||
|
|
||||||
|
Some Lenovos have TPMs that require a quirk to function correctly. This can
|
||||||
|
be autodetected by checking whether the device has a _HID of INTC0102. This
|
||||||
|
is an invalid PNPid, and as such is discarded by the pnp layer - however
|
||||||
|
it's still present in the ACPI code, so we can pull it out that way. This
|
||||||
|
means that the quirk won't be automatically applied on non-ACPI systems,
|
||||||
|
but without ACPI we don't have any way to identify the chip anyway so I
|
||||||
|
don't think that's a great concern.
|
||||||
|
|
||||||
|
Signed-off-by: Matthew Garrett <mjg@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
|
||||||
|
index 1030f84..c17a305 100644
|
||||||
|
--- a/drivers/char/tpm/tpm_tis.c
|
||||||
|
+++ b/drivers/char/tpm/tpm_tis.c
|
||||||
|
@@ -25,6 +25,7 @@
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
+#include <linux/acpi.h>
|
||||||
|
#include "tpm.h"
|
||||||
|
|
||||||
|
#define TPM_HEADER_SIZE 10
|
||||||
|
@@ -78,6 +79,26 @@ enum tis_defaults {
|
||||||
|
static LIST_HEAD(tis_chips);
|
||||||
|
static DEFINE_SPINLOCK(tis_lock);
|
||||||
|
|
||||||
|
+#ifdef CONFIG_ACPI
|
||||||
|
+static int is_itpm(struct pnp_dev *dev)
|
||||||
|
+{
|
||||||
|
+ struct acpi_device *acpi = pnp_acpi_device(dev);
|
||||||
|
+ struct acpi_hardware_id *id;
|
||||||
|
+
|
||||||
|
+ list_for_each_entry(id, &acpi->pnp.ids, list) {
|
||||||
|
+ if (!strcmp("INTC0102", id->id))
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+#else
|
||||||
|
+static int is_itpm(struct pnp_dev *dev)
|
||||||
|
+{
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
static int check_locality(struct tpm_chip *chip, int l)
|
||||||
|
{
|
||||||
|
if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
|
||||||
|
@@ -472,6 +493,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||||
|
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
|
||||||
|
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
|
||||||
|
|
||||||
|
+ if (is_itpm(to_pnp_dev(dev)))
|
||||||
|
+ itpm = 1;
|
||||||
|
+
|
||||||
|
if (itpm)
|
||||||
|
dev_info(dev, "Intel iTPM workaround enabled\n");
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
Fix TPM timeouts on boot (#530393)
|
||||||
|
|
||||||
|
--- a/drivers/char/tpm/tpm.c
|
||||||
|
+++ a/drivers/char/tpm/tpm.c
|
||||||
|
@@ -354,12 +354,14 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
|
||||||
|
tpm_protected_ordinal_duration[ordinal &
|
||||||
|
TPM_PROTECTED_ORDINAL_MASK];
|
||||||
|
|
||||||
|
- if (duration_idx != TPM_UNDEFINED)
|
||||||
|
+ if (duration_idx != TPM_UNDEFINED) {
|
||||||
|
duration = chip->vendor.duration[duration_idx];
|
||||||
|
- if (duration <= 0)
|
||||||
|
+ /* if duration is 0, it's because chip->vendor.duration wasn't */
|
||||||
|
+ /* filled yet, so we set the lowest timeout just to give enough */
|
||||||
|
+ /* time to tpm_get_timeouts() succeed */
|
||||||
|
+ return (duration <= 0 ? HZ : duration);
|
||||||
|
+ } else
|
||||||
|
return 2 * 60 * HZ;
|
||||||
|
- else
|
||||||
|
- return duration;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,982 @@
|
||||||
|
From f815dfecf23bfd19d4b5e9f1a660b1f5dbe70472 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alan Cox <alan@linux.intel.com>
|
||||||
|
Date: Thu, 16 Sep 2010 18:21:52 +0100
|
||||||
|
Subject: [PATCH 2/2] tty: icount changeover for other main devices
|
||||||
|
|
||||||
|
Again basically cut and paste
|
||||||
|
|
||||||
|
Convert the main driver set to use the hooks for GICOUNT
|
||||||
|
|
||||||
|
Signed-off-by: Alan Cox <alan@linux.intel.com>
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
|
---
|
||||||
|
arch/ia64/hp/sim/simserial.c | 12 +------
|
||||||
|
drivers/char/amiserial.c | 56 ++++++++++++++++-------------
|
||||||
|
drivers/char/cyclades.c | 49 +++++++++++++------------
|
||||||
|
drivers/char/ip2/ip2main.c | 72 ++++++++++++++++++++++---------------
|
||||||
|
drivers/char/mxser.c | 62 ++++++++++++++++++--------------
|
||||||
|
drivers/char/nozomi.c | 37 +++++++++----------
|
||||||
|
drivers/char/pcmcia/synclink_cs.c | 60 ++++++++++++++-----------------
|
||||||
|
drivers/char/synclink.c | 73 +++++++++++++++++--------------------
|
||||||
|
drivers/char/synclink_gt.c | 56 +++++++++++++++--------------
|
||||||
|
drivers/char/synclinkmp.c | 61 ++++++++++++++-----------------
|
||||||
|
drivers/serial/68360serial.c | 51 +++++++++++++-------------
|
||||||
|
net/bluetooth/rfcomm/tty.c | 4 --
|
||||||
|
12 files changed, 297 insertions(+), 296 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
|
||||||
|
index 2bef526..204f650 100644
|
||||||
|
--- a/arch/ia64/hp/sim/simserial.c
|
||||||
|
+++ b/arch/ia64/hp/sim/simserial.c
|
||||||
|
@@ -395,7 +395,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
{
|
||||||
|
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||||
|
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
|
||||||
|
- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
|
||||||
|
+ (cmd != TIOCMIWAIT)) {
|
||||||
|
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
@@ -433,16 +433,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
case TIOCMIWAIT:
|
||||||
|
printk(KERN_INFO "rs_ioctl: TIOCMIWAIT: called\n");
|
||||||
|
return 0;
|
||||||
|
- /*
|
||||||
|
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
- * Return: write counters to the user passed counter struct
|
||||||
|
- * NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
- * RI where only 0->1 is counted.
|
||||||
|
- */
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- printk(KERN_INFO "rs_ioctl: TIOCGICOUNT called\n");
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
case TIOCSERGWILD:
|
||||||
|
case TIOCSERSWILD:
|
||||||
|
/* "setserial -W" is called in Debian boot */
|
||||||
|
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
|
||||||
|
index 4f8d60c..2918d5d 100644
|
||||||
|
--- a/drivers/char/amiserial.c
|
||||||
|
+++ b/drivers/char/amiserial.c
|
||||||
|
@@ -1263,6 +1263,36 @@ static int rs_break(struct tty_struct *tty, int break_state)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
+ * Return: write counters to the user passed counter struct
|
||||||
|
+ * NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
+ * RI where only 0->1 is counted.
|
||||||
|
+ */
|
||||||
|
+static int rs_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
+{
|
||||||
|
+ struct async_struct *info = tty->driver_data;
|
||||||
|
+ struct async_icount cnow;
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ local_irq_save(flags);
|
||||||
|
+ cnow = info->state->icount;
|
||||||
|
+ local_irq_restore(flags);
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+ icount->rx = cnow.rx;
|
||||||
|
+ icount->tx = cnow.tx;
|
||||||
|
+ icount->frame = cnow.frame;
|
||||||
|
+ icount->overrun = cnow.overrun;
|
||||||
|
+ icount->parity = cnow.parity;
|
||||||
|
+ icount->brk = cnow.brk;
|
||||||
|
+ icount->buf_overrun = cnow.buf_overrun;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
|
||||||
|
static int rs_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
@@ -1332,31 +1362,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
}
|
||||||
|
/* NOTREACHED */
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
- * Return: write counters to the user passed counter struct
|
||||||
|
- * NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
- * RI where only 0->1 is counted.
|
||||||
|
- */
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- local_irq_save(flags);
|
||||||
|
- cnow = info->state->icount;
|
||||||
|
- local_irq_restore(flags);
|
||||||
|
- icount.cts = cnow.cts;
|
||||||
|
- icount.dsr = cnow.dsr;
|
||||||
|
- icount.rng = cnow.rng;
|
||||||
|
- icount.dcd = cnow.dcd;
|
||||||
|
- icount.rx = cnow.rx;
|
||||||
|
- icount.tx = cnow.tx;
|
||||||
|
- icount.frame = cnow.frame;
|
||||||
|
- icount.overrun = cnow.overrun;
|
||||||
|
- icount.parity = cnow.parity;
|
||||||
|
- icount.brk = cnow.brk;
|
||||||
|
- icount.buf_overrun = cnow.buf_overrun;
|
||||||
|
-
|
||||||
|
- if (copy_to_user(argp, &icount, sizeof(icount)))
|
||||||
|
- return -EFAULT;
|
||||||
|
- return 0;
|
||||||
|
case TIOCSERGWILD:
|
||||||
|
case TIOCSERSWILD:
|
||||||
|
/* "setserial -W" is called in Debian boot */
|
||||||
|
@@ -1949,6 +1954,7 @@ static const struct tty_operations serial_ops = {
|
||||||
|
.wait_until_sent = rs_wait_until_sent,
|
||||||
|
.tiocmget = rs_tiocmget,
|
||||||
|
.tiocmset = rs_tiocmset,
|
||||||
|
+ .get_icount = rs_get_icount,
|
||||||
|
.proc_fops = &rs_proc_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
|
||||||
|
index 9824b41..2364df8 100644
|
||||||
|
--- a/drivers/char/cyclades.c
|
||||||
|
+++ b/drivers/char/cyclades.c
|
||||||
|
@@ -2791,29 +2791,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
* NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
* RI where only 0->1 is counted.
|
||||||
|
*/
|
||||||
|
- case TIOCGICOUNT: {
|
||||||
|
- struct serial_icounter_struct sic = { };
|
||||||
|
-
|
||||||
|
- spin_lock_irqsave(&info->card->card_lock, flags);
|
||||||
|
- cnow = info->icount;
|
||||||
|
- spin_unlock_irqrestore(&info->card->card_lock, flags);
|
||||||
|
-
|
||||||
|
- sic.cts = cnow.cts;
|
||||||
|
- sic.dsr = cnow.dsr;
|
||||||
|
- sic.rng = cnow.rng;
|
||||||
|
- sic.dcd = cnow.dcd;
|
||||||
|
- sic.rx = cnow.rx;
|
||||||
|
- sic.tx = cnow.tx;
|
||||||
|
- sic.frame = cnow.frame;
|
||||||
|
- sic.overrun = cnow.overrun;
|
||||||
|
- sic.parity = cnow.parity;
|
||||||
|
- sic.brk = cnow.brk;
|
||||||
|
- sic.buf_overrun = cnow.buf_overrun;
|
||||||
|
-
|
||||||
|
- if (copy_to_user(argp, &sic, sizeof(sic)))
|
||||||
|
- ret_val = -EFAULT;
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
default:
|
||||||
|
ret_val = -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
@@ -2825,6 +2802,31 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
return ret_val;
|
||||||
|
} /* cy_ioctl */
|
||||||
|
|
||||||
|
+static int cy_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *sic)
|
||||||
|
+{
|
||||||
|
+ struct cyclades_port *info = tty->driver_data;
|
||||||
|
+ struct cyclades_icount cnow; /* Used to snapshot */
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&info->card->card_lock, flags);
|
||||||
|
+ cnow = info->icount;
|
||||||
|
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
|
||||||
|
+
|
||||||
|
+ sic->cts = cnow.cts;
|
||||||
|
+ sic->dsr = cnow.dsr;
|
||||||
|
+ sic->rng = cnow.rng;
|
||||||
|
+ sic->dcd = cnow.dcd;
|
||||||
|
+ sic->rx = cnow.rx;
|
||||||
|
+ sic->tx = cnow.tx;
|
||||||
|
+ sic->frame = cnow.frame;
|
||||||
|
+ sic->overrun = cnow.overrun;
|
||||||
|
+ sic->parity = cnow.parity;
|
||||||
|
+ sic->brk = cnow.brk;
|
||||||
|
+ sic->buf_overrun = cnow.buf_overrun;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* This routine allows the tty driver to be notified when
|
||||||
|
* device's termios settings have changed. Note that a
|
||||||
|
@@ -4086,6 +4088,7 @@ static const struct tty_operations cy_ops = {
|
||||||
|
.wait_until_sent = cy_wait_until_sent,
|
||||||
|
.tiocmget = cy_tiocmget,
|
||||||
|
.tiocmset = cy_tiocmset,
|
||||||
|
+ .get_icount = cy_get_icount,
|
||||||
|
.proc_fops = &cyclades_proc_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
|
||||||
|
index 911e1da..c0f864c 100644
|
||||||
|
--- a/drivers/char/ip2/ip2main.c
|
||||||
|
+++ b/drivers/char/ip2/ip2main.c
|
||||||
|
@@ -183,6 +183,8 @@ static void ip2_hangup(PTTY);
|
||||||
|
static int ip2_tiocmget(struct tty_struct *tty, struct file *file);
|
||||||
|
static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
|
||||||
|
unsigned int set, unsigned int clear);
|
||||||
|
+static int ip2_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount);
|
||||||
|
|
||||||
|
static void set_irq(int, int);
|
||||||
|
static void ip2_interrupt_bh(struct work_struct *work);
|
||||||
|
@@ -454,6 +456,7 @@ static const struct tty_operations ip2_ops = {
|
||||||
|
.hangup = ip2_hangup,
|
||||||
|
.tiocmget = ip2_tiocmget,
|
||||||
|
.tiocmset = ip2_tiocmset,
|
||||||
|
+ .get_icount = ip2_get_icount,
|
||||||
|
.proc_fops = &ip2_proc_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -2124,7 +2127,6 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
|
||||||
|
i2ChanStrPtr pCh = DevTable[tty->index];
|
||||||
|
i2eBordStrPtr pB;
|
||||||
|
struct async_icount cprev, cnow; /* kernel counter temps */
|
||||||
|
- struct serial_icounter_struct __user *p_cuser;
|
||||||
|
int rc = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
@@ -2293,34 +2295,6 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
- * Return: write counters to the user passed counter struct
|
||||||
|
- * NB: both 1->0 and 0->1 transitions are counted except for RI where
|
||||||
|
- * only 0->1 is counted. The controller is quite capable of counting
|
||||||
|
- * both, but this done to preserve compatibility with the standard
|
||||||
|
- * serial driver.
|
||||||
|
- */
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
|
||||||
|
-
|
||||||
|
- write_lock_irqsave(&pB->read_fifo_spinlock, flags);
|
||||||
|
- cnow = pCh->icount;
|
||||||
|
- write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
|
||||||
|
- p_cuser = argp;
|
||||||
|
- rc = put_user(cnow.cts, &p_cuser->cts);
|
||||||
|
- rc = put_user(cnow.dsr, &p_cuser->dsr);
|
||||||
|
- rc = put_user(cnow.rng, &p_cuser->rng);
|
||||||
|
- rc = put_user(cnow.dcd, &p_cuser->dcd);
|
||||||
|
- rc = put_user(cnow.rx, &p_cuser->rx);
|
||||||
|
- rc = put_user(cnow.tx, &p_cuser->tx);
|
||||||
|
- rc = put_user(cnow.frame, &p_cuser->frame);
|
||||||
|
- rc = put_user(cnow.overrun, &p_cuser->overrun);
|
||||||
|
- rc = put_user(cnow.parity, &p_cuser->parity);
|
||||||
|
- rc = put_user(cnow.brk, &p_cuser->brk);
|
||||||
|
- rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
|
||||||
|
- break;
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
* The rest are not supported by this driver. By returning -ENOIOCTLCMD they
|
||||||
|
* will be passed to the line discipline for it to handle.
|
||||||
|
*/
|
||||||
|
@@ -2344,6 +2318,46 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ip2_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
+{
|
||||||
|
+ i2ChanStrPtr pCh = DevTable[tty->index];
|
||||||
|
+ i2eBordStrPtr pB;
|
||||||
|
+ struct async_icount cnow; /* kernel counter temp */
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ if ( pCh == NULL )
|
||||||
|
+ return -ENODEV;
|
||||||
|
+
|
||||||
|
+ pB = pCh->pMyBord;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
+ * Return: write counters to the user passed counter struct
|
||||||
|
+ * NB: both 1->0 and 0->1 transitions are counted except for RI where
|
||||||
|
+ * only 0->1 is counted. The controller is quite capable of counting
|
||||||
|
+ * both, but this done to preserve compatibility with the standard
|
||||||
|
+ * serial driver.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
|
||||||
|
+ cnow = pCh->icount;
|
||||||
|
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
|
||||||
|
+
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+ icount->rx = cnow.rx;
|
||||||
|
+ icount->tx = cnow.tx;
|
||||||
|
+ icount->frame = cnow.frame;
|
||||||
|
+ icount->overrun = cnow.overrun;
|
||||||
|
+ icount->parity = cnow.parity;
|
||||||
|
+ icount->brk = cnow.brk;
|
||||||
|
+ icount->buf_overrun = cnow.buf_overrun;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Function: GetSerialInfo() */
|
||||||
|
/* Parameters: Pointer to channel structure */
|
||||||
|
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
|
||||||
|
index d2692d4..65aeae8 100644
|
||||||
|
--- a/drivers/char/mxser.c
|
||||||
|
+++ b/drivers/char/mxser.c
|
||||||
|
@@ -1700,7 +1700,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
|
||||||
|
+ if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT &&
|
||||||
|
test_bit(TTY_IO_ERROR, &tty->flags))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
@@ -1730,32 +1730,6 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
|
||||||
|
return wait_event_interruptible(info->port.delta_msr_wait,
|
||||||
|
mxser_cflags_changed(info, arg, &cnow));
|
||||||
|
- /*
|
||||||
|
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
- * Return: write counters to the user passed counter struct
|
||||||
|
- * NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
- * RI where only 0->1 is counted.
|
||||||
|
- */
|
||||||
|
- case TIOCGICOUNT: {
|
||||||
|
- struct serial_icounter_struct icnt = { 0 };
|
||||||
|
- spin_lock_irqsave(&info->slock, flags);
|
||||||
|
- cnow = info->icount;
|
||||||
|
- spin_unlock_irqrestore(&info->slock, flags);
|
||||||
|
-
|
||||||
|
- icnt.frame = cnow.frame;
|
||||||
|
- icnt.brk = cnow.brk;
|
||||||
|
- icnt.overrun = cnow.overrun;
|
||||||
|
- icnt.buf_overrun = cnow.buf_overrun;
|
||||||
|
- icnt.parity = cnow.parity;
|
||||||
|
- icnt.rx = cnow.rx;
|
||||||
|
- icnt.tx = cnow.tx;
|
||||||
|
- icnt.cts = cnow.cts;
|
||||||
|
- icnt.dsr = cnow.dsr;
|
||||||
|
- icnt.rng = cnow.rng;
|
||||||
|
- icnt.dcd = cnow.dcd;
|
||||||
|
-
|
||||||
|
- return copy_to_user(argp, &icnt, sizeof(icnt)) ? -EFAULT : 0;
|
||||||
|
- }
|
||||||
|
case MOXA_HighSpeedOn:
|
||||||
|
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
|
||||||
|
case MOXA_SDS_RSTICOUNTER:
|
||||||
|
@@ -1828,6 +1802,39 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /*
|
||||||
|
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
+ * Return: write counters to the user passed counter struct
|
||||||
|
+ * NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
+ * RI where only 0->1 is counted.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+static int mxser_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
+
|
||||||
|
+{
|
||||||
|
+ struct mxser_port *info = tty->driver_data;
|
||||||
|
+ struct async_icount cnow;
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&info->slock, flags);
|
||||||
|
+ cnow = info->icount;
|
||||||
|
+ spin_unlock_irqrestore(&info->slock, flags);
|
||||||
|
+
|
||||||
|
+ icount->frame = cnow.frame;
|
||||||
|
+ icount->brk = cnow.brk;
|
||||||
|
+ icount->overrun = cnow.overrun;
|
||||||
|
+ icount->buf_overrun = cnow.buf_overrun;
|
||||||
|
+ icount->parity = cnow.parity;
|
||||||
|
+ icount->rx = cnow.rx;
|
||||||
|
+ icount->tx = cnow.tx;
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void mxser_stoprx(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
struct mxser_port *info = tty->driver_data;
|
||||||
|
@@ -2326,6 +2333,7 @@ static const struct tty_operations mxser_ops = {
|
||||||
|
.wait_until_sent = mxser_wait_until_sent,
|
||||||
|
.tiocmget = mxser_tiocmget,
|
||||||
|
.tiocmset = mxser_tiocmset,
|
||||||
|
+ .get_icount = mxser_get_icount,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tty_port_operations mxser_port_ops = {
|
||||||
|
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
|
||||||
|
index 18af923..0924435 100644
|
||||||
|
--- a/drivers/char/nozomi.c
|
||||||
|
+++ b/drivers/char/nozomi.c
|
||||||
|
@@ -1805,24 +1805,24 @@ static int ntty_cflags_changed(struct port *port, unsigned long flags,
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp)
|
||||||
|
+static int ntty_tiocgicount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
{
|
||||||
|
+ struct port *port = tty->driver_data;
|
||||||
|
const struct async_icount cnow = port->tty_icount;
|
||||||
|
- struct serial_icounter_struct icount;
|
||||||
|
-
|
||||||
|
- icount.cts = cnow.cts;
|
||||||
|
- icount.dsr = cnow.dsr;
|
||||||
|
- icount.rng = cnow.rng;
|
||||||
|
- icount.dcd = cnow.dcd;
|
||||||
|
- icount.rx = cnow.rx;
|
||||||
|
- icount.tx = cnow.tx;
|
||||||
|
- icount.frame = cnow.frame;
|
||||||
|
- icount.overrun = cnow.overrun;
|
||||||
|
- icount.parity = cnow.parity;
|
||||||
|
- icount.brk = cnow.brk;
|
||||||
|
- icount.buf_overrun = cnow.buf_overrun;
|
||||||
|
-
|
||||||
|
- return copy_to_user(argp, &icount, sizeof(icount)) ? -EFAULT : 0;
|
||||||
|
+
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+ icount->rx = cnow.rx;
|
||||||
|
+ icount->tx = cnow.tx;
|
||||||
|
+ icount->frame = cnow.frame;
|
||||||
|
+ icount->overrun = cnow.overrun;
|
||||||
|
+ icount->parity = cnow.parity;
|
||||||
|
+ icount->brk = cnow.brk;
|
||||||
|
+ icount->buf_overrun = cnow.buf_overrun;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ntty_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
@@ -1841,9 +1841,7 @@ static int ntty_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
rval = wait_event_interruptible(port->tty_wait,
|
||||||
|
ntty_cflags_changed(port, arg, &cprev));
|
||||||
|
break;
|
||||||
|
- } case TIOCGICOUNT:
|
||||||
|
- rval = ntty_ioctl_tiocgicount(port, argp);
|
||||||
|
- break;
|
||||||
|
+ }
|
||||||
|
default:
|
||||||
|
DBG1("ERR: 0x%08X, %d", cmd, cmd);
|
||||||
|
break;
|
||||||
|
@@ -1923,6 +1921,7 @@ static const struct tty_operations tty_ops = {
|
||||||
|
.chars_in_buffer = ntty_chars_in_buffer,
|
||||||
|
.tiocmget = ntty_tiocmget,
|
||||||
|
.tiocmset = ntty_tiocmset,
|
||||||
|
+ .get_icount = ntty_tiocgicount,
|
||||||
|
.install = ntty_install,
|
||||||
|
.cleanup = ntty_cleanup,
|
||||||
|
};
|
||||||
|
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
|
||||||
|
index 824d67c..1dc493f 100644
|
||||||
|
--- a/drivers/char/pcmcia/synclink_cs.c
|
||||||
|
+++ b/drivers/char/pcmcia/synclink_cs.c
|
||||||
|
@@ -2220,6 +2220,32 @@ static int mgslpc_break(struct tty_struct *tty, int break_state)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int mgslpc_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
+{
|
||||||
|
+ MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
|
||||||
|
+ struct mgsl_icount cnow; /* kernel counter temps */
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&info->lock,flags);
|
||||||
|
+ cnow = info->icount;
|
||||||
|
+ spin_unlock_irqrestore(&info->lock,flags);
|
||||||
|
+
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+ icount->rx = cnow.rx;
|
||||||
|
+ icount->tx = cnow.tx;
|
||||||
|
+ icount->frame = cnow.frame;
|
||||||
|
+ icount->overrun = cnow.overrun;
|
||||||
|
+ icount->parity = cnow.parity;
|
||||||
|
+ icount->brk = cnow.brk;
|
||||||
|
+ icount->buf_overrun = cnow.buf_overrun;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Service an IOCTL request
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
@@ -2235,11 +2261,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
|
||||||
|
- int error;
|
||||||
|
- struct mgsl_icount cnow; /* kernel counter temps */
|
||||||
|
- struct serial_icounter_struct __user *p_cuser; /* user space */
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
- unsigned long flags;
|
||||||
|
|
||||||
|
if (debug_level >= DEBUG_LEVEL_INFO)
|
||||||
|
printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
|
||||||
|
@@ -2249,7 +2271,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||||
|
- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
|
||||||
|
+ (cmd != TIOCMIWAIT)) {
|
||||||
|
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
@@ -2279,34 +2301,6 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
return wait_events(info, argp);
|
||||||
|
case TIOCMIWAIT:
|
||||||
|
return modem_input_wait(info,(int)arg);
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- spin_lock_irqsave(&info->lock,flags);
|
||||||
|
- cnow = info->icount;
|
||||||
|
- spin_unlock_irqrestore(&info->lock,flags);
|
||||||
|
- p_cuser = argp;
|
||||||
|
- PUT_USER(error,cnow.cts, &p_cuser->cts);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.dsr, &p_cuser->dsr);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.rng, &p_cuser->rng);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.dcd, &p_cuser->dcd);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.rx, &p_cuser->rx);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.tx, &p_cuser->tx);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.frame, &p_cuser->frame);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.overrun, &p_cuser->overrun);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.parity, &p_cuser->parity);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.brk, &p_cuser->brk);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
|
||||||
|
- if (error) return error;
|
||||||
|
- return 0;
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
|
||||||
|
index 0658fc5..9970aca 100644
|
||||||
|
--- a/drivers/char/synclink.c
|
||||||
|
+++ b/drivers/char/synclink.c
|
||||||
|
@@ -2920,6 +2920,38 @@ static int mgsl_break(struct tty_struct *tty, int break_state)
|
||||||
|
|
||||||
|
} /* end of mgsl_break() */
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
+ * Return: write counters to the user passed counter struct
|
||||||
|
+ * NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
+ * RI where only 0->1 is counted.
|
||||||
|
+ */
|
||||||
|
+static int msgl_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
+
|
||||||
|
+{
|
||||||
|
+ struct mgsl_struct * info = tty->driver_data;
|
||||||
|
+ struct mgsl_icount cnow; /* kernel counter temps */
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&info->irq_spinlock,flags);
|
||||||
|
+ cnow = info->icount;
|
||||||
|
+ spin_unlock_irqrestore(&info->irq_spinlock,flags);
|
||||||
|
+
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+ icount->rx = cnow.rx;
|
||||||
|
+ icount->tx = cnow.tx;
|
||||||
|
+ icount->frame = cnow.frame;
|
||||||
|
+ icount->overrun = cnow.overrun;
|
||||||
|
+ icount->parity = cnow.parity;
|
||||||
|
+ icount->brk = cnow.brk;
|
||||||
|
+ icount->buf_overrun = cnow.buf_overrun;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* mgsl_ioctl() Service an IOCTL request
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
@@ -2945,7 +2977,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||||
|
- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
|
||||||
|
+ (cmd != TIOCMIWAIT)) {
|
||||||
|
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
@@ -2958,11 +2990,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
|
||||||
|
static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
- int error;
|
||||||
|
- struct mgsl_icount cnow; /* kernel counter temps */
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
- struct serial_icounter_struct __user *p_cuser; /* user space */
|
||||||
|
- unsigned long flags;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case MGSL_IOCGPARAMS:
|
||||||
|
@@ -2991,40 +3019,6 @@ static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigne
|
||||||
|
case TIOCMIWAIT:
|
||||||
|
return modem_input_wait(info,(int)arg);
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
- * Return: write counters to the user passed counter struct
|
||||||
|
- * NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
- * RI where only 0->1 is counted.
|
||||||
|
- */
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- spin_lock_irqsave(&info->irq_spinlock,flags);
|
||||||
|
- cnow = info->icount;
|
||||||
|
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
|
||||||
|
- p_cuser = argp;
|
||||||
|
- PUT_USER(error,cnow.cts, &p_cuser->cts);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.dsr, &p_cuser->dsr);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.rng, &p_cuser->rng);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.dcd, &p_cuser->dcd);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.rx, &p_cuser->rx);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.tx, &p_cuser->tx);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.frame, &p_cuser->frame);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.overrun, &p_cuser->overrun);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.parity, &p_cuser->parity);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.brk, &p_cuser->brk);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
|
||||||
|
- if (error) return error;
|
||||||
|
- return 0;
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
@@ -4325,6 +4319,7 @@ static const struct tty_operations mgsl_ops = {
|
||||||
|
.hangup = mgsl_hangup,
|
||||||
|
.tiocmget = tiocmget,
|
||||||
|
.tiocmset = tiocmset,
|
||||||
|
+ .get_icount = msgl_get_icount,
|
||||||
|
.proc_fops = &mgsl_proc_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
|
||||||
|
index 4561ce2..54fa0ee4 100644
|
||||||
|
--- a/drivers/char/synclink_gt.c
|
||||||
|
+++ b/drivers/char/synclink_gt.c
|
||||||
|
@@ -1025,9 +1025,6 @@ static int ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
struct slgt_info *info = tty->driver_data;
|
||||||
|
- struct mgsl_icount cnow; /* kernel counter temps */
|
||||||
|
- struct serial_icounter_struct __user *p_cuser; /* user space */
|
||||||
|
- unsigned long flags;
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
@@ -1036,7 +1033,7 @@ static int ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd));
|
||||||
|
|
||||||
|
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||||
|
- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
|
||||||
|
+ (cmd != TIOCMIWAIT)) {
|
||||||
|
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
@@ -1089,25 +1086,6 @@ static int ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
case MGSL_IOCWAITGPIO:
|
||||||
|
ret = wait_gpio(info, argp);
|
||||||
|
break;
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- spin_lock_irqsave(&info->lock,flags);
|
||||||
|
- cnow = info->icount;
|
||||||
|
- spin_unlock_irqrestore(&info->lock,flags);
|
||||||
|
- p_cuser = argp;
|
||||||
|
- if (put_user(cnow.cts, &p_cuser->cts) ||
|
||||||
|
- put_user(cnow.dsr, &p_cuser->dsr) ||
|
||||||
|
- put_user(cnow.rng, &p_cuser->rng) ||
|
||||||
|
- put_user(cnow.dcd, &p_cuser->dcd) ||
|
||||||
|
- put_user(cnow.rx, &p_cuser->rx) ||
|
||||||
|
- put_user(cnow.tx, &p_cuser->tx) ||
|
||||||
|
- put_user(cnow.frame, &p_cuser->frame) ||
|
||||||
|
- put_user(cnow.overrun, &p_cuser->overrun) ||
|
||||||
|
- put_user(cnow.parity, &p_cuser->parity) ||
|
||||||
|
- put_user(cnow.brk, &p_cuser->brk) ||
|
||||||
|
- put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
|
||||||
|
- ret = -EFAULT;
|
||||||
|
- ret = 0;
|
||||||
|
- break;
|
||||||
|
default:
|
||||||
|
ret = -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
@@ -1115,6 +1093,33 @@ static int ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
+
|
||||||
|
+{
|
||||||
|
+ struct slgt_info *info = tty->driver_data;
|
||||||
|
+ struct mgsl_icount cnow; /* kernel counter temps */
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&info->lock,flags);
|
||||||
|
+ cnow = info->icount;
|
||||||
|
+ spin_unlock_irqrestore(&info->lock,flags);
|
||||||
|
+
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+ icount->rx = cnow.rx;
|
||||||
|
+ icount->tx = cnow.tx;
|
||||||
|
+ icount->frame = cnow.frame;
|
||||||
|
+ icount->overrun = cnow.overrun;
|
||||||
|
+ icount->parity = cnow.parity;
|
||||||
|
+ icount->brk = cnow.brk;
|
||||||
|
+ icount->buf_overrun = cnow.buf_overrun;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* support for 32 bit ioctl calls on 64 bit systems
|
||||||
|
*/
|
||||||
|
@@ -1204,10 +1209,6 @@ static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
case MGSL_IOCSGPIO:
|
||||||
|
case MGSL_IOCGGPIO:
|
||||||
|
case MGSL_IOCWAITGPIO:
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg)));
|
||||||
|
- break;
|
||||||
|
-
|
||||||
|
case MGSL_IOCSTXIDLE:
|
||||||
|
case MGSL_IOCTXENABLE:
|
||||||
|
case MGSL_IOCRXENABLE:
|
||||||
|
@@ -3638,6 +3639,7 @@ static const struct tty_operations ops = {
|
||||||
|
.hangup = hangup,
|
||||||
|
.tiocmget = tiocmget,
|
||||||
|
.tiocmset = tiocmset,
|
||||||
|
+ .get_icount = get_icount,
|
||||||
|
.proc_fops = &synclink_gt_proc_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
|
||||||
|
index 2b18adc..beffc24 100644
|
||||||
|
--- a/drivers/char/synclinkmp.c
|
||||||
|
+++ b/drivers/char/synclinkmp.c
|
||||||
|
@@ -1255,10 +1255,6 @@ static int do_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
SLMP_INFO *info = tty->driver_data;
|
||||||
|
- int error;
|
||||||
|
- struct mgsl_icount cnow; /* kernel counter temps */
|
||||||
|
- struct serial_icounter_struct __user *p_cuser; /* user space */
|
||||||
|
- unsigned long flags;
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
|
||||||
|
if (debug_level >= DEBUG_LEVEL_INFO)
|
||||||
|
@@ -1269,7 +1265,7 @@ static int do_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||||
|
- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
|
||||||
|
+ (cmd != TIOCMIWAIT)) {
|
||||||
|
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
@@ -1307,34 +1303,6 @@ static int do_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
* NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
* RI where only 0->1 is counted.
|
||||||
|
*/
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- spin_lock_irqsave(&info->lock,flags);
|
||||||
|
- cnow = info->icount;
|
||||||
|
- spin_unlock_irqrestore(&info->lock,flags);
|
||||||
|
- p_cuser = argp;
|
||||||
|
- PUT_USER(error,cnow.cts, &p_cuser->cts);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.dsr, &p_cuser->dsr);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.rng, &p_cuser->rng);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.dcd, &p_cuser->dcd);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.rx, &p_cuser->rx);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.tx, &p_cuser->tx);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.frame, &p_cuser->frame);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.overrun, &p_cuser->overrun);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.parity, &p_cuser->parity);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.brk, &p_cuser->brk);
|
||||||
|
- if (error) return error;
|
||||||
|
- PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
|
||||||
|
- if (error) return error;
|
||||||
|
- return 0;
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
@@ -1351,6 +1319,32 @@ static int ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
+{
|
||||||
|
+ SLMP_INFO *info = tty->driver_data;
|
||||||
|
+ struct mgsl_icount cnow; /* kernel counter temps */
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&info->lock,flags);
|
||||||
|
+ cnow = info->icount;
|
||||||
|
+ spin_unlock_irqrestore(&info->lock,flags);
|
||||||
|
+
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+ icount->rx = cnow.rx;
|
||||||
|
+ icount->tx = cnow.tx;
|
||||||
|
+ icount->frame = cnow.frame;
|
||||||
|
+ icount->overrun = cnow.overrun;
|
||||||
|
+ icount->parity = cnow.parity;
|
||||||
|
+ icount->brk = cnow.brk;
|
||||||
|
+ icount->buf_overrun = cnow.buf_overrun;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* /proc fs routines....
|
||||||
|
*/
|
||||||
|
@@ -3908,6 +3902,7 @@ static const struct tty_operations ops = {
|
||||||
|
.hangup = hangup,
|
||||||
|
.tiocmget = tiocmget,
|
||||||
|
.tiocmset = tiocmset,
|
||||||
|
+ .get_icount = get_icount,
|
||||||
|
.proc_fops = &synclinkmp_proc_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
|
||||||
|
index 24661cd..1e4f831 100644
|
||||||
|
--- a/drivers/serial/68360serial.c
|
||||||
|
+++ b/drivers/serial/68360serial.c
|
||||||
|
@@ -1381,6 +1381,30 @@ static void send_break(ser_info_t *info, unsigned int duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
+ * Return: write counters to the user passed counter struct
|
||||||
|
+ * NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
+ * RI where only 0->1 is counted.
|
||||||
|
+ */
|
||||||
|
+static int rs_360_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
+{
|
||||||
|
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
|
||||||
|
+ struct async_icount cnow;
|
||||||
|
+
|
||||||
|
+ local_irq_disable();
|
||||||
|
+ cnow = info->state->icount;
|
||||||
|
+ local_irq_enable();
|
||||||
|
+
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
@@ -1394,7 +1418,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
- if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
|
||||||
|
+ if (cmd != TIOCMIWAIT) {
|
||||||
|
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
@@ -1477,31 +1501,6 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
|
||||||
|
- * Return: write counters to the user passed counter struct
|
||||||
|
- * NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
- * RI where only 0->1 is counted.
|
||||||
|
- */
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- local_irq_disable();
|
||||||
|
- cnow = info->state->icount;
|
||||||
|
- local_irq_enable();
|
||||||
|
- p_cuser = (struct serial_icounter_struct *) arg;
|
||||||
|
-/* error = put_user(cnow.cts, &p_cuser->cts); */
|
||||||
|
-/* if (error) return error; */
|
||||||
|
-/* error = put_user(cnow.dsr, &p_cuser->dsr); */
|
||||||
|
-/* if (error) return error; */
|
||||||
|
-/* error = put_user(cnow.rng, &p_cuser->rng); */
|
||||||
|
-/* if (error) return error; */
|
||||||
|
-/* error = put_user(cnow.dcd, &p_cuser->dcd); */
|
||||||
|
-/* if (error) return error; */
|
||||||
|
-
|
||||||
|
- put_user(cnow.cts, &p_cuser->cts);
|
||||||
|
- put_user(cnow.dsr, &p_cuser->dsr);
|
||||||
|
- put_user(cnow.rng, &p_cuser->rng);
|
||||||
|
- put_user(cnow.dcd, &p_cuser->dcd);
|
||||||
|
- return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
|
||||||
|
index 309b6c2..8996006 100644
|
||||||
|
--- a/net/bluetooth/rfcomm/tty.c
|
||||||
|
+++ b/net/bluetooth/rfcomm/tty.c
|
||||||
|
@@ -844,10 +844,6 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned
|
||||||
|
BT_DBG("TIOCMIWAIT");
|
||||||
|
break;
|
||||||
|
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- BT_DBG("TIOCGICOUNT");
|
||||||
|
- break;
|
||||||
|
-
|
||||||
|
case TIOCGSERIAL:
|
||||||
|
BT_ERR("TIOCGSERIAL is not supported");
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
From 52583e6fde34587a38c72a5c094c17e0a3503791 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alan Cox <alan@linux.intel.com>
|
||||||
|
Date: Thu, 16 Sep 2010 18:21:24 +0100
|
||||||
|
Subject: [PATCH 1/2] tty: Make tiocgicount a handler
|
||||||
|
|
||||||
|
Dan Rosenberg noted that various drivers return the struct with uncleared
|
||||||
|
fields. Instead of spending forever trying to stomp all the drivers that
|
||||||
|
get it wrong (and every new driver) do the job in one place.
|
||||||
|
|
||||||
|
This first patch adds the needed operations and hooks them up, including
|
||||||
|
the needed USB midlayer and serial core plumbing.
|
||||||
|
|
||||||
|
Signed-off-by: Alan Cox <alan@linux.intel.com>
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
|
---
|
||||||
|
drivers/char/tty_io.c | 21 +++++++++++++++++++++
|
||||||
|
drivers/serial/serial_core.c | 37 +++++++++++++++++--------------------
|
||||||
|
drivers/usb/serial/usb-serial.c | 13 +++++++++++++
|
||||||
|
include/linux/tty_driver.h | 9 +++++++++
|
||||||
|
include/linux/usb/serial.h | 2 ++
|
||||||
|
5 files changed, 62 insertions(+), 20 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
|
||||||
|
index 507441a..3a69c39 100644
|
||||||
|
--- a/drivers/char/tty_io.c
|
||||||
|
+++ b/drivers/char/tty_io.c
|
||||||
|
@@ -96,6 +96,7 @@
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
+#include <linux/serial.h>
|
||||||
|
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <asm/system.h>
|
||||||
|
@@ -2456,6 +2457,20 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
|
||||||
|
return tty->ops->tiocmset(tty, file, set, clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
|
||||||
|
+{
|
||||||
|
+ int retval = -EINVAL;
|
||||||
|
+ struct serial_icounter_struct icount;
|
||||||
|
+ memset(&icount, 0, sizeof(icount));
|
||||||
|
+ if (tty->ops->get_icount)
|
||||||
|
+ retval = tty->ops->get_icount(tty, &icount);
|
||||||
|
+ if (retval != 0)
|
||||||
|
+ return retval;
|
||||||
|
+ if (copy_to_user(arg, &icount, sizeof(icount)))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||||
|
@@ -2576,6 +2591,12 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
|
case TIOCMBIC:
|
||||||
|
case TIOCMBIS:
|
||||||
|
return tty_tiocmset(tty, file, cmd, p);
|
||||||
|
+ case TIOCGICOUNT:
|
||||||
|
+ retval = tty_tiocgicount(tty, p);
|
||||||
|
+ /* For the moment allow fall through to the old method */
|
||||||
|
+ if (retval != -EINVAL)
|
||||||
|
+ return retval;
|
||||||
|
+ break;
|
||||||
|
case TCFLSH:
|
||||||
|
switch (arg) {
|
||||||
|
case TCIFLUSH:
|
||||||
|
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
|
||||||
|
index 7f28307..232e2bb 100644
|
||||||
|
--- a/drivers/serial/serial_core.c
|
||||||
|
+++ b/drivers/serial/serial_core.c
|
||||||
|
@@ -1074,10 +1074,10 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
|
||||||
|
* NB: both 1->0 and 0->1 transitions are counted except for
|
||||||
|
* RI where only 0->1 is counted.
|
||||||
|
*/
|
||||||
|
-static int uart_get_count(struct uart_state *state,
|
||||||
|
- struct serial_icounter_struct __user *icnt)
|
||||||
|
+static int uart_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
{
|
||||||
|
- struct serial_icounter_struct icount;
|
||||||
|
+ struct uart_state *state = tty->driver_data;
|
||||||
|
struct uart_icount cnow;
|
||||||
|
struct uart_port *uport = state->uart_port;
|
||||||
|
|
||||||
|
@@ -1085,19 +1085,19 @@ static int uart_get_count(struct uart_state *state,
|
||||||
|
memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
|
||||||
|
spin_unlock_irq(&uport->lock);
|
||||||
|
|
||||||
|
- icount.cts = cnow.cts;
|
||||||
|
- icount.dsr = cnow.dsr;
|
||||||
|
- icount.rng = cnow.rng;
|
||||||
|
- icount.dcd = cnow.dcd;
|
||||||
|
- icount.rx = cnow.rx;
|
||||||
|
- icount.tx = cnow.tx;
|
||||||
|
- icount.frame = cnow.frame;
|
||||||
|
- icount.overrun = cnow.overrun;
|
||||||
|
- icount.parity = cnow.parity;
|
||||||
|
- icount.brk = cnow.brk;
|
||||||
|
- icount.buf_overrun = cnow.buf_overrun;
|
||||||
|
+ icount->cts = cnow.cts;
|
||||||
|
+ icount->dsr = cnow.dsr;
|
||||||
|
+ icount->rng = cnow.rng;
|
||||||
|
+ icount->dcd = cnow.dcd;
|
||||||
|
+ icount->rx = cnow.rx;
|
||||||
|
+ icount->tx = cnow.tx;
|
||||||
|
+ icount->frame = cnow.frame;
|
||||||
|
+ icount->overrun = cnow.overrun;
|
||||||
|
+ icount->parity = cnow.parity;
|
||||||
|
+ icount->brk = cnow.brk;
|
||||||
|
+ icount->buf_overrun = cnow.buf_overrun;
|
||||||
|
|
||||||
|
- return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -1150,10 +1150,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
|
||||||
|
case TIOCMIWAIT:
|
||||||
|
ret = uart_wait_modem_status(state, arg);
|
||||||
|
break;
|
||||||
|
-
|
||||||
|
- case TIOCGICOUNT:
|
||||||
|
- ret = uart_get_count(state, uarg);
|
||||||
|
- break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != -ENOIOCTLCMD)
|
||||||
|
@@ -2305,6 +2301,7 @@ static const struct tty_operations uart_ops = {
|
||||||
|
#endif
|
||||||
|
.tiocmget = uart_tiocmget,
|
||||||
|
.tiocmset = uart_tiocmset,
|
||||||
|
+ .get_icount = uart_get_icount,
|
||||||
|
#ifdef CONFIG_CONSOLE_POLL
|
||||||
|
.poll_init = uart_poll_init,
|
||||||
|
.poll_get_char = uart_poll_get_char,
|
||||||
|
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
|
||||||
|
index 941c2d4..8aea96b 100644
|
||||||
|
--- a/drivers/usb/serial/usb-serial.c
|
||||||
|
+++ b/drivers/usb/serial/usb-serial.c
|
||||||
|
@@ -519,6 +519,18 @@ static int serial_tiocmset(struct tty_struct *tty, struct file *file,
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int serial_get_icount(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount)
|
||||||
|
+{
|
||||||
|
+ struct usb_serial_port *port = tty->driver_data;
|
||||||
|
+
|
||||||
|
+ dbg("%s - port %d", __func__, port->number);
|
||||||
|
+
|
||||||
|
+ if (port->serial->type->get_icount)
|
||||||
|
+ return port->serial->type->get_icount(tty, icount);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* We would be calling tty_wakeup here, but unfortunately some line
|
||||||
|
* disciplines have an annoying habit of calling tty->write from
|
||||||
|
@@ -1208,6 +1220,7 @@ static const struct tty_operations serial_ops = {
|
||||||
|
.chars_in_buffer = serial_chars_in_buffer,
|
||||||
|
.tiocmget = serial_tiocmget,
|
||||||
|
.tiocmset = serial_tiocmset,
|
||||||
|
+ .get_icount = serial_get_icount,
|
||||||
|
.cleanup = serial_cleanup,
|
||||||
|
.install = serial_install,
|
||||||
|
.proc_fops = &serial_proc_fops,
|
||||||
|
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
|
||||||
|
index b086779..db2d227 100644
|
||||||
|
--- a/include/linux/tty_driver.h
|
||||||
|
+++ b/include/linux/tty_driver.h
|
||||||
|
@@ -224,6 +224,12 @@
|
||||||
|
* unless the tty also has a valid tty->termiox pointer.
|
||||||
|
*
|
||||||
|
* Optional: Called under the termios lock
|
||||||
|
+ *
|
||||||
|
+ * int (*get_icount)(struct tty_struct *tty, struct serial_icounter *icount);
|
||||||
|
+ *
|
||||||
|
+ * Called when the device receives a TIOCGICOUNT ioctl. Passed a kernel
|
||||||
|
+ * structure to complete. This method is optional and will only be called
|
||||||
|
+ * if provided (otherwise EINVAL will be returned).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/fs.h>
|
||||||
|
@@ -232,6 +238,7 @@
|
||||||
|
|
||||||
|
struct tty_struct;
|
||||||
|
struct tty_driver;
|
||||||
|
+struct serial_icounter_struct;
|
||||||
|
|
||||||
|
struct tty_operations {
|
||||||
|
struct tty_struct * (*lookup)(struct tty_driver *driver,
|
||||||
|
@@ -268,6 +275,8 @@ struct tty_operations {
|
||||||
|
unsigned int set, unsigned int clear);
|
||||||
|
int (*resize)(struct tty_struct *tty, struct winsize *ws);
|
||||||
|
int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
|
||||||
|
+ int (*get_icount)(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount);
|
||||||
|
#ifdef CONFIG_CONSOLE_POLL
|
||||||
|
int (*poll_init)(struct tty_driver *driver, int line, char *options);
|
||||||
|
int (*poll_get_char)(struct tty_driver *driver, int line);
|
||||||
|
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
|
||||||
|
index 84a4c44..8288b57 100644
|
||||||
|
--- a/include/linux/usb/serial.h
|
||||||
|
+++ b/include/linux/usb/serial.h
|
||||||
|
@@ -271,6 +271,8 @@ struct usb_serial_driver {
|
||||||
|
int (*tiocmget)(struct tty_struct *tty, struct file *file);
|
||||||
|
int (*tiocmset)(struct tty_struct *tty, struct file *file,
|
||||||
|
unsigned int set, unsigned int clear);
|
||||||
|
+ int (*get_icount)(struct tty_struct *tty,
|
||||||
|
+ struct serial_icounter_struct *icount);
|
||||||
|
/* Called by the tty layer for port level work. There may or may not
|
||||||
|
be an attached tty at this point */
|
||||||
|
void (*dtr_rts)(struct usb_serial_port *port, int on);
|
||||||
|
--
|
||||||
|
1.7.3.2
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue