diff options
125 files changed, 3143 insertions, 1274 deletions
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt index 5147be5e13cd..b58b84b50fa2 100644 --- a/Documentation/filesystems/vfat.txt +++ b/Documentation/filesystems/vfat.txt @@ -132,6 +132,11 @@ rodir -- FAT has the ATTR_RO (read-only) attribute. On Windows, If you want to use ATTR_RO as read-only flag even for the directory, set this option. +errors=panic|continue|remount-ro + -- specify FAT behavior on critical errors: panic, continue + without doing anything or remount the partition in + read-only mode (default behavior). + <bool>: 0,1,yes,no,true,false TODO diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg index a8321267b5b6..bee4c30bc1e2 100644 --- a/Documentation/hwmon/f71882fg +++ b/Documentation/hwmon/f71882fg @@ -2,14 +2,18 @@ Kernel driver f71882fg ====================== Supported chips: - * Fintek F71882FG and F71883FG - Prefix: 'f71882fg' + * Fintek F71858FG + Prefix: 'f71858fg' Addresses scanned: none, address read from Super I/O config space Datasheet: Available from the Fintek website * Fintek F71862FG and F71863FG Prefix: 'f71862fg' Addresses scanned: none, address read from Super I/O config space Datasheet: Available from the Fintek website + * Fintek F71882FG and F71883FG + Prefix: 'f71882fg' + Addresses scanned: none, address read from Super I/O config space + Datasheet: Available from the Fintek website * Fintek F8000 Prefix: 'f8000' Addresses scanned: none, address read from Super I/O config space @@ -66,13 +70,13 @@ printed when loading the driver. Three different fan control modes are supported; the mode number is written to the pwm#_enable file. Note that not all modes are supported on all -chips, and some modes may only be available in RPM / PWM mode on the F8000. +chips, and some modes may only be available in RPM / PWM mode. Writing an unsupported mode will result in an invalid parameter error. * 1: Manual mode You ask for a specific PWM duty cycle / DC voltage or a specific % of fan#_full_speed by writing to the pwm# file. This mode is only - available on the F8000 if the fan channel is in RPM mode. + available on the F71858FG / F8000 if the fan channel is in RPM mode. * 2: Normal auto mode You can define a number of temperature/fan speed trip points, which % the diff --git a/Documentation/hwmon/ibmaem b/Documentation/hwmon/ibmaem index e98bdfea3467..1e0d59e000b4 100644 --- a/Documentation/hwmon/ibmaem +++ b/Documentation/hwmon/ibmaem @@ -7,7 +7,7 @@ henceforth as AEM. Supported systems: * Any recent IBM System X server with AEM support. This includes the x3350, x3550, x3650, x3655, x3755, x3850 M2, - x3950 M2, and certain HS2x/LS2x/QS2x blades. The IPMI host interface + x3950 M2, and certain HC10/HS2x/LS2x/QS2x blades. The IPMI host interface driver ("ipmi-si") needs to be loaded for this driver to do anything. Prefix: 'ibmaem' Datasheet: Not available diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index 004ee161721e..dcbd502c8792 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface @@ -70,6 +70,7 @@ are interpreted as 0! For more on how written strings are interpreted see the [0-*] denotes any positive number starting from 0 [1-*] denotes any positive number starting from 1 RO read only value +WO write only value RW read/write value Read/write values may be read-only for some chips, depending on the @@ -295,6 +296,24 @@ temp[1-*]_label Suggested temperature channel label. user-space. RO +temp[1-*]_lowest + Historical minimum temperature + Unit: millidegree Celsius + RO + +temp[1-*]_highest + Historical maximum temperature + Unit: millidegree Celsius + RO + +temp[1-*]_reset_history + Reset temp_lowest and temp_highest + WO + +temp_reset_history + Reset temp_lowest and temp_highest for all sensors + WO + Some chips measure temperature using external thermistors and an ADC, and report the temperature measurement as a voltage. Converting this voltage back to a temperature (or the other way around for limits) requires diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401 new file mode 100644 index 000000000000..9fc447249212 --- /dev/null +++ b/Documentation/hwmon/tmp401 @@ -0,0 +1,42 @@ +Kernel driver tmp401 +==================== + +Supported chips: + * Texas Instruments TMP401 + Prefix: 'tmp401' + Addresses scanned: I2C 0x4c + Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html + * Texas Instruments TMP411 + Prefix: 'tmp411' + Addresses scanned: I2C 0x4c + Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html + +Authors: + Hans de Goede <hdegoede@redhat.com> + Andre Prendel <andre.prendel@gmx.de> + +Description +----------- + +This driver implements support for Texas Instruments TMP401 and +TMP411 chips. These chips implements one remote and one local +temperature sensor. Temperature is measured in degrees +Celsius. Resolution of the remote sensor is 0.0625 degree. Local +sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not +supported by the driver so far, so using the default resolution of 0.5 +degree). + +The driver provides the common sysfs-interface for temperatures (see +/Documentation/hwmon/sysfs-interface under Temperatures). + +The TMP411 chip is compatible with TMP401. It provides some additional +features. + +* Minimum and Maximum temperature measured since power-on, chip-reset + + Exported via sysfs attributes tempX_lowest and tempX_highest. + +* Reset of historical minimum/maximum temperature measurements + + Exported via sysfs attribute temp_reset_history. Writing 1 to this + file triggers a reset. diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index b6eb59384bb3..02b74899edaf 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf @@ -12,6 +12,10 @@ Supported chips: Addresses scanned: ISA address retrieved from Super I/O registers Datasheet: http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf + * Winbond W83627DHG-P + Prefix: 'w83627dhg' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: not available * Winbond W83667HG Prefix: 'w83667hg' Addresses scanned: ISA address retrieved from Super I/O registers @@ -28,8 +32,8 @@ Description ----------- This driver implements support for the Winbond W83627EHF, W83627EHG, -W83627DHG and W83667HG super I/O chips. We will refer to them collectively -as Winbond chips. +W83627DHG, W83627DHG-P and W83667HG super I/O chips. We will refer to them +collectively as Winbond chips. The chips implement three temperature sensors, five fan rotation speed sensors, ten analog voltage sensors (only nine for the 627DHG), one @@ -135,3 +139,6 @@ done in the driver for all register addresses. The DHG also supports PECI, where the DHG queries Intel CPU temperatures, and the ICH8 southbridge gets that data via PECI from the DHG, so that the southbridge drives the fans. And the DHG supports SST, a one-wire serial bus. + +The DHG-P has an additional automatic fan speed control mode named Smart Fan +(TM) III+. This mode is not yet supported by the driver. diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index 22efedf60c87..2e758b0e9456 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -19,6 +19,9 @@ Supported adapters: * VIA Technologies, Inc. VX800/VX820 Datasheet: available on http://linux.via.com.tw + * VIA Technologies, Inc. VX855/VX875 + Datasheet: Availability unknown + Authors: Kyösti Mälkki <kmalkki@cc.hut.fi>, Mark D. Studebaker <mdsxyz123@yahoo.com>, @@ -53,6 +56,7 @@ Your lspci -n listing must show one of these : device 1106:3287 (VT8251) device 1106:8324 (CX700) device 1106:8353 (VX800/VX820) + device 1106:8409 (VX855/VX875) If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 783da855a2e3..d6d35b2e5fe8 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -963,7 +963,7 @@ CONFIG_EEPROM_LEGACY=y CONFIG_SENSORS_PCF8574=y # CONFIG_PCF8575 is not set CONFIG_SENSORS_PCF8591=y -CONFIG_SENSORS_MAX6875=y +CONFIG_EEPROM_MAX6875=y # CONFIG_SENSORS_TSL2550 is not set CONFIG_I2C_DEBUG_CORE=y CONFIG_I2C_DEBUG_ALGO=y diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 8426d3b9501c..fadb351d249b 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -1849,7 +1849,7 @@ CONFIG_EEPROM_LEGACY=m CONFIG_SENSORS_PCF8574=m CONFIG_SENSORS_PCA9539=m CONFIG_SENSORS_PCF8591=m -CONFIG_SENSORS_MAX6875=m +CONFIG_EEPROM_MAX6875=m # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 93a61898b259..9fb344d5a86a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -93,10 +93,6 @@ config GENERIC_HWEIGHT bool default y -config GENERIC_CALIBRATE_DELAY - bool - default y - config GENERIC_FIND_NEXT_BIT bool default y @@ -129,6 +125,7 @@ config PPC select USE_GENERIC_SMP_HELPERS if SMP select HAVE_OPROFILE select HAVE_SYSCALL_WRAPPERS if PPC64 + select GENERIC_ATOMIC64 if PPC32 config EARLY_PRINTK bool diff --git a/arch/powerpc/boot/install.sh b/arch/powerpc/boot/install.sh index 51b2387bdba0..98312d169c85 100644 --- a/arch/powerpc/boot/install.sh +++ b/arch/powerpc/boot/install.sh @@ -18,6 +18,9 @@ # $5 and more - kernel boot files; zImage*, uImage, cuImage.*, etc. # +# Bail with error code if anything goes wrong +set -e + # User may have a custom install script if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 7d044dfd9236..12dc7c409616 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -1808,7 +1808,7 @@ CONFIG_PCF8575=m CONFIG_SENSORS_PCA9539=m CONFIG_SENSORS_PCF8591=m # CONFIG_TPS65010 is not set -CONFIG_SENSORS_MAX6875=m +CONFIG_EEPROM_MAX6875=m CONFIG_SENSORS_TSL2550=m CONFIG_MCU_MPC8349EMITX=m # CONFIG_I2C_DEBUG_CORE is not set diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index b7d2d07b6f96..4012483b1899 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -470,6 +470,9 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) +#else /* __powerpc64__ */ +#include <asm-generic/atomic64.h> + #endif /* __powerpc64__ */ #include <asm-generic/atomic-long.h> diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 53512374e1c9..b7f8f4a87cc0 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -80,7 +80,7 @@ static inline void local_irq_disable(void) __asm__ __volatile__("wrteei 0": : :"memory"); #else unsigned long msr; - __asm__ __volatile__("": : :"memory"); + msr = mfmsr(); SET_MSR_EE(msr & ~MSR_EE); #endif @@ -92,7 +92,7 @@ static inline void local_irq_enable(void) __asm__ __volatile__("wrteei 1": : :"memory"); #else unsigned long msr; - __asm__ __volatile__("": : :"memory"); + msr = mfmsr(); SET_MSR_EE(msr | MSR_EE); #endif @@ -108,7 +108,6 @@ static inline void local_irq_save_ptr(unsigned long *flags) #else SET_MSR_EE(msr & ~MSR_EE); #endif - __asm__ __volatile__("": : :"memory"); } #define local_save_flags(flags) ((flags) = mfmsr()) diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index 7464c0daddd1..7ead7c16fb7c 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -35,6 +35,16 @@ #define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1)) #define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE) +/* Cell page table entries */ +#define CBE_IOPTE_PP_W 0x8000000000000000ul /* protection: write */ +#define CBE_IOPTE_PP_R 0x4000000000000000ul /* protection: read */ +#define CBE_IOPTE_M 0x2000000000000000ul /* coherency required */ +#define CBE_IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */ +#define CBE_IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */ +#define CBE_IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */ +#define CBE_IOPTE_H 0x0000000000000800ul /* cache hint */ +#define CBE_IOPTE_IOID_Mask 0x00000000000007fful /* ioid */ + /* Boot time flags */ extern int iommu_is_off; extern int iommu_force_on; diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index cdb6fd814de8..7f065e178ec4 100644 --- a/arch/powerpc/include/asm/ps3.h +++ b/arch/powerpc/include/asm/ps3.h @@ -53,6 +53,13 @@ enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void); extern u64 ps3_os_area_get_rtc_diff(void); extern void ps3_os_area_set_rtc_diff(u64 rtc_diff); +struct ps3_os_area_flash_ops { + ssize_t (*read)(void *buf, size_t count, loff_t pos); + ssize_t (*write)(const void *buf, size_t count, loff_t pos); +}; + +extern void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops); + /* dma routines */ enum ps3_dma_page_size { @@ -418,15 +425,15 @@ static inline struct ps3_system_bus_driver * * @data: Data to set */ -static inline void ps3_system_bus_set_driver_data( +static inline void ps3_system_bus_set_drvdata( struct ps3_system_bus_device *dev, void *data) { - dev->core.driver_data = data; + dev_set_drvdata(&dev->core, data); } -static inline void *ps3_system_bus_get_driver_data( +static inline void *ps3_system_bus_get_drvdata( struct ps3_system_bus_device *dev) { - return dev->core.driver_data; + return dev_get_drvdata(&dev->core); } /* These two need global scope for get_dma_ops(). */ @@ -520,7 +527,4 @@ void ps3_sync_irq(int node); u32 ps3_get_hw_thread_id(int cpu); u64 ps3_get_spe_id(void *arg); -/* mutex synchronizing GPU accesses and video mode changes */ -extern struct mutex ps3_gpu_mutex; - #endif diff --git a/arch/powerpc/include/asm/ps3gpu.h b/arch/powerpc/include/asm/ps3gpu.h new file mode 100644 index 000000000000..b2b89591907c --- /dev/null +++ b/arch/powerpc/include/asm/ps3gpu.h @@ -0,0 +1,86 @@ +/* + * PS3 GPU declarations. + * + * Copyright 2009 Sony Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. + * If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _ASM_POWERPC_PS3GPU_H +#define _ASM_POWERPC_PS3GPU_H + +#include <linux/mutex.h> + +#include <asm/lv1call.h> + + +#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 +#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 + +#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 +#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 +#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602 +#define L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE 0x603 + +#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32) + +#define L1GPU_DISPLAY_SYNC_HSYNC 1 +#define L1GPU_DISPLAY_SYNC_VSYNC 2 + + +/* mutex synchronizing GPU accesses and video mode changes */ +extern struct mutex ps3_gpu_mutex; + + +static inline int lv1_gpu_display_sync(u64 context_handle, u64 head, + u64 ddr_offset) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, + head, ddr_offset, 0, 0); +} + +static inline int lv1_gpu_display_flip(u64 context_handle, u64 head, + u64 ddr_offset) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, + head, ddr_offset, 0, 0); +} + +static inline int lv1_gpu_fb_setup(u64 context_handle, u64 xdr_lpar, + u64 xdr_size, u64 ioif_offset) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, + xdr_lpar, xdr_size, ioif_offset, 0); +} + +static inline int lv1_gpu_fb_blit(u64 context_handle, u64 ddr_offset, + u64 ioif_offset, u64 sync_width, u64 pitch) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, + ddr_offset, ioif_offset, sync_width, + pitch); +} + +static inline int lv1_gpu_fb_close(u64 context_handle) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE, 0, + 0, 0, 0); +} + +#endif /* _ASM_POWERPC_PS3GPU_H */ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index fb359b0a6937..a3c28e46947c 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -745,11 +745,11 @@ asm volatile("mfmsr %0" : "=r" (rval)); rval;}) #ifdef CONFIG_PPC64 #define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \ - : : "r" (v)) + : : "r" (v) : "memory") #define mtmsrd(v) __mtmsrd((v), 0) #define mtmsr(v) mtmsrd(v) #else -#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v)) +#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v) : "memory") #endif #define mfspr(rn) ({unsigned long rval; \ diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index a0b92de51c7e..370600ca2765 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -325,3 +325,4 @@ SYSCALL(inotify_init1) SYSCALL_SPU(perf_counter_open) COMPAT_SYS_SPU(preadv) COMPAT_SYS_SPU(pwritev) +COMPAT_SYS(rt_tgsigqueueinfo) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index 4badac2d11d1..cef080bfc607 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -344,10 +344,11 @@ #define __NR_perf_counter_open 319 #define __NR_preadv 320 #define __NR_pwritev 321 +#define __NR_rt_tgsigqueueinfo 322 #ifdef __KERNEL__ -#define __NR_syscalls 322 +#define __NR_syscalls 323 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index a7def5f90cad..612b0c4dc26d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -125,6 +125,7 @@ PHONY += systbl_chk systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i $(call cmd,systbl_chk) +ifeq ($(CONFIG_PPC_OF_BOOT_TRAMPOLINE),y) $(obj)/built-in.o: prom_init_check quiet_cmd_prom_init_check = CALL $< @@ -133,5 +134,6 @@ quiet_cmd_prom_init_check = CALL $< PHONY += prom_init_check prom_init_check: $(src)/prom_init_check.sh $(obj)/prom_init.o $(call cmd,prom_init_check) +endif clean-files := vmlinux.lds diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index f46548e66045..1f6816003ebe 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -424,8 +424,8 @@ void __init setup_system(void) printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); #endif /* CONFIG_PPC_STD_MMU_64 */ if (PHYSICAL_START > 0) - printk("physical_start = 0x%lx\n", - PHYSICAL_START); + printk("physical_start = 0x%llx\n", + (unsigned long long)PHYSICAL_START); printk("-----------------------------------------------------\n"); DBG(" <- setup_system()\n"); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index bee1443da763..15391c2ab013 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -52,6 +52,7 @@ #include <linux/jiffies.h> #include <linux/posix-timers.h> #include <linux/irq.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/processor.h> @@ -1143,6 +1144,15 @@ void div128_by_32(u64 dividend_high, u64 dividend_low, } +/* We don't need to calibrate delay, we use the CPU timebase for that */ +void calibrate_delay(void) +{ + /* Some generic code (such as spinlock debug) use loops_per_jiffy + * as the number of __delay(1) in a jiffy, so make it so + */ + loops_per_jiffy = tb_ticks_per_jiffy; +} + static int __init rtc_init(void) { struct platform_device *pdev; diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 0ce45c2b42f8..c71498dbf211 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -329,7 +329,7 @@ static struct irq_host_ops msic_host_ops = { static int axon_msi_shutdown(struct of_device *device) { - struct axon_msic *msic = device->dev.platform_data; + struct axon_msic *msic = dev_get_drvdata(&device->dev); u32 tmp; pr_debug("axon_msi: disabling %s\n", @@ -416,7 +416,7 @@ static int axon_msi_probe(struct of_device *device, msic->read_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG) & MSIC_FIFO_SIZE_MASK; - device->dev.platform_data = msic; + dev_set_drvdata(&device->dev, msic); ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs; ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index bed4690de394..5b34fc211f35 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -100,16 +100,6 @@ #define IOSTE_PS_1M 0x0000000000000005ul /* - 1MB */ #define IOSTE_PS_16M 0x0000000000000007ul /* - 16MB */ -/* Page table entries */ -#define IOPTE_PP_W 0x8000000000000000ul /* protection: write */ -#define IOPTE_PP_R 0x4000000000000000ul /* protection: read */ -#define IOPTE_M 0x2000000000000000ul /* coherency required */ -#define IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */ -#define IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */ -#define IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */ -#define IOPTE_H 0x0000000000000800ul /* cache hint */ -#define IOPTE_IOID_Mask 0x00000000000007fful /* ioid */ - /* IOMMU sizing */ #define IO_SEGMENT_SHIFT 28 @@ -193,19 +183,21 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages, */ const unsigned long prot = 0xc48; base_pte = - ((prot << (52 + 4 * direction)) & (IOPTE_PP_W | IOPTE_PP_R)) - | IOPTE_M | IOPTE_SO_RW | (window->ioid & IOPTE_IOID_Mask); + ((prot << (52 + 4 * direction)) & + (CBE_IOPTE_PP_W | CBE_IOPTE_PP_R)) | + CBE_IOPTE_M | CBE_IOPTE_SO_RW | + (window->ioid & CBE_IOPTE_IOID_Mask); #else - base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | - (window->ioid & IOPTE_IOID_Mask); + base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M | + CBE_IOPTE_SO_RW | (window->ioid & CBE_IOPTE_IOID_Mask); #endif if (unlikely(dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))) - base_pte &= ~IOPTE_SO_RW; + base_pte &= ~CBE_IOPTE_SO_RW; io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset); for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE) - io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask); + io_pte[i] = base_pte | (__pa(uaddr) & CBE_IOPTE_RPN_Mask); mb(); @@ -231,8 +223,9 @@ static void tce_free_cell(struct iommu_table *tbl, long index, long npages) #else /* spider bridge does PCI reads after freeing - insert a mapping * to a scratch page instead of an invalid entry */ - pte = IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | __pa(window->iommu->pad_page) - | (window->ioid & IOPTE_IOID_Mask); + pte = CBE_IOPTE_PP_R | CBE_IOPTE_M | CBE_IOPTE_SO_RW | + __pa(window->iommu->pad_page) | + (window->ioid & CBE_IOPTE_IOID_Mask); #endif io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset); @@ -1001,7 +994,7 @@ static void insert_16M_pte(unsigned long addr, unsigned long *ptab, pr_debug("iommu: addr %lx ptab %p segment %lx offset %lx\n", addr, ptab, segment, offset); - ptab[offset] = base_pte | (__pa(addr) & IOPTE_RPN_Mask); + ptab[offset] = base_pte | (__pa(addr) & CBE_IOPTE_RPN_Mask); } static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu, @@ -1016,14 +1009,14 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu, pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase); - base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M - | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask); + base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M | + (cell_iommu_get_ioid(np) & CBE_IOPTE_IOID_Mask); if (iommu_fixed_is_weak) pr_info("IOMMU: Using weak ordering for fixed mapping\n"); else { pr_info("IOMMU: Using strong ordering for fixed mapping\n"); - base_pte |= IOPTE_SO_RW; + base_pte |= CBE_IOPTE_SO_RW; } for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) { diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 4543c4bc3a56..c5a87a72057b 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c @@ -204,7 +204,8 @@ static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name, dt_prop(dt, name, &data, sizeof(u32)); } -static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name, +static void __init __maybe_unused dt_prop_u64(struct iseries_flat_dt *dt, + const char *name, u64 data) { dt_prop(dt, name, &data, sizeof(u64)); diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 3689c2413d24..fef4d5150517 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -267,7 +267,8 @@ static struct pending_event *new_pending_event(void) return ev; } -static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) +static int __maybe_unused +signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) { struct pending_event *ev = new_pending_event(); int rc; diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 9a2b6d948610..846eb8b57fd1 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -24,6 +24,7 @@ #include <linux/lmb.h> #include <asm/firmware.h> +#include <asm/iommu.h> #include <asm/prom.h> #include <asm/udbg.h> #include <asm/lv1call.h> @@ -605,9 +606,8 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, r->ioid, iopte_flag); if (result) { - printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region " - "failed: %s\n", __func__, __LINE__, - ps3_result(result)); + pr_warning("%s:%d: lv1_put_iopte failed: %s\n", + __func__, __LINE__, ps3_result(result)); goto fail_map; } DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__, @@ -1001,7 +1001,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r) if (len > r->len) len = r->len; result = dma_sb_map_area(r, virt_addr, len, &tmp, - IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW | + CBE_IOPTE_M); BUG_ON(result); } @@ -1014,7 +1015,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r) else len -= map.rm.size - r->offset; result = dma_sb_map_area(r, virt_addr, len, &tmp, - IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW | + CBE_IOPTE_M); BUG_ON(result); } diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index cf1cd0f8c18f..d6487a9c8019 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -226,6 +226,44 @@ static struct property property_av_multi_out = { .value = &saved_params.av_multi_out, }; + +static DEFINE_MUTEX(os_area_flash_mutex); + +static const struct ps3_os_area_flash_ops *os_area_flash_ops; + +void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops) +{ + mutex_lock(&os_area_flash_mutex); + os_area_flash_ops = ops; + mutex_unlock(&os_area_flash_mutex); +} +EXPORT_SYMBOL_GPL(ps3_os_area_flash_register); + +static ssize_t os_area_flash_read(void *buf, size_t count, loff_t pos) +{ + ssize_t res = -ENODEV; + + mutex_lock(&os_area_flash_mutex); + if (os_area_flash_ops) + res = os_area_flash_ops->read(buf, count, pos); + mutex_unlock(&os_area_flash_mutex); + + return res; +} + +static ssize_t os_area_flash_write(const void *buf, size_t count, loff_t pos) +{ + ssize_t res = -ENODEV; + + mutex_lock(&os_area_flash_mutex); + if (os_area_flash_ops) + res = os_area_flash_ops->write(buf, count, pos); + mutex_unlock(&os_area_flash_mutex); + + return res; +} + + /** * os_area_set_property - Add or overwrite a saved_params value to the device tree. * @@ -352,12 +390,12 @@ static int db_verify(const struct os_area_db *db) if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM, sizeof(db->magic_num))) { pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); - return -1; + return -EINVAL; } if (db->version != 1) { pr_debug("%s:%d version failed\n", __func__, __LINE__); - return -1; + return -EINVAL; } return 0; @@ -578,59 +616,48 @@ static void os_area_db_init(struct os_area_db *db) * */ -static void __maybe_unused update_flash_db(void) +static int update_flash_db(void) { - int result; - int file; - off_t offset; + const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE; + struct os_area_header *header; ssize_t count; - static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE; - const struct os_area_header *header; + int error; + loff_t pos; struct os_area_db* db; /* Read in header and db from flash. */ - file = sys_open("/dev/ps3flash", O_RDWR, 0); - - if (file < 0) { - pr_debug("%s:%d sys_open failed\n", __func__, __LINE__); - goto fail_open; - } - header = kmalloc(buf_len, GFP_KERNEL); - if (!header) { - pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__); - goto fail_malloc; + pr_debug("%s: kmalloc failed\n", __func__); + return -ENOMEM; } - offset = sys_lseek(file, 0, SEEK_SET); - - if (offset != 0) { - pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); - goto fail_header_seek; + count = os_area_flash_read(header, buf_len, 0); + if (count < 0) { + pr_debug("%s: os_area_flash_read failed %zd\n", __func__, + count); + error = count; + goto fail; } - count = sys_read(file, (char __user *)header, buf_len); - - result = count < OS_AREA_SEGMENT_SIZE || verify_header(header) - || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE; - - if (result) { - pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); + pos = header->db_area_offset * OS_AREA_SEGMENT_SIZE; + if (count < OS_AREA_SEGMENT_SIZE || verify_header(header) || + count < pos) { + pr_debug("%s: verify_header failed\n", __func__); dump_header(header); - goto fail_header; + error = -EINVAL; + goto fail; } /* Now got a good db offset and some maybe good db data. */ - db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE; + db = (void *)header + pos; - result = db_verify(db); - - if (result) { - printk(KERN_NOTICE "%s:%d: Verify of flash database failed, " - "formatting.\n", __func__, __LINE__); + error = db_verify(db); + if (error) { + pr_notice("%s: Verify of flash database failed, formatting.\n", + __func__); dump_db(db); os_area_db_init(db); } @@ -639,29 +666,16 @@ static void __maybe_unused update_flash_db(void) db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff); - offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE, - SEEK_SET); - - if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) { - pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); - goto fail_db_seek; - } - - count = sys_write(file, (const char __user *)db, - sizeof(struct os_area_db)); - + count = os_area_flash_write(db, sizeof(struct os_area_db), pos); if (count < sizeof(struct os_area_db)) { - pr_debug("%s:%d sys_write failed\n", __func__, __LINE__); + pr_debug("%s: os_area_flash_write failed %zd\n", __func__, + count); + error = count < 0 ? count : -EIO; } -fail_db_seek: -fail_header: -fail_header_seek: +fail: kfree(header); -fail_malloc: - sys_close(file); -fail_open: - return; + return error; } /** @@ -674,11 +688,11 @@ fail_open: static void os_area_queue_work_handler(struct work_struct *work) { struct device_node *node; + int error; pr_debug(" -> %s:%d\n", __func__, __LINE__); node = of_find_node_by_path("/"); - if (node) { os_area_set_property(node, &property_rtc_diff); of_node_put(node); @@ -686,12 +700,10 @@ static void os_area_queue_work_handler(struct work_struct *work) pr_debug("%s:%d of_find_node_by_path failed\n", __func__, __LINE__); -#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) - update_flash_db(); -#else - printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n", - __func__, __LINE__); -#endif + error = update_flash_db(); + if (error) + pr_warning("%s: Could not update FLASH ROM\n", __func__); + pr_debug(" <- %s:%d\n", __func__, __LINE__); } @@ -808,7 +820,7 @@ u64 ps3_os_area_get_rtc_diff(void) { return saved_params.rtc_diff; } -EXPORT_SYMBOL(ps3_os_area_get_rtc_diff); +EXPORT_SYMBOL_GPL(ps3_os_area_get_rtc_diff); /** * ps3_os_area_set_rtc_diff - Set the rtc diff value. @@ -824,7 +836,7 @@ void ps3_os_area_set_rtc_diff(u64 rtc_diff) os_area_queue_work(); } } -EXPORT_SYMBOL(ps3_os_area_set_rtc_diff); +EXPORT_SYMBOL_GPL(ps3_os_area_set_rtc_diff); /** * ps3_os_area_get_av_multi_out - Returns the default video mode. diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 136aa0637d9c..9a196a88eda7 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -232,14 +232,4 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index, int ps3_repository_read_vuart_av_port(unsigned int *port); int ps3_repository_read_vuart_sysmgr_port(unsigned int *port); -/* Page table entries */ -#define IOPTE_PP_W 0x8000000000000000ul /* protection: write */ -#define IOPTE_PP_R 0x4000000000000000ul /* protection: read */ -#define IOPTE_M 0x2000000000000000ul /* coherency required */ -#define IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */ -#define IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */ -#define IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */ -#define IOPTE_H 0x0000000000000800ul /* cache hint */ -#define IOPTE_IOID_Mask 0x00000000000007fful /* ioid */ - #endif diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 1a7b5ae0c83e..149bea2ce583 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -32,6 +32,7 @@ #include <asm/udbg.h> #include <asm/prom.h> #include <asm/lv1call.h> +#include <asm/ps3gpu.h> #include "platform.h" diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 9a73d0238639..9fead0faf38b 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -27,6 +27,7 @@ #include <asm/udbg.h> #include <asm/lv1call.h> #include <asm/firmware.h> +#include <asm/iommu.h> #include "platform.h" @@ -531,7 +532,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size, } result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle, - IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | + CBE_IOPTE_SO_RW | CBE_IOPTE_M); if (result) { pr_debug("%s:%d: ps3_dma_map failed (%d)\n", @@ -575,7 +577,8 @@ static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page, result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, &bus_addr, - IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M); + CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | + CBE_IOPTE_SO_RW | CBE_IOPTE_M); if (result) { pr_debug("%s:%d: ps3_dma_map failed (%d)\n", @@ -596,16 +599,16 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page, u64 iopte_flag; void *ptr = page_address(page) + offset; - iopte_flag = IOPTE_M; + iopte_flag = CBE_IOPTE_M; switch (direction) { case DMA_BIDIRECTIONAL: - iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW; + iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW; break; case DMA_TO_DEVICE: - iopte_flag |= IOPTE_PP_R | IOPTE_SO_R; + iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_SO_R; break; case DMA_FROM_DEVICE: - iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW; + iopte_flag |= CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW; break; default: /* not happned */ diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 07e20135f01b..0bba148a2c61 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -139,7 +139,7 @@ acpi_status acpi_ev_initialize_op_regions(void); acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, - acpi_physical_address address, + u32 region_offset, u32 bit_width, acpi_integer * value); acpi_status diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 16e5210ae936..3d87362d17ed 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -362,9 +362,6 @@ extern u8 acpi_gbl_method_executing; extern u8 acpi_gbl_abort_method; extern u8 acpi_gbl_db_terminate_threads; -ACPI_EXTERN int optind; -ACPI_EXTERN char *optarg; - ACPI_EXTERN u8 acpi_gbl_db_opt_tables; ACPI_EXTERN u8 acpi_gbl_db_opt_stats; ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 2ec394a328e9..ee986edfa0da 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -205,6 +205,7 @@ struct acpi_namespace_node { #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ +#define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ #define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */ #define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */ @@ -788,11 +789,14 @@ struct acpi_bit_register_info { /* For control registers, both ignored and reserved bits must be preserved */ /* - * The ACPI spec says to ignore PM1_CTL.SCI_EN (bit 0) - * but we need to be able to write ACPI_BITREG_SCI_ENABLE directly - * as a BIOS workaround on some machines. + * For PM1 control, the SCI enable bit (bit 0, SCI_EN) is defined by the + * ACPI specification to be a "preserved" bit - "OSPM always preserves this + * bit position", section 4.7.3.2.1. However, on some machines the OS must + * write a one to this bit after resume for the machine to work properly. + * To enable this, we no longer attempt to preserve this bit. No machines + * are known to fail if the bit is not preserved. (May 2009) */ -#define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bits 9 */ +#define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bit 9 */ #define ACPI_PM1_CONTROL_RESERVED_BITS 0xC1F8 /* Bits 14-15, 3-8 */ #define ACPI_PM1_CONTROL_PRESERVED_BITS \ (ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS) diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 46cb5b46d280..94cdc2b8cb93 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -99,10 +99,19 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_walk_callback user_function, void *context, void **return_value); -struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node - *parent, struct acpi_namespace_node +struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node + *parent, + struct acpi_namespace_node *child); +struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, + struct + acpi_namespace_node + *parent, + struct + acpi_namespace_node + *child); + /* * nsparse - table parsing */ diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index ff851c5df698..067f967eb389 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -483,7 +483,7 @@ typedef enum { #define AML_METHOD_ARG_COUNT 0x07 #define AML_METHOD_SERIALIZED 0x08 -#define AML_METHOD_SYNCH_LEVEL 0xF0 +#define AML_METHOD_SYNC_LEVEL 0xF0 /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index dab3f48f0b42..02e6caad4a76 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -734,7 +734,8 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */ - obj_desc->reference.value = opcode - AML_LOCAL_OP; + obj_desc->reference.value = + ((u32)opcode) - AML_LOCAL_OP; obj_desc->reference.class = ACPI_REFCLASS_LOCAL; #ifndef ACPI_NO_METHOD_EXECUTION @@ -754,7 +755,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */ - obj_desc->reference.value = opcode - AML_ARG_OP; + obj_desc->reference.value = ((u32)opcode) - AML_ARG_OP; obj_desc->reference.class = ACPI_REFCLASS_ARG; #ifndef ACPI_NO_METHOD_EXECUTION diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index b4c87b5053e6..584d766e6f12 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -1386,14 +1386,19 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, case AML_BREAK_POINT_OP: - /* Call up to the OS service layer to handle this */ - - status = - acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, - "Executed AML Breakpoint opcode"); + /* + * Set the single-step flag. This will cause the debugger (if present) + * to break to the console within the AML debugger at the start of the + * next AML instruction. + */ + ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE); + ACPI_DEBUGGER_EXEC(acpi_os_printf + ("**break** Executed AML BreakPoint opcode\n")); - /* If and when it returns, all done. */ + /* Call to the OSL in case OS wants a piece of the action */ + status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, + "Executed AML Breakpoint opcode"); break; case AML_BREAK_OP: diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 40f92bf7dce5..e46c821cf572 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -102,7 +102,7 @@ acpi_ds_result_pop(union acpi_operand_object **object, /* Return object of the top element and clean that top element result stack */ walk_state->result_count--; - index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; + index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; *object = state->results.obj_desc[index]; if (!*object) { @@ -186,7 +186,7 @@ acpi_ds_result_push(union acpi_operand_object * object, /* Assign the address of object to the top free element of result stack */ - index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; + index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; state->results.obj_desc[index] = object; walk_state->result_count++; diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 538d63264555..98c7f9c62653 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -275,7 +275,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) * * PARAMETERS: region_obj - Internal region object * Function - Read or Write operation - * Address - Where in the space to read or write + * region_offset - Where in the region to read or write * bit_width - Field width in bits (8, 16, 32, or 64) * Value - Pointer to in or out value, must be * full 64-bit acpi_integer @@ -290,7 +290,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, - acpi_physical_address address, + u32 region_offset, u32 bit_width, acpi_integer * value) { acpi_status status; @@ -396,7 +396,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", ®ion_obj->region.handler->address_space, handler, - ACPI_FORMAT_NATIVE_UINT(address), + ACPI_FORMAT_NATIVE_UINT(region_obj->region.address + + region_offset), acpi_ut_get_region_name(region_obj->region. space_id))); @@ -412,8 +413,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* Call the handler */ - status = handler(function, address, bit_width, value, - handler_desc->address_space.context, + status = handler(function, + (region_obj->region.address + region_offset), + bit_width, value, handler_desc->address_space.context, region_obj2->extra.region_context); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index d0a080747ec3..4721f58fe42c 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -51,7 +51,7 @@ ACPI_MODULE_NAME("evxfevnt") /* Local prototypes */ -acpi_status +static acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context); @@ -785,7 +785,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_gpe_device) * block device. NULL if the GPE is one of the FADT-defined GPEs. * ******************************************************************************/ -acpi_status +static acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context) { diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 3deb20a126b2..277fd609611a 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -47,6 +47,7 @@ #include "acnamesp.h" #include "actables.h" #include "acdispat.h" +#include "acevents.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exconfig") @@ -57,6 +58,10 @@ acpi_ex_add_table(u32 table_index, struct acpi_namespace_node *parent_node, union acpi_operand_object **ddb_handle); +static acpi_status +acpi_ex_region_read(union acpi_operand_object *obj_desc, + u32 length, u8 *buffer); + /******************************************************************************* * * FUNCTION: acpi_ex_add_table @@ -91,6 +96,7 @@ acpi_ex_add_table(u32 table_index, /* Init the table handle */ + obj_desc->common.flags |= AOPOBJ_DATA_VALID; obj_desc->reference.class = ACPI_REFCLASS_TABLE; *ddb_handle = obj_desc; @@ -229,6 +235,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, walk_state); if (ACPI_FAILURE(status)) { (void)acpi_ex_unload_table(ddb_handle); + + acpi_ut_remove_reference(ddb_handle); return_ACPI_STATUS(status); } } @@ -254,6 +262,47 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, /******************************************************************************* * + * FUNCTION: acpi_ex_region_read + * + * PARAMETERS: obj_desc - Region descriptor + * Length - Number of bytes to read + * Buffer - Pointer to where to put the data + * + * RETURN: Status + * + * DESCRIPTION: Read data from an operation region. The read starts from the + * beginning of the region. + * + ******************************************************************************/ + +static acpi_status +acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) +{ + acpi_status status; + acpi_integer value; + u32 region_offset = 0; + u32 i; + + /* Bytewise reads */ + + for (i = 0; i < length; i++) { + status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, + region_offset, 8, + &value); + if (ACPI_FAILURE(status)) { + return status; + } + + *buffer = (u8)value; + buffer++; + region_offset++; + } + + return AE_OK; +} + +/******************************************************************************* + * * FUNCTION: acpi_ex_load_op * * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be @@ -314,18 +363,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } } - /* - * Map the table header and get the actual table length. The region - * length is not guaranteed to be the same as the table length. - */ - table = acpi_os_map_memory(obj_desc->region.address, - sizeof(struct acpi_table_header)); + /* Get the table header first so we can get the table length */ + + table = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); if (!table) { return_ACPI_STATUS(AE_NO_MEMORY); } + status = + acpi_ex_region_read(obj_desc, + sizeof(struct acpi_table_header), + ACPI_CAST_PTR(u8, table)); length = table->length; - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); + ACPI_FREE(table); + + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } /* Must have at least an ACPI table header */ @@ -334,10 +388,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } /* - * The memory region is not guaranteed to remain stable and we must - * copy the table to a local buffer. For example, the memory region - * is corrupted after suspend on some machines. Dynamically loaded - * tables are usually small, so this overhead is minimal. + * The original implementation simply mapped the table, with no copy. + * However, the memory region is not guaranteed to remain stable and + * we must copy the table to a local buffer. For example, the memory + * region is corrupted after suspend on some machines. Dynamically + * loaded tables are usually small, so this overhead is minimal. + * + * The latest implementation (5/2009) does not use a mapping at all. + * We use the low-level operation region interface to read the table + * instead of the obvious optimization of using a direct mapping. + * This maintains a consistent use of operation regions across the + * entire subsystem. This is important if additional processing must + * be performed in the (possibly user-installed) operation region + * handler. For example, acpi_exec and ASLTS depend on this. */ /* Allocate a buffer for the table */ @@ -347,17 +410,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_NO_MEMORY); } - /* Map the entire table and copy it */ + /* Read the entire table */ - table = acpi_os_map_memory(obj_desc->region.address, length); - if (!table) { + status = acpi_ex_region_read(obj_desc, length, + ACPI_CAST_PTR(u8, + table_desc.pointer)); + if (ACPI_FAILURE(status)) { ACPI_FREE(table_desc.pointer); - return_ACPI_STATUS(AE_NO_MEMORY); + return_ACPI_STATUS(status); } - ACPI_MEMCPY(table_desc.pointer, table, length); - acpi_os_unmap_memory(table, length); - table_desc.address = obj_desc->region.address; break; @@ -454,6 +516,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } + /* Remove the reference by added by acpi_ex_store above */ + + acpi_ut_remove_reference(ddb_handle); + /* Invoke table handler if present */ if (acpi_gbl_table_handler) { @@ -495,13 +561,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) /* * Validate the handle - * Although the handle is partially validated in acpi_ex_reconfiguration(), + * Although the handle is partially validated in acpi_ex_reconfiguration() * when it calls acpi_ex_resolve_operands(), the handle is more completely * validated here. + * + * Handle must be a valid operand object of type reference. Also, the + * ddb_handle must still be marked valid (table has not been previously + * unloaded) */ if ((!ddb_handle) || (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || - (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE)) { + (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) || + (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -509,6 +580,12 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) table_index = table_desc->reference.value; + /* Ensure the table is still loaded */ + + if (!acpi_tb_is_table_loaded(table_index)) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + /* Invoke table handler if present */ if (acpi_gbl_table_handler) { @@ -530,8 +607,10 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) (void)acpi_tb_release_owner_id(table_index); acpi_tb_set_table_loaded_flag(table_index, FALSE); - /* Table unloaded, remove a reference to the ddb_handle object */ - - acpi_ut_remove_reference(ddb_handle); + /* + * Invalidate the handle. We do this because the handle may be stored + * in a named object and may not be actually deleted until much later. + */ + ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID; return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index a57ad2564ab0..02b25d233d99 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -502,7 +502,7 @@ acpi_ex_create_method(u8 * aml_start, * ACPI 2.0: sync_level = sync_level in method declaration */ obj_desc->method.sync_level = (u8) - ((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4); + ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); } /* Attach the new object to the method Node */ diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 89d141fdae0b..ec524614e708 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -120,9 +120,11 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = { {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"} }; -static struct acpi_exdump_info acpi_ex_dump_method[8] = { +static struct acpi_exdump_info acpi_ex_dump_method[9] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, - {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), + "Parameter Count"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 99cee61e655d..d4075b821021 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -222,7 +222,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, { acpi_status status; union acpi_operand_object *rgn_desc; - acpi_physical_address address; + u32 region_offset; ACPI_FUNCTION_TRACE(ex_access_region); @@ -243,7 +243,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, * 3) The current offset into the field */ rgn_desc = obj_desc->common_field.region_obj; - address = rgn_desc->region.address + + region_offset = obj_desc->common_field.base_byte_offset + field_datum_byte_offset; if ((function & ACPI_IO_MASK) == ACPI_READ) { @@ -260,16 +260,18 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, field_datum_byte_offset, ACPI_CAST_PTR(void, - address))); + (rgn_desc-> + region. + address + + region_offset)))); /* Invoke the appropriate address_space/op_region handler */ - status = acpi_ev_address_space_dispatch(rgn_desc, function, - address, - ACPI_MUL_8(obj_desc-> - common_field. - access_byte_width), - value); + status = + acpi_ev_address_space_dispatch(rgn_desc, function, region_offset, + ACPI_MUL_8(obj_desc->common_field. + access_byte_width), + value); if (ACPI_FAILURE(status)) { if (status == AE_NOT_IMPLEMENTED) { diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index d301c1f363ef..2f0114202b05 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -83,6 +83,15 @@ void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) if (obj_desc->mutex.prev) { (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; + + /* + * Migrate the previous sync level associated with this mutex to the + * previous mutex on the list so that it may be preserved. This handles + * the case where several mutexes have been acquired at the same level, + * but are not released in opposite order. + */ + (obj_desc->mutex.prev)->mutex.original_sync_level = + obj_desc->mutex.original_sync_level; } else { thread->acquired_mutex_list = obj_desc->mutex.next; } @@ -349,6 +358,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; + u8 previous_sync_level; ACPI_FUNCTION_TRACE(ex_release_mutex); @@ -373,11 +383,12 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, walk_state->thread->thread_id) && (obj_desc != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, - "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", - (unsigned long)walk_state->thread->thread_id, + "Thread %p cannot release Mutex [%4.4s] acquired by thread %p", + ACPI_CAST_PTR(void, walk_state->thread->thread_id), acpi_ut_get_node_name(obj_desc->mutex.node), - (unsigned long)obj_desc->mutex.owner_thread-> - thread_id)); + ACPI_CAST_PTR(void, + obj_desc->mutex.owner_thread-> + thread_id))); return_ACPI_STATUS(AE_AML_NOT_OWNER); } @@ -391,10 +402,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, } /* - * The sync level of the mutex must be less than or equal to the current - * sync level + * The sync level of the mutex must be equal to the current sync level. In + * other words, the current level means that at least one mutex at that + * level is currently being held. Attempting to release a mutex of a + * different level can only mean that the mutex ordering rule is being + * violated. This behavior is clarified in ACPI 4.0 specification. */ - if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { + if (obj_desc->mutex.sync_level != + walk_state->thread->current_sync_level) { ACPI_ERROR((AE_INFO, "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d", acpi_ut_get_node_name(obj_desc->mutex.node), @@ -403,14 +418,24 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } + /* + * Get the previous sync_level from the head of the acquired mutex list. + * This handles the case where several mutexes at the same level have been + * acquired, but are not released in reverse order. + */ + previous_sync_level = + walk_state->thread->acquired_mutex_list->mutex.original_sync_level; + status = acpi_ex_release_mutex_object(obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } if (obj_desc->mutex.acquisition_depth == 0) { - /* Restore the original sync_level */ + /* Restore the previous sync_level */ - walk_state->thread->current_sync_level = - obj_desc->mutex.original_sync_level; + walk_state->thread->current_sync_level = previous_sync_level; } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 90d606196c99..6efd07a4f779 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -193,10 +193,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, case ACPI_REFCLASS_TABLE: + /* Case for ddb_handle */ + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "Table Index 0x%X\n", source_desc->reference.value)); - break; + return; default: break; diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 7b2fb602b5cb..23d5505cb1f7 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -81,9 +81,9 @@ acpi_status acpi_hw_clear_acpi_status(void) ACPI_FUNCTION_TRACE(hw_clear_acpi_status); - ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %0llX\n", + ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", ACPI_BITMASK_ALL_FIXED_STATUS, - acpi_gbl_xpm1a_status.address)); + ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index aceb93111967..efc971ab7d65 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -334,9 +334,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) /* Get the next node in this scope (NULL if none) */ - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = acpi_ns_get_next_node(parent_node, child_node); if (child_node) { /* Found a child node - detach any attached object */ @@ -345,8 +343,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) /* Check if this node has any children */ - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + if (child_node->child) { /* * There is at least one child of this node, * visit the node @@ -432,9 +429,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) * Get the next child of this parent node. When child_node is NULL, * the first child of the parent is returned */ - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = acpi_ns_get_next_node(parent_node, child_node); if (deletion_node) { acpi_ns_delete_children(deletion_node); @@ -452,8 +447,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) /* Check if this node has any children */ - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + if (child_node->child) { /* * There is at least one child of this node, * visit the node diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index ae3dc10a7e81..af8e6bcee07e 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -149,7 +149,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) name_buffer = ACPI_ALLOCATE_ZEROED(size); if (!name_buffer) { - ACPI_ERROR((AE_INFO, "Allocation failure")); + ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); return_PTR(NULL); } diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 3eb20bfda9d8..60f3af08d28c 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -213,6 +213,15 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node) return_VOID; } + if (node->flags & ANOBJ_ALLOCATED_BUFFER) { + + /* Free the dynamic aml buffer */ + + if (obj_desc->common.type == ACPI_TYPE_METHOD) { + ACPI_FREE(obj_desc->method.aml_start); + } + } + /* Clear the entry in all cases */ node->object = NULL; diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index d9e8cbc6e679..7f8e066b12a3 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -144,7 +144,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, pathname = acpi_ns_get_external_pathname(node); if (!pathname) { - pathname = ACPI_CAST_PTR(char, predefined->info.name); + return AE_OK; /* Could not get pathname, ignore */ } /* @@ -230,10 +230,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, } exit: - if (pathname != predefined->info.name) { - ACPI_FREE(pathname); - } - + ACPI_FREE(pathname); return (status); } diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index f9b4f51bf8f2..7e865639a928 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -45,6 +45,10 @@ #include "accommon.h" #include "acnamesp.h" +#ifdef ACPI_ASL_COMPILER +#include "amlcode.h" +#endif + #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nssearch") diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 83e3aa6d4b9b..35539df5c75d 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -52,8 +52,7 @@ ACPI_MODULE_NAME("nswalk") * * FUNCTION: acpi_ns_get_next_node * - * PARAMETERS: Type - Type of node to be searched for - * parent_node - Parent node whose children we are + * PARAMETERS: parent_node - Parent node whose children we are * getting * child_node - Previous child that was found. * The NEXT child will be returned @@ -66,27 +65,68 @@ ACPI_MODULE_NAME("nswalk") * within Scope is returned. * ******************************************************************************/ -struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node - *parent_node, struct acpi_namespace_node +struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node + *parent_node, + struct acpi_namespace_node *child_node) { - struct acpi_namespace_node *next_node = NULL; - ACPI_FUNCTION_ENTRY(); if (!child_node) { /* It's really the parent's _scope_ that we want */ - next_node = parent_node->child; + return parent_node->child; } - else { - /* Start search at the NEXT node */ - - next_node = acpi_ns_get_next_valid_node(child_node); + /* + * Get the next node. + * + * If we are at the end of this peer list, return NULL + */ + if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { + return NULL; } + /* Otherwise just return the next peer */ + + return child_node->peer; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_next_node_typed + * + * PARAMETERS: Type - Type of node to be searched for + * parent_node - Parent node whose children we are + * getting + * child_node - Previous child that was found. + * The NEXT child will be returned + * + * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if + * none is found. + * + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node + * within Scope is returned. + * + ******************************************************************************/ + +struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, + struct + acpi_namespace_node + *parent_node, + struct + acpi_namespace_node + *child_node) +{ + struct acpi_namespace_node *next_node = NULL; + + ACPI_FUNCTION_ENTRY(); + + next_node = acpi_ns_get_next_node(parent_node, child_node); + + /* If any type is OK, we are done */ if (type == ACPI_TYPE_ANY) { @@ -186,9 +226,7 @@ acpi_ns_walk_namespace(acpi_object_type type, /* Get the next node in this scope. Null if not found */ status = AE_OK; - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = acpi_ns_get_next_node(parent_node, child_node); if (child_node) { /* Found next child, get the type if we are not searching for ANY */ @@ -269,8 +307,7 @@ acpi_ns_walk_namespace(acpi_object_type type, * function has specified that the maximum depth has been reached. */ if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + if (child_node->child) { /* There is at least one child of this node, visit it */ diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 9589fea24997..f23593d6add4 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -45,6 +45,8 @@ #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfname") @@ -358,3 +360,151 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) } ACPI_EXPORT_SYMBOL(acpi_get_object_info) + +/****************************************************************************** + * + * FUNCTION: acpi_install_method + * + * PARAMETERS: Buffer - An ACPI table containing one control method + * + * RETURN: Status + * + * DESCRIPTION: Install a control method into the namespace. If the method + * name already exists in the namespace, it is overwritten. The + * input buffer must contain a valid DSDT or SSDT containing a + * single control method. + * + ******************************************************************************/ +acpi_status acpi_install_method(u8 *buffer) +{ + struct acpi_table_header *table = + ACPI_CAST_PTR(struct acpi_table_header, buffer); + u8 *aml_buffer; + u8 *aml_start; + char *path; + struct acpi_namespace_node *node; + union acpi_operand_object *method_obj; + struct acpi_parse_state parser_state; + u32 aml_length; + u16 opcode; + u8 method_flags; + acpi_status status; + + /* Parameter validation */ + + if (!buffer) { + return AE_BAD_PARAMETER; + } + + /* Table must be a DSDT or SSDT */ + + if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) && + !ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { + return AE_BAD_HEADER; + } + + /* First AML opcode in the table must be a control method */ + + parser_state.aml = buffer + sizeof(struct acpi_table_header); + opcode = acpi_ps_peek_opcode(&parser_state); + if (opcode != AML_METHOD_OP) { + return AE_BAD_PARAMETER; + } + + /* Extract method information from the raw AML */ + + parser_state.aml += acpi_ps_get_opcode_size(opcode); + parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state); + path = acpi_ps_get_next_namestring(&parser_state); + method_flags = *parser_state.aml++; + aml_start = parser_state.aml; + aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); + + /* + * Allocate resources up-front. We don't want to have to delete a new + * node from the namespace if we cannot allocate memory. + */ + aml_buffer = ACPI_ALLOCATE(aml_length); + if (!aml_buffer) { + return AE_NO_MEMORY; + } + + method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); + if (!method_obj) { + ACPI_FREE(aml_buffer); + return AE_NO_MEMORY; + } + + /* Lock namespace for acpi_ns_lookup, we may be creating a new node */ + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto error_exit; + } + + /* The lookup either returns an existing node or creates a new one */ + + status = + acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, + ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, + NULL, &node); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE(status)) { /* ns_lookup */ + if (status != AE_ALREADY_EXISTS) { + goto error_exit; + } + + /* Node existed previously, make sure it is a method node */ + + if (node->type != ACPI_TYPE_METHOD) { + status = AE_TYPE; + goto error_exit; + } + } + + /* Copy the method AML to the local buffer */ + + ACPI_MEMCPY(aml_buffer, aml_start, aml_length); + + /* Initialize the method object with the new method's information */ + + method_obj->method.aml_start = aml_buffer; + method_obj->method.aml_length = aml_length; + + method_obj->method.param_count = (u8) + (method_flags & AML_METHOD_ARG_COUNT); + + method_obj->method.method_flags = (u8) + (method_flags & ~AML_METHOD_ARG_COUNT); + + if (method_flags & AML_METHOD_SERIALIZED) { + method_obj->method.sync_level = (u8) + ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); + } + + /* + * Now that it is complete, we can attach the new method object to + * the method Node (detaches/deletes any existing object) + */ + status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD); + + /* + * Flag indicates AML buffer is dynamic, must be deleted later. + * Must be set only after attach above. + */ + node->flags |= ANOBJ_ALLOCATED_BUFFER; + + /* Remove local reference to the method object */ + + acpi_ut_remove_reference(method_obj); + return status; + +error_exit: + + ACPI_FREE(aml_buffer); + ACPI_FREE(method_obj); + return status; +} +ACPI_EXPORT_SYMBOL(acpi_install_method) diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 1c7efc15225f..4071bad4458e 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -162,6 +162,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_type) acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) { struct acpi_namespace_node *node; + struct acpi_namespace_node *parent_node; acpi_status status; if (!ret_handle) { @@ -189,12 +190,12 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) /* Get the parent entry */ - *ret_handle = - acpi_ns_convert_entry_to_handle(acpi_ns_get_parent_node(node)); + parent_node = acpi_ns_get_parent_node(node); + *ret_handle = acpi_ns_convert_entry_to_handle(parent_node); /* Return exception if parent is null */ - if (!acpi_ns_get_parent_node(node)) { + if (!parent_node) { status = AE_NULL_ENTRY; } @@ -268,7 +269,7 @@ acpi_get_next_object(acpi_object_type type, /* Internal function does the real work */ - node = acpi_ns_get_next_node(type, parent_node, child_node); + node = acpi_ns_get_next_node_typed(type, parent_node, child_node); if (!node) { status = AE_NOT_FOUND; goto unlock_and_exit; diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 88b5a2c4814d..3c4dcc3d1069 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -547,7 +547,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, if (!package_element || (package_element->common.type != ACPI_TYPE_PACKAGE)) { - return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } /* @@ -593,9 +593,6 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, } else { temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node); - if (!temp_size_needed) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } } } else { /* diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 69a2aa5b5d83..395212bcd19b 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -338,13 +338,17 @@ acpi_resource_to_address64(struct acpi_resource *resource, switch (resource->type) { case ACPI_RESOURCE_TYPE_ADDRESS16: - address16 = (struct acpi_resource_address16 *)&resource->data; + address16 = + ACPI_CAST_PTR(struct acpi_resource_address16, + &resource->data); ACPI_COPY_ADDRESS(out, address16); break; case ACPI_RESOURCE_TYPE_ADDRESS32: - address32 = (struct acpi_resource_address32 *)&resource->data; + address32 = + ACPI_CAST_PTR(struct acpi_resource_address32, + &resource->data); ACPI_COPY_ADDRESS(out, address32); break; diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 71e655d14cb0..82b02dcb942e 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -284,9 +284,9 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) if (length > sizeof(struct acpi_table_fadt)) { ACPI_WARNING((AE_INFO, "FADT (revision %u) is longer than ACPI 2.0 version, " - "truncating length 0x%X to 0x%zX", - table->revision, (unsigned)length, - sizeof(struct acpi_table_fadt))); + "truncating length 0x%X to 0x%X", + table->revision, length, + (u32)sizeof(struct acpi_table_fadt))); } /* Clear the entire local FADT */ @@ -441,7 +441,7 @@ static void acpi_tb_convert_fadt(void) &acpi_gbl_FADT, fadt_info_table [i].length), - address32); + (u64) address32); } } } @@ -469,7 +469,6 @@ static void acpi_tb_convert_fadt(void) static void acpi_tb_validate_fadt(void) { char *name; - u32 *address32; struct acpi_generic_address *address64; u8 length; u32 i; @@ -505,15 +504,12 @@ static void acpi_tb_validate_fadt(void) for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { /* - * Generate pointers to the 32-bit and 64-bit addresses, get the - * register length (width), and the register name + * Generate pointer to the 64-bit address, get the register + * length (width) and the register name */ address64 = ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, fadt_info_table[i].address64); - address32 = - ACPI_ADD_PTR(u32, &acpi_gbl_FADT, - fadt_info_table[i].address32); length = *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, fadt_info_table[i].length); diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index f865d5a096de..63e82329a9e8 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -472,7 +472,7 @@ acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) * lock may block, and also since the execution of a namespace walk * must be allowed to use the interpreter. */ - acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); + (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); acpi_ns_delete_namespace_by_owner(owner_id); diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 919624f123d5..0f0c64bf8ac9 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -676,6 +676,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, { u16 reference_count; union acpi_operand_object *next_object; + acpi_status status; /* Save fields from destination that we don't want to overwrite */ @@ -768,6 +769,28 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, } break; + /* + * For Mutex and Event objects, we cannot simply copy the underlying + * OS object. We must create a new one. + */ + case ACPI_TYPE_MUTEX: + + status = acpi_os_create_mutex(&dest_desc->mutex.os_mutex); + if (ACPI_FAILURE(status)) { + return status; + } + break; + + case ACPI_TYPE_EVENT: + + status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, + &dest_desc->event. + os_semaphore); + if (ACPI_FAILURE(status)) { + return status; + } + break; + default: /* Nothing to do for other simple objects */ break; diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 38821f53042c..527d729f6815 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -179,9 +179,9 @@ acpi_debug_print(u32 requested_debug_level, if (thread_id != acpi_gbl_prev_thread_id) { if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf - ("\n**** Context Switch from TID %lX to TID %lX ****\n\n", - (unsigned long)acpi_gbl_prev_thread_id, - (unsigned long)thread_id); + ("\n**** Context Switch from TID %p to TID %p ****\n\n", + ACPI_CAST_PTR(void, acpi_gbl_prev_thread_id), + ACPI_CAST_PTR(void, thread_id)); } acpi_gbl_prev_thread_id = thread_id; @@ -194,7 +194,7 @@ acpi_debug_print(u32 requested_debug_level, acpi_os_printf("%8s-%04ld ", module_name, line_number); if (ACPI_LV_THREADS & acpi_dbg_level) { - acpi_os_printf("[%04lX] ", (unsigned long)thread_id); + acpi_os_printf("[%p] ", ACPI_CAST_PTR(void, thread_id)); } acpi_os_printf("[%02ld] %-22.22s: ", diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index a5ee23bc4f55..bc1710315088 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) union acpi_operand_object *handler_desc; union acpi_operand_object *second_desc; union acpi_operand_object *next_desc; + union acpi_operand_object **last_obj_ptr; ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); @@ -223,6 +224,26 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) */ handler_desc = object->region.handler; if (handler_desc) { + next_desc = + handler_desc->address_space.region_list; + last_obj_ptr = + &handler_desc->address_space.region_list; + + /* Remove the region object from the handler's list */ + + while (next_desc) { + if (next_desc == object) { + *last_obj_ptr = + next_desc->region.next; + break; + } + + /* Walk the linked list of handler */ + + last_obj_ptr = &next_desc->region.next; + next_desc = next_desc->region.next; + } + if (handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 1c9e250caefb..fbe782348b0b 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -1033,11 +1033,12 @@ acpi_error(const char *module_name, u32 line_number, const char *format, ...) { va_list args; - acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number); + acpi_os_printf("ACPI Error: "); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, + line_number); va_end(args); } @@ -1047,12 +1048,12 @@ acpi_exception(const char *module_name, { va_list args; - acpi_os_printf("ACPI Exception (%s-%04d): %s, ", module_name, - line_number, acpi_format_exception(status)); + acpi_os_printf("ACPI Exception: %s, ", acpi_format_exception(status)); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, + line_number); va_end(args); } @@ -1061,11 +1062,12 @@ acpi_warning(const char *module_name, u32 line_number, const char *format, ...) { va_list args; - acpi_os_printf("ACPI Warning (%s-%04d): ", module_name, line_number); + acpi_os_printf("ACPI Warning: "); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, + line_number); va_end(args); } @@ -1074,10 +1076,6 @@ acpi_info(const char *module_name, u32 line_number, const char *format, ...) { va_list args; - /* - * Removed module_name, line_number, and acpica version, not needed - * for info output - */ acpi_os_printf("ACPI: "); va_start(args, format); diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 26c93a748e64..80bb65154117 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -230,17 +230,18 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { if (i == mutex_id) { ACPI_ERROR((AE_INFO, - "Mutex [%s] already acquired by this thread [%X]", + "Mutex [%s] already acquired by this thread [%p]", acpi_ut_get_mutex_name (mutex_id), - this_thread_id)); + ACPI_CAST_PTR(void, + this_thread_id))); return (AE_ALREADY_ACQUIRED); } ACPI_ERROR((AE_INFO, - "Invalid acquire order: Thread %X owns [%s], wants [%s]", - this_thread_id, + "Invalid acquire order: Thread %p owns [%s], wants [%s]", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(i), acpi_ut_get_mutex_name(mutex_id))); @@ -251,24 +252,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) #endif ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %lX attempting to acquire Mutex [%s]\n", - (unsigned long)this_thread_id, + "Thread %p attempting to acquire Mutex [%s]\n", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(mutex_id))); status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS(status)) { ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %lX acquired Mutex [%s]\n", - (unsigned long)this_thread_id, + "Thread %p acquired Mutex [%s]\n", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(mutex_id))); acpi_gbl_mutex_info[mutex_id].use_count++; acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; } else { ACPI_EXCEPTION((AE_INFO, status, - "Thread %lX could not acquire Mutex [%X]", - (unsigned long)this_thread_id, mutex_id)); + "Thread %p could not acquire Mutex [%X]", + ACPI_CAST_PTR(void, this_thread_id), mutex_id)); } return (status); @@ -293,9 +294,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) ACPI_FUNCTION_NAME(ut_release_mutex); this_thread_id = acpi_os_get_thread_id(); - ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %lX releasing Mutex [%s]\n", - (unsigned long)this_thread_id, + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index aaeeb544228a..34cbb7f3efa8 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -120,7 +120,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, struct request *req) { - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); int write = rq_data_dir(req), res; const char *op = write ? "write" : "read"; u64 start_sector, sectors; @@ -168,7 +168,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, struct request *req) { - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); u64 res; dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__); @@ -213,7 +213,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, static void ps3disk_request(struct request_queue *q) { struct ps3_storage_device *dev = q->queuedata; - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); if (priv->req) { dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__); @@ -245,7 +245,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) return IRQ_HANDLED; } - priv = dev->sbd.core.driver_data; + priv = ps3_system_bus_get_drvdata(&dev->sbd); req = priv->req; if (!req) { dev_dbg(&dev->sbd.core, @@ -364,7 +364,7 @@ static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, static int ps3disk_identify(struct ps3_storage_device *dev) { - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); struct lv1_ata_cmnd_block ata_cmnd; u16 *id = dev->bounce_buf; u64 res; @@ -445,7 +445,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) goto fail; } - dev->sbd.core.driver_data = priv; + ps3_system_bus_set_drvdata(_dev, priv); spin_lock_init(&priv->lock); dev->bounce_size = BOUNCE_SIZE; @@ -523,7 +523,7 @@ fail_free_bounce: kfree(dev->bounce_buf); fail_free_priv: kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(_dev, NULL); fail: mutex_lock(&ps3disk_mask_mutex); __clear_bit(devidx, &ps3disk_mask); @@ -534,7 +534,7 @@ fail: static int ps3disk_remove(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); mutex_lock(&ps3disk_mask_mutex); __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS, @@ -548,7 +548,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev) ps3stor_teardown(dev); kfree(dev->bounce_buf); kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(_dev, NULL); return 0; } diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 8eddef373a91..095f97e60665 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -14,8 +14,10 @@ #include <linux/seq_file.h> #include <asm/firmware.h> +#include <asm/iommu.h> #include <asm/lv1call.h> #include <asm/ps3.h> +#include <asm/ps3gpu.h> #define DEVICE_NAME "ps3vram" @@ -45,8 +47,6 @@ #define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c #define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 - #define CACHE_PAGE_PRESENT 1 #define CACHE_PAGE_DIRTY 2 @@ -72,8 +72,7 @@ struct ps3vram_priv { u64 memory_handle; u64 context_handle; u32 *ctrl; - u32 *reports; - u8 __iomem *ddr_base; + void *reports; u8 *xdr_buf; u32 *fifo_base; @@ -81,8 +80,8 @@ struct ps3vram_priv { struct ps3vram_cache cache; - /* Used to serialize cache/DMA operations */ - struct mutex lock; + spinlock_t lock; /* protecting list of bios */ + struct bio_list list; }; @@ -103,15 +102,15 @@ static char *size = "256M"; module_param(size, charp, 0); MODULE_PARM_DESC(size, "memory size"); -static u32 *ps3vram_get_notifier(u32 *reports, int notifier) +static u32 *ps3vram_get_notifier(void *reports, int notifier) { - return (void *)reports + DMA_NOTIFIER_OFFSET_BASE + + return reports + DMA_NOTIFIER_OFFSET_BASE + DMA_NOTIFIER_SIZE * notifier; } static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); int i; @@ -122,7 +121,7 @@ static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, unsigned int timeout_ms) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); @@ -137,7 +136,7 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, static void ps3vram_init_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; @@ -146,7 +145,7 @@ static void ps3vram_init_ring(struct ps3_system_bus_device *dev) static int ps3vram_wait_ring(struct ps3_system_bus_device *dev, unsigned int timeout_ms) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); do { @@ -175,7 +174,7 @@ static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag, static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int status; ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); @@ -183,20 +182,17 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; /* asking the HV for a blit will kick the FIFO */ - status = lv1_gpu_context_attribute(priv->context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, - 0, 0, 0); + status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0); if (status) - dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed %d\n", __func__, - status); + dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n", + __func__, status); priv->fifo_ptr = priv->fifo_base; } static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int status; mutex_lock(&ps3_gpu_mutex); @@ -205,13 +201,10 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) (priv->fifo_ptr - priv->fifo_base) * sizeof(u32); /* asking the HV for a blit will kick the FIFO */ - status = lv1_gpu_context_attribute(priv->context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, - 0, 0, 0); + status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0); if (status) - dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed %d\n", __func__, - status); + dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n", + __func__, status); if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) > FIFO_SIZE - 1024) { @@ -225,7 +218,7 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) static void ps3vram_bind(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); ps3vram_out_ring(priv, 0x31337303); @@ -248,7 +241,7 @@ static int ps3vram_upload(struct ps3_system_bus_device *dev, unsigned int src_offset, unsigned int dst_offset, int len, int count) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -280,7 +273,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, unsigned int src_offset, unsigned int dst_offset, int len, int count) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -310,7 +303,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY)) @@ -332,7 +325,7 @@ static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, unsigned int address) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address); @@ -352,7 +345,7 @@ static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; int i; @@ -366,7 +359,7 @@ static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, loff_t address) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; unsigned int base; unsigned int offset; @@ -400,7 +393,7 @@ static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, static int ps3vram_cache_init(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); priv->cache.page_count = CACHE_PAGE_COUNT; priv->cache.page_size = CACHE_PAGE_SIZE; @@ -419,7 +412,7 @@ static int ps3vram_cache_init(struct ps3_system_bus_device *dev) static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_cache_flush(dev); kfree(priv->cache.tags); @@ -428,7 +421,7 @@ static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); unsigned int cached, count; dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__, @@ -449,8 +442,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, offset = (unsigned int) (from & (priv->cache.page_size - 1)); avail = priv->cache.page_size - offset; - mutex_lock(&priv->lock); - entry = ps3vram_cache_match(dev, from); cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; @@ -462,8 +453,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, avail = count; memcpy(buf, priv->xdr_buf + cached, avail); - mutex_unlock(&priv->lock); - buf += avail; count -= avail; from += avail; @@ -476,7 +465,7 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); unsigned int cached, count; if (to >= priv->size) @@ -494,8 +483,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, offset = (unsigned int) (to & (priv->cache.page_size - 1)); avail = priv->cache.page_size - offset; - mutex_lock(&priv->lock); - entry = ps3vram_cache_match(dev, to); cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; @@ -509,8 +496,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY; - mutex_unlock(&priv->lock); - buf += avail; count -= avail; to += avail; @@ -543,28 +528,26 @@ static const struct file_operations ps3vram_proc_fops = { static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct proc_dir_entry *pde; - pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops); - if (!pde) { + pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops, + priv); + if (!pde) dev_warn(&dev->core, "failed to create /proc entry\n"); - return; - } - pde->data = priv; } -static int ps3vram_make_request(struct request_queue *q, struct bio *bio) +static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, + struct bio *bio) { - struct ps3_system_bus_device *dev = q->queuedata; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int write = bio_data_dir(bio) == WRITE; const char *op = write ? "write" : "read"; loff_t offset = bio->bi_sector << 9; int error = 0; struct bio_vec *bvec; unsigned int i; - - dev_dbg(&dev->core, "%s\n", __func__); + struct bio *next; bio_for_each_segment(bvec, bio, i) { /* PS3 is ppc64, so we don't handle highmem */ @@ -585,6 +568,7 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) if (retlen != len) { dev_err(&dev->core, "Short %s\n", op); + error = -EIO; goto out; } @@ -594,7 +578,35 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) dev_dbg(&dev->core, "%s completed\n", op); out: + spin_lock_irq(&priv->lock); + bio_list_pop(&priv->list); + next = bio_list_peek(&priv->list); + spin_unlock_irq(&priv->lock); + bio_endio(bio, error); + return next; +} + +static int ps3vram_make_request(struct request_queue *q, struct bio *bio) +{ + struct ps3_system_bus_device *dev = q->queuedata; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); + int busy; + + dev_dbg(&dev->core, "%s\n", __func__); + + spin_lock_irq(&priv->lock); + busy = !bio_list_empty(&priv->list); + bio_list_add(&priv->list, bio); + spin_unlock_irq(&priv->lock); + + if (busy) + return 0; + + do { + bio = ps3vram_do_bio(dev, bio); + } while (bio); + return 0; } @@ -604,8 +616,8 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) int error, status; struct request_queue *queue; struct gendisk *gendisk; - u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size, - reports_size; + u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, + reports_size, xdr_lpar; char *rest; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -614,10 +626,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) goto fail; } - mutex_init(&priv->lock); - dev->core.driver_data = priv; - - priv = dev->core.driver_data; + spin_lock_init(&priv->lock); + bio_list_init(&priv->list); + ps3_system_bus_set_drvdata(dev, priv); /* Allocate XDR buffer (1MiB aligned) */ priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, @@ -636,7 +647,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) if (ps3_open_hv_device(dev)) { dev_err(&dev->core, "ps3_open_hv_device failed\n"); error = -EAGAIN; - goto out_close_gpu; + goto out_free_xdr_buf; } /* Request memory */ @@ -660,7 +671,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n", status); error = -ENOMEM; - goto out_free_xdr_buf; + goto out_close_gpu; } /* Request context */ @@ -676,9 +687,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) } /* Map XDR buffer to RSX */ + xdr_lpar = ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)); status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, - ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), - XDR_BUF_SIZE, 0); + xdr_lpar, XDR_BUF_SIZE, + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | + CBE_IOPTE_M); if (status) { dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n", status); @@ -686,19 +699,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) goto out_free_context; } - priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE); - - if (!priv->ddr_base) { - dev_err(&dev->core, "ioremap DDR failed\n"); - error = -ENOMEM; - goto out_free_context; - } - priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); if (!priv->ctrl) { dev_err(&dev->core, "ioremap CTRL failed\n"); error = -ENOMEM; - goto out_unmap_vram; + goto out_unmap_context; } priv->reports = ioremap(reports_lpar, reports_size); @@ -775,8 +780,9 @@ out_unmap_reports: iounmap(priv->reports); out_unmap_ctrl: iounmap(priv->ctrl); -out_unmap_vram: - iounmap(priv->ddr_base); +out_unmap_context: + lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar, + XDR_BUF_SIZE, CBE_IOPTE_M); out_free_context: lv1_gpu_context_free(priv->context_handle); out_free_memory: @@ -787,14 +793,14 @@ out_free_xdr_buf: free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); fail_free_priv: kfree(priv); - dev->core.driver_data = NULL; + ps3_system_bus_set_drvdata(dev, NULL); fail: return error; } static int ps3vram_remove(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); del_gendisk(priv->gendisk); put_disk(priv->gendisk); @@ -803,13 +809,15 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev) ps3vram_cache_cleanup(dev); iounmap(priv->reports); iounmap(priv->ctrl); - iounmap(priv->ddr_base); + lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, + ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), + XDR_BUF_SIZE, CBE_IOPTE_M); lv1_gpu_context_free(priv->context_handle); lv1_gpu_memory_free(priv->memory_handle); ps3_close_hv_device(dev); free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); kfree(priv); - dev->core.driver_data = NULL; + ps3_system_bus_set_drvdata(dev, NULL); return 0; } diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index afbe45676d71..f424d394a286 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -33,48 +33,64 @@ struct ps3flash_private { struct mutex mutex; /* Bounce buffer mutex */ + u64 chunk_sectors; + int tag; /* Start sector of buffer, -1 if invalid */ + bool dirty; }; static struct ps3_storage_device *ps3flash_dev; -static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev, - u64 lpar, u64 start_sector, - u64 sectors, int write) +static int ps3flash_read_write_sectors(struct ps3_storage_device *dev, + u64 start_sector, int write) { - u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors, + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, + start_sector, priv->chunk_sectors, write); if (res) { dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__, __LINE__, write ? "write" : "read", res); return -EIO; } - return sectors; + return 0; } -static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev, - u64 start_sector, u64 sectors, - unsigned int sector_offset) +static int ps3flash_writeback(struct ps3_storage_device *dev) { - u64 max_sectors, lpar; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + int res; - max_sectors = dev->bounce_size / dev->blk_size; - if (sectors > max_sectors) { - dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n", - __func__, __LINE__, max_sectors); - sectors = max_sectors; - } + if (!priv->dirty || priv->tag < 0) + return 0; - lpar = dev->bounce_lpar + sector_offset * dev->blk_size; - return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, - 0); + res = ps3flash_read_write_sectors(dev, priv->tag, 1); + if (res) + return res; + + priv->dirty = false; + return 0; } -static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev, - u64 start_sector) +static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector) { - u64 sectors = dev->bounce_size / dev->blk_size; - return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector, - sectors, 1); + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + int res; + + if (start_sector == priv->tag) + return 0; + + res = ps3flash_writeback(dev); + if (res) + return res; + + priv->tag = -1; + + res = ps3flash_read_write_sectors(dev, start_sector, 0); + if (res) + return res; + + priv->tag = start_sector; + return 0; } static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) @@ -104,18 +120,19 @@ out: return res; } -static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, - loff_t *pos) +static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, + size_t count, loff_t *pos) { struct ps3_storage_device *dev = ps3flash_dev; - struct ps3flash_private *priv = dev->sbd.core.driver_data; - u64 size, start_sector, end_sector, offset; - ssize_t sectors_read; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + u64 size, sector, offset; + int res; size_t remaining, n; + const void *src; dev_dbg(&dev->sbd.core, - "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n", - __func__, __LINE__, count, *pos, buf); + "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n", + __func__, __LINE__, count, *pos, userbuf, kernelbuf); size = dev->regions[dev->region_idx].size*dev->blk_size; if (*pos >= size || !count) @@ -128,61 +145,63 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, count = size - *pos; } - start_sector = *pos / dev->blk_size; - offset = *pos % dev->blk_size; - end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size); + sector = *pos / dev->bounce_size * priv->chunk_sectors; + offset = *pos % dev->bounce_size; remaining = count; do { + n = min_t(u64, remaining, dev->bounce_size - offset); + src = dev->bounce_buf + offset; + mutex_lock(&priv->mutex); - sectors_read = ps3flash_read_sectors(dev, start_sector, - end_sector-start_sector, - 0); - if (sectors_read < 0) { - mutex_unlock(&priv->mutex); + res = ps3flash_fetch(dev, sector); + if (res) goto fail; - } - n = min_t(u64, remaining, sectors_read*dev->blk_size-offset); dev_dbg(&dev->sbd.core, - "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n", - __func__, __LINE__, n, dev->bounce_buf+offset, buf); - if (copy_to_user(buf, dev->bounce_buf+offset, n)) { - mutex_unlock(&priv->mutex); - sectors_read = -EFAULT; - goto fail; + "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n", + __func__, __LINE__, n, src, userbuf, kernelbuf); + if (userbuf) { + if (copy_to_user(userbuf, src, n)) { + res = -EFAULT; + goto fail; + } + userbuf += n; + } + if (kernelbuf) { + memcpy(kernelbuf, src, n); + kernelbuf += n; } mutex_unlock(&priv->mutex); *pos += n; - buf += n; remaining -= n; - start_sector += sectors_read; + sector += priv->chunk_sectors; offset = 0; } while (remaining > 0); return count; fail: - return sectors_read; + mutex_unlock(&priv->mutex); + return res; } -static ssize_t ps3flash_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) +static ssize_t ps3flash_write(const char __user *userbuf, + const void *kernelbuf, size_t count, loff_t *pos) { struct ps3_storage_device *dev = ps3flash_dev; - struct ps3flash_private *priv = dev->sbd.core.driver_data; - u64 size, chunk_sectors, start_write_sector, end_write_sector, - end_read_sector, start_read_sector, head, tail, offset; - ssize_t res; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + u64 size, sector, offset; + int res = 0; size_t remaining, n; - unsigned int sec_off; + void *dst; dev_dbg(&dev->sbd.core, - "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n", - __func__, __LINE__, count, *pos, buf); + "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n", + __func__, __LINE__, count, *pos, userbuf, kernelbuf); size = dev->regions[dev->region_idx].size*dev->blk_size; if (*pos >= size || !count) @@ -195,89 +214,46 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, count = size - *pos; } - chunk_sectors = dev->bounce_size / dev->blk_size; - - start_write_sector = *pos / dev->bounce_size * chunk_sectors; + sector = *pos / dev->bounce_size * priv->chunk_sectors; offset = *pos % dev->bounce_size; - end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) * - chunk_sectors; - - end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size); - start_read_sector = (*pos + count) / dev->blk_size; - - /* - * As we have to write in 256 KiB chunks, while we can read in blk_size - * (usually 512 bytes) chunks, we perform the following steps: - * 1. Read from start_write_sector to end_read_sector ("head") - * 2. Read from start_read_sector to end_write_sector ("tail") - * 3. Copy data to buffer - * 4. Write from start_write_sector to end_write_sector - * All of this is complicated by using only one 256 KiB bounce buffer. - */ - - head = end_read_sector - start_write_sector; - tail = end_write_sector - start_read_sector; remaining = count; do { + n = min_t(u64, remaining, dev->bounce_size - offset); + dst = dev->bounce_buf + offset; + mutex_lock(&priv->mutex); - if (end_read_sector >= start_read_sector) { - /* Merge head and tail */ - dev_dbg(&dev->sbd.core, - "Merged head and tail: %llu sectors at %llu\n", - chunk_sectors, start_write_sector); - res = ps3flash_read_sectors(dev, start_write_sector, - chunk_sectors, 0); - if (res < 0) + if (n != dev->bounce_size) + res = ps3flash_fetch(dev, sector); + else if (sector != priv->tag) + res = ps3flash_writeback(dev); + if (res) + goto fail; + + dev_dbg(&dev->sbd.core, + "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n", + __func__, __LINE__, n, userbuf, kernelbuf, dst); + if (userbuf) { + if (copy_from_user(dst, userbuf, n)) { + res = -EFAULT; goto fail; - } else { - if (head) { - /* Read head */ - dev_dbg(&dev->sbd.core, - "head: %llu sectors at %llu\n", head, - start_write_sector); - res = ps3flash_read_sectors(dev, - start_write_sector, - head, 0); - if (res < 0) - goto fail; - } - if (start_read_sector < - start_write_sector+chunk_sectors) { - /* Read tail */ - dev_dbg(&dev->sbd.core, - "tail: %llu sectors at %llu\n", tail, - start_read_sector); - sec_off = start_read_sector-start_write_sector; - res = ps3flash_read_sectors(dev, - start_read_sector, - tail, sec_off); - if (res < 0) - goto fail; } + userbuf += n; } - - n = min_t(u64, remaining, dev->bounce_size-offset); - dev_dbg(&dev->sbd.core, - "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n", - __func__, __LINE__, n, buf, dev->bounce_buf+offset); - if (copy_from_user(dev->bounce_buf+offset, buf, n)) { - res = -EFAULT; - goto fail; + if (kernelbuf) { + memcpy(dst, kernelbuf, n); + kernelbuf += n; } - res = ps3flash_write_chunk(dev, start_write_sector); - if (res < 0) - goto fail; + priv->tag = sector; + priv->dirty = true; mutex_unlock(&priv->mutex); *pos += n; - buf += n; remaining -= n; - start_write_sector += chunk_sectors; - head = 0; + sector += priv->chunk_sectors; offset = 0; } while (remaining > 0); @@ -288,6 +264,51 @@ fail: return res; } +static ssize_t ps3flash_user_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + return ps3flash_read(buf, NULL, count, pos); +} + +static ssize_t ps3flash_user_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + return ps3flash_write(buf, NULL, count, pos); +} + +static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos) +{ + return ps3flash_read(NULL, buf, count, &pos); +} + +static ssize_t ps3flash_kernel_write(const void *buf, size_t count, + loff_t pos) +{ + ssize_t res; + int wb; + + res = ps3flash_write(NULL, buf, count, &pos); + if (res < 0) + return res; + + /* Make kernel writes synchronous */ + wb = ps3flash_writeback(ps3flash_dev); + if (wb) + return wb; + + return res; +} + +static int ps3flash_flush(struct file *file, fl_owner_t id) +{ + return ps3flash_writeback(ps3flash_dev); +} + +static int ps3flash_fsync(struct file *file, struct dentry *dentry, + int datasync) +{ + return ps3flash_writeback(ps3flash_dev); +} static irqreturn_t ps3flash_interrupt(int irq, void *data) { @@ -312,12 +333,18 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data) return IRQ_HANDLED; } - static const struct file_operations ps3flash_fops = { .owner = THIS_MODULE, .llseek = ps3flash_llseek, - .read = ps3flash_read, - .write = ps3flash_write, + .read = ps3flash_user_read, + .write = ps3flash_user_write, + .flush = ps3flash_flush, + .fsync = ps3flash_fsync, +}; + +static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = { + .read = ps3flash_kernel_read, + .write = ps3flash_kernel_write, }; static struct miscdevice ps3flash_misc = { @@ -366,11 +393,13 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) goto fail; } - dev->sbd.core.driver_data = priv; + ps3_system_bus_set_drvdata(&dev->sbd, priv); mutex_init(&priv->mutex); + priv->tag = -1; dev->bounce_size = ps3flash_bounce_buffer.size; dev->bounce_buf = ps3flash_bounce_buffer.address; + priv->chunk_sectors = dev->bounce_size / dev->blk_size; error = ps3stor_setup(dev, ps3flash_interrupt); if (error) @@ -386,13 +415,15 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", __func__, __LINE__, ps3flash_misc.minor); + + ps3_os_area_flash_register(&ps3flash_kernel_ops); return 0; fail_teardown: ps3stor_teardown(dev); fail_free_priv: kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(&dev->sbd, NULL); fail: ps3flash_dev = NULL; return error; @@ -402,10 +433,11 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); + ps3_os_area_flash_register(NULL); misc_deregister(&ps3flash_misc); ps3stor_teardown(dev); - kfree(dev->sbd.core.driver_data); - dev->sbd.core.driver_data = NULL; + kfree(ps3_system_bus_get_drvdata(&dev->sbd)); + ps3_system_bus_set_drvdata(&dev->sbd, NULL); ps3flash_dev = NULL; return 0; } diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 5acd29e6e043..3910ce112a95 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -104,7 +104,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, struct tty_struct *to = tty->link; int c; - if (!to || tty->stopped) + if (!to || !to->ldisc || tty->stopped) return 0; c = to->receive_room; @@ -148,7 +148,7 @@ static int pty_chars_in_buffer(struct tty_struct *tty) int count; /* We should get the line discipline lock for "tty->link" */ - if (!to || !to->ldisc->ops->chars_in_buffer) + if (!to || !to->ldisc || !to->ldisc->ops->chars_in_buffer) return 0; /* The ldisc must report 0 if no characters available to be read */ @@ -183,7 +183,7 @@ static void pty_flush_buffer(struct tty_struct *tty) struct tty_struct *to = tty->link; unsigned long flags; - if (!to) + if (!to || !to->ldisc) return; if (to->ldisc->ops->flush_buffer) diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 39c8f86dedd4..94b3e06d73ec 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -148,8 +148,10 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc) } } spin_unlock_irqrestore(&tty_ldisc_lock, flags); - if (err) + if (err) { + kfree(ld); return ERR_PTR(err); + } return ld; } @@ -262,7 +264,7 @@ const struct file_operations tty_ldiscs_proc_fops = { * @ld: line discipline * * Install an instance of a line discipline into a tty structure. The - * ldisc must have a reference count above zero to ensure it remains/ + * ldisc must have a reference count above zero to ensure it remains. * The tty instance refcount starts at zero. * * Locking: diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index d73f5f473e38..f8090e137fef 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -306,11 +306,11 @@ config SENSORS_F71805F will be called f71805f. config SENSORS_F71882FG - tristate "Fintek F71862FG, F71882FG and F8000" + tristate "Fintek F71858FG, F71862FG, F71882FG and F8000" depends on EXPERIMENTAL help If you say yes here you get support for hardware monitoring - features of the Fintek F71882FG/F71883FG, F71862FG/71863FG + features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG and F8000 Super-I/O chips. This driver can also be built as a module. If so, the module @@ -418,7 +418,7 @@ config SENSORS_IBMAEM power sensors and capping hardware in various IBM System X servers that support Active Energy Manager. This includes the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2, - and certain HS2x/LS2x/QS2x blades. + and certain HC10/HS2x/LS2x/QS2x blades. This driver can also be built as a module. If so, the module will be called ibmaem. @@ -787,6 +787,16 @@ config SENSORS_THMC50 This driver can also be built as a module. If so, the module will be called thmc50. +config SENSORS_TMP401 + tristate "Texas Instruments TMP401 and compatibles" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for Texas Instruments TMP401 and + TMP411 temperature sensor chips. + + This driver can also be built as a module. If so, the module + will be called tmp401. + config SENSORS_VIA686A tristate "VIA686A" depends on PCI diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 0ae26984ba45..b793dce6bed5 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o obj-$(CONFIG_SENSORS_THMC50) += thmc50.o +obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VT1211) += vt1211.o obj-$(CONFIG_SENSORS_VT8231) += vt8231.o diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 5f81ddf71508..4146105f1a57 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -1,6 +1,6 @@ /*************************************************************************** * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> * - * Copyright (C) 2007,2008 by Hans de Goede <hdegoede@redhat.com> * + * Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.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 * @@ -32,6 +32,7 @@ #define DRVNAME "f71882fg" +#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */ #define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */ #define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ #define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */ @@ -44,6 +45,7 @@ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ +#define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F8000_ID 0x0581 /* Chipset ID */ @@ -70,6 +72,7 @@ #define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr)) #define F71882FG_REG_TEMP_STATUS 0x62 #define F71882FG_REG_TEMP_BEEP 0x63 +#define F71882FG_REG_TEMP_CONFIG 0x69 #define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr)) #define F71882FG_REG_TEMP_TYPE 0x6B #define F71882FG_REG_TEMP_DIODE_OPEN 0x6F @@ -92,9 +95,10 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -enum chips { f71862fg, f71882fg, f8000 }; +enum chips { f71858fg, f71862fg, f71882fg, f8000 }; static const char *f71882fg_names[] = { + "f71858fg", "f71862fg", "f71882fg", "f8000", @@ -119,6 +123,7 @@ struct f71882fg_data { struct device *hwmon_dev; struct mutex update_lock; + int temp_start; /* temp numbering start (0 or 1) */ char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned long last_limits; /* In jiffies */ @@ -136,7 +141,7 @@ struct f71882fg_data { /* Note: all models have only 3 temperature channels, but on some they are addressed as 0-2 and on others as 1-3, so for coding convenience we reserve space for 4 channels */ - u8 temp[4]; + u16 temp[4]; u8 temp_ovt[4]; u8 temp_high[4]; u8 temp_hyst[2]; /* 2 hysts stored per reg */ @@ -144,6 +149,7 @@ struct f71882fg_data { u8 temp_status; u8 temp_beep; u8 temp_diode_open; + u8 temp_config; u8 pwm[4]; u8 pwm_enable; u8 pwm_auto_point_hyst[2]; @@ -247,11 +253,55 @@ static struct platform_driver f71882fg_driver = { .name = DRVNAME, }, .probe = f71882fg_probe, - .remove = __devexit_p(f71882fg_remove), + .remove = f71882fg_remove, }; static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +/* Temp and in attr for the f71858fg */ +static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = { + SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), + SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), + SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), + SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), + SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 0), + SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 0), + SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0), + SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 0), + SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 0), + SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), + SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), + SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), + SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 1), + SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 1), + SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1), + SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 1), + SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 1), + SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), + SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), + SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), + SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 2), + SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 2), + SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2), + SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 2), + SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 2), + SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), + SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), +}; + /* Temp and in attr common to both the f71862fg and f71882fg */ static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = { SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), @@ -344,6 +394,7 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = { SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 0), SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), + SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 1), @@ -351,12 +402,14 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = { store_temp_max, 0, 1), SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 2), SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 2), SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), + SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), }; /* Fan / PWM attr common to all models */ @@ -395,6 +448,9 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[] = { show_pwm_auto_point_channel, store_pwm_auto_point_channel, 0, 1), + SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), + SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, + store_pwm_enable, 0, 2), SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR, show_pwm_interpolate, store_pwm_interpolate, 0, 2), SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, @@ -450,9 +506,6 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 1), - SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), - SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, - store_pwm_enable, 0, 2), SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 1, 2), @@ -473,22 +526,8 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { show_pwm_auto_point_temp_hyst, NULL, 3, 2), }; -/* Fan / PWM attr for the f71882fg */ -static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { - SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 0), - SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 1), - SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 2), - SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), - SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, - show_fan_full_speed, - store_fan_full_speed, 0, 3), - SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 3), - SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), - +/* Fan / PWM attr common to both the f71882fg and f71858fg */ +static struct sensor_device_attribute_2 f71882fg_f71858fg_fan_attr[] = { SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 0), @@ -565,9 +604,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 1), - SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), - SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, - store_pwm_enable, 0, 2), SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 2), @@ -605,6 +641,24 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { show_pwm_auto_point_temp_hyst, NULL, 2, 2), SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 2), +}; + +/* Fan / PWM attr found on the f71882fg but not on the f71858fg */ +static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { + SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 0), + SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 1), + SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 2), + + SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), + SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, + show_fan_full_speed, + store_fan_full_speed, 0, 3), + SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 3), + SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3), SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable, @@ -659,8 +713,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { static struct sensor_device_attribute_2 f8000_fan_attr[] = { SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), - SENSOR_ATTR_2(pwm3, S_IRUGO, show_pwm, NULL, 0, 2), - SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 2), @@ -857,13 +909,20 @@ static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val) outb(val & 255, data->addr + DATA_REG_OFFSET); } +static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) +{ + if (data->type == f71858fg) + return f71882fg_read16(data, F71882FG_REG_TEMP(nr)); + else + return f71882fg_read8(data, F71882FG_REG_TEMP(nr)); +} + static struct f71882fg_data *f71882fg_update_device(struct device *dev) { struct f71882fg_data *data = dev_get_drvdata(dev); int nr, reg = 0, reg2; int nr_fans = (data->type == f71882fg) ? 4 : 3; - int nr_ins = (data->type == f8000) ? 3 : 9; - int temp_start = (data->type == f8000) ? 0 : 1; + int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9; mutex_lock(&data->update_lock); @@ -878,7 +937,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) } /* Get High & boundary temps*/ - for (nr = temp_start; nr < 3 + temp_start; nr++) { + for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) { data->temp_ovt[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_OVT(nr)); data->temp_high[nr] = f71882fg_read8(data, @@ -886,14 +945,17 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) } if (data->type != f8000) { - data->fan_beep = f71882fg_read8(data, - F71882FG_REG_FAN_BEEP); - data->temp_beep = f71882fg_read8(data, - F71882FG_REG_TEMP_BEEP); data->temp_hyst[0] = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(0)); data->temp_hyst[1] = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(1)); + } + + if (data->type == f71862fg || data->type == f71882fg) { + data->fan_beep = f71882fg_read8(data, + F71882FG_REG_FAN_BEEP); + data->temp_beep = f71882fg_read8(data, + F71882FG_REG_TEMP_BEEP); /* Have to hardcode type, because temp1 is special */ reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); data->temp_type[2] = (reg & 0x04) ? 2 : 4; @@ -904,10 +966,10 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) data->temp_type[1] = 6 /* PECI */; else if ((reg2 & 0x03) == 0x02) data->temp_type[1] = 5 /* AMDSI */; - else if (data->type != f8000) + else if (data->type == f71862fg || data->type == f71882fg) data->temp_type[1] = (reg & 0x02) ? 2 : 4; else - data->temp_type[1] = 2; /* F8000 only supports BJT */ + data->temp_type[1] = 2; /* Only supports BJT */ data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); @@ -963,9 +1025,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) F71882FG_REG_TEMP_STATUS); data->temp_diode_open = f71882fg_read8(data, F71882FG_REG_TEMP_DIODE_OPEN); - for (nr = temp_start; nr < 3 + temp_start; nr++) - data->temp[nr] = f71882fg_read8(data, - F71882FG_REG_TEMP(nr)); + for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) + data->temp[nr] = f71882fg_read_temp(data, nr); data->fan_status = f71882fg_read8(data, F71882FG_REG_FAN_STATUS); @@ -1168,8 +1229,24 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, { struct f71882fg_data *data = f71882fg_update_device(dev); int nr = to_sensor_dev_attr_2(devattr)->index; + int sign, temp; + + if (data->type == f71858fg) { + /* TEMP_TABLE_SEL 1 or 3 ? */ + if (data->temp_config & 1) { + sign = data->temp[nr] & 0x0001; + temp = (data->temp[nr] >> 5) & 0x7ff; + } else { + sign = data->temp[nr] & 0x8000; + temp = (data->temp[nr] >> 5) & 0x3ff; + } + temp *= 125; + if (sign) + temp -= 128000; + } else + temp = data->temp[nr] * 1000; - return sprintf(buf, "%d\n", data->temp[nr] * 1000); + return sprintf(buf, "%d\n", temp); } static ssize_t show_temp_max(struct device *dev, struct device_attribute @@ -1440,6 +1517,10 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute int nr = to_sensor_dev_attr_2(devattr)->index; long val = simple_strtol(buf, NULL, 10); + /* Special case for F8000 pwm channel 3 which only does auto mode */ + if (data->type == f8000 && nr == 2 && val != 2) + return -EINVAL; + mutex_lock(&data->update_lock); data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); /* Special case for F8000 auto PWM mode / Thermostat mode */ @@ -1458,6 +1539,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute } else { switch (val) { case 1: + /* The f71858fg does not support manual RPM mode */ + if (data->type == f71858fg && + ((data->pwm_enable >> (2 * nr)) & 1)) { + count = -EINVAL; + goto leave; + } data->pwm_enable |= 2 << (2 * nr); break; /* Manual */ case 2: @@ -1616,9 +1703,9 @@ static ssize_t show_pwm_auto_point_channel(struct device *dev, int result; struct f71882fg_data *data = f71882fg_update_device(dev); int nr = to_sensor_dev_attr_2(devattr)->index; - int temp_start = (data->type == f8000) ? 0 : 1; - result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start); + result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - + data->temp_start); return sprintf(buf, "%d\n", result); } @@ -1629,7 +1716,6 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, { struct f71882fg_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr_2(devattr)->index; - int temp_start = (data->type == f8000) ? 0 : 1; long val = simple_strtol(buf, NULL, 10); switch (val) { @@ -1645,7 +1731,7 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, default: return -EINVAL; } - val += temp_start; + val += data->temp_start; mutex_lock(&data->update_lock); data->pwm_auto_point_mapping[nr] = f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); @@ -1721,6 +1807,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; data->type = sio_data->type; + data->temp_start = + (data->type == f71858fg || data->type == f8000) ? 0 : 1; mutex_init(&data->update_lock); platform_set_drvdata(pdev, data); @@ -1736,19 +1824,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) goto exit_free; } - data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - /* If it is a 71862 and the fan / pwm part is enabled sanity check - the pwm settings */ - if (data->type == f71862fg && (start_reg & 0x02)) { - if ((data->pwm_enable & 0x15) != 0x15) { - dev_err(&pdev->dev, - "Invalid (reserved) pwm settings: 0x%02x\n", - (unsigned int)data->pwm_enable); - err = -ENODEV; - goto exit_free; - } - } - /* Register sysfs interface files */ err = device_create_file(&pdev->dev, &dev_attr_name); if (err) @@ -1756,6 +1831,20 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) if (start_reg & 0x01) { switch (data->type) { + case f71858fg: + data->temp_config = + f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG); + if (data->temp_config & 0x10) + /* The f71858fg temperature alarms behave as + the f8000 alarms in this mode */ + err = f71882fg_create_sysfs_files(pdev, + f8000_in_temp_attr, + ARRAY_SIZE(f8000_in_temp_attr)); + else + err = f71882fg_create_sysfs_files(pdev, + f71858fg_in_temp_attr, + ARRAY_SIZE(f71858fg_in_temp_attr)); + break; case f71882fg: err = f71882fg_create_sysfs_files(pdev, f71882fg_in_temp_attr, @@ -1779,6 +1868,35 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) } if (start_reg & 0x02) { + data->pwm_enable = + f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); + + /* Sanity check the pwm settings */ + switch (data->type) { + case f71858fg: + err = 0; + for (i = 0; i < nr_fans; i++) + if (((data->pwm_enable >> (i * 2)) & 3) == 3) + err = 1; + break; + case f71862fg: + err = (data->pwm_enable & 0x15) != 0x15; + break; + case f71882fg: + err = 0; + break; + case f8000: + err = data->pwm_enable & 0x20; + break; + } + if (err) { + dev_err(&pdev->dev, + "Invalid (reserved) pwm settings: 0x%02x\n", + (unsigned int)data->pwm_enable); + err = -ENODEV; + goto exit_unregister_sysfs; + } + err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr, ARRAY_SIZE(fxxxx_fan_attr)); if (err) @@ -1794,6 +1912,13 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) err = f71882fg_create_sysfs_files(pdev, f71882fg_fan_attr, ARRAY_SIZE(f71882fg_fan_attr)); + if (err) + goto exit_unregister_sysfs; + /* fall through! */ + case f71858fg: + err = f71882fg_create_sysfs_files(pdev, + f71882fg_f71858fg_fan_attr, + ARRAY_SIZE(f71882fg_f71858fg_fan_attr)); break; case f8000: err = f71882fg_create_sysfs_files(pdev, @@ -1878,6 +2003,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); switch (devid) { + case SIO_F71858_ID: + sio_data->type = f71858fg; + break; case SIO_F71862_ID: sio_data->type = f71862fg; break; @@ -1892,7 +2020,11 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, goto exit; } - superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (sio_data->type == f71858fg) + superio_select(sioaddr, SIO_F71858FG_LD_HWM); + else + superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { printk(KERN_WARNING DRVNAME ": Device not activated\n"); goto exit; diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index e15c3e7b07e9..29ea6753f3bb 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -18,6 +18,7 @@ #include <linux/hwmon.h> #include <linux/gfp.h> #include <linux/spinlock.h> +#include <linux/pci.h> #define HWMON_ID_PREFIX "hwmon" #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" @@ -86,8 +87,36 @@ void hwmon_device_unregister(struct device *dev) "hwmon_device_unregister() failed: bad class ID!\n"); } +static void __init hwmon_pci_quirks(void) +{ +#if defined CONFIG_X86 && defined CONFIG_PCI + struct pci_dev *sb; + u16 base; + u8 enable; + + /* Open access to 0x295-0x296 on MSI MS-7031 */ + sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); + if (sb && + (sb->subsystem_vendor == 0x1462 && /* MSI */ + sb->subsystem_device == 0x0031)) { /* MS-7031 */ + + pci_read_config_byte(sb, 0x48, &enable); + pci_read_config_word(sb, 0x64, &base); + + if (base == 0 && !(enable & BIT(2))) { + dev_info(&sb->dev, + "Opening wide generic port at 0x295\n"); + pci_write_config_word(sb, 0x64, 0x295); + pci_write_config_byte(sb, 0x48, enable | BIT(2)); + } + } +#endif +} + static int __init hwmon_init(void) { + hwmon_pci_quirks(); + hwmon_class = class_create(THIS_MODULE, "hwmon"); if (IS_ERR(hwmon_class)) { printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n"); diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index fe74609a7feb..405d3fb5d76f 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -1127,3 +1127,4 @@ MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*"); MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*"); MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*"); MODULE_ALIAS("dmi:bvnIBM:*:pnIBM3850M2/x3950M2-*"); +MODULE_ALIAS("dmi:bvnIBM:*:pnIBMBladeHC10-*"); diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index f27af6a9da41..86142a858238 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -12,7 +12,7 @@ * also work with the MAX6651. It does not distinguish max6650 and max6651 * chips. * - * Tha datasheet was last seen at: + * The datasheet was last seen at: * * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf * @@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650); #define MAX6650_CFG_MODE_OPEN_LOOP 0x30 #define MAX6650_COUNT_MASK 0x03 +/* + * Alarm status register bits + */ + +#define MAX6650_ALRM_MAX 0x01 +#define MAX6650_ALRM_MIN 0x02 +#define MAX6650_ALRM_TACH 0x04 +#define MAX6650_ALRM_GPIO1 0x08 +#define MAX6650_ALRM_GPIO2 0x10 + /* Minimum and maximum values of the FAN-RPM */ #define FAN_RPM_MIN 240 #define FAN_RPM_MAX 30000 @@ -151,6 +161,7 @@ struct max6650_data u8 tach[4]; u8 count; u8 dac; + u8 alarm; }; static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, @@ -418,6 +429,33 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr, return count; } +/* + * Get alarm stati: + * Possible values: + * 0 = no alarm + * 1 = alarm + */ + +static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct max6650_data *data = max6650_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + int alarm = 0; + + if (data->alarm & attr->index) { + mutex_lock(&data->update_lock); + alarm = 1; + data->alarm &= ~attr->index; + data->alarm |= i2c_smbus_read_byte_data(client, + MAX6650_REG_ALARM); + mutex_unlock(&data->update_lock); + } + + return sprintf(buf, "%d\n", alarm); +} + static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); @@ -426,7 +464,41 @@ static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target); static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); +static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_MAX); +static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_MIN); +static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_TACH); +static SENSOR_DEVICE_ATTR(gpio1_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_GPIO1); +static SENSOR_DEVICE_ATTR(gpio2_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_GPIO2); + +static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a, + int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct i2c_client *client = to_i2c_client(dev); + u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN); + struct device_attribute *devattr; + /* + * Hide the alarms that have not been enabled by the firmware + */ + + devattr = container_of(a, struct device_attribute, attr); + if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr + || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr + || devattr == &sensor_dev_attr_fan1_fault.dev_attr + || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr + || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) { + if (!(alarm_en & to_sensor_dev_attr(devattr)->index)) + return 0; + } + + return a->mode; +} static struct attribute *max6650_attrs[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, @@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = { &dev_attr_fan1_div.attr, &dev_attr_pwm1_enable.attr, &dev_attr_pwm1.attr, + &sensor_dev_attr_fan1_max_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_min_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_fault.dev_attr.attr, + &sensor_dev_attr_gpio1_alarm.dev_attr.attr, + &sensor_dev_attr_gpio2_alarm.dev_attr.attr, NULL }; static struct attribute_group max6650_attr_grp = { .attrs = max6650_attrs, + .is_visible = max6650_attrs_visible, }; /* @@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev) MAX6650_REG_COUNT); data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); + /* Alarms are cleared on read in case the condition that + * caused the alarm is removed. Keep the value latched here + * for providing the register through different alarm files. */ + data->alarm |= i2c_smbus_read_byte_data(client, + MAX6650_REG_ALARM); + data->last_updated = jiffies; data->valid = 1; } diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 6cbdc2fea734..56cd6004da36 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -627,35 +627,35 @@ static struct platform_driver sht_drivers[] = { .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht11", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht15", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht71", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht75", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, }; diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c new file mode 100644 index 000000000000..7b34f2cd08bb --- /dev/null +++ b/drivers/hwmon/tmp401.c @@ -0,0 +1,690 @@ +/* tmp401.c + * + * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com> + * Preliminary tmp411 support by: + * Gabriel Konat, Sander Leget, Wouter Willems + * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC. + * + * Note this IC is in some aspect similar to the LM90, but it has quite a + * few differences too, for example the local temp has a higher resolution + * and thus has 16 bits registers for its value and limit instead of 8 bits. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/sysfs.h> + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_2(tmp401, tmp411); + +/* + * The TMP401 registers, note some registers have different addresses for + * reading and writing + */ +#define TMP401_STATUS 0x02 +#define TMP401_CONFIG_READ 0x03 +#define TMP401_CONFIG_WRITE 0x09 +#define TMP401_CONVERSION_RATE_READ 0x04 +#define TMP401_CONVERSION_RATE_WRITE 0x0A +#define TMP401_TEMP_CRIT_HYST 0x21 +#define TMP401_CONSECUTIVE_ALERT 0x22 +#define TMP401_MANUFACTURER_ID_REG 0xFE +#define TMP401_DEVICE_ID_REG 0xFF +#define TMP411_N_FACTOR_REG 0x18 + +static const u8 TMP401_TEMP_MSB[2] = { 0x00, 0x01 }; +static const u8 TMP401_TEMP_LSB[2] = { 0x15, 0x10 }; +static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2] = { 0x06, 0x08 }; +static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2] = { 0x0C, 0x0E }; +static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2] = { 0x17, 0x14 }; +static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2] = { 0x05, 0x07 }; +static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2] = { 0x0B, 0x0D }; +static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2] = { 0x16, 0x13 }; +/* These are called the THERM limit / hysteresis / mask in the datasheet */ +static const u8 TMP401_TEMP_CRIT_LIMIT[2] = { 0x20, 0x19 }; + +static const u8 TMP411_TEMP_LOWEST_MSB[2] = { 0x30, 0x34 }; +static const u8 TMP411_TEMP_LOWEST_LSB[2] = { 0x31, 0x35 }; +static const u8 TMP411_TEMP_HIGHEST_MSB[2] = { 0x32, 0x36 }; +static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 }; + +/* Flags */ +#define TMP401_CONFIG_RANGE 0x04 +#define TMP401_CONFIG_SHUTDOWN 0x40 +#define TMP401_STATUS_LOCAL_CRIT 0x01 +#define TMP401_STATUS_REMOTE_CRIT 0x02 +#define TMP401_STATUS_REMOTE_OPEN 0x04 +#define TMP401_STATUS_REMOTE_LOW 0x08 +#define TMP401_STATUS_REMOTE_HIGH 0x10 +#define TMP401_STATUS_LOCAL_LOW 0x20 +#define TMP401_STATUS_LOCAL_HIGH 0x40 + +/* Manufacturer / Device ID's */ +#define TMP401_MANUFACTURER_ID 0x55 +#define TMP401_DEVICE_ID 0x11 +#define TMP411_DEVICE_ID 0x12 + +/* + * Functions declarations + */ + +static int tmp401_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int tmp401_detect(struct i2c_client *client, int kind, + struct i2c_board_info *info); +static int tmp401_remove(struct i2c_client *client); +static struct tmp401_data *tmp401_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static const struct i2c_device_id tmp401_id[] = { + { "tmp401", tmp401 }, + { "tmp411", tmp411 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tmp401_id); + +static struct i2c_driver tmp401_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "tmp401", + }, + .probe = tmp401_probe, + .remove = tmp401_remove, + .id_table = tmp401_id, + .detect = tmp401_detect, + .address_data = &addr_data, +}; + +/* + * Client data (each client gets its own) + */ + +struct tmp401_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + int kind; + + /* register values */ + u8 status; + u8 config; + u16 temp[2]; + u16 temp_low[2]; + u16 temp_high[2]; + u8 temp_crit[2]; + u8 temp_crit_hyst; + u16 temp_lowest[2]; + u16 temp_highest[2]; +}; + +/* + * Sysfs attr show / store functions + */ + +static int tmp401_register_to_temp(u16 reg, u8 config) +{ + int temp = reg; + + if (config & TMP401_CONFIG_RANGE) + temp -= 64 * 256; + + return (temp * 625 + 80) / 160; +} + +static u16 tmp401_temp_to_register(long temp, u8 config) +{ + if (config & TMP401_CONFIG_RANGE) { + temp = SENSORS_LIMIT(temp, -64000, 191000); + temp += 64000; + } else + temp = SENSORS_LIMIT(temp, 0, 127000); + + return (temp * 160 + 312) / 625; +} + +static int tmp401_crit_register_to_temp(u8 reg, u8 config) +{ + int temp = reg; + + if (config & TMP401_CONFIG_RANGE) + temp -= 64; + + return temp * 1000; +} + +static u8 tmp401_crit_temp_to_register(long temp, u8 config) +{ + if (config & TMP401_CONFIG_RANGE) { + temp = SENSORS_LIMIT(temp, -64000, 191000); + temp += 64000; + } else + temp = SENSORS_LIMIT(temp, 0, 127000); + + return (temp + 500) / 1000; +} + +static ssize_t show_temp_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp[index], data->config)); +} + +static ssize_t show_temp_min(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_low[index], data->config)); +} + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_high[index], data->config)); +} + +static ssize_t show_temp_crit(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_crit_register_to_temp(data->temp_crit[index], + data->config)); +} + +static ssize_t show_temp_crit_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + mutex_lock(&data->update_lock); + temp = tmp401_crit_register_to_temp(data->temp_crit[index], + data->config); + temp -= data->temp_crit_hyst * 1000; + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", temp); +} + +static ssize_t show_temp_lowest(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_lowest[index], + data->config)); +} + +static ssize_t show_temp_highest(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_highest[index], + data->config)); +} + +static ssize_t show_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int mask = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + if (data->status & mask) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_temp_min(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u16 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_temp_to_register(val, data->config); + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8); + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF); + + data->temp_low[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u16 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_temp_to_register(val, data->config); + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8); + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF); + + data->temp_high[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_crit(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u8 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_crit_temp_to_register(val, data->config); + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_CRIT_LIMIT[index], reg); + + data->temp_crit[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u8 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + if (data->config & TMP401_CONFIG_RANGE) + val = SENSORS_LIMIT(val, -64000, 191000); + else + val = SENSORS_LIMIT(val, 0, 127000); + + mutex_lock(&data->update_lock); + temp = tmp401_crit_register_to_temp(data->temp_crit[index], + data->config); + val = SENSORS_LIMIT(val, temp - 255000, temp); + reg = ((temp - val) + 500) / 1000; + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_CRIT_HYST, reg); + + data->temp_crit_hyst = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * Resets the historical measurements of minimum and maximum temperatures. + * This is done by writing any value to any of the minimum/maximum registers + * (0x30-0x37). + */ +static ssize_t reset_temp_history(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + long val; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + if (val != 1) { + dev_err(dev, "temp_reset_history value %ld not" + " supported. Use 1 to reset the history!\n", val); + return -EINVAL; + } + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP411_TEMP_LOWEST_MSB[0], val); + + return count; +} + +static struct sensor_device_attribute tmp401_attr[] = { + SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0), + SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0), + SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0), + SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0), + SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst, + store_temp_crit_hyst, 0), + SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL, + TMP401_STATUS_LOCAL_LOW), + SENSOR_ATTR(temp1_max_alarm, 0444, show_status, NULL, + TMP401_STATUS_LOCAL_HIGH), + SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL, + TMP401_STATUS_LOCAL_CRIT), + SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1), + SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1), + SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1), + SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1), + SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1), + SENSOR_ATTR(temp2_fault, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_OPEN), + SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_LOW), + SENSOR_ATTR(temp2_max_alarm, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_HIGH), + SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_CRIT), +}; + +/* + * Additional features of the TMP411 chip. + * The TMP411 stores the minimum and maximum + * temperature measured since power-on, chip-reset, or + * minimum and maximum register reset for both the local + * and remote channels. + */ +static struct sensor_device_attribute tmp411_attr[] = { + SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0), + SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0), + SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1), + SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1), + SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0), +}; + +/* + * Begin non sysfs callback code (aka Real code) + */ + +static void tmp401_init_client(struct i2c_client *client) +{ + int config, config_orig; + + /* Set the conversion rate to 2 Hz */ + i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); + + /* Start conversions (disable shutdown if necessary) */ + config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (config < 0) { + dev_warn(&client->dev, "Initialization failed!\n"); + return; + } + + config_orig = config; + config &= ~TMP401_CONFIG_SHUTDOWN; + + if (config != config_orig) + i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config); +} + +static int tmp401_detect(struct i2c_client *client, int kind, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + /* Detect and identify the chip */ + if (kind <= 0) { + u8 reg; + + reg = i2c_smbus_read_byte_data(client, + TMP401_MANUFACTURER_ID_REG); + if (reg != TMP401_MANUFACTURER_ID) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); + + switch (reg) { + case TMP401_DEVICE_ID: + kind = tmp401; + break; + case TMP411_DEVICE_ID: + kind = tmp411; + break; + default: + return -ENODEV; + } + + reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (reg & 0x1b) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, + TMP401_CONVERSION_RATE_READ); + /* Datasheet says: 0x1-0x6 */ + if (reg > 15) + return -ENODEV; + } + strlcpy(info->type, tmp401_id[kind - 1].name, I2C_NAME_SIZE); + + return 0; +} + +static int tmp401_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int i, err = 0; + struct tmp401_data *data; + const char *names[] = { "TMP401", "TMP411" }; + + data = kzalloc(sizeof(struct tmp401_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->kind = id->driver_data; + + /* Initialize the TMP401 chip */ + tmp401_init_client(client); + + /* Register sysfs hooks */ + for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) { + err = device_create_file(&client->dev, + &tmp401_attr[i].dev_attr); + if (err) + goto exit_remove; + } + + /* Register aditional tmp411 sysfs hooks */ + if (data->kind == tmp411) { + for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) { + err = device_create_file(&client->dev, + &tmp411_attr[i].dev_attr); + if (err) + goto exit_remove; + } + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + data->hwmon_dev = NULL; + goto exit_remove; + } + + dev_info(&client->dev, "Detected TI %s chip\n", + names[data->kind - 1]); + + return 0; + +exit_remove: + tmp401_remove(client); /* will also free data for us */ + return err; +} + +static int tmp401_remove(struct i2c_client *client) +{ + struct tmp401_data *data = i2c_get_clientdata(client); + int i; + + if (data->hwmon_dev) + hwmon_device_unregister(data->hwmon_dev); + + for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) + device_remove_file(&client->dev, &tmp401_attr[i].dev_attr); + + if (data->kind == tmp411) { + for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) + device_remove_file(&client->dev, + &tmp411_attr[i].dev_attr); + } + + kfree(data); + return 0; +} + +static struct tmp401_data *tmp401_update_device_reg16( + struct i2c_client *client, struct tmp401_data *data) +{ + int i; + + for (i = 0; i < 2; i++) { + /* + * High byte must be read first immediately followed + * by the low byte + */ + data->temp[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_MSB[i]) << 8; + data->temp[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_LSB[i]); + data->temp_low[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8; + data->temp_low[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_LOW_LIMIT_LSB[i]); + data->temp_high[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8; + data->temp_high[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_HIGH_LIMIT_LSB[i]); + data->temp_crit[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_CRIT_LIMIT[i]); + + if (data->kind == tmp411) { + data->temp_lowest[i] = i2c_smbus_read_byte_data(client, + TMP411_TEMP_LOWEST_MSB[i]) << 8; + data->temp_lowest[i] |= i2c_smbus_read_byte_data( + client, TMP411_TEMP_LOWEST_LSB[i]); + + data->temp_highest[i] = i2c_smbus_read_byte_data( + client, TMP411_TEMP_HIGHEST_MSB[i]) << 8; + data->temp_highest[i] |= i2c_smbus_read_byte_data( + client, TMP411_TEMP_HIGHEST_LSB[i]); + } + } + return data; +} + +static struct tmp401_data *tmp401_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct tmp401_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS); + data->config = i2c_smbus_read_byte_data(client, + TMP401_CONFIG_READ); + tmp401_update_device_reg16(client, data); + + data->temp_crit_hyst = i2c_smbus_read_byte_data(client, + TMP401_TEMP_CRIT_HYST); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init tmp401_init(void) +{ + return i2c_add_driver(&tmp401_driver); +} + +static void __exit tmp401_exit(void) +{ + i2c_del_driver(&tmp401_driver); +} + +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(tmp401_init); +module_exit(tmp401_exit); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index e64b42058b21..0e9746913d2b 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -36,6 +36,7 @@ w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 0x8860 0xa1 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 + w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 */ @@ -53,12 +54,13 @@ #include <asm/io.h> #include "lm75.h" -enum kinds { w83627ehf, w83627dhg, w83667hg }; +enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg }; /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ static const char * w83627ehf_device_names[] = { "w83627ehf", "w83627dhg", + "w83627dhg", "w83667hg", }; @@ -86,6 +88,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); #define SIO_W83627EHF_ID 0x8850 #define SIO_W83627EHG_ID 0x8860 #define SIO_W83627DHG_ID 0xa020 +#define SIO_W83627DHG_P_ID 0xb070 #define SIO_W83667HG_ID 0xa510 #define SIO_ID_MASK 0xFFF0 @@ -1517,6 +1520,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; + static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; static const char __initdata sio_name_W83667HG[] = "W83667HG"; u16 val; @@ -1542,6 +1546,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, sio_data->kind = w83627dhg; sio_name = sio_name_W83627DHG; break; + case SIO_W83627DHG_P_ID: + sio_data->kind = w83627dhg_p; + sio_name = sio_name_W83627DHG_P; + break; case SIO_W83667HG_ID: sio_data->kind = w83667hg; sio_name = sio_name_W83667HG; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c8460fa9cfac..0d04d3ebfc2d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -211,7 +211,7 @@ config I2C_VIA will be called i2c-via. config I2C_VIAPRO - tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820" + tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx" depends on PCI help If you say yes to this option, support will be included for the VIA @@ -225,8 +225,8 @@ config I2C_VIAPRO VT8237R/A/S VT8251 CX700 - VX800 - VX820 + VX800/VX820 + VX855/VX875 This driver can also be built as a module. If so, the module will be called i2c-viapro. diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 02e6f724b05f..54d810a4d00f 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -37,6 +37,7 @@ VT8251 0x3287 yes CX700 0x8324 yes VX800/VX820 0x8353 yes + VX855/VX875 0x8409 yes Note: we assume there can only be one device, with one SMBus interface. */ @@ -404,6 +405,7 @@ found: switch (pdev->device) { case PCI_DEVICE_ID_VIA_CX700: case PCI_DEVICE_ID_VIA_VX800: + case PCI_DEVICE_ID_VIA_VX855: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: @@ -469,6 +471,8 @@ static struct pci_device_id vt596_ids[] = { .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855), + .driver_data = SMBBA3 }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 1a474acc0ddd..7663d57833a0 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -163,7 +163,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = { static struct i2c_adapter voodoo3_i2c_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_TV_ANALOG, .name = "I2C Voodoo3/Banshee adapter", .algo_data = &voo_i2c_bit_data, }; diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 8f8c81eb0aee..02d746c9c474 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -64,21 +64,6 @@ config SENSORS_PCA9539 This driver is deprecated and will be dropped soon. Use drivers/gpio/pca953x.c instead. -config SENSORS_MAX6875 - tristate "Maxim MAX6875 Power supply supervisor" - depends on EXPERIMENTAL - help - If you say yes here you get support for the Maxim MAX6875 - EEPROM-programmable, quad power-supply sequencer/supervisor. - - This provides an interface to program the EEPROM and reset the chip. - - This driver also supports the Maxim MAX6874 hex power-supply - sequencer/supervisor if found at a compatible address. - - This driver can also be built as a module. If so, the module - will be called max6875. - config SENSORS_TSL2550 tristate "Taos TSL2550 ambient light sensor" depends on EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 55a376037183..f4680d16ee34 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -11,7 +11,6 @@ # obj-$(CONFIG_DS1682) += ds1682.o -obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_PCF8575) += pcf8575.o diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 85e2e919d1cd..5ed622ee65c3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -29,7 +29,6 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/idr.h> -#include <linux/platform_device.h> #include <linux/mutex.h> #include <linux/completion.h> #include <linux/hardirq.h> @@ -451,16 +450,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap) mutex_lock(&core_lock); - /* Add the adapter to the driver core. - * If the parent pointer is not set up, - * we add this adapter to the host bus. - */ - if (adap->dev.parent == NULL) { - adap->dev.parent = &platform_bus; - pr_debug("I2C adapter driver [%s] forgot to specify " - "physical device\n", adap->name); - } - /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; @@ -1022,7 +1011,8 @@ module_exit(i2c_exit); */ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - int ret; + unsigned long orig_jiffies; + int ret, try; /* REVISIT the fault reporting model here is weak: * @@ -1060,7 +1050,15 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) mutex_lock_nested(&adap->bus_lock, adap->level); } - ret = adap->algo->master_xfer(adap,msgs,num); + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (ret = 0, try = 0; try <= adap->retries; try++) { + ret = adap->algo->master_xfer(adap, msgs, num); + if (ret != -EAGAIN) + break; + if (time_after(jiffies, orig_jiffies + adap->timeout)) + break; + } mutex_unlock(&adap->bus_lock); return ret; @@ -1509,7 +1507,7 @@ struct i2c_adapter* i2c_get_adapter(int id) struct i2c_adapter *adapter; mutex_lock(&core_lock); - adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); + adapter = idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; @@ -1995,14 +1993,27 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, union i2c_smbus_data *data) { + unsigned long orig_jiffies; + int try; s32 res; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter->algo->smbus_xfer) { mutex_lock(&adapter->bus_lock); - res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, - command, protocol, data); + + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (res = 0, try = 0; try <= adapter->retries; try++) { + res = adapter->algo->smbus_xfer(adapter, addr, flags, + read_write, command, + protocol, data); + if (res != -EAGAIN) + break; + if (time_after(jiffies, + orig_jiffies + adapter->timeout)) + break; + } mutex_unlock(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 0ddf9044948a..fde377c60cca 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -72,7 +72,7 @@ MODULE_PARM_DESC(verbose,"Verbose log operations " "(default 0)"); struct thermostat { - struct i2c_client clt; + struct i2c_client *clt; u8 temps[3]; u8 cached_temp[3]; u8 initial_limits[3]; @@ -87,9 +87,6 @@ static struct of_device * of_dev; static struct thermostat* thermostat; static struct task_struct *thread_therm = NULL; -static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, - int busno); - static void write_both_fan_speed(struct thermostat *th, int speed); static void write_fan_speed(struct thermostat *th, int speed, int fan); @@ -101,7 +98,7 @@ write_reg(struct thermostat* th, int reg, u8 data) tmp[0] = reg; tmp[1] = data; - rc = i2c_master_send(&th->clt, (const char *)tmp, 2); + rc = i2c_master_send(th->clt, (const char *)tmp, 2); if (rc < 0) return rc; if (rc != 2) @@ -116,12 +113,12 @@ read_reg(struct thermostat* th, int reg) int rc; reg_addr = (u8)reg; - rc = i2c_master_send(&th->clt, ®_addr, 1); + rc = i2c_master_send(th->clt, ®_addr, 1); if (rc < 0) return rc; if (rc != 1) return -ENODEV; - rc = i2c_master_recv(&th->clt, (char *)&data, 1); + rc = i2c_master_recv(th->clt, (char *)&data, 1); if (rc < 0) return rc; return data; @@ -131,26 +128,36 @@ static int attach_thermostat(struct i2c_adapter *adapter) { unsigned long bus_no; + struct i2c_board_info info; + struct i2c_client *client; if (strncmp(adapter->name, "uni-n", 5)) return -ENODEV; bus_no = simple_strtoul(adapter->name + 6, NULL, 10); if (bus_no != therm_bus) return -ENODEV; - return attach_one_thermostat(adapter, therm_address, bus_no); + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE); + info.addr = therm_address; + client = i2c_new_device(adapter, &info); + if (!client) + return -ENODEV; + + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); + return 0; } static int -detach_thermostat(struct i2c_adapter *adapter) +remove_thermostat(struct i2c_client *client) { - struct thermostat* th; + struct thermostat *th = i2c_get_clientdata(client); int i; - if (thermostat == NULL) - return 0; - - th = thermostat; - if (thread_therm != NULL) { kthread_stop(thread_therm); } @@ -166,8 +173,6 @@ detach_thermostat(struct i2c_adapter *adapter) write_both_fan_speed(th, -1); - i2c_detach_client(&th->clt); - thermostat = NULL; kfree(th); @@ -175,14 +180,6 @@ detach_thermostat(struct i2c_adapter *adapter) return 0; } -static struct i2c_driver thermostat_driver = { - .driver = { - .name = "therm_adt746x", - }, - .attach_adapter = attach_thermostat, - .detach_adapter = detach_thermostat, -}; - static int read_fan_speed(struct thermostat *th, u8 addr) { u8 tmp[2]; @@ -371,8 +368,8 @@ static void set_limit(struct thermostat *th, int i) th->limits[i] = default_limits_local[i] + limit_adjust; } -static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, - int busno) +static int probe_thermostat(struct i2c_client *client, + const struct i2c_device_id *id) { struct thermostat* th; int rc; @@ -385,16 +382,12 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, if (!th) return -ENOMEM; - th->clt.addr = addr; - th->clt.adapter = adapter; - th->clt.driver = &thermostat_driver; - strcpy(th->clt.name, "thermostat"); + i2c_set_clientdata(client, th); + th->clt = client; rc = read_reg(th, 0); if (rc < 0) { - printk(KERN_ERR "adt746x: Thermostat failed to read config " - "from bus %d !\n", - busno); + dev_err(&client->dev, "Thermostat failed to read config!\n"); kfree(th); return -ENODEV; } @@ -423,14 +416,6 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, thermostat = th; - if (i2c_attach_client(&th->clt)) { - printk(KERN_INFO "adt746x: Thermostat failed to attach " - "client !\n"); - thermostat = NULL; - kfree(th); - return -ENODEV; - } - /* be sure to really write fan speed the first time */ th->last_speed[0] = -2; th->last_speed[1] = -2; @@ -456,6 +441,21 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, return 0; } +static const struct i2c_device_id therm_adt746x_id[] = { + { "therm_adt746x", 0 }, + { } +}; + +static struct i2c_driver thermostat_driver = { + .driver = { + .name = "therm_adt746x", + }, + .attach_adapter = attach_thermostat, + .probe = probe_thermostat, + .remove = remove_thermostat, + .id_table = therm_adt746x_id, +}; + /* * Now, unfortunately, sysfs doesn't give us a nice void * we could * pass around to the attribute functions, so we don't really have diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 817607e2af6a..a028598af2d3 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -287,22 +287,6 @@ struct fcu_fan_table fcu_fans[] = { }; /* - * i2c_driver structure to attach to the host i2c controller - */ - -static int therm_pm72_attach(struct i2c_adapter *adapter); -static int therm_pm72_detach(struct i2c_adapter *adapter); - -static struct i2c_driver therm_pm72_driver = -{ - .driver = { - .name = "therm_pm72", - }, - .attach_adapter = therm_pm72_attach, - .detach_adapter = therm_pm72_detach, -}; - -/* * Utility function to create an i2c_client structure and * attach it to one of u3 adapters */ @@ -310,6 +294,7 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name) { struct i2c_client *clt; struct i2c_adapter *adap; + struct i2c_board_info info; if (id & 0x200) adap = k2; @@ -320,31 +305,21 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name) if (adap == NULL) return NULL; - clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (clt == NULL) - return NULL; - - clt->addr = (id >> 1) & 0x7f; - clt->adapter = adap; - clt->driver = &therm_pm72_driver; - strncpy(clt->name, name, I2C_NAME_SIZE-1); - - if (i2c_attach_client(clt)) { + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = (id >> 1) & 0x7f; + strlcpy(info.type, "therm_pm72", I2C_NAME_SIZE); + clt = i2c_new_device(adap, &info); + if (!clt) { printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id); - kfree(clt); return NULL; } - return clt; -} -/* - * Utility function to get rid of the i2c_client structure - * (will also detach from the adapter hopepfully) - */ -static void detach_i2c_chip(struct i2c_client *clt) -{ - i2c_detach_client(clt); - kfree(clt); + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&clt->detected, &clt->driver->clients); + return clt; } /* @@ -1203,8 +1178,6 @@ static int init_cpu_state(struct cpu_pid_state *state, int index) return 0; fail: - if (state->monitor) - detach_i2c_chip(state->monitor); state->monitor = NULL; return -ENODEV; @@ -1232,7 +1205,6 @@ static void dispose_cpu_state(struct cpu_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm); } - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1407,7 +1379,6 @@ static void dispose_backside_state(struct backside_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_backside_temperature); device_remove_file(&of_dev->dev, &dev_attr_backside_fan_pwm); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1532,7 +1503,6 @@ static void dispose_drives_state(struct drives_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_drives_temperature); device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1654,7 +1624,6 @@ static void dispose_dimms_state(struct dimm_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_dimms_temperature); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1779,7 +1748,6 @@ static void dispose_slots_state(struct slots_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_slots_temperature); device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -2008,8 +1976,6 @@ static int attach_fcu(void) */ static void detach_fcu(void) { - if (fcu) - detach_i2c_chip(fcu); fcu = NULL; } @@ -2060,12 +2026,21 @@ static int therm_pm72_attach(struct i2c_adapter *adapter) return 0; } +static int therm_pm72_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + /* Always succeed, the real work was done in therm_pm72_attach() */ + return 0; +} + /* - * Called on every adapter when the driver or the i2c controller + * Called when any of the devices which participates into thermal management * is going away. */ -static int therm_pm72_detach(struct i2c_adapter *adapter) +static int therm_pm72_remove(struct i2c_client *client) { + struct i2c_adapter *adapter = client->adapter; + mutex_lock(&driver_lock); if (state != state_detached) @@ -2096,6 +2071,30 @@ static int therm_pm72_detach(struct i2c_adapter *adapter) return 0; } +/* + * i2c_driver structure to attach to the host i2c controller + */ + +static const struct i2c_device_id therm_pm72_id[] = { + /* + * Fake device name, thermal management is done by several + * chips but we don't need to differentiate between them at + * this point. + */ + { "therm_pm72", 0 }, + { } +}; + +static struct i2c_driver therm_pm72_driver = { + .driver = { + .name = "therm_pm72", + }, + .attach_adapter = therm_pm72_attach, + .probe = therm_pm72_probe, + .remove = therm_pm72_remove, + .id_table = therm_pm72_id, +}; + static int fan_check_loc_match(const char *loc, int fan) { char tmp[64]; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 3da0a02efd76..40023313a760 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -48,16 +48,6 @@ #define LOG_TEMP 0 /* continously log temperature */ -static int do_probe( struct i2c_adapter *adapter, int addr, int kind); - -/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ -static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, - 0x4c, 0x4d, 0x4e, 0x4f, - 0x2c, 0x2d, 0x2e, 0x2f, - I2C_CLIENT_END }; - -I2C_CLIENT_INSMOD; - static struct { volatile int running; struct task_struct *poll_task; @@ -315,53 +305,54 @@ static int control_loop(void *dummy) static int do_attach( struct i2c_adapter *adapter ) { - int ret = 0; + /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ + static const unsigned short scan_ds1775[] = { + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + I2C_CLIENT_END + }; + static const unsigned short scan_adm1030[] = { + 0x2c, 0x2d, 0x2e, 0x2f, + I2C_CLIENT_END + }; if( strncmp(adapter->name, "uni-n", 5) ) return 0; if( !x.running ) { - ret = i2c_probe( adapter, &addr_data, &do_probe ); + struct i2c_board_info info; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE); + i2c_new_probed_device(adapter, &info, scan_ds1775); + + strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE); + i2c_new_probed_device(adapter, &info, scan_adm1030); + if( x.thermostat && x.fan ) { x.running = 1; x.poll_task = kthread_run(control_loop, NULL, "g4fand"); } } - return ret; + return 0; } static int -do_detach( struct i2c_client *client ) +do_remove(struct i2c_client *client) { - int err; - - if( (err=i2c_detach_client(client)) ) - printk(KERN_ERR "failed to detach thermostat client\n"); - else { - if( x.running ) { - x.running = 0; - kthread_stop(x.poll_task); - x.poll_task = NULL; - } - if( client == x.thermostat ) - x.thermostat = NULL; - else if( client == x.fan ) - x.fan = NULL; - else { - printk(KERN_ERR "g4fan: bad client\n"); - } - kfree( client ); + if (x.running) { + x.running = 0; + kthread_stop(x.poll_task); + x.poll_task = NULL; } - return err; -} + if (client == x.thermostat) + x.thermostat = NULL; + else if (client == x.fan) + x.fan = NULL; + else + printk(KERN_ERR "g4fan: bad client\n"); -static struct i2c_driver g4fan_driver = { - .driver = { - .name = "therm_windtunnel", - }, - .attach_adapter = do_attach, - .detach_client = do_detach, -}; + return 0; +} static int attach_fan( struct i2c_client *cl ) @@ -374,13 +365,8 @@ attach_fan( struct i2c_client *cl ) goto out; printk("ADM1030 fan controller [@%02x]\n", cl->addr ); - strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) ); - - if( !i2c_attach_client(cl) ) - x.fan = cl; + x.fan = cl; out: - if( cl != x.fan ) - kfree( cl ); return 0; } @@ -412,39 +398,47 @@ attach_thermostat( struct i2c_client *cl ) x.temp = temp; x.overheat_temp = os_temp; x.overheat_hyst = hyst_temp; - - strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) ); - - if( !i2c_attach_client(cl) ) - x.thermostat = cl; + x.thermostat = cl; out: - if( cl != x.thermostat ) - kfree( cl ); return 0; } +enum chip { ds1775, adm1030 }; + +static const struct i2c_device_id therm_windtunnel_id[] = { + { "therm_ds1775", ds1775 }, + { "therm_adm1030", adm1030 }, + { } +}; + static int -do_probe( struct i2c_adapter *adapter, int addr, int kind ) +do_probe(struct i2c_client *cl, const struct i2c_device_id *id) { - struct i2c_client *cl; + struct i2c_adapter *adapter = cl->adapter; if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE) ) return 0; - if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) ) - return -ENOMEM; - - cl->addr = addr; - cl->adapter = adapter; - cl->driver = &g4fan_driver; - cl->flags = 0; - - if( addr < 0x48 ) + switch (id->driver_data) { + case adm1030: return attach_fan( cl ); - return attach_thermostat( cl ); + case ds1775: + return attach_thermostat(cl); + } + return 0; } +static struct i2c_driver g4fan_driver = { + .driver = { + .name = "therm_windtunnel", + }, + .attach_adapter = do_attach, + .probe = do_probe, + .remove = do_remove, + .id_table = therm_windtunnel_id, +}; + /************************************************************************/ /* initialization / cleanup */ diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index b92b959fe16e..529886c7a826 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -37,34 +37,22 @@ struct wf_lm75_sensor { int ds1775 : 1; int inited : 1; - struct i2c_client i2c; + struct i2c_client *i2c; struct wf_sensor sens; }; #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) -#define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c) - -static int wf_lm75_attach(struct i2c_adapter *adapter); -static int wf_lm75_detach(struct i2c_client *client); - -static struct i2c_driver wf_lm75_driver = { - .driver = { - .name = "wf_lm75", - }, - .attach_adapter = wf_lm75_attach, - .detach_client = wf_lm75_detach, -}; static int wf_lm75_get(struct wf_sensor *sr, s32 *value) { struct wf_lm75_sensor *lm = wf_to_lm75(sr); s32 data; - if (lm->i2c.adapter == NULL) + if (lm->i2c == NULL) return -ENODEV; /* Init chip if necessary */ if (!lm->inited) { - u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1); + u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(lm->i2c, 1); DBG("wf_lm75: Initializing %s, cfg was: %02x\n", sr->name, cfg); @@ -73,7 +61,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value) * the firmware for now */ cfg_new = cfg & ~0x01; - i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new); + i2c_smbus_write_byte_data(lm->i2c, 1, cfg_new); lm->inited = 1; /* If we just powered it up, let's wait 200 ms */ @@ -81,7 +69,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value) } /* Read temperature register */ - data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0)); + data = (s32)le16_to_cpu(i2c_smbus_read_word_data(lm->i2c, 0)); data <<= 8; *value = data; @@ -92,12 +80,6 @@ static void wf_lm75_release(struct wf_sensor *sr) { struct wf_lm75_sensor *lm = wf_to_lm75(sr); - /* check if client is registered and detach from i2c */ - if (lm->i2c.adapter) { - i2c_detach_client(&lm->i2c); - lm->i2c.adapter = NULL; - } - kfree(lm); } @@ -107,59 +89,77 @@ static struct wf_sensor_ops wf_lm75_ops = { .owner = THIS_MODULE, }; -static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, - u8 addr, int ds1775, - const char *loc) +static int wf_lm75_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wf_lm75_sensor *lm; int rc; - DBG("wf_lm75: creating %s device at address 0x%02x\n", - ds1775 ? "ds1775" : "lm75", addr); - lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); if (lm == NULL) - return NULL; + return -ENODEV; + + lm->inited = 0; + lm->ds1775 = id->driver_data; + lm->i2c = client; + lm->sens.name = client->dev.platform_data; + lm->sens.ops = &wf_lm75_ops; + i2c_set_clientdata(client, lm); + + rc = wf_register_sensor(&lm->sens); + if (rc) { + i2c_set_clientdata(client, NULL); + kfree(lm); + } + + return rc; +} + +static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter, + u8 addr, int ds1775, + const char *loc) +{ + struct i2c_board_info info; + struct i2c_client *client; + char *name; + + DBG("wf_lm75: creating %s device at address 0x%02x\n", + ds1775 ? "ds1775" : "lm75", addr); /* Usual rant about sensor names not beeing very consistent in * the device-tree, oh well ... * Add more entries below as you deal with more setups */ if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) - lm->sens.name = "hd-temp"; + name = "hd-temp"; else if (!strcmp(loc, "Incoming Air Temp")) - lm->sens.name = "incoming-air-temp"; + name = "incoming-air-temp"; else if (!strcmp(loc, "ODD Temp")) - lm->sens.name = "optical-drive-temp"; + name = "optical-drive-temp"; else if (!strcmp(loc, "HD Temp")) - lm->sens.name = "hard-drive-temp"; + name = "hard-drive-temp"; else goto fail; - lm->inited = 0; - lm->sens.ops = &wf_lm75_ops; - lm->ds1775 = ds1775; - lm->i2c.addr = (addr >> 1) & 0x7f; - lm->i2c.adapter = adapter; - lm->i2c.driver = &wf_lm75_driver; - strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1); - - rc = i2c_attach_client(&lm->i2c); - if (rc) { - printk(KERN_ERR "windfarm: failed to attach %s %s to i2c," - " err %d\n", ds1775 ? "ds1775" : "lm75", - lm->i2c.name, rc); - goto fail; - } + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = (addr >> 1) & 0x7f; + info.platform_data = name; + strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE); - if (wf_register_sensor(&lm->sens)) { - i2c_detach_client(&lm->i2c); + client = i2c_new_device(adapter, &info); + if (client == NULL) { + printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n", + ds1775 ? "ds1775" : "lm75", name); goto fail; } - return lm; + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); + return client; fail: - kfree(lm); return NULL; } @@ -202,21 +202,38 @@ static int wf_lm75_attach(struct i2c_adapter *adapter) return 0; } -static int wf_lm75_detach(struct i2c_client *client) +static int wf_lm75_remove(struct i2c_client *client) { - struct wf_lm75_sensor *lm = i2c_to_lm75(client); + struct wf_lm75_sensor *lm = i2c_get_clientdata(client); DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name); /* Mark client detached */ - lm->i2c.adapter = NULL; + lm->i2c = NULL; /* release sensor */ wf_unregister_sensor(&lm->sens); + i2c_set_clientdata(client, NULL); return 0; } +static const struct i2c_device_id wf_lm75_id[] = { + { "wf_lm75", 0 }, + { "wf_ds1775", 1 }, + { } +}; + +static struct i2c_driver wf_lm75_driver = { + .driver = { + .name = "wf_lm75", + }, + .attach_adapter = wf_lm75_attach, + .probe = wf_lm75_probe, + .remove = wf_lm75_remove, + .id_table = wf_lm75_id, +}; + static int __init wf_lm75_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index e207a90d6b27..e2a55ecda2b2 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -26,34 +26,22 @@ #define MAX6690_EXTERNAL_TEMP 1 struct wf_6690_sensor { - struct i2c_client i2c; + struct i2c_client *i2c; struct wf_sensor sens; }; #define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens) -#define i2c_to_6690(x) container_of((x), struct wf_6690_sensor, i2c) - -static int wf_max6690_attach(struct i2c_adapter *adapter); -static int wf_max6690_detach(struct i2c_client *client); - -static struct i2c_driver wf_max6690_driver = { - .driver = { - .name = "wf_max6690", - }, - .attach_adapter = wf_max6690_attach, - .detach_client = wf_max6690_detach, -}; static int wf_max6690_get(struct wf_sensor *sr, s32 *value) { struct wf_6690_sensor *max = wf_to_6690(sr); s32 data; - if (max->i2c.adapter == NULL) + if (max->i2c == NULL) return -ENODEV; /* chip gets initialized by firmware */ - data = i2c_smbus_read_byte_data(&max->i2c, MAX6690_EXTERNAL_TEMP); + data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP); if (data < 0) return data; *value = data << 16; @@ -64,10 +52,6 @@ static void wf_max6690_release(struct wf_sensor *sr) { struct wf_6690_sensor *max = wf_to_6690(sr); - if (max->i2c.adapter) { - i2c_detach_client(&max->i2c); - max->i2c.adapter = NULL; - } kfree(max); } @@ -77,19 +61,40 @@ static struct wf_sensor_ops wf_max6690_ops = { .owner = THIS_MODULE, }; -static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, - const char *loc) +static int wf_max6690_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wf_6690_sensor *max; - char *name; + int rc; max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); if (max == NULL) { - printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: " - "no memory\n", loc); - return; + printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: " + "no memory\n"); + return -ENOMEM; + } + + max->i2c = client; + max->sens.name = client->dev.platform_data; + max->sens.ops = &wf_max6690_ops; + i2c_set_clientdata(client, max); + + rc = wf_register_sensor(&max->sens); + if (rc) { + i2c_set_clientdata(client, NULL); + kfree(max); } + return rc; +} + +static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter, + u8 addr, const char *loc) +{ + struct i2c_board_info info; + struct i2c_client *client; + char *name; + if (!strcmp(loc, "BACKSIDE")) name = "backside-temp"; else if (!strcmp(loc, "NB Ambient")) @@ -99,27 +104,26 @@ static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, else goto fail; - max->sens.ops = &wf_max6690_ops; - max->sens.name = name; - max->i2c.addr = addr >> 1; - max->i2c.adapter = adapter; - max->i2c.driver = &wf_max6690_driver; - strncpy(max->i2c.name, name, I2C_NAME_SIZE-1); + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = addr >> 1; + info.platform_data = name; + strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE); - if (i2c_attach_client(&max->i2c)) { + client = i2c_new_device(adapter, &info); + if (client == NULL) { printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n"); goto fail; } - if (wf_register_sensor(&max->sens)) { - i2c_detach_client(&max->i2c); - goto fail; - } - - return; + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); + return client; fail: - kfree(max); + return NULL; } static int wf_max6690_attach(struct i2c_adapter *adapter) @@ -154,16 +158,31 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) return 0; } -static int wf_max6690_detach(struct i2c_client *client) +static int wf_max6690_remove(struct i2c_client *client) { - struct wf_6690_sensor *max = i2c_to_6690(client); + struct wf_6690_sensor *max = i2c_get_clientdata(client); - max->i2c.adapter = NULL; + max->i2c = NULL; wf_unregister_sensor(&max->sens); return 0; } +static const struct i2c_device_id wf_max6690_id[] = { + { "wf_max6690", 0 }, + { } +}; + +static struct i2c_driver wf_max6690_driver = { + .driver = { + .name = "wf_max6690", + }, + .attach_adapter = wf_max6690_attach, + .probe = wf_max6690_probe, + .remove = wf_max6690_remove, + .id_table = wf_max6690_id, +}; + static int __init wf_max6690_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 7847e981ac33..5da729e58f99 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -39,7 +39,7 @@ struct wf_sat { struct mutex mutex; unsigned long last_read; /* jiffies when cache last updated */ u8 cache[16]; - struct i2c_client i2c; + struct i2c_client *i2c; struct device_node *node; }; @@ -54,18 +54,6 @@ struct wf_sat_sensor { }; #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) -#define i2c_to_sat(c) container_of(c, struct wf_sat, i2c) - -static int wf_sat_attach(struct i2c_adapter *adapter); -static int wf_sat_detach(struct i2c_client *client); - -static struct i2c_driver wf_sat_driver = { - .driver = { - .name = "wf_smu_sat", - }, - .attach_adapter = wf_sat_attach, - .detach_client = wf_sat_detach, -}; struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, unsigned int *size) @@ -81,13 +69,13 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, if (sat_id > 1 || (sat = sats[sat_id]) == NULL) return NULL; - err = i2c_smbus_write_word_data(&sat->i2c, 8, id << 8); + err = i2c_smbus_write_word_data(sat->i2c, 8, id << 8); if (err) { printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err); return NULL; } - err = i2c_smbus_read_word_data(&sat->i2c, 9); + err = i2c_smbus_read_word_data(sat->i2c, 9); if (err < 0) { printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n"); return NULL; @@ -105,7 +93,7 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, return NULL; for (i = 0; i < len; i += 4) { - err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0xa, 4, data); + err = i2c_smbus_read_i2c_block_data(sat->i2c, 0xa, 4, data); if (err < 0) { printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n", err); @@ -138,7 +126,7 @@ static int wf_sat_read_cache(struct wf_sat *sat) { int err; - err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0x3f, 16, sat->cache); + err = i2c_smbus_read_i2c_block_data(sat->i2c, 0x3f, 16, sat->cache); if (err < 0) return err; sat->last_read = jiffies; @@ -161,7 +149,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value) int i, err; s32 val; - if (sat->i2c.adapter == NULL) + if (sat->i2c == NULL) return -ENODEV; mutex_lock(&sat->mutex); @@ -193,10 +181,6 @@ static void wf_sat_release(struct wf_sensor *sr) struct wf_sat *sat = sens->sat; if (atomic_dec_and_test(&sat->refcnt)) { - if (sat->i2c.adapter) { - i2c_detach_client(&sat->i2c); - sat->i2c.adapter = NULL; - } if (sat->nr >= 0) sats[sat->nr] = NULL; kfree(sat); @@ -212,38 +196,58 @@ static struct wf_sensor_ops wf_sat_ops = { static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) { + struct i2c_board_info info; + struct i2c_client *client; + const u32 *reg; + u8 addr; + + reg = of_get_property(dev, "reg", NULL); + if (reg == NULL) + return; + addr = *reg; + DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr); + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = (addr >> 1) & 0x7f; + info.platform_data = dev; + strlcpy(info.type, "wf_sat", I2C_NAME_SIZE); + + client = i2c_new_device(adapter, &info); + if (client == NULL) { + printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); + return; + } + + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); +} + +static int wf_sat_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *dev = client->dev.platform_data; struct wf_sat *sat; struct wf_sat_sensor *sens; const u32 *reg; const char *loc, *type; - u8 addr, chip, core; + u8 chip, core; struct device_node *child; int shift, cpu, index; char *name; int vsens[2], isens[2]; - reg = of_get_property(dev, "reg", NULL); - if (reg == NULL) - return; - addr = *reg; - DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr); - sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL); if (sat == NULL) - return; + return -ENOMEM; sat->nr = -1; sat->node = of_node_get(dev); atomic_set(&sat->refcnt, 0); mutex_init(&sat->mutex); - sat->i2c.addr = (addr >> 1) & 0x7f; - sat->i2c.adapter = adapter; - sat->i2c.driver = &wf_sat_driver; - strncpy(sat->i2c.name, "smu-sat", I2C_NAME_SIZE-1); - - if (i2c_attach_client(&sat->i2c)) { - printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); - goto fail; - } + sat->i2c = client; + i2c_set_clientdata(client, sat); vsens[0] = vsens[1] = -1; isens[0] = isens[1] = -1; @@ -344,10 +348,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) if (sat->nr >= 0) sats[sat->nr] = sat; - return; - - fail: - kfree(sat); + return 0; } static int wf_sat_attach(struct i2c_adapter *adapter) @@ -366,16 +367,32 @@ static int wf_sat_attach(struct i2c_adapter *adapter) return 0; } -static int wf_sat_detach(struct i2c_client *client) +static int wf_sat_remove(struct i2c_client *client) { - struct wf_sat *sat = i2c_to_sat(client); + struct wf_sat *sat = i2c_get_clientdata(client); /* XXX TODO */ - sat->i2c.adapter = NULL; + sat->i2c = NULL; + i2c_set_clientdata(client, NULL); return 0; } +static const struct i2c_device_id wf_sat_id[] = { + { "wf_sat", 0 }, + { } +}; + +static struct i2c_driver wf_sat_driver = { + .driver = { + .name = "wf_smu_sat", + }, + .attach_adapter = wf_sat_attach, + .probe = wf_sat_probe, + .remove = wf_sat_remove, + .id_table = wf_sat_id, +}; + static int __init sat_sensors_init(void) { return i2c_add_driver(&wf_sat_driver); diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 89fec052f3b4..9118613af321 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -48,6 +48,20 @@ config EEPROM_LEGACY This driver can also be built as a module. If so, the module will be called eeprom. +config EEPROM_MAX6875 + tristate "Maxim MAX6874/5 power supply supervisor" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get read-only support for the user EEPROM of + the Maxim MAX6874/5 EEPROM-programmable, quad power-supply + sequencer/supervisor. + + All other features of this chip should be accessed via i2c-dev. + + This driver can also be built as a module. If so, the module + will be called max6875. + + config EEPROM_93CX6 tristate "EEPROM 93CX6 support" help diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 539dd8f88128..df3d68ffa9d1 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_EEPROM_AT24) += at24.o obj-$(CONFIG_EEPROM_AT25) += at25.o obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o +obj-$(CONFIG_EEPROM_MAX6875) += max6875.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o diff --git a/drivers/i2c/chips/max6875.c b/drivers/misc/eeprom/max6875.c index 033d9d81ec8a..3c0c58eed347 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/misc/eeprom/max6875.c @@ -3,7 +3,7 @@ Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> - Based on i2c/chips/eeprom.c + Based on eeprom.c The MAX6875 has a bank of registers and two banks of EEPROM. Address ranges are defined as follows: diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 30900b30d532..2b38f39924a6 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1648,7 +1648,7 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) result = -ENOMEM; goto fail_alloc_card; } - ps3_system_bus_set_driver_data(dev, card); + ps3_system_bus_set_drvdata(dev, card); card->dev = dev; /* get internal vlan info */ @@ -1749,7 +1749,7 @@ fail_alloc_irq: bus_id(card), 0, 0); fail_status_indicator: - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); kfree(netdev_card(netdev)->unalign); free_netdev(netdev); fail_alloc_card: @@ -1766,7 +1766,7 @@ fail_open: static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) { - struct gelic_card *card = ps3_system_bus_get_driver_data(dev); + struct gelic_card *card = ps3_system_bus_get_drvdata(dev); struct net_device *netdev0; pr_debug("%s: called\n", __func__); @@ -1803,7 +1803,7 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) kfree(netdev_card(netdev0)->unalign); free_netdev(netdev0); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); ps3_dma_region_free(dev->d_region); diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c index f17513dd9d4b..88cb74088611 100644 --- a/drivers/ps3/ps3-sys-manager.c +++ b/drivers/ps3/ps3-sys-manager.c @@ -706,7 +706,7 @@ static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); } -static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) +static int __devinit ps3_sys_manager_probe(struct ps3_system_bus_device *dev) { int result; struct ps3_sys_manager_ops ops; diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 235e87fcb49f..e82d8c9c6cda 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -80,12 +80,12 @@ static const struct avset_video_mode { { 0, }, /* auto */ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_W, 1280, 720}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_W, 1280, 720}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080}, { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768}, @@ -937,7 +937,7 @@ int ps3av_audio_mute(int mute) EXPORT_SYMBOL_GPL(ps3av_audio_mute); -static int ps3av_probe(struct ps3_system_bus_device *dev) +static int __devinit ps3av_probe(struct ps3_system_bus_device *dev) { int res; int id; @@ -1048,7 +1048,7 @@ static struct ps3_vuart_port_driver ps3av_driver = { .shutdown = ps3av_shutdown, }; -static int ps3av_module_init(void) +static int __init ps3av_module_init(void) { int error; diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index 716596e8e5b0..f555fedd5073 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c @@ -21,9 +21,10 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> + #include <asm/ps3av.h> -#include <asm/ps3fb.h> #include <asm/ps3.h> +#include <asm/ps3gpu.h> #include "vuart.h" diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 1ba9f9a8c308..bb870b8f81bc 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -162,7 +162,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, (unsigned long)virq); - ps3_system_bus_set_driver_data(dev, hcd); + ps3_system_bus_set_drvdata(dev, hcd); result = usb_add_hcd(hcd, virq, IRQF_DISABLED); @@ -195,8 +195,7 @@ fail_start: static int ps3_ehci_remove(struct ps3_system_bus_device *dev) { unsigned int tmp; - struct usb_hcd *hcd = - (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); BUG_ON(!hcd); @@ -208,7 +207,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev) ehci_shutdown(hcd); usb_remove_hcd(hcd); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); BUG_ON(!hcd->regs); iounmap(hcd->regs); diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 3d1910317328..1d56259c5db1 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -162,7 +162,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, (unsigned long)virq); - ps3_system_bus_set_driver_data(dev, hcd); + ps3_system_bus_set_drvdata(dev, hcd); result = usb_add_hcd(hcd, virq, IRQF_DISABLED); @@ -195,8 +195,7 @@ fail_start: static int ps3_ohci_remove(struct ps3_system_bus_device *dev) { unsigned int tmp; - struct usb_hcd *hcd = - (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); BUG_ON(!hcd); @@ -208,7 +207,7 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev) ohci_shutdown(hcd); usb_remove_hcd(hcd); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); BUG_ON(!hcd->regs); iounmap(hcd->regs); diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index e00c1dff55de..c0af638fe702 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -32,25 +32,16 @@ #include <linux/init.h> #include <asm/abs_addr.h> +#include <asm/iommu.h> #include <asm/lv1call.h> #include <asm/ps3av.h> #include <asm/ps3fb.h> #include <asm/ps3.h> +#include <asm/ps3gpu.h> #define DEVICE_NAME "ps3fb" -#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 -#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602 - -#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32) - -#define L1GPU_DISPLAY_SYNC_HSYNC 1 -#define L1GPU_DISPLAY_SYNC_VSYNC 2 - #define GPU_CMD_BUF_SIZE (2 * 1024 * 1024) #define GPU_FB_START (64 * 1024) #define GPU_IOIF (0x0d000000UL) @@ -462,33 +453,27 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset, src_offset += GPU_FB_START; mutex_lock(&ps3_gpu_mutex); - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, - dst_offset, GPU_IOIF + src_offset, - L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | - (width << 16) | height, - line_length); + status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset, + GPU_IOIF + src_offset, + L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | + (width << 16) | height, + line_length); mutex_unlock(&ps3_gpu_mutex); if (status) - dev_err(dev, - "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__, + status); #ifdef HEAD_A - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 0, frame_offset, 0, 0); + status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset); if (status) - dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, + status); #endif #ifdef HEAD_B - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 1, frame_offset, 0, 0); + status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset); if (status) - dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, + status); #endif } @@ -956,73 +941,6 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) } -static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, - struct device *dev) -{ - int error; - - dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver); - dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet); - dev_dbg(dev, - "version_gpu: %x memory_size: %x ch: %x core_freq: %d " - "mem_freq:%d\n", - dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel, - dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); - - if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { - dev_err(dev, "%s: version_driver err:%x\n", __func__, - dinfo->version_driver); - return -EINVAL; - } - - error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, - &ps3fb.irq_no); - if (error) { - dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error); - return error; - } - - error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, - DEVICE_NAME, dev); - if (error) { - dev_err(dev, "%s: request_irq failed %d\n", __func__, error); - ps3_irq_plug_destroy(ps3fb.irq_no); - return error; - } - - dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | - (1 << GPU_INTR_STATUS_FLIP_1); - return 0; -} - -static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev) -{ - int status; - - status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, - xdr_lpar, ps3fb_videomemory.size, 0); - if (status) { - dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n", - __func__, status); - return -ENXIO; - } - dev_dbg(dev, "video:%p ioif:%lx lpar:%llx size:%lx\n", - ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, - ps3fb_videomemory.size); - - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, - xdr_lpar, GPU_CMD_BUF_SIZE, - GPU_IOIF, 0); - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", - __func__, status); - return -ENXIO; - } - return 0; -} - static struct fb_ops ps3fb_ops = { .fb_open = ps3fb_open, .fb_release = ps3fb_release, @@ -1048,49 +966,18 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static int ps3fb_set_sync(struct device *dev) -{ - int status; - -#ifdef HEAD_A - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", - __func__, status); - return -1; - } -#endif -#ifdef HEAD_B - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); - - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", - __func__, status); - return -1; - } -#endif - return 0; -} - static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) { struct fb_info *info; struct ps3fb_par *par; - int retval = -ENOMEM; + int retval; u64 ddr_lpar = 0; u64 lpar_dma_control = 0; u64 lpar_driver_info = 0; u64 lpar_reports = 0; u64 lpar_reports_size = 0; u64 xdr_lpar; + struct gpu_driver_info *dinfo; void *fb_start; int status; struct task_struct *task; @@ -1101,8 +988,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) return -ENOMEM; } - status = ps3_open_hv_device(dev); - if (status) { + retval = ps3_open_hv_device(dev); + if (retval) { dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", __func__); goto err; @@ -1116,7 +1003,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ init_waitqueue_head(&ps3fb.wait_vsync); - ps3fb_set_sync(&dev->core); +#ifdef HEAD_A + status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", + __func__, status); + retval = -ENODEV; + goto err_close_device; + } +#endif +#ifdef HEAD_B + status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", + __func__, status); + retval = -ENODEV; + goto err_close_device; + } +#endif max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF; if (ps3fb_videomemory.size > max_ps3fb_size) { @@ -1131,7 +1035,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (status) { dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", __func__, status); - goto err; + goto err_close_device; } dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar); @@ -1141,33 +1045,85 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) &lpar_reports, &lpar_reports_size); if (status) { dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed: %d\n", __func__, + "%s: lv1_gpu_context_allocate failed: %d\n", __func__, status); goto err_gpu_memory_free; } /* vsync interrupt */ - ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); - if (!ps3fb.dinfo) { + dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); + if (!dinfo) { dev_err(&dev->core, "%s: ioremap failed\n", __func__); goto err_gpu_context_free; } - retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core); - if (retval) + ps3fb.dinfo = dinfo; + dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver); + dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet); + dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x " + "core_freq: %d mem_freq:%d\n", dinfo->version_gpu, + dinfo->memory_size, dinfo->hardware_channel, + dinfo->nvcore_frequency/1000000, + dinfo->memory_frequency/1000000); + + if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { + dev_err(&dev->core, "%s: version_driver err:%x\n", __func__, + dinfo->version_driver); + retval = -EINVAL; + goto err_iounmap_dinfo; + } + + retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, + &ps3fb.irq_no); + if (retval) { + dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__, + retval); goto err_iounmap_dinfo; + } + + retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, + IRQF_DISABLED, DEVICE_NAME, &dev->core); + if (retval) { + dev_err(&dev->core, "%s: request_irq failed %d\n", __func__, + retval); + goto err_destroy_plug; + } + + dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | + (1 << GPU_INTR_STATUS_FLIP_1); /* Clear memory to prevent kernel info leakage into userspace */ memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size); xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); - retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); - if (retval) + + status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, + xdr_lpar, ps3fb_videomemory.size, + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | + CBE_IOPTE_M); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n", + __func__, status); + retval = -ENXIO; goto err_free_irq; + } + + dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n", + ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size); + + status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar, + GPU_CMD_BUF_SIZE, GPU_IOIF); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n", + __func__, status); + retval = -ENXIO; + goto err_context_unmap; + } info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); if (!info) - goto err_free_irq; + goto err_context_fb_close; par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ @@ -1210,7 +1166,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (retval < 0) goto err_fb_dealloc; - dev->core.driver_data = info; + ps3_system_bus_set_drvdata(dev, info); dev_info(info->device, "%s %s, using %u KiB of video memory\n", dev_driver_string(info->dev), dev_name(info->dev), @@ -1232,8 +1188,14 @@ err_fb_dealloc: fb_dealloc_cmap(&info->cmap); err_framebuffer_release: framebuffer_release(info); +err_context_fb_close: + lv1_gpu_fb_close(ps3fb.context_handle); +err_context_unmap: + lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size, CBE_IOPTE_M); err_free_irq: free_irq(ps3fb.irq_no, &dev->core); +err_destroy_plug: ps3_irq_plug_destroy(ps3fb.irq_no); err_iounmap_dinfo: iounmap((u8 __force __iomem *)ps3fb.dinfo); @@ -1241,14 +1203,16 @@ err_gpu_context_free: lv1_gpu_context_free(ps3fb.context_handle); err_gpu_memory_free: lv1_gpu_memory_free(ps3fb.memory_handle); +err_close_device: + ps3_close_hv_device(dev); err: return retval; } static int ps3fb_shutdown(struct ps3_system_bus_device *dev) { - int status; - struct fb_info *info = dev->core.driver_data; + struct fb_info *info = ps3_system_bus_get_drvdata(dev); + u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); @@ -1268,20 +1232,14 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); framebuffer_release(info); - info = dev->core.driver_data = NULL; + ps3_system_bus_set_drvdata(dev, NULL); } iounmap((u8 __force __iomem *)ps3fb.dinfo); - - status = lv1_gpu_context_free(ps3fb.context_handle); - if (status) - dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n", - status); - - status = lv1_gpu_memory_free(ps3fb.memory_handle); - if (status) - dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n", - status); - + lv1_gpu_fb_close(ps3fb.context_handle); + lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size, CBE_IOPTE_M); + lv1_gpu_context_free(ps3fb.context_handle); + lv1_gpu_memory_free(ps3fb.memory_handle); ps3_close_hv_device(dev); dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 89f231dc443f..ff43c8885028 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1315,7 +1315,6 @@ static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan, strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name)); chan->adapter.owner = THIS_MODULE; - chan->adapter.class = I2C_CLASS_TV_ANALOG; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = dev; chan->algo.setsda = tdfxfb_i2c_setsda; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 2e177d7f4bb9..4e83457ea253 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -543,13 +543,13 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, btrfs_free_log(trans, root); btrfs_update_reloc_root(trans, root); - if (root->commit_root == root->node) - continue; - - free_extent_buffer(root->commit_root); - root->commit_root = btrfs_root_node(root); + if (root->commit_root != root->node) { + free_extent_buffer(root->commit_root); + root->commit_root = btrfs_root_node(root); + btrfs_set_root_node(&root->root_item, + root->node); + } - btrfs_set_root_node(&root->root_item, root->node); err = btrfs_update_root(trans, fs_info->tree_root, &root->root_key, &root->root_item); diff --git a/fs/fat/cache.c b/fs/fat/cache.c index b42602298087..923990e4f16e 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -241,7 +241,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) while (*fclus < cluster) { /* prevent the infinite loop of cluster chain */ if (*fclus > limit) { - fat_fs_panic(sb, "%s: detected the cluster chain loop" + fat_fs_error(sb, "%s: detected the cluster chain loop" " (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); nr = -EIO; @@ -252,7 +252,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) if (nr < 0) goto out; else if (nr == FAT_ENT_FREE) { - fat_fs_panic(sb, "%s: invalid cluster chain" + fat_fs_error(sb, "%s: invalid cluster chain" " (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); nr = -EIO; @@ -285,7 +285,7 @@ static int fat_bmap_cluster(struct inode *inode, int cluster) if (ret < 0) return ret; else if (ret == FAT_ENT_EOF) { - fat_fs_panic(sb, "%s: request beyond EOF (i_pos %lld)", + fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); return -EIO; } diff --git a/fs/fat/dir.c b/fs/fat/dir.c index f3500294eec5..3b8e71b412fd 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -1334,7 +1334,7 @@ found: goto error_remove; } if (dir->i_size & (sbi->cluster_size - 1)) { - fat_fs_panic(sb, "Odd directory size"); + fat_fs_error(sb, "Odd directory size"); dir->i_size = (dir->i_size + sbi->cluster_size - 1) & ~((loff_t)sbi->cluster_size - 1); } diff --git a/fs/fat/fat.h b/fs/fat/fat.h index e4d88527b5dd..adb0e72a176d 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -17,6 +17,10 @@ #define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */ #define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */ +#define FAT_ERRORS_CONT 1 /* ignore error and continue */ +#define FAT_ERRORS_PANIC 2 /* panic on error */ +#define FAT_ERRORS_RO 3 /* remount r/o on error */ + struct fat_mount_options { uid_t fs_uid; gid_t fs_gid; @@ -26,6 +30,7 @@ struct fat_mount_options { char *iocharset; /* Charset used for filename input/display */ unsigned short shortname; /* flags for shortname display/create rule */ unsigned char name_check; /* r = relaxed, n = normal, s = strict */ + unsigned char errors; /* On error: continue, panic, remount-ro */ unsigned short allow_utime;/* permission for setting the [am]time */ unsigned quiet:1, /* set = fake successful chmods and chowns */ showexec:1, /* set = only set x bit for com/exe/bat */ @@ -316,7 +321,7 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent, extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2); /* fat/misc.c */ -extern void fat_fs_panic(struct super_block *s, const char *fmt, ...) +extern void fat_fs_error(struct super_block *s, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))) __cold; extern void fat_clusters_flush(struct super_block *sb); extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 618f5305c2e4..a81037721a6f 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -348,7 +348,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry) if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { fatent_brelse(fatent); - fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry); + fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); return -EIO; } @@ -560,7 +560,7 @@ int fat_free_clusters(struct inode *inode, int cluster) err = cluster; goto error; } else if (cluster == FAT_ENT_FREE) { - fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF", + fat_fs_error(sb, "%s: deleting FAT entry beyond EOF", __func__); err = -EIO; goto error; diff --git a/fs/fat/file.c b/fs/fat/file.c index e955a56b4e5e..b28ea646ff60 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -18,106 +18,112 @@ #include <linux/security.h> #include "fat.h" -int fat_generic_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr) { + u32 attr; + + mutex_lock(&inode->i_mutex); + attr = fat_make_attrs(inode); + mutex_unlock(&inode->i_mutex); + + return put_user(attr, user_attr); +} + +static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr) +{ + struct inode *inode = file->f_path.dentry->d_inode; struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - u32 __user *user_attr = (u32 __user *)arg; + int is_dir = S_ISDIR(inode->i_mode); + u32 attr, oldattr; + struct iattr ia; + int err; - switch (cmd) { - case FAT_IOCTL_GET_ATTRIBUTES: - { - u32 attr; + err = get_user(attr, user_attr); + if (err) + goto out; - mutex_lock(&inode->i_mutex); - attr = fat_make_attrs(inode); - mutex_unlock(&inode->i_mutex); + mutex_lock(&inode->i_mutex); + err = mnt_want_write(file->f_path.mnt); + if (err) + goto out_unlock_inode; - return put_user(attr, user_attr); + /* + * ATTR_VOLUME and ATTR_DIR cannot be changed; this also + * prevents the user from turning us into a VFAT + * longname entry. Also, we obviously can't set + * any of the NTFS attributes in the high 24 bits. + */ + attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); + /* Merge in ATTR_VOLUME and ATTR_DIR */ + attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | + (is_dir ? ATTR_DIR : 0); + oldattr = fat_make_attrs(inode); + + /* Equivalent to a chmod() */ + ia.ia_valid = ATTR_MODE | ATTR_CTIME; + ia.ia_ctime = current_fs_time(inode->i_sb); + if (is_dir) + ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); + else { + ia.ia_mode = fat_make_mode(sbi, attr, + S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); } - case FAT_IOCTL_SET_ATTRIBUTES: - { - u32 attr, oldattr; - int err, is_dir = S_ISDIR(inode->i_mode); - struct iattr ia; - err = get_user(attr, user_attr); - if (err) - return err; + /* The root directory has no attributes */ + if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { + err = -EINVAL; + goto out_drop_write; + } - mutex_lock(&inode->i_mutex); - - err = mnt_want_write(filp->f_path.mnt); - if (err) - goto up_no_drop_write; - - /* - * ATTR_VOLUME and ATTR_DIR cannot be changed; this also - * prevents the user from turning us into a VFAT - * longname entry. Also, we obviously can't set - * any of the NTFS attributes in the high 24 bits. - */ - attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); - /* Merge in ATTR_VOLUME and ATTR_DIR */ - attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | - (is_dir ? ATTR_DIR : 0); - oldattr = fat_make_attrs(inode); - - /* Equivalent to a chmod() */ - ia.ia_valid = ATTR_MODE | ATTR_CTIME; - ia.ia_ctime = current_fs_time(inode->i_sb); - if (is_dir) - ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); - else { - ia.ia_mode = fat_make_mode(sbi, attr, - S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); - } + if (sbi->options.sys_immutable && + ((attr | oldattr) & ATTR_SYS) && + !capable(CAP_LINUX_IMMUTABLE)) { + err = -EPERM; + goto out_drop_write; + } - /* The root directory has no attributes */ - if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { - err = -EINVAL; - goto up; - } + /* + * The security check is questionable... We single + * out the RO attribute for checking by the security + * module, just because it maps to a file mode. + */ + err = security_inode_setattr(file->f_path.dentry, &ia); + if (err) + goto out_drop_write; - if (sbi->options.sys_immutable) { - if ((attr | oldattr) & ATTR_SYS) { - if (!capable(CAP_LINUX_IMMUTABLE)) { - err = -EPERM; - goto up; - } - } - } + /* This MUST be done before doing anything irreversible... */ + err = fat_setattr(file->f_path.dentry, &ia); + if (err) + goto out_drop_write; + + fsnotify_change(file->f_path.dentry, ia.ia_valid); + if (sbi->options.sys_immutable) { + if (attr & ATTR_SYS) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= S_IMMUTABLE; + } - /* - * The security check is questionable... We single - * out the RO attribute for checking by the security - * module, just because it maps to a file mode. - */ - err = security_inode_setattr(filp->f_path.dentry, &ia); - if (err) - goto up; - - /* This MUST be done before doing anything irreversible... */ - err = fat_setattr(filp->f_path.dentry, &ia); - if (err) - goto up; - - fsnotify_change(filp->f_path.dentry, ia.ia_valid); - if (sbi->options.sys_immutable) { - if (attr & ATTR_SYS) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= S_IMMUTABLE; - } + fat_save_attrs(inode, attr); + mark_inode_dirty(inode); +out_drop_write: + mnt_drop_write(file->f_path.mnt); +out_unlock_inode: + mutex_unlock(&inode->i_mutex); +out: + return err; +} - fat_save_attrs(inode, attr); - mark_inode_dirty(inode); -up: - mnt_drop_write(filp->f_path.mnt); -up_no_drop_write: - mutex_unlock(&inode->i_mutex); - return err; - } +int fat_generic_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + u32 __user *user_attr = (u32 __user *)arg; + + switch (cmd) { + case FAT_IOCTL_GET_ATTRIBUTES: + return fat_ioctl_get_attributes(inode, user_attr); + case FAT_IOCTL_SET_ATTRIBUTES: + return fat_ioctl_set_attributes(filp, user_attr); default: return -ENOTTY; /* Inappropriate ioctl for device */ } @@ -225,7 +231,7 @@ static int fat_free(struct inode *inode, int skip) fatent_brelse(&fatent); return 0; } else if (ret == FAT_ENT_FREE) { - fat_fs_panic(sb, + fat_fs_error(sb, "%s: invalid cluster chain (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); ret = -EIO; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 51a5ecf9000a..304b411cb8bc 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -76,7 +76,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock, return 0; if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { - fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)", + fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)", MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); return -EIO; } @@ -856,6 +856,12 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",flush"); if (opts->tz_utc) seq_puts(m, ",tz=UTC"); + if (opts->errors == FAT_ERRORS_CONT) + seq_puts(m, ",errors=continue"); + else if (opts->errors == FAT_ERRORS_PANIC) + seq_puts(m, ",errors=panic"); + else + seq_puts(m, ",errors=remount-ro"); return 0; } @@ -868,7 +874,8 @@ enum { Opt_charset, Opt_shortname_lower, Opt_shortname_win95, Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, - Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err, + Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, + Opt_err_panic, Opt_err_ro, Opt_err, }; static const match_table_t fat_tokens = { @@ -891,6 +898,11 @@ static const match_table_t fat_tokens = { {Opt_showexec, "showexec"}, {Opt_debug, "debug"}, {Opt_immutable, "sys_immutable"}, + {Opt_flush, "flush"}, + {Opt_tz_utc, "tz=UTC"}, + {Opt_err_cont, "errors=continue"}, + {Opt_err_panic, "errors=panic"}, + {Opt_err_ro, "errors=remount-ro"}, {Opt_obsolate, "conv=binary"}, {Opt_obsolate, "conv=text"}, {Opt_obsolate, "conv=auto"}, @@ -902,8 +914,6 @@ static const match_table_t fat_tokens = { {Opt_obsolate, "cvf_format=%20s"}, {Opt_obsolate, "cvf_options=%100s"}, {Opt_obsolate, "posix"}, - {Opt_flush, "flush"}, - {Opt_tz_utc, "tz=UTC"}, {Opt_err, NULL}, }; static const match_table_t msdos_tokens = { @@ -973,6 +983,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, opts->numtail = 1; opts->usefree = opts->nocase = 0; opts->tz_utc = 0; + opts->errors = FAT_ERRORS_RO; *debug = 0; if (!options) @@ -1065,6 +1076,15 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, case Opt_tz_utc: opts->tz_utc = 1; break; + case Opt_err_cont: + opts->errors = FAT_ERRORS_CONT; + break; + case Opt_err_panic: + opts->errors = FAT_ERRORS_PANIC; + break; + case Opt_err_ro: + opts->errors = FAT_ERRORS_RO; + break; /* msdos specific */ case Opt_dots: diff --git a/fs/fat/misc.c b/fs/fat/misc.c index ac39ebcc1496..a6c20473dfd7 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -12,14 +12,19 @@ #include "fat.h" /* - * fat_fs_panic reports a severe file system problem and sets the file system - * read-only. The file system can be made writable again by remounting it. + * fat_fs_error reports a file system problem that might indicate fa data + * corruption/inconsistency. Depending on 'errors' mount option the + * panic() is called, or error message is printed FAT and nothing is done, + * or filesystem is remounted read-only (default behavior). + * In case the file system is remounted read-only, it can be made writable + * again by remounting it. */ -void fat_fs_panic(struct super_block *s, const char *fmt, ...) +void fat_fs_error(struct super_block *s, const char *fmt, ...) { + struct fat_mount_options *opts = &MSDOS_SB(s)->options; va_list args; - printk(KERN_ERR "FAT: Filesystem panic (dev %s)\n", s->s_id); + printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id); printk(KERN_ERR " "); va_start(args, fmt); @@ -27,13 +32,14 @@ void fat_fs_panic(struct super_block *s, const char *fmt, ...) va_end(args); printk("\n"); - if (!(s->s_flags & MS_RDONLY)) { + if (opts->errors == FAT_ERRORS_PANIC) + panic(" FAT fs panic from previous error\n"); + else if (opts->errors == FAT_ERRORS_RO && !(s->s_flags & MS_RDONLY)) { s->s_flags |= MS_RDONLY; printk(KERN_ERR " File system has been set read-only\n"); } } - -EXPORT_SYMBOL_GPL(fat_fs_panic); +EXPORT_SYMBOL_GPL(fat_fs_error); /* Flushes the number of free clusters on FAT32 */ /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ @@ -124,7 +130,7 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) mark_inode_dirty(inode); } if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { - fat_fs_panic(sb, "clusters badly computed (%d != %llu)", + fat_fs_error(sb, "clusters badly computed (%d != %llu)", new_fclus, (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); fat_cache_inval_inode(inode); diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 20f522861355..82f88733b681 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -608,7 +608,7 @@ error_inode: sinfo.bh = NULL; } if (corrupt < 0) { - fat_fs_panic(new_dir->i_sb, + fat_fs_error(new_dir->i_sb, "%s: Filesystem corrupted (i_pos %lld)", __func__, sinfo.i_pos); } diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index b50ecbe97f83..8d6fdcfd41df 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -1030,7 +1030,7 @@ error_inode: sinfo.bh = NULL; } if (corrupt < 0) { - fat_fs_panic(new_dir->i_sb, + fat_fs_error(new_dir->i_sb, "%s: Filesystem corrupted (i_pos %lld)", __func__, sinfo.i_pos); } diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 4db89e98535d..82ec6a3c0500 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -47,7 +47,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20090320 +#define ACPI_CA_VERSION 0x20090521 #include "actypes.h" #include "actbl.h" @@ -201,6 +201,8 @@ acpi_evaluate_object_typed(acpi_handle object, acpi_status acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer); +acpi_status acpi_install_method(u8 *buffer); + acpi_status acpi_get_next_object(acpi_object_type type, acpi_handle parent, @@ -375,7 +377,7 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state); acpi_status acpi_leave_sleep_state(u8 sleep_state); /* - * Debug output + * Error/Warning output */ void ACPI_INTERNAL_VAR_XFACE acpi_error(const char *module_name, @@ -394,6 +396,9 @@ void ACPI_INTERNAL_VAR_XFACE acpi_info(const char *module_name, u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3); +/* + * Debug output + */ #ifdef ACPI_DEBUG_OUTPUT void ACPI_INTERNAL_VAR_XFACE diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index f555d927f7c0..37ba576d06e8 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -429,20 +429,12 @@ typedef unsigned long long acpi_integer; /* Data manipulation */ -#define ACPI_LOWORD(l) ((u16)(u32)(l)) -#define ACPI_HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF)) -#define ACPI_LOBYTE(l) ((u8)(u16)(l)) -#define ACPI_HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) - -/* Full 64-bit integer must be available on both 32-bit and 64-bit platforms */ - -struct acpi_integer_overlay { - u32 lo_dword; - u32 hi_dword; -}; - -#define ACPI_LODWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->lo_dword) -#define ACPI_HIDWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->hi_dword) +#define ACPI_LOBYTE(integer) ((u8) (u16)(integer)) +#define ACPI_HIBYTE(integer) ((u8) (((u16)(integer)) >> 8)) +#define ACPI_LOWORD(integer) ((u16) (u32)(integer)) +#define ACPI_HIWORD(integer) ((u16)(((u32)(integer)) >> 16)) +#define ACPI_LODWORD(integer64) ((u32) (u64)(integer64)) +#define ACPI_HIDWORD(integer64) ((u32)(((u64)(integer64)) >> 32)) #define ACPI_SET_BIT(target,bit) ((target) |= (bit)) #define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index 8e2cdc57b197..935c5d7fc86e 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -62,4 +62,8 @@ */ #define ACPI_UNUSED_VAR __attribute__ ((unused)) +#ifdef _ANSI +#define inline +#endif + #endif /* __ACGCC_H__ */ diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 6d49b2a498c4..fcb8e4b159b1 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -1,11 +1,11 @@ /****************************************************************************** * - * Name: aclinux.h - OS specific defines, etc. + * Name: aclinux.h - OS specific defines, etc. for Linux * *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2009, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,10 +44,13 @@ #ifndef __ACLINUX_H__ #define __ACLINUX_H__ +/* Common (in-kernel/user-space) ACPICA configuration */ + #define ACPI_USE_SYSTEM_CLIBRARY #define ACPI_USE_DO_WHILE_0 #define ACPI_MUTEX_TYPE ACPI_BINARY_SEMAPHORE + #ifdef __KERNEL__ #include <linux/string.h> @@ -63,15 +66,18 @@ #include <linux/spinlock_types.h> #include <asm/current.h> -/* Host-dependent types and defines */ +/* Host-dependent types and defines for in-kernel ACPICA */ #define ACPI_MACHINE_WIDTH BITS_PER_LONG -#define acpi_cache_t struct kmem_cache -#define acpi_spinlock spinlock_t * #define ACPI_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol); #define strtoul simple_strtoul -#else /* !__KERNEL__ */ +#define acpi_cache_t struct kmem_cache +#define acpi_spinlock spinlock_t * +#define acpi_cpu_flags unsigned long +#define acpi_thread_id struct task_struct * + +#else /* !__KERNEL__ */ #include <stdarg.h> #include <string.h> @@ -79,6 +85,11 @@ #include <ctype.h> #include <unistd.h> +/* Host-dependent types and defines for user-space ACPICA */ + +#define ACPI_FLUSH_CPU_CACHE() +#define acpi_thread_id pthread_t + #if defined(__ia64__) || defined(__x86_64__) #define ACPI_MACHINE_WIDTH 64 #define COMPILER_DEPENDENT_INT64 long @@ -94,17 +105,17 @@ #define __cdecl #endif -#define ACPI_FLUSH_CPU_CACHE() -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ /* Linux uses GCC */ #include "acgcc.h" -#define acpi_cpu_flags unsigned long - -#define acpi_thread_id struct task_struct * +#ifdef __KERNEL__ +/* + * Overrides for in-kernel ACPICA + */ static inline acpi_thread_id acpi_os_get_thread_id(void) { return current; @@ -119,30 +130,32 @@ static inline acpi_thread_id acpi_os_get_thread_id(void) #include <acpi/actypes.h> static inline void *acpi_os_allocate(acpi_size size) { - return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); + return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); } + static inline void *acpi_os_allocate_zeroed(acpi_size size) { - return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); + return kzalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); } static inline void *acpi_os_acquire_object(acpi_cache_t * cache) { return kmem_cache_zalloc(cache, - irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); + irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); } -#define ACPI_ALLOCATE(a) acpi_os_allocate(a) -#define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed(a) -#define ACPI_FREE(a) kfree(a) +#define ACPI_ALLOCATE(a) acpi_os_allocate(a) +#define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed(a) +#define ACPI_FREE(a) kfree(a) -/* - * We need to show where it is safe to preempt execution of ACPICA - */ -#define ACPI_PREEMPTION_POINT() \ - do { \ - if (!irqs_disabled()) \ - cond_resched(); \ +/* Used within ACPICA to show where it is safe to preempt execution */ + +#define ACPI_PREEMPTION_POINT() \ + do { \ + if (!irqs_disabled()) \ + cond_resched(); \ } while (0) -#endif /* __ACLINUX_H__ */ +#endif /* __KERNEL__ */ + +#endif /* __ACLINUX_H__ */ diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h new file mode 100644 index 000000000000..b18ce4f9ee3d --- /dev/null +++ b/include/asm-generic/atomic64.h @@ -0,0 +1,42 @@ +/* + * Generic implementation of 64-bit atomics using spinlocks, + * useful on processors that don't have 64-bit atomic instructions. + * + * Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.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. + */ +#ifndef _ASM_GENERIC_ATOMIC64_H +#define _ASM_GENERIC_ATOMIC64_H + +typedef struct { + long long counter; +} atomic64_t; + +#define ATOMIC64_INIT(i) { (i) } + +extern long long atomic64_read(const atomic64_t *v); +extern void atomic64_set(atomic64_t *v, long long i); +extern void atomic64_add(long long a, atomic64_t *v); +extern long long atomic64_add_return(long long a, atomic64_t *v); +extern void atomic64_sub(long long a, atomic64_t *v); +extern long long atomic64_sub_return(long long a, atomic64_t *v); +extern long long atomic64_dec_if_positive(atomic64_t *v); +extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n); +extern long long atomic64_xchg(atomic64_t *v, long long new); +extern int atomic64_add_unless(atomic64_t *v, long long a, long long u); + +#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) +#define atomic64_inc(v) atomic64_add(1LL, (v)) +#define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) +#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) +#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) +#define atomic64_dec(v) atomic64_sub(1LL, (v)) +#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) +#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) + +#endif /* _ASM_GENERIC_ATOMIC64_H */ diff --git a/include/linux/bio.h b/include/linux/bio.h index 12737be58601..2a04eb54c0dd 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -590,6 +590,11 @@ static inline void bio_list_merge_head(struct bio_list *bl, bl->head = bl2->head; } +static inline struct bio *bio_list_peek(struct bio_list *bl) +{ + return bl->head; +} + static inline struct bio *bio_list_pop(struct bio_list *bl) { struct bio *bio = bl->head; diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 883cd44ff765..1b2e1747df1a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -97,12 +97,14 @@ extern const char linux_proc_banner[]; #define KERN_INFO "<6>" /* informational */ #define KERN_DEBUG "<7>" /* debug-level messages */ +/* Use the default kernel loglevel */ +#define KERN_DEFAULT "<d>" /* * Annotation for a "continued" line of log printout (only done after a * line that had no enclosing \n). Only to be used by core/arch code * during early bootup (a continued line is not SMP-safe otherwise). */ -#define KERN_CONT "" +#define KERN_CONT "<c>" extern int console_printk[]; diff --git a/kernel/module.c b/kernel/module.c index e4ab36ce7672..215aaab09e91 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2899,7 +2899,7 @@ void print_modules(void) struct module *mod; char buf[8]; - printk("Modules linked in:"); + printk(KERN_DEFAULT "Modules linked in:"); /* Most callers should already have preempt disabled, but make sure */ preempt_disable(); list_for_each_entry_rcu(mod, &modules, list) diff --git a/kernel/printk.c b/kernel/printk.c index 5052b5497c67..b4d97b54c1ec 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -687,20 +687,35 @@ asmlinkage int vprintk(const char *fmt, va_list args) sizeof(printk_buf) - printed_len, fmt, args); + p = printk_buf; + + /* Do we have a loglevel in the string? */ + if (p[0] == '<') { + unsigned char c = p[1]; + if (c && p[2] == '>') { + switch (c) { + case '0' ... '7': /* loglevel */ + current_log_level = c - '0'; + /* Fallthrough - make sure we're on a new line */ + case 'd': /* KERN_DEFAULT */ + if (!new_text_line) { + emit_log_char('\n'); + new_text_line = 1; + } + /* Fallthrough - skip the loglevel */ + case 'c': /* KERN_CONT */ + p += 3; + break; + } + } + } + /* * Copy the output into log_buf. If the caller didn't provide * appropriate log level tags, we insert them here */ - for (p = printk_buf; *p; p++) { + for ( ; *p; p++) { if (new_text_line) { - /* If a token, set current_log_level and skip over */ - if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' && - p[2] == '>') { - current_log_level = p[1] - '0'; - p += 3; - printed_len -= 3; - } - /* Always output the token */ emit_log_char('<'); emit_log_char(current_log_level + '0'); diff --git a/lib/Kconfig b/lib/Kconfig index 9960be04cbbe..bb1326d3839c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -194,4 +194,10 @@ config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS config NLATTR bool +# +# Generic 64-bit atomic support is selected if needed +# +config GENERIC_ATOMIC64 + bool + endmenu diff --git a/lib/Makefile b/lib/Makefile index 34c5c0e6222e..8e9bcf9d3261 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -95,6 +95,8 @@ obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o obj-$(CONFIG_GENERIC_CSUM) += checksum.o +obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/atomic64.c b/lib/atomic64.c new file mode 100644 index 000000000000..c5e725562416 --- /dev/null +++ b/lib/atomic64.c @@ -0,0 +1,175 @@ +/* + * Generic implementation of 64-bit atomics using spinlocks, + * useful on processors that don't have 64-bit atomic instructions. + * + * Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.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/types.h> +#include <linux/cache.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <asm/atomic.h> + +/* + * We use a hashed array of spinlocks to provide exclusive access + * to each atomic64_t variable. Since this is expected to used on + * systems with small numbers of CPUs (<= 4 or so), we use a + * relatively small array of 16 spinlocks to avoid wasting too much + * memory on the spinlock array. + */ +#define NR_LOCKS 16 + +/* + * Ensure each lock is in a separate cacheline. + */ +static union { + spinlock_t lock; + char pad[L1_CACHE_BYTES]; +} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp; + +static inline spinlock_t *lock_addr(const atomic64_t *v) +{ + unsigned long addr = (unsigned long) v; + + addr >>= L1_CACHE_SHIFT; + addr ^= (addr >> 8) ^ (addr >> 16); + return &atomic64_lock[addr & (NR_LOCKS - 1)].lock; +} + +long long atomic64_read(const atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter; + spin_unlock_irqrestore(lock, flags); + return val; +} + +void atomic64_set(atomic64_t *v, long long i) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + + spin_lock_irqsave(lock, flags); + v->counter = i; + spin_unlock_irqrestore(lock, flags); +} + +void atomic64_add(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + + spin_lock_irqsave(lock, flags); + v->counter += a; + spin_unlock_irqrestore(lock, flags); +} + +long long atomic64_add_return(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter += a; + spin_unlock_irqrestore(lock, flags); + return val; +} + +void atomic64_sub(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + + spin_lock_irqsave(lock, flags); + v->counter -= a; + spin_unlock_irqrestore(lock, flags); +} + +long long atomic64_sub_return(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter -= a; + spin_unlock_irqrestore(lock, flags); + return val; +} + +long long atomic64_dec_if_positive(atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter - 1; + if (val >= 0) + v->counter = val; + spin_unlock_irqrestore(lock, flags); + return val; +} + +long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter; + if (val == o) + v->counter = n; + spin_unlock_irqrestore(lock, flags); + return val; +} + +long long atomic64_xchg(atomic64_t *v, long long new) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter; + v->counter = new; + spin_unlock_irqrestore(lock, flags); + return val; +} + +int atomic64_add_unless(atomic64_t *v, long long a, long long u) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + int ret = 1; + + spin_lock_irqsave(lock, flags); + if (v->counter != u) { + v->counter += a; + ret = 0; + } + spin_unlock_irqrestore(lock, flags); + return ret; +} + +static int init_atomic64_lock(void) +{ + int i; + + for (i = 0; i < NR_LOCKS; ++i) + spin_lock_init(&atomic64_lock[i].lock); + return 0; +} + +pure_initcall(init_atomic64_lock); |