diff options
author | David S. Miller <davem@davemloft.net> | 2009-02-28 15:36:58 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-02-28 15:36:58 -0800 |
commit | 18963caaf55240d6a0491bdb27b7fef2882ffb15 (patch) | |
tree | d0e4365cae0ce401ba826809f4eef0bd755f4f2d | |
parent | 98f8948f13b4d27c3695c49ac9a970a77166f9ee (diff) | |
parent | 778ef1e6cbb049c9bcbf405936ee6f2b6e451892 (diff) | |
download | kernel-common-18963caaf55240d6a0491bdb27b7fef2882ffb15.tar.gz kernel-common-18963caaf55240d6a0491bdb27b7fef2882ffb15.tar.bz2 kernel-common-18963caaf55240d6a0491bdb27b7fef2882ffb15.zip |
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
176 files changed, 4783 insertions, 1029 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index ceddcff4082a..e638e15a8895 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -1,3 +1,46 @@ +What: /sys/bus/pci/drivers/.../bind +Date: December 2003 +Contact: linux-pci@vger.kernel.org +Description: + Writing a device location to this file will cause + the driver to attempt to bind to the device found at + this location. This is useful for overriding default + bindings. The format for the location is: DDDD:BB:DD.F. + That is Domain:Bus:Device.Function and is the same as + found in /sys/bus/pci/devices/. For example: + # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/bind + (Note: kernels before 2.6.28 may require echo -n). + +What: /sys/bus/pci/drivers/.../unbind +Date: December 2003 +Contact: linux-pci@vger.kernel.org +Description: + Writing a device location to this file will cause the + driver to attempt to unbind from the device found at + this location. This may be useful when overriding default + bindings. The format for the location is: DDDD:BB:DD.F. + That is Domain:Bus:Device.Function and is the same as + found in /sys/bus/pci/devices/. For example: + # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/unbind + (Note: kernels before 2.6.28 may require echo -n). + +What: /sys/bus/pci/drivers/.../new_id +Date: December 2003 +Contact: linux-pci@vger.kernel.org +Description: + Writing a device ID to this file will attempt to + dynamically add a new device ID to a PCI device driver. + This may allow the driver to support more hardware than + was included in the driver's static device ID support + table at compile time. The format for the device ID is: + VVVV DDDD SVVV SDDD CCCC MMMM PPPP. That is Vendor ID, + Device ID, Subsystem Vendor ID, Subsystem Device ID, + Class, Class Mask, and Private Driver Data. The Vendor ID + and Device ID fields are required, the rest are optional. + Upon successfully adding an ID, the driver will probe + for the device and attempt to bind to it. For example: + # echo "8086 10f5" > /sys/bus/pci/drivers/foo/new_id + What: /sys/bus/pci/devices/.../vpd Date: February 2008 Contact: Ben Hutchings <bhutchings@solarflare.com> diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop deleted file mode 100644 index 5515469de7cf..000000000000 --- a/Documentation/dvb/README.flexcop +++ /dev/null @@ -1,205 +0,0 @@ -This README escorted the skystar2-driver rewriting procedure. It describes the -state of the new flexcop-driver set and some internals are written down here -too. - -This document hopefully describes things about the flexcop and its -device-offsprings. Goal was to write an easy-to-write and easy-to-read set of -drivers based on the skystar2.c and other information. - -Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been -touched and rewritten. - -History & News -============== - 2005-04-01 - correct USB ISOC transfers (thanks to Vadim Catana) - - - - -General coding processing -========================= - -We should proceed as follows (as long as no one complains): - -0) Think before start writing code! - -1) rewriting the skystar2.c with the help of the flexcop register descriptions -and splitting up the files to a pci-bus-part and a flexcop-part. -The new driver will be called b2c2-flexcop-pci.ko/b2c2-flexcop-usb.ko for the -device-specific part and b2c2-flexcop.ko for the common flexcop-functions. - -2) Search for errors in the leftover of flexcop-pci.c (compare with pluto2.c -and other pci drivers) - -3) make some beautification (see 'Improvements when rewriting (refactoring) is -done') - -4) Testing the new driver and maybe substitute the skystar2.c with it, to reach -a wider tester audience. - -5) creating an usb-bus-part using the already written flexcop code for the pci -card. - -Idea: create a kernel-object for the flexcop and export all important -functions. This option saves kernel-memory, but maybe a lot of functions have -to be exported to kernel namespace. - - -Current situation -================= - -0) Done :) -1) Done (some minor issues left) -2) Done -3) Not ready yet, more information is necessary -4) next to be done (see the table below) -5) USB driver is working (yes, there are some minor issues) - -What seems to be ready? ------------------------ - -1) Rewriting -1a) i2c is cut off from the flexcop-pci.c and seems to work -1b) moved tuner and demod stuff from flexcop-pci.c to flexcop-tuner-fe.c -1c) moved lnb and diseqc stuff from flexcop-pci.c to flexcop-tuner-fe.c -1e) eeprom (reading MAC address) -1d) sram (no dynamic sll size detection (commented out) (using default as JJ told me)) -1f) misc. register accesses for reading parameters (e.g. resetting, revision) -1g) pid/mac filter (flexcop-hw-filter.c) -1i) dvb-stuff initialization in flexcop.c (done) -1h) dma stuff (now just using the size-irq, instead of all-together, to be done) -1j) remove flexcop initialization from flexcop-pci.c completely (done) -1l) use a well working dma IRQ method (done, see 'Known bugs and problems and TODO') -1k) cleanup flexcop-files (remove unused EXPORT_SYMBOLs, make static from -non-static where possible, moved code to proper places) - -2) Search for errors in the leftover of flexcop-pci.c (partially done) -5a) add MAC address reading -5c) feeding of ISOC data to the software demux (format of the isochronous data -and speed optimization, no real error) (thanks to Vadim Catana) - -What to do in the near future? --------------------------------------- -(no special order here) - -5) USB driver -5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting) - -Testing changes ---------------- - -O = item is working -P = item is partially working -X = item is not working -N = item does not apply here -<empty field> = item need to be examined - - | PCI | USB -item | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312 --------+-------+---------+---------+-------+-------+---------+---------+------- -1a) | O | | | | N | N | N | N -1b) | O | | | | | | O | -1c) | N | N | | | N | N | O | -1d) | O | O -1e) | O | O -1f) | P -1g) | O -1h) | P | -1i) | O | N -1j) | O | N -1l) | O | N -2) | O | N -5a) | N | O -5b)* | N | -5c) | N | O - -* - not done yet - -Known bugs and problems and TODO --------------------------------- - -1g/h/l) when pid filtering is enabled on the pci card - -DMA usage currently: - The DMA is splitted in 2 equal-sized subbuffers. The Flexcop writes to first - address and triggers an IRQ when it's full and starts writing to the second - address. When the second address is full, the IRQ is triggered again, and - the flexcop writes to first address again, and so on. - The buffersize of each address is currently 640*188 bytes. - - Problem is, when using hw-pid-filtering and doing some low-bandwidth - operation (like scanning) the buffers won't be filled enough to trigger - the IRQ. That's why: - - When PID filtering is activated, the timer IRQ is used. Every 1.97 ms the IRQ - is triggered. Is the current write address of DMA1 different to the one - during the last IRQ, then the data is passed to the demuxer. - - There is an additional DMA-IRQ-method: packet count IRQ. This isn't - implemented correctly yet. - - The solution is to disable HW PID filtering, but I don't know how the DVB - API software demux behaves on slow systems with 45MBit/s TS. - -Solved bugs :) --------------- -1g) pid-filtering (somehow pid index 4 and 5 (EMM_PID and ECM_PID) aren't -working) -SOLUTION: also index 0 was affected, because net_translation is done for -these indexes by default - -5b) isochronous transfer does only work in the first attempt (for the Sky2PC -USB, Air2PC is working) SOLUTION: the flexcop was going asleep and never really -woke up again (don't know if this need fixes, see -flexcop-fe-tuner.c:flexcop_sleep) - -NEWS: when the driver is loaded and unloaded and loaded again (w/o doing -anything in the while the driver is loaded the first time), no transfers take -place anymore. - -Improvements when rewriting (refactoring) is done -================================================= - -- split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control - (enable sleeping for other demods than dvb-s) -- add support for CableStar (stv0297 Microtune 203x/ALPS) (almost done, incompatibilities with the Nexus-CA) - -Debugging ---------- -- add verbose debugging to skystar2.c (dump the reg_dw_data) and compare it - with this flexcop, this is important, because i2c is now using the - flexcop_ibi_value union from flexcop-reg.h (do you have a better idea for - that, please tell us so). - -Everything which is identical in the following table, can be put into a common -flexcop-module. - - PCI USB -------------------------------------------------------------------------------- -Different: -Register access: accessing IO memory USB control message -I2C bus: I2C bus of the FC USB control message -Data transfer: DMA isochronous transfer -EEPROM transfer: through i2c bus not clear yet - -Identical: -Streaming: accessing registers -PID Filtering: accessing registers -Sram destinations: accessing registers -Tuner/Demod: I2C bus -DVB-stuff: can be written for common use - -Acknowledgements (just for the rewriting part) -================ - -Bjarne Steinsbo thought a lot in the first place of the pci part for this code -sharing idea. - -Andreas Oberritter for providing a recent PCI initialization template -(pluto2.c). - -Boleslaw Ciesielski for pointing out a problem with firmware loader. - -Vadim Catana for correcting the USB transfer. - -comments, critics and ideas to linux-dvb@linuxtv.org. diff --git a/Documentation/dvb/technisat.txt b/Documentation/dvb/technisat.txt index cdf6ee4b2da1..3f435ffb289c 100644 --- a/Documentation/dvb/technisat.txt +++ b/Documentation/dvb/technisat.txt @@ -1,5 +1,5 @@ -How to set up the Technisat devices -=================================== +How to set up the Technisat/B2C2 Flexcop devices +================================================ 1) Find out what device you have ================================ @@ -16,54 +16,60 @@ DVB: registering frontend 0 (Conexant CX24123/CX24109)... If the Technisat is the only TV device in your box get rid of unnecessary modules and check this one: "Multimedia devices" => "Customise analog and hybrid tuner modules to build" -In this directory uncheck every driver which is activated there. +In this directory uncheck every driver which is activated there (except "Simple tuner support" for case 9 only). Then please activate: 2a) Main module part: a.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" -b.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC PCI" in case of a PCI card OR +b.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC PCI" in case of a PCI card +OR c.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC USB" in case of an USB 1.1 adapter d.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Enable debug for the B2C2 FlexCop drivers" Notice: d.) is helpful for troubleshooting 2b) Frontend module part: -1.) Revision 2.3: +1.) SkyStar DVB-S Revision 2.3: a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build" b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink VP310/MT312/ZL10313 based" -2.) Revision 2.6: +2.) SkyStar DVB-S Revision 2.6: a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build" b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0299 based" -3.) Revision 2.7: +3.) SkyStar DVB-S Revision 2.7: a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build" b.)"Multimedia devices" => "Customise DVB frontends" => "Samsung S5H1420 based" c.)"Multimedia devices" => "Customise DVB frontends" => "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller" -4.) Revision 2.8: +4.) SkyStar DVB-S Revision 2.8: a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build" b.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24113/CX24128 tuner for DVB-S/DSS" c.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24123 based" d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller" -5.) DVB-T card: +5.) AirStar DVB-T card: a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build" b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink MT352 based" -6.) DVB-C card: +6.) CableStar DVB-C card: a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build" b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0297 based" -7.) ATSC card 1st generation: +7.) AirStar ATSC card 1st generation: a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build" b.)"Multimedia devices" => "Customise DVB frontends" => "Broadcom BCM3510" -8.) ATSC card 2nd generation: +8.) AirStar ATSC card 2nd generation: a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build" b.)"Multimedia devices" => "Customise DVB frontends" => "NxtWave Communications NXT2002/NXT2004 based" -c.)"Multimedia devices" => "Customise DVB frontends" => "LG Electronics LGDT3302/LGDT3303 based" +c.)"Multimedia devices" => "Customise DVB frontends" => "Generic I2C PLL based tuners" -Author: Uwe Bugla <uwe.bugla@gmx.de> December 2008 +9.) AirStar ATSC card 3rd generation: +a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build" +b.)"Multimedia devices" => "Customise DVB frontends" => "LG Electronics LGDT3302/LGDT3303 based" +c.)"Multimedia devices" => "Customise analog and hybrid tuner modules to build" => "Simple tuner support" + +Author: Uwe Bugla <uwe.bugla@gmx.de> February 2009 diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 319785b6dcb1..54f21a5c262b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -114,7 +114,7 @@ In addition, the following text indicates that the option: Parameters denoted with BOOT are actually interpreted by the boot loader, and have no meaning to the kernel directly. Do not modify the syntax of boot loader parameters without extreme -need or coordination with <Documentation/x86/i386/boot.txt>. +need or coordination with <Documentation/x86/boot.txt>. There are also arch-specific kernel-parameters not documented here. See for example <Documentation/x86/x86_64/boot-options.txt>. @@ -868,8 +868,10 @@ and is between 256 and 4096 characters. It is defined in the file icn= [HW,ISDN] Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]] - ide= [HW] (E)IDE subsystem - Format: ide=nodma or ide=doubler + ide-core.nodma= [HW] (E)IDE subsystem + Format: =0.0 to prevent dma on hda, =0.1 hdb =1.0 hdc + .vlb_clock .pci_clock .noflush .noprobe .nowerr .cdrom + .chs .ignore_cable are additional options See Documentation/ide/ide.txt. idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed @@ -2449,7 +2451,7 @@ and is between 256 and 4096 characters. It is defined in the file See Documentation/fb/modedb.txt. vga= [BOOT,X86-32] Select a particular video mode - See Documentation/x86/i386/boot.txt and + See Documentation/x86/boot.txt and Documentation/svga.txt. Use vga=ask for menu. This is actually a boot loader parameter; the value is diff --git a/arch/arm/mach-davinci/board-evm.c b/arch/arm/mach-davinci/board-evm.c index a957d239a683..38b6a9ce2a93 100644 --- a/arch/arm/mach-davinci/board-evm.c +++ b/arch/arm/mach-davinci/board-evm.c @@ -311,6 +311,9 @@ evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c) gpio_request(gpio + 7, "nCF_SEL"); gpio_direction_output(gpio + 7, 1); + /* irlml6401 sustains over 3A, switches 5V in under 8 msec */ + setup_usb(500, 8); + return 0; } @@ -417,9 +420,6 @@ static __init void davinci_evm_init(void) platform_add_devices(davinci_evm_devices, ARRAY_SIZE(davinci_evm_devices)); evm_init_i2c(); - - /* irlml6401 sustains over 3A, switches 5V in under 8 msec */ - setup_usb(500, 8); } static __init void davinci_evm_irq_init(void) diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 28f6dbc95bd7..abb92b7eca0c 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -231,6 +231,11 @@ static struct clk davinci_clks[] = { .lpsc = DAVINCI_LPSC_GPIO, }, { + .name = "usb", + .rate = &commonrate, + .lpsc = DAVINCI_LPSC_USB, + }, + { .name = "AEMIFCLK", .rate = &commonrate, .lpsc = DAVINCI_LPSC_AEMIF, diff --git a/arch/arm/mach-davinci/usb.c b/arch/arm/mach-davinci/usb.c index 867ead2559ad..69680784448a 100644 --- a/arch/arm/mach-davinci/usb.c +++ b/arch/arm/mach-davinci/usb.c @@ -47,6 +47,7 @@ static struct musb_hdrc_platform_data usb_data = { #elif defined(CONFIG_USB_MUSB_HOST) .mode = MUSB_HOST, #endif + .clock = "usb", .config = &musb_config, }; diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c index e88d417736af..c7fc01e9d1f6 100644 --- a/arch/arm/mach-rpc/riscpc.c +++ b/arch/arm/mach-rpc/riscpc.c @@ -19,6 +19,7 @@ #include <linux/serial_8250.h> #include <linux/ata_platform.h> #include <linux/io.h> +#include <linux/i2c.h> #include <asm/elf.h> #include <asm/mach-types.h> @@ -201,8 +202,13 @@ static struct platform_device *devs[] __initdata = { &pata_device, }; +static struct i2c_board_info i2c_rtc = { + I2C_BOARD_INFO("pcf8583", 0x50) +}; + static int __init rpc_init(void) { + i2c_register_board_info(0, &i2c_rtc, 1); return platform_add_devices(devs, ARRAY_SIZE(devs)); } diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 4eb45c012498..153e727a6e8e 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -638,6 +638,17 @@ config DMAR and include PCI device scope covered by these DMA remapping devices. +config DMAR_DEFAULT_ON + def_bool y + prompt "Enable DMA Remapping Devices by default" + depends on DMAR + help + Selecting this option will enable a DMAR device at boot time if + one is found. If this option is not selected, DMAR support can + be enabled by passing intel_iommu=on to the kernel. It is + recommended you say N here while the DMAR code remains + experimental. + endmenu endif diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 5cfd3d91001a..e13125058bed 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -507,7 +507,7 @@ static int iosapic_find_sharable_irq(unsigned long trigger, unsigned long pol) if (trigger == IOSAPIC_EDGE) return -EINVAL; - for (i = 0; i <= NR_IRQS; i++) { + for (i = 0; i < NR_IRQS; i++) { info = &iosapic_intr_info[i]; if (info->trigger == trigger && info->polarity == pol && (info->dmode == IOSAPIC_FIXED || diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 67810b77d998..b6c0e63a0bf6 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -2149,7 +2149,7 @@ unw_remove_unwind_table (void *handle) /* next, remove hash table entries for this table */ - for (index = 0; index <= UNW_HASH_SIZE; ++index) { + for (index = 0; index < UNW_HASH_SIZE; ++index) { tmp = unw.cache + unw.hash[index]; if (unw.hash[index] >= UNW_CACHE_SIZE || tmp->ip < table->start || tmp->ip >= table->end) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 600eef3f3ac7..e61465a18c7e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -603,7 +603,7 @@ config CAVIUM_OCTEON_SIMULATOR select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_HIGHMEM - select CPU_CAVIUM_OCTEON + select SYS_HAS_CPU_CAVIUM_OCTEON help The Octeon simulator is software performance model of the Cavium Octeon Processor. It supports simulating Octeon processors on x86 @@ -618,7 +618,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_HIGHMEM select SYS_HAS_EARLY_PRINTK - select CPU_CAVIUM_OCTEON + select SYS_HAS_CPU_CAVIUM_OCTEON select SWAP_IO_SPACE help This option supports all of the Octeon reference boards from Cavium @@ -1234,6 +1234,7 @@ config CPU_SB1 config CPU_CAVIUM_OCTEON bool "Cavium Octeon processor" + depends on SYS_HAS_CPU_CAVIUM_OCTEON select IRQ_CPU select IRQ_CPU_OCTEON select CPU_HAS_PREFETCH @@ -1314,6 +1315,9 @@ config SYS_HAS_CPU_RM9000 config SYS_HAS_CPU_SB1 bool +config SYS_HAS_CPU_CAVIUM_OCTEON + bool + # # CPU may reorder R->R, R->W, W->R, W->W # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC @@ -1387,6 +1391,7 @@ config 32BIT config 64BIT bool "64-bit kernel" depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL + select HAVE_SYSCALL_WRAPPERS help Select this option if you want to build a 64-bit kernel. diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c index 6fd441d16af5..f58d4ffb8945 100644 --- a/arch/mips/alchemy/common/time.c +++ b/arch/mips/alchemy/common/time.c @@ -118,7 +118,7 @@ void __init plat_time_init(void) * setup counter 1 (RTC) to tick at full speed */ t = 0xffffff; - while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S) && t--) + while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S) && --t) asm volatile ("nop"); if (!t) goto cntr_err; @@ -127,7 +127,7 @@ void __init plat_time_init(void) au_sync(); t = 0xffffff; - while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && t--) + while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && --t) asm volatile ("nop"); if (!t) goto cntr_err; @@ -135,7 +135,7 @@ void __init plat_time_init(void) au_sync(); t = 0xffffff; - while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && t--) + while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && --t) asm volatile ("nop"); if (!t) goto cntr_err; diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index a0ff2b66e22b..4b4007b3083a 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -111,7 +111,6 @@ int show_interrupts(struct seq_file *p, void *v) seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif seq_printf(p, " %14s", irq_desc[i].chip->name); - seq_printf(p, "-%-8s", irq_desc[i].name); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index aa2c55e3b55f..2f8452b404c7 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -32,6 +32,7 @@ #include <linux/module.h> #include <linux/binfmts.h> #include <linux/security.h> +#include <linux/syscalls.h> #include <linux/compat.h> #include <linux/vfs.h> #include <linux/ipc.h> @@ -63,9 +64,9 @@ #define merge_64(r1, r2) ((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL)) #endif -asmlinkage unsigned long -sys32_mmap2(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, unsigned long pgoff) +SYSCALL_DEFINE6(32_mmap2, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, unsigned long, fd, + unsigned long, pgoff) { struct file * file = NULL; unsigned long error; @@ -121,21 +122,21 @@ struct rlimit32 { int rlim_max; }; -asmlinkage long sys32_truncate64(const char __user * path, - unsigned long __dummy, int a2, int a3) +SYSCALL_DEFINE4(32_truncate64, const char __user *, path, + unsigned long, __dummy, unsigned long, a2, unsigned long, a3) { return sys_truncate(path, merge_64(a2, a3)); } -asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long __dummy, - int a2, int a3) +SYSCALL_DEFINE4(32_ftruncate64, unsigned long, fd, unsigned long, __dummy, + unsigned long, a2, unsigned long, a3) { return sys_ftruncate(fd, merge_64(a2, a3)); } -asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high, - unsigned int offset_low, loff_t __user * result, - unsigned int origin) +SYSCALL_DEFINE5(32_llseek, unsigned long, fd, unsigned long, offset_high, + unsigned long, offset_low, loff_t __user *, result, + unsigned long, origin) { return sys_llseek(fd, offset_high, offset_low, result, origin); } @@ -144,20 +145,20 @@ asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high, lseek back to original location. They fail just like lseek does on non-seekable files. */ -asmlinkage ssize_t sys32_pread(unsigned int fd, char __user * buf, - size_t count, u32 unused, u64 a4, u64 a5) +SYSCALL_DEFINE6(32_pread, unsigned long, fd, char __user *, buf, size_t, count, + unsigned long, unused, unsigned long, a4, unsigned long, a5) { return sys_pread64(fd, buf, count, merge_64(a4, a5)); } -asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char __user * buf, - size_t count, u32 unused, u64 a4, u64 a5) +SYSCALL_DEFINE6(32_pwrite, unsigned int, fd, const char __user *, buf, + size_t, count, u32, unused, u64, a4, u64, a5) { return sys_pwrite64(fd, buf, count, merge_64(a4, a5)); } -asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid, - struct compat_timespec __user *interval) +SYSCALL_DEFINE2(32_sched_rr_get_interval, compat_pid_t, pid, + struct compat_timespec __user *, interval) { struct timespec t; int ret; @@ -174,8 +175,8 @@ asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid, #ifdef CONFIG_SYSVIPC -asmlinkage long -sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) +SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third, + unsigned long, ptr, unsigned long, fifth) { int version, err; @@ -233,8 +234,8 @@ sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) #else -asmlinkage long -sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) +SYSCALL_DEFINE6(32_ipc, u32, call, int, first, int, second, int, third, + u32, ptr, u32 fifth) { return -ENOSYS; } @@ -242,7 +243,7 @@ sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) #endif /* CONFIG_SYSVIPC */ #ifdef CONFIG_MIPS32_N32 -asmlinkage long sysn32_semctl(int semid, int semnum, int cmd, u32 arg) +SYSCALL_DEFINE4(n32_semctl, int, semid, int, semnum, int, cmd, u32, arg) { /* compat_sys_semctl expects a pointer to union semun */ u32 __user *uptr = compat_alloc_user_space(sizeof(u32)); @@ -251,13 +252,14 @@ asmlinkage long sysn32_semctl(int semid, int semnum, int cmd, u32 arg) return compat_sys_semctl(semid, semnum, cmd, uptr); } -asmlinkage long sysn32_msgsnd(int msqid, u32 msgp, unsigned msgsz, int msgflg) +SYSCALL_DEFINE4(n32_msgsnd, int, msqid, u32, msgp, unsigned int, msgsz, + int, msgflg) { return compat_sys_msgsnd(msqid, msgsz, msgflg, compat_ptr(msgp)); } -asmlinkage long sysn32_msgrcv(int msqid, u32 msgp, size_t msgsz, int msgtyp, - int msgflg) +SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz, + int, msgtyp, int, msgflg) { return compat_sys_msgrcv(msqid, msgsz, msgtyp, msgflg, IPC_64, compat_ptr(msgp)); @@ -277,7 +279,7 @@ struct sysctl_args32 #ifdef CONFIG_SYSCTL_SYSCALL -asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args) +SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args) { struct sysctl_args32 tmp; int error; @@ -316,9 +318,16 @@ asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args) return error; } +#else + +SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args) +{ + return -ENOSYS; +} + #endif /* CONFIG_SYSCTL_SYSCALL */ -asmlinkage long sys32_newuname(struct new_utsname __user * name) +SYSCALL_DEFINE1(32_newuname, struct new_utsname __user *, name) { int ret = 0; @@ -334,7 +343,7 @@ asmlinkage long sys32_newuname(struct new_utsname __user * name) return ret; } -asmlinkage int sys32_personality(unsigned long personality) +SYSCALL_DEFINE1(32_personality, unsigned long, personality) { int ret; personality &= 0xffffffff; @@ -357,7 +366,7 @@ struct ustat32 { extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf); -asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32) +SYSCALL_DEFINE2(32_ustat, dev_t, dev, struct ustat32 __user *, ubuf32) { int err; struct ustat tmp; @@ -381,8 +390,8 @@ out: return err; } -asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, - s32 count) +SYSCALL_DEFINE4(32_sendfile, long, out_fd, long, in_fd, + compat_off_t __user *, offset, s32, count) { mm_segment_t old_fs = get_fs(); int ret; diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 51d1ba415b90..9ab70c3b5be6 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -399,7 +399,7 @@ einval: li v0, -ENOSYS sys sys_swapon 2 sys sys_reboot 3 sys sys_old_readdir 3 - sys old_mmap 6 /* 4090 */ + sys sys_mips_mmap 6 /* 4090 */ sys sys_munmap 2 sys sys_truncate 2 sys sys_ftruncate 2 @@ -519,7 +519,7 @@ einval: li v0, -ENOSYS sys sys_sendfile 4 sys sys_ni_syscall 0 sys sys_ni_syscall 0 - sys sys_mmap2 6 /* 4210 */ + sys sys_mips_mmap2 6 /* 4210 */ sys sys_truncate64 4 sys sys_ftruncate64 4 sys sys_stat64 2 diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index a9e171618994..9b4698667154 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -207,7 +207,7 @@ sys_call_table: PTR sys_newlstat PTR sys_poll PTR sys_lseek - PTR old_mmap + PTR sys_mips_mmap PTR sys_mprotect /* 5010 */ PTR sys_munmap PTR sys_brk diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 30f3b6317a83..7438e92f8a01 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -129,12 +129,12 @@ EXPORT(sysn32_call_table) PTR sys_newlstat PTR sys_poll PTR sys_lseek - PTR old_mmap + PTR sys_mips_mmap PTR sys_mprotect /* 6010 */ PTR sys_munmap PTR sys_brk - PTR sys32_rt_sigaction - PTR sys32_rt_sigprocmask + PTR sys_32_rt_sigaction + PTR sys_32_rt_sigprocmask PTR compat_sys_ioctl /* 6015 */ PTR sys_pread64 PTR sys_pwrite64 @@ -159,7 +159,7 @@ EXPORT(sysn32_call_table) PTR compat_sys_setitimer PTR sys_alarm PTR sys_getpid - PTR sys32_sendfile + PTR sys_32_sendfile PTR sys_socket /* 6040 */ PTR sys_connect PTR sys_accept @@ -181,14 +181,14 @@ EXPORT(sysn32_call_table) PTR sys_exit PTR compat_sys_wait4 PTR sys_kill /* 6060 */ - PTR sys32_newuname + PTR sys_32_newuname PTR sys_semget PTR sys_semop - PTR sysn32_semctl + PTR sys_n32_semctl PTR sys_shmdt /* 6065 */ PTR sys_msgget - PTR sysn32_msgsnd - PTR sysn32_msgrcv + PTR sys_n32_msgsnd + PTR sys_n32_msgrcv PTR compat_sys_msgctl PTR compat_sys_fcntl /* 6070 */ PTR sys_flock @@ -245,15 +245,15 @@ EXPORT(sysn32_call_table) PTR sys_getsid PTR sys_capget PTR sys_capset - PTR sys32_rt_sigpending /* 6125 */ + PTR sys_32_rt_sigpending /* 6125 */ PTR compat_sys_rt_sigtimedwait - PTR sys32_rt_sigqueueinfo + PTR sys_32_rt_sigqueueinfo PTR sysn32_rt_sigsuspend PTR sys32_sigaltstack PTR compat_sys_utime /* 6130 */ PTR sys_mknod - PTR sys32_personality - PTR sys32_ustat + PTR sys_32_personality + PTR sys_32_ustat PTR compat_sys_statfs PTR compat_sys_fstatfs /* 6135 */ PTR sys_sysfs @@ -265,14 +265,14 @@ EXPORT(sysn32_call_table) PTR sys_sched_getscheduler PTR sys_sched_get_priority_max PTR sys_sched_get_priority_min - PTR sys32_sched_rr_get_interval /* 6145 */ + PTR sys_32_sched_rr_get_interval /* 6145 */ PTR sys_mlock PTR sys_munlock PTR sys_mlockall PTR sys_munlockall PTR sys_vhangup /* 6150 */ PTR sys_pivot_root - PTR sys32_sysctl + PTR sys_32_sysctl PTR sys_prctl PTR compat_sys_adjtimex PTR compat_sys_setrlimit /* 6155 */ diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index fefef4af8595..b0fef4ff9827 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -265,12 +265,12 @@ sys_call_table: PTR sys_olduname PTR sys_umask /* 4060 */ PTR sys_chroot - PTR sys32_ustat + PTR sys_32_ustat PTR sys_dup2 PTR sys_getppid PTR sys_getpgrp /* 4065 */ PTR sys_setsid - PTR sys32_sigaction + PTR sys_32_sigaction PTR sys_sgetmask PTR sys_ssetmask PTR sys_setreuid /* 4070 */ @@ -293,7 +293,7 @@ sys_call_table: PTR sys_swapon PTR sys_reboot PTR compat_sys_old_readdir - PTR old_mmap /* 4090 */ + PTR sys_mips_mmap /* 4090 */ PTR sys_munmap PTR sys_truncate PTR sys_ftruncate @@ -320,12 +320,12 @@ sys_call_table: PTR compat_sys_wait4 PTR sys_swapoff /* 4115 */ PTR compat_sys_sysinfo - PTR sys32_ipc + PTR sys_32_ipc PTR sys_fsync PTR sys32_sigreturn PTR sys32_clone /* 4120 */ PTR sys_setdomainname - PTR sys32_newuname + PTR sys_32_newuname PTR sys_ni_syscall /* sys_modify_ldt */ PTR compat_sys_adjtimex PTR sys_mprotect /* 4125 */ @@ -339,11 +339,11 @@ sys_call_table: PTR sys_fchdir PTR sys_bdflush PTR sys_sysfs /* 4135 */ - PTR sys32_personality + PTR sys_32_personality PTR sys_ni_syscall /* for afs_syscall */ PTR sys_setfsuid PTR sys_setfsgid - PTR sys32_llseek /* 4140 */ + PTR sys_32_llseek /* 4140 */ PTR compat_sys_getdents PTR compat_sys_select PTR sys_flock @@ -356,7 +356,7 @@ sys_call_table: PTR sys_ni_syscall /* 4150 */ PTR sys_getsid PTR sys_fdatasync - PTR sys32_sysctl + PTR sys_32_sysctl PTR sys_mlock PTR sys_munlock /* 4155 */ PTR sys_mlockall @@ -368,7 +368,7 @@ sys_call_table: PTR sys_sched_yield PTR sys_sched_get_priority_max PTR sys_sched_get_priority_min - PTR sys32_sched_rr_get_interval /* 4165 */ + PTR sys_32_sched_rr_get_interval /* 4165 */ PTR compat_sys_nanosleep PTR sys_mremap PTR sys_accept @@ -397,25 +397,25 @@ sys_call_table: PTR sys_getresgid PTR sys_prctl PTR sys32_rt_sigreturn - PTR sys32_rt_sigaction - PTR sys32_rt_sigprocmask /* 4195 */ - PTR sys32_rt_sigpending + PTR sys_32_rt_sigaction + PTR sys_32_rt_sigprocmask /* 4195 */ + PTR sys_32_rt_sigpending PTR compat_sys_rt_sigtimedwait - PTR sys32_rt_sigqueueinfo + PTR sys_32_rt_sigqueueinfo PTR sys32_rt_sigsuspend - PTR sys32_pread /* 4200 */ - PTR sys32_pwrite + PTR sys_32_pread /* 4200 */ + PTR sys_32_pwrite PTR sys_chown PTR sys_getcwd PTR sys_capget PTR sys_capset /* 4205 */ PTR sys32_sigaltstack - PTR sys32_sendfile + PTR sys_32_sendfile PTR sys_ni_syscall PTR sys_ni_syscall - PTR sys32_mmap2 /* 4210 */ - PTR sys32_truncate64 - PTR sys32_ftruncate64 + PTR sys_mips_mmap2 /* 4210 */ + PTR sys_32_truncate64 + PTR sys_32_ftruncate64 PTR sys_newstat PTR sys_newlstat PTR sys_newfstat /* 4215 */ @@ -481,7 +481,7 @@ sys_call_table: PTR compat_sys_mq_notify /* 4275 */ PTR compat_sys_mq_getsetattr PTR sys_ni_syscall /* sys_vserver */ - PTR sys32_waitid + PTR sys_32_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key /* 4280 */ PTR sys_request_key diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index a4e106c56ab5..830c5ef9932b 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -19,6 +19,7 @@ #include <linux/ptrace.h> #include <linux/unistd.h> #include <linux/compiler.h> +#include <linux/syscalls.h> #include <linux/uaccess.h> #include <asm/abi.h> @@ -338,8 +339,8 @@ asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) } #ifdef CONFIG_TRAD_SIGNALS -asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act, - struct sigaction __user *oact) +SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, + struct sigaction __user *, oact) { struct k_sigaction new_ka, old_ka; int ret; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 652709b353ad..2e74075ac0ca 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -349,8 +349,8 @@ asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) return -ERESTARTNOHAND; } -asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act, - struct sigaction32 __user *oact) +SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act, + struct sigaction32 __user *, oact) { struct k_sigaction new_ka, old_ka; int ret; @@ -704,9 +704,9 @@ struct mips_abi mips_abi_32 = { .restart = __NR_O32_restart_syscall }; -asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, - struct sigaction32 __user *oact, - unsigned int sigsetsize) +SYSCALL_DEFINE4(32_rt_sigaction, int, sig, + const struct sigaction32 __user *, act, + struct sigaction32 __user *, oact, unsigned int, sigsetsize) { struct k_sigaction new_sa, old_sa; int ret = -EINVAL; @@ -748,8 +748,8 @@ out: return ret; } -asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, - compat_sigset_t __user *oset, unsigned int sigsetsize) +SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set, + compat_sigset_t __user *, oset, unsigned int, sigsetsize) { sigset_t old_set, new_set; int ret; @@ -770,8 +770,8 @@ asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, return ret; } -asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset, - unsigned int sigsetsize) +SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset, + unsigned int, sigsetsize) { int ret; sigset_t set; @@ -787,7 +787,8 @@ asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset, return ret; } -asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo) +SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig, + compat_siginfo_t __user *, uinfo) { siginfo_t info; int ret; @@ -802,10 +803,9 @@ asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user * return ret; } -asmlinkage long -sys32_waitid(int which, compat_pid_t pid, - compat_siginfo_t __user *uinfo, int options, - struct compat_rusage __user *uru) +SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid, + compat_siginfo_t __user *, uinfo, int, options, + struct compat_rusage __user *, uru) { siginfo_t info; struct rusage ru; diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 37970d9b2186..8cf384644040 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -152,9 +152,9 @@ out: return error; } -asmlinkage unsigned long -old_mmap(unsigned long addr, unsigned long len, int prot, - int flags, int fd, off_t offset) +SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, unsigned long, + fd, off_t, offset) { unsigned long result; @@ -168,9 +168,9 @@ out: return result; } -asmlinkage unsigned long -sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, unsigned long pgoff) +SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, unsigned long, fd, + unsigned long, pgoff) { if (pgoff & (~PAGE_MASK >> 12)) return -EINVAL; @@ -240,7 +240,7 @@ out: /* * Compacrapability ... */ -asmlinkage int sys_uname(struct old_utsname __user * name) +SYSCALL_DEFINE1(uname, struct old_utsname __user *, name) { if (name && !copy_to_user(name, utsname(), sizeof (*name))) return 0; @@ -250,7 +250,7 @@ asmlinkage int sys_uname(struct old_utsname __user * name) /* * Compacrapability ... */ -asmlinkage int sys_olduname(struct oldold_utsname __user * name) +SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name) { int error; @@ -279,7 +279,7 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name) return error; } -asmlinkage int sys_set_thread_area(unsigned long addr) +SYSCALL_DEFINE1(set_thread_area, unsigned long, addr) { struct thread_info *ti = task_thread_info(current); @@ -290,7 +290,7 @@ asmlinkage int sys_set_thread_area(unsigned long addr) return 0; } -asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) +asmlinkage int _sys_sysmips(long cmd, long arg1, long arg2, long arg3) { switch (cmd) { case MIPS_ATOMIC_SET: @@ -325,8 +325,8 @@ asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) * * This is really horribly ugly. */ -asmlinkage int sys_ipc(unsigned int call, int first, int second, - unsigned long third, void __user *ptr, long fifth) +SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, int, second, + unsigned long, third, void __user *, ptr, long, fifth) { int version, ret; @@ -411,7 +411,7 @@ asmlinkage int sys_ipc(unsigned int call, int first, int second, /* * No implemented yet ... */ -asmlinkage int sys_cachectl(char *addr, int nbytes, int op) +SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op) { return -ENOSYS; } diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 98ad0a82c29e..694d51f523d1 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -13,6 +13,7 @@ #include <linux/linkage.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/syscalls.h> #include <linux/mm.h> #include <asm/cacheflush.h> @@ -58,8 +59,8 @@ EXPORT_SYMBOL(_dma_cache_wback_inv); * We could optimize the case where the cache argument is not BCACHE but * that seems very atypical use ... */ -asmlinkage int sys_cacheflush(unsigned long addr, - unsigned long bytes, unsigned int cache) +SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, + unsigned int, cache) { if (bytes == 0) return 0; diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index ada06924a423..73cb6a3229ae 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -367,27 +367,24 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, unsigned int flags) { - char *ptr = (char *) ¤t->thread.TS_FPR(reg); - int i, ret; + char *ptr0 = (char *) ¤t->thread.TS_FPR(reg); + char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1); + int i, ret, sw = 0; if (!(flags & F)) return 0; if (reg & 1) return 0; /* invalid form: FRS/FRT must be even */ - if (!(flags & SW)) { - /* not byte-swapped - easy */ - if (!(flags & ST)) - ret = __copy_from_user(ptr, addr, 16); - else - ret = __copy_to_user(addr, ptr, 16); - } else { - /* each FPR value is byte-swapped separately */ - ret = 0; - for (i = 0; i < 16; ++i) { - if (!(flags & ST)) - ret |= __get_user(ptr[i^7], addr + i); - else - ret |= __put_user(ptr[i^7], addr + i); + if (flags & SW) + sw = 7; + ret = 0; + for (i = 0; i < 8; ++i) { + if (!(flags & ST)) { + ret |= __get_user(ptr0[i^sw], addr + i); + ret |= __get_user(ptr1[i^sw], addr + i + 8); + } else { + ret |= __put_user(ptr0[i^sw], addr + i); + ret |= __put_user(ptr1[i^sw], addr + i + 8); } } if (ret) diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S index 70693a5c12a1..693b14a778fa 100644 --- a/arch/powerpc/lib/copyuser_64.S +++ b/arch/powerpc/lib/copyuser_64.S @@ -62,18 +62,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 72: std r8,8(r3) beq+ 3f addi r3,r3,16 -23: ld r9,8(r4) .Ldo_tail: bf cr7*4+1,1f - rotldi r9,r9,32 +23: lwz r9,8(r4) + addi r4,r4,4 73: stw r9,0(r3) addi r3,r3,4 1: bf cr7*4+2,2f - rotldi r9,r9,16 +44: lhz r9,8(r4) + addi r4,r4,2 74: sth r9,0(r3) addi r3,r3,2 2: bf cr7*4+3,3f - rotldi r9,r9,8 +45: lbz r9,8(r4) 75: stb r9,0(r3) 3: li r3,0 blr @@ -141,11 +142,24 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 6: cmpwi cr1,r5,8 addi r3,r3,32 sld r9,r9,r10 - ble cr1,.Ldo_tail + ble cr1,7f 34: ld r0,8(r4) srd r7,r0,r11 or r9,r7,r9 - b .Ldo_tail +7: + bf cr7*4+1,1f + rotldi r9,r9,32 +94: stw r9,0(r3) + addi r3,r3,4 +1: bf cr7*4+2,2f + rotldi r9,r9,16 +95: sth r9,0(r3) + addi r3,r3,2 +2: bf cr7*4+3,3f + rotldi r9,r9,8 +96: stb r9,0(r3) +3: li r3,0 + blr .Ldst_unaligned: PPC_MTOCRF 0x01,r6 /* put #bytes to 8B bdry into cr7 */ @@ -218,7 +232,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 121: 132: addi r3,r3,8 -123: 134: 135: 138: @@ -226,6 +239,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 140: 141: 142: +123: +144: +145: /* * here we have had a fault on a load and r3 points to the first @@ -309,6 +325,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 187: 188: 189: +194: +195: +196: 1: ld r6,-24(r1) ld r5,-8(r1) @@ -329,7 +348,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) .llong 72b,172b .llong 23b,123b .llong 73b,173b + .llong 44b,144b .llong 74b,174b + .llong 45b,145b .llong 75b,175b .llong 24b,124b .llong 25b,125b @@ -347,6 +368,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) .llong 79b,179b .llong 80b,180b .llong 34b,134b + .llong 94b,194b + .llong 95b,195b + .llong 96b,196b .llong 35b,135b .llong 81b,181b .llong 36b,136b diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S index fe2d34e5332d..e178922b2c21 100644 --- a/arch/powerpc/lib/memcpy_64.S +++ b/arch/powerpc/lib/memcpy_64.S @@ -53,18 +53,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 3: std r8,8(r3) beq 3f addi r3,r3,16 - ld r9,8(r4) .Ldo_tail: bf cr7*4+1,1f - rotldi r9,r9,32 + lwz r9,8(r4) + addi r4,r4,4 stw r9,0(r3) addi r3,r3,4 1: bf cr7*4+2,2f - rotldi r9,r9,16 + lhz r9,8(r4) + addi r4,r4,2 sth r9,0(r3) addi r3,r3,2 2: bf cr7*4+3,3f - rotldi r9,r9,8 + lbz r9,8(r4) stb r9,0(r3) 3: ld r3,48(r1) /* return dest pointer */ blr @@ -133,11 +134,24 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) cmpwi cr1,r5,8 addi r3,r3,32 sld r9,r9,r10 - ble cr1,.Ldo_tail + ble cr1,6f ld r0,8(r4) srd r7,r0,r11 or r9,r7,r9 - b .Ldo_tail +6: + bf cr7*4+1,1f + rotldi r9,r9,32 + stw r9,0(r3) + addi r3,r3,4 +1: bf cr7*4+2,2f + rotldi r9,r9,16 + sth r9,0(r3) + addi r3,r3,2 +2: bf cr7*4+3,3f + rotldi r9,r9,8 + stb r9,0(r3) +3: ld r3,48(r1) /* return dest pointer */ + blr .Ldst_unaligned: PPC_MTOCRF 0x01,r6 # put #bytes to 8B bdry into cr7 diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 77fae5f64f2e..5558d932b4d5 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -204,6 +204,23 @@ static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller *hose, { u32 ma, pcila, pciha; + /* Hack warning ! The "old" PCI 2.x cell only let us configure the low + * 32-bit of incoming PLB addresses. The top 4 bits of the 36-bit + * address are actually hard wired to a value that appears to depend + * on the specific SoC. For example, it's 0 on 440EP and 1 on 440EPx. + * + * The trick here is we just crop those top bits and ignore them when + * programming the chip. That means the device-tree has to be right + * for the specific part used (we don't print a warning if it's wrong + * but on the other hand, you'll crash quickly enough), but at least + * this code should work whatever the hard coded value is + */ + plb_addr &= 0xffffffffull; + + /* Note: Due to the above hack, the test below doesn't actually test + * if you address is above 4G, but it tests that address and + * (address + size) are both contained in the same 4G + */ if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) || size < 0x1000 || (plb_addr & (size - 1)) != 0) { printk(KERN_WARNING "%s: Resource out of range\n", diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c index 7c35787d29b4..72da416f6162 100644 --- a/arch/sh/boards/board-ap325rxa.c +++ b/arch/sh/boards/board-ap325rxa.c @@ -22,7 +22,6 @@ #include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/spi/spi_gpio.h> -#include <media/ov772x.h> #include <media/soc_camera_platform.h> #include <media/sh_mobile_ceu.h> #include <video/sh_mobile_lcdc.h> @@ -224,7 +223,6 @@ static void camera_power(int val) } #ifdef CONFIG_I2C -/* support for the old ncm03j camera */ static unsigned char camera_ncm03j_magic[] = { 0x87, 0x00, 0x88, 0x08, 0x89, 0x01, 0x8A, 0xE8, @@ -245,23 +243,6 @@ static unsigned char camera_ncm03j_magic[] = 0x63, 0xD4, 0x64, 0xEA, 0xD6, 0x0F, }; -static int camera_probe(void) -{ - struct i2c_adapter *a = i2c_get_adapter(0); - struct i2c_msg msg; - int ret; - - camera_power(1); - msg.addr = 0x6e; - msg.buf = camera_ncm03j_magic; - msg.len = 2; - msg.flags = 0; - ret = i2c_transfer(a, &msg, 1); - camera_power(0); - - return ret; -} - static int camera_set_capture(struct soc_camera_platform_info *info, int enable) { @@ -313,35 +294,8 @@ static struct platform_device camera_device = { .platform_data = &camera_info, }, }; - -static int __init camera_setup(void) -{ - if (camera_probe() > 0) - platform_device_register(&camera_device); - - return 0; -} -late_initcall(camera_setup); - #endif /* CONFIG_I2C */ -static int ov7725_power(struct device *dev, int mode) -{ - camera_power(0); - if (mode) - camera_power(1); - - return 0; -} - -static struct ov772x_camera_info ov7725_info = { - .buswidth = SOCAM_DATAWIDTH_8, - .flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP, - .link = { - .power = ov7725_power, - }, -}; - static struct sh_mobile_ceu_info sh_mobile_ceu_info = { .flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8, @@ -392,6 +346,9 @@ static struct platform_device *ap325rxa_devices[] __initdata = { &ap325rxa_nor_flash_device, &lcdc_device, &ceu_device, +#ifdef CONFIG_I2C + &camera_device, +#endif &nand_flash_device, &sdcard_cn3_device, }; @@ -400,10 +357,6 @@ static struct i2c_board_info __initdata ap325rxa_i2c_devices[] = { { I2C_BOARD_INFO("pcf8563", 0x51), }, - { - I2C_BOARD_INFO("ov772x", 0x21), - .platform_data = &ov7725_info, - }, }; static struct spi_board_info ap325rxa_spi_devices[] = { diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c index 020a96fe961a..4a5e59732334 100644 --- a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c @@ -18,8 +18,8 @@ #include <asm/freq.h> #include <asm/io.h> -const static int pll1rate[]={1,2,3,4,6,8}; -const static int pfc_divisors[]={1,2,3,4,6,8,12}; +static const int pll1rate[]={1,2,3,4,6,8}; +static const int pfc_divisors[]={1,2,3,4,6,8,12}; #define ifc_divisors pfc_divisors #if (CONFIG_SH_CLK_MD == 0) diff --git a/arch/sparc/kernel/chmc.c b/arch/sparc/kernel/chmc.c index 3b9f4d6e14a9..e1a9598e2a4d 100644 --- a/arch/sparc/kernel/chmc.c +++ b/arch/sparc/kernel/chmc.c @@ -306,6 +306,7 @@ static int jbusmc_print_dimm(int syndrome_code, buf[1] = '?'; buf[2] = '?'; buf[3] = '\0'; + return 0; } p = dp->controller; prop = &p->layout; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 9c39095b33fc..bc2fbadff9f9 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1803,7 +1803,7 @@ config DMAR remapping devices. config DMAR_DEFAULT_ON - def_bool n + def_bool y prompt "Enable DMA Remapping Devices by default" depends on DMAR help diff --git a/arch/x86/include/asm/iomap.h b/arch/x86/include/asm/iomap.h index c1f06289b14b..86af26091d6c 100644 --- a/arch/x86/include/asm/iomap.h +++ b/arch/x86/include/asm/iomap.h @@ -23,6 +23,9 @@ #include <asm/pgtable.h> #include <asm/tlbflush.h> +int +is_io_mapping_possible(resource_size_t base, unsigned long size); + void * iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot); diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c index 7ffcdeec4631..b9cc84a2a4fc 100644 --- a/arch/x86/mach-voyager/voyager_smp.c +++ b/arch/x86/mach-voyager/voyager_smp.c @@ -65,7 +65,7 @@ static volatile unsigned long smp_invalidate_needed; /* Bitmask of CPUs present in the system - exported by i386_syms.c, used * by scheduler but indexed physically */ -cpumask_t phys_cpu_present_map = CPU_MASK_NONE; +static cpumask_t voyager_phys_cpu_present_map = CPU_MASK_NONE; /* The internal functions */ static void send_CPI(__u32 cpuset, __u8 cpi); @@ -366,19 +366,19 @@ void __init find_smp_config(void) /* set up everything for just this CPU, we can alter * this as we start the other CPUs later */ /* now get the CPU disposition from the extended CMOS */ - cpus_addr(phys_cpu_present_map)[0] = + cpus_addr(voyager_phys_cpu_present_map)[0] = voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK); - cpus_addr(phys_cpu_present_map)[0] |= + cpus_addr(voyager_phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 1) << 8; - cpus_addr(phys_cpu_present_map)[0] |= + cpus_addr(voyager_phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 2) << 16; - cpus_addr(phys_cpu_present_map)[0] |= + cpus_addr(voyager_phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 3) << 24; - init_cpu_possible(&phys_cpu_present_map); - printk("VOYAGER SMP: phys_cpu_present_map = 0x%lx\n", - cpus_addr(phys_cpu_present_map)[0]); + init_cpu_possible(&voyager_phys_cpu_present_map); + printk("VOYAGER SMP: voyager_phys_cpu_present_map = 0x%lx\n", + cpus_addr(voyager_phys_cpu_present_map)[0]); /* Here we set up the VIC to enable SMP */ /* enable the CPIs by writing the base vector to their register */ outb(VIC_DEFAULT_CPI_BASE, VIC_CPI_BASE_REGISTER); @@ -628,15 +628,15 @@ void __init smp_boot_cpus(void) /* now that the cat has probed the Voyager System Bus, sanity * check the cpu map */ if (((voyager_quad_processors | voyager_extended_vic_processors) - & cpus_addr(phys_cpu_present_map)[0]) != - cpus_addr(phys_cpu_present_map)[0]) { + & cpus_addr(voyager_phys_cpu_present_map)[0]) != + cpus_addr(voyager_phys_cpu_present_map)[0]) { /* should panic */ printk("\n\n***WARNING*** " "Sanity check of CPU present map FAILED\n"); } } else if (voyager_level == 4) voyager_extended_vic_processors = - cpus_addr(phys_cpu_present_map)[0]; + cpus_addr(voyager_phys_cpu_present_map)[0]; /* this sets up the idle task to run on the current cpu */ voyager_extended_cpus = 1; @@ -670,7 +670,7 @@ void __init smp_boot_cpus(void) /* loop over all the extended VIC CPUs and boot them. The * Quad CPUs must be bootstrapped by their extended VIC cpu */ for (i = 0; i < nr_cpu_ids; i++) { - if (i == boot_cpu_id || !cpu_isset(i, phys_cpu_present_map)) + if (i == boot_cpu_id || !cpu_isset(i, voyager_phys_cpu_present_map)) continue; do_boot_cpu(i); /* This udelay seems to be needed for the Quad boots diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c index ca53224fc56c..6c2b1af16926 100644 --- a/arch/x86/mm/iomap_32.c +++ b/arch/x86/mm/iomap_32.c @@ -20,6 +20,24 @@ #include <asm/pat.h> #include <linux/module.h> +#ifdef CONFIG_X86_PAE +int +is_io_mapping_possible(resource_size_t base, unsigned long size) +{ + return 1; +} +#else +int +is_io_mapping_possible(resource_size_t base, unsigned long size) +{ + /* There is no way to map greater than 1 << 32 address without PAE */ + if (base + size > 0x100000000ULL) + return 0; + + return 1; +} +#endif + /* Map 'pfn' using fixed map 'type' and protections 'prot' */ void * diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index bea215230b20..b58e96338149 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1672,6 +1672,9 @@ asmlinkage void __init xen_start_kernel(void) possible map and a non-dummy shared_info. */ per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; + local_irq_disable(); + early_boot_irqs_off(); + xen_raw_console_write("mapping kernel into physical memory\n"); pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages); diff --git a/block/blk-merge.c b/block/blk-merge.c index b92f5b0866b0..a104593e70c3 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -38,72 +38,84 @@ void blk_recalc_rq_sectors(struct request *rq, int nsect) } } -void blk_recalc_rq_segments(struct request *rq) +static unsigned int __blk_recalc_rq_segments(struct request_queue *q, + struct bio *bio, + unsigned int *seg_size_ptr) { - int nr_phys_segs; unsigned int phys_size; struct bio_vec *bv, *bvprv = NULL; - int seg_size; - int cluster; - struct req_iterator iter; - int high, highprv = 1; - struct request_queue *q = rq->q; + int cluster, i, high, highprv = 1; + unsigned int seg_size, nr_phys_segs; + struct bio *fbio; - if (!rq->bio) - return; + if (!bio) + return 0; + fbio = bio; cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); seg_size = 0; phys_size = nr_phys_segs = 0; - rq_for_each_segment(bv, rq, iter) { - /* - * the trick here is making sure that a high page is never - * considered part of another segment, since that might - * change with the bounce page. - */ - high = page_to_pfn(bv->bv_page) > q->bounce_pfn; - if (high || highprv) - goto new_segment; - if (cluster) { - if (seg_size + bv->bv_len > q->max_segment_size) - goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv)) - goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv)) + for_each_bio(bio) { + bio_for_each_segment(bv, bio, i) { + /* + * the trick here is making sure that a high page is + * never considered part of another segment, since that + * might change with the bounce page. + */ + high = page_to_pfn(bv->bv_page) > q->bounce_pfn; + if (high || highprv) goto new_segment; + if (cluster) { + if (seg_size + bv->bv_len > q->max_segment_size) + goto new_segment; + if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv)) + goto new_segment; + if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv)) + goto new_segment; + + seg_size += bv->bv_len; + bvprv = bv; + continue; + } +new_segment: + if (nr_phys_segs == 1 && seg_size > + fbio->bi_seg_front_size) + fbio->bi_seg_front_size = seg_size; - seg_size += bv->bv_len; + nr_phys_segs++; bvprv = bv; - continue; + seg_size = bv->bv_len; + highprv = high; } -new_segment: - if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size) - rq->bio->bi_seg_front_size = seg_size; - - nr_phys_segs++; - bvprv = bv; - seg_size = bv->bv_len; - highprv = high; } - if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size) + if (seg_size_ptr) + *seg_size_ptr = seg_size; + + return nr_phys_segs; +} + +void blk_recalc_rq_segments(struct request *rq) +{ + unsigned int seg_size = 0, phys_segs; + + phys_segs = __blk_recalc_rq_segments(rq->q, rq->bio, &seg_size); + + if (phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size) rq->bio->bi_seg_front_size = seg_size; if (seg_size > rq->biotail->bi_seg_back_size) rq->biotail->bi_seg_back_size = seg_size; - rq->nr_phys_segments = nr_phys_segs; + rq->nr_phys_segments = phys_segs; } void blk_recount_segments(struct request_queue *q, struct bio *bio) { - struct request rq; struct bio *nxt = bio->bi_next; - rq.q = q; - rq.bio = rq.biotail = bio; + bio->bi_next = NULL; - blk_recalc_rq_segments(&rq); + bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio, NULL); bio->bi_next = nxt; - bio->bi_phys_segments = rq.nr_phys_segments; bio->bi_flags |= (1 << BIO_SEG_VALID); } EXPORT_SYMBOL(blk_recount_segments); diff --git a/block/genhd.c b/block/genhd.c index e1eadcc9546a..a9ec910974c1 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -256,6 +256,22 @@ void blkdev_show(struct seq_file *seqf, off_t offset) } #endif /* CONFIG_PROC_FS */ +/** + * register_blkdev - register a new block device + * + * @major: the requested major device number [1..255]. If @major=0, try to + * allocate any unused major number. + * @name: the name of the new block device as a zero terminated string + * + * The @name must be unique within the system. + * + * The return value depends on the @major input parameter. + * - if a major device number was requested in range [1..255] then the + * function returns zero on success, or a negative error code + * - if any unused major number was requested with @major=0 parameter + * then the return value is the allocated major number in range + * [1..255] or a negative error code otherwise + */ int register_blkdev(unsigned int major, const char *name) { struct blk_major_name **n, *p; diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 63719ab9ea44..115b1cd6dcf5 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -24,7 +24,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_amd" -#define DRV_VERSION "0.3.11" +#define DRV_VERSION "0.4.1" /** * timing_setup - shared timing computation and load @@ -145,6 +145,13 @@ static int amd_pre_reset(struct ata_link *link, unsigned long deadline) return ata_sff_prereset(link, deadline); } +/** + * amd_cable_detect - report cable type + * @ap: port + * + * AMD controller/BIOS setups record the cable type in word 0x42 + */ + static int amd_cable_detect(struct ata_port *ap) { static const u32 bitmask[2] = {0x03, 0x0C}; @@ -158,6 +165,40 @@ static int amd_cable_detect(struct ata_port *ap) } /** + * amd_fifo_setup - set the PIO FIFO for ATA/ATAPI + * @ap: ATA interface + * @adev: ATA device + * + * Set the PCI fifo for this device according to the devices present + * on the bus at this point in time. We need to turn the post write buffer + * off for ATAPI devices as we may need to issue a word sized write to the + * device as the final I/O + */ + +static void amd_fifo_setup(struct ata_port *ap) +{ + struct ata_device *adev; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + static const u8 fifobit[2] = { 0xC0, 0x30}; + u8 fifo = fifobit[ap->port_no]; + u8 r; + + + ata_for_each_dev(adev, &ap->link, ENABLED) { + if (adev->class == ATA_DEV_ATAPI) + fifo = 0; + } + if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411) /* FIFO is broken */ + fifo = 0; + + /* On the later chips the read prefetch bits become no-op bits */ + pci_read_config_byte(pdev, 0x41, &r); + r &= ~fifobit[ap->port_no]; + r |= fifo; + pci_write_config_byte(pdev, 0x41, r); +} + +/** * amd33_set_piomode - set initial PIO mode data * @ap: ATA interface * @adev: ATA device @@ -167,21 +208,25 @@ static int amd_cable_detect(struct ata_port *ap) static void amd33_set_piomode(struct ata_port *ap, struct ata_device *adev) { + amd_fifo_setup(ap); timing_setup(ap, adev, 0x40, adev->pio_mode, 1); } static void amd66_set_piomode(struct ata_port *ap, struct ata_device *adev) { + amd_fifo_setup(ap); timing_setup(ap, adev, 0x40, adev->pio_mode, 2); } static void amd100_set_piomode(struct ata_port *ap, struct ata_device *adev) { + amd_fifo_setup(ap); timing_setup(ap, adev, 0x40, adev->pio_mode, 3); } static void amd133_set_piomode(struct ata_port *ap, struct ata_device *adev) { + amd_fifo_setup(ap); timing_setup(ap, adev, 0x40, adev->pio_mode, 4); } @@ -397,6 +442,16 @@ static struct ata_port_operations nv133_port_ops = { .set_dmamode = nv133_set_dmamode, }; +static void amd_clear_fifo(struct pci_dev *pdev) +{ + u8 fifo; + /* Disable the FIFO, the FIFO logic will re-enable it as + appropriate */ + pci_read_config_byte(pdev, 0x41, &fifo); + fifo &= 0x0F; + pci_write_config_byte(pdev, 0x41, fifo); +} + static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info[10] = { @@ -503,14 +558,8 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (type < 3) ata_pci_bmdma_clear_simplex(pdev); - - /* Check for AMD7411 */ - if (type == 3) - /* FIFO is broken */ - pci_write_config_byte(pdev, 0x41, fifo & 0x0F); - else - pci_write_config_byte(pdev, 0x41, fifo | 0xF0); - + if (pdev->vendor == PCI_VENDOR_ID_AMD) + amd_clear_fifo(pdev); /* Cable detection on Nvidia chips doesn't work too well, * cache BIOS programmed UDMA mode. */ @@ -536,18 +585,11 @@ static int amd_reinit_one(struct pci_dev *pdev) return rc; if (pdev->vendor == PCI_VENDOR_ID_AMD) { - u8 fifo; - pci_read_config_byte(pdev, 0x41, &fifo); - if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411) - /* FIFO is broken */ - pci_write_config_byte(pdev, 0x41, fifo & 0x0F); - else - pci_write_config_byte(pdev, 0x41, fifo | 0xF0); + amd_clear_fifo(pdev); if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7409 || pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401) ata_pci_bmdma_clear_simplex(pdev); } - ata_host_resume(host); return 0; } diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index f1bb2f9fecbf..b05b86a912c5 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -557,6 +557,9 @@ static unsigned int it821x_read_id(struct ata_device *adev, id[83] |= 0x4400; /* Word 83 is valid and LBA48 */ id[86] |= 0x0400; /* LBA48 on */ id[ATA_ID_MAJOR_VER] |= 0x1F; + /* Clear the serial number because it's different each boot + which breaks validation on resume */ + memset(&id[ATA_ID_SERNO], 0x20, ATA_ID_SERNO_LEN); } return err_mask; } diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 6c1d778b63a9..e3bc1b436284 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -283,9 +283,10 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, unsigned char *buf, unsigned int buflen, int rw) { - if (ata_id_has_dword_io(dev->id)) { + int slop = buflen & 3; + /* 32bit I/O capable *and* we need to write a whole number of dwords */ + if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3)) { struct ata_port *ap = dev->link->ap; - int slop = buflen & 3; unsigned long flags; local_irq_save(flags); @@ -735,7 +736,7 @@ static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf, struct ata_port *ap = adev->link->ap; int slop = buflen & 3; - if (ata_id_has_dword_io(adev->id)) { + if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3)) { if (rw == WRITE) iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); else diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 4ae1a4138b47..7007edd2d451 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -3114,19 +3114,17 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); } - if (!IS_SOC(hpriv)) { - /* Clear any currently outstanding host interrupt conditions */ - writelfl(0, mmio + hpriv->irq_cause_ofs); + /* Clear any currently outstanding host interrupt conditions */ + writelfl(0, mmio + hpriv->irq_cause_ofs); - /* and unmask interrupt generation for host regs */ - writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs); + /* and unmask interrupt generation for host regs */ + writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs); - /* - * enable only global host interrupts for now. - * The per-port interrupts get done later as ports are set up. - */ - mv_set_main_irq_mask(host, 0, PCI_ERR); - } + /* + * enable only global host interrupts for now. + * The per-port interrupts get done later as ports are set up. + */ + mv_set_main_irq_mask(host, 0, PCI_ERR); done: return rc; } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index d2cb67b61176..b5a061114630 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -3611,11 +3611,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, schedule_timeout_uninterruptible(30*HZ); /* Now try to get the controller to respond to a no-op */ - for (i=0; i<12; i++) { + for (i=0; i<30; i++) { if (cciss_noop(pdev) == 0) break; - else - printk("cciss: no-op failed%s\n", (i < 11 ? "; re-trying" : "")); + + schedule_timeout_uninterruptible(HZ); + } + if (i == 30) { + printk(KERN_ERR "cciss: controller seems dead\n"); + return -EBUSY; } } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 918ef725de41..b6c8ce254359 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -40,6 +40,7 @@ #include <linux/hdreg.h> #include <linux/cdrom.h> #include <linux/module.h> +#include <linux/scatterlist.h> #include <xen/xenbus.h> #include <xen/grant_table.h> @@ -82,6 +83,7 @@ struct blkfront_info enum blkif_state connected; int ring_ref; struct blkif_front_ring ring; + struct scatterlist sg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; unsigned int evtchn, irq; struct request_queue *rq; struct work_struct work; @@ -204,12 +206,11 @@ static int blkif_queue_request(struct request *req) struct blkfront_info *info = req->rq_disk->private_data; unsigned long buffer_mfn; struct blkif_request *ring_req; - struct req_iterator iter; - struct bio_vec *bvec; unsigned long id; unsigned int fsect, lsect; - int ref; + int i, ref; grant_ref_t gref_head; + struct scatterlist *sg; if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) return 1; @@ -238,12 +239,13 @@ static int blkif_queue_request(struct request *req) if (blk_barrier_rq(req)) ring_req->operation = BLKIF_OP_WRITE_BARRIER; - ring_req->nr_segments = 0; - rq_for_each_segment(bvec, req, iter) { - BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST); - buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page)); - fsect = bvec->bv_offset >> 9; - lsect = fsect + (bvec->bv_len >> 9) - 1; + ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); + BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); + + for_each_sg(info->sg, sg, ring_req->nr_segments, i) { + buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg))); + fsect = sg->offset >> 9; + lsect = fsect + (sg->length >> 9) - 1; /* install a grant reference. */ ref = gnttab_claim_grant_reference(&gref_head); BUG_ON(ref == -ENOSPC); @@ -254,16 +256,12 @@ static int blkif_queue_request(struct request *req) buffer_mfn, rq_data_dir(req) ); - info->shadow[id].frame[ring_req->nr_segments] = - mfn_to_pfn(buffer_mfn); - - ring_req->seg[ring_req->nr_segments] = + info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn); + ring_req->seg[i] = (struct blkif_request_segment) { .gref = ref, .first_sect = fsect, .last_sect = lsect }; - - ring_req->nr_segments++; } info->ring.req_prod_pvt++; @@ -622,6 +620,8 @@ static int setup_blkring(struct xenbus_device *dev, SHARED_RING_INIT(sring); FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); + sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST); + err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); if (err < 0) { free_page((unsigned long)sring); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 733028b4d45e..1c3a8c557140 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -452,6 +452,59 @@ static void drm_setup_crtcs(struct drm_device *dev) kfree(modes); kfree(enabled); } + +/** + * drm_encoder_crtc_ok - can a given crtc drive a given encoder? + * @encoder: encoder to test + * @crtc: crtc to test + * + * Return false if @encoder can't be driven by @crtc, true otherwise. + */ +static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, + struct drm_crtc *crtc) +{ + struct drm_device *dev; + struct drm_crtc *tmp; + int crtc_mask = 1; + + WARN(!crtc, "checking null crtc?"); + + dev = crtc->dev; + + list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { + if (tmp == crtc) + break; + crtc_mask <<= 1; + } + + if (encoder->possible_crtcs & crtc_mask) + return true; + return false; +} + +/* + * Check the CRTC we're going to map each output to vs. its current + * CRTC. If they don't match, we have to disable the output and the CRTC + * since the driver will have to re-route things. + */ +static void +drm_crtc_prepare_encoders(struct drm_device *dev) +{ + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_encoder *encoder; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder_funcs = encoder->helper_private; + /* Disable unused encoders */ + if (encoder->crtc == NULL) + (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); + /* Disable encoders whose CRTC is about to change */ + if (encoder_funcs->get_crtc && + encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) + (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); + } +} + /** * drm_crtc_set_mode - set a mode * @crtc: CRTC to program @@ -547,6 +600,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, encoder_funcs->prepare(encoder); } + drm_crtc_prepare_encoders(dev); + crtc_funcs->prepare(crtc); /* Set up the DPLL and any encoders state that needs to adjust or depend @@ -617,7 +672,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) struct drm_device *dev; struct drm_crtc **save_crtcs, *new_crtc; struct drm_encoder **save_encoders, *new_encoder; - struct drm_framebuffer *old_fb; + struct drm_framebuffer *old_fb = NULL; bool save_enabled; bool mode_changed = false; bool fb_changed = false; @@ -668,9 +723,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) * and then just flip_or_move it */ if (set->crtc->fb != set->fb) { /* If we have no fb then treat it as a full mode set */ - if (set->crtc->fb == NULL) + if (set->crtc->fb == NULL) { + DRM_DEBUG("crtc has no fb, full mode set\n"); mode_changed = true; - else if ((set->fb->bits_per_pixel != + } else if ((set->fb->bits_per_pixel != set->crtc->fb->bits_per_pixel) || set->fb->depth != set->crtc->fb->depth) fb_changed = true; @@ -682,7 +738,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) fb_changed = true; if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { - DRM_DEBUG("modes are different\n"); + DRM_DEBUG("modes are different, full mode set\n"); drm_mode_debug_printmodeline(&set->crtc->mode); drm_mode_debug_printmodeline(set->mode); mode_changed = true; @@ -708,6 +764,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) } if (new_encoder != connector->encoder) { + DRM_DEBUG("encoder changed, full mode switch\n"); mode_changed = true; connector->encoder = new_encoder; } @@ -734,10 +791,20 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) if (set->connectors[ro] == connector) new_crtc = set->crtc; } + + /* Make sure the new CRTC will work with the encoder */ + if (new_crtc && + !drm_encoder_crtc_ok(connector->encoder, new_crtc)) { + ret = -EINVAL; + goto fail_set_mode; + } if (new_crtc != connector->encoder->crtc) { + DRM_DEBUG("crtc changed, full mode switch\n"); mode_changed = true; connector->encoder->crtc = new_crtc; } + DRM_DEBUG("setting connector %d crtc to %p\n", + connector->base.id, new_crtc); } /* mode_set_base is not a required function */ @@ -781,6 +848,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) fail_set_mode: set->crtc->enabled = save_enabled; + set->crtc->fb = old_fb; count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5a4d3244758a..a839a28d8ee6 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -125,7 +125,7 @@ static bool edid_is_valid(struct edid *edid) DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); goto bad; } - if (edid->revision <= 0 || edid->revision > 3) { + if (edid->revision > 3) { DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision); goto bad; } @@ -320,10 +320,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo); mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo; - mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) | + mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 4) | pt->vsync_offset_lo); mode->vsync_end = mode->vsync_start + - ((pt->vsync_pulse_width_hi << 8) | + ((pt->vsync_pulse_width_hi << 4) | pt->vsync_pulse_width_lo); mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 3795dbc0f50c..93e677a481f5 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -435,6 +435,8 @@ EXPORT_SYMBOL(drm_vblank_get); */ void drm_vblank_put(struct drm_device *dev, int crtc) { + BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0); + /* Last user schedules interrupt disable */ if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); @@ -460,8 +462,9 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) * so that interrupts remain enabled in the interim. */ if (!dev->vblank_inmodeset[crtc]) { - dev->vblank_inmodeset[crtc] = 1; - drm_vblank_get(dev, crtc); + dev->vblank_inmodeset[crtc] = 0x1; + if (drm_vblank_get(dev, crtc) == 0) + dev->vblank_inmodeset[crtc] |= 0x2; } } EXPORT_SYMBOL(drm_vblank_pre_modeset); @@ -473,9 +476,12 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc) if (dev->vblank_inmodeset[crtc]) { spin_lock_irqsave(&dev->vbl_lock, irqflags); dev->vblank_disable_allowed = 1; - dev->vblank_inmodeset[crtc] = 0; spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - drm_vblank_put(dev, crtc); + + if (dev->vblank_inmodeset[crtc] & 0x2) + drm_vblank_put(dev, crtc); + + dev->vblank_inmodeset[crtc] = 0; } } EXPORT_SYMBOL(drm_vblank_post_modeset); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2d797ffe8137..6dab63bdc4c1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -811,7 +811,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, dev_priv->hws_map.flags = 0; dev_priv->hws_map.mtrr = 0; - drm_core_ioremap(&dev_priv->hws_map, dev); + drm_core_ioremap_wc(&dev_priv->hws_map, dev); if (dev_priv->hws_map.handle == NULL) { i915_dma_cleanup(dev); dev_priv->status_gfx_addr = 0; @@ -1090,6 +1090,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->mm.gtt_mapping = io_mapping_create_wc(dev->agp->base, dev->agp->agp_info.aper_size * 1024*1024); + if (dev_priv->mm.gtt_mapping == NULL) { + ret = -EIO; + goto out_rmmap; + } + /* Set up a WC MTRR for non-PAT systems. This is more common than * one would think, because the kernel disables PAT on first * generation Core chips because WC PAT gets overridden by a UC @@ -1122,7 +1127,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (!I915_NEED_GFX_HWS(dev)) { ret = i915_init_phys_hws(dev); if (ret != 0) - goto out_rmmap; + goto out_iomapfree; } /* On the 945G/GM, the chipset reports the MSI capability on the @@ -1161,6 +1166,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) return 0; +out_iomapfree: + io_mapping_free(dev_priv->mm.gtt_mapping); out_rmmap: iounmap(dev_priv->regs); free_priv: diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 28b726d07a0c..85685bfd12da 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3548,7 +3548,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, user_data = (char __user *) (uintptr_t) args->data_ptr; obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset; - DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size); + DRM_DEBUG("obj_addr %p, %lld\n", obj_addr, args->size); ret = copy_from_user(obj_addr, user_data, args->size); if (ret) return -EFAULT; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 65be30dccc77..fc28e2bbd542 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -111,6 +111,12 @@ parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) panel_fixed_mode->clock = dvo_timing->clock * 10; panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; + /* Some VBTs have bogus h/vtotal values */ + if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) + panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; + if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) + panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; + drm_mode_set_name(panel_fixed_mode); dev_priv->vbt_mode = panel_fixed_mode; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 65b635ce28c8..a2834276cb38 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -217,7 +217,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type) return false; } -#define INTELPllInvalid(s) do { DRM_DEBUG(s); return false; } while (0) +#define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) /** * Returns whether the given set of divisors are valid for a given refclk with * the given connectors. diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c index 9fee3ca17344..9aefb5e5864d 100644 --- a/drivers/i2c/busses/i2c-acorn.c +++ b/drivers/i2c/busses/i2c-acorn.c @@ -79,10 +79,11 @@ static struct i2c_algo_bit_data ioc_data = { .getsda = ioc_getsda, .getscl = ioc_getscl, .udelay = 80, - .timeout = 100 + .timeout = HZ, }; static struct i2c_adapter ioc_ops = { + .nr = 0, .algo_data = &ioc_data, }; @@ -90,7 +91,7 @@ static int __init i2c_ioc_init(void) { force_ones = FORCE_ONES | SCL | SDA; - return i2c_bit_add_bus(&ioc_ops); + return i2c_bit_add_numbered_bus(&ioc_ops); } module_init(i2c_ioc_init); diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index edab51973bf5..a7c59908c457 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -72,7 +72,7 @@ static unsigned int amd_ec_wait_write(struct amd_smbus *smbus) { int timeout = 500; - while (timeout-- && (inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF)) + while ((inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF) && --timeout) udelay(1); if (!timeout) { @@ -88,7 +88,7 @@ static unsigned int amd_ec_wait_read(struct amd_smbus *smbus) { int timeout = 500; - while (timeout-- && (~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF)) + while ((~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF) && --timeout) udelay(1); if (!timeout) { diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index 8e8467970481..c016f7a2c5fc 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -114,7 +114,7 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev) drv_data->algo_data.getsda = ixp2000_bit_getsda; drv_data->algo_data.getscl = ixp2000_bit_getscl; drv_data->algo_data.udelay = 6; - drv_data->algo_data.timeout = 100; + drv_data->algo_data.timeout = HZ; strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, sizeof(drv_data->adapter.name)); diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 6af68146c342..bdb1f7510e91 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -644,7 +644,7 @@ static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c, i2c_pxa_start_message(i2c); - while (timeout-- && i2c->msg_num > 0) { + while (i2c->msg_num > 0 && --timeout) { i2c_pxa_handler(0, i2c); udelay(10); } diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c index 162b74a04886..42df0eca43d5 100644 --- a/drivers/i2c/busses/scx200_i2c.c +++ b/drivers/i2c/busses/scx200_i2c.c @@ -76,7 +76,7 @@ static struct i2c_algo_bit_data scx200_i2c_data = { .getsda = scx200_i2c_getsda, .getscl = scx200_i2c_getscl, .udelay = 10, - .timeout = 100, + .timeout = HZ, }; static struct i2c_adapter scx200_i2c_ops = { diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b1c9abe24c7b..e7d984866de0 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1831,7 +1831,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, case I2C_SMBUS_QUICK: msg[0].len = 0; /* Special case: The read/write field is used as data */ - msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0; + msg[0].flags = flags | (read_write == I2C_SMBUS_READ ? + I2C_M_RD : 0); num = 1; break; case I2C_SMBUS_BYTE: diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index c171988a9f51..7e13d2df9af3 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -35,6 +35,7 @@ #include <linux/i2c.h> #include <linux/i2c-dev.h> #include <linux/smp_lock.h> +#include <linux/jiffies.h> #include <asm/uaccess.h> static struct i2c_driver i2cdev_driver; @@ -422,7 +423,10 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) client->adapter->retries = arg; break; case I2C_TIMEOUT: - client->adapter->timeout = arg; + /* For historical reasons, user-space sets the timeout + * value in units of 10 ms. + */ + client->adapter->timeout = msecs_to_jiffies(arg * 10); break; default: /* NOTE: returning a fault code here could cause trouble diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 3dad2299d9c5..e072903b12f0 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -46,7 +46,7 @@ menuconfig IDE SMART parameters from disk drives. To compile this driver as a module, choose M here: the - module will be called ide. + module will be called ide-core.ko. For further information, please read <file:Documentation/ide/ide.txt>. diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c index 69660a431cd9..77267c859965 100644 --- a/drivers/ide/amd74xx.c +++ b/drivers/ide/amd74xx.c @@ -166,7 +166,7 @@ static unsigned int init_chipset_amd74xx(struct pci_dev *dev) * Check for broken FIFO support. */ if (dev->vendor == PCI_VENDOR_ID_AMD && - dev->vendor == PCI_DEVICE_ID_AMD_VIPER_7411) + dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) t &= 0x0f; else t |= 0xf0; diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c index b2735d28f5cc..ecd1e62ca91a 100644 --- a/drivers/ide/atiixp.c +++ b/drivers/ide/atiixp.c @@ -52,7 +52,7 @@ static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio) { struct pci_dev *dev = to_pci_dev(drive->hwif->dev); unsigned long flags; - int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; + int timing_shift = (drive->dn ^ 1) * 8; u32 pio_timing_data; u16 pio_mode_data; @@ -85,7 +85,7 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed) { struct pci_dev *dev = to_pci_dev(drive->hwif->dev); unsigned long flags; - int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; + int timing_shift = (drive->dn ^ 1) * 8; u32 tmp32; u16 tmp16; u16 udma_ctl = 0; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 0bfeb0c79d6e..ddfbea41d296 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -55,7 +55,7 @@ static DEFINE_MUTEX(idecd_ref_mutex); -static void ide_cd_release(struct kref *); +static void ide_cd_release(struct device *); static struct cdrom_info *ide_cd_get(struct gendisk *disk) { @@ -67,7 +67,7 @@ static struct cdrom_info *ide_cd_get(struct gendisk *disk) if (ide_device_get(cd->drive)) cd = NULL; else - kref_get(&cd->kref); + get_device(&cd->dev); } mutex_unlock(&idecd_ref_mutex); @@ -79,7 +79,7 @@ static void ide_cd_put(struct cdrom_info *cd) ide_drive_t *drive = cd->drive; mutex_lock(&idecd_ref_mutex); - kref_put(&cd->kref, ide_cd_release); + put_device(&cd->dev); ide_device_put(drive); mutex_unlock(&idecd_ref_mutex); } @@ -194,6 +194,14 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, bio_sectors = max(bio_sectors(failed_command->bio), 4U); sector &= ~(bio_sectors - 1); + /* + * The SCSI specification allows for the value + * returned by READ CAPACITY to be up to 75 2K + * sectors past the last readable block. + * Therefore, if we hit a medium error within the + * last 75 2K sectors, we decrease the saved size + * value. + */ if (sector < get_capacity(info->disk) && drive->probed_capacity - sector < 4 * 75) set_capacity(info->disk, sector); @@ -1790,15 +1798,17 @@ static void ide_cd_remove(ide_drive_t *drive) ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__); ide_proc_unregister_driver(drive, info->driver); - + device_del(&info->dev); del_gendisk(info->disk); - ide_cd_put(info); + mutex_lock(&idecd_ref_mutex); + put_device(&info->dev); + mutex_unlock(&idecd_ref_mutex); } -static void ide_cd_release(struct kref *kref) +static void ide_cd_release(struct device *dev) { - struct cdrom_info *info = to_ide_drv(kref, cdrom_info); + struct cdrom_info *info = to_ide_drv(dev, cdrom_info); struct cdrom_device_info *devinfo = &info->devinfo; ide_drive_t *drive = info->drive; struct gendisk *g = info->disk; @@ -1997,7 +2007,12 @@ static int ide_cd_probe(ide_drive_t *drive) ide_init_disk(g, drive); - kref_init(&info->kref); + info->dev.parent = &drive->gendev; + info->dev.release = ide_cd_release; + dev_set_name(&info->dev, dev_name(&drive->gendev)); + + if (device_register(&info->dev)) + goto out_free_disk; info->drive = drive; info->driver = &ide_cdrom_driver; @@ -2011,7 +2026,7 @@ static int ide_cd_probe(ide_drive_t *drive) g->driverfs_dev = &drive->gendev; g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE; if (ide_cdrom_setup(drive)) { - ide_cd_release(&info->kref); + put_device(&info->dev); goto failed; } @@ -2021,6 +2036,8 @@ static int ide_cd_probe(ide_drive_t *drive) add_disk(g); return 0; +out_free_disk: + put_disk(g); out_free_cd: kfree(info); failed: diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h index ac40d6cb90a2..c878bfcf1116 100644 --- a/drivers/ide/ide-cd.h +++ b/drivers/ide/ide-cd.h @@ -80,7 +80,7 @@ struct cdrom_info { ide_drive_t *drive; struct ide_driver *driver; struct gendisk *disk; - struct kref kref; + struct device dev; /* Buffer for table of contents. NULL if we haven't allocated a TOC buffer for this device yet. */ diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index 7857b209c6df..047109419902 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c @@ -25,7 +25,7 @@ module_param(debug_mask, ulong, 0644); static DEFINE_MUTEX(ide_disk_ref_mutex); -static void ide_disk_release(struct kref *); +static void ide_disk_release(struct device *); static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) { @@ -37,7 +37,7 @@ static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) if (ide_device_get(idkp->drive)) idkp = NULL; else - kref_get(&idkp->kref); + get_device(&idkp->dev); } mutex_unlock(&ide_disk_ref_mutex); return idkp; @@ -48,7 +48,7 @@ static void ide_disk_put(struct ide_disk_obj *idkp) ide_drive_t *drive = idkp->drive; mutex_lock(&ide_disk_ref_mutex); - kref_put(&idkp->kref, ide_disk_release); + put_device(&idkp->dev); ide_device_put(drive); mutex_unlock(&ide_disk_ref_mutex); } @@ -66,17 +66,18 @@ static void ide_gd_remove(ide_drive_t *drive) struct gendisk *g = idkp->disk; ide_proc_unregister_driver(drive, idkp->driver); - + device_del(&idkp->dev); del_gendisk(g); - drive->disk_ops->flush(drive); - ide_disk_put(idkp); + mutex_lock(&ide_disk_ref_mutex); + put_device(&idkp->dev); + mutex_unlock(&ide_disk_ref_mutex); } -static void ide_disk_release(struct kref *kref) +static void ide_disk_release(struct device *dev) { - struct ide_disk_obj *idkp = to_ide_drv(kref, ide_disk_obj); + struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj); ide_drive_t *drive = idkp->drive; struct gendisk *g = idkp->disk; @@ -348,7 +349,12 @@ static int ide_gd_probe(ide_drive_t *drive) ide_init_disk(g, drive); - kref_init(&idkp->kref); + idkp->dev.parent = &drive->gendev; + idkp->dev.release = ide_disk_release; + dev_set_name(&idkp->dev, dev_name(&drive->gendev)); + + if (device_register(&idkp->dev)) + goto out_free_disk; idkp->drive = drive; idkp->driver = &ide_gd_driver; @@ -373,6 +379,8 @@ static int ide_gd_probe(ide_drive_t *drive) add_disk(g); return 0; +out_free_disk: + put_disk(g); out_free_idkp: kfree(idkp); failed: diff --git a/drivers/ide/ide-gd.h b/drivers/ide/ide-gd.h index a86779f0756b..b604bdd318a1 100644 --- a/drivers/ide/ide-gd.h +++ b/drivers/ide/ide-gd.h @@ -17,7 +17,7 @@ struct ide_disk_obj { ide_drive_t *drive; struct ide_driver *driver; struct gendisk *disk; - struct kref kref; + struct device dev; unsigned int openers; /* protected by BKL for now */ /* Last failed packet command */ diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index d7ecd3c79757..bb450a7608c2 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -169,7 +169,7 @@ typedef struct ide_tape_obj { ide_drive_t *drive; struct ide_driver *driver; struct gendisk *disk; - struct kref kref; + struct device dev; /* * failed_pc points to the last failed packet command, or contains @@ -267,7 +267,7 @@ static DEFINE_MUTEX(idetape_ref_mutex); static struct class *idetape_sysfs_class; -static void ide_tape_release(struct kref *); +static void ide_tape_release(struct device *); static struct ide_tape_obj *ide_tape_get(struct gendisk *disk) { @@ -279,7 +279,7 @@ static struct ide_tape_obj *ide_tape_get(struct gendisk *disk) if (ide_device_get(tape->drive)) tape = NULL; else - kref_get(&tape->kref); + get_device(&tape->dev); } mutex_unlock(&idetape_ref_mutex); return tape; @@ -290,7 +290,7 @@ static void ide_tape_put(struct ide_tape_obj *tape) ide_drive_t *drive = tape->drive; mutex_lock(&idetape_ref_mutex); - kref_put(&tape->kref, ide_tape_release); + put_device(&tape->dev); ide_device_put(drive); mutex_unlock(&idetape_ref_mutex); } @@ -308,7 +308,7 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i) mutex_lock(&idetape_ref_mutex); tape = idetape_devs[i]; if (tape) - kref_get(&tape->kref); + get_device(&tape->dev); mutex_unlock(&idetape_ref_mutex); return tape; } @@ -2256,15 +2256,17 @@ static void ide_tape_remove(ide_drive_t *drive) idetape_tape_t *tape = drive->driver_data; ide_proc_unregister_driver(drive, tape->driver); - + device_del(&tape->dev); ide_unregister_region(tape->disk); - ide_tape_put(tape); + mutex_lock(&idetape_ref_mutex); + put_device(&tape->dev); + mutex_unlock(&idetape_ref_mutex); } -static void ide_tape_release(struct kref *kref) +static void ide_tape_release(struct device *dev) { - struct ide_tape_obj *tape = to_ide_drv(kref, ide_tape_obj); + struct ide_tape_obj *tape = to_ide_drv(dev, ide_tape_obj); ide_drive_t *drive = tape->drive; struct gendisk *g = tape->disk; @@ -2407,7 +2409,12 @@ static int ide_tape_probe(ide_drive_t *drive) ide_init_disk(g, drive); - kref_init(&tape->kref); + tape->dev.parent = &drive->gendev; + tape->dev.release = ide_tape_release; + dev_set_name(&tape->dev, dev_name(&drive->gendev)); + + if (device_register(&tape->dev)) + goto out_free_disk; tape->drive = drive; tape->driver = &idetape_driver; @@ -2436,6 +2443,8 @@ static int ide_tape_probe(ide_drive_t *drive) return 0; +out_free_disk: + put_disk(g); out_free_tape: kfree(tape); failed: diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 258805da15c3..0920e3b0c962 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -337,6 +337,7 @@ static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp) int a, b, i, j = 1; unsigned int *dev_param_mask = (unsigned int *)kp->arg; + /* controller . device (0 or 1) [ : 1 (set) | 0 (clear) ] */ if (sscanf(s, "%d.%d:%d", &a, &b, &j) != 3 && sscanf(s, "%d.%d", &a, &b) != 2) return -EINVAL; @@ -349,7 +350,7 @@ static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp) if (j) *dev_param_mask |= (1 << i); else - *dev_param_mask &= (1 << i); + *dev_param_mask &= ~(1 << i); return 0; } @@ -392,6 +393,8 @@ static int ide_set_disk_chs(const char *str, struct kernel_param *kp) { int a, b, c = 0, h = 0, s = 0, i, j = 1; + /* controller . device (0 or 1) : Cylinders , Heads , Sectors */ + /* controller . device (0 or 1) : 1 (use CHS) | 0 (ignore CHS) */ if (sscanf(str, "%d.%d:%d,%d,%d", &a, &b, &c, &h, &s) != 5 && sscanf(str, "%d.%d:%d", &a, &b, &j) != 3) return -EINVAL; @@ -407,7 +410,7 @@ static int ide_set_disk_chs(const char *str, struct kernel_param *kp) if (j) ide_disks |= (1 << i); else - ide_disks &= (1 << i); + ide_disks &= ~(1 << i); ide_disks_chs[i].cyl = c; ide_disks_chs[i].head = h; @@ -469,6 +472,8 @@ static int ide_set_ignore_cable(const char *s, struct kernel_param *kp) { int i, j = 1; + /* controller (ignore) */ + /* controller : 1 (ignore) | 0 (use) */ if (sscanf(s, "%d:%d", &i, &j) != 2 && sscanf(s, "%d", &i) != 1) return -EINVAL; @@ -478,7 +483,7 @@ static int ide_set_ignore_cable(const char *s, struct kernel_param *kp) if (j) ide_ignore_cable |= (1 << i); else - ide_ignore_cable &= (1 << i); + ide_ignore_cable &= ~(1 << i); return 0; } diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c index e1c4f5437396..13b8153112ed 100644 --- a/drivers/ide/it821x.c +++ b/drivers/ide/it821x.c @@ -5,9 +5,8 @@ * May be copied or modified under the terms of the GNU General Public License * Based in part on the ITE vendor provided SCSI driver. * - * Documentation available from - * http://www.ite.com.tw/pc/IT8212F_V04.pdf - * Some other documents are NDA. + * Documentation: + * Datasheet is freely available, some other documents under NDA. * * The ITE8212 isn't exactly a standard IDE controller. It has two * modes. In pass through mode then it is an IDE controller. In its smart diff --git a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h index 2727bcd24194..467373cab8e5 100644 --- a/drivers/ieee1394/dma.h +++ b/drivers/ieee1394/dma.h @@ -12,6 +12,7 @@ #include <asm/types.h> +struct file; struct pci_dev; struct scatterlist; struct vm_area_struct; diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 2beb8d94f7bd..872338003721 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -1275,7 +1275,7 @@ static void __exit ieee1394_cleanup(void) unregister_chrdev_region(IEEE1394_CORE_DEV, 256); } -module_init(ieee1394_init); +fs_initcall(ieee1394_init); module_exit(ieee1394_cleanup); /* Exported symbols */ @@ -1314,6 +1314,7 @@ EXPORT_SYMBOL(hpsb_make_lock64packet); EXPORT_SYMBOL(hpsb_make_phypacket); EXPORT_SYMBOL(hpsb_read); EXPORT_SYMBOL(hpsb_write); +EXPORT_SYMBOL(hpsb_lock); EXPORT_SYMBOL(hpsb_packet_success); /** highlevel.c **/ diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c index 10c3d9f8c038..675b3135d5f1 100644 --- a/drivers/ieee1394/ieee1394_transactions.c +++ b/drivers/ieee1394/ieee1394_transactions.c @@ -501,8 +501,6 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, if (length == 0) return -EINVAL; - BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet - packet = hpsb_make_readpacket(host, node, addr, length); if (!packet) { @@ -550,8 +548,6 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, if (length == 0) return -EINVAL; - BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet - packet = hpsb_make_writepacket(host, node, addr, buffer, length); if (!packet) @@ -570,3 +566,30 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, return retval; } + +int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, quadlet_t *data, quadlet_t arg) +{ + struct hpsb_packet *packet; + int retval = 0; + + packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg); + if (!packet) + return -ENOMEM; + + packet->generation = generation; + retval = hpsb_send_packet_and_wait(packet); + if (retval < 0) + goto hpsb_lock_fail; + + retval = hpsb_packet_success(packet); + + if (retval == 0) + *data = packet->data[0]; + +hpsb_lock_fail: + hpsb_free_tlabel(packet); + hpsb_free_packet(packet); + + return retval; +} diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h index d2d5bc3546d7..20b693be14b2 100644 --- a/drivers/ieee1394/ieee1394_transactions.h +++ b/drivers/ieee1394/ieee1394_transactions.h @@ -30,6 +30,8 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, quadlet_t *buffer, size_t length); int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, quadlet_t *buffer, size_t length); +int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, quadlet_t *data, quadlet_t arg); #ifdef HPSB_DEBUG_TLABELS extern spinlock_t hpsb_tlabel_lock; diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h index b5de5f21ef78..c2089c093aa7 100644 --- a/drivers/ieee1394/iso.h +++ b/drivers/ieee1394/iso.h @@ -13,6 +13,7 @@ #define IEEE1394_ISO_H #include <linux/spinlock_types.h> +#include <linux/wait.h> #include <asm/atomic.h> #include <asm/types.h> diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 906c5a98d814..53aada5bbe1e 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -971,6 +971,9 @@ static struct unit_directory *nodemgr_process_unit_directory ud->ud_kv = ud_kv; ud->id = (*id)++; + /* inherit vendor_id from root directory if none exists in unit dir */ + ud->vendor_id = ne->vendor_id; + csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) { switch (kv->key.id) { case CSR1212_KV_ID_VENDOR: @@ -1265,7 +1268,8 @@ static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr, csr1212_destroy_csr(csr); } - /* Mark the node current */ + /* Finally, mark the node current */ + smp_wmb(); ne->generation = generation; if (ne->in_limbo) { @@ -1798,7 +1802,7 @@ void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet) { packet->host = ne->host; packet->generation = ne->generation; - barrier(); + smp_rmb(); packet->node_id = ne->nodeid; } @@ -1807,7 +1811,7 @@ int hpsb_node_write(struct node_entry *ne, u64 addr, { unsigned int generation = ne->generation; - barrier(); + smp_rmb(); return hpsb_write(ne->host, ne->nodeid, generation, addr, buffer, length); } diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h index 15ea09733e84..ee5acdbd114a 100644 --- a/drivers/ieee1394/nodemgr.h +++ b/drivers/ieee1394/nodemgr.h @@ -21,9 +21,11 @@ #define _IEEE1394_NODEMGR_H #include <linux/device.h> +#include <asm/system.h> #include <asm/types.h> #include "ieee1394_core.h" +#include "ieee1394_transactions.h" #include "ieee1394_types.h" struct csr1212_csr; @@ -154,6 +156,22 @@ static inline int hpsb_node_entry_valid(struct node_entry *ne) void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet); int hpsb_node_write(struct node_entry *ne, u64 addr, quadlet_t *buffer, size_t length); +static inline int hpsb_node_read(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length) +{ + unsigned int g = ne->generation; + + smp_rmb(); + return hpsb_read(ne->host, ne->nodeid, g, addr, buffer, length); +} +static inline int hpsb_node_lock(struct node_entry *ne, u64 addr, int extcode, + quadlet_t *buffer, quadlet_t arg) +{ + unsigned int g = ne->generation; + + smp_rmb(); + return hpsb_lock(ne->host, ne->nodeid, g, addr, extcode, buffer, arg); +} int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)); int init_ieee1394_nodemgr(void); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 01e3cffd03b8..e2466425d9ca 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1237,8 +1237,9 @@ static void end_sync_write(struct bio *bio, int error) update_head_pos(mirror, r1_bio); if (atomic_dec_and_test(&r1_bio->remaining)) { - md_done_sync(mddev, r1_bio->sectors, uptodate); + sector_t s = r1_bio->sectors; put_buf(r1_bio); + md_done_sync(mddev, s, uptodate); } } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 6736d6dff981..7301631abe04 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1236,6 +1236,7 @@ static void end_sync_read(struct bio *bio, int error) /* for reconstruct, we always reschedule after a read. * for resync, only after all reads */ + rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev); if (test_bit(R10BIO_IsRecover, &r10_bio->state) || atomic_dec_and_test(&r10_bio->remaining)) { /* we have read all the blocks, @@ -1243,7 +1244,6 @@ static void end_sync_read(struct bio *bio, int error) */ reschedule_retry(r10_bio); } - rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev); } static void end_sync_write(struct bio *bio, int error) @@ -1264,11 +1264,13 @@ static void end_sync_write(struct bio *bio, int error) update_head_pos(i, r10_bio); + rdev_dec_pending(conf->mirrors[d].rdev, mddev); while (atomic_dec_and_test(&r10_bio->remaining)) { if (r10_bio->master_bio == NULL) { /* the primary of several recovery bios */ - md_done_sync(mddev, r10_bio->sectors, 1); + sector_t s = r10_bio->sectors; put_buf(r10_bio); + md_done_sync(mddev, s, 1); break; } else { r10bio_t *r10_bio2 = (r10bio_t *)r10_bio->master_bio; @@ -1276,7 +1278,6 @@ static void end_sync_write(struct bio *bio, int error) r10_bio = r10_bio2; } } - rdev_dec_pending(conf->mirrors[d].rdev, mddev); } /* @@ -1749,8 +1750,6 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i if (!go_faster && conf->nr_waiting) msleep_interruptible(1000); - bitmap_cond_end_sync(mddev->bitmap, sector_nr); - /* Again, very different code for resync and recovery. * Both must result in an r10bio with a list of bios that * have bi_end_io, bi_sector, bi_bdev set, @@ -1886,6 +1885,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i /* resync. Schedule a read for every block at this virt offset */ int count = 0; + bitmap_cond_end_sync(mddev->bitmap, sector_nr); + if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, mddev->degraded) && !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { @@ -2010,13 +2011,13 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i /* There is nowhere to write, so all non-sync * drives must be failed, so try the next chunk... */ - { - sector_t sec = max_sector - sector_nr; - sectors_skipped += sec; + if (sector_nr + max_sync < max_sector) + max_sector = sector_nr + max_sync; + + sectors_skipped += (max_sector - sector_nr); chunks_skipped ++; sector_nr = max_sector; goto skipped; - } } static int run(mddev_t *mddev) diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 40ebde53b3ce..b0198691892a 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -51,6 +51,10 @@ comment "Supported SDMC DM1105 Adapters" depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/dm1105/Kconfig" +comment "Supported FireWire (IEEE 1394) Adapters" + depends on DVB_CORE && IEEE1394 +source "drivers/media/dvb/firewire/Kconfig" + comment "Supported DVB Frontends" depends on DVB_CORE source "drivers/media/dvb/frontends/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index f91e9eb15e52..6092a5bb5a7d 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -3,3 +3,5 @@ # obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ + +obj-$(CONFIG_DVB_FIREDTV) += firewire/ diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c index b386cc66c6b3..451974ba32f3 100644 --- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -192,6 +192,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d return 0; } +EXPORT_SYMBOL(flexcop_pid_feed_control); void flexcop_hw_filter_init(struct flexcop_device *fc) { diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 5b30dfc7846b..76e37fd96bb6 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -13,9 +13,9 @@ static int enable_pid_filtering = 1; module_param(enable_pid_filtering, int, 0444); MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); -static int irq_chk_intv; +static int irq_chk_intv = 100; module_param(irq_chk_intv, int, 0644); -MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging)."); +MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog."); #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG #define dprintk(level,args...) \ @@ -34,7 +34,9 @@ MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently jus static int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS); +MODULE_PARM_DESC(debug, + "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))." + DEBSTATUS); #define DRIVER_VERSION "0.1" #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" @@ -58,6 +60,8 @@ struct flexcop_pci { int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */ int count; + int count_prev; + int stream_problem; spinlock_t irq_lock; @@ -103,18 +107,32 @@ static void flexcop_pci_irq_check_work(struct work_struct *work) container_of(work, struct flexcop_pci, irq_check_work.work); struct flexcop_device *fc = fc_pci->fc_dev; - flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); - - flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4); - - if (v.sram_dest_reg_714.net_ovflow_error) - deb_chk("sram net_ovflow_error\n"); - if (v.sram_dest_reg_714.media_ovflow_error) - deb_chk("sram media_ovflow_error\n"); - if (v.sram_dest_reg_714.cai_ovflow_error) - deb_chk("sram cai_ovflow_error\n"); - if (v.sram_dest_reg_714.cai_ovflow_error) - deb_chk("sram cai_ovflow_error\n"); + if (fc->feedcount) { + + if (fc_pci->count == fc_pci->count_prev) { + deb_chk("no IRQ since the last check\n"); + if (fc_pci->stream_problem++ == 3) { + struct dvb_demux_feed *feed; + + spin_lock_irq(&fc->demux.lock); + list_for_each_entry(feed, &fc->demux.feed_list, + list_head) { + flexcop_pid_feed_control(fc, feed, 0); + } + + list_for_each_entry(feed, &fc->demux.feed_list, + list_head) { + flexcop_pid_feed_control(fc, feed, 1); + } + spin_unlock_irq(&fc->demux.lock); + + fc_pci->stream_problem = 0; + } + } else { + fc_pci->stream_problem = 0; + fc_pci->count_prev = fc_pci->count; + } + } schedule_delayed_work(&fc_pci->irq_check_work, msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); @@ -216,16 +234,12 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) flexcop_dma_control_timer_irq(fc,FC_DMA_1,1); deb_irq("IRQ enabled\n"); + fc_pci->count_prev = fc_pci->count; + // fc_pci->active_dma1_addr = 0; // flexcop_dma_control_size_irq(fc,FC_DMA_1,1); - if (irq_chk_intv > 0) - schedule_delayed_work(&fc_pci->irq_check_work, - msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); } else { - if (irq_chk_intv > 0) - cancel_delayed_work(&fc_pci->irq_check_work); - flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); deb_irq("IRQ disabled\n"); @@ -299,8 +313,6 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) goto err_pci_iounmap; - - fc_pci->init_state |= FC_PCI_INIT; return ret; @@ -375,6 +387,10 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work); + if (irq_chk_intv > 0) + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); + return ret; err_fc_exit: @@ -393,6 +409,9 @@ static void flexcop_pci_remove(struct pci_dev *pdev) { struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); + if (irq_chk_intv > 0) + cancel_delayed_work(&fc_pci->irq_check_work); + flexcop_pci_dma_exit(fc_pci); flexcop_device_exit(fc_pci->fc_dev); flexcop_pci_exit(fc_pci); diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 676413a915b4..91068952b502 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -212,8 +212,7 @@ void flexcop_reset_block_300(struct flexcop_device *fc) v210.sw_reset_210.Block_reset_enable = 0xb2; fc->write_ibi_reg(fc,sw_reset_210,v210); - msleep(1); - + udelay(1000); fc->write_ibi_reg(fc,ctrl_208,v208_save); } diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/dvb/firewire/Kconfig new file mode 100644 index 000000000000..69028253e984 --- /dev/null +++ b/drivers/media/dvb/firewire/Kconfig @@ -0,0 +1,22 @@ +config DVB_FIREDTV + tristate "FireDTV and FloppyDTV" + depends on DVB_CORE && IEEE1394 + help + Support for DVB receivers from Digital Everywhere + which are connected via IEEE 1394 (FireWire). + + These devices don't have an MPEG decoder built in, + so you need an external software decoder to watch TV. + + To compile this driver as a module, say M here: + the module will be called firedtv. + +if DVB_FIREDTV + +config DVB_FIREDTV_IEEE1394 + def_bool IEEE1394 + +config DVB_FIREDTV_INPUT + def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m) + +endif # DVB_FIREDTV diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile new file mode 100644 index 000000000000..2034695ba194 --- /dev/null +++ b/drivers/media/dvb/firewire/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_DVB_FIREDTV) += firedtv.o + +firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o +firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o +firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o + +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-$(CONFIG_DVB_FIREDTV_IEEE1394) += -Idrivers/ieee1394 diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c new file mode 100644 index 000000000000..4e207658c5d9 --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-1394.c @@ -0,0 +1,285 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> + * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com> + * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <dma.h> +#include <csr1212.h> +#include <highlevel.h> +#include <hosts.h> +#include <ieee1394.h> +#include <iso.h> +#include <nodemgr.h> + +#include "firedtv.h" + +static LIST_HEAD(node_list); +static DEFINE_SPINLOCK(node_list_lock); + +#define FIREWIRE_HEADER_SIZE 4 +#define CIP_HEADER_SIZE 8 + +static void rawiso_activity_cb(struct hpsb_iso *iso) +{ + struct firedtv *f, *fdtv = NULL; + unsigned int i, num, packet; + unsigned char *buf; + unsigned long flags; + int count; + + spin_lock_irqsave(&node_list_lock, flags); + list_for_each_entry(f, &node_list, list) + if (f->backend_data == iso) { + fdtv = f; + break; + } + spin_unlock_irqrestore(&node_list_lock, flags); + + packet = iso->first_packet; + num = hpsb_iso_n_ready(iso); + + if (!fdtv) { + dev_err(fdtv->device, "received at unknown iso channel\n"); + goto out; + } + + for (i = 0; i < num; i++, packet = (packet + 1) % iso->buf_packets) { + buf = dma_region_i(&iso->data_buf, unsigned char, + iso->infos[packet].offset + CIP_HEADER_SIZE); + count = (iso->infos[packet].len - CIP_HEADER_SIZE) / + (188 + FIREWIRE_HEADER_SIZE); + + /* ignore empty packet */ + if (iso->infos[packet].len <= CIP_HEADER_SIZE) + continue; + + while (count--) { + if (buf[FIREWIRE_HEADER_SIZE] == 0x47) + dvb_dmx_swfilter_packets(&fdtv->demux, + &buf[FIREWIRE_HEADER_SIZE], 1); + else + dev_err(fdtv->device, + "skipping invalid packet\n"); + buf += 188 + FIREWIRE_HEADER_SIZE; + } + } +out: + hpsb_iso_recv_release_packets(iso, num); +} + +static inline struct node_entry *node_of(struct firedtv *fdtv) +{ + return container_of(fdtv->device, struct unit_directory, device)->ne; +} + +static int node_lock(struct firedtv *fdtv, u64 addr, void *data, __be32 arg) +{ + return hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP, data, + (__force quadlet_t)arg); +} + +static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len) +{ + return hpsb_node_read(node_of(fdtv), addr, data, len); +} + +static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) +{ + return hpsb_node_write(node_of(fdtv), addr, data, len); +} + +#define FDTV_ISO_BUFFER_PACKETS 256 +#define FDTV_ISO_BUFFER_SIZE (FDTV_ISO_BUFFER_PACKETS * 200) + +static int start_iso(struct firedtv *fdtv) +{ + struct hpsb_iso *iso_handle; + int ret; + + iso_handle = hpsb_iso_recv_init(node_of(fdtv)->host, + FDTV_ISO_BUFFER_SIZE, FDTV_ISO_BUFFER_PACKETS, + fdtv->isochannel, HPSB_ISO_DMA_DEFAULT, + -1, /* stat.config.irq_interval */ + rawiso_activity_cb); + if (iso_handle == NULL) { + dev_err(fdtv->device, "cannot initialize iso receive\n"); + return -ENOMEM; + } + fdtv->backend_data = iso_handle; + + ret = hpsb_iso_recv_start(iso_handle, -1, -1, 0); + if (ret != 0) { + dev_err(fdtv->device, "cannot start iso receive\n"); + hpsb_iso_shutdown(iso_handle); + fdtv->backend_data = NULL; + } + return ret; +} + +static void stop_iso(struct firedtv *fdtv) +{ + struct hpsb_iso *iso_handle = fdtv->backend_data; + + if (iso_handle != NULL) { + hpsb_iso_stop(iso_handle); + hpsb_iso_shutdown(iso_handle); + } + fdtv->backend_data = NULL; +} + +static const struct firedtv_backend fdtv_1394_backend = { + .lock = node_lock, + .read = node_read, + .write = node_write, + .start_iso = start_iso, + .stop_iso = stop_iso, +}; + +static void fcp_request(struct hpsb_host *host, int nodeid, int direction, + int cts, u8 *data, size_t length) +{ + struct firedtv *f, *fdtv = NULL; + unsigned long flags; + int su; + + if (length == 0 || (data[0] & 0xf0) != 0) + return; + + su = data[1] & 0x7; + + spin_lock_irqsave(&node_list_lock, flags); + list_for_each_entry(f, &node_list, list) + if (node_of(f)->host == host && + node_of(f)->nodeid == nodeid && + (f->subunit == su || (f->subunit == 0 && su == 0x7))) { + fdtv = f; + break; + } + spin_unlock_irqrestore(&node_list_lock, flags); + + if (fdtv) + avc_recv(fdtv, data, length); +} + +static int node_probe(struct device *dev) +{ + struct unit_directory *ud = + container_of(dev, struct unit_directory, device); + struct firedtv *fdtv; + int kv_len, err; + void *kv_str; + + kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t); + kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv); + + fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len); + if (!fdtv) + return -ENOMEM; + + /* + * Work around a bug in udev's path_id script: Use the fw-host's dev + * instead of the unit directory's dev as parent of the input device. + */ + err = fdtv_register_rc(fdtv, dev->parent->parent); + if (err) + goto fail_free; + + spin_lock_irq(&node_list_lock); + list_add_tail(&fdtv->list, &node_list); + spin_unlock_irq(&node_list_lock); + + err = avc_identify_subunit(fdtv); + if (err) + goto fail; + + err = fdtv_dvb_register(fdtv); + if (err) + goto fail; + + avc_register_remote_control(fdtv); + return 0; +fail: + spin_lock_irq(&node_list_lock); + list_del(&fdtv->list); + spin_unlock_irq(&node_list_lock); + fdtv_unregister_rc(fdtv); +fail_free: + kfree(fdtv); + return err; +} + +static int node_remove(struct device *dev) +{ + struct firedtv *fdtv = dev->driver_data; + + fdtv_dvb_unregister(fdtv); + + spin_lock_irq(&node_list_lock); + list_del(&fdtv->list); + spin_unlock_irq(&node_list_lock); + + cancel_work_sync(&fdtv->remote_ctrl_work); + fdtv_unregister_rc(fdtv); + + kfree(fdtv); + return 0; +} + +static int node_update(struct unit_directory *ud) +{ + struct firedtv *fdtv = ud->device.driver_data; + + if (fdtv->isochannel >= 0) + cmp_establish_pp_connection(fdtv, fdtv->subunit, + fdtv->isochannel); + return 0; +} + +static struct hpsb_protocol_driver fdtv_driver = { + .name = "firedtv", + .update = node_update, + .driver = { + .probe = node_probe, + .remove = node_remove, + }, +}; + +static struct hpsb_highlevel fdtv_highlevel = { + .name = "firedtv", + .fcp_request = fcp_request, +}; + +int __init fdtv_1394_init(struct ieee1394_device_id id_table[]) +{ + int ret; + + hpsb_register_highlevel(&fdtv_highlevel); + fdtv_driver.id_table = id_table; + ret = hpsb_register_protocol(&fdtv_driver); + if (ret) { + printk(KERN_ERR "firedtv: failed to register protocol\n"); + hpsb_unregister_highlevel(&fdtv_highlevel); + } + return ret; +} + +void __exit fdtv_1394_exit(void) +{ + hpsb_unregister_protocol(&fdtv_driver); + hpsb_unregister_highlevel(&fdtv_highlevel); +} diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c new file mode 100644 index 000000000000..b55d9ccaf33e --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-avc.c @@ -0,0 +1,1315 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> + * Copyright (C) 2008 Ben Backx <ben@bbackx.com> + * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/bug.h> +#include <linux/crc32.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/moduleparam.h> +#include <linux/mutex.h> +#include <linux/string.h> +#include <linux/stringify.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +#include "firedtv.h" + +#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL + +#define AVC_CTYPE_CONTROL 0x0 +#define AVC_CTYPE_STATUS 0x1 +#define AVC_CTYPE_NOTIFY 0x3 + +#define AVC_RESPONSE_ACCEPTED 0x9 +#define AVC_RESPONSE_STABLE 0xc +#define AVC_RESPONSE_CHANGED 0xd +#define AVC_RESPONSE_INTERIM 0xf + +#define AVC_SUBUNIT_TYPE_TUNER (0x05 << 3) +#define AVC_SUBUNIT_TYPE_UNIT (0x1f << 3) + +#define AVC_OPCODE_VENDOR 0x00 +#define AVC_OPCODE_READ_DESCRIPTOR 0x09 +#define AVC_OPCODE_DSIT 0xc8 +#define AVC_OPCODE_DSD 0xcb + +#define DESCRIPTOR_TUNER_STATUS 0x80 +#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00 + +#define SFE_VENDOR_DE_COMPANYID_0 0x00 /* OUI of Digital Everywhere */ +#define SFE_VENDOR_DE_COMPANYID_1 0x12 +#define SFE_VENDOR_DE_COMPANYID_2 0x87 + +#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0a +#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52 +#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 /* for DVB-S */ + +#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00 +#define SFE_VENDOR_OPCODE_HOST2CA 0x56 +#define SFE_VENDOR_OPCODE_CA2HOST 0x57 +#define SFE_VENDOR_OPCODE_CISTATUS 0x59 +#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 /* for DVB-S2 */ + +#define SFE_VENDOR_TAG_CA_RESET 0x00 +#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01 +#define SFE_VENDOR_TAG_CA_PMT 0x02 +#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04 +#define SFE_VENDOR_TAG_CA_MMI 0x05 +#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07 + +#define EN50221_LIST_MANAGEMENT_ONLY 0x03 +#define EN50221_TAG_APP_INFO 0x9f8021 +#define EN50221_TAG_CA_INFO 0x9f8031 + +struct avc_command_frame { + int length; + u8 ctype; + u8 subunit; + u8 opcode; + u8 operand[509]; +}; + +struct avc_response_frame { + int length; + u8 response; + u8 subunit; + u8 opcode; + u8 operand[509]; +}; + +#define AVC_DEBUG_FCP_SUBACTIONS 1 +#define AVC_DEBUG_FCP_PAYLOADS 2 + +static int avc_debug; +module_param_named(debug, avc_debug, int, 0644); +MODULE_PARM_DESC(debug, "Verbose logging (default = 0" + ", FCP subactions = " __stringify(AVC_DEBUG_FCP_SUBACTIONS) + ", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS) + ", or all = -1)"); + +static const char *debug_fcp_ctype(unsigned int ctype) +{ + static const char *ctypes[] = { + [0x0] = "CONTROL", [0x1] = "STATUS", + [0x2] = "SPECIFIC INQUIRY", [0x3] = "NOTIFY", + [0x4] = "GENERAL INQUIRY", [0x8] = "NOT IMPLEMENTED", + [0x9] = "ACCEPTED", [0xa] = "REJECTED", + [0xb] = "IN TRANSITION", [0xc] = "IMPLEMENTED/STABLE", + [0xd] = "CHANGED", [0xf] = "INTERIM", + }; + const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL; + + return ret ? ret : "?"; +} + +static const char *debug_fcp_opcode(unsigned int opcode, + const u8 *data, size_t length) +{ + switch (opcode) { + case AVC_OPCODE_VENDOR: break; + case AVC_OPCODE_READ_DESCRIPTOR: return "ReadDescriptor"; + case AVC_OPCODE_DSIT: return "DirectSelectInfo.Type"; + case AVC_OPCODE_DSD: return "DirectSelectData"; + default: return "?"; + } + + if (length < 7 || + data[3] != SFE_VENDOR_DE_COMPANYID_0 || + data[4] != SFE_VENDOR_DE_COMPANYID_1 || + data[5] != SFE_VENDOR_DE_COMPANYID_2) + return "Vendor"; + + switch (data[6]) { + case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL: return "RegisterRC"; + case SFE_VENDOR_OPCODE_LNB_CONTROL: return "LNBControl"; + case SFE_VENDOR_OPCODE_TUNE_QPSK: return "TuneQPSK"; + case SFE_VENDOR_OPCODE_HOST2CA: return "Host2CA"; + case SFE_VENDOR_OPCODE_CA2HOST: return "CA2Host"; + } + return "Vendor"; +} + +static void debug_fcp(const u8 *data, size_t length) +{ + unsigned int subunit_type, subunit_id, op; + const char *prefix = data[0] > 7 ? "FCP <- " : "FCP -> "; + + if (avc_debug & AVC_DEBUG_FCP_SUBACTIONS) { + subunit_type = data[1] >> 3; + subunit_id = data[1] & 7; + op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2]; + printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n", + prefix, subunit_type, subunit_id, length, + debug_fcp_ctype(data[0]), + debug_fcp_opcode(op, data, length)); + } + + if (avc_debug & AVC_DEBUG_FCP_PAYLOADS) + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE, 16, 1, + data, length, false); +} + +static int __avc_write(struct firedtv *fdtv, + const struct avc_command_frame *c, struct avc_response_frame *r) +{ + int err, retry; + + if (r) + fdtv->avc_reply_received = false; + + for (retry = 0; retry < 6; retry++) { + if (unlikely(avc_debug)) + debug_fcp(&c->ctype, c->length); + + err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER, + (void *)&c->ctype, c->length); + if (err) { + fdtv->avc_reply_received = true; + dev_err(fdtv->device, "FCP command write failed\n"); + return err; + } + + if (!r) + return 0; + + /* + * AV/C specs say that answers should be sent within 150 ms. + * Time out after 200 ms. + */ + if (wait_event_timeout(fdtv->avc_wait, + fdtv->avc_reply_received, + msecs_to_jiffies(200)) != 0) { + r->length = fdtv->response_length; + memcpy(&r->response, fdtv->response, r->length); + + return 0; + } + } + dev_err(fdtv->device, "FCP response timed out\n"); + return -ETIMEDOUT; +} + +static int avc_write(struct firedtv *fdtv, + const struct avc_command_frame *c, struct avc_response_frame *r) +{ + int ret; + + if (mutex_lock_interruptible(&fdtv->avc_mutex)) + return -EINTR; + + ret = __avc_write(fdtv, c, r); + + mutex_unlock(&fdtv->avc_mutex); + return ret; +} + +int avc_recv(struct firedtv *fdtv, void *data, size_t length) +{ + struct avc_response_frame *r = + data - offsetof(struct avc_response_frame, response); + + if (unlikely(avc_debug)) + debug_fcp(data, length); + + if (length >= 8 && + r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && + r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && + r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && + r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { + if (r->response == AVC_RESPONSE_CHANGED) { + fdtv_handle_rc(fdtv, + r->operand[4] << 8 | r->operand[5]); + schedule_work(&fdtv->remote_ctrl_work); + } else if (r->response != AVC_RESPONSE_INTERIM) { + dev_info(fdtv->device, + "remote control result = %d\n", r->response); + } + return 0; + } + + if (fdtv->avc_reply_received) { + dev_err(fdtv->device, "out-of-order AVC response, ignored\n"); + return -EIO; + } + + memcpy(fdtv->response, data, length); + fdtv->response_length = length; + + fdtv->avc_reply_received = true; + wake_up(&fdtv->avc_wait); + + return 0; +} + +/* + * tuning command for setting the relative LNB frequency + * (not supported by the AVC standard) + */ +static void avc_tuner_tuneqpsk(struct firedtv *fdtv, + struct dvb_frontend_parameters *params, + struct avc_command_frame *c) +{ + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; + + c->operand[4] = (params->frequency >> 24) & 0xff; + c->operand[5] = (params->frequency >> 16) & 0xff; + c->operand[6] = (params->frequency >> 8) & 0xff; + c->operand[7] = params->frequency & 0xff; + + c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; + c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; + + switch (params->u.qpsk.fec_inner) { + case FEC_1_2: c->operand[10] = 0x1; break; + case FEC_2_3: c->operand[10] = 0x2; break; + case FEC_3_4: c->operand[10] = 0x3; break; + case FEC_5_6: c->operand[10] = 0x4; break; + case FEC_7_8: c->operand[10] = 0x5; break; + case FEC_4_5: + case FEC_8_9: + case FEC_AUTO: + default: c->operand[10] = 0x0; + } + + if (fdtv->voltage == 0xff) + c->operand[11] = 0xff; + else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */ + c->operand[11] = 0; + else + c->operand[11] = 1; + + if (fdtv->tone == 0xff) + c->operand[12] = 0xff; + else if (fdtv->tone == SEC_TONE_ON) /* band */ + c->operand[12] = 1; + else + c->operand[12] = 0; + + if (fdtv->type == FIREDTV_DVB_S2) { + c->operand[13] = 0x1; + c->operand[14] = 0xff; + c->operand[15] = 0xff; + c->length = 20; + } else { + c->length = 16; + } +} + +static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params, + struct avc_command_frame *c) +{ + c->opcode = AVC_OPCODE_DSD; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0x20; /* system id = DVB */ + c->operand[3] = 0x00; /* antenna number */ + c->operand[4] = 0x11; /* system_specific_multiplex selection_length */ + + /* multiplex_valid_flags, high byte */ + c->operand[5] = 0 << 7 /* reserved */ + | 0 << 6 /* Polarisation */ + | 0 << 5 /* Orbital_Pos */ + | 1 << 4 /* Frequency */ + | 1 << 3 /* Symbol_Rate */ + | 0 << 2 /* FEC_outer */ + | (params->u.qam.fec_inner != FEC_AUTO ? 1 << 1 : 0) + | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0); + + /* multiplex_valid_flags, low byte */ + c->operand[6] = 0 << 7 /* NetworkID */ + | 0 << 0 /* reserved */ ; + + c->operand[7] = 0x00; + c->operand[8] = 0x00; + c->operand[9] = 0x00; + c->operand[10] = 0x00; + + c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); + c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff; + c->operand[13] = (params->frequency / 4000) & 0xff; + c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; + c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; + c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; + c->operand[17] = 0x00; + + switch (params->u.qpsk.fec_inner) { + case FEC_1_2: c->operand[18] = 0x1; break; + case FEC_2_3: c->operand[18] = 0x2; break; + case FEC_3_4: c->operand[18] = 0x3; break; + case FEC_5_6: c->operand[18] = 0x4; break; + case FEC_7_8: c->operand[18] = 0x5; break; + case FEC_8_9: c->operand[18] = 0x6; break; + case FEC_4_5: c->operand[18] = 0x8; break; + case FEC_AUTO: + default: c->operand[18] = 0x0; + } + + switch (params->u.qam.modulation) { + case QAM_16: c->operand[19] = 0x08; break; + case QAM_32: c->operand[19] = 0x10; break; + case QAM_64: c->operand[19] = 0x18; break; + case QAM_128: c->operand[19] = 0x20; break; + case QAM_256: c->operand[19] = 0x28; break; + case QAM_AUTO: + default: c->operand[19] = 0x00; + } + + c->operand[20] = 0x00; + c->operand[21] = 0x00; + /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ + c->operand[22] = 0x00; + + c->length = 28; +} + +static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params, + struct avc_command_frame *c) +{ + struct dvb_ofdm_parameters *ofdm = ¶ms->u.ofdm; + + c->opcode = AVC_OPCODE_DSD; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0x20; /* system id = DVB */ + c->operand[3] = 0x00; /* antenna number */ + c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */ + + /* multiplex_valid_flags, high byte */ + c->operand[5] = + 0 << 7 /* reserved */ + | 1 << 6 /* CenterFrequency */ + | (ofdm->bandwidth != BANDWIDTH_AUTO ? 1 << 5 : 0) + | (ofdm->constellation != QAM_AUTO ? 1 << 4 : 0) + | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0) + | (ofdm->code_rate_HP != FEC_AUTO ? 1 << 2 : 0) + | (ofdm->code_rate_LP != FEC_AUTO ? 1 << 1 : 0) + | (ofdm->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0); + + /* multiplex_valid_flags, low byte */ + c->operand[6] = + 0 << 7 /* NetworkID */ + | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0) + | 0 << 5 /* OtherFrequencyFlag */ + | 0 << 0 /* reserved */ ; + + c->operand[7] = 0x0; + c->operand[8] = (params->frequency / 10) >> 24; + c->operand[9] = ((params->frequency / 10) >> 16) & 0xff; + c->operand[10] = ((params->frequency / 10) >> 8) & 0xff; + c->operand[11] = (params->frequency / 10) & 0xff; + + switch (ofdm->bandwidth) { + case BANDWIDTH_7_MHZ: c->operand[12] = 0x20; break; + case BANDWIDTH_8_MHZ: + case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ + case BANDWIDTH_AUTO: + default: c->operand[12] = 0x00; + } + + switch (ofdm->constellation) { + case QAM_16: c->operand[13] = 1 << 6; break; + case QAM_64: c->operand[13] = 2 << 6; break; + case QPSK: + default: c->operand[13] = 0x00; + } + + switch (ofdm->hierarchy_information) { + case HIERARCHY_1: c->operand[13] |= 1 << 3; break; + case HIERARCHY_2: c->operand[13] |= 2 << 3; break; + case HIERARCHY_4: c->operand[13] |= 3 << 3; break; + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + default: break; + } + + switch (ofdm->code_rate_HP) { + case FEC_2_3: c->operand[13] |= 1; break; + case FEC_3_4: c->operand[13] |= 2; break; + case FEC_5_6: c->operand[13] |= 3; break; + case FEC_7_8: c->operand[13] |= 4; break; + case FEC_1_2: + default: break; + } + + switch (ofdm->code_rate_LP) { + case FEC_2_3: c->operand[14] = 1 << 5; break; + case FEC_3_4: c->operand[14] = 2 << 5; break; + case FEC_5_6: c->operand[14] = 3 << 5; break; + case FEC_7_8: c->operand[14] = 4 << 5; break; + case FEC_1_2: + default: c->operand[14] = 0x00; break; + } + + switch (ofdm->guard_interval) { + case GUARD_INTERVAL_1_16: c->operand[14] |= 1 << 3; break; + case GUARD_INTERVAL_1_8: c->operand[14] |= 2 << 3; break; + case GUARD_INTERVAL_1_4: c->operand[14] |= 3 << 3; break; + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + default: break; + } + + switch (ofdm->transmission_mode) { + case TRANSMISSION_MODE_8K: c->operand[14] |= 1 << 1; break; + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + default: break; + } + + c->operand[15] = 0x00; /* network_ID[0] */ + c->operand[16] = 0x00; /* network_ID[1] */ + /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ + c->operand[17] = 0x00; + + c->length = 24; +} + +int avc_tuner_dsd(struct firedtv *fdtv, + struct dvb_frontend_parameters *params) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + + switch (fdtv->type) { + case FIREDTV_DVB_S: + case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break; + case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(params, c); break; + case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(params, c); break; + default: + BUG(); + } + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + msleep(500); +#if 0 + /* FIXME: */ + /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */ + if (status) + *status = r->operand[2]; +#endif + return 0; +} + +int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + int pos, k; + + if (pidc > 16 && pidc != 0xff) + return -EINVAL; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_DSD; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0x20; /* system id = DVB */ + c->operand[3] = 0x00; /* antenna number */ + c->operand[4] = 0x00; /* system_specific_multiplex selection_length */ + c->operand[5] = pidc; /* Nr_of_dsd_sel_specs */ + + pos = 6; + if (pidc != 0xff) + for (k = 0; k < pidc; k++) { + c->operand[pos++] = 0x13; /* flowfunction relay */ + c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */ + c->operand[pos++] = (pid[k] >> 8) & 0x1f; + c->operand[pos++] = pid[k] & 0xff; + c->operand[pos++] = 0x00; /* tableID */ + c->operand[pos++] = 0x00; /* filter_length */ + } + + c->length = ALIGN(3 + pos, 4); + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + msleep(50); + return 0; +} + +int avc_tuner_get_ts(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + int sl; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_DSIT; + + sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0xff; /* status */ + c->operand[3] = 0x20; /* system id = DVB */ + c->operand[4] = 0x00; /* antenna number */ + c->operand[5] = 0x0; /* system_specific_search_flags */ + c->operand[6] = sl; /* system_specific_multiplex selection_length */ + c->operand[7] = 0x00; /* valid_flags [0] */ + c->operand[8] = 0x00; /* valid_flags [1] */ + c->operand[7 + sl] = 0x00; /* nr_of_dsit_sel_specs (always 0) */ + + c->length = fdtv->type == FIREDTV_DVB_T ? 24 : 28; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + msleep(250); + return 0; +} + +int avc_identify_subunit(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_READ_DESCRIPTOR; + + c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER; + c->operand[1] = 0xff; + c->operand[2] = 0x00; + c->operand[3] = 0x00; /* length highbyte */ + c->operand[4] = 0x08; /* length lowbyte */ + c->operand[5] = 0x00; /* offset highbyte */ + c->operand[6] = 0x0d; /* offset lowbyte */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + if ((r->response != AVC_RESPONSE_STABLE && + r->response != AVC_RESPONSE_ACCEPTED) || + (r->operand[3] << 8) + r->operand[4] != 8) { + dev_err(fdtv->device, "cannot read subunit identifier\n"); + return -EINVAL; + } + return 0; +} + +#define SIZEOF_ANTENNA_INPUT_INFO 22 + +int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int length; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_READ_DESCRIPTOR; + + c->operand[0] = DESCRIPTOR_TUNER_STATUS; + c->operand[1] = 0xff; /* read_result_status */ + c->operand[2] = 0x00; /* reserved */ + c->operand[3] = 0; /* SIZEOF_ANTENNA_INPUT_INFO >> 8; */ + c->operand[4] = 0; /* SIZEOF_ANTENNA_INPUT_INFO & 0xff; */ + c->operand[5] = 0x00; + c->operand[6] = 0x00; + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + if (r->response != AVC_RESPONSE_STABLE && + r->response != AVC_RESPONSE_ACCEPTED) { + dev_err(fdtv->device, "cannot read tuner status\n"); + return -EINVAL; + } + + length = r->operand[9]; + if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) { + dev_err(fdtv->device, "got invalid tuner status\n"); + return -EINVAL; + } + + stat->active_system = r->operand[10]; + stat->searching = r->operand[11] >> 7 & 1; + stat->moving = r->operand[11] >> 6 & 1; + stat->no_rf = r->operand[11] >> 5 & 1; + stat->input = r->operand[12] >> 7 & 1; + stat->selected_antenna = r->operand[12] & 0x7f; + stat->ber = r->operand[13] << 24 | + r->operand[14] << 16 | + r->operand[15] << 8 | + r->operand[16]; + stat->signal_strength = r->operand[17]; + stat->raster_frequency = r->operand[18] >> 6 & 2; + stat->rf_frequency = (r->operand[18] & 0x3f) << 16 | + r->operand[19] << 8 | + r->operand[20]; + stat->man_dep_info_length = r->operand[21]; + stat->front_end_error = r->operand[22] >> 4 & 1; + stat->antenna_error = r->operand[22] >> 3 & 1; + stat->front_end_power_status = r->operand[22] >> 1 & 1; + stat->power_supply = r->operand[22] & 1; + stat->carrier_noise_ratio = r->operand[23] << 8 | + r->operand[24]; + stat->power_supply_voltage = r->operand[27]; + stat->antenna_voltage = r->operand[28]; + stat->firewire_bus_voltage = r->operand[29]; + stat->ca_mmi = r->operand[30] & 1; + stat->ca_pmt_reply = r->operand[31] >> 7 & 1; + stat->ca_date_time_request = r->operand[31] >> 6 & 1; + stat->ca_application_info = r->operand[31] >> 5 & 1; + stat->ca_module_present_status = r->operand[31] >> 4 & 1; + stat->ca_dvb_flag = r->operand[31] >> 3 & 1; + stat->ca_error_flag = r->operand[31] >> 2 & 1; + stat->ca_initialization_status = r->operand[31] >> 1 & 1; + + return 0; +} + +int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int i, j, k; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL; + + c->operand[4] = voltage; + c->operand[5] = nrdiseq; + + i = 6; + + for (j = 0; j < nrdiseq; j++) { + c->operand[i++] = diseqcmd[j].msg_len; + + for (k = 0; k < diseqcmd[j].msg_len; k++) + c->operand[i++] = diseqcmd[j].msg[k]; + } + + c->operand[i++] = burst; + c->operand[i++] = conttone; + + c->length = ALIGN(3 + i, 4); + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + if (r->response != AVC_RESPONSE_ACCEPTED) { + dev_err(fdtv->device, "LNB control failed\n"); + return -EINVAL; + } + + return 0; +} + +int avc_register_remote_control(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_NOTIFY; + c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; + + c->length = 8; + + return avc_write(fdtv, c, NULL); +} + +void avc_remote_ctrl_work(struct work_struct *work) +{ + struct firedtv *fdtv = + container_of(work, struct firedtv, remote_ctrl_work); + + /* Should it be rescheduled in failure cases? */ + avc_register_remote_control(fdtv); +} + +#if 0 /* FIXME: unused */ +int avc_tuner_host2ca(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ + c->operand[6] = 0; /* more/last */ + c->operand[7] = 0; /* length */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + return 0; +} +#endif + +static int get_ca_object_pos(struct avc_response_frame *r) +{ + int length = 1; + + /* Check length of length field */ + if (r->operand[7] & 0x80) + length = (r->operand[7] & 0x7f) + 1; + return length + 7; +} + +static int get_ca_object_length(struct avc_response_frame *r) +{ +#if 0 /* FIXME: unused */ + int size = 0; + int i; + + if (r->operand[7] & 0x80) + for (i = 0; i < (r->operand[7] & 0x7f); i++) { + size <<= 8; + size += r->operand[8 + i]; + } +#endif + return r->operand[7]; +} + +int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int pos; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + /* FIXME: check response code and validate response data */ + + pos = get_ca_object_pos(r); + app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff; + app_info[1] = (EN50221_TAG_APP_INFO >> 8) & 0xff; + app_info[2] = (EN50221_TAG_APP_INFO >> 0) & 0xff; + app_info[3] = 6 + r->operand[pos + 4]; + app_info[4] = 0x01; + memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]); + *len = app_info[3] + 4; + + return 0; +} + +int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int pos; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + pos = get_ca_object_pos(r); + app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff; + app_info[1] = (EN50221_TAG_CA_INFO >> 8) & 0xff; + app_info[2] = (EN50221_TAG_CA_INFO >> 0) & 0xff; + app_info[3] = 2; + app_info[4] = r->operand[pos + 0]; + app_info[5] = r->operand[pos + 1]; + *len = app_info[3] + 4; + + return 0; +} + +int avc_ca_reset(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */ + c->operand[6] = 0; /* more/last */ + c->operand[7] = 1; /* length */ + c->operand[8] = 0; /* force hardware reset */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + return 0; +} + +int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int list_management; + int program_info_length; + int pmt_cmd_id; + int read_pos; + int write_pos; + int es_info_length; + int crc32_csum; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) { + dev_info(fdtv->device, "forcing list_management to ONLY\n"); + msg[0] = EN50221_LIST_MANAGEMENT_ONLY; + } + /* We take the cmd_id from the programme level only! */ + list_management = msg[0]; + program_info_length = ((msg[4] & 0x0f) << 8) + msg[5]; + if (program_info_length > 0) + program_info_length--; /* Remove pmt_cmd_id */ + pmt_cmd_id = msg[6]; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */ + c->operand[6] = 0; /* more/last */ + /* c->operand[7] = XXXprogram_info_length + 17; */ /* length */ + c->operand[8] = list_management; + c->operand[9] = 0x01; /* pmt_cmd=OK_descramble */ + + /* TS program map table */ + + c->operand[10] = 0x02; /* Table id=2 */ + c->operand[11] = 0x80; /* Section syntax + length */ + /* c->operand[12] = XXXprogram_info_length + 12; */ + c->operand[13] = msg[1]; /* Program number */ + c->operand[14] = msg[2]; + c->operand[15] = 0x01; /* Version number=0 + current/next=1 */ + c->operand[16] = 0x00; /* Section number=0 */ + c->operand[17] = 0x00; /* Last section number=0 */ + c->operand[18] = 0x1f; /* PCR_PID=1FFF */ + c->operand[19] = 0xff; + c->operand[20] = (program_info_length >> 8); /* Program info length */ + c->operand[21] = (program_info_length & 0xff); + + /* CA descriptors at programme level */ + read_pos = 6; + write_pos = 22; + if (program_info_length > 0) { + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(fdtv->device, + "invalid pmt_cmd_id %d\n", pmt_cmd_id); + + memcpy(&c->operand[write_pos], &msg[read_pos], + program_info_length); + read_pos += program_info_length; + write_pos += program_info_length; + } + while (read_pos < length) { + c->operand[write_pos++] = msg[read_pos++]; + c->operand[write_pos++] = msg[read_pos++]; + c->operand[write_pos++] = msg[read_pos++]; + es_info_length = + ((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1]; + read_pos += 2; + if (es_info_length > 0) + es_info_length--; /* Remove pmt_cmd_id */ + c->operand[write_pos++] = es_info_length >> 8; + c->operand[write_pos++] = es_info_length & 0xff; + if (es_info_length > 0) { + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(fdtv->device, "invalid pmt_cmd_id %d " + "at stream level\n", pmt_cmd_id); + + memcpy(&c->operand[write_pos], &msg[read_pos], + es_info_length); + read_pos += es_info_length; + write_pos += es_info_length; + } + } + + /* CRC */ + c->operand[write_pos++] = 0x00; + c->operand[write_pos++] = 0x00; + c->operand[write_pos++] = 0x00; + c->operand[write_pos++] = 0x00; + + c->operand[7] = write_pos - 8; + c->operand[12] = write_pos - 13; + + crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1); + c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff; + c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff; + c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff; + c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff; + + c->length = ALIGN(3 + write_pos, 4); + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + if (r->response != AVC_RESPONSE_ACCEPTED) { + dev_err(fdtv->device, + "CA PMT failed with response 0x%x\n", r->response); + return -EFAULT; + } + + return 0; +} + +int avc_ca_get_time_date(struct firedtv *fdtv, int *interval) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */ + c->operand[6] = 0; /* more/last */ + c->operand[7] = 0; /* length */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + /* FIXME: check response code and validate response data */ + + *interval = r->operand[get_ca_object_pos(r)]; + + return 0; +} + +int avc_ca_enter_menu(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; + c->operand[6] = 0; /* more/last */ + c->operand[7] = 0; /* length */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + return 0; +} + +int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_MMI; + c->operand[6] = 0; /* more/last */ + c->operand[7] = 0; /* length */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + /* FIXME: check response code and validate response data */ + + *len = get_ca_object_length(r); + memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len); + + return 0; +} + +#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL + +static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len) +{ + int ret; + + if (mutex_lock_interruptible(&fdtv->avc_mutex)) + return -EINTR; + + ret = fdtv->backend->read(fdtv, addr, buf, len); + if (ret < 0) + dev_err(fdtv->device, "CMP: read I/O error\n"); + + mutex_unlock(&fdtv->avc_mutex); + return ret; +} + +static int cmp_lock(struct firedtv *fdtv, void *data, u64 addr, __be32 arg) +{ + int ret; + + if (mutex_lock_interruptible(&fdtv->avc_mutex)) + return -EINTR; + + ret = fdtv->backend->lock(fdtv, addr, data, arg); + if (ret < 0) + dev_err(fdtv->device, "CMP: lock I/O error\n"); + + mutex_unlock(&fdtv->avc_mutex); + return ret; +} + +static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift) +{ + return (be32_to_cpu(opcr) >> shift) & mask; +} + +static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift) +{ + *opcr &= ~cpu_to_be32(mask << shift); + *opcr |= cpu_to_be32((value & mask) << shift); +} + +#define get_opcr_online(v) get_opcr((v), 0x1, 31) +#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24) +#define get_opcr_channel(v) get_opcr((v), 0x3f, 16) + +#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24) +#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16) +#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14) +#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10) + +int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel) +{ + __be32 old_opcr, opcr; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + int ret; + + ret = cmp_read(fdtv, &opcr, opcr_address, 4); + if (ret < 0) + return ret; + +repeat: + if (!get_opcr_online(opcr)) { + dev_err(fdtv->device, "CMP: output offline\n"); + return -EBUSY; + } + + old_opcr = opcr; + + if (get_opcr_p2p_connections(opcr)) { + if (get_opcr_channel(opcr) != channel) { + dev_err(fdtv->device, "CMP: cannot change channel\n"); + return -EBUSY; + } + dev_info(fdtv->device, "CMP: overlaying connection\n"); + + /* We don't allocate isochronous resources. */ + } else { + set_opcr_channel(&opcr, channel); + set_opcr_data_rate(&opcr, 2); /* S400 */ + + /* FIXME: this is for the worst case - optimize */ + set_opcr_overhead_id(&opcr, 0); + + /* + * FIXME: allocate isochronous channel and bandwidth at IRM + * fdtv->backend->alloc_resources(fdtv, channels_mask, bw); + */ + } + + set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1); + + ret = cmp_lock(fdtv, &opcr, opcr_address, old_opcr); + if (ret < 0) + return ret; + + if (old_opcr != opcr) { + /* + * FIXME: if old_opcr.P2P_Connections > 0, + * deallocate isochronous channel and bandwidth at IRM + * if (...) + * fdtv->backend->dealloc_resources(fdtv, channel, bw); + */ + + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + return -EBUSY; + } + + return 0; +} + +void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel) +{ + __be32 old_opcr, opcr; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + + if (cmp_read(fdtv, &opcr, opcr_address, 4) < 0) + return; + +repeat: + if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) || + get_opcr_channel(opcr) != channel) { + dev_err(fdtv->device, "CMP: no connection to break\n"); + return; + } + + old_opcr = opcr; + set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1); + + if (cmp_lock(fdtv, &opcr, opcr_address, old_opcr) < 0) + return; + + if (old_opcr != opcr) { + /* + * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last + * owner, deallocate isochronous channel and bandwidth at IRM + * if (...) + * fdtv->backend->dealloc_resources(fdtv, channel, bw); + */ + + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + } +} diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c new file mode 100644 index 000000000000..eeb80d0ea3ff --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-ci.c @@ -0,0 +1,260 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> + * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/device.h> +#include <linux/dvb/ca.h> +#include <linux/fs.h> +#include <linux/module.h> + +#include <dvbdev.h> + +#include "firedtv.h" + +#define EN50221_TAG_APP_INFO_ENQUIRY 0x9f8020 +#define EN50221_TAG_CA_INFO_ENQUIRY 0x9f8030 +#define EN50221_TAG_CA_PMT 0x9f8032 +#define EN50221_TAG_ENTER_MENU 0x9f8022 + +static int fdtv_ca_ready(struct firedtv_tuner_status *stat) +{ + return stat->ca_initialization_status == 1 && + stat->ca_error_flag == 0 && + stat->ca_dvb_flag == 1 && + stat->ca_module_present_status == 1; +} + +static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat) +{ + int flags = 0; + + if (stat->ca_module_present_status == 1) + flags |= CA_CI_MODULE_PRESENT; + if (stat->ca_initialization_status == 1 && + stat->ca_error_flag == 0 && + stat->ca_dvb_flag == 1) + flags |= CA_CI_MODULE_READY; + return flags; +} + +static int fdtv_ca_reset(struct firedtv *fdtv) +{ + return avc_ca_reset(fdtv) ? -EFAULT : 0; +} + +static int fdtv_ca_get_caps(void *arg) +{ + struct ca_caps *cap = arg; + + cap->slot_num = 1; + cap->slot_type = CA_CI; + cap->descr_num = 1; + cap->descr_type = CA_ECD; + return 0; +} + +static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg) +{ + struct firedtv_tuner_status stat; + struct ca_slot_info *slot = arg; + + if (avc_tuner_status(fdtv, &stat)) + return -EFAULT; + + if (slot->num != 0) + return -EFAULT; + + slot->type = CA_CI; + slot->flags = fdtv_get_ca_flags(&stat); + return 0; +} + +static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *reply = arg; + + return avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; +} + +static int fdtv_ca_info(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *reply = arg; + + return avc_ca_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; +} + +static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *reply = arg; + + return avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; +} + +static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg) +{ + struct firedtv_tuner_status stat; + int err; + + switch (fdtv->ca_last_command) { + case EN50221_TAG_APP_INFO_ENQUIRY: + err = fdtv_ca_app_info(fdtv, arg); + break; + case EN50221_TAG_CA_INFO_ENQUIRY: + err = fdtv_ca_info(fdtv, arg); + break; + default: + if (avc_tuner_status(fdtv, &stat)) + err = -EFAULT; + else if (stat.ca_mmi == 1) + err = fdtv_ca_get_mmi(fdtv, arg); + else { + dev_info(fdtv->device, "unhandled CA message 0x%08x\n", + fdtv->ca_last_command); + err = -EFAULT; + } + } + fdtv->ca_last_command = 0; + return err; +} + +static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *msg = arg; + int data_pos; + int data_length; + int i; + + data_pos = 4; + if (msg->msg[3] & 0x80) { + data_length = 0; + for (i = 0; i < (msg->msg[3] & 0x7f); i++) + data_length = (data_length << 8) + msg->msg[data_pos++]; + } else { + data_length = msg->msg[3]; + } + + return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? -EFAULT : 0; +} + +static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *msg = arg; + int err; + + /* Do we need a semaphore for this? */ + fdtv->ca_last_command = + (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2]; + switch (fdtv->ca_last_command) { + case EN50221_TAG_CA_PMT: + err = fdtv_ca_pmt(fdtv, arg); + break; + case EN50221_TAG_APP_INFO_ENQUIRY: + /* handled in ca_get_msg */ + err = 0; + break; + case EN50221_TAG_CA_INFO_ENQUIRY: + /* handled in ca_get_msg */ + err = 0; + break; + case EN50221_TAG_ENTER_MENU: + err = avc_ca_enter_menu(fdtv); + break; + default: + dev_err(fdtv->device, "unhandled CA message 0x%08x\n", + fdtv->ca_last_command); + err = -EFAULT; + } + return err; +} + +static int fdtv_ca_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct dvb_device *dvbdev = file->private_data; + struct firedtv *fdtv = dvbdev->priv; + struct firedtv_tuner_status stat; + int err; + + switch (cmd) { + case CA_RESET: + err = fdtv_ca_reset(fdtv); + break; + case CA_GET_CAP: + err = fdtv_ca_get_caps(arg); + break; + case CA_GET_SLOT_INFO: + err = fdtv_ca_get_slot_info(fdtv, arg); + break; + case CA_GET_MSG: + err = fdtv_ca_get_msg(fdtv, arg); + break; + case CA_SEND_MSG: + err = fdtv_ca_send_msg(fdtv, arg); + break; + default: + dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd); + err = -EOPNOTSUPP; + } + + /* FIXME Is this necessary? */ + avc_tuner_status(fdtv, &stat); + + return err; +} + +static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait) +{ + return POLLIN; +} + +static struct file_operations fdtv_ca_fops = { + .owner = THIS_MODULE, + .ioctl = dvb_generic_ioctl, + .open = dvb_generic_open, + .release = dvb_generic_release, + .poll = fdtv_ca_io_poll, +}; + +static struct dvb_device fdtv_ca = { + .users = 1, + .readers = 1, + .writers = 1, + .fops = &fdtv_ca_fops, + .kernel_ioctl = fdtv_ca_ioctl, +}; + +int fdtv_ca_register(struct firedtv *fdtv) +{ + struct firedtv_tuner_status stat; + int err; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + if (!fdtv_ca_ready(&stat)) + return -EFAULT; + + err = dvb_register_device(&fdtv->adapter, &fdtv->cadev, + &fdtv_ca, fdtv, DVB_DEVICE_CA); + + if (stat.ca_application_info == 0) + dev_err(fdtv->device, "CaApplicationInfo is not set\n"); + if (stat.ca_date_time_request == 1) + avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval); + + return err; +} + +void fdtv_ca_release(struct firedtv *fdtv) +{ + if (fdtv->cadev) + dvb_unregister_device(fdtv->cadev); +} diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c new file mode 100644 index 000000000000..9d308dd32a5c --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-dvb.c @@ -0,0 +1,364 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> + * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +#include <dmxdev.h> +#include <dvb_demux.h> +#include <dvbdev.h> +#include <dvb_frontend.h> + +#include "firedtv.h" + +static int alloc_channel(struct firedtv *fdtv) +{ + int i; + + for (i = 0; i < 16; i++) + if (!__test_and_set_bit(i, &fdtv->channel_active)) + break; + return i; +} + +static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[]) +{ + int i, n; + + for (i = 0, n = 0; i < 16; i++) + if (test_bit(i, &fdtv->channel_active)) + pid[n++] = fdtv->channel_pid[i]; + *pidc = n; +} + +static inline void dealloc_channel(struct firedtv *fdtv, int i) +{ + __clear_bit(i, &fdtv->channel_active); +} + +int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct firedtv *fdtv = dvbdmxfeed->demux->priv; + int pidc, c, ret; + u16 pids[16]; + + switch (dvbdmxfeed->type) { + case DMX_TYPE_TS: + case DMX_TYPE_SEC: + break; + default: + dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n", + dvbdmxfeed->type); + return -EINVAL; + } + + if (mutex_lock_interruptible(&fdtv->demux_mutex)) + return -EINTR; + + if (dvbdmxfeed->type == DMX_TYPE_TS) { + switch (dvbdmxfeed->pes_type) { + case DMX_TS_PES_VIDEO: + case DMX_TS_PES_AUDIO: + case DMX_TS_PES_TELETEXT: + case DMX_TS_PES_PCR: + case DMX_TS_PES_OTHER: + c = alloc_channel(fdtv); + break; + default: + dev_err(fdtv->device, + "can't start dmx feed: invalid pes type %u\n", + dvbdmxfeed->pes_type); + ret = -EINVAL; + goto out; + } + } else { + c = alloc_channel(fdtv); + } + + if (c > 15) { + dev_err(fdtv->device, "can't start dmx feed: busy\n"); + ret = -EBUSY; + goto out; + } + + dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c; + fdtv->channel_pid[c] = dvbdmxfeed->pid; + collect_channels(fdtv, &pidc, pids); + + if (dvbdmxfeed->pid == 8192) { + ret = avc_tuner_get_ts(fdtv); + if (ret) { + dealloc_channel(fdtv, c); + dev_err(fdtv->device, "can't get TS\n"); + goto out; + } + } else { + ret = avc_tuner_set_pids(fdtv, pidc, pids); + if (ret) { + dealloc_channel(fdtv, c); + dev_err(fdtv->device, "can't set PIDs\n"); + goto out; + } + } +out: + mutex_unlock(&fdtv->demux_mutex); + + return ret; +} + +int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *demux = dvbdmxfeed->demux; + struct firedtv *fdtv = demux->priv; + int pidc, c, ret; + u16 pids[16]; + + if (dvbdmxfeed->type == DMX_TYPE_TS && + !((dvbdmxfeed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE))) { + + if (dvbdmxfeed->ts_type & TS_DECODER) { + if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || + !demux->pesfilter[dvbdmxfeed->pes_type]) + return -EINVAL; + + demux->pids[dvbdmxfeed->pes_type] |= 0x8000; + demux->pesfilter[dvbdmxfeed->pes_type] = NULL; + } + + if (!(dvbdmxfeed->ts_type & TS_DECODER && + dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) + return 0; + } + + if (mutex_lock_interruptible(&fdtv->demux_mutex)) + return -EINTR; + + c = (unsigned long)dvbdmxfeed->priv; + dealloc_channel(fdtv, c); + collect_channels(fdtv, &pidc, pids); + + ret = avc_tuner_set_pids(fdtv, pidc, pids); + + mutex_unlock(&fdtv->demux_mutex); + + return ret; +} + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +int fdtv_dvb_register(struct firedtv *fdtv) +{ + int err; + + err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type], + THIS_MODULE, fdtv->device, adapter_nr); + if (err < 0) + goto fail_log; + + /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/ + fdtv->demux.dmx.capabilities = 0; + + fdtv->demux.priv = fdtv; + fdtv->demux.filternum = 16; + fdtv->demux.feednum = 16; + fdtv->demux.start_feed = fdtv_start_feed; + fdtv->demux.stop_feed = fdtv_stop_feed; + fdtv->demux.write_to_decoder = NULL; + + err = dvb_dmx_init(&fdtv->demux); + if (err) + goto fail_unreg_adapter; + + fdtv->dmxdev.filternum = 16; + fdtv->dmxdev.demux = &fdtv->demux.dmx; + fdtv->dmxdev.capabilities = 0; + + err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter); + if (err) + goto fail_dmx_release; + + fdtv->frontend.source = DMX_FRONTEND_0; + + err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend); + if (err) + goto fail_dmxdev_release; + + err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx, + &fdtv->frontend); + if (err) + goto fail_rem_frontend; + + dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); + + fdtv_frontend_init(fdtv); + err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe); + if (err) + goto fail_net_release; + + err = fdtv_ca_register(fdtv); + if (err) + dev_info(fdtv->device, + "Conditional Access Module not enabled\n"); + return 0; + +fail_net_release: + dvb_net_release(&fdtv->dvbnet); + fdtv->demux.dmx.close(&fdtv->demux.dmx); +fail_rem_frontend: + fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); +fail_dmxdev_release: + dvb_dmxdev_release(&fdtv->dmxdev); +fail_dmx_release: + dvb_dmx_release(&fdtv->demux); +fail_unreg_adapter: + dvb_unregister_adapter(&fdtv->adapter); +fail_log: + dev_err(fdtv->device, "DVB initialization failed\n"); + return err; +} + +void fdtv_dvb_unregister(struct firedtv *fdtv) +{ + fdtv_ca_release(fdtv); + dvb_unregister_frontend(&fdtv->fe); + dvb_net_release(&fdtv->dvbnet); + fdtv->demux.dmx.close(&fdtv->demux.dmx); + fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); + dvb_dmxdev_release(&fdtv->dmxdev); + dvb_dmx_release(&fdtv->demux); + dvb_unregister_adapter(&fdtv->adapter); +} + +const char *fdtv_model_names[] = { + [FIREDTV_UNKNOWN] = "unknown type", + [FIREDTV_DVB_S] = "FireDTV S/CI", + [FIREDTV_DVB_C] = "FireDTV C/CI", + [FIREDTV_DVB_T] = "FireDTV T/CI", + [FIREDTV_DVB_S2] = "FireDTV S2 ", +}; + +struct firedtv *fdtv_alloc(struct device *dev, + const struct firedtv_backend *backend, + const char *name, size_t name_len) +{ + struct firedtv *fdtv; + int i; + + fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); + if (!fdtv) + return NULL; + + dev->driver_data = fdtv; + fdtv->device = dev; + fdtv->isochannel = -1; + fdtv->voltage = 0xff; + fdtv->tone = 0xff; + fdtv->backend = backend; + + mutex_init(&fdtv->avc_mutex); + init_waitqueue_head(&fdtv->avc_wait); + fdtv->avc_reply_received = true; + mutex_init(&fdtv->demux_mutex); + INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); + + for (i = ARRAY_SIZE(fdtv_model_names); --i; ) + if (strlen(fdtv_model_names[i]) <= name_len && + strncmp(name, fdtv_model_names[i], name_len) == 0) + break; + fdtv->type = i; + + return fdtv; +} + +#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION) + +#define DIGITAL_EVERYWHERE_OUI 0x001287 +#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d +#define AVC_SW_VERSION_ENTRY 0x010001 + +static struct ieee1394_device_id fdtv_id_table[] = { + { + /* FloppyDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000024, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FloppyDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000025, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FloppyDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000026, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000034, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000035, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000036, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, {} +}; +MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); + +static int __init fdtv_init(void) +{ + return fdtv_1394_init(fdtv_id_table); +} + +static void __exit fdtv_exit(void) +{ + fdtv_1394_exit(); +} + +module_init(fdtv_init); +module_exit(fdtv_exit); + +MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>"); +MODULE_AUTHOR("Ben Backx <ben@bbackx.com>"); +MODULE_DESCRIPTION("FireDTV DVB Driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c new file mode 100644 index 000000000000..7ba43630a25d --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-fe.c @@ -0,0 +1,247 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> + * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <dvb_frontend.h> + +#include "firedtv.h" + +static int fdtv_dvb_init(struct dvb_frontend *fe) +{ + struct firedtv *fdtv = fe->sec_priv; + int err; + + /* FIXME - allocate free channel at IRM */ + fdtv->isochannel = fdtv->adapter.num; + + err = cmp_establish_pp_connection(fdtv, fdtv->subunit, + fdtv->isochannel); + if (err) { + dev_err(fdtv->device, + "could not establish point to point connection\n"); + return err; + } + + return fdtv->backend->start_iso(fdtv); +} + +static int fdtv_sleep(struct dvb_frontend *fe) +{ + struct firedtv *fdtv = fe->sec_priv; + + fdtv->backend->stop_iso(fdtv); + cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel); + fdtv->isochannel = -1; + return 0; +} + +#define LNBCONTROL_DONTCARE 0xff + +static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct firedtv *fdtv = fe->sec_priv; + + return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, + LNBCONTROL_DONTCARE, 1, cmd); +} + +static int fdtv_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t minicmd) +{ + return 0; +} + +static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct firedtv *fdtv = fe->sec_priv; + + fdtv->tone = tone; + return 0; +} + +static int fdtv_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct firedtv *fdtv = fe->sec_priv; + + fdtv->voltage = voltage; + return 0; +} + +static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct firedtv *fdtv = fe->sec_priv; + struct firedtv_tuner_status stat; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + if (stat.no_rf) + *status = 0; + else + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; +} + +static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct firedtv *fdtv = fe->sec_priv; + struct firedtv_tuner_status stat; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + *ber = stat.ber; + return 0; +} + +static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct firedtv *fdtv = fe->sec_priv; + struct firedtv_tuner_status stat; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + *strength = stat.signal_strength << 8; + return 0; +} + +static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct firedtv *fdtv = fe->sec_priv; + struct firedtv_tuner_status stat; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + /* C/N[dB] = -10 * log10(snr / 65535) */ + *snr = stat.carrier_noise_ratio * 257; + return 0; +} + +static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + return -EOPNOTSUPP; +} + +#define ACCEPTED 0x9 + +static int fdtv_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct firedtv *fdtv = fe->sec_priv; + + /* FIXME: avc_tuner_dsd never returns ACCEPTED. Check status? */ + if (avc_tuner_dsd(fdtv, params) != ACCEPTED) + return -EINVAL; + else + return 0; /* not sure of this... */ +} + +static int fdtv_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + return -EOPNOTSUPP; +} + +void fdtv_frontend_init(struct firedtv *fdtv) +{ + struct dvb_frontend_ops *ops = &fdtv->fe.ops; + struct dvb_frontend_info *fi = &ops->info; + + ops->init = fdtv_dvb_init; + ops->sleep = fdtv_sleep; + + ops->set_frontend = fdtv_set_frontend; + ops->get_frontend = fdtv_get_frontend; + + ops->read_status = fdtv_read_status; + ops->read_ber = fdtv_read_ber; + ops->read_signal_strength = fdtv_read_signal_strength; + ops->read_snr = fdtv_read_snr; + ops->read_ucblocks = fdtv_read_uncorrected_blocks; + + ops->diseqc_send_master_cmd = fdtv_diseqc_send_master_cmd; + ops->diseqc_send_burst = fdtv_diseqc_send_burst; + ops->set_tone = fdtv_set_tone; + ops->set_voltage = fdtv_set_voltage; + + switch (fdtv->type) { + case FIREDTV_DVB_S: + case FIREDTV_DVB_S2: + fi->type = FE_QPSK; + + fi->frequency_min = 950000; + fi->frequency_max = 2150000; + fi->frequency_stepsize = 125; + fi->symbol_rate_min = 1000000; + fi->symbol_rate_max = 40000000; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK; + break; + + case FIREDTV_DVB_C: + fi->type = FE_QAM; + + fi->frequency_min = 47000000; + fi->frequency_max = 866000000; + fi->frequency_stepsize = 62500; + fi->symbol_rate_min = 870000; + fi->symbol_rate_max = 6900000; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO; + break; + + case FIREDTV_DVB_T: + fi->type = FE_OFDM; + + fi->frequency_min = 49000000; + fi->frequency_max = 861000000; + fi->frequency_stepsize = 62500; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_2_3 | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO; + break; + + default: + dev_err(fdtv->device, "no frontend for model type %d\n", + fdtv->type); + } + strcpy(fi->name, fdtv_model_names[fdtv->type]); + + fdtv->fe.dvb = &fdtv->adapter; + fdtv->fe.sec_priv = fdtv; +} diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c new file mode 100644 index 000000000000..46a6324d7b73 --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-rc.c @@ -0,0 +1,190 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/bitops.h> +#include <linux/input.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/types.h> + +#include "firedtv.h" + +/* fixed table with older keycodes, geared towards MythTV */ +const static u16 oldtable[] = { + + /* code from device: 0x4501...0x451f */ + + KEY_ESC, + KEY_F9, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_I, + KEY_0, + KEY_ENTER, + KEY_RED, + KEY_UP, + KEY_GREEN, + KEY_F10, + KEY_SPACE, + KEY_F11, + KEY_YELLOW, + KEY_DOWN, + KEY_BLUE, + KEY_Z, + KEY_P, + KEY_PAGEDOWN, + KEY_LEFT, + KEY_W, + KEY_RIGHT, + KEY_P, + KEY_M, + + /* code from device: 0x4540...0x4542 */ + + KEY_R, + KEY_V, + KEY_C, +}; + +/* user-modifiable table for a remote as sold in 2008 */ +const static u16 keytable[] = { + + /* code from device: 0x0300...0x031f */ + + [0x00] = KEY_POWER, + [0x01] = KEY_SLEEP, + [0x02] = KEY_STOP, + [0x03] = KEY_OK, + [0x04] = KEY_RIGHT, + [0x05] = KEY_1, + [0x06] = KEY_2, + [0x07] = KEY_3, + [0x08] = KEY_LEFT, + [0x09] = KEY_4, + [0x0a] = KEY_5, + [0x0b] = KEY_6, + [0x0c] = KEY_UP, + [0x0d] = KEY_7, + [0x0e] = KEY_8, + [0x0f] = KEY_9, + [0x10] = KEY_DOWN, + [0x11] = KEY_TITLE, /* "OSD" - fixme */ + [0x12] = KEY_0, + [0x13] = KEY_F20, /* "16:9" - fixme */ + [0x14] = KEY_SCREEN, /* "FULL" - fixme */ + [0x15] = KEY_MUTE, + [0x16] = KEY_SUBTITLE, + [0x17] = KEY_RECORD, + [0x18] = KEY_TEXT, + [0x19] = KEY_AUDIO, + [0x1a] = KEY_RED, + [0x1b] = KEY_PREVIOUS, + [0x1c] = KEY_REWIND, + [0x1d] = KEY_PLAYPAUSE, + [0x1e] = KEY_NEXT, + [0x1f] = KEY_VOLUMEUP, + + /* code from device: 0x0340...0x0354 */ + + [0x20] = KEY_CHANNELUP, + [0x21] = KEY_F21, /* "4:3" - fixme */ + [0x22] = KEY_TV, + [0x23] = KEY_DVD, + [0x24] = KEY_VCR, + [0x25] = KEY_AUX, + [0x26] = KEY_GREEN, + [0x27] = KEY_YELLOW, + [0x28] = KEY_BLUE, + [0x29] = KEY_CHANNEL, /* "CH.LIST" */ + [0x2a] = KEY_VENDOR, /* "CI" - fixme */ + [0x2b] = KEY_VOLUMEDOWN, + [0x2c] = KEY_CHANNELDOWN, + [0x2d] = KEY_LAST, + [0x2e] = KEY_INFO, + [0x2f] = KEY_FORWARD, + [0x30] = KEY_LIST, + [0x31] = KEY_FAVORITES, + [0x32] = KEY_MENU, + [0x33] = KEY_EPG, + [0x34] = KEY_EXIT, +}; + +int fdtv_register_rc(struct firedtv *fdtv, struct device *dev) +{ + struct input_dev *idev; + int i, err; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; + + fdtv->remote_ctrl_dev = idev; + idev->name = "FireDTV remote control"; + idev->dev.parent = dev; + idev->evbit[0] = BIT_MASK(EV_KEY); + idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL); + if (!idev->keycode) { + err = -ENOMEM; + goto fail; + } + idev->keycodesize = sizeof(keytable[0]); + idev->keycodemax = ARRAY_SIZE(keytable); + + for (i = 0; i < ARRAY_SIZE(keytable); i++) + set_bit(keytable[i], idev->keybit); + + err = input_register_device(idev); + if (err) + goto fail_free_keymap; + + return 0; + +fail_free_keymap: + kfree(idev->keycode); +fail: + input_free_device(idev); + return err; +} + +void fdtv_unregister_rc(struct firedtv *fdtv) +{ + kfree(fdtv->remote_ctrl_dev->keycode); + input_unregister_device(fdtv->remote_ctrl_dev); +} + +void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) +{ + u16 *keycode = fdtv->remote_ctrl_dev->keycode; + + if (code >= 0x0300 && code <= 0x031f) + code = keycode[code - 0x0300]; + else if (code >= 0x0340 && code <= 0x0354) + code = keycode[code - 0x0320]; + else if (code >= 0x4501 && code <= 0x451f) + code = oldtable[code - 0x4501]; + else if (code >= 0x4540 && code <= 0x4542) + code = oldtable[code - 0x4521]; + else { + printk(KERN_DEBUG "firedtv: invalid key code 0x%04x " + "from remote control\n", code); + return; + } + + input_report_key(fdtv->remote_ctrl_dev, code, 1); + input_report_key(fdtv->remote_ctrl_dev, code, 0); +} diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h new file mode 100644 index 000000000000..d48530b81e61 --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv.h @@ -0,0 +1,182 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> + * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#ifndef _FIREDTV_H +#define _FIREDTV_H + +#include <linux/dvb/dmx.h> +#include <linux/dvb/frontend.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/spinlock_types.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +#include <demux.h> +#include <dmxdev.h> +#include <dvb_demux.h> +#include <dvb_frontend.h> +#include <dvb_net.h> +#include <dvbdev.h> + +struct firedtv_tuner_status { + unsigned active_system:8; + unsigned searching:1; + unsigned moving:1; + unsigned no_rf:1; + unsigned input:1; + unsigned selected_antenna:7; + unsigned ber:32; + unsigned signal_strength:8; + unsigned raster_frequency:2; + unsigned rf_frequency:22; + unsigned man_dep_info_length:8; + unsigned front_end_error:1; + unsigned antenna_error:1; + unsigned front_end_power_status:1; + unsigned power_supply:1; + unsigned carrier_noise_ratio:16; + unsigned power_supply_voltage:8; + unsigned antenna_voltage:8; + unsigned firewire_bus_voltage:8; + unsigned ca_mmi:1; + unsigned ca_pmt_reply:1; + unsigned ca_date_time_request:1; + unsigned ca_application_info:1; + unsigned ca_module_present_status:1; + unsigned ca_dvb_flag:1; + unsigned ca_error_flag:1; + unsigned ca_initialization_status:1; +}; + +enum model_type { + FIREDTV_UNKNOWN = 0, + FIREDTV_DVB_S = 1, + FIREDTV_DVB_C = 2, + FIREDTV_DVB_T = 3, + FIREDTV_DVB_S2 = 4, +}; + +struct device; +struct input_dev; +struct firedtv; + +struct firedtv_backend { + int (*lock)(struct firedtv *fdtv, u64 addr, void *data, __be32 arg); + int (*read)(struct firedtv *fdtv, u64 addr, void *data, size_t len); + int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len); + int (*start_iso)(struct firedtv *fdtv); + void (*stop_iso)(struct firedtv *fdtv); +}; + +struct firedtv { + struct device *device; + struct list_head list; + + struct dvb_adapter adapter; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dmx_frontend frontend; + struct dvb_net dvbnet; + struct dvb_frontend fe; + + struct dvb_device *cadev; + int ca_last_command; + int ca_time_interval; + + struct mutex avc_mutex; + wait_queue_head_t avc_wait; + bool avc_reply_received; + struct work_struct remote_ctrl_work; + struct input_dev *remote_ctrl_dev; + + enum model_type type; + char subunit; + char isochannel; + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; + + const struct firedtv_backend *backend; + void *backend_data; + + struct mutex demux_mutex; + unsigned long channel_active; + u16 channel_pid[16]; + + size_t response_length; + u8 response[512]; +}; + +/* firedtv-1394.c */ +#ifdef CONFIG_DVB_FIREDTV_IEEE1394 +int fdtv_1394_init(struct ieee1394_device_id id_table[]); +void fdtv_1394_exit(void); +#else +static inline int fdtv_1394_init(struct ieee1394_device_id it[]) { return 0; } +static inline void fdtv_1394_exit(void) {} +#endif + +/* firedtv-avc.c */ +int avc_recv(struct firedtv *fdtv, void *data, size_t length); +int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat); +struct dvb_frontend_parameters; +int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params); +int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]); +int avc_tuner_get_ts(struct firedtv *fdtv); +int avc_identify_subunit(struct firedtv *fdtv); +struct dvb_diseqc_master_cmd; +int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd); +void avc_remote_ctrl_work(struct work_struct *work); +int avc_register_remote_control(struct firedtv *fdtv); +int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len); +int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len); +int avc_ca_reset(struct firedtv *fdtv); +int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length); +int avc_ca_get_time_date(struct firedtv *fdtv, int *interval); +int avc_ca_enter_menu(struct firedtv *fdtv); +int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len); +int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel); +void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel); + +/* firedtv-ci.c */ +int fdtv_ca_register(struct firedtv *fdtv); +void fdtv_ca_release(struct firedtv *fdtv); + +/* firedtv-dvb.c */ +int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed); +int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed); +int fdtv_dvb_register(struct firedtv *fdtv); +void fdtv_dvb_unregister(struct firedtv *fdtv); +struct firedtv *fdtv_alloc(struct device *dev, + const struct firedtv_backend *backend, + const char *name, size_t name_len); +extern const char *fdtv_model_names[]; + +/* firedtv-fe.c */ +void fdtv_frontend_init(struct firedtv *fdtv); + +/* firedtv-rc.c */ +#ifdef CONFIG_DVB_FIREDTV_INPUT +int fdtv_register_rc(struct firedtv *fdtv, struct device *dev); +void fdtv_unregister_rc(struct firedtv *fdtv); +void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code); +#else +static inline int fdtv_register_rc(struct firedtv *fdtv, + struct device *dev) { return 0; } +static inline void fdtv_unregister_rc(struct firedtv *fdtv) {} +static inline void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) {} +#endif + +#endif /* _FIREDTV_H */ diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index 5d882a44e3ee..2ac738fa6a07 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -463,6 +463,8 @@ static int em28xx_audio_init(struct em28xx *dev) pcm->info_flags = 0; pcm->private_data = dev; strcpy(pcm->name, "Empia 28xx Capture"); + + snd_card_set_dev(card, &dev->udev->dev); strcpy(card->driver, "Empia Em28xx Audio"); strcpy(card->shortname, "Em28xx Audio"); strcpy(card->longname, "Empia Em28xx Audio"); diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index a1d6008efcbb..07c334f25aae 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -1155,23 +1155,23 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; - const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL; - const struct soc_camera_format_xlate *xlate; + const struct soc_camera_data_format *cam_fmt = NULL; + const struct soc_camera_format_xlate *xlate = NULL; struct soc_camera_sense sense = { .master_clock = pcdev->mclk, .pixel_clock_max = pcdev->ciclk / 4, }; - int ret, buswidth; + int ret; - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); - return -EINVAL; - } + if (pixfmt) { + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + return -EINVAL; + } - buswidth = xlate->buswidth; - host_fmt = xlate->host_fmt; - cam_fmt = xlate->cam_fmt; + cam_fmt = xlate->cam_fmt; + } /* If PCLK is used to latch data from the sensor, check sense */ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) @@ -1201,8 +1201,8 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, } if (pixfmt && !ret) { - icd->buswidth = buswidth; - icd->current_fmt = host_fmt; + icd->buswidth = xlate->buswidth; + icd->current_fmt = xlate->host_fmt; } return ret; diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 9a2586b07a05..ddcb81d0b81a 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -603,21 +603,18 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; int ret; + if (!pixfmt) + return icd->ops->set_fmt(icd, pixfmt, rect); + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { dev_warn(&ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } - switch (pixfmt) { - case 0: /* Only geometry change */ - ret = icd->ops->set_fmt(icd, pixfmt, rect); - break; - default: - ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect); - } + ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect); - if (pixfmt && !ret) { + if (!ret) { icd->buswidth = xlate->buswidth; icd->current_fmt = xlate->host_fmt; pcdev->camera_fmt = xlate->cam_fmt; diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index f26667a7abf7..cf991850f01b 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -710,6 +710,7 @@ out: static struct pci_device_id ilo_devices[] = { { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB204) }, + { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3307) }, { } }; MODULE_DEVICE_TABLE(pci, ilo_devices); @@ -758,7 +759,7 @@ static void __exit ilo_exit(void) class_destroy(ilo_class); } -MODULE_VERSION("0.06"); +MODULE_VERSION("1.0"); MODULE_ALIAS(ILO_NAME); MODULE_DESCRIPTION(ILO_NAME); MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>"); diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c index 821d0ed6bae3..c76d6e5f47ee 100644 --- a/drivers/mtd/chips/map_rom.c +++ b/drivers/mtd/chips/map_rom.c @@ -19,6 +19,7 @@ static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static void maprom_nop (struct mtd_info *); static struct mtd_info *map_rom_probe(struct map_info *map); +static int maprom_erase (struct mtd_info *mtd, struct erase_info *info); static struct mtd_chip_driver maprom_chipdrv = { .probe = map_rom_probe, @@ -42,6 +43,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map) mtd->read = maprom_read; mtd->write = maprom_write; mtd->sync = maprom_nop; + mtd->erase = maprom_erase; mtd->flags = MTD_CAP_ROM; mtd->erasesize = map->size; mtd->writesize = 1; @@ -71,6 +73,12 @@ static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *re return -EIO; } +static int maprom_erase (struct mtd_info *mtd, struct erase_info *info) +{ + /* We do our best 8) */ + return -EROFS; +} + static int __init map_rom_init(void) { register_mtd_chip_driver(&maprom_chipdrv); diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index a425d09f35a0..00248e81ecd5 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -267,22 +267,28 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) if (*(szlength) != '+') { devlength = simple_strtoul(szlength, &buffer, 0); devlength = handle_unit(devlength, buffer) - devstart; + if (devlength < devstart) + goto err_out; + + devlength -= devstart; } else { devlength = simple_strtoul(szlength + 1, &buffer, 0); devlength = handle_unit(devlength, buffer); } T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n", devname, devstart, devlength); - if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) { - E("slram: Illegal start / length parameter.\n"); - return(-EINVAL); - } + if (devlength % SLRAM_BLK_SZ != 0) + goto err_out; if ((devstart = register_device(devname, devstart, devlength))){ unregister_devices(); return((int)devstart); } return(0); + +err_out: + E("slram: Illegal length parameter.\n"); + return(-EINVAL); } #ifndef MODULE diff --git a/drivers/mtd/lpddr/Kconfig b/drivers/mtd/lpddr/Kconfig index acd4ea9b2278..5a401d8047ab 100644 --- a/drivers/mtd/lpddr/Kconfig +++ b/drivers/mtd/lpddr/Kconfig @@ -12,6 +12,7 @@ config MTD_LPDDR DDR memories, intended for battery-operated systems. config MTD_QINFO_PROBE + depends on MTD_LPDDR tristate "Detect flash chips by QINFO probe" help Device Information for LPDDR chips is offered through the Overlay diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 0225cbbf22de..043d50fb6ef6 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -491,7 +491,7 @@ config MTD_PCMCIA_ANONYMOUS config MTD_BFIN_ASYNC tristate "Blackfin BF533-STAMP Flash Chip Support" - depends on BFIN533_STAMP && MTD_CFI + depends on BFIN533_STAMP && MTD_CFI && MTD_COMPLEX_MAPPINGS select MTD_PARTITIONS default y help diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 6fec86aaed7e..576611f605db 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -152,14 +152,18 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev) if (gpio_request(state->enet_flash_pin, DRIVER_NAME)) { pr_devinit(KERN_ERR DRIVER_NAME ": Failed to request gpio %d\n", state->enet_flash_pin); + kfree(state); return -EBUSY; } gpio_direction_output(state->enet_flash_pin, 1); pr_devinit(KERN_NOTICE DRIVER_NAME ": probing %d-bit flash bus\n", state->map.bankwidth * 8); state->mtd = do_map_probe(memory->name, &state->map); - if (!state->mtd) + if (!state->mtd) { + gpio_free(state->enet_flash_pin); + kfree(state); return -ENXIO; + } #ifdef CONFIG_MTD_PARTITIONS ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0); diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 5f7a245ed132..424f17d6ffd1 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -342,9 +342,9 @@ static struct pci_device_id ck804xrom_pci_tbl[] = { { 0, } }; +#if 0 MODULE_DEVICE_TABLE(pci, ck804xrom_pci_tbl); -#if 0 static struct pci_driver ck804xrom_driver = { .name = MOD_NAME, .id_table = ck804xrom_pci_tbl, diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 87743661d48e..4b122e7ab4b3 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -29,6 +29,7 @@ struct physmap_flash_info { struct map_info map[MAX_RESOURCES]; #ifdef CONFIG_MTD_PARTITIONS int nr_parts; + struct mtd_partition *parts; #endif }; @@ -45,25 +46,26 @@ static int physmap_flash_remove(struct platform_device *dev) physmap_data = dev->dev.platform_data; -#ifdef CONFIG_MTD_CONCAT - if (info->cmtd != info->mtd[0]) { +#ifdef CONFIG_MTD_PARTITIONS + if (info->nr_parts) { + del_mtd_partitions(info->cmtd); + kfree(info->parts); + } else if (physmap_data->nr_parts) + del_mtd_partitions(info->cmtd); + else del_mtd_device(info->cmtd); +#else + del_mtd_device(info->cmtd); +#endif + +#ifdef CONFIG_MTD_CONCAT + if (info->cmtd != info->mtd[0]) mtd_concat_destroy(info->cmtd); - } #endif for (i = 0; i < MAX_RESOURCES; i++) { - if (info->mtd[i] != NULL) { -#ifdef CONFIG_MTD_PARTITIONS - if (info->nr_parts || physmap_data->nr_parts) - del_mtd_partitions(info->mtd[i]); - else - del_mtd_device(info->mtd[i]); -#else - del_mtd_device(info->mtd[i]); -#endif + if (info->mtd[i] != NULL) map_destroy(info->mtd[i]); - } } return 0; } @@ -86,9 +88,6 @@ static int physmap_flash_probe(struct platform_device *dev) int err = 0; int i; int devices_found = 0; -#ifdef CONFIG_MTD_PARTITIONS - struct mtd_partition *parts; -#endif physmap_data = dev->dev.platform_data; if (physmap_data == NULL) @@ -167,10 +166,11 @@ static int physmap_flash_probe(struct platform_device *dev) goto err_out; #ifdef CONFIG_MTD_PARTITIONS - err = parse_mtd_partitions(info->cmtd, part_probe_types, &parts, 0); + err = parse_mtd_partitions(info->cmtd, part_probe_types, + &info->parts, 0); if (err > 0) { - add_mtd_partitions(info->cmtd, parts, err); - kfree(parts); + add_mtd_partitions(info->cmtd, info->parts, err); + info->nr_parts = err; return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index b0ee86c62685..ab13ff22a8c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -148,7 +148,7 @@ static void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) pci_unmap_single(dev, pci_unmap_addr(&txq->cmd[index]->meta, mapping), pci_unmap_len(&txq->cmd[index]->meta, len), - PCI_DMA_TODEVICE); + PCI_DMA_BIDIRECTIONAL); /* Unmap chunks, if any. */ for (i = 1; i < num_tbs; i++) { @@ -964,7 +964,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) * within command buffer array. */ txcmd_phys = pci_map_single(priv->pci_dev, out_cmd, sizeof(struct iwl_cmd), - PCI_DMA_TODEVICE); + PCI_DMA_BIDIRECTIONAL); pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd)); /* Add buffer containing Tx command and MAC(!) header to TFD's @@ -1115,7 +1115,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd); phys_addr = pci_map_single(priv->pci_dev, out_cmd, - len, PCI_DMA_TODEVICE); + len, PCI_DMA_BIDIRECTIONAL); pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr); pci_unmap_len_set(&out_cmd->meta, len, len); phys_addr += offsetof(struct iwl_cmd, hdr); @@ -1212,7 +1212,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, pci_unmap_single(priv->pci_dev, pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping), pci_unmap_len(&txq->cmd[cmd_idx]->meta, len), - PCI_DMA_TODEVICE); + PCI_DMA_BIDIRECTIONAL); for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index f5a662a50acb..26c536b51c5a 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -330,6 +330,14 @@ parse_dmar_table(void) entry_header = (struct acpi_dmar_header *)(dmar + 1); while (((unsigned long)entry_header) < (((unsigned long)dmar) + dmar_tbl->length)) { + /* Avoid looping forever on bad ACPI tables */ + if (entry_header->length == 0) { + printk(KERN_WARNING PREFIX + "Invalid 0-length structure\n"); + ret = -EINVAL; + break; + } + dmar_table_print_dmar_entry(entry_header); switch (entry_header->type) { @@ -491,7 +499,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) int map_size; u32 ver; static int iommu_allocated = 0; - int agaw; + int agaw = 0; iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); if (!iommu) @@ -507,6 +515,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); +#ifdef CONFIG_DMAR agaw = iommu_calculate_agaw(iommu); if (agaw < 0) { printk(KERN_ERR @@ -514,6 +523,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) iommu->seq_id); goto error; } +#endif iommu->agaw = agaw; /* the registers might be more than one page */ @@ -571,19 +581,49 @@ static inline void reclaim_free_desc(struct q_inval *qi) } } +static int qi_check_fault(struct intel_iommu *iommu, int index) +{ + u32 fault; + int head; + struct q_inval *qi = iommu->qi; + int wait_index = (index + 1) % QI_LENGTH; + + fault = readl(iommu->reg + DMAR_FSTS_REG); + + /* + * If IQE happens, the head points to the descriptor associated + * with the error. No new descriptors are fetched until the IQE + * is cleared. + */ + if (fault & DMA_FSTS_IQE) { + head = readl(iommu->reg + DMAR_IQH_REG); + if ((head >> 4) == index) { + memcpy(&qi->desc[index], &qi->desc[wait_index], + sizeof(struct qi_desc)); + __iommu_flush_cache(iommu, &qi->desc[index], + sizeof(struct qi_desc)); + writel(DMA_FSTS_IQE, iommu->reg + DMAR_FSTS_REG); + return -EINVAL; + } + } + + return 0; +} + /* * Submit the queued invalidation descriptor to the remapping * hardware unit and wait for its completion. */ -void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) +int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) { + int rc = 0; struct q_inval *qi = iommu->qi; struct qi_desc *hw, wait_desc; int wait_index, index; unsigned long flags; if (!qi) - return; + return 0; hw = qi->desc; @@ -601,7 +641,8 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) hw[index] = *desc; - wait_desc.low = QI_IWD_STATUS_DATA(2) | QI_IWD_STATUS_WRITE | QI_IWD_TYPE; + wait_desc.low = QI_IWD_STATUS_DATA(QI_DONE) | + QI_IWD_STATUS_WRITE | QI_IWD_TYPE; wait_desc.high = virt_to_phys(&qi->desc_status[wait_index]); hw[wait_index] = wait_desc; @@ -612,13 +653,11 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) qi->free_head = (qi->free_head + 2) % QI_LENGTH; qi->free_cnt -= 2; - spin_lock(&iommu->register_lock); /* * update the HW tail register indicating the presence of * new descriptors. */ writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG); - spin_unlock(&iommu->register_lock); while (qi->desc_status[wait_index] != QI_DONE) { /* @@ -628,15 +667,21 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) * a deadlock where the interrupt context can wait indefinitely * for free slots in the queue. */ + rc = qi_check_fault(iommu, index); + if (rc) + goto out; + spin_unlock(&qi->q_lock); cpu_relax(); spin_lock(&qi->q_lock); } - - qi->desc_status[index] = QI_DONE; +out: + qi->desc_status[index] = qi->desc_status[wait_index] = QI_DONE; reclaim_free_desc(qi); spin_unlock_irqrestore(&qi->q_lock, flags); + + return rc; } /* @@ -649,13 +694,13 @@ void qi_global_iec(struct intel_iommu *iommu) desc.low = QI_IEC_TYPE; desc.high = 0; + /* should never fail */ qi_submit_sync(&desc, iommu); } int qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm, u64 type, int non_present_entry_flush) { - struct qi_desc desc; if (non_present_entry_flush) { @@ -669,10 +714,7 @@ int qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm, | QI_CC_GRAN(type) | QI_CC_TYPE; desc.high = 0; - qi_submit_sync(&desc, iommu); - - return 0; - + return qi_submit_sync(&desc, iommu); } int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, @@ -702,10 +744,7 @@ int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, desc.high = QI_IOTLB_ADDR(addr) | QI_IOTLB_IH(ih) | QI_IOTLB_AM(size_order); - qi_submit_sync(&desc, iommu); - - return 0; - + return qi_submit_sync(&desc, iommu); } /* diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index db85284ffb62..39ae37589fda 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -111,6 +111,7 @@ struct controller { int cmd_busy; unsigned int no_cmd_complete:1; unsigned int link_active_reporting:1; + unsigned int notification_enabled:1; }; #define INT_BUTTON_IGNORE 0 @@ -170,6 +171,7 @@ extern int pciehp_configure_device(struct slot *p_slot); extern int pciehp_unconfigure_device(struct slot *p_slot); extern void pciehp_queue_pushbutton_work(struct work_struct *work); struct controller *pcie_init(struct pcie_device *dev); +int pcie_init_notification(struct controller *ctrl); int pciehp_enable_slot(struct slot *p_slot); int pciehp_disable_slot(struct slot *p_slot); int pcie_enable_notification(struct controller *ctrl); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index c2485542f543..681e3912b821 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -434,6 +434,13 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ goto err_out_release_ctlr; } + /* Enable events after we have setup the data structures */ + rc = pcie_init_notification(ctrl); + if (rc) { + ctrl_err(ctrl, "Notification initialization failed\n"); + goto err_out_release_ctlr; + } + /* Check if slot is occupied */ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); t_slot->hpc_ops->get_adapter_status(t_slot, &value); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 71a8012886b0..7a16c6897bb9 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -934,7 +934,7 @@ static void pcie_disable_notification(struct controller *ctrl) ctrl_warn(ctrl, "Cannot disable software notification\n"); } -static int pcie_init_notification(struct controller *ctrl) +int pcie_init_notification(struct controller *ctrl) { if (pciehp_request_irq(ctrl)) return -1; @@ -942,13 +942,17 @@ static int pcie_init_notification(struct controller *ctrl) pciehp_free_irq(ctrl); return -1; } + ctrl->notification_enabled = 1; return 0; } static void pcie_shutdown_notification(struct controller *ctrl) { - pcie_disable_notification(ctrl); - pciehp_free_irq(ctrl); + if (ctrl->notification_enabled) { + pcie_disable_notification(ctrl); + pciehp_free_irq(ctrl); + ctrl->notification_enabled = 0; + } } static int pcie_init_slot(struct controller *ctrl) @@ -1110,13 +1114,8 @@ struct controller *pcie_init(struct pcie_device *dev) if (pcie_init_slot(ctrl)) goto abort_ctrl; - if (pcie_init_notification(ctrl)) - goto abort_slot; - return ctrl; -abort_slot: - pcie_cleanup_slot(ctrl); abort_ctrl: kfree(ctrl); abort: diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index f78371b22529..45effc5726c0 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -207,7 +207,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) return index; } -static void qi_flush_iec(struct intel_iommu *iommu, int index, int mask) +static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask) { struct qi_desc desc; @@ -215,7 +215,7 @@ static void qi_flush_iec(struct intel_iommu *iommu, int index, int mask) | QI_IEC_SELECTIVE; desc.high = 0; - qi_submit_sync(&desc, iommu); + return qi_submit_sync(&desc, iommu); } int map_irq_to_irte_handle(int irq, u16 *sub_handle) @@ -283,6 +283,7 @@ int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index) int modify_irte(int irq, struct irte *irte_modified) { + int rc; int index; struct irte *irte; struct intel_iommu *iommu; @@ -303,14 +304,15 @@ int modify_irte(int irq, struct irte *irte_modified) set_64bit((unsigned long *)irte, irte_modified->low | (1 << 1)); __iommu_flush_cache(iommu, irte, sizeof(*irte)); - qi_flush_iec(iommu, index, 0); - + rc = qi_flush_iec(iommu, index, 0); spin_unlock(&irq_2_ir_lock); - return 0; + + return rc; } int flush_irte(int irq) { + int rc; int index; struct intel_iommu *iommu; struct irq_2_iommu *irq_iommu; @@ -326,10 +328,10 @@ int flush_irte(int irq) index = irq_iommu->irte_index + irq_iommu->sub_handle; - qi_flush_iec(iommu, index, irq_iommu->irte_mask); + rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask); spin_unlock(&irq_2_ir_lock); - return 0; + return rc; } struct intel_iommu *map_ioapic_to_ir(int apic) @@ -355,6 +357,7 @@ struct intel_iommu *map_dev_to_ir(struct pci_dev *dev) int free_irte(int irq) { + int rc = 0; int index, i; struct irte *irte; struct intel_iommu *iommu; @@ -375,7 +378,7 @@ int free_irte(int irq) if (!irq_iommu->sub_handle) { for (i = 0; i < (1 << irq_iommu->irte_mask); i++) set_64bit((unsigned long *)irte, 0); - qi_flush_iec(iommu, index, irq_iommu->irte_mask); + rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask); } irq_iommu->iommu = NULL; @@ -385,7 +388,7 @@ int free_irte(int irq) spin_unlock(&irq_2_ir_lock); - return 0; + return rc; } static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index aac7006949f1..d0c973685868 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -108,6 +108,34 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev) } #endif /* 0 */ + +static void set_device_error_reporting(struct pci_dev *dev, void *data) +{ + bool enable = *((bool *)data); + + if (dev->pcie_type != PCIE_RC_PORT && + dev->pcie_type != PCIE_SW_UPSTREAM_PORT && + dev->pcie_type != PCIE_SW_DOWNSTREAM_PORT) + return; + + if (enable) + pci_enable_pcie_error_reporting(dev); + else + pci_disable_pcie_error_reporting(dev); +} + +/** + * set_downstream_devices_error_reporting - enable/disable the error reporting bits on the root port and its downstream ports. + * @dev: pointer to root port's pci_dev data structure + * @enable: true = enable error reporting, false = disable error reporting. + */ +static void set_downstream_devices_error_reporting(struct pci_dev *dev, + bool enable) +{ + set_device_error_reporting(dev, &enable); + pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable); +} + static int find_device_iter(struct device *device, void *data) { struct pci_dev *dev; @@ -525,15 +553,11 @@ void aer_enable_rootport(struct aer_rpc *rpc) pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, ®32); pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32); - /* Enable Root Port device reporting error itself */ - pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, ®16); - reg16 = reg16 | - PCI_EXP_DEVCTL_CERE | - PCI_EXP_DEVCTL_NFERE | - PCI_EXP_DEVCTL_FERE | - PCI_EXP_DEVCTL_URRE; - pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL, - reg16); + /* + * Enable error reporting for the root port device and downstream port + * devices. + */ + set_downstream_devices_error_reporting(pdev, true); /* Enable Root Port's interrupt in response to error messages */ pci_write_config_dword(pdev, @@ -553,6 +577,12 @@ static void disable_root_aer(struct aer_rpc *rpc) u32 reg32; int pos; + /* + * Disable error reporting for the root port device and downstream port + * devices. + */ + set_downstream_devices_error_reporting(pdev, false); + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); /* Disable Root's interrupt in response to error messages */ pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0); diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index f9b874eaeb9f..248b4db91552 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -97,8 +97,6 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, pcie_portdrv_save_config(dev); - pci_enable_pcie_error_reporting(dev); - return 0; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index baad093aafe3..f20d55368edb 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1584,6 +1584,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_ */ #define AMD_813X_MISC 0x40 #define AMD_813X_NOIOAMODE (1<<0) +#define AMD_813X_REV_B2 0x13 static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev) { @@ -1591,6 +1592,8 @@ static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev) if (noioapicquirk) return; + if (dev->revision == AMD_813X_REV_B2) + return; pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword); pci_config_dword &= ~AMD_813X_NOIOAMODE; @@ -1981,7 +1984,6 @@ static void __devinit quirk_msi_ht_cap(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE, quirk_msi_ht_cap); - /* The nVidia CK804 chipset may have 2 HT MSI mappings. * MSI are supported if the MSI capability set in any of these mappings. */ @@ -2032,6 +2034,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB, ht_enable_msi_mapping); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, + ht_enable_msi_mapping); + /* The P5N32-SLI Premium motherboard from Asus has a problem with msi * for the MCP55 NIC. It is not yet determined whether the msi problem * also affects other devices. As for now, turn off msi for this device. @@ -2048,10 +2053,100 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15, nvenet_msi_disable); -static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) +static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev) { struct pci_dev *host_bridge; + int pos; + int i, dev_no; + int found = 0; + + dev_no = dev->devfn >> 3; + for (i = dev_no; i >= 0; i--) { + host_bridge = pci_get_slot(dev->bus, PCI_DEVFN(i, 0)); + if (!host_bridge) + continue; + + pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE); + if (pos != 0) { + found = 1; + break; + } + pci_dev_put(host_bridge); + } + + if (!found) + return; + + /* root did that ! */ + if (msi_ht_cap_enabled(host_bridge)) + goto out; + + ht_enable_msi_mapping(dev); + +out: + pci_dev_put(host_bridge); +} + +static void __devinit ht_disable_msi_mapping(struct pci_dev *dev) +{ + int pos, ttl = 48; + + pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); + while (pos && ttl--) { + u8 flags; + + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, + &flags) == 0) { + dev_info(&dev->dev, "Enabling HT MSI Mapping\n"); + + pci_write_config_byte(dev, pos + HT_MSI_FLAGS, + flags & ~HT_MSI_FLAGS_ENABLE); + } + pos = pci_find_next_ht_capability(dev, pos, + HT_CAPTYPE_MSI_MAPPING); + } +} + +static int __devinit ht_check_msi_mapping(struct pci_dev *dev) +{ int pos, ttl = 48; + int found = 0; + + /* check if there is HT MSI cap or enabled on this device */ + pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); + while (pos && ttl--) { + u8 flags; + + if (found < 1) + found = 1; + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, + &flags) == 0) { + if (flags & HT_MSI_FLAGS_ENABLE) { + if (found < 2) { + found = 2; + break; + } + } + } + pos = pci_find_next_ht_capability(dev, pos, + HT_CAPTYPE_MSI_MAPPING); + } + + return found; +} + +static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) +{ + struct pci_dev *host_bridge; + int pos; + int found; + + /* check if there is HT MSI cap or enabled on this device */ + found = ht_check_msi_mapping(dev); + + /* no HT MSI CAP */ + if (found == 0) + return; /* * HT MSI mapping should be disabled on devices that are below @@ -2067,24 +2162,19 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE); if (pos != 0) { /* Host bridge is to HT */ - ht_enable_msi_mapping(dev); + if (found == 1) { + /* it is not enabled, try to enable it */ + nv_ht_enable_msi_mapping(dev); + } return; } - /* Host bridge is not to HT, disable HT MSI mapping on this device */ - pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); - while (pos && ttl--) { - u8 flags; + /* HT MSI is not enabled */ + if (found == 1) + return; - if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, - &flags) == 0) { - dev_info(&dev->dev, "Disabling HT MSI mapping"); - pci_write_config_byte(dev, pos + HT_MSI_FLAGS, - flags & ~HT_MSI_FLAGS_ENABLE); - } - pos = pci_find_next_ht_capability(dev, pos, - HT_CAPTYPE_MSI_MAPPING); - } + /* Host bridge is not to HT, disable HT MSI mapping on this device */ + ht_disable_msi_mapping(dev); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk); diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 3599828b9766..022e89ffec1d 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -133,7 +133,7 @@ # define SCSPTR3 0xffed0024 /* 16 bit SCIF */ # define SCSPTR4 0xffee0024 /* 16 bit SCIF */ # define SCSPTR5 0xffef0024 /* 16 bit SCIF */ -# define SCIF_OPER 0x0001 /* Overrun error bit */ +# define SCIF_ORER 0x0001 /* Overrun error bit */ # define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \ defined(CONFIG_CPU_SUBTYPE_SH7203) || \ diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index ab69c1bf36a8..c2747bc88c6f 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -2164,19 +2164,20 @@ static void __exit panel_cleanup_module(void) if (scan_timer.function != NULL) del_timer(&scan_timer); - if (keypad_enabled) - misc_deregister(&keypad_dev); + if (pprt != NULL) { + if (keypad_enabled) + misc_deregister(&keypad_dev); + + if (lcd_enabled) { + panel_lcd_print("\x0cLCD driver " PANEL_VERSION + "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-"); + misc_deregister(&lcd_dev); + } - if (lcd_enabled) { - panel_lcd_print("\x0cLCD driver " PANEL_VERSION - "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-"); - misc_deregister(&lcd_dev); + /* TODO: free all input signals */ + parport_release(pprt); + parport_unregister_device(pprt); } - - /* TODO: free all input signals */ - - parport_release(pprt); - parport_unregister_device(pprt); parport_unregister_driver(&panel_driver); } diff --git a/drivers/staging/rtl8187se/Kconfig b/drivers/staging/rtl8187se/Kconfig index 79c225acd1ad..f636296b54bc 100644 --- a/drivers/staging/rtl8187se/Kconfig +++ b/drivers/staging/rtl8187se/Kconfig @@ -1,5 +1,6 @@ config RTL8187SE tristate "RealTek RTL8187SE Wireless LAN NIC driver" depends on PCI + depends on WIRELESS_EXT && COMPAT_NET_DEV_OPS default N ---help--- diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c index af64cfbe16db..7370296225e1 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c @@ -234,20 +234,21 @@ out: void ieee80211_crypto_deinit(void) { struct list_head *ptr, *n; + struct ieee80211_crypto_alg *alg = NULL; if (hcrypt == NULL) return; - for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; - ptr = n, n = ptr->next) { - struct ieee80211_crypto_alg *alg = - (struct ieee80211_crypto_alg *) ptr; - list_del(ptr); - printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " - "'%s' (deinit)\n", alg->ops->name); - kfree(alg); + list_for_each_safe(ptr, n, &hcrypt->algs) { + alg = list_entry(ptr, struct ieee80211_crypto_alg, list); + if (alg) { + list_del(ptr); + printk(KERN_DEBUG + "ieee80211_crypt: unregistered algorithm '%s' (deinit)\n", + alg->ops->name); + kfree(alg); + } } - kfree(hcrypt); } diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index 94534955e38b..66de5cc8ddf1 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -6161,10 +6161,10 @@ static void __exit rtl8180_pci_module_exit(void) { pci_unregister_driver (&rtl8180_pci_driver); rtl8180_proc_module_remove(); - ieee80211_crypto_deinit(); ieee80211_crypto_tkip_exit(); ieee80211_crypto_ccmp_exit(); ieee80211_crypto_wep_exit(); + ieee80211_crypto_deinit(); DMESG("Exiting"); } diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index b003f9a7e151..f716b2e92b65 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -319,16 +319,18 @@ static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id struct usb_device *udev = interface_to_usbdev(intf); struct wbsoft_priv *priv; struct ieee80211_hw *dev; - int err; + int nr, err; usb_get_dev(udev); // 20060630.2 Check the device if it already be opened - err = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ), - 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, - 0x0, 0x400, <mp, 4, HZ*100 ); - if (err) + nr = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ), + 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, + 0x0, 0x400, <mp, 4, HZ*100 ); + if (nr < 0) { + err = nr; goto error; + } ltmp = cpu_to_le32(ltmp); if (ltmp) { // Is already initialized? @@ -337,8 +339,10 @@ static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id } dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops); - if (!dev) + if (!dev) { + err = -ENOMEM; goto error; + } priv = dev->priv; @@ -369,9 +373,11 @@ static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id } dev->extra_tx_headroom = 12; /* FIXME */ - dev->flags = 0; + dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; + dev->max_signal = 100; dev->queues = 1; dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &wbsoft_band_2GHz; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 326dd7f65ee9..b3d5a23ab56f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1376,6 +1376,15 @@ static struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, + { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ + }, + { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ + .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on + data interface instead of + communications interface. + Maybe we should define a new + quirk for this. */ + }, /* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 31fb204f44c6..49e7f56e0d7f 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -653,7 +653,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, if (result <= 0 && result != -ETIMEDOUT) continue; if (result > 1 && ((u8 *)buf)[1] != type) { - result = -EPROTO; + result = -ENODATA; continue; } break; @@ -696,8 +696,13 @@ static int usb_get_string(struct usb_device *dev, unsigned short langid, USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (USB_DT_STRING << 8) + index, langid, buf, size, USB_CTRL_GET_TIMEOUT); - if (!(result == 0 || result == -EPIPE)) - break; + if (result == 0 || result == -EPIPE) + continue; + if (result > 1 && ((u8 *) buf)[1] != USB_DT_STRING) { + result = -ENODATA; + continue; + } + break; } return result; } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3219d137340a..e55fef52a5dc 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -191,6 +191,7 @@ config USB_GADGET_OMAP boolean "OMAP USB Device Controller" depends on ARCH_OMAP select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG + select USB_OTG_UTILS if ARCH_OMAP help Many Texas Instruments OMAP processors have flexible full speed USB device controllers, with support for up to 30 diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index 80c2e7e9622f..38aa896cc5db 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -366,9 +366,9 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) f->hs_descriptors = usb_copy_descriptors(hs_function); obex->hs.obex_in = usb_find_endpoint(hs_function, - f->descriptors, &obex_hs_ep_in_desc); + f->hs_descriptors, &obex_hs_ep_in_desc); obex->hs.obex_out = usb_find_endpoint(hs_function, - f->descriptors, &obex_hs_ep_out_desc); + f->hs_descriptors, &obex_hs_ep_out_desc); } /* Avoid letting this gadget enumerate until the userspace diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index b10fa31cc915..1ab9dac7e12d 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3879,7 +3879,11 @@ static int __init check_parameters(struct fsg_dev *fsg) mod_data.protocol_type = USB_SC_SCSI; mod_data.protocol_name = "Transparent SCSI"; - if (gadget_is_sh(fsg->gadget)) + /* Some peripheral controllers are known not to be able to + * halt bulk endpoints correctly. If one of them is present, + * disable stalls. + */ + if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget)) mod_data.can_stall = 0; if (mod_data.release == 0xffff) { // Parameter wasn't set diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index f3c6703cffda..d8d9a52a44b3 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -404,7 +404,10 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num, } if (zlt) tmp |= EP_QUEUE_HEAD_ZLT_SEL; + p_QH->max_pkt_length = cpu_to_le32(tmp); + p_QH->next_dtd_ptr = 1; + p_QH->size_ioc_int_sts = 0; return; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 4725d15d096f..e551bb38852b 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -485,6 +485,7 @@ static int ehci_init(struct usb_hcd *hcd) * periodic_size can shrink by USBCMD update if hcc_params allows. */ ehci->periodic_size = DEFAULT_I_TDPS; + INIT_LIST_HEAD(&ehci->cached_itd_list); if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0) return retval; @@ -497,6 +498,7 @@ static int ehci_init(struct usb_hcd *hcd) ehci->reclaim = NULL; ehci->next_uframe = -1; + ehci->clock_frame = -1; /* * dedicate a qh for the async ring head, since we couldn't unlink diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 0431397836f6..10d52919abbb 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -128,6 +128,7 @@ static inline void qh_put (struct ehci_qh *qh) static void ehci_mem_cleanup (struct ehci_hcd *ehci) { + free_cached_itd_list(ehci); if (ehci->async) qh_put (ehci->async); ehci->async = NULL; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a081ee65bde6..07bcb931021b 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1004,7 +1004,8 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream) is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0; stream->bEndpointAddress &= 0x0f; - stream->ep->hcpriv = NULL; + if (stream->ep) + stream->ep->hcpriv = NULL; if (stream->rescheduled) { ehci_info (ehci, "ep%d%s-iso rescheduled " @@ -1653,14 +1654,28 @@ itd_complete ( (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); } iso_stream_put (ehci, stream); - /* OK to recycle this ITD now that its completion callback ran. */ + done: usb_put_urb(urb); itd->urb = NULL; - itd->stream = NULL; - list_move(&itd->itd_list, &stream->free_list); - iso_stream_put(ehci, stream); - + if (ehci->clock_frame != itd->frame || itd->index[7] != -1) { + /* OK to recycle this ITD now. */ + itd->stream = NULL; + list_move(&itd->itd_list, &stream->free_list); + iso_stream_put(ehci, stream); + } else { + /* HW might remember this ITD, so we can't recycle it yet. + * Move it to a safe place until a new frame starts. + */ + list_move(&itd->itd_list, &ehci->cached_itd_list); + if (stream->refcount == 2) { + /* If iso_stream_put() were called here, stream + * would be freed. Instead, just prevent reuse. + */ + stream->ep->hcpriv = NULL; + stream->ep = NULL; + } + } return retval; } @@ -2101,6 +2116,20 @@ done: /*-------------------------------------------------------------------------*/ +static void free_cached_itd_list(struct ehci_hcd *ehci) +{ + struct ehci_itd *itd, *n; + + list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) { + struct ehci_iso_stream *stream = itd->stream; + itd->stream = NULL; + list_move(&itd->itd_list, &stream->free_list); + iso_stream_put(ehci, stream); + } +} + +/*-------------------------------------------------------------------------*/ + static void scan_periodic (struct ehci_hcd *ehci) { @@ -2115,10 +2144,17 @@ scan_periodic (struct ehci_hcd *ehci) * Touches as few pages as possible: cache-friendly. */ now_uframe = ehci->next_uframe; - if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) + if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { clock = ehci_readl(ehci, &ehci->regs->frame_index); - else + clock_frame = (clock >> 3) % ehci->periodic_size; + } else { clock = now_uframe + mod - 1; + clock_frame = -1; + } + if (ehci->clock_frame != clock_frame) { + free_cached_itd_list(ehci); + ehci->clock_frame = clock_frame; + } clock %= mod; clock_frame = clock >> 3; @@ -2277,6 +2313,10 @@ restart: /* rescan the rest of this frame, then ... */ clock = now; clock_frame = clock >> 3; + if (ehci->clock_frame != clock_frame) { + free_cached_itd_list(ehci); + ehci->clock_frame = clock_frame; + } } else { now_uframe++; now_uframe %= mod; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index fb7054ccf4fc..262b00c9b334 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -87,6 +87,10 @@ struct ehci_hcd { /* one per controller */ int next_uframe; /* scan periodic, start here */ unsigned periodic_sched; /* periodic activity count */ + /* list of itds completed while clock_frame was still active */ + struct list_head cached_itd_list; + unsigned clock_frame; + /* per root hub port */ unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; @@ -220,6 +224,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) } } +static void free_cached_itd_list(struct ehci_hcd *ehci); + /*-------------------------------------------------------------------------*/ #include <linux/usb/ehci_def.h> diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 5a8fd5d57a11..2dc7606f319c 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -377,18 +377,8 @@ int __init musb_platform_init(struct musb *musb) u32 revision; musb->mregs += DAVINCI_BASE_OFFSET; -#if 0 - /* REVISIT there's something odd about clocking, this - * didn't appear do the job ... - */ - musb->clock = clk_get(pDevice, "usb"); - if (IS_ERR(musb->clock)) - return PTR_ERR(musb->clock); - status = clk_enable(musb->clock); - if (status < 0) - return -ENODEV; -#endif + clk_enable(musb->clock); /* returns zero if e.g. not clocked */ revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); @@ -453,5 +443,8 @@ int musb_platform_exit(struct musb *musb) } phy_off(); + + clk_disable(musb->clock); + return 0; } diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 2cc34fa05b73..af77e4659006 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -115,7 +115,7 @@ unsigned musb_debug; -module_param(musb_debug, uint, S_IRUGO | S_IWUSR); +module_param_named(debug, musb_debug, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug message level. Default = 0"); #define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia" @@ -767,6 +767,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb, #ifdef CONFIG_USB_MUSB_HDRC_HCD case OTG_STATE_A_HOST: case OTG_STATE_A_SUSPEND: + usb_hcd_resume_root_hub(musb_to_hcd(musb)); musb_root_disconnect(musb); if (musb->a_wait_bcon != 0) musb_platform_try_idle(musb, jiffies @@ -1815,7 +1816,7 @@ static void musb_free(struct musb *musb) #ifdef CONFIG_SYSFS device_remove_file(musb->controller, &dev_attr_mode); device_remove_file(musb->controller, &dev_attr_vbus); -#ifdef CONFIG_USB_MUSB_OTG +#ifdef CONFIG_USB_GADGET_MUSB_HDRC device_remove_file(musb->controller, &dev_attr_srp); #endif #endif @@ -2063,7 +2064,7 @@ fail2: #ifdef CONFIG_SYSFS device_remove_file(musb->controller, &dev_attr_mode); device_remove_file(musb->controller, &dev_attr_vbus); -#ifdef CONFIG_USB_MUSB_OTG +#ifdef CONFIG_USB_GADGET_MUSB_HDRC device_remove_file(musb->controller, &dev_attr_srp); #endif #endif @@ -2243,10 +2244,10 @@ static int __init musb_init(void) return platform_driver_probe(&musb_driver, musb_probe); } -/* make us init after usbcore and before usb - * gadget and host-side drivers start to register +/* make us init after usbcore and i2c (transceivers, regulators, etc) + * and before usb gadget and host-side drivers start to register */ -subsys_initcall(musb_init); +fs_initcall(musb_init); static void __exit musb_cleanup(void) { diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 4ea305387981..c7ebd0867fcc 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -575,7 +575,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) struct usb_request *request = &req->request; struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out; void __iomem *epio = musb->endpoints[epnum].regs; - u16 fifo_count = 0; + unsigned fifo_count = 0; u16 len = musb_ep->packet_sz; csr = musb_readw(epio, MUSB_RXCSR); @@ -687,7 +687,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) len, fifo_count, musb_ep->packet_sz); - fifo_count = min(len, fifo_count); + fifo_count = min_t(unsigned, len, fifo_count); #ifdef CONFIG_USB_TUSB_OMAP_DMA if (tusb_dma_omap() && musb_ep->dma) { diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index a035ceccf950..6dbbd0786a6a 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -335,16 +335,11 @@ musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb) static struct musb_qh * musb_giveback(struct musb_qh *qh, struct urb *urb, int status) { - int is_in; struct musb_hw_ep *ep = qh->hw_ep; struct musb *musb = ep->musb; + int is_in = usb_pipein(urb->pipe); int ready = qh->is_ready; - if (ep->is_shared_fifo) - is_in = 1; - else - is_in = usb_pipein(urb->pipe); - /* save toggle eagerly, for paranoia */ switch (qh->type) { case USB_ENDPOINT_XFER_BULK: @@ -432,7 +427,7 @@ musb_advance_schedule(struct musb *musb, struct urb *urb, else qh = musb_giveback(qh, urb, urb->status); - if (qh && qh->is_ready && !list_empty(&qh->hep->urb_list)) { + if (qh != NULL && qh->is_ready) { DBG(4, "... next ep%d %cX urb %p\n", hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh)); @@ -942,8 +937,8 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb) switch (musb->ep0_stage) { case MUSB_EP0_IN: fifo_dest = urb->transfer_buffer + urb->actual_length; - fifo_count = min(len, ((u16) (urb->transfer_buffer_length - - urb->actual_length))); + fifo_count = min_t(size_t, len, urb->transfer_buffer_length - + urb->actual_length); if (fifo_count < len) urb->status = -EOVERFLOW; @@ -976,10 +971,9 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb) } /* FALLTHROUGH */ case MUSB_EP0_OUT: - fifo_count = min(qh->maxpacket, ((u16) - (urb->transfer_buffer_length - - urb->actual_length))); - + fifo_count = min_t(size_t, qh->maxpacket, + urb->transfer_buffer_length - + urb->actual_length); if (fifo_count) { fifo_dest = (u8 *) (urb->transfer_buffer + urb->actual_length); @@ -1161,7 +1155,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) struct urb *urb; struct musb_hw_ep *hw_ep = musb->endpoints + epnum; void __iomem *epio = hw_ep->regs; - struct musb_qh *qh = hw_ep->out_qh; + struct musb_qh *qh = hw_ep->is_shared_fifo ? hw_ep->in_qh + : hw_ep->out_qh; u32 status = 0; void __iomem *mbase = musb->mregs; struct dma_channel *dma; @@ -1308,7 +1303,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) * packets before updating TXCSR ... other docs disagree ... */ /* PIO: start next packet in this URB */ - wLength = min(qh->maxpacket, (u16) wLength); + if (wLength > qh->maxpacket) + wLength = qh->maxpacket; musb_write_fifo(hw_ep, wLength, buf); qh->segsize = wLength; @@ -1867,19 +1863,21 @@ static int musb_urb_enqueue( } qh->type_reg = type_reg; - /* precompute rxinterval/txinterval register */ - interval = min((u8)16, epd->bInterval); /* log encoding */ + /* Precompute RXINTERVAL/TXINTERVAL register */ switch (qh->type) { case USB_ENDPOINT_XFER_INT: - /* fullspeed uses linear encoding */ - if (USB_SPEED_FULL == urb->dev->speed) { - interval = epd->bInterval; - if (!interval) - interval = 1; + /* + * Full/low speeds use the linear encoding, + * high speed uses the logarithmic encoding. + */ + if (urb->dev->speed <= USB_SPEED_FULL) { + interval = max_t(u8, epd->bInterval, 1); + break; } /* FALLTHROUGH */ case USB_ENDPOINT_XFER_ISOC: - /* iso always uses log encoding */ + /* ISO always uses logarithmic encoding */ + interval = min_t(u8, epd->bInterval, 16); break; default: /* REVISIT we actually want to use NAK limits, hinting to the @@ -2037,9 +2035,9 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) goto done; /* Any URB not actively programmed into endpoint hardware can be - * immediately given back. Such an URB must be at the head of its + * immediately given back; that's any URB not at the head of an * endpoint queue, unless someday we get real DMA queues. And even - * then, it might not be known to the hardware... + * if it's at the head, it might not be known to the hardware... * * Otherwise abort current transfer, pending dma, etc.; urb->status * has already been updated. This is a synchronous abort; it'd be @@ -2078,6 +2076,15 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) qh->is_ready = 0; __musb_giveback(musb, urb, 0); qh->is_ready = ready; + + /* If nothing else (usually musb_giveback) is using it + * and its URB list has emptied, recycle this qh. + */ + if (ready && list_empty(&qh->hep->urb_list)) { + qh->hep->hcpriv = NULL; + list_del(&qh->ring); + kfree(qh); + } } else ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); done: @@ -2093,15 +2100,16 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) unsigned long flags; struct musb *musb = hcd_to_musb(hcd); u8 is_in = epnum & USB_DIR_IN; - struct musb_qh *qh = hep->hcpriv; - struct urb *urb, *tmp; + struct musb_qh *qh; + struct urb *urb; struct list_head *sched; - if (!qh) - return; - spin_lock_irqsave(&musb->lock, flags); + qh = hep->hcpriv; + if (qh == NULL) + goto exit; + switch (qh->type) { case USB_ENDPOINT_XFER_CONTROL: sched = &musb->control; @@ -2135,13 +2143,28 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) /* cleanup */ musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); - } else - urb = NULL; - /* then just nuke all the others */ - list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list) - musb_giveback(qh, urb, -ESHUTDOWN); + /* Then nuke all the others ... and advance the + * queue on hw_ep (e.g. bulk ring) when we're done. + */ + while (!list_empty(&hep->urb_list)) { + urb = next_urb(qh); + urb->status = -ESHUTDOWN; + musb_advance_schedule(musb, urb, qh->hw_ep, is_in); + } + } else { + /* Just empty the queue; the hardware is busy with + * other transfers, and since !qh->is_ready nothing + * will activate any of these as it advances. + */ + while (!list_empty(&hep->urb_list)) + __musb_giveback(musb, next_urb(qh), -ESHUTDOWN); + hep->hcpriv = NULL; + list_del(&qh->ring); + kfree(qh); + } +exit: spin_unlock_irqrestore(&musb->lock, flags); } diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index bfd0b68ceccd..b7c132bded7f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -294,7 +294,11 @@ static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *po /* Ericsson products */ #define ERICSSON_VENDOR_ID 0x0bdb -#define ERICSSON_PRODUCT_F3507G 0x1900 +#define ERICSSON_PRODUCT_F3507G_1 0x1900 +#define ERICSSON_PRODUCT_F3507G_2 0x1902 + +#define BENQ_VENDOR_ID 0x04a5 +#define BENQ_PRODUCT_H10 0x4068 static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, @@ -509,7 +513,10 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) }, - { USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G) }, + { USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G_1) }, + { USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G_2) }, + { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, + { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 50dc33a6065b..6f59c8e510ea 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -907,13 +907,13 @@ UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff, "Genesys Logic", "USB to IDE Optical", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ), + US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ), UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, "Genesys Logic", "USB to IDE Disk", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ), + US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ), /* Reported by Ben Efros <ben@pc-doctor.com> */ UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451, diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 8d0b1fb1e52e..1f51366417b9 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -16,6 +16,12 @@ config W1_SLAVE_SMEM Say Y here if you want to connect 1-wire simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire. +config W1_SLAVE_DS2431 + tristate "1kb EEPROM family support (DS2431)" + help + Say Y here if you want to use a 1-wire + 1kb EEPROM family device (DS2431) + config W1_SLAVE_DS2433 tristate "4kb EEPROM family support (DS2433)" help diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index 990f400b6d22..f1f51f19b129 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o +obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index 858c16a544c2..139447148822 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c @@ -156,6 +156,9 @@ out_up: */ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data) { +#ifdef CONFIG_W1_SLAVE_DS2433_CRC + struct w1_f23_data *f23 = sl->family_data; +#endif u8 wrbuf[4]; u8 rdbuf[W1_PAGE_SIZE + 3]; u8 es = (addr + len - 1) & 0x1f; @@ -196,7 +199,9 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data) /* Reset the bus to wake up the EEPROM (this may not be needed) */ w1_reset_bus(sl->master); - +#ifdef CONFIG_W1_SLAVE_DS2433_CRC + f23->validcrc &= ~(1 << (addr >> W1_PAGE_BITS)); +#endif return 0; } @@ -302,7 +302,7 @@ void bio_init(struct bio *bio) struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs) { struct bio *bio = NULL; - void *p; + void *uninitialized_var(p); if (bs) { p = mempool_alloc(bs->bio_pool, gfp_mask); diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index a8c9693b75ac..72677ce2b74f 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -66,6 +66,9 @@ struct btrfs_inode { */ struct list_head delalloc_inodes; + /* the space_info for where this inode's data allocations are done */ + struct btrfs_space_info *space_info; + /* full 64 bit generation number, struct vfs_inode doesn't have a big * enough field for this. */ @@ -94,6 +97,11 @@ struct btrfs_inode { */ u64 delalloc_bytes; + /* total number of bytes that may be used for this inode for + * delalloc + */ + u64 reserved_bytes; + /* * the size of the file stored in the metadata on disk. data=ordered * means the in-memory i_size might be larger than the size on disk diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 766b31ae3186..82491ba8fa40 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -596,13 +596,27 @@ struct btrfs_block_group_item { struct btrfs_space_info { u64 flags; - u64 total_bytes; - u64 bytes_used; - u64 bytes_pinned; - u64 bytes_reserved; - u64 bytes_readonly; - int full; - int force_alloc; + + u64 total_bytes; /* total bytes in the space */ + u64 bytes_used; /* total bytes used on disk */ + u64 bytes_pinned; /* total bytes pinned, will be freed when the + transaction finishes */ + u64 bytes_reserved; /* total bytes the allocator has reserved for + current allocations */ + u64 bytes_readonly; /* total bytes that are read only */ + + /* delalloc accounting */ + u64 bytes_delalloc; /* number of bytes reserved for allocation, + this space is not necessarily reserved yet + by the allocator */ + u64 bytes_may_use; /* number of bytes that may be used for + delalloc */ + + int full; /* indicates that we cannot allocate any more + chunks for this space */ + int force_alloc; /* set if we need to force a chunk alloc for + this space */ + struct list_head list; /* for block groups in our same type */ @@ -1782,6 +1796,16 @@ int btrfs_add_dead_reloc_root(struct btrfs_root *root); int btrfs_cleanup_reloc_trees(struct btrfs_root *root); int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len); u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags); +void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde); +int btrfs_check_metadata_free_space(struct btrfs_root *root); +int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode, + u64 bytes); +void btrfs_free_reserved_data_space(struct btrfs_root *root, + struct inode *inode, u64 bytes); +void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode, + u64 bytes); +void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode, + u64 bytes); /* ctree.c */ int btrfs_previous_item(struct btrfs_root *root, struct btrfs_path *path, u64 min_objectid, @@ -2027,8 +2051,6 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, unsigned long btrfs_force_ra(struct address_space *mapping, struct file_ra_state *ra, struct file *file, pgoff_t offset, pgoff_t last_index); -int btrfs_check_free_space(struct btrfs_root *root, u64 num_required, - int for_del); int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page); int btrfs_readpage(struct file *file, struct page *page); void btrfs_delete_inode(struct inode *inode); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0a5d796c9f7e..6b5966aacf44 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -60,6 +60,10 @@ static int update_block_group(struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, int alloc, int mark_free); +static int do_chunk_alloc(struct btrfs_trans_handle *trans, + struct btrfs_root *extent_root, u64 alloc_bytes, + u64 flags, int force); + static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) { return (cache->flags & bits) == bits; @@ -1909,6 +1913,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, found->bytes_pinned = 0; found->bytes_reserved = 0; found->bytes_readonly = 0; + found->bytes_delalloc = 0; found->full = 0; found->force_alloc = 0; *space_info = found; @@ -1972,6 +1977,233 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) return flags; } +static u64 btrfs_get_alloc_profile(struct btrfs_root *root, u64 data) +{ + struct btrfs_fs_info *info = root->fs_info; + u64 alloc_profile; + + if (data) { + alloc_profile = info->avail_data_alloc_bits & + info->data_alloc_profile; + data = BTRFS_BLOCK_GROUP_DATA | alloc_profile; + } else if (root == root->fs_info->chunk_root) { + alloc_profile = info->avail_system_alloc_bits & + info->system_alloc_profile; + data = BTRFS_BLOCK_GROUP_SYSTEM | alloc_profile; + } else { + alloc_profile = info->avail_metadata_alloc_bits & + info->metadata_alloc_profile; + data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile; + } + + return btrfs_reduce_alloc_profile(root, data); +} + +void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *inode) +{ + u64 alloc_target; + + alloc_target = btrfs_get_alloc_profile(root, 1); + BTRFS_I(inode)->space_info = __find_space_info(root->fs_info, + alloc_target); +} + +/* + * for now this just makes sure we have at least 5% of our metadata space free + * for use. + */ +int btrfs_check_metadata_free_space(struct btrfs_root *root) +{ + struct btrfs_fs_info *info = root->fs_info; + struct btrfs_space_info *meta_sinfo; + u64 alloc_target, thresh; + int committed = 0, ret; + + /* get the space info for where the metadata will live */ + alloc_target = btrfs_get_alloc_profile(root, 0); + meta_sinfo = __find_space_info(info, alloc_target); + +again: + spin_lock(&meta_sinfo->lock); + if (!meta_sinfo->full) + thresh = meta_sinfo->total_bytes * 80; + else + thresh = meta_sinfo->total_bytes * 95; + + do_div(thresh, 100); + + if (meta_sinfo->bytes_used + meta_sinfo->bytes_reserved + + meta_sinfo->bytes_pinned + meta_sinfo->bytes_readonly > thresh) { + struct btrfs_trans_handle *trans; + if (!meta_sinfo->full) { + meta_sinfo->force_alloc = 1; + spin_unlock(&meta_sinfo->lock); + + trans = btrfs_start_transaction(root, 1); + if (!trans) + return -ENOMEM; + + ret = do_chunk_alloc(trans, root->fs_info->extent_root, + 2 * 1024 * 1024, alloc_target, 0); + btrfs_end_transaction(trans, root); + goto again; + } + spin_unlock(&meta_sinfo->lock); + + if (!committed) { + committed = 1; + trans = btrfs_join_transaction(root, 1); + if (!trans) + return -ENOMEM; + ret = btrfs_commit_transaction(trans, root); + if (ret) + return ret; + goto again; + } + return -ENOSPC; + } + spin_unlock(&meta_sinfo->lock); + + return 0; +} + +/* + * This will check the space that the inode allocates from to make sure we have + * enough space for bytes. + */ +int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode, + u64 bytes) +{ + struct btrfs_space_info *data_sinfo; + int ret = 0, committed = 0; + + /* make sure bytes are sectorsize aligned */ + bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); + + data_sinfo = BTRFS_I(inode)->space_info; +again: + /* make sure we have enough space to handle the data first */ + spin_lock(&data_sinfo->lock); + if (data_sinfo->total_bytes - data_sinfo->bytes_used - + data_sinfo->bytes_delalloc - data_sinfo->bytes_reserved - + data_sinfo->bytes_pinned - data_sinfo->bytes_readonly - + data_sinfo->bytes_may_use < bytes) { + struct btrfs_trans_handle *trans; + + /* + * if we don't have enough free bytes in this space then we need + * to alloc a new chunk. + */ + if (!data_sinfo->full) { + u64 alloc_target; + + data_sinfo->force_alloc = 1; + spin_unlock(&data_sinfo->lock); + + alloc_target = btrfs_get_alloc_profile(root, 1); + trans = btrfs_start_transaction(root, 1); + if (!trans) + return -ENOMEM; + + ret = do_chunk_alloc(trans, root->fs_info->extent_root, + bytes + 2 * 1024 * 1024, + alloc_target, 0); + btrfs_end_transaction(trans, root); + if (ret) + return ret; + goto again; + } + spin_unlock(&data_sinfo->lock); + + /* commit the current transaction and try again */ + if (!committed) { + committed = 1; + trans = btrfs_join_transaction(root, 1); + if (!trans) + return -ENOMEM; + ret = btrfs_commit_transaction(trans, root); + if (ret) + return ret; + goto again; + } + + printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes" + ", %llu bytes_used, %llu bytes_reserved, " + "%llu bytes_pinned, %llu bytes_readonly, %llu may use" + "%llu total\n", bytes, data_sinfo->bytes_delalloc, + data_sinfo->bytes_used, data_sinfo->bytes_reserved, + data_sinfo->bytes_pinned, data_sinfo->bytes_readonly, + data_sinfo->bytes_may_use, data_sinfo->total_bytes); + return -ENOSPC; + } + data_sinfo->bytes_may_use += bytes; + BTRFS_I(inode)->reserved_bytes += bytes; + spin_unlock(&data_sinfo->lock); + + return btrfs_check_metadata_free_space(root); +} + +/* + * if there was an error for whatever reason after calling + * btrfs_check_data_free_space, call this so we can cleanup the counters. + */ +void btrfs_free_reserved_data_space(struct btrfs_root *root, + struct inode *inode, u64 bytes) +{ + struct btrfs_space_info *data_sinfo; + + /* make sure bytes are sectorsize aligned */ + bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); + + data_sinfo = BTRFS_I(inode)->space_info; + spin_lock(&data_sinfo->lock); + data_sinfo->bytes_may_use -= bytes; + BTRFS_I(inode)->reserved_bytes -= bytes; + spin_unlock(&data_sinfo->lock); +} + +/* called when we are adding a delalloc extent to the inode's io_tree */ +void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode, + u64 bytes) +{ + struct btrfs_space_info *data_sinfo; + + /* get the space info for where this inode will be storing its data */ + data_sinfo = BTRFS_I(inode)->space_info; + + /* make sure we have enough space to handle the data first */ + spin_lock(&data_sinfo->lock); + data_sinfo->bytes_delalloc += bytes; + + /* + * we are adding a delalloc extent without calling + * btrfs_check_data_free_space first. This happens on a weird + * writepage condition, but shouldn't hurt our accounting + */ + if (unlikely(bytes > BTRFS_I(inode)->reserved_bytes)) { + data_sinfo->bytes_may_use -= BTRFS_I(inode)->reserved_bytes; + BTRFS_I(inode)->reserved_bytes = 0; + } else { + data_sinfo->bytes_may_use -= bytes; + BTRFS_I(inode)->reserved_bytes -= bytes; + } + + spin_unlock(&data_sinfo->lock); +} + +/* called when we are clearing an delalloc extent from the inode's io_tree */ +void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode, + u64 bytes) +{ + struct btrfs_space_info *info; + + info = BTRFS_I(inode)->space_info; + + spin_lock(&info->lock); + info->bytes_delalloc -= bytes; + spin_unlock(&info->lock); +} + static int do_chunk_alloc(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root, u64 alloc_bytes, u64 flags, int force) @@ -3105,6 +3337,10 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes) (unsigned long long)(info->total_bytes - info->bytes_used - info->bytes_pinned - info->bytes_reserved), (info->full) ? "" : "not "); + printk(KERN_INFO "space_info total=%llu, pinned=%llu, delalloc=%llu," + " may_use=%llu, used=%llu\n", info->total_bytes, + info->bytes_pinned, info->bytes_delalloc, info->bytes_may_use, + info->bytes_used); down_read(&info->groups_sem); list_for_each_entry(cache, &info->block_groups, list) { @@ -3131,24 +3367,10 @@ static int __btrfs_reserve_extent(struct btrfs_trans_handle *trans, { int ret; u64 search_start = 0; - u64 alloc_profile; struct btrfs_fs_info *info = root->fs_info; - if (data) { - alloc_profile = info->avail_data_alloc_bits & - info->data_alloc_profile; - data = BTRFS_BLOCK_GROUP_DATA | alloc_profile; - } else if (root == root->fs_info->chunk_root) { - alloc_profile = info->avail_system_alloc_bits & - info->system_alloc_profile; - data = BTRFS_BLOCK_GROUP_SYSTEM | alloc_profile; - } else { - alloc_profile = info->avail_metadata_alloc_bits & - info->metadata_alloc_profile; - data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile; - } + data = btrfs_get_alloc_profile(root, data); again: - data = btrfs_reduce_alloc_profile(root, data); /* * the only place that sets empty_size is btrfs_realloc_node, which * is not called recursively on allocations diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 872f104576e5..dc78954861b3 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1091,19 +1091,24 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, WARN_ON(num_pages > nrptrs); memset(pages, 0, sizeof(struct page *) * nrptrs); - ret = btrfs_check_free_space(root, write_bytes, 0); + ret = btrfs_check_data_free_space(root, inode, write_bytes); if (ret) goto out; ret = prepare_pages(root, file, pages, num_pages, pos, first_index, last_index, write_bytes); - if (ret) + if (ret) { + btrfs_free_reserved_data_space(root, inode, + write_bytes); goto out; + } ret = btrfs_copy_from_user(pos, num_pages, write_bytes, pages, buf); if (ret) { + btrfs_free_reserved_data_space(root, inode, + write_bytes); btrfs_drop_pages(pages, num_pages); goto out; } @@ -1111,8 +1116,11 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, ret = dirty_and_release_pages(NULL, root, file, pages, num_pages, pos, write_bytes); btrfs_drop_pages(pages, num_pages); - if (ret) + if (ret) { + btrfs_free_reserved_data_space(root, inode, + write_bytes); goto out; + } if (will_write) { btrfs_fdatawrite_range(inode->i_mapping, pos, @@ -1136,6 +1144,8 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, } out: mutex_unlock(&inode->i_mutex); + if (ret) + err = ret; out_nolock: kfree(pages); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3cee77ae03c8..7d4f948bc22a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -102,34 +102,6 @@ static int btrfs_init_inode_security(struct inode *inode, struct inode *dir) } /* - * a very lame attempt at stopping writes when the FS is 85% full. There - * are countless ways this is incorrect, but it is better than nothing. - */ -int btrfs_check_free_space(struct btrfs_root *root, u64 num_required, - int for_del) -{ - u64 total; - u64 used; - u64 thresh; - int ret = 0; - - spin_lock(&root->fs_info->delalloc_lock); - total = btrfs_super_total_bytes(&root->fs_info->super_copy); - used = btrfs_super_bytes_used(&root->fs_info->super_copy); - if (for_del) - thresh = total * 90; - else - thresh = total * 85; - - do_div(thresh, 100); - - if (used + root->fs_info->delalloc_bytes + num_required > thresh) - ret = -ENOSPC; - spin_unlock(&root->fs_info->delalloc_lock); - return ret; -} - -/* * this does all the hard work for inserting an inline extent into * the btree. The caller should have done a btrfs_drop_extents so that * no overlapping inline items exist in the btree @@ -1190,6 +1162,7 @@ static int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end, */ if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) { struct btrfs_root *root = BTRFS_I(inode)->root; + btrfs_delalloc_reserve_space(root, inode, end - start + 1); spin_lock(&root->fs_info->delalloc_lock); BTRFS_I(inode)->delalloc_bytes += end - start + 1; root->fs_info->delalloc_bytes += end - start + 1; @@ -1223,9 +1196,12 @@ static int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end, (unsigned long long)end - start + 1, (unsigned long long) root->fs_info->delalloc_bytes); + btrfs_delalloc_free_space(root, inode, (u64)-1); root->fs_info->delalloc_bytes = 0; BTRFS_I(inode)->delalloc_bytes = 0; } else { + btrfs_delalloc_free_space(root, inode, + end - start + 1); root->fs_info->delalloc_bytes -= end - start + 1; BTRFS_I(inode)->delalloc_bytes -= end - start + 1; } @@ -2245,10 +2221,6 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) root = BTRFS_I(dir)->root; - ret = btrfs_check_free_space(root, 1, 1); - if (ret) - goto fail; - trans = btrfs_start_transaction(root, 1); btrfs_set_trans_block_group(trans, dir); @@ -2261,7 +2233,6 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) nr = trans->blocks_used; btrfs_end_transaction_throttle(trans, root); -fail: btrfs_btree_balance_dirty(root, nr); return ret; } @@ -2284,10 +2255,6 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) return -ENOTEMPTY; } - ret = btrfs_check_free_space(root, 1, 1); - if (ret) - goto fail; - trans = btrfs_start_transaction(root, 1); btrfs_set_trans_block_group(trans, dir); @@ -2304,7 +2271,6 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) fail_trans: nr = trans->blocks_used; ret = btrfs_end_transaction_throttle(trans, root); -fail: btrfs_btree_balance_dirty(root, nr); if (ret && !err) @@ -2818,7 +2784,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size) if (size <= hole_start) return 0; - err = btrfs_check_free_space(root, 1, 0); + err = btrfs_check_metadata_free_space(root); if (err) return err; @@ -3014,6 +2980,7 @@ static noinline void init_btrfs_i(struct inode *inode) bi->last_trans = 0; bi->logged_trans = 0; bi->delalloc_bytes = 0; + bi->reserved_bytes = 0; bi->disk_i_size = 0; bi->flags = 0; bi->index_cnt = (u64)-1; @@ -3035,6 +3002,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p) inode->i_ino = args->ino; init_btrfs_i(inode); BTRFS_I(inode)->root = args->root; + btrfs_set_inode_space_info(args->root, inode); return 0; } @@ -3455,6 +3423,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, BTRFS_I(inode)->index_cnt = 2; BTRFS_I(inode)->root = root; BTRFS_I(inode)->generation = trans->transid; + btrfs_set_inode_space_info(root, inode); if (mode & S_IFDIR) owner = 0; @@ -3602,7 +3571,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, if (!new_valid_dev(rdev)) return -EINVAL; - err = btrfs_check_free_space(root, 1, 0); + err = btrfs_check_metadata_free_space(root); if (err) goto fail; @@ -3665,7 +3634,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, u64 objectid; u64 index = 0; - err = btrfs_check_free_space(root, 1, 0); + err = btrfs_check_metadata_free_space(root); if (err) goto fail; trans = btrfs_start_transaction(root, 1); @@ -3733,7 +3702,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, return -ENOENT; btrfs_inc_nlink(inode); - err = btrfs_check_free_space(root, 1, 0); + err = btrfs_check_metadata_free_space(root); if (err) goto fail; err = btrfs_set_inode_index(dir, &index); @@ -3779,7 +3748,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) u64 index = 0; unsigned long nr = 1; - err = btrfs_check_free_space(root, 1, 0); + err = btrfs_check_metadata_free_space(root); if (err) goto out_unlock; @@ -4336,7 +4305,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page) u64 page_start; u64 page_end; - ret = btrfs_check_free_space(root, PAGE_CACHE_SIZE, 0); + ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE); if (ret) goto out; @@ -4349,6 +4318,7 @@ again: if ((page->mapping != inode->i_mapping) || (page_start >= size)) { + btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE); /* page got truncated out from underneath us */ goto out_unlock; } @@ -4631,7 +4601,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) return -EXDEV; - ret = btrfs_check_free_space(root, 1, 0); + ret = btrfs_check_metadata_free_space(root); if (ret) goto out_unlock; @@ -4749,7 +4719,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root)) return -ENAMETOOLONG; - err = btrfs_check_free_space(root, 1, 0); + err = btrfs_check_metadata_free_space(root); if (err) goto out_fail; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 988fdc8b49eb..bca729fc80c8 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -70,7 +70,7 @@ static noinline int create_subvol(struct btrfs_root *root, u64 index = 0; unsigned long nr = 1; - ret = btrfs_check_free_space(root, 1, 0); + ret = btrfs_check_metadata_free_space(root); if (ret) goto fail_commit; @@ -203,7 +203,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, if (!root->ref_cows) return -EINVAL; - ret = btrfs_check_free_space(root, 1, 0); + ret = btrfs_check_metadata_free_space(root); if (ret) goto fail_unlock; @@ -374,7 +374,7 @@ static int btrfs_defrag_file(struct file *file) unsigned long i; int ret; - ret = btrfs_check_free_space(root, inode->i_size, 0); + ret = btrfs_check_data_free_space(root, inode, inode->i_size); if (ret) return -ENOSPC; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 39bd4d38e889..45e59d3c7f1f 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -1913,6 +1913,9 @@ COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ /* 0x00 */ COMPATIBLE_IOCTL(FIBMAP) COMPATIBLE_IOCTL(FIGETBSZ) +/* 'X' - originally XFS but some now in the VFS */ +COMPATIBLE_IOCTL(FIFREEZE) +COMPATIBLE_IOCTL(FITHAW) /* RAID */ COMPATIBLE_IOCTL(RAID_VERSION) COMPATIBLE_IOCTL(GET_ARRAY_INFO) diff --git a/fs/dcache.c b/fs/dcache.c index 937df0fb0da5..07e2d4a44bda 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1180,7 +1180,7 @@ struct dentry *d_obtain_alias(struct inode *inode) iput(inode); return res; } -EXPORT_SYMBOL_GPL(d_obtain_alias); +EXPORT_SYMBOL(d_obtain_alias); /** * d_splice_alias - splice a disconnected dentry into the tree if one exists diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 4fb86a0061d0..f18a919be70b 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -715,6 +715,13 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) if (sbi->s_log_groups_per_flex) { ret2 = find_group_flex(sb, dir, &group); + if (ret2 == -1) { + ret2 = find_group_other(sb, dir, &group); + if (ret2 == 0 && printk_ratelimit()) + printk(KERN_NOTICE "ext4: find_group_flex " + "failed, fallback succeeded dir %lu\n", + dir->i_ino); + } goto got_group; } diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index cbd2ca99d113..51cdd13e1c31 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1368,6 +1368,10 @@ retry: goto out; } + /* We cannot recurse into the filesystem as the transaction is already + * started */ + flags |= AOP_FLAG_NOFS; + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) { ext4_journal_stop(handle); @@ -1377,7 +1381,7 @@ retry: *pagep = page; ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, - ext4_get_block); + ext4_get_block); if (!ret && ext4_should_journal_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), @@ -2667,6 +2671,9 @@ retry: ret = PTR_ERR(handle); goto out; } + /* We cannot recurse into the filesystem as the transaction is already + * started */ + flags |= AOP_FLAG_NOFS; page = grab_cache_page_write_begin(mapping, index, flags); if (!page) { diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 3cceef4ad2b7..e9580104b6ba 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -95,13 +95,17 @@ static int jffs2_garbage_collect_thread(void *_c) spin_unlock(&c->erase_completion_lock); - /* This thread is purely an optimisation. But if it runs when - other things could be running, it actually makes things a - lot worse. Use yield() and put it at the back of the runqueue - every time. Especially during boot, pulling an inode in - with read_inode() is much preferable to having the GC thread - get there first. */ - yield(); + /* Problem - immediately after bootup, the GCD spends a lot + * of time in places like jffs2_kill_fragtree(); so much so + * that userspace processes (like gdm and X) are starved + * despite plenty of cond_resched()s and renicing. Yield() + * doesn't help, either (presumably because userspace and GCD + * are generally competing for a higher latency resource - + * disk). + * This forces the GCD to slow the hell down. Pulling an + * inode in with read_inode() is much preferable to having + * the GC thread get there first. */ + schedule_timeout_interruptible(msecs_to_jiffies(50)); /* Put_super will send a SIGKILL and then wait on the sem. */ diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 6ca08ad887c0..1fc1e92356ee 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -220,7 +220,7 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) { uint32_t fn_end = tn->fn->ofs + tn->fn->size; - struct jffs2_tmp_dnode_info *this; + struct jffs2_tmp_dnode_info *this, *ptn; dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw)); @@ -251,11 +251,18 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, if (this) { /* If the node is coincident with another at a lower address, back up until the other node is found. It may be relevant */ - while (this->overlapped) - this = tn_prev(this); - - /* First node should never be marked overlapped */ - BUG_ON(!this); + while (this->overlapped) { + ptn = tn_prev(this); + if (!ptn) { + /* + * We killed a node which set the overlapped + * flags during the scan. Fix it up. + */ + this->overlapped = 0; + break; + } + this = ptn; + } dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole"); } @@ -360,7 +367,17 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, } if (!this->overlapped) break; - this = tn_prev(this); + + ptn = tn_prev(this); + if (!ptn) { + /* + * We killed a node which set the overlapped + * flags during the scan. Fix it up. + */ + this->overlapped = 0; + break; + } + this = ptn; } } @@ -456,8 +473,15 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, eat_last(&rii->tn_root, &last->rb); ver_insert(&ver_root, last); - if (unlikely(last->overlapped)) - continue; + if (unlikely(last->overlapped)) { + if (pen) + continue; + /* + * We killed a node which set the overlapped + * flags during the scan. Fix it up. + */ + last->overlapped = 0; + } /* Now we have a bunch of nodes in reverse version order, in the tree at ver_root. Most of the time, diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 60fe74035db5..3a9e5deed74d 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -4796,6 +4796,29 @@ out: return ret; } +static int ocfs2_replace_extent_rec(struct inode *inode, + handle_t *handle, + struct ocfs2_path *path, + struct ocfs2_extent_list *el, + int split_index, + struct ocfs2_extent_rec *split_rec) +{ + int ret; + + ret = ocfs2_path_bh_journal_access(handle, inode, path, + path_num_items(path) - 1); + if (ret) { + mlog_errno(ret); + goto out; + } + + el->l_recs[split_index] = *split_rec; + + ocfs2_journal_dirty(handle, path_leaf_bh(path)); +out: + return ret; +} + /* * Mark part or all of the extent record at split_index in the leaf * pointed to by path as written. This removes the unwritten @@ -4885,7 +4908,9 @@ static int __ocfs2_mark_extent_written(struct inode *inode, if (ctxt.c_contig_type == CONTIG_NONE) { if (ctxt.c_split_covers_rec) - el->l_recs[split_index] = *split_rec; + ret = ocfs2_replace_extent_rec(inode, handle, + path, el, + split_index, split_rec); else ret = ocfs2_split_and_insert(inode, handle, path, et, &last_eb_bh, split_index, diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 54e182a27caf..0a2813947853 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -1849,12 +1849,12 @@ int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data, if (!mle) { if (res->owner != DLM_LOCK_RES_OWNER_UNKNOWN && res->owner != assert->node_idx) { - mlog(ML_ERROR, "assert_master from " - "%u, but current owner is " - "%u! (%.*s)\n", - assert->node_idx, res->owner, - namelen, name); - goto kill; + mlog(ML_ERROR, "DIE! Mastery assert from %u, " + "but current owner is %u! (%.*s)\n", + assert->node_idx, res->owner, namelen, + name); + __dlm_print_one_lock_resource(res); + BUG(); } } else if (mle->type != DLM_MLE_MIGRATION) { if (res->owner != DLM_LOCK_RES_OWNER_UNKNOWN) { diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c index d1295203029f..4060bb328bc8 100644 --- a/fs/ocfs2/dlm/dlmthread.c +++ b/fs/ocfs2/dlm/dlmthread.c @@ -181,8 +181,7 @@ static int dlm_purge_lockres(struct dlm_ctxt *dlm, spin_lock(&res->spinlock); /* This ensures that clear refmap is sent after the set */ - __dlm_wait_on_lockres_flags(res, (DLM_LOCK_RES_SETREF_INPROG | - DLM_LOCK_RES_MIGRATING)); + __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG); spin_unlock(&res->spinlock); /* clear our bit from the master's refmap, ignore errors */ diff --git a/fs/ocfs2/dlm/dlmunlock.c b/fs/ocfs2/dlm/dlmunlock.c index 86ca085ef324..fcf879ed6930 100644 --- a/fs/ocfs2/dlm/dlmunlock.c +++ b/fs/ocfs2/dlm/dlmunlock.c @@ -117,11 +117,11 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm, else BUG_ON(res->owner == dlm->node_num); - spin_lock(&dlm->spinlock); + spin_lock(&dlm->ast_lock); /* We want to be sure that we're not freeing a lock * that still has AST's pending... */ in_use = !list_empty(&lock->ast_list); - spin_unlock(&dlm->spinlock); + spin_unlock(&dlm->ast_lock); if (in_use) { mlog(ML_ERROR, "lockres %.*s: Someone is calling dlmunlock " "while waiting for an ast!", res->lockname.len, diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 206a2370876a..7219a86d34cc 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -320,9 +320,14 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb, struct ocfs2_lock_res *lockres); static inline void ocfs2_recover_from_dlm_error(struct ocfs2_lock_res *lockres, int convert); -#define ocfs2_log_dlm_error(_func, _err, _lockres) do { \ - mlog(ML_ERROR, "DLM error %d while calling %s on resource %s\n", \ - _err, _func, _lockres->l_name); \ +#define ocfs2_log_dlm_error(_func, _err, _lockres) do { \ + if ((_lockres)->l_type != OCFS2_LOCK_TYPE_DENTRY) \ + mlog(ML_ERROR, "DLM error %d while calling %s on resource %s\n", \ + _err, _func, _lockres->l_name); \ + else \ + mlog(ML_ERROR, "DLM error %d while calling %s on resource %.*s%08x\n", \ + _err, _func, OCFS2_DENTRY_LOCK_INO_START - 1, (_lockres)->l_name, \ + (unsigned int)ocfs2_get_dentry_lock_ino(_lockres)); \ } while (0) static int ocfs2_downconvert_thread(void *arg); static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb, diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 077384135f4e..946d3c34b90b 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -341,6 +341,9 @@ struct ocfs2_super struct ocfs2_node_map osb_recovering_orphan_dirs; unsigned int *osb_orphan_wipes; wait_queue_head_t osb_wipe_event; + + /* used to protect metaecc calculation check of xattr. */ + spinlock_t osb_xattr_lock; }; #define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index b1cb38fbe807..7ac83a81ee55 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1537,6 +1537,13 @@ static int ocfs2_get_sector(struct super_block *sb, unlock_buffer(*bh); ll_rw_block(READ, 1, bh); wait_on_buffer(*bh); + if (!buffer_uptodate(*bh)) { + mlog_errno(-EIO); + brelse(*bh); + *bh = NULL; + return -EIO; + } + return 0; } @@ -1747,6 +1754,7 @@ static int ocfs2_initialize_super(struct super_block *sb, INIT_LIST_HEAD(&osb->blocked_lock_list); osb->blocked_lock_count = 0; spin_lock_init(&osb->osb_lock); + spin_lock_init(&osb->osb_xattr_lock); ocfs2_init_inode_steal_slot(osb); atomic_set(&osb->alloc_stats.moves, 0); diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 915039fffe6e..4ddd788add67 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -82,13 +82,14 @@ struct ocfs2_xattr_set_ctxt { #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) #define OCFS2_XATTR_INLINE_SIZE 80 +#define OCFS2_XATTR_HEADER_GAP 4 #define OCFS2_XATTR_FREE_IN_IBODY (OCFS2_MIN_XATTR_INLINE_SIZE \ - sizeof(struct ocfs2_xattr_header) \ - - sizeof(__u32)) + - OCFS2_XATTR_HEADER_GAP) #define OCFS2_XATTR_FREE_IN_BLOCK(ptr) ((ptr)->i_sb->s_blocksize \ - sizeof(struct ocfs2_xattr_block) \ - sizeof(struct ocfs2_xattr_header) \ - - sizeof(__u32)) + - OCFS2_XATTR_HEADER_GAP) static struct ocfs2_xattr_def_value_root def_xv = { .xv.xr_list.l_count = cpu_to_le16(1), @@ -274,10 +275,12 @@ static int ocfs2_read_xattr_bucket(struct ocfs2_xattr_bucket *bucket, bucket->bu_blocks, bucket->bu_bhs, 0, NULL); if (!rc) { + spin_lock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock); rc = ocfs2_validate_meta_ecc_bhs(bucket->bu_inode->i_sb, bucket->bu_bhs, bucket->bu_blocks, &bucket_xh(bucket)->xh_check); + spin_unlock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock); if (rc) mlog_errno(rc); } @@ -310,9 +313,11 @@ static void ocfs2_xattr_bucket_journal_dirty(handle_t *handle, { int i; + spin_lock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock); ocfs2_compute_meta_ecc_bhs(bucket->bu_inode->i_sb, bucket->bu_bhs, bucket->bu_blocks, &bucket_xh(bucket)->xh_check); + spin_unlock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock); for (i = 0; i < bucket->bu_blocks; i++) ocfs2_journal_dirty(handle, bucket->bu_bhs[i]); @@ -1507,7 +1512,7 @@ static int ocfs2_xattr_set_entry(struct inode *inode, last += 1; } - free = min_offs - ((void *)last - xs->base) - sizeof(__u32); + free = min_offs - ((void *)last - xs->base) - OCFS2_XATTR_HEADER_GAP; if (free < 0) return -EIO; @@ -2190,7 +2195,7 @@ static int ocfs2_xattr_can_be_in_inode(struct inode *inode, last += 1; } - free = min_offs - ((void *)last - xs->base) - sizeof(__u32); + free = min_offs - ((void *)last - xs->base) - OCFS2_XATTR_HEADER_GAP; if (free < 0) return 0; @@ -2592,8 +2597,9 @@ static int __ocfs2_xattr_set_handle(struct inode *inode, if (!ret) { /* Update inode ctime. */ - ret = ocfs2_journal_access(ctxt->handle, inode, xis->inode_bh, - OCFS2_JOURNAL_ACCESS_WRITE); + ret = ocfs2_journal_access_di(ctxt->handle, inode, + xis->inode_bh, + OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); goto out; @@ -5060,8 +5066,8 @@ try_again: xh_free_start = le16_to_cpu(xh->xh_free_start); header_size = sizeof(struct ocfs2_xattr_header) + count * sizeof(struct ocfs2_xattr_entry); - max_free = OCFS2_XATTR_BUCKET_SIZE - - le16_to_cpu(xh->xh_name_value_len) - header_size; + max_free = OCFS2_XATTR_BUCKET_SIZE - header_size - + le16_to_cpu(xh->xh_name_value_len) - OCFS2_XATTR_HEADER_GAP; mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size " "of %u which exceed block size\n", @@ -5094,7 +5100,7 @@ try_again: need = 0; } - free = xh_free_start - header_size; + free = xh_free_start - header_size - OCFS2_XATTR_HEADER_GAP; /* * We need to make sure the new name/value pair * can exist in the same block. @@ -5127,7 +5133,8 @@ try_again: } xh_free_start = le16_to_cpu(xh->xh_free_start); - free = xh_free_start - header_size; + free = xh_free_start - header_size + - OCFS2_XATTR_HEADER_GAP; if (xh_free_start % blocksize < need) free -= xh_free_start % blocksize; diff --git a/fs/proc/page.c b/fs/proc/page.c index 767d95a6d1b1..2d1345112a42 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -107,7 +107,7 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, else kflags = ppage->flags; - uflags = kpf_copy_bit(KPF_LOCKED, PG_locked, kflags) | + uflags = kpf_copy_bit(kflags, KPF_LOCKED, PG_locked) | kpf_copy_bit(kflags, KPF_ERROR, PG_error) | kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) | kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) | diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 0b0d236c2154..c7d4b2e606a5 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -76,6 +76,7 @@ struct drm_encoder_helper_funcs { void (*mode_set)(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); + struct drm_crtc *(*get_crtc)(struct drm_encoder *encoder); /* detect for DAC style encoders */ enum drm_connector_status (*detect)(struct drm_encoder *encoder, struct drm_connector *connector); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index c707c15f5164..ff8d27af4786 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -58,10 +58,10 @@ struct detailed_pixel_timing { u8 hsync_pulse_width_lo; u8 vsync_pulse_width_lo:4; u8 vsync_offset_lo:4; - u8 hsync_pulse_width_hi:2; - u8 hsync_offset_hi:2; u8 vsync_pulse_width_hi:2; u8 vsync_offset_hi:2; + u8 hsync_pulse_width_hi:2; + u8 hsync_offset_hi:2; u8 width_mm_lo; u8 height_mm_lo; u8 height_mm_hi:4; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index dcaa0fd84b02..465d6babc847 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -708,6 +708,8 @@ struct req_iterator { }; /* This should not be used directly - use rq_for_each_segment */ +#define for_each_bio(_bio) \ + for (; _bio; _bio = _bio->bi_next) #define __rq_for_each_bio(_bio, rq) \ if ((rq->bio)) \ for (_bio = (rq)->bio; _bio; _bio = _bio->bi_next) diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h index 311315b56b61..fd53bfd26470 100644 --- a/include/linux/i2c-dev.h +++ b/include/linux/i2c-dev.h @@ -33,7 +33,7 @@ */ #define I2C_RETRIES 0x0701 /* number of times a device address should be polled when not acknowledging */ -#define I2C_TIMEOUT 0x0702 /* set timeout in jiffies - call with int */ +#define I2C_TIMEOUT 0x0702 /* set timeout in units of 10 ms */ /* NOTE: Slave address is 7 or 10 bits, but 10-bit addresses * are NOT supported! (due to code brokenness) diff --git a/include/linux/i2c.h b/include/linux/i2c.h index fcfbfea3af72..c86c3b07604c 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -361,7 +361,7 @@ struct i2c_adapter { struct mutex bus_lock; struct mutex clist_lock; - int timeout; + int timeout; /* in jiffies */ int retries; struct device dev; /* the adapter device */ diff --git a/include/linux/ide.h b/include/linux/ide.h index 194da5a4b0d6..fe235b65207e 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -663,7 +663,7 @@ typedef struct ide_drive_s ide_drive_t; #define to_ide_device(dev) container_of(dev, ide_drive_t, gendev) #define to_ide_drv(obj, cont_type) \ - container_of(obj, struct cont_type, kref) + container_of(obj, struct cont_type, dev) #define ide_drv_g(disk, cont_type) \ container_of((disk)->private_data, struct cont_type, driver) diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index c4f6c101dbcd..d2e3cbfba14f 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -194,6 +194,7 @@ static inline void dmar_writeq(void __iomem *addr, u64 val) /* FSTS_REG */ #define DMA_FSTS_PPF ((u32)2) #define DMA_FSTS_PFO ((u32)1) +#define DMA_FSTS_IQE (1 << 4) #define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff) /* FRCD_REG, 32 bits access */ @@ -328,7 +329,7 @@ extern int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, unsigned int size_order, u64 type, int non_present_entry_flush); -extern void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu); +extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu); extern void *intel_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t); extern void intel_free_coherent(struct device *, size_t, void *, dma_addr_t); diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h index 82df31726a54..cbc2f0cd631b 100644 --- a/include/linux/io-mapping.h +++ b/include/linux/io-mapping.h @@ -30,11 +30,14 @@ * See Documentation/io_mapping.txt */ -/* this struct isn't actually defined anywhere */ -struct io_mapping; - #ifdef CONFIG_HAVE_ATOMIC_IOMAP +struct io_mapping { + resource_size_t base; + unsigned long size; + pgprot_t prot; +}; + /* * For small address space machines, mapping large objects * into the kernel virtual space isn't practical. Where @@ -43,23 +46,40 @@ struct io_mapping; */ static inline struct io_mapping * -io_mapping_create_wc(unsigned long base, unsigned long size) +io_mapping_create_wc(resource_size_t base, unsigned long size) { - return (struct io_mapping *) base; + struct io_mapping *iomap; + + if (!is_io_mapping_possible(base, size)) + return NULL; + + iomap = kmalloc(sizeof(*iomap), GFP_KERNEL); + if (!iomap) + return NULL; + + iomap->base = base; + iomap->size = size; + iomap->prot = pgprot_writecombine(__pgprot(__PAGE_KERNEL)); + return iomap; } static inline void io_mapping_free(struct io_mapping *mapping) { + kfree(mapping); } /* Atomic map/unmap */ static inline void * io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset) { - offset += (unsigned long) mapping; - return iomap_atomic_prot_pfn(offset >> PAGE_SHIFT, KM_USER0, - __pgprot(__PAGE_KERNEL_WC)); + resource_size_t phys_addr; + unsigned long pfn; + + BUG_ON(offset >= mapping->size); + phys_addr = mapping->base + offset; + pfn = (unsigned long) (phys_addr >> PAGE_SHIFT); + return iomap_atomic_prot_pfn(pfn, KM_USER0, mapping->prot); } static inline void @@ -71,8 +91,9 @@ io_mapping_unmap_atomic(void *vaddr) static inline void * io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset) { - offset += (unsigned long) mapping; - return ioremap_wc(offset, PAGE_SIZE); + BUG_ON(offset >= mapping->size); + resource_size_t phys_addr = mapping->base + offset; + return ioremap_wc(phys_addr, PAGE_SIZE); } static inline void @@ -83,9 +104,12 @@ io_mapping_unmap(void *vaddr) #else +/* this struct isn't actually defined anywhere */ +struct io_mapping; + /* Create the io_mapping object*/ static inline struct io_mapping * -io_mapping_create_wc(unsigned long base, unsigned long size) +io_mapping_create_wc(resource_size_t base, unsigned long size) { return (struct io_mapping *) ioremap_wc(base, size); } diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 315bcd375224..cc4f45361dbb 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -13,6 +13,7 @@ struct user_namespace { struct kref kref; struct hlist_head uidhash_table[UIDHASH_SZ]; struct user_struct *creator; + struct work_struct destroyer; }; extern struct user_namespace init_user_ns; diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 79084311ee57..076c7c8215b0 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -60,12 +60,25 @@ int create_user_ns(struct cred *new) return 0; } -void free_user_ns(struct kref *kref) +/* + * Deferred destructor for a user namespace. This is required because + * free_user_ns() may be called with uidhash_lock held, but we need to call + * back to free_uid() which will want to take the lock again. + */ +static void free_user_ns_work(struct work_struct *work) { - struct user_namespace *ns; - - ns = container_of(kref, struct user_namespace, kref); + struct user_namespace *ns = + container_of(work, struct user_namespace, destroyer); free_uid(ns->creator); kfree(ns); } + +void free_user_ns(struct kref *kref) +{ + struct user_namespace *ns = + container_of(kref, struct user_namespace, kref); + + INIT_WORK(&ns->destroyer, free_user_ns_work); + schedule_work(&ns->destroyer); +} EXPORT_SYMBOL(free_user_ns); diff --git a/mm/shmem.c b/mm/shmem.c index 19d566ccdeea..4103a239ce84 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -169,13 +169,13 @@ static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb) */ static inline int shmem_acct_size(unsigned long flags, loff_t size) { - return (flags & VM_ACCOUNT) ? - security_vm_enough_memory_kern(VM_ACCT(size)) : 0; + return (flags & VM_NORESERVE) ? + 0 : security_vm_enough_memory_kern(VM_ACCT(size)); } static inline void shmem_unacct_size(unsigned long flags, loff_t size) { - if (flags & VM_ACCOUNT) + if (!(flags & VM_NORESERVE)) vm_unacct_memory(VM_ACCT(size)); } @@ -187,13 +187,13 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size) */ static inline int shmem_acct_block(unsigned long flags) { - return (flags & VM_ACCOUNT) ? - 0 : security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE)); + return (flags & VM_NORESERVE) ? + security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE)) : 0; } static inline void shmem_unacct_blocks(unsigned long flags, long pages) { - if (!(flags & VM_ACCOUNT)) + if (flags & VM_NORESERVE) vm_unacct_memory(pages * VM_ACCT(PAGE_CACHE_SIZE)); } @@ -1515,8 +1515,8 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma) return 0; } -static struct inode * -shmem_get_inode(struct super_block *sb, int mode, dev_t dev) +static struct inode *shmem_get_inode(struct super_block *sb, int mode, + dev_t dev, unsigned long flags) { struct inode *inode; struct shmem_inode_info *info; @@ -1537,6 +1537,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) info = SHMEM_I(inode); memset(info, 0, (char *)inode - (char *)info); spin_lock_init(&info->lock); + info->flags = flags & VM_NORESERVE; INIT_LIST_HEAD(&info->swaplist); switch (mode & S_IFMT) { @@ -1779,9 +1780,10 @@ static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf) static int shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - struct inode *inode = shmem_get_inode(dir->i_sb, mode, dev); + struct inode *inode; int error = -ENOSPC; + inode = shmem_get_inode(dir->i_sb, mode, dev, VM_NORESERVE); if (inode) { error = security_inode_init_security(inode, dir, NULL, NULL, NULL); @@ -1920,7 +1922,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s if (len > PAGE_CACHE_SIZE) return -ENAMETOOLONG; - inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE); if (!inode) return -ENOSPC; @@ -2332,7 +2334,7 @@ static int shmem_fill_super(struct super_block *sb, sb->s_flags |= MS_POSIXACL; #endif - inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0); + inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE); if (!inode) goto failed; inode->i_uid = sbinfo->uid; @@ -2574,12 +2576,12 @@ int shmem_unuse(swp_entry_t entry, struct page *page) return 0; } -#define shmem_file_operations ramfs_file_operations -#define shmem_vm_ops generic_file_vm_ops -#define shmem_get_inode ramfs_get_inode -#define shmem_acct_size(a, b) 0 -#define shmem_unacct_size(a, b) do {} while (0) -#define SHMEM_MAX_BYTES LLONG_MAX +#define shmem_vm_ops generic_file_vm_ops +#define shmem_file_operations ramfs_file_operations +#define shmem_get_inode(sb, mode, dev, flags) ramfs_get_inode(sb, mode, dev) +#define shmem_acct_size(flags, size) 0 +#define shmem_unacct_size(flags, size) do {} while (0) +#define SHMEM_MAX_BYTES LLONG_MAX #endif /* CONFIG_SHMEM */ @@ -2589,7 +2591,7 @@ int shmem_unuse(swp_entry_t entry, struct page *page) * shmem_file_setup - get an unlinked file living in tmpfs * @name: name for dentry (to be seen in /proc/<pid>/maps * @size: size to be set for the file - * @flags: vm_flags + * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size */ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) { @@ -2623,13 +2625,10 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) goto put_dentry; error = -ENOSPC; - inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0); + inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0, flags); if (!inode) goto close_file; -#ifdef CONFIG_SHMEM - SHMEM_I(inode)->flags = (flags & VM_NORESERVE) ? 0 : VM_ACCOUNT; -#endif d_instantiate(dentry, inode); inode->i_size = size; inode->i_nlink = 0; /* It is unlinked */ diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 903cad46e796..520a75980269 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -323,6 +323,7 @@ static struct vmap_area *alloc_vmap_area(unsigned long size, unsigned long addr; int purged = 0; + BUG_ON(!size); BUG_ON(size & ~PAGE_MASK); va = kmalloc_node(sizeof(struct vmap_area), @@ -334,6 +335,9 @@ retry: addr = ALIGN(vstart, align); spin_lock(&vmap_area_lock); + if (addr + size - 1 < addr) + goto overflow; + /* XXX: could have a last_hole cache */ n = vmap_area_root.rb_node; if (n) { @@ -365,6 +369,8 @@ retry: while (addr + size > first->va_start && addr + size <= vend) { addr = ALIGN(first->va_end + PAGE_SIZE, align); + if (addr + size - 1 < addr) + goto overflow; n = rb_next(&first->rb_node); if (n) @@ -375,6 +381,7 @@ retry: } found: if (addr + size > vend) { +overflow: spin_unlock(&vmap_area_lock); if (!purged) { purge_vmap_area_lazy(); @@ -498,6 +505,7 @@ static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end, static DEFINE_SPINLOCK(purge_lock); LIST_HEAD(valist); struct vmap_area *va; + struct vmap_area *n_va; int nr = 0; /* @@ -537,7 +545,7 @@ static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end, if (nr) { spin_lock(&vmap_area_lock); - list_for_each_entry(va, &valist, purge_list) + list_for_each_entry_safe(va, n_va, &valist, purge_list) __free_vmap_area(va); spin_unlock(&vmap_area_lock); } diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 45eb0ae98eba..2d5ece798c4c 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -10,7 +10,7 @@ use strict; my $P = $0; $P =~ s@.*/@@g; -my $V = '0.27'; +my $V = '0.28'; use Getopt::Long qw(:config no_auto_abbrev); @@ -110,7 +110,8 @@ our $Sparse = qr{ __iomem| __must_check| __init_refok| - __kprobes + __kprobes| + __ref }x; our $Attribute = qr{ const| @@ -1240,7 +1241,8 @@ sub process { $realfile =~ s@^([^/]*)/@@; $p1_prefix = $1; - if ($tree && $p1_prefix ne '' && -e "$root/$p1_prefix") { + if (!$file && $tree && $p1_prefix ne '' && + -e "$root/$p1_prefix") { WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); } @@ -1583,9 +1585,9 @@ sub process { } # TEST: allow direct testing of the attribute matcher. if ($dbg_attr) { - if ($line =~ /^.\s*$Attribute\s*$/) { + if ($line =~ /^.\s*$Modifier\s*$/) { ERROR("TEST: is attr\n" . $herecurr); - } elsif ($dbg_attr > 1 && $line =~ /^.+($Attribute)/) { + } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) { ERROR("TEST: is not attr ($1 is)\n". $herecurr); } next; @@ -1657,7 +1659,7 @@ sub process { # * goes on variable not on type # (char*[ const]) - if ($line =~ m{\($NonptrType(\s*\*[\s\*]*(?:$Modifier\s*)*)\)}) { + if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) { my ($from, $to) = ($1, $1); # Should start with a space. @@ -1672,7 +1674,7 @@ sub process { if ($from ne $to) { ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr); } - } elsif ($line =~ m{\b$NonptrType(\s*\*[\s\*]*(?:$Modifier\s*)?)($Ident)}) { + } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) { my ($from, $to, $ident) = ($1, $1, $2); # Should start with a space. @@ -1685,8 +1687,8 @@ sub process { # Modifiers should have spaces. $to =~ s/(\b$Modifier$)/$1 /; - #print "from<$from> to<$to>\n"; - if ($from ne $to) { + #print "from<$from> to<$to> ident<$ident>\n"; + if ($from ne $to && $ident !~ /^$Modifier$/) { ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr); } } @@ -1885,11 +1887,11 @@ sub process { if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { ERROR("space required before that '$op' $at\n" . $hereptr); } - if ($op eq '*' && $cc =~/\s*const\b/) { + if ($op eq '*' && $cc =~/\s*$Modifier\b/) { # A unary '*' may be const } elsif ($ctx =~ /.xW/) { - ERROR("space prohibited after that '$op' $at\n" . $hereptr); + ERROR("Aspace prohibited after that '$op' $at\n" . $hereptr); } # unary ++ and unary -- are allowed no space on one side. @@ -2560,7 +2562,7 @@ sub process { if ($line =~ /\bin_atomic\s*\(/) { if ($realfile =~ m@^drivers/@) { ERROR("do not use in_atomic in drivers\n" . $herecurr); - } else { + } elsif ($realfile !~ m@^kernel/@) { WARN("use of in_atomic() is incorrect outside core kernel code\n" . $herecurr); } } diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c index a466443c4a26..2fa9299a440d 100644 --- a/sound/core/oss/rate.c +++ b/sound/core/oss/rate.c @@ -157,7 +157,7 @@ static void resample_shrink(struct snd_pcm_plugin *plugin, while (dst_frames1 > 0) { S1 = S2; if (src_frames1-- > 0) { - S1 = *src; + S2 = *src; src += src_step; } if (pos & ~R_MASK) { diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 3f00ddf450f8..c7c54e7748e9 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -165,7 +165,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard."); static struct pci_device_id snd_aw2_ids[] = { - {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, PCI_ANY_ID, PCI_ANY_ID, + {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0, 0, 0, 0}, {0} }; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 7958006a1d66..101a1c13a20d 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1528,6 +1528,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0151_chip = 1, .spk71 = 1, .spdif_bug = 1, + .invert_shared_spdif = 1, /* digital/analog switch swapped */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]", diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 482fb0304ca9..4ae51dcb81af 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -277,18 +277,19 @@ static ssize_t init_verbs_store(struct device *dev, { struct snd_hwdep *hwdep = dev_get_drvdata(dev); struct hda_codec *codec = hwdep->private_data; - char *p; - struct hda_verb verb, *v; + struct hda_verb *v; + int nid, verb, param; - verb.nid = simple_strtoul(buf, &p, 0); - verb.verb = simple_strtoul(p, &p, 0); - verb.param = simple_strtoul(p, &p, 0); - if (!verb.nid || !verb.verb || !verb.param) + if (sscanf(buf, "%i %i %i", &nid, &verb, ¶m) != 3) + return -EINVAL; + if (!nid || !verb) return -EINVAL; v = snd_array_new(&codec->init_verbs); if (!v) return -ENOMEM; - *v = verb; + v->nid = nid; + v->verb = verb; + v->param = param; return count; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ed8fcbd60003..a680be0d4534 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7017,6 +7017,7 @@ static int patch_alc882(struct hda_codec *codec) case 0x106b3e00: /* iMac 24 Aluminium */ board_config = ALC885_IMAC24; break; + case 0x106b00a0: /* MacBookPro3,1 - Another revision */ case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ case 0x106b00a4: /* MacbookPro4,1 */ case 0x106b2c00: /* Macbook Pro rev3 */ @@ -8469,6 +8470,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", + ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h index 84131a916c92..69d87dee6995 100644 --- a/sound/pci/pcxhr/pcxhr.h +++ b/sound/pci/pcxhr/pcxhr.h @@ -97,12 +97,12 @@ struct pcxhr_mgr { int capture_chips; int fw_file_set; int firmware_num; - int is_hr_stereo:1; - int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */ - int board_has_analog:1; /* if 0 the board is digital only */ - int board_has_mic:1; /* if 1 the board has microphone input */ - int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */ - int mono_capture:1; /* if 1 the board does mono capture */ + unsigned int is_hr_stereo:1; + unsigned int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */ + unsigned int board_has_analog:1; /* if 0 the board is digital only */ + unsigned int board_has_mic:1; /* if 1 the board has microphone input */ + unsigned int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */ + unsigned int mono_capture:1; /* if 1 the board does mono capture */ struct snd_dma_buffer hostport; |