diff options
Diffstat (limited to 'drivers/char')
87 files changed, 3658 insertions, 2398 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 14219972c74..6e9f74a5c09 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -40,7 +40,7 @@ config SGI_MBCS  source "drivers/tty/serial/Kconfig"  config TTY_PRINTK -	bool "TTY driver to output user messages via printk" +	tristate "TTY driver to output user messages via printk"  	depends on EXPERT && TTY  	default n  	---help--- @@ -408,7 +408,7 @@ config APPLICOM  config SONYPI  	tristate "Sony Vaio Programmable I/O Control Device support" -	depends on X86 && PCI && INPUT && !64BIT +	depends on X86_32 && PCI && INPUT  	---help---  	  This driver enables access to the Sony Programmable I/O Control  	  Device which can be found in many (all ?) Sony Vaio laptops. @@ -499,6 +499,7 @@ config RAW_DRIVER  config MAX_RAW_DEVS  	int "Maximum number of RAW devices to support (1-65536)"  	depends on RAW_DRIVER +	range 1 65536  	default "256"  	help  	  The maximum number of RAW devices that are supported. @@ -522,10 +523,16 @@ config HPET_MMAP  	  If you say Y here, user applications will be able to mmap  	  the HPET registers. +config HPET_MMAP_DEFAULT +	bool "Enable HPET MMAP access by default" +	default y +	depends on HPET_MMAP +	help  	  In some hardware implementations, the page containing HPET  	  registers may also contain other things that shouldn't be -	  exposed to the user.  If this applies to your hardware, -	  say N here. +	  exposed to the user.  This option selects the default (if +	  kernel parameter hpet_mmap is not set) user access to the +	  registers for applications that require it.  config HANGCHECK_TIMER  	tristate "Hangcheck timer" diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 7ff1d0d208a..a324f9303e3 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_MSM_SMD_PKT)	+= msm_smd_pkt.o  obj-$(CONFIG_MSPEC)		+= mspec.o  obj-$(CONFIG_MMTIMER)		+= mmtimer.o  obj-$(CONFIG_UV_MMTIMER)	+= uv_mmtimer.o -obj-$(CONFIG_VIOTAPE)		+= viotape.o  obj-$(CONFIG_IBM_BSR)		+= bsr.o  obj-$(CONFIG_SGI_MBCS)		+= mbcs.o  obj-$(CONFIG_BFIN_OTP)		+= bfin-otp.o @@ -50,7 +49,7 @@ obj-$(CONFIG_GPIO_TB0219)	+= tb0219.o  obj-$(CONFIG_TELCLOCK)		+= tlclk.o  obj-$(CONFIG_MWAVE)		+= mwave/ -obj-$(CONFIG_AGP)		+= agp/ +obj-y				+= agp/  obj-$(CONFIG_PCMCIA)		+= pcmcia/  obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index d8b1b576556..c528f96ee20 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -68,6 +68,7 @@ config AGP_AMD64  config AGP_INTEL  	tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support"  	depends on AGP && X86 +	select INTEL_GTT  	help  	  This option gives you AGP support for the GLX component of X  	  on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875, @@ -155,3 +156,7 @@ config AGP_SGI_TIOCA            This option gives you AGP GART support for the SGI TIO chipset            for IA64 processors. +config INTEL_GTT +	tristate +	depends on X86 && PCI + diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 8eb56e273e7..604489bcdbf 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1)	+= hp-agp.o  obj-$(CONFIG_AGP_PARISC)	+= parisc-agp.o  obj-$(CONFIG_AGP_I460)		+= i460-agp.o  obj-$(CONFIG_AGP_INTEL)		+= intel-agp.o -obj-$(CONFIG_AGP_INTEL)		+= intel-gtt.o +obj-$(CONFIG_INTEL_GTT)		+= intel-gtt.o  obj-$(CONFIG_AGP_NVIDIA)	+= nvidia-agp.o  obj-$(CONFIG_AGP_SGI_TIOCA)	+= sgi-agp.o  obj-$(CONFIG_AGP_SIS)		+= sis-agp.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 923f99df4f1..b709749c863 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -239,6 +239,7 @@ long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg);  /* Chipset independent registers (from AGP Spec) */  #define AGP_APBASE	0x10 +#define AGP_APERTURE_BAR	0  #define AGPSTAT		0x4  #define AGPCMD		0x8 diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 443cd6751ca..19db0366765 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -85,8 +85,8 @@ static int ali_configure(void)  	pci_write_config_dword(agp_bridge->dev, ALI_TLBCTRL, ((temp & 0xffffff00) | 0x00000010));  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  #if 0  	if (agp_bridge->type == ALI_M1541) { diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 779f0ab845a..3661a51e93e 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -11,7 +11,7 @@  #include <linux/slab.h>  #include "agp.h" -#define AMD_MMBASE	0x14 +#define AMD_MMBASE_BAR	1  #define AMD_APSIZE	0xac  #define AMD_MODECNTL	0xb0  #define AMD_MODECNTL2	0xb2 @@ -126,7 +126,6 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)  	unsigned long __iomem *cur_gatt;  	unsigned long addr;  	int retval; -	u32 temp;  	int i;  	value = A_SIZE_LVL2(agp_bridge->current_size); @@ -149,8 +148,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)  	 * used to program the agp master not the cpu  	 */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);  	agp_bridge->gart_bus_addr = addr;  	/* Calculate the agp offset */ @@ -207,6 +205,7 @@ static int amd_irongate_fetch_size(void)  static int amd_irongate_configure(void)  {  	struct aper_size_info_lvl2 *current_size; +	phys_addr_t reg;  	u32 temp;  	u16 enable_reg; @@ -214,9 +213,8 @@ static int amd_irongate_configure(void)  	if (!amd_irongate_private.registers) {  		/* Get the memory mapped registers */ -		pci_read_config_dword(agp_bridge->dev, AMD_MMBASE, &temp); -		temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); -		amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); +		reg = pci_resource_start(agp_bridge->dev, AMD_MMBASE_BAR); +		amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(reg, 4096);  		if (!amd_irongate_private.registers)  			return -ENOMEM;  	} diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index d79d692d05b..3b47ed0310e 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -269,7 +269,6 @@ static int agp_aperture_valid(u64 aper, u32 size)   */  static int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap)  { -	u32 aper_low, aper_hi;  	u64 aper, nb_aper;  	int order = 0;  	u32 nb_order, nb_base; @@ -295,9 +294,7 @@ static int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap)  		apsize |= 0xf00;  	order = 7 - hweight16(apsize); -	pci_read_config_dword(agp, 0x10, &aper_low); -	pci_read_config_dword(agp, 0x14, &aper_hi); -	aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); +	aper = pci_bus_address(agp, AGP_APERTURE_BAR);  	/*  	 * On some sick chips APSIZE is 0. This means it wants 4G @@ -735,7 +732,7 @@ static struct pci_device_id agp_amd64_pci_table[] = {  MODULE_DEVICE_TABLE(pci, agp_amd64_pci_table); -static DEFINE_PCI_DEVICE_TABLE(agp_amd64_pci_promisc_table) = { +static const struct pci_device_id agp_amd64_pci_promisc_table[] = {  	{ PCI_DEVICE_CLASS(0, 0) },  	{ }  }; diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 03c1dc1ab55..18a7a6baa30 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -12,7 +12,7 @@  #include <asm/agp.h>  #include "agp.h" -#define ATI_GART_MMBASE_ADDR	0x14 +#define ATI_GART_MMBASE_BAR	1  #define ATI_RS100_APSIZE	0xac  #define ATI_RS100_IG_AGPMODE	0xb0  #define ATI_RS300_APSIZE	0xf8 @@ -196,12 +196,12 @@ static void ati_cleanup(void)  static int ati_configure(void)  { +	phys_addr_t reg;  	u32 temp;  	/* Get the memory mapped registers */ -	pci_read_config_dword(agp_bridge->dev, ATI_GART_MMBASE_ADDR, &temp); -	temp = (temp & 0xfffff000); -	ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); +	reg = pci_resource_start(agp_bridge->dev, ATI_GART_MMBASE_BAR); +	ati_generic_private.registers = (volatile u8 __iomem *) ioremap(reg, 4096);  	if (!ati_generic_private.registers)  		return -ENOMEM; @@ -211,18 +211,18 @@ static int ati_configure(void)  	else  		pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000); -	/* address to map too */ +	/* address to map to */  	/* -	pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp); -	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge.gart_bus_addr = pci_bus_address(agp_bridge.dev, +						   AGP_APERTURE_BAR);  	printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr);  	*/  	writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID);  	readl(ati_generic_private.registers+ATI_GART_FEATURE_ID);	/* PCI Posting.*/  	/* SIGNALED_SYSTEM_ERROR @ NB_STATUS */ -	pci_read_config_dword(agp_bridge->dev, 4, &temp); -	pci_write_config_dword(agp_bridge->dev, 4, temp | (1<<14)); +	pci_read_config_dword(agp_bridge->dev, PCI_COMMAND, &temp); +	pci_write_config_dword(agp_bridge->dev, PCI_COMMAND, temp | (1<<14));  	/* Write out the address of the gatt table */  	writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE); @@ -385,8 +385,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)  	 * This is a bus address even on the alpha, b/c its  	 * used to program the agp master not the cpu  	 */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);  	agp_bridge->gart_bus_addr = addr;  	/* Calculate the agp offset */ diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 6974d503205..533cb6d229b 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -128,7 +128,6 @@ static void efficeon_cleanup(void)  static int efficeon_configure(void)  { -	u32 temp;  	u16 temp2;  	struct aper_size_info_lvl2 *current_size; @@ -141,8 +140,8 @@ static int efficeon_configure(void)  			      current_size->size_value);  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* agpctrl */  	pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280); diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 1b192395a90..b29703324e9 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -31,7 +31,6 @@  #include <linux/module.h>  #include <linux/mman.h>  #include <linux/pci.h> -#include <linux/init.h>  #include <linux/miscdevice.h>  #include <linux/agp_backend.h>  #include <linux/agpgart.h> @@ -731,6 +730,7 @@ static int agpioc_info_wrap(struct agp_file_private *priv, void __user *arg)  	agp_copy_info(agp_bridge, &kerninfo); +	memset(&userinfo, 0, sizeof(userinfo));  	userinfo.version.major = kerninfo.version.major;  	userinfo.version.minor = kerninfo.version.minor;  	userinfo.bridge_id = kerninfo.device->vendor | diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index a0df182f6f7..0fbccce1cee 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -29,7 +29,6 @@   */  #include <linux/module.h>  #include <linux/pci.h> -#include <linux/init.h>  #include <linux/pagemap.h>  #include <linux/miscdevice.h>  #include <linux/pm.h> @@ -1396,8 +1395,8 @@ int agp3_generic_configure(void)  	current_size = A_SIZE_16(agp_bridge->current_size); -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* set aperture size */  	pci_write_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, current_size->size_value); diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a426ee1f57a..f9b9ca5d31b 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -14,9 +14,6 @@  #include "intel-agp.h"  #include <drm/intel-gtt.h> -int intel_agp_enabled; -EXPORT_SYMBOL(intel_agp_enabled); -  static int intel_fetch_size(void)  {  	int i; @@ -118,7 +115,6 @@ static void intel_8xx_cleanup(void)  static int intel_configure(void)  { -	u32 temp;  	u16 temp2;  	struct aper_size_info_16 *current_size; @@ -128,8 +124,8 @@ static int intel_configure(void)  	pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* attbase - aperture base */  	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); @@ -148,7 +144,7 @@ static int intel_configure(void)  static int intel_815_configure(void)  { -	u32 temp, addr; +	u32 addr;  	u8 temp2;  	struct aper_size_info_8 *current_size; @@ -167,8 +163,8 @@ static int intel_815_configure(void)  			current_size->size_value);  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	pci_read_config_dword(agp_bridge->dev, INTEL_ATTBASE, &addr);  	addr &= INTEL_815_ATTBASE_MASK; @@ -208,7 +204,6 @@ static void intel_820_cleanup(void)  static int intel_820_configure(void)  { -	u32 temp;  	u8 temp2;  	struct aper_size_info_8 *current_size; @@ -218,8 +213,8 @@ static int intel_820_configure(void)  	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* attbase - aperture base */  	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); @@ -239,7 +234,6 @@ static int intel_820_configure(void)  static int intel_840_configure(void)  { -	u32 temp;  	u16 temp2;  	struct aper_size_info_8 *current_size; @@ -249,8 +243,8 @@ static int intel_840_configure(void)  	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* attbase - aperture base */  	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); @@ -268,7 +262,6 @@ static int intel_840_configure(void)  static int intel_845_configure(void)  { -	u32 temp;  	u8 temp2;  	struct aper_size_info_8 *current_size; @@ -282,9 +275,9 @@ static int intel_845_configure(void)  				       agp_bridge->apbase_config);  	} else {  		/* address to map to */ -		pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -		agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); -		agp_bridge->apbase_config = temp; +		agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +							    AGP_APERTURE_BAR); +		agp_bridge->apbase_config = agp_bridge->gart_bus_addr;  	}  	/* attbase - aperture base */ @@ -303,7 +296,6 @@ static int intel_845_configure(void)  static int intel_850_configure(void)  { -	u32 temp;  	u16 temp2;  	struct aper_size_info_8 *current_size; @@ -313,8 +305,8 @@ static int intel_850_configure(void)  	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* attbase - aperture base */  	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); @@ -332,7 +324,6 @@ static int intel_850_configure(void)  static int intel_860_configure(void)  { -	u32 temp;  	u16 temp2;  	struct aper_size_info_8 *current_size; @@ -342,8 +333,8 @@ static int intel_860_configure(void)  	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* attbase - aperture base */  	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); @@ -361,7 +352,6 @@ static int intel_860_configure(void)  static int intel_830mp_configure(void)  { -	u32 temp;  	u16 temp2;  	struct aper_size_info_8 *current_size; @@ -371,8 +361,8 @@ static int intel_830mp_configure(void)  	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* attbase - aperture base */  	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); @@ -390,7 +380,6 @@ static int intel_830mp_configure(void)  static int intel_7505_configure(void)  { -	u32 temp;  	u16 temp2;  	struct aper_size_info_8 *current_size; @@ -400,8 +389,8 @@ static int intel_7505_configure(void)  	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);  	/* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* attbase - aperture base */  	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); @@ -814,8 +803,6 @@ static int agp_intel_probe(struct pci_dev *pdev,  found_gmch:  	pci_set_drvdata(pdev, bridge);  	err = agp_add_bridge(bridge); -	if (!err) -		intel_agp_enabled = 1;  	return err;  } diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 1042c1b9037..fda073dcd96 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -55,8 +55,8 @@  #define INTEL_I860_ERRSTS	0xc8  /* Intel i810 registers */ -#define I810_GMADDR		0x10 -#define I810_MMADDR		0x14 +#define I810_GMADR_BAR		0 +#define I810_MMADR_BAR		1  #define I810_PTE_BASE		0x10000  #define I810_PTE_MAIN_UNCACHED	0x00000000  #define I810_PTE_LOCAL		0x00000002 @@ -113,9 +113,9 @@  #define INTEL_I850_ERRSTS	0xc8  /* intel 915G registers */ -#define I915_GMADDR	0x18 -#define I915_MMADDR	0x10 -#define I915_PTEADDR	0x1C +#define I915_GMADR_BAR	2 +#define I915_MMADR_BAR	0 +#define I915_PTE_BAR	3  #define I915_GMCH_GMS_STOLEN_48M	(0x6 << 4)  #define I915_GMCH_GMS_STOLEN_64M	(0x7 << 4)  #define G33_GMCH_GMS_STOLEN_128M	(0x8 << 4) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index b8e2014cb9c..9a024f899dd 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -17,7 +17,6 @@  #include <linux/module.h>  #include <linux/pci.h> -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/pagemap.h>  #include <linux/agp_backend.h> @@ -64,7 +63,7 @@ static struct _intel_private {  	struct pci_dev *pcidev;	/* device one */  	struct pci_dev *bridge_dev;  	u8 __iomem *registers; -	phys_addr_t gtt_bus_addr; +	phys_addr_t gtt_phys_addr;  	u32 PGETBL_save;  	u32 __iomem *gtt;		/* I915G */  	bool clear_fake_agp; /* on first access via agp, fill with scratch */ @@ -94,6 +93,7 @@ static struct _intel_private {  #define IS_IRONLAKE	intel_private.driver->is_ironlake  #define HAS_PGTBL_EN	intel_private.driver->has_pgtbl_enable +#if IS_ENABLED(CONFIG_AGP_INTEL)  static int intel_gtt_map_memory(struct page **pages,  				unsigned int num_entries,  				struct sg_table *st) @@ -168,11 +168,12 @@ static void i8xx_destroy_pages(struct page *page)  	__free_pages(page, 2);  	atomic_dec(&agp_bridge->current_memory_agp);  } +#endif  #define I810_GTT_ORDER 4  static int i810_setup(void)  { -	u32 reg_addr; +	phys_addr_t reg_addr;  	char *gtt_table;  	/* i81x does not preallocate the gtt. It's always 64kb in size. */ @@ -181,8 +182,7 @@ static int i810_setup(void)  		return -ENOMEM;  	intel_private.i81x_gtt_table = gtt_table; -	pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); -	reg_addr &= 0xfff80000; +	reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR);  	intel_private.registers = ioremap(reg_addr, KB(64));  	if (!intel_private.registers) @@ -191,7 +191,7 @@ static int i810_setup(void)  	writel(virt_to_phys(gtt_table) | I810_PGETBL_ENABLED,  	       intel_private.registers+I810_PGETBL_CTL); -	intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; +	intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE;  	if ((readl(intel_private.registers+I810_DRAM_CTL)  		& I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { @@ -209,6 +209,7 @@ static void i810_cleanup(void)  	free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER);  } +#if IS_ENABLED(CONFIG_AGP_INTEL)  static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start,  				      int type)  { @@ -289,6 +290,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr)  	}  	kfree(curr);  } +#endif  static int intel_gtt_setup_scratch_page(void)  { @@ -608,9 +610,8 @@ static bool intel_gtt_can_wc(void)  static int intel_gtt_init(void)  { -	u32 gma_addr;  	u32 gtt_map_size; -	int ret; +	int ret, bar;  	ret = intel_private.driver->setup();  	if (ret != 0) @@ -636,10 +637,10 @@ static int intel_gtt_init(void)  	intel_private.gtt = NULL;  	if (intel_gtt_can_wc()) -		intel_private.gtt = ioremap_wc(intel_private.gtt_bus_addr, +		intel_private.gtt = ioremap_wc(intel_private.gtt_phys_addr,  					       gtt_map_size);  	if (intel_private.gtt == NULL) -		intel_private.gtt = ioremap(intel_private.gtt_bus_addr, +		intel_private.gtt = ioremap(intel_private.gtt_phys_addr,  					    gtt_map_size);  	if (intel_private.gtt == NULL) {  		intel_private.driver->cleanup(); @@ -647,7 +648,9 @@ static int intel_gtt_init(void)  		return -ENOMEM;  	} +#if IS_ENABLED(CONFIG_AGP_INTEL)  	global_cache_flush();   /* FIXME: ? */ +#endif  	intel_private.stolen_size = intel_gtt_stolen_size(); @@ -660,17 +663,15 @@ static int intel_gtt_init(void)  	}  	if (INTEL_GTT_GEN <= 2) -		pci_read_config_dword(intel_private.pcidev, I810_GMADDR, -				      &gma_addr); +		bar = I810_GMADR_BAR;  	else -		pci_read_config_dword(intel_private.pcidev, I915_GMADDR, -				      &gma_addr); - -	intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); +		bar = I915_GMADR_BAR; +	intel_private.gma_bus_addr = pci_bus_address(intel_private.pcidev, bar);  	return 0;  } +#if IS_ENABLED(CONFIG_AGP_INTEL)  static int intel_fake_agp_fetch_size(void)  {  	int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); @@ -689,6 +690,7 @@ static int intel_fake_agp_fetch_size(void)  	return 0;  } +#endif  static void i830_cleanup(void)  { @@ -787,20 +789,20 @@ EXPORT_SYMBOL(intel_enable_gtt);  static int i830_setup(void)  { -	u32 reg_addr; +	phys_addr_t reg_addr; -	pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); -	reg_addr &= 0xfff80000; +	reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR);  	intel_private.registers = ioremap(reg_addr, KB(64));  	if (!intel_private.registers)  		return -ENOMEM; -	intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; +	intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE;  	return 0;  } +#if IS_ENABLED(CONFIG_AGP_INTEL)  static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge)  {  	agp_bridge->gatt_table_real = NULL; @@ -825,6 +827,7 @@ static int intel_fake_agp_configure(void)  	return 0;  } +#endif  static bool i830_check_flags(unsigned int flags)  { @@ -863,6 +866,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st,  }  EXPORT_SYMBOL(intel_gtt_insert_sg_entries); +#if IS_ENABLED(CONFIG_AGP_INTEL)  static void intel_gtt_insert_pages(unsigned int first_entry,  				   unsigned int num_entries,  				   struct page **pages, @@ -928,6 +932,7 @@ out_err:  	mem->is_flushed = true;  	return ret;  } +#endif  void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)  { @@ -941,6 +946,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)  }  EXPORT_SYMBOL(intel_gtt_clear_range); +#if IS_ENABLED(CONFIG_AGP_INTEL)  static int intel_fake_agp_remove_entries(struct agp_memory *mem,  					 off_t pg_start, int type)  { @@ -982,6 +988,7 @@ static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,  	/* always return NULL for other allocation types for now */  	return NULL;  } +#endif  static int intel_alloc_chipset_flush_resource(void)  { @@ -1108,12 +1115,10 @@ static void i965_write_entry(dma_addr_t addr,  static int i9xx_setup(void)  { -	u32 reg_addr, gtt_addr; +	phys_addr_t reg_addr;  	int size = KB(512); -	pci_read_config_dword(intel_private.pcidev, I915_MMADDR, ®_addr); - -	reg_addr &= 0xfff80000; +	reg_addr = pci_resource_start(intel_private.pcidev, I915_MMADR_BAR);  	intel_private.registers = ioremap(reg_addr, size);  	if (!intel_private.registers) @@ -1121,15 +1126,14 @@ static int i9xx_setup(void)  	switch (INTEL_GTT_GEN) {  	case 3: -		pci_read_config_dword(intel_private.pcidev, -				      I915_PTEADDR, >t_addr); -		intel_private.gtt_bus_addr = gtt_addr; +		intel_private.gtt_phys_addr = +			pci_resource_start(intel_private.pcidev, I915_PTE_BAR);  		break;  	case 5: -		intel_private.gtt_bus_addr = reg_addr + MB(2); +		intel_private.gtt_phys_addr = reg_addr + MB(2);  		break;  	default: -		intel_private.gtt_bus_addr = reg_addr + KB(512); +		intel_private.gtt_phys_addr = reg_addr + KB(512);  		break;  	} @@ -1138,6 +1142,7 @@ static int i9xx_setup(void)  	return 0;  } +#if IS_ENABLED(CONFIG_AGP_INTEL)  static const struct agp_bridge_driver intel_fake_agp_driver = {  	.owner			= THIS_MODULE,  	.size_type		= FIXED_APER_SIZE, @@ -1159,6 +1164,7 @@ static const struct agp_bridge_driver intel_fake_agp_driver = {  	.agp_destroy_page	= agp_generic_destroy_page,  	.agp_destroy_pages      = agp_generic_destroy_pages,  }; +#endif  static const struct intel_gtt_driver i81x_gtt_driver = {  	.gen = 1, @@ -1376,11 +1382,13 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev,  	intel_private.refcount++; +#if IS_ENABLED(CONFIG_AGP_INTEL)  	if (bridge) {  		bridge->driver = &intel_fake_agp_driver;  		bridge->dev_private_data = &intel_private;  		bridge->dev = bridge_pdev;  	} +#endif  	intel_private.bridge_dev = pci_dev_get(bridge_pdev); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index be42a2312dc..a1861b75eb3 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -106,6 +106,7 @@ static int nvidia_configure(void)  {  	int i, rc, num_dirs;  	u32 apbase, aplimit; +	phys_addr_t apbase_phys;  	struct aper_size_info_8 *current_size;  	u32 temp; @@ -115,9 +116,8 @@ static int nvidia_configure(void)  	pci_write_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE,  		current_size->size_value); -    /* address to map to */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &apbase); -	apbase &= PCI_BASE_ADDRESS_MEM_MASK; +	/* address to map to */ +	apbase = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);  	agp_bridge->gart_bus_addr = apbase;  	aplimit = apbase + (current_size->size * 1024 * 1024) - 1;  	pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APBASE, apbase); @@ -153,8 +153,9 @@ static int nvidia_configure(void)  	pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp | 0x100);  	/* map aperture */ +	apbase_phys = pci_resource_start(agp_bridge->dev, AGP_APERTURE_BAR);  	nvidia_private.aperture = -		(volatile u32 __iomem *) ioremap(apbase, 33 * PAGE_SIZE); +		(volatile u32 __iomem *) ioremap(apbase_phys, 33 * PAGE_SIZE);  	if (!nvidia_private.aperture)  		return -ENOMEM; diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 05b8d0241bd..3051c73bc38 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -15,7 +15,6 @@  #include <linux/module.h>  #include <linux/pci.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/agp_backend.h>  #include <asm/sn/addrs.h>  #include <asm/sn/io.h> diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 79c838c434b..2c74038da45 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -50,13 +50,12 @@ static void sis_tlbflush(struct agp_memory *mem)  static int sis_configure(void)  { -	u32 temp;  	struct aper_size_info_8 *current_size;  	current_size = A_SIZE_8(agp_bridge->current_size);  	pci_write_config_byte(agp_bridge->dev, SIS_TLBCNTRL, 0x05); -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	pci_write_config_dword(agp_bridge->dev, SIS_ATTBASE,  			       agp_bridge->gatt_bus_addr);  	pci_write_config_byte(agp_bridge->dev, SIS_APSIZE, diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 74d3aa3773b..228f20cddc0 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -43,16 +43,15 @@ static int via_fetch_size(void)  static int via_configure(void)  { -	u32 temp;  	struct aper_size_info_8 *current_size;  	current_size = A_SIZE_8(agp_bridge->current_size);  	/* aperture size */  	pci_write_config_byte(agp_bridge->dev, VIA_APSIZE,  			      current_size->size_value); -	/* address to map too */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	/* address to map to */ +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* GART control register */  	pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, 0x0000000f); @@ -132,9 +131,9 @@ static int via_configure_agp3(void)  	current_size = A_SIZE_16(agp_bridge->current_size); -	/* address to map too */ -	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); -	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +	/* address to map to */ +	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, +						    AGP_APERTURE_BAR);  	/* attbase - aperture GATT base */  	pci_write_config_dword(agp_bridge->dev, VIA_AGP3_ATTBASE, diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index 46118f84594..dd9dfa15e9d 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -531,6 +531,7 @@ static int apm_suspend_notifier(struct notifier_block *nb,  {  	struct apm_user *as;  	int err; +	unsigned long apm_event;  	/* short-cut emergency suspends */  	if (atomic_read(&userspace_notification_inhibit)) @@ -538,6 +539,9 @@ static int apm_suspend_notifier(struct notifier_block *nb,  	switch (event) {  	case PM_SUSPEND_PREPARE: +	case PM_HIBERNATION_PREPARE: +		apm_event = (event == PM_SUSPEND_PREPARE) ? +			APM_USER_SUSPEND : APM_USER_HIBERNATION;  		/*  		 * Queue an event to all "writer" users that we want  		 * to suspend and need their ack. @@ -550,7 +554,7 @@ static int apm_suspend_notifier(struct notifier_block *nb,  			    as->writer && as->suser) {  				as->suspend_state = SUSPEND_PENDING;  				atomic_inc(&suspend_acks_pending); -				queue_add_event(&as->queue, APM_USER_SUSPEND); +				queue_add_event(&as->queue, apm_event);  			}  		} @@ -601,11 +605,14 @@ static int apm_suspend_notifier(struct notifier_block *nb,  		return notifier_from_errno(err);  	case PM_POST_SUSPEND: +	case PM_POST_HIBERNATION: +		apm_event = (event == PM_POST_SUSPEND) ? +			APM_NORMAL_RESUME : APM_HIBERNATION_RESUME;  		/*  		 * Anyone on the APM queues will think we're still suspended.  		 * Send a message so everyone knows we're now awake again.  		 */ -		queue_event(APM_NORMAL_RESUME); +		queue_event(apm_event);  		/*  		 * Finally, wake up anyone who is sleeping on the suspend. diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 974321a2508..14790304b84 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -345,7 +345,6 @@ out:  			free_irq(apbs[i].irq, &dummy);  		iounmap(apbs[i].RamIO);  	} -	pci_disable_device(dev);  	return ret;  } diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 0671e45daa5..8fedbc25041 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -21,6 +21,7 @@  #include <linux/kernel.h>  #include <linux/of.h> +#include <linux/of_address.h>  #include <linux/of_device.h>  #include <linux/of_platform.h>  #include <linux/fs.h> diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 448ce5e29c5..d5d4cd82b9f 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -34,15 +34,12 @@  #include <linux/uaccess.h>  #include <linux/slab.h>  #include <linux/io.h> - +#include <linux/acpi.h> +#include <linux/hpet.h>  #include <asm/current.h>  #include <asm/irq.h>  #include <asm/div64.h> -#include <linux/acpi.h> -#include <acpi/acpi_bus.h> -#include <linux/hpet.h> -  /*   * The High Precision Event Timer driver.   * This driver is closely modelled after the rtc.c driver. @@ -367,12 +364,29 @@ static unsigned int hpet_poll(struct file *file, poll_table * wait)  	return 0;  } +#ifdef CONFIG_HPET_MMAP +#ifdef CONFIG_HPET_MMAP_DEFAULT +static int hpet_mmap_enabled = 1; +#else +static int hpet_mmap_enabled = 0; +#endif + +static __init int hpet_mmap_enable(char *str) +{ +	get_option(&str, &hpet_mmap_enabled); +	pr_info("HPET mmap %s\n", hpet_mmap_enabled ? "enabled" : "disabled"); +	return 1; +} +__setup("hpet_mmap", hpet_mmap_enable); +  static int hpet_mmap(struct file *file, struct vm_area_struct *vma)  { -#ifdef	CONFIG_HPET_MMAP  	struct hpet_dev *devp;  	unsigned long addr; +	if (!hpet_mmap_enabled) +		return -EACCES; +  	devp = file->private_data;  	addr = devp->hd_hpets->hp_hpet_phys; @@ -381,10 +395,13 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)  	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);  	return vm_iomap_memory(vma, addr, PAGE_SIZE); +}  #else +static int hpet_mmap(struct file *file, struct vm_area_struct *vma) +{  	return -ENOSYS; -#endif  } +#endif  static int hpet_fasync(int fd, struct file *file, int on)  { @@ -486,8 +503,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)  		}  		sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev)); -		irq_flags = devp->hd_flags & HPET_SHARED_IRQ -						? IRQF_SHARED : IRQF_DISABLED; +		irq_flags = devp->hd_flags & HPET_SHARED_IRQ ? IRQF_SHARED : 0;  		if (request_irq(irq, hpet_interrupt, irq_flags,  				devp->hd_name, (void *)devp)) {  			printk(KERN_ERR "hpet: IRQ %d is not free\n", irq); @@ -971,8 +987,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)  		struct acpi_resource_fixed_memory32 *fixmem32;  		fixmem32 = &res->data.fixed_memory32; -		if (!fixmem32) -			return AE_NO_MEMORY;  		hdp->hd_phys_address = fixmem32->address;  		hdp->hd_address = ioremap(fixmem32->address, diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 0aa9d91daef..836b061ced3 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -2,7 +2,7 @@  # Hardware Random Number Generator (RNG) configuration  # -config HW_RANDOM +menuconfig HW_RANDOM  	tristate "Hardware Random Number Generator Core support"  	default m  	---help--- @@ -20,9 +20,11 @@ config HW_RANDOM  	  If unsure, say Y. +if HW_RANDOM +  config HW_RANDOM_TIMERIOMEM  	tristate "Timer IOMEM HW Random Number Generator support" -	depends on HW_RANDOM && HAS_IOMEM +	depends on HAS_IOMEM  	---help---  	  This driver provides kernel-side support for a generic Random  	  Number Generator used by reading a 'dumb' iomem address that @@ -36,7 +38,7 @@ config HW_RANDOM_TIMERIOMEM  config HW_RANDOM_INTEL  	tristate "Intel HW Random Number Generator support" -	depends on HW_RANDOM && (X86 || IA64) && PCI +	depends on (X86 || IA64) && PCI  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -49,7 +51,7 @@ config HW_RANDOM_INTEL  config HW_RANDOM_AMD  	tristate "AMD HW Random Number Generator support" -	depends on HW_RANDOM && (X86 || PPC_MAPLE) && PCI +	depends on (X86 || PPC_MAPLE) && PCI  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -62,8 +64,8 @@ config HW_RANDOM_AMD  config HW_RANDOM_ATMEL  	tristate "Atmel Random Number Generator support" -	depends on HW_RANDOM && HAVE_CLK -	default (HW_RANDOM && ARCH_AT91) +	depends on ARCH_AT91 && HAVE_CLK +	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number  	  Generator hardware found on Atmel AT91 devices. @@ -75,7 +77,7 @@ config HW_RANDOM_ATMEL  config HW_RANDOM_BCM63XX  	tristate "Broadcom BCM63xx Random Number Generator support" -	depends on HW_RANDOM && BCM63XX +	depends on BCM63XX  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -88,7 +90,7 @@ config HW_RANDOM_BCM63XX  config HW_RANDOM_BCM2835  	tristate "Broadcom BCM2835 Random Number Generator support" -	depends on HW_RANDOM && ARCH_BCM2835 +	depends on ARCH_BCM2835  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -101,7 +103,7 @@ config HW_RANDOM_BCM2835  config HW_RANDOM_GEODE  	tristate "AMD Geode HW Random Number Generator support" -	depends on HW_RANDOM && X86_32 && PCI +	depends on X86_32 && PCI  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -114,7 +116,7 @@ config HW_RANDOM_GEODE  config HW_RANDOM_N2RNG  	tristate "Niagara2 Random Number Generator support" -	depends on HW_RANDOM && SPARC64 +	depends on SPARC64  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -127,7 +129,7 @@ config HW_RANDOM_N2RNG  config HW_RANDOM_VIA  	tristate "VIA HW Random Number Generator support" -	depends on HW_RANDOM && X86 +	depends on X86  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -140,7 +142,7 @@ config HW_RANDOM_VIA  config HW_RANDOM_IXP4XX  	tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support" -	depends on HW_RANDOM && ARCH_IXP4XX +	depends on ARCH_IXP4XX  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Pseudo-Random @@ -153,7 +155,7 @@ config HW_RANDOM_IXP4XX  config HW_RANDOM_OMAP  	tristate "OMAP Random Number Generator support" -	depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2PLUS) +	depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS  	default HW_RANDOM   	---help---   	  This driver provides kernel-side support for the Random Number @@ -165,9 +167,22 @@ config HW_RANDOM_OMAP   	  If unsure, say Y. +config HW_RANDOM_OMAP3_ROM +	tristate "OMAP3 ROM Random Number Generator support" +	depends on ARCH_OMAP3 +	default HW_RANDOM +	---help--- +	  This driver provides kernel-side support for the Random Number +	  Generator hardware found on OMAP34xx processors. + +	  To compile this driver as a module, choose M here: the +	  module will be called omap3-rom-rng. + +	  If unsure, say Y. +  config HW_RANDOM_OCTEON  	tristate "Octeon Random Number Generator support" -	depends on HW_RANDOM && CAVIUM_OCTEON_SOC +	depends on CAVIUM_OCTEON_SOC  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -180,7 +195,7 @@ config HW_RANDOM_OCTEON  config HW_RANDOM_PASEMI  	tristate "PA Semi HW Random Number Generator support" -	depends on HW_RANDOM && PPC_PASEMI +	depends on PPC_PASEMI  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -193,7 +208,7 @@ config HW_RANDOM_PASEMI  config HW_RANDOM_VIRTIO  	tristate "VirtIO Random Number Generator support" -	depends on HW_RANDOM && VIRTIO +	depends on VIRTIO  	---help---  	  This driver provides kernel-side support for the virtual Random Number  	  Generator hardware. @@ -203,7 +218,7 @@ config HW_RANDOM_VIRTIO  config HW_RANDOM_TX4939  	tristate "TX4939 Random Number Generator support" -	depends on HW_RANDOM && SOC_TX4939 +	depends on SOC_TX4939  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -216,7 +231,8 @@ config HW_RANDOM_TX4939  config HW_RANDOM_MXC_RNGA  	tristate "Freescale i.MX RNGA Random Number Generator" -	depends on HW_RANDOM && ARCH_HAS_RNGA +	depends on ARCH_HAS_RNGA +	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number  	  Generator hardware found on Freescale i.MX processors. @@ -228,7 +244,8 @@ config HW_RANDOM_MXC_RNGA  config HW_RANDOM_NOMADIK  	tristate "ST-Ericsson Nomadik Random Number Generator support" -	depends on HW_RANDOM && ARCH_NOMADIK +	depends on ARCH_NOMADIK +	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number  	  Generator hardware found on ST-Ericsson SoCs (8815 and 8500). @@ -238,21 +255,10 @@ config HW_RANDOM_NOMADIK  	  If unsure, say Y. -config HW_RANDOM_PICOXCELL -	tristate "Picochip picoXcell true random number generator support" -	depends on HW_RANDOM && ARCH_PICOXCELL && PICOXCELL_PC3X3 -	---help--- -	  This driver provides kernel-side support for the Random Number -	  Generator hardware found on Picochip PC3x3 and later devices. - -	  To compile this driver as a module, choose M here: the -	  module will be called picoxcell-rng. - -	  If unsure, say Y. -  config HW_RANDOM_PPC4XX  	tristate "PowerPC 4xx generic true random number generator support" -	depends on HW_RANDOM && PPC && 4xx +	depends on PPC && 4xx +	default HW_RANDOM  	---help---  	 This driver provides the kernel-side support for the TRNG hardware  	 found in the security function of some PowerPC 4xx SoCs. @@ -262,24 +268,9 @@ config HW_RANDOM_PPC4XX  	 If unsure, say N. -config UML_RANDOM -	depends on UML -	tristate "Hardware random number generator" -	help -	  This option enables UML's "hardware" random number generator.  It -	  attaches itself to the host's /dev/random, supplying as much entropy -	  as the host has, rather than the small amount the UML gets from its -	  own drivers.  It registers itself as a standard hardware random number -	  generator, major 10, minor 183, and the canonical device name is -	  /dev/hwrng. -	  The way to make use of this is to install the rng-tools package -	  (check your distro, or download from -	  http://sourceforge.net/projects/gkernel/).  rngd periodically reads -	  /dev/hwrng and injects the entropy into /dev/random. -  config HW_RANDOM_PSERIES  	tristate "pSeries HW Random Number Generator support" -	depends on HW_RANDOM && PPC64 && IBMVIO +	depends on PPC64 && IBMVIO  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -290,9 +281,23 @@ config HW_RANDOM_PSERIES  	  If unsure, say Y. +config HW_RANDOM_POWERNV +	tristate "PowerNV Random Number Generator support" +	depends on PPC_POWERNV +	default HW_RANDOM +	---help--- +	  This is the driver for Random Number Generator hardware found +	  in POWER7+ and above machines for PowerNV platform. + +	  To compile this driver as a module, choose M here: the +	  module will be called powernv-rng. + +	  If unsure, say Y. +  config HW_RANDOM_EXYNOS  	tristate "EXYNOS HW random number generator support" -	depends on HW_RANDOM && HAS_IOMEM && HAVE_CLK +	depends on ARCH_EXYNOS +	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number  	  Generator hardware found on EXYNOS SOCs. @@ -304,7 +309,7 @@ config HW_RANDOM_EXYNOS  config HW_RANDOM_TPM  	tristate "TPM HW Random Number Generator support" -	depends on HW_RANDOM && TCG_TPM +	depends on TCG_TPM  	default HW_RANDOM  	---help---  	  This driver provides kernel-side support for the Random Number @@ -314,3 +319,33 @@ config HW_RANDOM_TPM  	  module will be called tpm-rng.  	  If unsure, say Y. + +config HW_RANDOM_MSM +	tristate "Qualcomm SoCs Random Number Generator support" +	depends on HW_RANDOM && ARCH_QCOM +	default HW_RANDOM +	---help--- +	  This driver provides kernel-side support for the Random Number +	  Generator hardware found on Qualcomm SoCs. + +	  To compile this driver as a module, choose M here. the +	  module will be called msm-rng. + +	  If unsure, say Y. + +endif # HW_RANDOM + +config UML_RANDOM +	depends on UML +	tristate "Hardware random number generator" +	help +	  This option enables UML's "hardware" random number generator.  It +	  attaches itself to the host's /dev/random, supplying as much entropy +	  as the host has, rather than the small amount the UML gets from its +	  own drivers.  It registers itself as a standard hardware random number +	  generator, major 10, minor 183, and the canonical device name is +	  /dev/hwrng. +	  The way to make use of this is to install the rng-tools package +	  (check your distro, or download from +	  http://sourceforge.net/projects/gkernel/).  rngd periodically reads +	  /dev/hwrng and injects the entropy into /dev/random. diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index bed467c9300..199ed283e14 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -15,15 +15,17 @@ n2-rng-y := n2-drv.o n2-asm.o  obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o  obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o  obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o +obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o  obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o  obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o  obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o  obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o  obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o  obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o -obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o  obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o  obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o +obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o  obj-$(CONFIG_HW_RANDOM_EXYNOS)	+= exynos-rng.o  obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o  obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o +obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index bf9fc6b7932..851bc7e20ad 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -54,29 +54,22 @@ static int atmel_trng_probe(struct platform_device *pdev)  	struct resource *res;  	int ret; -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) -		return -EINVAL; -  	trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);  	if (!trng)  		return -ENOMEM; -	if (!devm_request_mem_region(&pdev->dev, res->start, -				     resource_size(res), pdev->name)) -		return -EBUSY; - -	trng->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); -	if (!trng->base) -		return -EBUSY; +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	trng->base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(trng->base)) +		return PTR_ERR(trng->base); -	trng->clk = clk_get(&pdev->dev, NULL); +	trng->clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(trng->clk))  		return PTR_ERR(trng->clk);  	ret = clk_enable(trng->clk);  	if (ret) -		goto err_enable; +		return ret;  	writel(TRNG_KEY | 1, trng->base + TRNG_CR);  	trng->rng.name = pdev->name; @@ -92,9 +85,6 @@ static int atmel_trng_probe(struct platform_device *pdev)  err_register:  	clk_disable(trng->clk); -err_enable: -	clk_put(trng->clk); -  	return ret;  } @@ -106,7 +96,6 @@ static int atmel_trng_remove(struct platform_device *pdev)  	writel(TRNG_KEY, trng->base + TRNG_CR);  	clk_disable(trng->clk); -	clk_put(trng->clk);  	return 0;  } diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c index 43577ca780e..e900961cdd2 100644 --- a/drivers/char/hw_random/bcm2835-rng.c +++ b/drivers/char/hw_random/bcm2835-rng.c @@ -8,7 +8,6 @@   */  #include <linux/hw_random.h> -#include <linux/init.h>  #include <linux/io.h>  #include <linux/kernel.h>  #include <linux/module.h> @@ -62,18 +61,18 @@ static int bcm2835_rng_probe(struct platform_device *pdev)  	}  	bcm2835_rng_ops.priv = (unsigned long)rng_base; +	/* set warm-up count & enable */ +	__raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS); +	__raw_writel(RNG_RBGEN, rng_base + RNG_CTRL); +  	/* register driver */  	err = hwrng_register(&bcm2835_rng_ops);  	if (err) {  		dev_err(dev, "hwrng registration failed\n");  		iounmap(rng_base); -	} else { +	} else  		dev_info(dev, "hwrng registered\n"); -		/* set warm-up count & enable */ -		__raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS); -		__raw_writel(RNG_RBGEN, rng_base + RNG_CTRL); -	}  	return err;  } diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index a0f7724852e..c4419ea1ab0 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -37,10 +37,10 @@  #include <linux/kernel.h>  #include <linux/fs.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <linux/miscdevice.h>  #include <linux/delay.h>  #include <linux/slab.h> +#include <linux/random.h>  #include <asm/uaccess.h> @@ -55,16 +55,41 @@ static DEFINE_MUTEX(rng_mutex);  static int data_avail;  static u8 *rng_buffer; +static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, +			       int wait); +  static size_t rng_buffer_size(void)  {  	return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES;  } +static void add_early_randomness(struct hwrng *rng) +{ +	unsigned char bytes[16]; +	int bytes_read; + +	/* +	 * Currently only virtio-rng cannot return data during device +	 * probe, and that's handled in virtio-rng.c itself.  If there +	 * are more such devices, this call to rng_get_data can be +	 * made conditional here instead of doing it per-device. +	 */ +	bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1); +	if (bytes_read > 0) +		add_device_randomness(bytes, bytes_read); +} +  static inline int hwrng_init(struct hwrng *rng)  { -	if (!rng->init) -		return 0; -	return rng->init(rng); +	if (rng->init) { +		int ret; + +		ret =  rng->init(rng); +		if (ret) +			return ret; +	} +	add_early_randomness(rng); +	return 0;  }  static inline void hwrng_cleanup(struct hwrng *rng) @@ -302,7 +327,6 @@ err_misc_dereg:  int hwrng_register(struct hwrng *rng)  { -	int must_register_misc;  	int err = -EINVAL;  	struct hwrng *old_rng, *tmp; @@ -327,7 +351,6 @@ int hwrng_register(struct hwrng *rng)  			goto out_unlock;  	} -	must_register_misc = (current_rng == NULL);  	old_rng = current_rng;  	if (!old_rng) {  		err = hwrng_init(rng); @@ -336,18 +359,28 @@ int hwrng_register(struct hwrng *rng)  		current_rng = rng;  	}  	err = 0; -	if (must_register_misc) { +	if (!old_rng) {  		err = register_miscdev();  		if (err) { -			if (!old_rng) { -				hwrng_cleanup(rng); -				current_rng = NULL; -			} +			hwrng_cleanup(rng); +			current_rng = NULL;  			goto out_unlock;  		}  	}  	INIT_LIST_HEAD(&rng->list);  	list_add_tail(&rng->list, &rng_list); + +	if (old_rng && !rng->init) { +		/* +		 * Use a new device's input to add some randomness to +		 * the system.  If this rng device isn't going to be +		 * used right away, its init function hasn't been +		 * called yet; so only use the randomness from devices +		 * that don't need an init callback. +		 */ +		add_early_randomness(rng); +	} +  out_unlock:  	mutex_unlock(&rng_mutex);  out: diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index 402ccfb625c..9f8277cc44b 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -22,7 +22,6 @@  #include <linux/hw_random.h>  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/io.h>  #include <linux/platform_device.h>  #include <linux/clk.h> diff --git a/drivers/char/hw_random/msm-rng.c b/drivers/char/hw_random/msm-rng.c new file mode 100644 index 00000000000..148521e51dc --- /dev/null +++ b/drivers/char/hw_random/msm-rng.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/hw_random.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +/* Device specific register offsets */ +#define PRNG_DATA_OUT		0x0000 +#define PRNG_STATUS		0x0004 +#define PRNG_LFSR_CFG		0x0100 +#define PRNG_CONFIG		0x0104 + +/* Device specific register masks and config values */ +#define PRNG_LFSR_CFG_MASK	0x0000ffff +#define PRNG_LFSR_CFG_CLOCKS	0x0000dddd +#define PRNG_CONFIG_HW_ENABLE	BIT(1) +#define PRNG_STATUS_DATA_AVAIL	BIT(0) + +#define MAX_HW_FIFO_DEPTH	16 +#define MAX_HW_FIFO_SIZE	(MAX_HW_FIFO_DEPTH * 4) +#define WORD_SZ			4 + +struct msm_rng { +	void __iomem *base; +	struct clk *clk; +	struct hwrng hwrng; +}; + +#define to_msm_rng(p)	container_of(p, struct msm_rng, hwrng) + +static int msm_rng_enable(struct hwrng *hwrng, int enable) +{ +	struct msm_rng *rng = to_msm_rng(hwrng); +	u32 val; +	int ret; + +	ret = clk_prepare_enable(rng->clk); +	if (ret) +		return ret; + +	if (enable) { +		/* Enable PRNG only if it is not already enabled */ +		val = readl_relaxed(rng->base + PRNG_CONFIG); +		if (val & PRNG_CONFIG_HW_ENABLE) +			goto already_enabled; + +		val = readl_relaxed(rng->base + PRNG_LFSR_CFG); +		val &= ~PRNG_LFSR_CFG_MASK; +		val |= PRNG_LFSR_CFG_CLOCKS; +		writel(val, rng->base + PRNG_LFSR_CFG); + +		val = readl_relaxed(rng->base + PRNG_CONFIG); +		val |= PRNG_CONFIG_HW_ENABLE; +		writel(val, rng->base + PRNG_CONFIG); +	} else { +		val = readl_relaxed(rng->base + PRNG_CONFIG); +		val &= ~PRNG_CONFIG_HW_ENABLE; +		writel(val, rng->base + PRNG_CONFIG); +	} + +already_enabled: +	clk_disable_unprepare(rng->clk); +	return 0; +} + +static int msm_rng_read(struct hwrng *hwrng, void *data, size_t max, bool wait) +{ +	struct msm_rng *rng = to_msm_rng(hwrng); +	size_t currsize = 0; +	u32 *retdata = data; +	size_t maxsize; +	int ret; +	u32 val; + +	/* calculate max size bytes to transfer back to caller */ +	maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, max); + +	/* no room for word data */ +	if (maxsize < WORD_SZ) +		return 0; + +	ret = clk_prepare_enable(rng->clk); +	if (ret) +		return ret; + +	/* read random data from hardware */ +	do { +		val = readl_relaxed(rng->base + PRNG_STATUS); +		if (!(val & PRNG_STATUS_DATA_AVAIL)) +			break; + +		val = readl_relaxed(rng->base + PRNG_DATA_OUT); +		if (!val) +			break; + +		*retdata++ = val; +		currsize += WORD_SZ; + +		/* make sure we stay on 32bit boundary */ +		if ((maxsize - currsize) < WORD_SZ) +			break; +	} while (currsize < maxsize); + +	clk_disable_unprepare(rng->clk); + +	return currsize; +} + +static int msm_rng_init(struct hwrng *hwrng) +{ +	return msm_rng_enable(hwrng, 1); +} + +static void msm_rng_cleanup(struct hwrng *hwrng) +{ +	msm_rng_enable(hwrng, 0); +} + +static int msm_rng_probe(struct platform_device *pdev) +{ +	struct resource *res; +	struct msm_rng *rng; +	int ret; + +	rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); +	if (!rng) +		return -ENOMEM; + +	platform_set_drvdata(pdev, rng); + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	rng->base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(rng->base)) +		return PTR_ERR(rng->base); + +	rng->clk = devm_clk_get(&pdev->dev, "core"); +	if (IS_ERR(rng->clk)) +		return PTR_ERR(rng->clk); + +	rng->hwrng.name = KBUILD_MODNAME, +	rng->hwrng.init = msm_rng_init, +	rng->hwrng.cleanup = msm_rng_cleanup, +	rng->hwrng.read = msm_rng_read, + +	ret = hwrng_register(&rng->hwrng); +	if (ret) { +		dev_err(&pdev->dev, "failed to register hwrng\n"); +		return ret; +	} + +	return 0; +} + +static int msm_rng_remove(struct platform_device *pdev) +{ +	struct msm_rng *rng = platform_get_drvdata(pdev); + +	hwrng_unregister(&rng->hwrng); +	return 0; +} + +static const struct of_device_id msm_rng_of_match[] = { +	{ .compatible = "qcom,prng", }, +	{} +}; +MODULE_DEVICE_TABLE(of, msm_rng_of_match); + +static struct platform_driver msm_rng_driver = { +	.probe = msm_rng_probe, +	.remove = msm_rng_remove, +	.driver = { +		.name = KBUILD_MODNAME, +		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(msm_rng_of_match), +	} +}; +module_platform_driver(msm_rng_driver); + +MODULE_ALIAS("platform:" KBUILD_MODNAME); +MODULE_AUTHOR("The Linux Foundation"); +MODULE_DESCRIPTION("Qualcomm MSM random number generator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index f9beed54d0c..292a5889f67 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -7,7 +7,6 @@  #include <linux/module.h>  #include <linux/types.h>  #include <linux/delay.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/workqueue.h>  #include <linux/preempt.h> @@ -633,7 +632,7 @@ static int n2rng_probe(struct platform_device *op)  	multi_capable = (match->data != NULL);  	n2rng_driver_version(); -	np = kzalloc(sizeof(*np), GFP_KERNEL); +	np = devm_kzalloc(&op->dev, sizeof(*np), GFP_KERNEL);  	if (!np)  		goto out;  	np->op = op; @@ -654,7 +653,7 @@ static int n2rng_probe(struct platform_device *op)  					 &np->hvapi_minor)) {  			dev_err(&op->dev, "Cannot register suitable "  				"HVAPI version.\n"); -			goto out_free; +			goto out;  		}  	} @@ -677,15 +676,16 @@ static int n2rng_probe(struct platform_device *op)  	dev_info(&op->dev, "Registered RNG HVAPI major %lu minor %lu\n",  		 np->hvapi_major, np->hvapi_minor); -	np->units = kzalloc(sizeof(struct n2rng_unit) * np->num_units, -			    GFP_KERNEL); +	np->units = devm_kzalloc(&op->dev, +				 sizeof(struct n2rng_unit) * np->num_units, +				 GFP_KERNEL);  	err = -ENOMEM;  	if (!np->units)  		goto out_hvapi_unregister;  	err = n2rng_init_control(np);  	if (err) -		goto out_free_units; +		goto out_hvapi_unregister;  	dev_info(&op->dev, "Found %s RNG, units: %d\n",  		 ((np->flags & N2RNG_FLAG_MULTI) ? @@ -698,7 +698,7 @@ static int n2rng_probe(struct platform_device *op)  	err = hwrng_register(&np->hwrng);  	if (err) -		goto out_free_units; +		goto out_hvapi_unregister;  	platform_set_drvdata(op, np); @@ -706,15 +706,9 @@ static int n2rng_probe(struct platform_device *op)  	return 0; -out_free_units: -	kfree(np->units); -	np->units = NULL; -  out_hvapi_unregister:  	sun4v_hvapi_unregister(HV_GRP_RNG); -out_free: -	kfree(np);  out:  	return err;  } @@ -731,11 +725,6 @@ static int n2rng_remove(struct platform_device *op)  	sun4v_hvapi_unregister(HV_GRP_RNG); -	kfree(np->units); -	np->units = NULL; - -	kfree(np); -  	return 0;  } diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c index 232b87fb5fc..9c858157724 100644 --- a/drivers/char/hw_random/nomadik-rng.c +++ b/drivers/char/hw_random/nomadik-rng.c @@ -10,7 +10,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/device.h>  #include <linux/amba/bus.h>  #include <linux/hw_random.h> @@ -44,7 +43,7 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)  	void __iomem *base;  	int ret; -	rng_clk = clk_get(&dev->dev, NULL); +	rng_clk = devm_clk_get(&dev->dev, NULL);  	if (IS_ERR(rng_clk)) {  		dev_err(&dev->dev, "could not get rng clock\n");  		ret = PTR_ERR(rng_clk); @@ -57,33 +56,28 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)  	if (ret)  		goto out_clk;  	ret = -ENOMEM; -	base = ioremap(dev->res.start, resource_size(&dev->res)); +	base = devm_ioremap(&dev->dev, dev->res.start, +			    resource_size(&dev->res));  	if (!base)  		goto out_release;  	nmk_rng.priv = (unsigned long)base;  	ret = hwrng_register(&nmk_rng);  	if (ret) -		goto out_unmap; +		goto out_release;  	return 0; -out_unmap: -	iounmap(base);  out_release:  	amba_release_regions(dev);  out_clk:  	clk_disable(rng_clk); -	clk_put(rng_clk);  	return ret;  }  static int nmk_rng_remove(struct amba_device *dev)  { -	void __iomem *base = (void __iomem *)nmk_rng.priv;  	hwrng_unregister(&nmk_rng); -	iounmap(base);  	amba_release_regions(dev);  	clk_disable(rng_clk); -	clk_put(rng_clk);  	return 0;  } diff --git a/drivers/char/hw_random/octeon-rng.c b/drivers/char/hw_random/octeon-rng.c index f2885dbe184..b5cc3420c65 100644 --- a/drivers/char/hw_random/octeon-rng.c +++ b/drivers/char/hw_random/octeon-rng.c @@ -10,7 +10,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/device.h>  #include <linux/hw_random.h> diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 9b89ff4881d..f66ea258382 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -369,10 +369,8 @@ static int omap_rng_probe(struct platform_device *pdev)  	int ret;  	priv = devm_kzalloc(dev, sizeof(struct omap_rng_dev), GFP_KERNEL); -	if (!priv) { -		dev_err(&pdev->dev, "could not allocate memory\n"); +	if (!priv)  		return -ENOMEM; -	};  	omap_rng_ops.priv = (unsigned long)priv;  	platform_set_drvdata(pdev, priv); diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c new file mode 100644 index 00000000000..6f2eaffed62 --- /dev/null +++ b/drivers/char/hw_random/omap3-rom-rng.c @@ -0,0 +1,140 @@ +/* + * omap3-rom-rng.c - RNG driver for TI OMAP3 CPU family + * + * Copyright (C) 2009 Nokia Corporation + * Author: Juha Yrjola <juha.yrjola@solidboot.com> + * + * Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com> + * + * This file is licensed under  the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/random.h> +#include <linux/hw_random.h> +#include <linux/timer.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/platform_device.h> + +#define RNG_RESET			0x01 +#define RNG_GEN_PRNG_HW_INIT		0x02 +#define RNG_GEN_HW			0x08 + +/* param1: ptr, param2: count, param3: flag */ +static u32 (*omap3_rom_rng_call)(u32, u32, u32); + +static struct timer_list idle_timer; +static int rng_idle; +static struct clk *rng_clk; + +static void omap3_rom_rng_idle(unsigned long data) +{ +	int r; + +	r = omap3_rom_rng_call(0, 0, RNG_RESET); +	if (r != 0) { +		pr_err("reset failed: %d\n", r); +		return; +	} +	clk_disable_unprepare(rng_clk); +	rng_idle = 1; +} + +static int omap3_rom_rng_get_random(void *buf, unsigned int count) +{ +	u32 r; +	u32 ptr; + +	del_timer_sync(&idle_timer); +	if (rng_idle) { +		clk_prepare_enable(rng_clk); +		r = omap3_rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT); +		if (r != 0) { +			clk_disable_unprepare(rng_clk); +			pr_err("HW init failed: %d\n", r); +			return -EIO; +		} +		rng_idle = 0; +	} + +	ptr = virt_to_phys(buf); +	r = omap3_rom_rng_call(ptr, count, RNG_GEN_HW); +	mod_timer(&idle_timer, jiffies + msecs_to_jiffies(500)); +	if (r != 0) +		return -EINVAL; +	return 0; +} + +static int omap3_rom_rng_data_present(struct hwrng *rng, int wait) +{ +	return 1; +} + +static int omap3_rom_rng_data_read(struct hwrng *rng, u32 *data) +{ +	int r; + +	r = omap3_rom_rng_get_random(data, 4); +	if (r < 0) +		return r; +	return 4; +} + +static struct hwrng omap3_rom_rng_ops = { +	.name		= "omap3-rom", +	.data_present	= omap3_rom_rng_data_present, +	.data_read	= omap3_rom_rng_data_read, +}; + +static int omap3_rom_rng_probe(struct platform_device *pdev) +{ +	pr_info("initializing\n"); + +	omap3_rom_rng_call = pdev->dev.platform_data; +	if (!omap3_rom_rng_call) { +		pr_err("omap3_rom_rng_call is NULL\n"); +		return -EINVAL; +	} + +	setup_timer(&idle_timer, omap3_rom_rng_idle, 0); +	rng_clk = devm_clk_get(&pdev->dev, "ick"); +	if (IS_ERR(rng_clk)) { +		pr_err("unable to get RNG clock\n"); +		return PTR_ERR(rng_clk); +	} + +	/* Leave the RNG in reset state. */ +	clk_prepare_enable(rng_clk); +	omap3_rom_rng_idle(0); + +	return hwrng_register(&omap3_rom_rng_ops); +} + +static int omap3_rom_rng_remove(struct platform_device *pdev) +{ +	hwrng_unregister(&omap3_rom_rng_ops); +	clk_disable_unprepare(rng_clk); +	return 0; +} + +static struct platform_driver omap3_rom_rng_driver = { +	.driver = { +		.name		= "omap3-rom-rng", +		.owner		= THIS_MODULE, +	}, +	.probe		= omap3_rom_rng_probe, +	.remove		= omap3_rom_rng_remove, +}; + +module_platform_driver(omap3_rom_rng_driver); + +MODULE_ALIAS("platform:omap3-rom-rng"); +MODULE_AUTHOR("Juha Yrjola"); +MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index c6df5b29af0..c66279bb6ef 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -24,6 +24,7 @@  #include <linux/platform_device.h>  #include <linux/hw_random.h>  #include <linux/delay.h> +#include <linux/of_address.h>  #include <linux/of_platform.h>  #include <asm/io.h> diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c deleted file mode 100644 index 3d4c2293c6f..00000000000 --- a/drivers/char/hw_random/picoxcell-rng.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2010-2011 Picochip Ltd., Jamie Iles - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * All enquiries to support@picochip.com - */ -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/hw_random.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> - -#define DATA_REG_OFFSET		0x0200 -#define CSR_REG_OFFSET		0x0278 -#define CSR_OUT_EMPTY_MASK	(1 << 24) -#define CSR_FAULT_MASK		(1 << 1) -#define TRNG_BLOCK_RESET_MASK	(1 << 0) -#define TAI_REG_OFFSET		0x0380 - -/* - * The maximum amount of time in microseconds to spend waiting for data if the - * core wants us to wait.  The TRNG should generate 32 bits every 320ns so a - * timeout of 20us seems reasonable.  The TRNG does builtin tests of the data - * for randomness so we can't always assume there is data present. - */ -#define PICO_TRNG_TIMEOUT		20 - -static void __iomem *rng_base; -static struct clk *rng_clk; -static struct device *rng_dev; - -static inline u32 picoxcell_trng_read_csr(void) -{ -	return __raw_readl(rng_base + CSR_REG_OFFSET); -} - -static inline bool picoxcell_trng_is_empty(void) -{ -	return picoxcell_trng_read_csr() & CSR_OUT_EMPTY_MASK; -} - -/* - * Take the random number generator out of reset and make sure the interrupts - * are masked. We shouldn't need to get large amounts of random bytes so just - * poll the status register. The hardware generates 32 bits every 320ns so we - * shouldn't have to wait long enough to warrant waiting for an IRQ. - */ -static void picoxcell_trng_start(void) -{ -	__raw_writel(0, rng_base + TAI_REG_OFFSET); -	__raw_writel(0, rng_base + CSR_REG_OFFSET); -} - -static void picoxcell_trng_reset(void) -{ -	__raw_writel(TRNG_BLOCK_RESET_MASK, rng_base + CSR_REG_OFFSET); -	__raw_writel(TRNG_BLOCK_RESET_MASK, rng_base + TAI_REG_OFFSET); -	picoxcell_trng_start(); -} - -/* - * Get some random data from the random number generator. The hw_random core - * layer provides us with locking. - */ -static int picoxcell_trng_read(struct hwrng *rng, void *buf, size_t max, -			       bool wait) -{ -	int i; - -	/* Wait for some data to become available. */ -	for (i = 0; i < PICO_TRNG_TIMEOUT && picoxcell_trng_is_empty(); ++i) { -		if (!wait) -			return 0; - -		udelay(1); -	} - -	if (picoxcell_trng_read_csr() & CSR_FAULT_MASK) { -		dev_err(rng_dev, "fault detected, resetting TRNG\n"); -		picoxcell_trng_reset(); -		return -EIO; -	} - -	if (i == PICO_TRNG_TIMEOUT) -		return 0; - -	*(u32 *)buf = __raw_readl(rng_base + DATA_REG_OFFSET); -	return sizeof(u32); -} - -static struct hwrng picoxcell_trng = { -	.name		= "picoxcell", -	.read		= picoxcell_trng_read, -}; - -static int picoxcell_trng_probe(struct platform_device *pdev) -{ -	int ret; -	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - -	if (!mem) { -		dev_warn(&pdev->dev, "no memory resource\n"); -		return -ENOMEM; -	} - -	if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), -				     "picoxcell_trng")) { -		dev_warn(&pdev->dev, "unable to request io mem\n"); -		return -EBUSY; -	} - -	rng_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); -	if (!rng_base) { -		dev_warn(&pdev->dev, "unable to remap io mem\n"); -		return -ENOMEM; -	} - -	rng_clk = clk_get(&pdev->dev, NULL); -	if (IS_ERR(rng_clk)) { -		dev_warn(&pdev->dev, "no clk\n"); -		return PTR_ERR(rng_clk); -	} - -	ret = clk_enable(rng_clk); -	if (ret) { -		dev_warn(&pdev->dev, "unable to enable clk\n"); -		goto err_enable; -	} - -	picoxcell_trng_start(); -	ret = hwrng_register(&picoxcell_trng); -	if (ret) -		goto err_register; - -	rng_dev = &pdev->dev; -	dev_info(&pdev->dev, "pixoxcell random number generator active\n"); - -	return 0; - -err_register: -	clk_disable(rng_clk); -err_enable: -	clk_put(rng_clk); - -	return ret; -} - -static int picoxcell_trng_remove(struct platform_device *pdev) -{ -	hwrng_unregister(&picoxcell_trng); -	clk_disable(rng_clk); -	clk_put(rng_clk); - -	return 0; -} - -#ifdef CONFIG_PM -static int picoxcell_trng_suspend(struct device *dev) -{ -	clk_disable(rng_clk); - -	return 0; -} - -static int picoxcell_trng_resume(struct device *dev) -{ -	return clk_enable(rng_clk); -} - -static const struct dev_pm_ops picoxcell_trng_pm_ops = { -	.suspend	= picoxcell_trng_suspend, -	.resume		= picoxcell_trng_resume, -}; -#endif /* CONFIG_PM */ - -static struct platform_driver picoxcell_trng_driver = { -	.probe		= picoxcell_trng_probe, -	.remove		= picoxcell_trng_remove, -	.driver		= { -		.name	= "picoxcell-trng", -		.owner	= THIS_MODULE, -#ifdef CONFIG_PM -		.pm	= &picoxcell_trng_pm_ops, -#endif /* CONFIG_PM */ -	}, -}; - -module_platform_driver(picoxcell_trng_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jamie Iles"); -MODULE_DESCRIPTION("Picochip picoXcell TRNG driver"); diff --git a/drivers/char/hw_random/powernv-rng.c b/drivers/char/hw_random/powernv-rng.c new file mode 100644 index 00000000000..3f4f6320456 --- /dev/null +++ b/drivers/char/hw_random/powernv-rng.c @@ -0,0 +1,81 @@ +/* + * Copyright 2013 Michael Ellerman, Guo Chao, IBM Corp. + * + * 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. + */ + +#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/random.h> +#include <linux/hw_random.h> + +static int powernv_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ +	unsigned long *buf; +	int i, len; + +	/* We rely on rng_buffer_size() being >= sizeof(unsigned long) */ +	len = max / sizeof(unsigned long); + +	buf = (unsigned long *)data; + +	for (i = 0; i < len; i++) +		powernv_get_random_long(buf++); + +	return len * sizeof(unsigned long); +} + +static struct hwrng powernv_hwrng = { +	.name = "powernv-rng", +	.read = powernv_rng_read, +}; + +static int powernv_rng_remove(struct platform_device *pdev) +{ +	hwrng_unregister(&powernv_hwrng); + +	return 0; +} + +static int powernv_rng_probe(struct platform_device *pdev) +{ +	int rc; + +	rc = hwrng_register(&powernv_hwrng); +	if (rc) { +		/* We only register one device, ignore any others */ +		if (rc == -EEXIST) +			rc = -ENODEV; + +		return rc; +	} + +	pr_info("Registered powernv hwrng.\n"); + +	return 0; +} + +static struct of_device_id powernv_rng_match[] = { +	{ .compatible	= "ibm,power-rng",}, +	{}, +}; +MODULE_DEVICE_TABLE(of, powernv_rng_match); + +static struct platform_driver powernv_rng_driver = { +	.driver = { +		.name = "powernv_rng", +		.of_match_table = powernv_rng_match, +	}, +	.probe	= powernv_rng_probe, +	.remove = powernv_rng_remove, +}; +module_platform_driver(powernv_rng_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Bare metal HWRNG driver for POWER7+ and above"); diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c index 732c330805f..521f76b0934 100644 --- a/drivers/char/hw_random/ppc4xx-rng.c +++ b/drivers/char/hw_random/ppc4xx-rng.c @@ -13,6 +13,7 @@  #include <linux/platform_device.h>  #include <linux/hw_random.h>  #include <linux/delay.h> +#include <linux/of_address.h>  #include <linux/of_platform.h>  #include <asm/io.h> diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c index 5f1197929f0..ab7ffdec0ec 100644 --- a/drivers/char/hw_random/pseries-rng.c +++ b/drivers/char/hw_random/pseries-rng.c @@ -17,18 +17,25 @@   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h>  #include <linux/module.h>  #include <linux/hw_random.h>  #include <asm/vio.h> -#define MODULE_NAME "pseries-rng"  static int pseries_rng_data_read(struct hwrng *rng, u32 *data)  { -	if (plpar_hcall(H_RANDOM, (unsigned long *)data) != H_SUCCESS) { -		printk(KERN_ERR "pseries rng hcall error\n"); -		return 0; +	int rc; + +	rc = plpar_hcall(H_RANDOM, (unsigned long *)data); +	if (rc != H_SUCCESS) { +		pr_err_ratelimited("H_RANDOM call failed %d\n", rc); +		return -EIO;  	} + +	/* The hypervisor interface returns 64 bits */  	return 8;  } @@ -47,7 +54,7 @@ static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev)  };  static struct hwrng pseries_rng = { -	.name		= MODULE_NAME, +	.name		= KBUILD_MODNAME,  	.data_read	= pseries_rng_data_read,  }; @@ -70,7 +77,7 @@ static struct vio_device_id pseries_rng_driver_ids[] = {  MODULE_DEVICE_TABLE(vio, pseries_rng_driver_ids);  static struct vio_driver pseries_rng_driver = { -	.name = MODULE_NAME, +	.name = KBUILD_MODNAME,  	.probe = pseries_rng_probe,  	.remove = pseries_rng_remove,  	.get_desired_dma = pseries_rng_get_desired_dma, diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index d2120ba8f3f..b6ab9ac3f34 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -79,7 +79,7 @@ static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data)  	priv->expires = cur + delay;  	priv->present = 0; -	INIT_COMPLETION(priv->completion); +	reinit_completion(&priv->completion);  	mod_timer(&priv->timer, priv->expires);  	return 4; @@ -118,11 +118,10 @@ static int timeriomem_rng_probe(struct platform_device *pdev)  	}  	/* Allocate memory for the device structure (and zero it) */ -	priv = kzalloc(sizeof(struct timeriomem_rng_private_data), GFP_KERNEL); -	if (!priv) { -		dev_err(&pdev->dev, "failed to allocate device structure.\n"); +	priv = devm_kzalloc(&pdev->dev, +			sizeof(struct timeriomem_rng_private_data), GFP_KERNEL); +	if (!priv)  		return -ENOMEM; -	}  	platform_set_drvdata(pdev, priv); @@ -134,17 +133,16 @@ static int timeriomem_rng_probe(struct platform_device *pdev)  			period = i;  		else {  			dev_err(&pdev->dev, "missing period\n"); -			err = -EINVAL; -			goto out_free; +			return -EINVAL;  		} -	} else +	} else {  		period = pdata->period; +	}  	priv->period = usecs_to_jiffies(period);  	if (priv->period < 1) {  		dev_err(&pdev->dev, "period is less than one jiffy\n"); -		err = -EINVAL; -		goto out_free; +		return -EINVAL;  	}  	priv->expires	= jiffies; @@ -160,24 +158,16 @@ static int timeriomem_rng_probe(struct platform_device *pdev)  	priv->timeriomem_rng_ops.data_read	= timeriomem_rng_data_read;  	priv->timeriomem_rng_ops.priv		= (unsigned long)priv; -	if (!request_mem_region(res->start, resource_size(res), -				dev_name(&pdev->dev))) { -		dev_err(&pdev->dev, "request_mem_region failed\n"); -		err = -EBUSY; +	priv->io_base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(priv->io_base)) { +		err = PTR_ERR(priv->io_base);  		goto out_timer;  	} -	priv->io_base = ioremap(res->start, resource_size(res)); -	if (priv->io_base == NULL) { -		dev_err(&pdev->dev, "ioremap failed\n"); -		err = -EIO; -		goto out_release_io; -	} -  	err = hwrng_register(&priv->timeriomem_rng_ops);  	if (err) {  		dev_err(&pdev->dev, "problem registering\n"); -		goto out; +		goto out_timer;  	}  	dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n", @@ -185,30 +175,18 @@ static int timeriomem_rng_probe(struct platform_device *pdev)  	return 0; -out: -	iounmap(priv->io_base); -out_release_io: -	release_mem_region(res->start, resource_size(res));  out_timer:  	del_timer_sync(&priv->timer); -out_free: -	kfree(priv);  	return err;  }  static int timeriomem_rng_remove(struct platform_device *pdev)  {  	struct timeriomem_rng_private_data *priv = platform_get_drvdata(pdev); -	struct resource *res; - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	hwrng_unregister(&priv->timeriomem_rng_ops);  	del_timer_sync(&priv->timer); -	iounmap(priv->io_base); -	release_mem_region(res->start, resource_size(res)); -	kfree(priv);  	return 0;  } diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index e737772ad69..de5a6dcfb3e 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -221,7 +221,7 @@ static void __exit mod_exit(void)  module_init(mod_init);  module_exit(mod_exit); -static struct x86_cpu_id via_rng_cpu_id[] = { +static struct x86_cpu_id __maybe_unused via_rng_cpu_id[] = {  	X86_FEATURE_MATCH(X86_FEATURE_XSTORE),  	{}  }; diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index ef46a9cfd83..e9b15bc18b4 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -25,102 +25,140 @@  #include <linux/virtio_rng.h>  #include <linux/module.h> -static struct virtqueue *vq; -static unsigned int data_avail; -static DECLARE_COMPLETION(have_data); -static bool busy; +static DEFINE_IDA(rng_index_ida); + +struct virtrng_info { +	struct virtio_device *vdev; +	struct hwrng hwrng; +	struct virtqueue *vq; +	unsigned int data_avail; +	struct completion have_data; +	bool busy; +	char name[25]; +	int index; +}; + +static bool probe_done;  static void random_recv_done(struct virtqueue *vq)  { +	struct virtrng_info *vi = vq->vdev->priv; +  	/* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */ -	if (!virtqueue_get_buf(vq, &data_avail)) +	if (!virtqueue_get_buf(vi->vq, &vi->data_avail))  		return; -	complete(&have_data); +	complete(&vi->have_data);  }  /* The host will fill any buffer we give it with sweet, sweet randomness. */ -static void register_buffer(u8 *buf, size_t size) +static void register_buffer(struct virtrng_info *vi, u8 *buf, size_t size)  {  	struct scatterlist sg;  	sg_init_one(&sg, buf, size);  	/* There should always be room for one buffer. */ -	if (virtqueue_add_inbuf(vq, &sg, 1, buf, GFP_KERNEL) < 0) -		BUG(); +	virtqueue_add_inbuf(vi->vq, &sg, 1, buf, GFP_KERNEL); -	virtqueue_kick(vq); +	virtqueue_kick(vi->vq);  }  static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)  {  	int ret; +	struct virtrng_info *vi = (struct virtrng_info *)rng->priv; -	if (!busy) { -		busy = true; -		init_completion(&have_data); -		register_buffer(buf, size); +	/* +	 * Don't ask host for data till we're setup.  This call can +	 * happen during hwrng_register(), after commit d9e7972619. +	 */ +	if (unlikely(!probe_done)) +		return 0; + +	if (!vi->busy) { +		vi->busy = true; +		init_completion(&vi->have_data); +		register_buffer(vi, buf, size);  	}  	if (!wait)  		return 0; -	ret = wait_for_completion_killable(&have_data); +	ret = wait_for_completion_killable(&vi->have_data);  	if (ret < 0)  		return ret; -	busy = false; +	vi->busy = false; -	return data_avail; +	return vi->data_avail;  }  static void virtio_cleanup(struct hwrng *rng)  { -	if (busy) -		wait_for_completion(&have_data); -} +	struct virtrng_info *vi = (struct virtrng_info *)rng->priv; - -static struct hwrng virtio_hwrng = { -	.name		= "virtio", -	.cleanup	= virtio_cleanup, -	.read		= virtio_read, -}; +	if (vi->busy) +		wait_for_completion(&vi->have_data); +}  static int probe_common(struct virtio_device *vdev)  { -	int err; +	int err, index; +	struct virtrng_info *vi = NULL; -	if (vq) { -		/* We only support one device for now */ -		return -EBUSY; +	vi = kzalloc(sizeof(struct virtrng_info), GFP_KERNEL); +	if (!vi) +		return -ENOMEM; + +	vi->index = index = ida_simple_get(&rng_index_ida, 0, 0, GFP_KERNEL); +	if (index < 0) { +		kfree(vi); +		return index;  	} +	sprintf(vi->name, "virtio_rng.%d", index); +	init_completion(&vi->have_data); + +	vi->hwrng = (struct hwrng) { +		.read = virtio_read, +		.cleanup = virtio_cleanup, +		.priv = (unsigned long)vi, +		.name = vi->name, +	}; +	vdev->priv = vi; +  	/* We expect a single virtqueue. */ -	vq = virtio_find_single_vq(vdev, random_recv_done, "input"); -	if (IS_ERR(vq)) { -		err = PTR_ERR(vq); -		vq = NULL; +	vi->vq = virtio_find_single_vq(vdev, random_recv_done, "input"); +	if (IS_ERR(vi->vq)) { +		err = PTR_ERR(vi->vq); +		vi->vq = NULL; +		kfree(vi); +		ida_simple_remove(&rng_index_ida, index);  		return err;  	} -	err = hwrng_register(&virtio_hwrng); +	err = hwrng_register(&vi->hwrng);  	if (err) {  		vdev->config->del_vqs(vdev); -		vq = NULL; +		vi->vq = NULL; +		kfree(vi); +		ida_simple_remove(&rng_index_ida, index);  		return err;  	} +	probe_done = true;  	return 0;  }  static void remove_common(struct virtio_device *vdev)  { +	struct virtrng_info *vi = vdev->priv;  	vdev->config->reset(vdev); -	busy = false; -	hwrng_unregister(&virtio_hwrng); +	vi->busy = false; +	hwrng_unregister(&vi->hwrng);  	vdev->config->del_vqs(vdev); -	vq = NULL; +	ida_simple_remove(&rng_index_ida, vi->index); +	kfree(vi);  }  static int virtrng_probe(struct virtio_device *vdev) @@ -133,7 +171,7 @@ static void virtrng_remove(struct virtio_device *vdev)  	remove_common(vdev);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int virtrng_freeze(struct virtio_device *vdev)  {  	remove_common(vdev); @@ -157,7 +195,7 @@ static struct virtio_driver virtio_rng_driver = {  	.id_table =	id_table,  	.probe =	virtrng_probe,  	.remove =	virtrng_remove, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.freeze =	virtrng_freeze,  	.restore =	virtrng_restore,  #endif diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 40cc0cf2ded..93dcad0c1cb 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -1,12 +1,11 @@  /*   * i8k.c -- Linux driver for accessing the SMM BIOS on Dell laptops. - *	    See http://www.debian.org/~dz/i8k/ for more information - *	    and for latest version of this driver.   *   * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>   *   * Hwmon integration: - * Copyright (C) 2011  Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2011  Jean Delvare <jdelvare@suse.de> + * Copyright (C) 2013  Guenter Roeck <linux@roeck-us.net>   *   * 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 @@ -19,6 +18,8 @@   * General Public License for more details.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/module.h>  #include <linux/types.h>  #include <linux/init.h> @@ -29,13 +30,12 @@  #include <linux/mutex.h>  #include <linux/hwmon.h>  #include <linux/hwmon-sysfs.h> -#include <asm/uaccess.h> -#include <asm/io.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <linux/sched.h>  #include <linux/i8k.h> -#define I8K_VERSION		"1.14 21/02/2005" -  #define I8K_SMM_FN_STATUS	0x0025  #define I8K_SMM_POWER_STATUS	0x0069  #define I8K_SMM_SET_FAN		0x01a3 @@ -44,7 +44,6 @@  #define I8K_SMM_GET_TEMP	0x10a3  #define I8K_SMM_GET_DELL_SIG1	0xfea3  #define I8K_SMM_GET_DELL_SIG2	0xffa3 -#define I8K_SMM_BIOS_VERSION	0x00a6  #define I8K_FAN_MULT		30  #define I8K_MAX_TEMP		127 @@ -64,6 +63,15 @@  static DEFINE_MUTEX(i8k_mutex);  static char bios_version[4];  static struct device *i8k_hwmon_dev; +static u32 i8k_hwmon_flags; +static int i8k_fan_mult; + +#define I8K_HWMON_HAVE_TEMP1	(1 << 0) +#define I8K_HWMON_HAVE_TEMP2	(1 << 1) +#define I8K_HWMON_HAVE_TEMP3	(1 << 2) +#define I8K_HWMON_HAVE_TEMP4	(1 << 3) +#define I8K_HWMON_HAVE_FAN1	(1 << 4) +#define I8K_HWMON_HAVE_FAN2	(1 << 5)  MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");  MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); @@ -103,11 +111,11 @@ static const struct file_operations i8k_fops = {  struct smm_regs {  	unsigned int eax; -	unsigned int ebx __attribute__ ((packed)); -	unsigned int ecx __attribute__ ((packed)); -	unsigned int edx __attribute__ ((packed)); -	unsigned int esi __attribute__ ((packed)); -	unsigned int edi __attribute__ ((packed)); +	unsigned int ebx __packed; +	unsigned int ecx __packed; +	unsigned int edx __packed; +	unsigned int esi __packed; +	unsigned int edi __packed;  };  static inline const char *i8k_get_dmi_data(int field) @@ -124,6 +132,19 @@ static int i8k_smm(struct smm_regs *regs)  {  	int rc;  	int eax = regs->eax; +	cpumask_var_t old_mask; + +	/* SMM requires CPU 0 */ +	if (!alloc_cpumask_var(&old_mask, GFP_KERNEL)) +		return -ENOMEM; +	cpumask_copy(old_mask, ¤t->cpus_allowed); +	rc = set_cpus_allowed_ptr(current, cpumask_of(0)); +	if (rc) +		goto out; +	if (smp_processor_id() != 0) { +		rc = -EBUSY; +		goto out; +	}  #if defined(CONFIG_X86_64)  	asm volatile("pushq %%rax\n\t" @@ -148,7 +169,7 @@ static int i8k_smm(struct smm_regs *regs)  		"pushfq\n\t"  		"popq %%rax\n\t"  		"andl $1,%%eax\n" -		:"=a"(rc) +		: "=a"(rc)  		:    "a"(regs)  		:    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");  #else @@ -174,25 +195,17 @@ static int i8k_smm(struct smm_regs *regs)  	    "lahf\n\t"  	    "shrl $8,%%eax\n\t"  	    "andl $1,%%eax\n" -	    :"=a"(rc) +	    : "=a"(rc)  	    :    "a"(regs)  	    :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");  #endif  	if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax) -		return -EINVAL; - -	return 0; -} - -/* - * Read the bios version. Return the version as an integer corresponding - * to the ascii value, for example "A17" is returned as 0x00413137. - */ -static int i8k_get_bios_version(void) -{ -	struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, }; +		rc = -EINVAL; -	return i8k_smm(®s) ? : regs.eax; +out: +	set_cpus_allowed_ptr(current, old_mask); +	free_cpumask_var(old_mask); +	return rc;  }  /* @@ -203,7 +216,8 @@ static int i8k_get_fn_status(void)  	struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, };  	int rc; -	if ((rc = i8k_smm(®s)) < 0) +	rc = i8k_smm(®s); +	if (rc < 0)  		return rc;  	switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { @@ -226,7 +240,8 @@ static int i8k_get_power_status(void)  	struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, };  	int rc; -	if ((rc = i8k_smm(®s)) < 0) +	rc = i8k_smm(®s); +	if (rc < 0)  		return rc;  	return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY; @@ -251,7 +266,7 @@ static int i8k_get_fan_speed(int fan)  	struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };  	regs.ebx = fan & 0xff; -	return i8k_smm(®s) ? : (regs.eax & 0xffff) * fan_mult; +	return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult;  }  /* @@ -277,10 +292,11 @@ static int i8k_get_temp(int sensor)  	int temp;  #ifdef I8K_TEMPERATURE_BUG -	static int prev; +	static int prev[4];  #endif  	regs.ebx = sensor & 0xff; -	if ((rc = i8k_smm(®s)) < 0) +	rc = i8k_smm(®s); +	if (rc < 0)  		return rc;  	temp = regs.eax & 0xff; @@ -294,10 +310,10 @@ static int i8k_get_temp(int sensor)  	 # 1003655139 00000054 00005c52  	 */  	if (temp > I8K_MAX_TEMP) { -		temp = prev; -		prev = I8K_MAX_TEMP; +		temp = prev[sensor]; +		prev[sensor] = I8K_MAX_TEMP;  	} else { -		prev = temp; +		prev[sensor] = temp;  	}  #endif @@ -309,7 +325,8 @@ static int i8k_get_dell_signature(int req_fn)  	struct smm_regs regs = { .eax = req_fn, };  	int rc; -	if ((rc = i8k_smm(®s)) < 0) +	rc = i8k_smm(®s); +	if (rc < 0)  		return rc;  	return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1; @@ -328,12 +345,14 @@ i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg)  	switch (cmd) {  	case I8K_BIOS_VERSION: -		val = i8k_get_bios_version(); +		val = (bios_version[0] << 16) | +				(bios_version[1] << 8) | bios_version[2];  		break;  	case I8K_MACHINE_ID:  		memset(buff, 0, 16); -		strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), sizeof(buff)); +		strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), +			sizeof(buff));  		break;  	case I8K_FN_STATUS: @@ -470,12 +489,13 @@ static ssize_t i8k_hwmon_show_temp(struct device *dev,  				   struct device_attribute *devattr,  				   char *buf)  { -	int cpu_temp; +	int index = to_sensor_dev_attr(devattr)->index; +	int temp; -	cpu_temp = i8k_get_temp(0); -	if (cpu_temp < 0) -		return cpu_temp; -	return sprintf(buf, "%d\n", cpu_temp * 1000); +	temp = i8k_get_temp(index); +	if (temp < 0) +		return temp; +	return sprintf(buf, "%d\n", temp * 1000);  }  static ssize_t i8k_hwmon_show_fan(struct device *dev, @@ -491,12 +511,44 @@ static ssize_t i8k_hwmon_show_fan(struct device *dev,  	return sprintf(buf, "%d\n", fan_speed);  } +static ssize_t i8k_hwmon_show_pwm(struct device *dev, +				  struct device_attribute *devattr, +				  char *buf) +{ +	int index = to_sensor_dev_attr(devattr)->index; +	int status; + +	status = i8k_get_fan_status(index); +	if (status < 0) +		return -EIO; +	return sprintf(buf, "%d\n", clamp_val(status * 128, 0, 255)); +} + +static ssize_t i8k_hwmon_set_pwm(struct device *dev, +				 struct device_attribute *attr, +				 const char *buf, size_t count) +{ +	int index = to_sensor_dev_attr(attr)->index; +	unsigned long val; +	int err; + +	err = kstrtoul(buf, 10, &val); +	if (err) +		return err; +	val = clamp_val(DIV_ROUND_CLOSEST(val, 128), 0, 2); + +	mutex_lock(&i8k_mutex); +	err = i8k_set_fan(index, val); +	mutex_unlock(&i8k_mutex); + +	return err < 0 ? -EIO : count; +} +  static ssize_t i8k_hwmon_show_label(struct device *dev,  				    struct device_attribute *devattr,  				    char *buf)  { -	static const char *labels[4] = { -		"i8k", +	static const char *labels[3] = {  		"CPU",  		"Left Fan",  		"Right Fan", @@ -506,108 +558,108 @@ static ssize_t i8k_hwmon_show_label(struct device *dev,  	return sprintf(buf, "%s\n", labels[index]);  } -static DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3);  static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,  			  I8K_FAN_LEFT); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, +			  i8k_hwmon_set_pwm, I8K_FAN_LEFT);  static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,  			  I8K_FAN_RIGHT); -static SENSOR_DEVICE_ATTR(name, S_IRUGO, i8k_hwmon_show_label, NULL, 0); -static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1); -static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2); -static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 3); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, +			  i8k_hwmon_set_pwm, I8K_FAN_RIGHT); +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1); +static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2); + +static struct attribute *i8k_attrs[] = { +	&sensor_dev_attr_temp1_input.dev_attr.attr,	/* 0 */ +	&sensor_dev_attr_temp1_label.dev_attr.attr,	/* 1 */ +	&sensor_dev_attr_temp2_input.dev_attr.attr,	/* 2 */ +	&sensor_dev_attr_temp3_input.dev_attr.attr,	/* 3 */ +	&sensor_dev_attr_temp4_input.dev_attr.attr,	/* 4 */ +	&sensor_dev_attr_fan1_input.dev_attr.attr,	/* 5 */ +	&sensor_dev_attr_pwm1.dev_attr.attr,		/* 6 */ +	&sensor_dev_attr_fan1_label.dev_attr.attr,	/* 7 */ +	&sensor_dev_attr_fan2_input.dev_attr.attr,	/* 8 */ +	&sensor_dev_attr_pwm2.dev_attr.attr,		/* 9 */ +	&sensor_dev_attr_fan2_label.dev_attr.attr,	/* 10 */ +	NULL +}; -static void i8k_hwmon_remove_files(struct device *dev) +static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, +			      int index)  { -	device_remove_file(dev, &dev_attr_temp1_input); -	device_remove_file(dev, &sensor_dev_attr_fan1_input.dev_attr); -	device_remove_file(dev, &sensor_dev_attr_fan2_input.dev_attr); -	device_remove_file(dev, &sensor_dev_attr_temp1_label.dev_attr); -	device_remove_file(dev, &sensor_dev_attr_fan1_label.dev_attr); -	device_remove_file(dev, &sensor_dev_attr_fan2_label.dev_attr); -	device_remove_file(dev, &sensor_dev_attr_name.dev_attr); +	if ((index == 0 || index == 1) && +	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) +		return 0; +	if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) +		return 0; +	if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) +		return 0; +	if (index == 4 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) +		return 0; +	if (index >= 5 && index <= 7 && +	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) +		return 0; +	if (index >= 8 && index <= 10 && +	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) +		return 0; + +	return attr->mode;  } +static const struct attribute_group i8k_group = { +	.attrs = i8k_attrs, +	.is_visible = i8k_is_visible, +}; +__ATTRIBUTE_GROUPS(i8k); +  static int __init i8k_init_hwmon(void)  {  	int err; -	i8k_hwmon_dev = hwmon_device_register(NULL); -	if (IS_ERR(i8k_hwmon_dev)) { -		err = PTR_ERR(i8k_hwmon_dev); -		i8k_hwmon_dev = NULL; -		printk(KERN_ERR "i8k: hwmon registration failed (%d)\n", err); -		return err; -	} - -	/* Required name attribute */ -	err = device_create_file(i8k_hwmon_dev, -				 &sensor_dev_attr_name.dev_attr); -	if (err) -		goto exit_unregister; +	i8k_hwmon_flags = 0;  	/* CPU temperature attributes, if temperature reading is OK */  	err = i8k_get_temp(0); -	if (err < 0) { -		dev_dbg(i8k_hwmon_dev, -			"Not creating temperature attributes (%d)\n", err); -	} else { -		err = device_create_file(i8k_hwmon_dev, &dev_attr_temp1_input); -		if (err) -			goto exit_remove_files; -		err = device_create_file(i8k_hwmon_dev, -					 &sensor_dev_attr_temp1_label.dev_attr); -		if (err) -			goto exit_remove_files; -	} +	if (err >= 0) +		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1; +	/* check for additional temperature sensors */ +	err = i8k_get_temp(1); +	if (err >= 0) +		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2; +	err = i8k_get_temp(2); +	if (err >= 0) +		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3; +	err = i8k_get_temp(3); +	if (err >= 0) +		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;  	/* Left fan attributes, if left fan is present */  	err = i8k_get_fan_status(I8K_FAN_LEFT); -	if (err < 0) { -		dev_dbg(i8k_hwmon_dev, -			"Not creating %s fan attributes (%d)\n", "left", err); -	} else { -		err = device_create_file(i8k_hwmon_dev, -					 &sensor_dev_attr_fan1_input.dev_attr); -		if (err) -			goto exit_remove_files; -		err = device_create_file(i8k_hwmon_dev, -					 &sensor_dev_attr_fan1_label.dev_attr); -		if (err) -			goto exit_remove_files; -	} +	if (err >= 0) +		i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;  	/* Right fan attributes, if right fan is present */  	err = i8k_get_fan_status(I8K_FAN_RIGHT); -	if (err < 0) { -		dev_dbg(i8k_hwmon_dev, -			"Not creating %s fan attributes (%d)\n", "right", err); -	} else { -		err = device_create_file(i8k_hwmon_dev, -					 &sensor_dev_attr_fan2_input.dev_attr); -		if (err) -			goto exit_remove_files; -		err = device_create_file(i8k_hwmon_dev, -					 &sensor_dev_attr_fan2_label.dev_attr); -		if (err) -			goto exit_remove_files; -	} +	if (err >= 0) +		i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; +	i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "i8k", NULL, +							  i8k_groups); +	if (IS_ERR(i8k_hwmon_dev)) { +		err = PTR_ERR(i8k_hwmon_dev); +		i8k_hwmon_dev = NULL; +		pr_err("hwmon registration failed (%d)\n", err); +		return err; +	}  	return 0; - - exit_remove_files: -	i8k_hwmon_remove_files(i8k_hwmon_dev); - exit_unregister: -	hwmon_device_unregister(i8k_hwmon_dev); -	return err; -} - -static void __exit i8k_exit_hwmon(void) -{ -	i8k_hwmon_remove_files(i8k_hwmon_dev); -	hwmon_device_unregister(i8k_hwmon_dev);  } -static struct dmi_system_id __initdata i8k_dmi_table[] = { +static struct dmi_system_id i8k_dmi_table[] __initdata = {  	{  		.ident = "Dell Inspiron",  		.matches = { @@ -664,7 +716,30 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {  			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"),  		},  	}, -        { } +	{ +		.ident = "Dell XPS421", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +			DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"), +		}, +	}, +	{ +		.ident = "Dell Studio", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +			DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), +		}, +		.driver_data = (void *)1,	/* fan multiplier override */ +	}, +	{ +		.ident = "Dell XPS M140", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +			DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), +		}, +		.driver_data = (void *)1,	/* fan multiplier override */ +	}, +	{ }  };  /* @@ -672,8 +747,7 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {   */  static int __init i8k_probe(void)  { -	char buff[4]; -	int version; +	const struct dmi_system_id *id;  	/*  	 * Get DMI information @@ -682,49 +756,30 @@ static int __init i8k_probe(void)  		if (!ignore_dmi && !force)  			return -ENODEV; -		printk(KERN_INFO "i8k: not running on a supported Dell system.\n"); -		printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n", +		pr_info("not running on a supported Dell system.\n"); +		pr_info("vendor=%s, model=%s, version=%s\n",  			i8k_get_dmi_data(DMI_SYS_VENDOR),  			i8k_get_dmi_data(DMI_PRODUCT_NAME),  			i8k_get_dmi_data(DMI_BIOS_VERSION));  	} -	strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version)); +	strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), +		sizeof(bios_version));  	/*  	 * Get SMM Dell signature  	 */  	if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) &&  	    i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) { -		printk(KERN_ERR "i8k: unable to get SMM Dell signature\n"); +		pr_err("unable to get SMM Dell signature\n");  		if (!force)  			return -ENODEV;  	} -	/* -	 * Get SMM BIOS version. -	 */ -	version = i8k_get_bios_version(); -	if (version <= 0) { -		printk(KERN_WARNING "i8k: unable to get SMM BIOS version\n"); -	} else { -		buff[0] = (version >> 16) & 0xff; -		buff[1] = (version >> 8) & 0xff; -		buff[2] = (version) & 0xff; -		buff[3] = '\0'; -		/* -		 * If DMI BIOS version is unknown use SMM BIOS version. -		 */ -		if (!dmi_get_system_info(DMI_BIOS_VERSION)) -			strlcpy(bios_version, buff, sizeof(bios_version)); - -		/* -		 * Check if the two versions match. -		 */ -		if (strncmp(buff, bios_version, sizeof(bios_version)) != 0) -			printk(KERN_WARNING "i8k: BIOS version mismatch: %s != %s\n", -				buff, bios_version); -	} +	i8k_fan_mult = fan_mult; +	id = dmi_first_match(i8k_dmi_table); +	if (id && fan_mult == I8K_FAN_MULT && id->driver_data) +		i8k_fan_mult = (unsigned long)id->driver_data;  	return 0;  } @@ -747,10 +802,6 @@ static int __init i8k_init(void)  	if (err)  		goto exit_remove_proc; -	printk(KERN_INFO -	       "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", -	       I8K_VERSION); -  	return 0;   exit_remove_proc: @@ -760,7 +811,7 @@ static int __init i8k_init(void)  static void __exit i8k_exit(void)  { -	i8k_exit_hwmon(); +	hwmon_device_unregister(i8k_hwmon_dev);  	remove_proc_entry("i8k", NULL);  } diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index 0baa8fab4ea..db1c9b7adaa 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -50,6 +50,18 @@ config IPMI_SI  	 Currently, only KCS and SMIC are supported.  If  	 you are using IPMI, you should probably say "y" here. +config IPMI_SI_PROBE_DEFAULTS +       bool 'Probe for all possible IPMI system interfaces by default' +       default n +       depends on IPMI_SI +       help +	 Modern systems will usually expose IPMI interfaces via a discoverable +	 firmware mechanism such as ACPI or DMI. Older systems do not, and so +	 the driver is forced to probe hardware manually. This may cause boot +	 delays. Say "n" here to disable this manual probing. IPMI will then +	 only be available on older systems if the "ipmi_si_intf.trydefaults=1" +	 boot argument is passed. +  config IPMI_WATCHDOG         tristate 'IPMI Watchdog Timer'         help diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index a22a7a50274..61e71616689 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -201,7 +201,7 @@ static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)  	}  	bt->state = BT_STATE_IDLE;	/* start here */  	bt->complete = BT_STATE_IDLE;	/* end here */ -	bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * 1000000; +	bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * USEC_PER_SEC;  	bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT;  	/* BT_CAP_outreqs == zero is a flag to read BT Capabilities */  	return 3; /* We claim 3 bytes of space; ought to check SPMI table */ @@ -352,7 +352,7 @@ static inline void write_all_bytes(struct si_sm_data *bt)  static inline int read_all_bytes(struct si_sm_data *bt)  { -	unsigned char i; +	unsigned int i;  	/*  	 * length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. @@ -613,7 +613,7 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)  		HOST2BMC(42);		/* Sequence number */  		HOST2BMC(3);		/* Cmd == Soft reset */  		BT_CONTROL(BT_H2B_ATN); -		bt->timeout = BT_RESET_DELAY * 1000000; +		bt->timeout = BT_RESET_DELAY * USEC_PER_SEC;  		BT_STATE_CHANGE(BT_STATE_RESET3,  				SI_SM_CALL_WITH_DELAY); @@ -651,14 +651,14 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)  		bt_init_data(bt, bt->io);  		if ((i == 8) && !BT_CAP[2]) {  			bt->BT_CAP_outreqs = BT_CAP[3]; -			bt->BT_CAP_req2rsp = BT_CAP[6] * 1000000; +			bt->BT_CAP_req2rsp = BT_CAP[6] * USEC_PER_SEC;  			bt->BT_CAP_retries = BT_CAP[7];  		} else  			printk(KERN_WARNING "IPMI BT: using default values\n");  		if (!bt->BT_CAP_outreqs)  			bt->BT_CAP_outreqs = 1;  		printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n", -			bt->BT_CAP_req2rsp / 1000000L, bt->BT_CAP_retries); +			bt->BT_CAP_req2rsp / USEC_PER_SEC, bt->BT_CAP_retries);  		bt->timeout = bt->BT_CAP_req2rsp;  		return SI_SM_CALL_WITHOUT_DELAY; diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index e53fc24c6af..8c25f596808 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -118,8 +118,8 @@ enum kcs_states {  #define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH  /* Timeouts in microseconds. */ -#define IBF_RETRY_TIMEOUT 5000000 -#define OBF_RETRY_TIMEOUT 5000000 +#define IBF_RETRY_TIMEOUT (5*USEC_PER_SEC) +#define OBF_RETRY_TIMEOUT (5*USEC_PER_SEC)  #define MAX_ERROR_RETRIES 10  #define ERROR0_OBF_WAIT_JIFFIES (2*HZ) @@ -251,8 +251,9 @@ static inline int check_obf(struct si_sm_data *kcs, unsigned char status,  	if (!GET_STATUS_OBF(status)) {  		kcs->obf_timeout -= time;  		if (kcs->obf_timeout < 0) { -		    start_error_recovery(kcs, "OBF not ready in time"); -		    return 1; +			kcs->obf_timeout = OBF_RETRY_TIMEOUT; +			start_error_recovery(kcs, "OBF not ready in time"); +			return 1;  		}  		return 0;  	} diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index ec4e10fcf1a..e6db9381b2c 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -55,6 +55,7 @@ static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);  static int ipmi_init_msghandler(void);  static void smi_recv_tasklet(unsigned long);  static void handle_new_recv_msgs(ipmi_smi_t intf); +static void need_waiter(ipmi_smi_t intf);  static int initialized; @@ -73,14 +74,28 @@ static struct proc_dir_entry *proc_ipmi_root;   */  #define MAX_MSG_TIMEOUT		60000 +/* Call every ~1000 ms. */ +#define IPMI_TIMEOUT_TIME	1000 + +/* How many jiffies does it take to get to the timeout time. */ +#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ) / 1000) + +/* + * Request events from the queue every second (this is the number of + * IPMI_TIMEOUT_TIMES between event requests).  Hopefully, in the + * future, IPMI will add a way to know immediately if an event is in + * the queue and this silliness can go away. + */ +#define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME)) +  /*   * The main "user" data structure.   */  struct ipmi_user {  	struct list_head link; -	/* Set to "0" when the user is destroyed. */ -	int valid; +	/* Set to false when the user is destroyed. */ +	bool valid;  	struct kref refcount; @@ -92,7 +107,7 @@ struct ipmi_user {  	ipmi_smi_t intf;  	/* Does this interface receive IPMI events? */ -	int gets_events; +	bool gets_events;  };  struct cmd_rcvr { @@ -383,6 +398,9 @@ struct ipmi_smi {  	unsigned int     waiting_events_count; /* How many events in queue? */  	char             delivering_events;  	char             event_msg_printed; +	atomic_t         event_waiters; +	unsigned int     ticks_to_req_ev; +	int              last_needs_timer;  	/*  	 * The event receiver for my BMC, only really used at panic @@ -395,7 +413,7 @@ struct ipmi_smi {  	/* For handling of maintenance mode. */  	int maintenance_mode; -	int maintenance_mode_enable; +	bool maintenance_mode_enable;  	int auto_maintenance_timeout;  	spinlock_t maintenance_mode_lock; /* Used in a timer... */ @@ -451,7 +469,6 @@ static DEFINE_MUTEX(ipmi_interfaces_mutex);  static LIST_HEAD(smi_watchers);  static DEFINE_MUTEX(smi_watchers_mutex); -  #define ipmi_inc_stat(intf, stat) \  	atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat])  #define ipmi_get_stat(intf, stat) \ @@ -772,6 +789,7 @@ static int intf_next_seq(ipmi_smi_t           intf,  		*seq = i;  		*seqid = intf->seq_table[i].seqid;  		intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ; +		need_waiter(intf);  	} else {  		rv = -EAGAIN;  	} @@ -941,7 +959,7 @@ int ipmi_create_user(unsigned int          if_num,  	new_user->handler = handler;  	new_user->handler_data = handler_data;  	new_user->intf = intf; -	new_user->gets_events = 0; +	new_user->gets_events = false;  	if (!try_module_get(intf->handlers->owner)) {  		rv = -ENODEV; @@ -962,10 +980,15 @@ int ipmi_create_user(unsigned int          if_num,  	 */  	mutex_unlock(&ipmi_interfaces_mutex); -	new_user->valid = 1; +	new_user->valid = true;  	spin_lock_irqsave(&intf->seq_lock, flags);  	list_add_rcu(&new_user->link, &intf->users);  	spin_unlock_irqrestore(&intf->seq_lock, flags); +	if (handler->ipmi_watchdog_pretimeout) { +		/* User wants pretimeouts, so make sure to watch for them. */ +		if (atomic_inc_return(&intf->event_waiters) == 1) +			need_waiter(intf); +	}  	*user = new_user;  	return 0; @@ -1019,7 +1042,13 @@ int ipmi_destroy_user(ipmi_user_t user)  	struct cmd_rcvr  *rcvr;  	struct cmd_rcvr  *rcvrs = NULL; -	user->valid = 0; +	user->valid = false; + +	if (user->handler->ipmi_watchdog_pretimeout) +		atomic_dec(&intf->event_waiters); + +	if (user->gets_events) +		atomic_dec(&intf->event_waiters);  	/* Remove the user from the interface's sequence table. */  	spin_lock_irqsave(&intf->seq_lock, flags); @@ -1155,25 +1184,23 @@ int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)  	if (intf->maintenance_mode != mode) {  		switch (mode) {  		case IPMI_MAINTENANCE_MODE_AUTO: -			intf->maintenance_mode = mode;  			intf->maintenance_mode_enable  				= (intf->auto_maintenance_timeout > 0);  			break;  		case IPMI_MAINTENANCE_MODE_OFF: -			intf->maintenance_mode = mode; -			intf->maintenance_mode_enable = 0; +			intf->maintenance_mode_enable = false;  			break;  		case IPMI_MAINTENANCE_MODE_ON: -			intf->maintenance_mode = mode; -			intf->maintenance_mode_enable = 1; +			intf->maintenance_mode_enable = true;  			break;  		default:  			rv = -EINVAL;  			goto out_unlock;  		} +		intf->maintenance_mode = mode;  		maintenance_mode_update(intf);  	} @@ -1184,7 +1211,7 @@ int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)  }  EXPORT_SYMBOL(ipmi_set_maintenance_mode); -int ipmi_set_gets_events(ipmi_user_t user, int val) +int ipmi_set_gets_events(ipmi_user_t user, bool val)  {  	unsigned long        flags;  	ipmi_smi_t           intf = user->intf; @@ -1194,8 +1221,18 @@ int ipmi_set_gets_events(ipmi_user_t user, int val)  	INIT_LIST_HEAD(&msgs);  	spin_lock_irqsave(&intf->events_lock, flags); +	if (user->gets_events == val) +		goto out; +  	user->gets_events = val; +	if (val) { +		if (atomic_inc_return(&intf->event_waiters) == 1) +			need_waiter(intf); +	} else { +		atomic_dec(&intf->event_waiters); +	} +  	if (intf->delivering_events)  		/*  		 * Another thread is delivering events for this, so @@ -1289,6 +1326,9 @@ int ipmi_register_for_cmd(ipmi_user_t   user,  		goto out_unlock;  	} +	if (atomic_inc_return(&intf->event_waiters) == 1) +		need_waiter(intf); +  	list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);   out_unlock: @@ -1330,6 +1370,7 @@ int ipmi_unregister_for_cmd(ipmi_user_t   user,  	mutex_unlock(&intf->cmd_rcvrs_mutex);  	synchronize_rcu();  	while (rcvrs) { +		atomic_dec(&intf->event_waiters);  		rcvr = rcvrs;  		rcvrs = rcvr->next;  		kfree(rcvr); @@ -1535,7 +1576,7 @@ static int i_ipmi_request(ipmi_user_t          user,  				= IPMI_MAINTENANCE_MODE_TIMEOUT;  			if (!intf->maintenance_mode  			    && !intf->maintenance_mode_enable) { -				intf->maintenance_mode_enable = 1; +				intf->maintenance_mode_enable = true;  				maintenance_mode_update(intf);  			}  			spin_unlock_irqrestore(&intf->maintenance_mode_lock, @@ -2876,6 +2917,8 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,  		     (unsigned long) intf);  	atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0);  	spin_lock_init(&intf->events_lock); +	atomic_set(&intf->event_waiters, 0); +	intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME;  	INIT_LIST_HEAD(&intf->waiting_events);  	intf->waiting_events_count = 0;  	mutex_init(&intf->cmd_rcvrs_mutex); @@ -3965,7 +4008,8 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,  static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,  			      struct list_head *timeouts, long timeout_period, -			      int slot, unsigned long *flags) +			      int slot, unsigned long *flags, +			      unsigned int *waiting_msgs)  {  	struct ipmi_recv_msg     *msg;  	struct ipmi_smi_handlers *handlers; @@ -3977,8 +4021,10 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,  		return;  	ent->timeout -= timeout_period; -	if (ent->timeout > 0) +	if (ent->timeout > 0) { +		(*waiting_msgs)++;  		return; +	}  	if (ent->retries_left == 0) {  		/* The message has used all its retries. */ @@ -3995,6 +4041,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,  		struct ipmi_smi_msg *smi_msg;  		/* More retries, send again. */ +		(*waiting_msgs)++; +  		/*  		 * Start with the max timer, set to normal timer after  		 * the message is sent. @@ -4040,117 +4088,118 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,  	}  } -static void ipmi_timeout_handler(long timeout_period) +static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, long timeout_period)  { -	ipmi_smi_t           intf;  	struct list_head     timeouts;  	struct ipmi_recv_msg *msg, *msg2;  	unsigned long        flags;  	int                  i; +	unsigned int         waiting_msgs = 0; -	rcu_read_lock(); -	list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { -		tasklet_schedule(&intf->recv_tasklet); - -		/* -		 * Go through the seq table and find any messages that -		 * have timed out, putting them in the timeouts -		 * list. -		 */ -		INIT_LIST_HEAD(&timeouts); -		spin_lock_irqsave(&intf->seq_lock, flags); -		for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) -			check_msg_timeout(intf, &(intf->seq_table[i]), -					  &timeouts, timeout_period, i, -					  &flags); -		spin_unlock_irqrestore(&intf->seq_lock, flags); +	/* +	 * Go through the seq table and find any messages that +	 * have timed out, putting them in the timeouts +	 * list. +	 */ +	INIT_LIST_HEAD(&timeouts); +	spin_lock_irqsave(&intf->seq_lock, flags); +	for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) +		check_msg_timeout(intf, &(intf->seq_table[i]), +				  &timeouts, timeout_period, i, +				  &flags, &waiting_msgs); +	spin_unlock_irqrestore(&intf->seq_lock, flags); -		list_for_each_entry_safe(msg, msg2, &timeouts, link) -			deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE); +	list_for_each_entry_safe(msg, msg2, &timeouts, link) +		deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE); -		/* -		 * Maintenance mode handling.  Check the timeout -		 * optimistically before we claim the lock.  It may -		 * mean a timeout gets missed occasionally, but that -		 * only means the timeout gets extended by one period -		 * in that case.  No big deal, and it avoids the lock -		 * most of the time. -		 */ +	/* +	 * Maintenance mode handling.  Check the timeout +	 * optimistically before we claim the lock.  It may +	 * mean a timeout gets missed occasionally, but that +	 * only means the timeout gets extended by one period +	 * in that case.  No big deal, and it avoids the lock +	 * most of the time. +	 */ +	if (intf->auto_maintenance_timeout > 0) { +		spin_lock_irqsave(&intf->maintenance_mode_lock, flags);  		if (intf->auto_maintenance_timeout > 0) { -			spin_lock_irqsave(&intf->maintenance_mode_lock, flags); -			if (intf->auto_maintenance_timeout > 0) { -				intf->auto_maintenance_timeout -					-= timeout_period; -				if (!intf->maintenance_mode -				    && (intf->auto_maintenance_timeout <= 0)) { -					intf->maintenance_mode_enable = 0; -					maintenance_mode_update(intf); -				} +			intf->auto_maintenance_timeout +				-= timeout_period; +			if (!intf->maintenance_mode +			    && (intf->auto_maintenance_timeout <= 0)) { +				intf->maintenance_mode_enable = false; +				maintenance_mode_update(intf);  			} -			spin_unlock_irqrestore(&intf->maintenance_mode_lock, -					       flags);  		} +		spin_unlock_irqrestore(&intf->maintenance_mode_lock, +				       flags);  	} -	rcu_read_unlock(); + +	tasklet_schedule(&intf->recv_tasklet); + +	return waiting_msgs;  } -static void ipmi_request_event(void) +static void ipmi_request_event(ipmi_smi_t intf)  { -	ipmi_smi_t               intf;  	struct ipmi_smi_handlers *handlers; -	rcu_read_lock(); -	/* -	 * Called from the timer, no need to check if handlers is -	 * valid. -	 */ -	list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { -		/* No event requests when in maintenance mode. */ -		if (intf->maintenance_mode_enable) -			continue; +	/* No event requests when in maintenance mode. */ +	if (intf->maintenance_mode_enable) +		return; -		handlers = intf->handlers; -		if (handlers) -			handlers->request_events(intf->send_info); -	} -	rcu_read_unlock(); +	handlers = intf->handlers; +	if (handlers) +		handlers->request_events(intf->send_info);  }  static struct timer_list ipmi_timer; -/* Call every ~1000 ms. */ -#define IPMI_TIMEOUT_TIME	1000 - -/* How many jiffies does it take to get to the timeout time. */ -#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ) / 1000) - -/* - * Request events from the queue every second (this is the number of - * IPMI_TIMEOUT_TIMES between event requests).  Hopefully, in the - * future, IPMI will add a way to know immediately if an event is in - * the queue and this silliness can go away. - */ -#define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME)) -  static atomic_t stop_operation; -static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;  static void ipmi_timeout(unsigned long data)  { +	ipmi_smi_t intf; +	int nt = 0; +  	if (atomic_read(&stop_operation))  		return; -	ticks_to_req_ev--; -	if (ticks_to_req_ev == 0) { -		ipmi_request_event(); -		ticks_to_req_ev = IPMI_REQUEST_EV_TIME; -	} +	rcu_read_lock(); +	list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { +		int lnt = 0; + +		if (atomic_read(&intf->event_waiters)) { +			intf->ticks_to_req_ev--; +			if (intf->ticks_to_req_ev == 0) { +				ipmi_request_event(intf); +				intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME; +			} +			lnt++; +		} -	ipmi_timeout_handler(IPMI_TIMEOUT_TIME); +		lnt += ipmi_timeout_handler(intf, IPMI_TIMEOUT_TIME); -	mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); +		lnt = !!lnt; +		if (lnt != intf->last_needs_timer && +					intf->handlers->set_need_watch) +			intf->handlers->set_need_watch(intf->send_info, lnt); +		intf->last_needs_timer = lnt; + +		nt += lnt; +	} +	rcu_read_unlock(); + +	if (nt) +		mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);  } +static void need_waiter(ipmi_smi_t intf) +{ +	/* Racy, but worst case we start the timer twice. */ +	if (!timer_pending(&ipmi_timer)) +		mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); +}  static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);  static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 15e4a603193..5d665680ae3 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -61,7 +61,6 @@  #include <linux/ipmi_smi.h>  #include <asm/io.h>  #include "ipmi_si_sm.h" -#include <linux/init.h>  #include <linux/dmi.h>  #include <linux/string.h>  #include <linux/ctype.h> @@ -218,7 +217,7 @@ struct smi_info {  	unsigned char       msg_flags;  	/* Does the BMC have an event buffer? */ -	char		    has_event_buffer; +	bool		    has_event_buffer;  	/*  	 * If set to true, this will request events the next time the @@ -231,7 +230,7 @@ struct smi_info {  	 * call.  Generally used after a panic to make sure stuff goes  	 * out.  	 */ -	int                 run_to_completion; +	bool                run_to_completion;  	/* The I/O port of an SI interface. */  	int                 port; @@ -249,19 +248,25 @@ struct smi_info {  	/* The timer for this si. */  	struct timer_list   si_timer; +	/* This flag is set, if the timer is running (timer_pending() isn't enough) */ +	bool		    timer_running; +  	/* The time (in jiffies) the last timeout occurred at. */  	unsigned long       last_timeout_jiffies;  	/* Used to gracefully stop the timer without race conditions. */  	atomic_t            stop_operation; +	/* Are we waiting for the events, pretimeouts, received msgs? */ +	atomic_t            need_watch; +  	/*  	 * The driver will disable interrupts when it gets into a  	 * situation where it cannot handle messages due to lack of  	 * memory.  Once that situation clears up, it will re-enable  	 * interrupts.  	 */ -	int interrupt_disabled; +	bool interrupt_disabled;  	/* From the get device id response... */  	struct ipmi_device_id device_id; @@ -274,7 +279,7 @@ struct smi_info {  	 * True if we allocated the device, false if it came from  	 * someplace else (like PCI).  	 */ -	int dev_registered; +	bool dev_registered;  	/* Slave address, could be reported from DMI. */  	unsigned char slave_addr; @@ -298,19 +303,19 @@ struct smi_info {  static int force_kipmid[SI_MAX_PARMS];  static int num_force_kipmid;  #ifdef CONFIG_PCI -static int pci_registered; +static bool pci_registered;  #endif  #ifdef CONFIG_ACPI -static int pnp_registered; +static bool pnp_registered;  #endif  #ifdef CONFIG_PARISC -static int parisc_registered; +static bool parisc_registered;  #endif  static unsigned int kipmid_max_busy_us[SI_MAX_PARMS];  static int num_max_busy_us; -static int unload_when_empty = 1; +static bool unload_when_empty = true;  static int add_smi(struct smi_info *smi);  static int try_smi_init(struct smi_info *smi); @@ -435,6 +440,13 @@ static void start_clear_flags(struct smi_info *smi_info)  	smi_info->si_state = SI_CLEARING_FLAGS;  } +static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) +{ +	smi_info->last_timeout_jiffies = jiffies; +	mod_timer(&smi_info->si_timer, new_val); +	smi_info->timer_running = true; +} +  /*   * When we have a situtaion where we run out of memory and cannot   * allocate messages, we just leave them in the BMC and run the system @@ -445,10 +457,9 @@ static inline void disable_si_irq(struct smi_info *smi_info)  {  	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {  		start_disable_irq(smi_info); -		smi_info->interrupt_disabled = 1; +		smi_info->interrupt_disabled = true;  		if (!atomic_read(&smi_info->stop_operation)) -			mod_timer(&smi_info->si_timer, -				  jiffies + SI_TIMEOUT_JIFFIES); +			smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);  	}  } @@ -456,7 +467,7 @@ static inline void enable_si_irq(struct smi_info *smi_info)  {  	if ((smi_info->irq) && (smi_info->interrupt_disabled)) {  		start_enable_irq(smi_info); -		smi_info->interrupt_disabled = 0; +		smi_info->interrupt_disabled = false;  	}  } @@ -701,7 +712,7 @@ static void handle_transaction_done(struct smi_info *smi_info)  			dev_warn(smi_info->dev,  				 "Maybe ok, but ipmi might run very slowly.\n");  		} else -			smi_info->interrupt_disabled = 0; +			smi_info->interrupt_disabled = false;  		smi_info->si_state = SI_NORMAL;  		break;  	} @@ -854,6 +865,19 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,  	return si_sm_result;  } +static void check_start_timer_thread(struct smi_info *smi_info) +{ +	if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) { +		smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES); + +		if (smi_info->thread) +			wake_up_process(smi_info->thread); + +		start_next_msg(smi_info); +		smi_event_handler(smi_info, 0); +	} +} +  static void sender(void                *send_info,  		   struct ipmi_smi_msg *msg,  		   int                 priority) @@ -907,27 +931,11 @@ static void sender(void                *send_info,  	else  		list_add_tail(&msg->link, &smi_info->xmit_msgs); -	if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) { -		/* -		 * last_timeout_jiffies is updated here to avoid -		 * smi_timeout() handler passing very large time_diff -		 * value to smi_event_handler() that causes -		 * the send command to abort. -		 */ -		smi_info->last_timeout_jiffies = jiffies; - -		mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES); - -		if (smi_info->thread) -			wake_up_process(smi_info->thread); - -		start_next_msg(smi_info); -		smi_event_handler(smi_info, 0); -	} +	check_start_timer_thread(smi_info);  	spin_unlock_irqrestore(&smi_info->si_lock, flags);  } -static void set_run_to_completion(void *send_info, int i_run_to_completion) +static void set_run_to_completion(void *send_info, bool i_run_to_completion)  {  	struct smi_info   *smi_info = send_info;  	enum si_sm_result result; @@ -999,12 +1007,23 @@ static int ipmi_thread(void *data)  	struct timespec busy_until;  	ipmi_si_set_not_busy(&busy_until); -	set_user_nice(current, 19); +	set_user_nice(current, MAX_NICE);  	while (!kthread_should_stop()) {  		int busy_wait;  		spin_lock_irqsave(&(smi_info->si_lock), flags);  		smi_result = smi_event_handler(smi_info, 0); + +		/* +		 * If the driver is doing something, there is a possible +		 * race with the timer.  If the timer handler see idle, +		 * and the thread here sees something else, the timer +		 * handler won't restart the timer even though it is +		 * required.  So start it here if necessary. +		 */ +		if (smi_result != SI_SM_IDLE && !smi_info->timer_running) +			smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES); +  		spin_unlock_irqrestore(&(smi_info->si_lock), flags);  		busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,  						  &busy_until); @@ -1012,9 +1031,15 @@ static int ipmi_thread(void *data)  			; /* do nothing */  		else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)  			schedule(); -		else if (smi_result == SI_SM_IDLE) -			schedule_timeout_interruptible(100); -		else +		else if (smi_result == SI_SM_IDLE) { +			if (atomic_read(&smi_info->need_watch)) { +				schedule_timeout_interruptible(100); +			} else { +				/* Wait to be woken up when we are needed. */ +				__set_current_state(TASK_INTERRUPTIBLE); +				schedule(); +			} +		} else  			schedule_timeout_interruptible(1);  	}  	return 0; @@ -1025,7 +1050,7 @@ static void poll(void *send_info)  {  	struct smi_info *smi_info = send_info;  	unsigned long flags = 0; -	int run_to_completion = smi_info->run_to_completion; +	bool run_to_completion = smi_info->run_to_completion;  	/*  	 * Make sure there is some delay in the poll loop so we can @@ -1050,6 +1075,17 @@ static void request_events(void *send_info)  	atomic_set(&smi_info->req_events, 1);  } +static void set_need_watch(void *send_info, bool enable) +{ +	struct smi_info *smi_info = send_info; +	unsigned long flags; + +	atomic_set(&smi_info->need_watch, enable); +	spin_lock_irqsave(&smi_info->si_lock, flags); +	check_start_timer_thread(smi_info); +	spin_unlock_irqrestore(&smi_info->si_lock, flags); +} +  static int initialized;  static void smi_timeout(unsigned long data) @@ -1074,10 +1110,6 @@ static void smi_timeout(unsigned long data)  		     * SI_USEC_PER_JIFFY);  	smi_result = smi_event_handler(smi_info, time_diff); -	spin_unlock_irqrestore(&(smi_info->si_lock), flags); - -	smi_info->last_timeout_jiffies = jiffies_now; -  	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {  		/* Running with interrupts, only do long timeouts. */  		timeout = jiffies + SI_TIMEOUT_JIFFIES; @@ -1099,7 +1131,10 @@ static void smi_timeout(unsigned long data)   do_mod_timer:  	if (smi_result != SI_SM_IDLE) -		mod_timer(&(smi_info->si_timer), timeout); +		smi_mod_timer(smi_info, timeout); +	else +		smi_info->timer_running = false; +	spin_unlock_irqrestore(&(smi_info->si_lock), flags);  }  static irqreturn_t si_irq_handler(int irq, void *data) @@ -1147,8 +1182,7 @@ static int smi_start_processing(void       *send_info,  	/* Set up the timer that drives the interface. */  	setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); -	new_smi->last_timeout_jiffies = jiffies; -	mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES); +	smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);  	/*  	 * Check if the user forcefully enabled the daemon. @@ -1189,7 +1223,7 @@ static int get_smi_info(void *send_info, struct ipmi_smi_info *data)  	return 0;  } -static void set_maintenance_mode(void *send_info, int enable) +static void set_maintenance_mode(void *send_info, bool enable)  {  	struct smi_info   *smi_info = send_info; @@ -1203,6 +1237,7 @@ static struct ipmi_smi_handlers handlers = {  	.get_smi_info		= get_smi_info,  	.sender			= sender,  	.request_events		= request_events, +	.set_need_watch		= set_need_watch,  	.set_maintenance_mode   = set_maintenance_mode,  	.set_run_to_completion  = set_run_to_completion,  	.poll			= poll, @@ -1230,7 +1265,7 @@ static bool          si_tryplatform = 1;  #ifdef CONFIG_PCI  static bool          si_trypci = 1;  #endif -static bool          si_trydefaults = 1; +static bool          si_trydefaults = IS_ENABLED(CONFIG_IPMI_SI_PROBE_DEFAULTS);  static char          *si_type[SI_MAX_PARMS];  #define MAX_SI_TYPE_STR 30  static char          si_type_str[MAX_SI_TYPE_STR]; @@ -1329,7 +1364,7 @@ module_param_array(force_kipmid, int, &num_force_kipmid, 0);  MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or"  		 " disabled(0).  Normally the IPMI driver auto-detects"  		 " this, but the value may be overridden by this parm."); -module_param(unload_when_empty, int, 0); +module_param(unload_when_empty, bool, 0);  MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are"  		 " specified or found, default is 1.  Setting to 0"  		 " is useful for hot add of devices using hotmod."); @@ -1358,7 +1393,7 @@ static int std_irq_setup(struct smi_info *info)  	if (info->si_type == SI_BT) {  		rv = request_irq(info->irq,  				 si_bt_irq_handler, -				 IRQF_SHARED | IRQF_DISABLED, +				 IRQF_SHARED,  				 DEVICE_NAME,  				 info);  		if (!rv) @@ -1368,7 +1403,7 @@ static int std_irq_setup(struct smi_info *info)  	} else  		rv = request_irq(info->irq,  				 si_irq_handler, -				 IRQF_SHARED | IRQF_DISABLED, +				 IRQF_SHARED,  				 DEVICE_NAME,  				 info);  	if (rv) { @@ -1849,11 +1884,15 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)  				info->irq_setup = std_irq_setup;  			info->slave_addr = ipmb; -			if (!add_smi(info)) { -				if (try_smi_init(info)) -					cleanup_one_si(info); -			} else { +			rv = add_smi(info); +			if (rv) {  				kfree(info); +				goto out; +			} +			rv = try_smi_init(info); +			if (rv) { +				cleanup_one_si(info); +				goto out;  			}  		} else {  			/* remove */ @@ -2067,6 +2106,7 @@ struct SPMITable {  static int try_init_spmi(struct SPMITable *spmi)  {  	struct smi_info  *info; +	int rv;  	if (spmi->IPMIlegacy != 1) {  		printk(KERN_INFO PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy); @@ -2141,10 +2181,11 @@ static int try_init_spmi(struct SPMITable *spmi)  		 info->io.addr_data, info->io.regsize, info->io.regspacing,  		 info->irq); -	if (add_smi(info)) +	rv = add_smi(info); +	if (rv)  		kfree(info); -	return 0; +	return rv;  }  static void spmi_find_bmc(void) @@ -2178,6 +2219,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,  	acpi_handle handle;  	acpi_status status;  	unsigned long long tmp; +	int rv;  	acpi_dev = pnp_acpi_device(dev);  	if (!acpi_dev) @@ -2259,10 +2301,11 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,  		 res, info->io.regsize, info->io.regspacing,  		 info->irq); -	if (add_smi(info)) -		goto err_free; +	rv = add_smi(info); +	if (rv) +		kfree(info); -	return 0; +	return rv;  err_free:  	kfree(info); @@ -2566,16 +2609,20 @@ static int ipmi_pci_probe(struct pci_dev *pdev,  		&pdev->resource[0], info->io.regsize, info->io.regspacing,  		info->irq); -	if (add_smi(info)) +	rv = add_smi(info); +	if (rv) {  		kfree(info); +		pci_disable_device(pdev); +	} -	return 0; +	return rv;  }  static void ipmi_pci_remove(struct pci_dev *pdev)  {  	struct smi_info *info = pci_get_drvdata(pdev);  	cleanup_one_si(info); +	pci_disable_device(pdev);  }  static struct pci_device_id ipmi_pci_devices[] = { @@ -2670,9 +2717,10 @@ static int ipmi_probe(struct platform_device *dev)  	dev_set_drvdata(&dev->dev, info); -	if (add_smi(info)) { +	ret = add_smi(info); +	if (ret) {  		kfree(info); -		return -EBUSY; +		return ret;  	}  #endif  	return 0; @@ -2711,6 +2759,7 @@ static struct platform_driver ipmi_driver = {  static int ipmi_parisc_probe(struct parisc_device *dev)  {  	struct smi_info *info; +	int rv;  	info = smi_info_alloc(); @@ -2736,9 +2785,10 @@ static int ipmi_parisc_probe(struct parisc_device *dev)  	dev_set_drvdata(&dev->dev, info); -	if (add_smi(info)) { +	rv = add_smi(info); +	if (rv) {  		kfree(info); -		return -EBUSY; +		return rv;  	}  	return 0; @@ -2773,7 +2823,7 @@ static int wait_for_msg_done(struct smi_info *smi_info)  		    smi_result == SI_SM_CALL_WITH_TICK_DELAY) {  			schedule_timeout_uninterruptible(1);  			smi_result = smi_info->handlers->event( -				smi_info->si_sm, 100); +				smi_info->si_sm, jiffies_to_usecs(1));  		} else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {  			smi_result = smi_info->handlers->event(  				smi_info->si_sm, 0); @@ -3322,18 +3372,19 @@ static int try_smi_init(struct smi_info *new_smi)  	INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));  	new_smi->curr_msg = NULL;  	atomic_set(&new_smi->req_events, 0); -	new_smi->run_to_completion = 0; +	new_smi->run_to_completion = false;  	for (i = 0; i < SI_NUM_STATS; i++)  		atomic_set(&new_smi->stats[i], 0); -	new_smi->interrupt_disabled = 1; +	new_smi->interrupt_disabled = true;  	atomic_set(&new_smi->stop_operation, 0); +	atomic_set(&new_smi->need_watch, 0);  	new_smi->intf_num = smi_num;  	smi_num++;  	rv = try_enable_event_buffer(new_smi);  	if (rv == 0) -		new_smi->has_event_buffer = 1; +		new_smi->has_event_buffer = true;  	/*  	 * Start clearing the flags before we enable interrupts or the @@ -3367,7 +3418,7 @@ static int try_smi_init(struct smi_info *new_smi)  			       rv);  			goto out_err;  		} -		new_smi->dev_registered = 1; +		new_smi->dev_registered = true;  	}  	rv = ipmi_register_smi(&handlers, @@ -3416,7 +3467,7 @@ static int try_smi_init(struct smi_info *new_smi)  	wait_for_timer_and_thread(new_smi);   out_err: -	new_smi->interrupt_disabled = 1; +	new_smi->interrupt_disabled = true;  	if (new_smi->intf) {  		ipmi_unregister_smi(new_smi->intf); @@ -3452,7 +3503,7 @@ static int try_smi_init(struct smi_info *new_smi)  	if (new_smi->dev_registered) {  		platform_device_unregister(new_smi->pdev); -		new_smi->dev_registered = 0; +		new_smi->dev_registered = false;  	}  	return rv; @@ -3507,14 +3558,14 @@ static int init_ipmi_si(void)  			printk(KERN_ERR PFX "Unable to register "  			       "PCI driver: %d\n", rv);  		else -			pci_registered = 1; +			pci_registered = true;  	}  #endif  #ifdef CONFIG_ACPI  	if (si_tryacpi) {  		pnp_register_driver(&ipmi_pnp_driver); -		pnp_registered = 1; +		pnp_registered = true;  	}  #endif @@ -3530,7 +3581,7 @@ static int init_ipmi_si(void)  #ifdef CONFIG_PARISC  	register_parisc_driver(&ipmi_parisc_driver); -	parisc_registered = 1; +	parisc_registered = true;  	/* poking PC IO addresses will crash machine, don't do it */  	si_trydefaults = 0;  #endif diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index faed9297190..c8e77afa8b9 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -80,7 +80,7 @@ enum smic_states {  #define SMIC_MAX_ERROR_RETRIES 3  /* Timeouts in microseconds. */ -#define SMIC_RETRY_TIMEOUT 2000000 +#define SMIC_RETRY_TIMEOUT (2*USEC_PER_SEC)  /* SMIC Flags Register Bits */  #define SMIC_RX_DATA_READY	0x80 diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 0913d79424d..c4094c4e22c 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -587,6 +587,8 @@ static int lp_do_ioctl(unsigned int minor, unsigned int cmd,  		return -ENODEV;  	switch ( cmd ) {  		case LPTIME: +			if (arg > UINT_MAX / HZ) +				return -EINVAL;  			LP_TIME(minor) = arg * HZ/100;  			break;  		case LPCHAR: diff --git a/drivers/char/mem.c b/drivers/char/mem.c index f895a8c8a24..917403fe10d 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -22,7 +22,6 @@  #include <linux/device.h>  #include <linux/highmem.h>  #include <linux/backing-dev.h> -#include <linux/bootmem.h>  #include <linux/splice.h>  #include <linux/pfn.h>  #include <linux/export.h> @@ -100,6 +99,9 @@ static ssize_t read_mem(struct file *file, char __user *buf,  	ssize_t read, sz;  	char *ptr; +	if (p != *ppos) +		return 0; +  	if (!valid_phys_addr_range(p, count))  		return -EFAULT;  	read = 0; @@ -158,6 +160,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf,  	unsigned long copied;  	void *ptr; +	if (p != *ppos) +		return -EFBIG; +  	if (!valid_phys_addr_range(p, count))  		return -EFAULT; diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 190d4423653..ffa97d261cf 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -114,7 +114,7 @@ static int misc_open(struct inode * inode, struct file * file)  	int minor = iminor(inode);  	struct miscdevice *c;  	int err = -ENODEV; -	const struct file_operations *old_fops, *new_fops = NULL; +	const struct file_operations *new_fops = NULL;  	mutex_lock(&misc_mtx); @@ -141,17 +141,11 @@ static int misc_open(struct inode * inode, struct file * file)  	}  	err = 0; -	old_fops = file->f_op; -	file->f_op = new_fops; +	replace_fops(file, new_fops);  	if (file->f_op->open) {  		file->private_data = c; -		err=file->f_op->open(inode,file); -		if (err) { -			fops_put(file->f_op); -			file->f_op = fops_get(old_fops); -		} +		err = file->f_op->open(inode,file);  	} -	fops_put(old_fops);  fail:  	mutex_unlock(&misc_mtx);  	return err; @@ -193,8 +187,8 @@ int misc_register(struct miscdevice * misc)  	if (misc->minor == MISC_DYNAMIC_MINOR) {  		int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);  		if (i >= DYNAMIC_MINORS) { -			mutex_unlock(&misc_mtx); -			return -EBUSY; +			err = -EBUSY; +			goto out;  		}  		misc->minor = DYNAMIC_MINORS - i - 1;  		set_bit(i, misc_minors); @@ -203,8 +197,8 @@ int misc_register(struct miscdevice * misc)  		list_for_each_entry(c, &misc_list, list) {  			if (c->minor == misc->minor) { -				mutex_unlock(&misc_mtx); -				return -EBUSY; +				err = -EBUSY; +				goto out;  			}  		}  	} diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c index 8eca55deb3a..ba82a06d968 100644 --- a/drivers/char/msm_smd_pkt.c +++ b/drivers/char/msm_smd_pkt.c @@ -182,7 +182,7 @@ static int smd_pkt_write(struct file *file, const char __user *buf,  	if (count > MAX_BUF_SIZE)  		return -EINVAL; -	DBG("writting %d bytes\n", count); +	DBG("writing %d bytes\n", count);  	smd_pkt_devp = file->private_data;  	if (!smd_pkt_devp || !smd_pkt_devp->ch) diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c index 881c9e59593..28740046bc8 100644 --- a/drivers/char/mwave/3780i.c +++ b/drivers/char/mwave/3780i.c @@ -50,7 +50,6 @@  #include <linux/unistd.h>  #include <linux/delay.h>  #include <linux/ioport.h> -#include <linux/init.h>  #include <linux/bitops.h>  #include <linux/sched.h>	/* cond_resched() */ diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index cfdfe493c6a..76c490fa051 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -168,7 +168,10 @@ static irqreturn_t button_handler (int irq, void *dev_id)  static int button_read (struct file *filp, char __user *buffer,  			size_t count, loff_t *ppos)  { -	interruptible_sleep_on (&button_wait_queue); +	DEFINE_WAIT(wait); +	prepare_to_wait(&button_wait_queue, &wait, TASK_INTERRUPTIBLE); +	schedule(); +	finish_wait(&button_wait_queue, &wait);  	return (copy_to_user (buffer, &button_output_buffer, bcount))  		 ? -EFAULT : bcount;  } @@ -220,7 +223,7 @@ static int __init nwbutton_init(void)  		return -EBUSY;  	} -	if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, IRQF_DISABLED, +	if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, 0,  			"nwbutton", NULL)) {  		printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n",  				IRQ_NETWINDER_BUTTON); diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig index b27f5342fe7..8d3dfb0c8a2 100644 --- a/drivers/char/pcmcia/Kconfig +++ b/drivers/char/pcmcia/Kconfig @@ -15,7 +15,7 @@ config SYNCLINK_CS  	  This driver may be built as a module ( = code which can be  	  inserted in and removed from the running kernel whenever you want). -	  The module will be called synclinkmp.  If you want to do that, say M +	  The module will be called synclink_cs.  If you want to do that, say M  	  here.  config CARDMAN_4000 diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index d39cca659a3..8320abd1ef1 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2511,8 +2511,8 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)  	/* If port is closing, signal caller to try again */  	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING){ -		if (port->flags & ASYNC_CLOSING) -			interruptible_sleep_on(&port->close_wait); +		wait_event_interruptible_tty(tty, port->close_wait, +					     !(port->flags & ASYNC_CLOSING));  		retval = ((port->flags & ASYNC_HUP_NOTIFY) ?  			-EAGAIN : -ERESTARTSYS);  		goto cleanup; diff --git a/drivers/char/random.c b/drivers/char/random.c index 7737b5bd26a..71529e196b8 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -255,6 +255,7 @@  #include <linux/fips.h>  #include <linux/ptrace.h>  #include <linux/kmemcheck.h> +#include <linux/workqueue.h>  #include <linux/irq.h>  #include <asm/processor.h> @@ -269,126 +270,132 @@  /*   * Configuration information   */ -#define INPUT_POOL_WORDS 128 -#define OUTPUT_POOL_WORDS 32 -#define SEC_XFER_SIZE 512 -#define EXTRACT_SIZE 10 +#define INPUT_POOL_SHIFT	12 +#define INPUT_POOL_WORDS	(1 << (INPUT_POOL_SHIFT-5)) +#define OUTPUT_POOL_SHIFT	10 +#define OUTPUT_POOL_WORDS	(1 << (OUTPUT_POOL_SHIFT-5)) +#define SEC_XFER_SIZE		512 +#define EXTRACT_SIZE		10 + +#define DEBUG_RANDOM_BOOT 0  #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long))  /* + * To allow fractional bits to be tracked, the entropy_count field is + * denominated in units of 1/8th bits. + * + * 2*(ENTROPY_SHIFT + log2(poolbits)) must <= 31, or the multiply in + * credit_entropy_bits() needs to be 64 bits wide. + */ +#define ENTROPY_SHIFT 3 +#define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT) + +/*   * The minimum number of bits of entropy before we wake up a read on   * /dev/random.  Should be enough to do a significant reseed.   */ -static int random_read_wakeup_thresh = 64; +static int random_read_wakeup_bits = 64;  /*   * If the entropy count falls under this number of bits, then we   * should wake up processes which are selecting or polling on write   * access to /dev/random.   */ -static int random_write_wakeup_thresh = 128; +static int random_write_wakeup_bits = 28 * OUTPUT_POOL_WORDS;  /* - * When the input pool goes over trickle_thresh, start dropping most - * samples to avoid wasting CPU time and reduce lock contention. + * The minimum number of seconds between urandom pool reseeding.  We + * do this to limit the amount of entropy that can be drained from the + * input pool even if there are heavy demands on /dev/urandom.   */ - -static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; - -static DEFINE_PER_CPU(int, trickle_count); +static int random_min_urandom_seed = 60;  /* - * A pool of size .poolwords is stirred with a primitive polynomial - * of degree .poolwords over GF(2).  The taps for various sizes are - * defined below.  They are chosen to be evenly spaced (minimum RMS - * distance from evenly spaced; the numbers in the comments are a - * scaled squared error sum) except for the last tap, which is 1 to - * get the twisting happening as fast as possible. + * Originally, we used a primitive polynomial of degree .poolwords + * over GF(2).  The taps for various sizes are defined below.  They + * were chosen to be evenly spaced except for the last tap, which is 1 + * to get the twisting happening as fast as possible. + * + * For the purposes of better mixing, we use the CRC-32 polynomial as + * well to make a (modified) twisted Generalized Feedback Shift + * Register.  (See M. Matsumoto & Y. Kurita, 1992.  Twisted GFSR + * generators.  ACM Transactions on Modeling and Computer Simulation + * 2(3):179-194.  Also see M. Matsumoto & Y. Kurita, 1994.  Twisted + * GFSR generators II.  ACM Transactions on Modeling and Computer + * Simulation 4:254-266) + * + * Thanks to Colin Plumb for suggesting this. + * + * The mixing operation is much less sensitive than the output hash, + * where we use SHA-1.  All that we want of mixing operation is that + * it be a good non-cryptographic hash; i.e. it not produce collisions + * when fed "random" data of the sort we expect to see.  As long as + * the pool state differs for different inputs, we have preserved the + * input entropy and done a good job.  The fact that an intelligent + * attacker can construct inputs that will produce controlled + * alterations to the pool's state is not important because we don't + * consider such inputs to contribute any randomness.  The only + * property we need with respect to them is that the attacker can't + * increase his/her knowledge of the pool's state.  Since all + * additions are reversible (knowing the final state and the input, + * you can reconstruct the initial state), if an attacker has any + * uncertainty about the initial state, he/she can only shuffle that + * uncertainty about, but never cause any collisions (which would + * decrease the uncertainty). + * + * Our mixing functions were analyzed by Lacharme, Roeck, Strubel, and + * Videau in their paper, "The Linux Pseudorandom Number Generator + * Revisited" (see: http://eprint.iacr.org/2012/251.pdf).  In their + * paper, they point out that we are not using a true Twisted GFSR, + * since Matsumoto & Kurita used a trinomial feedback polynomial (that + * is, with only three taps, instead of the six that we are using). + * As a result, the resulting polynomial is neither primitive nor + * irreducible, and hence does not have a maximal period over + * GF(2**32).  They suggest a slight change to the generator + * polynomial which improves the resulting TGFSR polynomial to be + * irreducible, which we have made here.   */  static struct poolinfo { -	int poolwords; +	int poolbitshift, poolwords, poolbytes, poolbits, poolfracbits; +#define S(x) ilog2(x)+5, (x), (x)*4, (x)*32, (x) << (ENTROPY_SHIFT+5)  	int tap1, tap2, tap3, tap4, tap5;  } poolinfo_table[] = { -	/* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ -	{ 128,	103,	76,	51,	25,	1 }, -	/* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ -	{ 32,	26,	20,	14,	7,	1 }, +	/* was: x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 */ +	/* x^128 + x^104 + x^76 + x^51 +x^25 + x + 1 */ +	{ S(128),	104,	76,	51,	25,	1 }, +	/* was: x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 */ +	/* x^32 + x^26 + x^19 + x^14 + x^7 + x + 1 */ +	{ S(32),	26,	19,	14,	7,	1 },  #if 0  	/* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1  -- 115 */ -	{ 2048,	1638,	1231,	819,	411,	1 }, +	{ S(2048),	1638,	1231,	819,	411,	1 },  	/* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ -	{ 1024,	817,	615,	412,	204,	1 }, +	{ S(1024),	817,	615,	412,	204,	1 },  	/* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ -	{ 1024,	819,	616,	410,	207,	2 }, +	{ S(1024),	819,	616,	410,	207,	2 },  	/* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ -	{ 512,	411,	308,	208,	104,	1 }, +	{ S(512),	411,	308,	208,	104,	1 },  	/* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ -	{ 512,	409,	307,	206,	102,	2 }, +	{ S(512),	409,	307,	206,	102,	2 },  	/* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ -	{ 512,	409,	309,	205,	103,	2 }, +	{ S(512),	409,	309,	205,	103,	2 },  	/* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ -	{ 256,	205,	155,	101,	52,	1 }, +	{ S(256),	205,	155,	101,	52,	1 },  	/* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ -	{ 128,	103,	78,	51,	27,	2 }, +	{ S(128),	103,	78,	51,	27,	2 },  	/* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ -	{ 64,	52,	39,	26,	14,	1 }, +	{ S(64),	52,	39,	26,	14,	1 },  #endif  }; -#define POOLBITS	poolwords*32 -#define POOLBYTES	poolwords*4 - -/* - * For the purposes of better mixing, we use the CRC-32 polynomial as - * well to make a twisted Generalized Feedback Shift Reigster - * - * (See M. Matsumoto & Y. Kurita, 1992.  Twisted GFSR generators.  ACM - * Transactions on Modeling and Computer Simulation 2(3):179-194. - * Also see M. Matsumoto & Y. Kurita, 1994.  Twisted GFSR generators - * II.  ACM Transactions on Mdeling and Computer Simulation 4:254-266) - * - * Thanks to Colin Plumb for suggesting this. - * - * We have not analyzed the resultant polynomial to prove it primitive; - * in fact it almost certainly isn't.  Nonetheless, the irreducible factors - * of a random large-degree polynomial over GF(2) are more than large enough - * that periodicity is not a concern. - * - * The input hash is much less sensitive than the output hash.  All - * that we want of it is that it be a good non-cryptographic hash; - * i.e. it not produce collisions when fed "random" data of the sort - * we expect to see.  As long as the pool state differs for different - * inputs, we have preserved the input entropy and done a good job. - * The fact that an intelligent attacker can construct inputs that - * will produce controlled alterations to the pool's state is not - * important because we don't consider such inputs to contribute any - * randomness.  The only property we need with respect to them is that - * the attacker can't increase his/her knowledge of the pool's state. - * Since all additions are reversible (knowing the final state and the - * input, you can reconstruct the initial state), if an attacker has - * any uncertainty about the initial state, he/she can only shuffle - * that uncertainty about, but never cause any collisions (which would - * decrease the uncertainty). - * - * The chosen system lets the state of the pool be (essentially) the input - * modulo the generator polymnomial.  Now, for random primitive polynomials, - * this is a universal class of hash functions, meaning that the chance - * of a collision is limited by the attacker's knowledge of the generator - * polynomail, so if it is chosen at random, an attacker can never force - * a collision.  Here, we use a fixed polynomial, but we *can* assume that - * ###--> it is unknown to the processes generating the input entropy. <-### - * Because of this important property, this is a good, collision-resistant - * hash; hash collisions will occur no more often than chance. - */ -  /*   * Static global variables   */ @@ -396,17 +403,6 @@ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);  static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);  static struct fasync_struct *fasync; -static bool debug; -module_param(debug, bool, 0644); -#define DEBUG_ENT(fmt, arg...) do { \ -	if (debug) \ -		printk(KERN_DEBUG "random %04d %04d %04d: " \ -		fmt,\ -		input_pool.entropy_count,\ -		blocking_pool.entropy_count,\ -		nonblocking_pool.entropy_count,\ -		## arg); } while (0) -  /**********************************************************************   *   * OS independent entropy store.   Here are the functions which handle @@ -417,23 +413,26 @@ module_param(debug, bool, 0644);  struct entropy_store;  struct entropy_store {  	/* read-only data: */ -	struct poolinfo *poolinfo; +	const struct poolinfo *poolinfo;  	__u32 *pool;  	const char *name;  	struct entropy_store *pull; -	int limit; +	struct work_struct push_work;  	/* read-write data: */ +	unsigned long last_pulled;  	spinlock_t lock; -	unsigned add_ptr; -	unsigned input_rotate; +	unsigned short add_ptr; +	unsigned short input_rotate;  	int entropy_count;  	int entropy_total;  	unsigned int initialized:1; -	bool last_data_init; +	unsigned int limit:1; +	unsigned int last_data_init:1;  	__u8 last_data[EXTRACT_SIZE];  }; +static void push_to_pool(struct work_struct *work);  static __u32 input_pool_data[INPUT_POOL_WORDS];  static __u32 blocking_pool_data[OUTPUT_POOL_WORDS];  static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; @@ -452,7 +451,9 @@ static struct entropy_store blocking_pool = {  	.limit = 1,  	.pull = &input_pool,  	.lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock), -	.pool = blocking_pool_data +	.pool = blocking_pool_data, +	.push_work = __WORK_INITIALIZER(blocking_pool.push_work, +					push_to_pool),  };  static struct entropy_store nonblocking_pool = { @@ -460,7 +461,9 @@ static struct entropy_store nonblocking_pool = {  	.name = "nonblocking",  	.pull = &input_pool,  	.lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock), -	.pool = nonblocking_pool_data +	.pool = nonblocking_pool_data, +	.push_work = __WORK_INITIALIZER(nonblocking_pool.push_work, +					push_to_pool),  };  static __u32 const twist_table[8] = { @@ -498,7 +501,7 @@ static void _mix_pool_bytes(struct entropy_store *r, const void *in,  	/* mix one byte at a time to simplify size handling and churn faster */  	while (nbytes--) { -		w = rol32(*bytes++, input_rotate & 31); +		w = rol32(*bytes++, input_rotate);  		i = (i - 1) & wordmask;  		/* XOR in the various taps */ @@ -518,7 +521,7 @@ static void _mix_pool_bytes(struct entropy_store *r, const void *in,  		 * rotation, so that successive passes spread the  		 * input bits across the pool evenly.  		 */ -		input_rotate += i ? 7 : 14; +		input_rotate = (input_rotate + (i ? 7 : 14)) & 31;  	}  	ACCESS_ONCE(r->input_rotate) = input_rotate; @@ -561,62 +564,151 @@ struct fast_pool {   * collector.  It's hardcoded for an 128 bit pool and assumes that any   * locks that might be needed are taken by the caller.   */ -static void fast_mix(struct fast_pool *f, const void *in, int nbytes) +static void fast_mix(struct fast_pool *f, __u32 input[4])  { -	const char	*bytes = in;  	__u32		w; -	unsigned	i = f->count;  	unsigned	input_rotate = f->rotate; -	while (nbytes--) { -		w = rol32(*bytes++, input_rotate & 31) ^ f->pool[i & 3] ^ -			f->pool[(i + 1) & 3]; -		f->pool[i & 3] = (w >> 3) ^ twist_table[w & 7]; -		input_rotate += (i++ & 3) ? 7 : 14; -	} -	f->count = i; +	w = rol32(input[0], input_rotate) ^ f->pool[0] ^ f->pool[3]; +	f->pool[0] = (w >> 3) ^ twist_table[w & 7]; +	input_rotate = (input_rotate + 14) & 31; +	w = rol32(input[1], input_rotate) ^ f->pool[1] ^ f->pool[0]; +	f->pool[1] = (w >> 3) ^ twist_table[w & 7]; +	input_rotate = (input_rotate + 7) & 31; +	w = rol32(input[2], input_rotate) ^ f->pool[2] ^ f->pool[1]; +	f->pool[2] = (w >> 3) ^ twist_table[w & 7]; +	input_rotate = (input_rotate + 7) & 31; +	w = rol32(input[3], input_rotate) ^ f->pool[3] ^ f->pool[2]; +	f->pool[3] = (w >> 3) ^ twist_table[w & 7]; +	input_rotate = (input_rotate + 7) & 31; +  	f->rotate = input_rotate; +	f->count++;  }  /* - * Credit (or debit) the entropy store with n bits of entropy + * Credit (or debit) the entropy store with n bits of entropy. + * Use credit_entropy_bits_safe() if the value comes from userspace + * or otherwise should be checked for extreme values.   */  static void credit_entropy_bits(struct entropy_store *r, int nbits)  {  	int entropy_count, orig; +	const int pool_size = r->poolinfo->poolfracbits; +	int nfrac = nbits << ENTROPY_SHIFT;  	if (!nbits)  		return; -	DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name);  retry:  	entropy_count = orig = ACCESS_ONCE(r->entropy_count); -	entropy_count += nbits; +	if (nfrac < 0) { +		/* Debit */ +		entropy_count += nfrac; +	} else { +		/* +		 * Credit: we have to account for the possibility of +		 * overwriting already present entropy.	 Even in the +		 * ideal case of pure Shannon entropy, new contributions +		 * approach the full value asymptotically: +		 * +		 * entropy <- entropy + (pool_size - entropy) * +		 *	(1 - exp(-add_entropy/pool_size)) +		 * +		 * For add_entropy <= pool_size/2 then +		 * (1 - exp(-add_entropy/pool_size)) >= +		 *    (add_entropy/pool_size)*0.7869... +		 * so we can approximate the exponential with +		 * 3/4*add_entropy/pool_size and still be on the +		 * safe side by adding at most pool_size/2 at a time. +		 * +		 * The use of pool_size-2 in the while statement is to +		 * prevent rounding artifacts from making the loop +		 * arbitrarily long; this limits the loop to log2(pool_size)*2 +		 * turns no matter how large nbits is. +		 */ +		int pnfrac = nfrac; +		const int s = r->poolinfo->poolbitshift + ENTROPY_SHIFT + 2; +		/* The +2 corresponds to the /4 in the denominator */ + +		do { +			unsigned int anfrac = min(pnfrac, pool_size/2); +			unsigned int add = +				((pool_size - entropy_count)*anfrac*3) >> s; + +			entropy_count += add; +			pnfrac -= anfrac; +		} while (unlikely(entropy_count < pool_size-2 && pnfrac)); +	} -	if (entropy_count < 0) { -		DEBUG_ENT("negative entropy/overflow\n"); +	if (unlikely(entropy_count < 0)) { +		pr_warn("random: negative entropy/overflow: pool %s count %d\n", +			r->name, entropy_count); +		WARN_ON(1);  		entropy_count = 0; -	} else if (entropy_count > r->poolinfo->POOLBITS) -		entropy_count = r->poolinfo->POOLBITS; +	} else if (entropy_count > pool_size) +		entropy_count = pool_size;  	if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)  		goto retry; -	if (!r->initialized && nbits > 0) { -		r->entropy_total += nbits; -		if (r->entropy_total > 128) -			r->initialized = 1; +	r->entropy_total += nbits; +	if (!r->initialized && r->entropy_total > 128) { +		r->initialized = 1; +		r->entropy_total = 0; +		if (r == &nonblocking_pool) { +			prandom_reseed_late(); +			pr_notice("random: %s pool is initialized\n", r->name); +		}  	} -	trace_credit_entropy_bits(r->name, nbits, entropy_count, +	trace_credit_entropy_bits(r->name, nbits, +				  entropy_count >> ENTROPY_SHIFT,  				  r->entropy_total, _RET_IP_); -	/* should we wake readers? */ -	if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { -		wake_up_interruptible(&random_read_wait); -		kill_fasync(&fasync, SIGIO, POLL_IN); +	if (r == &input_pool) { +		int entropy_bits = entropy_count >> ENTROPY_SHIFT; + +		/* should we wake readers? */ +		if (entropy_bits >= random_read_wakeup_bits) { +			wake_up_interruptible(&random_read_wait); +			kill_fasync(&fasync, SIGIO, POLL_IN); +		} +		/* If the input pool is getting full, send some +		 * entropy to the two output pools, flipping back and +		 * forth between them, until the output pools are 75% +		 * full. +		 */ +		if (entropy_bits > random_write_wakeup_bits && +		    r->initialized && +		    r->entropy_total >= 2*random_read_wakeup_bits) { +			static struct entropy_store *last = &blocking_pool; +			struct entropy_store *other = &blocking_pool; + +			if (last == &blocking_pool) +				other = &nonblocking_pool; +			if (other->entropy_count <= +			    3 * other->poolinfo->poolfracbits / 4) +				last = other; +			if (last->entropy_count <= +			    3 * last->poolinfo->poolfracbits / 4) { +				schedule_work(&last->push_work); +				r->entropy_total = 0; +			} +		}  	}  } +static void credit_entropy_bits_safe(struct entropy_store *r, int nbits) +{ +	const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); + +	/* Cap the value to avoid overflows */ +	nbits = min(nbits,  nbits_max); +	nbits = max(nbits, -nbits_max); + +	credit_entropy_bits(r, nbits); +} +  /*********************************************************************   *   * Entropy input management @@ -630,6 +722,8 @@ struct timer_rand_state {  	unsigned dont_count_entropy:1;  }; +#define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, }; +  /*   * Add device- or boot-specific data to the input and nonblocking   * pools to help initialize them to unique values. @@ -640,16 +734,23 @@ struct timer_rand_state {   */  void add_device_randomness(const void *buf, unsigned int size)  { -	unsigned long time = get_cycles() ^ jiffies; +	unsigned long time = random_get_entropy() ^ jiffies; +	unsigned long flags; + +	trace_add_device_randomness(size, _RET_IP_); +	spin_lock_irqsave(&input_pool.lock, flags); +	_mix_pool_bytes(&input_pool, buf, size, NULL); +	_mix_pool_bytes(&input_pool, &time, sizeof(time), NULL); +	spin_unlock_irqrestore(&input_pool.lock, flags); -	mix_pool_bytes(&input_pool, buf, size, NULL); -	mix_pool_bytes(&input_pool, &time, sizeof(time), NULL); -	mix_pool_bytes(&nonblocking_pool, buf, size, NULL); -	mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL); +	spin_lock_irqsave(&nonblocking_pool.lock, flags); +	_mix_pool_bytes(&nonblocking_pool, buf, size, NULL); +	_mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL); +	spin_unlock_irqrestore(&nonblocking_pool.lock, flags);  }  EXPORT_SYMBOL(add_device_randomness); -static struct timer_rand_state input_timer_state; +static struct timer_rand_state input_timer_state = INIT_TIMER_RAND_STATE;  /*   * This function adds entropy to the entropy "pool" by using timing @@ -663,6 +764,7 @@ static struct timer_rand_state input_timer_state;   */  static void add_timer_randomness(struct timer_rand_state *state, unsigned num)  { +	struct entropy_store	*r;  	struct {  		long jiffies;  		unsigned cycles; @@ -671,15 +773,12 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)  	long delta, delta2, delta3;  	preempt_disable(); -	/* if over the trickle threshold, use only 1 in 4096 samples */ -	if (input_pool.entropy_count > trickle_thresh && -	    ((__this_cpu_inc_return(trickle_count) - 1) & 0xfff)) -		goto out;  	sample.jiffies = jiffies; -	sample.cycles = get_cycles(); +	sample.cycles = random_get_entropy();  	sample.num = num; -	mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL); +	r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool; +	mix_pool_bytes(r, &sample, sizeof(sample), NULL);  	/*  	 * Calculate number of bits of randomness we probably added. @@ -713,10 +812,8 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)  		 * Round down by 1 bit on general principles,  		 * and limit entropy entimate to 12 bits.  		 */ -		credit_entropy_bits(&input_pool, -				    min_t(int, fls(delta>>1), 11)); +		credit_entropy_bits(r, min_t(int, fls(delta>>1), 11));  	} -out:  	preempt_enable();  } @@ -729,10 +826,10 @@ void add_input_randomness(unsigned int type, unsigned int code,  	if (value == last_value)  		return; -	DEBUG_ENT("input event\n");  	last_value = value;  	add_timer_randomness(&input_timer_state,  			     (type << 4) ^ code ^ (code >> 4) ^ value); +	trace_add_input_randomness(ENTROPY_BITS(&input_pool));  }  EXPORT_SYMBOL_GPL(add_input_randomness); @@ -744,40 +841,56 @@ void add_interrupt_randomness(int irq, int irq_flags)  	struct fast_pool	*fast_pool = &__get_cpu_var(irq_randomness);  	struct pt_regs		*regs = get_irq_regs();  	unsigned long		now = jiffies; -	__u32			input[4], cycles = get_cycles(); - -	input[0] = cycles ^ jiffies; -	input[1] = irq; -	if (regs) { -		__u64 ip = instruction_pointer(regs); -		input[2] = ip; -		input[3] = ip >> 32; -	} - -	fast_mix(fast_pool, input, sizeof(input)); - -	if ((fast_pool->count & 1023) && -	    !time_after(now, fast_pool->last + HZ)) +	cycles_t		cycles = random_get_entropy(); +	__u32			input[4], c_high, j_high; +	__u64			ip; +	unsigned long		seed; +	int			credit; + +	c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0; +	j_high = (sizeof(now) > 4) ? now >> 32 : 0; +	input[0] = cycles ^ j_high ^ irq; +	input[1] = now ^ c_high; +	ip = regs ? instruction_pointer(regs) : _RET_IP_; +	input[2] = ip; +	input[3] = ip >> 32; + +	fast_mix(fast_pool, input); + +	if ((fast_pool->count & 63) && !time_after(now, fast_pool->last + HZ))  		return;  	fast_pool->last = now;  	r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;  	__mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL); +  	/*  	 * If we don't have a valid cycle counter, and we see  	 * back-to-back timer interrupts, then skip giving credit for -	 * any entropy. +	 * any entropy, otherwise credit 1 bit.  	 */ +	credit = 1;  	if (cycles == 0) {  		if (irq_flags & __IRQF_TIMER) {  			if (fast_pool->last_timer_intr) -				return; +				credit = 0;  			fast_pool->last_timer_intr = 1;  		} else  			fast_pool->last_timer_intr = 0;  	} -	credit_entropy_bits(r, 1); + +	/* +	 * If we have architectural seed generator, produce a seed and +	 * add it to the pool.  For the sake of paranoia count it as +	 * 50% entropic. +	 */ +	if (arch_get_random_seed_long(&seed)) { +		__mix_pool_bytes(r, &seed, sizeof(seed), NULL); +		credit += sizeof(seed) * 4; +	} + +	credit_entropy_bits(r, credit);  }  #ifdef CONFIG_BLOCK @@ -786,11 +899,10 @@ void add_disk_randomness(struct gendisk *disk)  	if (!disk || !disk->random)  		return;  	/* first major is 1, so we get >= 0x200 here */ -	DEBUG_ENT("disk event %d:%d\n", -		  MAJOR(disk_devt(disk)), MINOR(disk_devt(disk))); -  	add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); +	trace_add_disk_randomness(disk_devt(disk), ENTROPY_BITS(&input_pool));  } +EXPORT_SYMBOL_GPL(add_disk_randomness);  #endif  /********************************************************************* @@ -807,108 +919,142 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,   * from the primary pool to the secondary extraction pool. We make   * sure we pull enough for a 'catastrophic reseed'.   */ +static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes);  static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)  { -	__u32	tmp[OUTPUT_POOL_WORDS]; +	if (r->limit == 0 && random_min_urandom_seed) { +		unsigned long now = jiffies; -	if (r->pull && r->entropy_count < nbytes * 8 && -	    r->entropy_count < r->poolinfo->POOLBITS) { -		/* If we're limited, always leave two wakeup worth's BITS */ -		int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; -		int bytes = nbytes; - -		/* pull at least as many as BYTES as wakeup BITS */ -		bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); -		/* but never more than the buffer size */ -		bytes = min_t(int, bytes, sizeof(tmp)); - -		DEBUG_ENT("going to reseed %s with %d bits " -			  "(%zu of %d requested)\n", -			  r->name, bytes * 8, nbytes * 8, r->entropy_count); - -		bytes = extract_entropy(r->pull, tmp, bytes, -					random_read_wakeup_thresh / 8, rsvd); -		mix_pool_bytes(r, tmp, bytes, NULL); -		credit_entropy_bits(r, bytes*8); +		if (time_before(now, +				r->last_pulled + random_min_urandom_seed * HZ)) +			return; +		r->last_pulled = now;  	} +	if (r->pull && +	    r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) && +	    r->entropy_count < r->poolinfo->poolfracbits) +		_xfer_secondary_pool(r, nbytes); +} + +static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes) +{ +	__u32	tmp[OUTPUT_POOL_WORDS]; + +	/* For /dev/random's pool, always leave two wakeups' worth */ +	int rsvd_bytes = r->limit ? 0 : random_read_wakeup_bits / 4; +	int bytes = nbytes; + +	/* pull at least as much as a wakeup */ +	bytes = max_t(int, bytes, random_read_wakeup_bits / 8); +	/* but never more than the buffer size */ +	bytes = min_t(int, bytes, sizeof(tmp)); + +	trace_xfer_secondary_pool(r->name, bytes * 8, nbytes * 8, +				  ENTROPY_BITS(r), ENTROPY_BITS(r->pull)); +	bytes = extract_entropy(r->pull, tmp, bytes, +				random_read_wakeup_bits / 8, rsvd_bytes); +	mix_pool_bytes(r, tmp, bytes, NULL); +	credit_entropy_bits(r, bytes*8);  }  /* - * These functions extracts randomness from the "entropy pool", and - * returns it in a buffer. - * - * The min parameter specifies the minimum amount we can pull before - * failing to avoid races that defeat catastrophic reseeding while the - * reserved parameter indicates how much entropy we must leave in the - * pool after each pull to avoid starving other readers. - * - * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words. + * Used as a workqueue function so that when the input pool is getting + * full, we can "spill over" some entropy to the output pools.  That + * way the output pools can store some of the excess entropy instead + * of letting it go to waste.   */ +static void push_to_pool(struct work_struct *work) +{ +	struct entropy_store *r = container_of(work, struct entropy_store, +					      push_work); +	BUG_ON(!r); +	_xfer_secondary_pool(r, random_read_wakeup_bits/8); +	trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT, +			   r->pull->entropy_count >> ENTROPY_SHIFT); +} +/* + * This function decides how many bytes to actually take from the + * given pool, and also debits the entropy count accordingly. + */  static size_t account(struct entropy_store *r, size_t nbytes, int min,  		      int reserved)  { -	unsigned long flags; -	int wakeup_write = 0; - -	/* Hold lock while accounting */ -	spin_lock_irqsave(&r->lock, flags); +	int entropy_count, orig; +	size_t ibytes, nfrac; -	BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); -	DEBUG_ENT("trying to extract %zu bits from %s\n", -		  nbytes * 8, r->name); +	BUG_ON(r->entropy_count > r->poolinfo->poolfracbits);  	/* Can we pull enough? */ -	if (r->entropy_count / 8 < min + reserved) { -		nbytes = 0; -	} else { -		int entropy_count, orig;  retry: -		entropy_count = orig = ACCESS_ONCE(r->entropy_count); -		/* If limited, never pull more than available */ -		if (r->limit && nbytes + reserved >= entropy_count / 8) -			nbytes = entropy_count/8 - reserved; - -		if (entropy_count / 8 >= nbytes + reserved) { -			entropy_count -= nbytes*8; -			if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) -				goto retry; -		} else { -			entropy_count = reserved; -			if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) -				goto retry; -		} - -		if (entropy_count < random_write_wakeup_thresh) -			wakeup_write = 1; +	entropy_count = orig = ACCESS_ONCE(r->entropy_count); +	ibytes = nbytes; +	/* If limited, never pull more than available */ +	if (r->limit) { +		int have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); + +		if ((have_bytes -= reserved) < 0) +			have_bytes = 0; +		ibytes = min_t(size_t, ibytes, have_bytes);  	} +	if (ibytes < min) +		ibytes = 0; -	DEBUG_ENT("debiting %zu entropy credits from %s%s\n", -		  nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); +	if (unlikely(entropy_count < 0)) { +		pr_warn("random: negative entropy count: pool %s count %d\n", +			r->name, entropy_count); +		WARN_ON(1); +		entropy_count = 0; +	} +	nfrac = ibytes << (ENTROPY_SHIFT + 3); +	if ((size_t) entropy_count > nfrac) +		entropy_count -= nfrac; +	else +		entropy_count = 0; -	spin_unlock_irqrestore(&r->lock, flags); +	if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) +		goto retry; -	if (wakeup_write) { +	trace_debit_entropy(r->name, 8 * ibytes); +	if (ibytes && +	    (r->entropy_count >> ENTROPY_SHIFT) < random_write_wakeup_bits) {  		wake_up_interruptible(&random_write_wait);  		kill_fasync(&fasync, SIGIO, POLL_OUT);  	} -	return nbytes; +	return ibytes;  } +/* + * This function does the actual extraction for extract_entropy and + * extract_entropy_user. + * + * Note: we assume that .poolwords is a multiple of 16 words. + */  static void extract_buf(struct entropy_store *r, __u8 *out)  {  	int i;  	union {  		__u32 w[5]; -		unsigned long l[LONGS(EXTRACT_SIZE)]; +		unsigned long l[LONGS(20)];  	} hash;  	__u32 workspace[SHA_WORKSPACE_WORDS];  	__u8 extract[64];  	unsigned long flags; -	/* Generate a hash across the pool, 16 words (512 bits) at a time */ +	/* +	 * If we have an architectural hardware random number +	 * generator, use it for SHA's initial vector +	 */  	sha_init(hash.w); +	for (i = 0; i < LONGS(20); i++) { +		unsigned long v; +		if (!arch_get_random_long(&v)) +			break; +		hash.l[i] = v; +	} + +	/* Generate a hash across the pool, 16 words (512 bits) at a time */  	spin_lock_irqsave(&r->lock, flags);  	for (i = 0; i < r->poolinfo->poolwords; i += 16)  		sha_transform(hash.w, (__u8 *)(r->pool + i), workspace); @@ -942,21 +1088,19 @@ static void extract_buf(struct entropy_store *r, __u8 *out)  	hash.w[1] ^= hash.w[4];  	hash.w[2] ^= rol32(hash.w[2], 16); -	/* -	 * If we have a architectural hardware random number -	 * generator, mix that in, too. -	 */ -	for (i = 0; i < LONGS(EXTRACT_SIZE); i++) { -		unsigned long v; -		if (!arch_get_random_long(&v)) -			break; -		hash.l[i] ^= v; -	} -  	memcpy(out, &hash, EXTRACT_SIZE);  	memset(&hash, 0, sizeof(hash));  } +/* + * This function extracts randomness from the "entropy pool", and + * returns it in a buffer. + * + * The min parameter specifies the minimum amount we can pull before + * failing to avoid races that defeat catastrophic reseeding while the + * reserved parameter indicates how much entropy we must leave in the + * pool after each pull to avoid starving other readers. + */  static ssize_t extract_entropy(struct entropy_store *r, void *buf,  				 size_t nbytes, int min, int reserved)  { @@ -968,10 +1112,10 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,  	if (fips_enabled) {  		spin_lock_irqsave(&r->lock, flags);  		if (!r->last_data_init) { -			r->last_data_init = true; +			r->last_data_init = 1;  			spin_unlock_irqrestore(&r->lock, flags);  			trace_extract_entropy(r->name, EXTRACT_SIZE, -					      r->entropy_count, _RET_IP_); +					      ENTROPY_BITS(r), _RET_IP_);  			xfer_secondary_pool(r, EXTRACT_SIZE);  			extract_buf(r, tmp);  			spin_lock_irqsave(&r->lock, flags); @@ -980,7 +1124,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,  		spin_unlock_irqrestore(&r->lock, flags);  	} -	trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_); +	trace_extract_entropy(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);  	xfer_secondary_pool(r, nbytes);  	nbytes = account(r, nbytes, min, reserved); @@ -1007,13 +1151,17 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,  	return ret;  } +/* + * This function extracts randomness from the "entropy pool", and + * returns it in a userspace buffer. + */  static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,  				    size_t nbytes)  {  	ssize_t ret = 0, i;  	__u8 tmp[EXTRACT_SIZE]; -	trace_extract_entropy_user(r->name, nbytes, r->entropy_count, _RET_IP_); +	trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);  	xfer_secondary_pool(r, nbytes);  	nbytes = account(r, nbytes, 0, 0); @@ -1048,11 +1196,20 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,  /*   * This function is the exported kernel interface.  It returns some   * number of good random numbers, suitable for key generation, seeding - * TCP sequence numbers, etc.  It does not use the hw random number - * generator, if available; use get_random_bytes_arch() for that. + * TCP sequence numbers, etc.  It does not rely on the hardware random + * number generator.  For random bytes direct from the hardware RNG + * (when available), use get_random_bytes_arch().   */  void get_random_bytes(void *buf, int nbytes)  { +#if DEBUG_RANDOM_BOOT > 0 +	if (unlikely(nonblocking_pool.initialized == 0)) +		printk(KERN_NOTICE "random: %pF get_random_bytes called " +		       "with %d bits of entropy available\n", +		       (void *) _RET_IP_, +		       nonblocking_pool.entropy_total); +#endif +	trace_get_random_bytes(nbytes, _RET_IP_);  	extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);  }  EXPORT_SYMBOL(get_random_bytes); @@ -1071,7 +1228,7 @@ void get_random_bytes_arch(void *buf, int nbytes)  {  	char *p = buf; -	trace_get_random_bytes(nbytes, _RET_IP_); +	trace_get_random_bytes_arch(nbytes, _RET_IP_);  	while (nbytes) {  		unsigned long v;  		int chunk = min(nbytes, (int)sizeof(unsigned long)); @@ -1105,13 +1262,12 @@ static void init_std_data(struct entropy_store *r)  	ktime_t now = ktime_get_real();  	unsigned long rv; -	r->entropy_count = 0; -	r->entropy_total = 0; -	r->last_data_init = false; +	r->last_pulled = jiffies;  	mix_pool_bytes(r, &now, sizeof(now), NULL); -	for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) { -		if (!arch_get_random_long(&rv)) -			break; +	for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) { +		if (!arch_get_random_seed_long(&rv) && +		    !arch_get_random_long(&rv)) +			rv = random_get_entropy();  		mix_pool_bytes(r, &rv, sizeof(rv), NULL);  	}  	mix_pool_bytes(r, utsname(), sizeof(*(utsname())), NULL); @@ -1134,7 +1290,7 @@ static int rand_initialize(void)  	init_std_data(&nonblocking_pool);  	return 0;  } -module_init(rand_initialize); +early_initcall(rand_initialize);  #ifdef CONFIG_BLOCK  void rand_initialize_disk(struct gendisk *disk) @@ -1146,72 +1302,96 @@ void rand_initialize_disk(struct gendisk *disk)  	 * source.  	 */  	state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); -	if (state) +	if (state) { +		state->last_time = INITIAL_JIFFIES;  		disk->random = state; +	}  }  #endif -static ssize_t -random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +/* + * Attempt an emergency refill using arch_get_random_seed_long(). + * + * As with add_interrupt_randomness() be paranoid and only + * credit the output as 50% entropic. + */ +static int arch_random_refill(void)  { -	ssize_t n, retval = 0, count = 0; +	const unsigned int nlongs = 64;	/* Arbitrary number */ +	unsigned int n = 0; +	unsigned int i; +	unsigned long buf[nlongs]; -	if (nbytes == 0) +	if (!arch_has_random_seed())  		return 0; -	while (nbytes > 0) { -		n = nbytes; -		if (n > SEC_XFER_SIZE) -			n = SEC_XFER_SIZE; - -		DEBUG_ENT("reading %zu bits\n", n*8); - -		n = extract_entropy_user(&blocking_pool, buf, n); - -		if (n < 0) { -			retval = n; -			break; -		} +	for (i = 0; i < nlongs; i++) { +		if (arch_get_random_seed_long(&buf[n])) +			n++; +	} -		DEBUG_ENT("read got %zd bits (%zd still needed)\n", -			  n*8, (nbytes-n)*8); +	if (n) { +		unsigned int rand_bytes = n * sizeof(unsigned long); -		if (n == 0) { -			if (file->f_flags & O_NONBLOCK) { -				retval = -EAGAIN; -				break; -			} - -			DEBUG_ENT("sleeping?\n"); +		mix_pool_bytes(&input_pool, buf, rand_bytes, NULL); +		credit_entropy_bits(&input_pool, rand_bytes*4); +	} -			wait_event_interruptible(random_read_wait, -				input_pool.entropy_count >= -						 random_read_wakeup_thresh); +	return n; +} -			DEBUG_ENT("awake\n"); +static ssize_t +random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +{ +	ssize_t n; -			if (signal_pending(current)) { -				retval = -ERESTARTSYS; -				break; -			} +	if (nbytes == 0) +		return 0; +	nbytes = min_t(size_t, nbytes, SEC_XFER_SIZE); +	while (1) { +		n = extract_entropy_user(&blocking_pool, buf, nbytes); +		if (n < 0) +			return n; +		trace_random_read(n*8, (nbytes-n)*8, +				  ENTROPY_BITS(&blocking_pool), +				  ENTROPY_BITS(&input_pool)); +		if (n > 0) +			return n; + +		/* Pool is (near) empty.  Maybe wait and retry. */ + +		/* First try an emergency refill */ +		if (arch_random_refill())  			continue; -		} -		count += n; -		buf += n; -		nbytes -= n; -		break;		/* This break makes the device work */ -				/* like a named pipe */ -	} +		if (file->f_flags & O_NONBLOCK) +			return -EAGAIN; -	return (count ? count : retval); +		wait_event_interruptible(random_read_wait, +			ENTROPY_BITS(&input_pool) >= +			random_read_wakeup_bits); +		if (signal_pending(current)) +			return -ERESTARTSYS; +	}  }  static ssize_t  urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)  { -	return extract_entropy_user(&nonblocking_pool, buf, nbytes); +	int ret; + +	if (unlikely(nonblocking_pool.initialized == 0)) +		printk_once(KERN_NOTICE "random: %s urandom read " +			    "with %d bits of entropy available\n", +			    current->comm, nonblocking_pool.entropy_total); + +	nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3)); +	ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); + +	trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), +			   ENTROPY_BITS(&input_pool)); +	return ret;  }  static unsigned int @@ -1222,9 +1402,9 @@ random_poll(struct file *file, poll_table * wait)  	poll_wait(file, &random_read_wait, wait);  	poll_wait(file, &random_write_wait, wait);  	mask = 0; -	if (input_pool.entropy_count >= random_read_wakeup_thresh) +	if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits)  		mask |= POLLIN | POLLRDNORM; -	if (input_pool.entropy_count < random_write_wakeup_thresh) +	if (ENTROPY_BITS(&input_pool) < random_write_wakeup_bits)  		mask |= POLLOUT | POLLWRNORM;  	return mask;  } @@ -1275,7 +1455,8 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)  	switch (cmd) {  	case RNDGETENTCNT:  		/* inherently racy, no point locking */ -		if (put_user(input_pool.entropy_count, p)) +		ent_count = ENTROPY_BITS(&input_pool); +		if (put_user(ent_count, p))  			return -EFAULT;  		return 0;  	case RNDADDTOENTCNT: @@ -1283,7 +1464,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)  			return -EPERM;  		if (get_user(ent_count, p))  			return -EFAULT; -		credit_entropy_bits(&input_pool, ent_count); +		credit_entropy_bits_safe(&input_pool, ent_count);  		return 0;  	case RNDADDENTROPY:  		if (!capable(CAP_SYS_ADMIN)) @@ -1298,14 +1479,19 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)  				    size);  		if (retval < 0)  			return retval; -		credit_entropy_bits(&input_pool, ent_count); +		credit_entropy_bits_safe(&input_pool, ent_count);  		return 0;  	case RNDZAPENTCNT:  	case RNDCLEARPOOL: -		/* Clear the entropy pool counters. */ +		/* +		 * Clear the entropy pool counters. We no longer clear +		 * the entropy pool, as that's silly. +		 */  		if (!capable(CAP_SYS_ADMIN))  			return -EPERM; -		rand_initialize(); +		input_pool.entropy_count = 0; +		nonblocking_pool.entropy_count = 0; +		blocking_pool.entropy_count = 0;  		return 0;  	default:  		return -EINVAL; @@ -1365,18 +1551,18 @@ EXPORT_SYMBOL(generate_random_uuid);  #include <linux/sysctl.h>  static int min_read_thresh = 8, min_write_thresh; -static int max_read_thresh = INPUT_POOL_WORDS * 32; +static int max_read_thresh = OUTPUT_POOL_WORDS * 32;  static int max_write_thresh = INPUT_POOL_WORDS * 32;  static char sysctl_bootid[16];  /* - * These functions is used to return both the bootid UUID, and random + * This function is used to return both the bootid UUID, and random   * UUID.  The difference is in whether table->data is NULL; if it is,   * then a new UUID is generated and returned to the user.   * - * If the user accesses this via the proc interface, it will be returned - * as an ASCII string in the standard UUID format.  If accesses via the - * sysctl system call, it is returned as 16 bytes of binary data. + * If the user accesses this via the proc interface, the UUID will be + * returned as an ASCII string in the standard UUID format; if via the + * sysctl system call, as 16 bytes of binary data.   */  static int proc_do_uuid(struct ctl_table *table, int write,  			void __user *buffer, size_t *lenp, loff_t *ppos) @@ -1405,6 +1591,23 @@ static int proc_do_uuid(struct ctl_table *table, int write,  	return proc_dostring(&fake_table, write, buffer, lenp, ppos);  } +/* + * Return entropy available scaled to integral bits + */ +static int proc_do_entropy(struct ctl_table *table, int write, +			   void __user *buffer, size_t *lenp, loff_t *ppos) +{ +	struct ctl_table fake_table; +	int entropy_count; + +	entropy_count = *(int *)table->data >> ENTROPY_SHIFT; + +	fake_table.data = &entropy_count; +	fake_table.maxlen = sizeof(entropy_count); + +	return proc_dointvec(&fake_table, write, buffer, lenp, ppos); +} +  static int sysctl_poolsize = INPUT_POOL_WORDS * 32;  extern struct ctl_table random_table[];  struct ctl_table random_table[] = { @@ -1419,12 +1622,12 @@ struct ctl_table random_table[] = {  		.procname	= "entropy_avail",  		.maxlen		= sizeof(int),  		.mode		= 0444, -		.proc_handler	= proc_dointvec, +		.proc_handler	= proc_do_entropy,  		.data		= &input_pool.entropy_count,  	},  	{  		.procname	= "read_wakeup_threshold", -		.data		= &random_read_wakeup_thresh, +		.data		= &random_read_wakeup_bits,  		.maxlen		= sizeof(int),  		.mode		= 0644,  		.proc_handler	= proc_dointvec_minmax, @@ -1433,7 +1636,7 @@ struct ctl_table random_table[] = {  	},  	{  		.procname	= "write_wakeup_threshold", -		.data		= &random_write_wakeup_thresh, +		.data		= &random_write_wakeup_bits,  		.maxlen		= sizeof(int),  		.mode		= 0644,  		.proc_handler	= proc_dointvec_minmax, @@ -1441,6 +1644,13 @@ struct ctl_table random_table[] = {  		.extra2		= &max_write_thresh,  	},  	{ +		.procname	= "urandom_min_reseed_secs", +		.data		= &random_min_urandom_seed, +		.maxlen		= sizeof(int), +		.mode		= 0644, +		.proc_handler	= proc_dointvec, +	}, +	{  		.procname	= "boot_id",  		.data		= &sysctl_bootid,  		.maxlen		= 16, @@ -1459,12 +1669,11 @@ struct ctl_table random_table[] = {  static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; -static int __init random_int_secret_init(void) +int random_int_secret_init(void)  {  	get_random_bytes(random_int_secret, sizeof(random_int_secret));  	return 0;  } -late_initcall(random_int_secret_init);  /*   * Get a random word for internal kernel use only. Similar to urandom but @@ -1483,7 +1692,7 @@ unsigned int get_random_int(void)  	hash = get_cpu_var(get_random_int_hash); -	hash[0] += current->pid + jiffies + get_cycles(); +	hash[0] += current->pid + jiffies + random_get_entropy();  	md5_transform(hash, random_int_secret);  	ret = hash[0];  	put_cpu_var(get_random_int_hash); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index f3223aac4df..0102dc78860 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -190,7 +190,7 @@ static int bind_get(int number, dev_t *dev)  	struct raw_device_data *rawdev;  	struct block_device *bdev; -	if (number <= 0 || number >= MAX_RAW_MINORS) +	if (number <= 0 || number >= max_raw_minors)  		return -EINVAL;  	rawdev = &raw_devices[number]; @@ -284,10 +284,10 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,  #endif  static const struct file_operations raw_fops = { -	.read		= do_sync_read, -	.aio_read	= generic_file_aio_read, -	.write		= do_sync_write, -	.aio_write	= blkdev_aio_write, +	.read		= new_sync_read, +	.read_iter	= generic_file_read_iter, +	.write		= new_sync_write, +	.write_iter	= blkdev_write_iter,  	.fsync		= blkdev_fsync,  	.open		= raw_open,  	.release	= raw_release, diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index c0cbbd429bd..35259961cc3 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -227,7 +227,7 @@ static inline unsigned char rtc_is_updating(void)  #ifdef RTC_IRQ  /* - *	A very tiny interrupt handler. It runs with IRQF_DISABLED set, + *	A very tiny interrupt handler. It runs with interrupts disabled,   *	but there is possibility of conflicting with the set_rtc_mmss()   *	call (the rtc irq and the timer irq can easily run at the same   *	time in two different CPUs). So we need to serialize @@ -1040,8 +1040,7 @@ no_irq:  		rtc_int_handler_ptr = rtc_interrupt;  	} -	if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, -			"rtc", NULL)) { +	if (request_irq(RTC_IRQ, rtc_int_handler_ptr, 0, "rtc", NULL)) {  		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */  		rtc_has_irq = 0;  		printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 5816b39ff5a..8bab59292a0 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -108,8 +108,7 @@ scdrv_open(struct inode *inode, struct file *file)  	/* hook this subchannel up to the system controller interrupt */  	mutex_lock(&scdrv_mutex);  	rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt, -			 IRQF_SHARED | IRQF_DISABLED, -			 SYSCTL_BASENAME, sd); +			 IRQF_SHARED, SYSCTL_BASENAME, sd);  	if (rv) {  		ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);  		kfree(sd); diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index ee156948b9f..59bcefd6ec7 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -292,8 +292,7 @@ scdrv_event_init(struct sysctl_data_s *scd)  	/* hook event subchannel up to the system controller interrupt */  	rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt, -			 IRQF_SHARED | IRQF_DISABLED, -			 "system controller events", event_sd); +			 IRQF_SHARED, "system controller events", event_sd);  	if (rv) {  		printk(KERN_WARNING "%s: irq request failed (%d)\n",  		       __func__, rv); diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c index 0e506bad198..bd377472dcf 100644 --- a/drivers/char/tile-srom.c +++ b/drivers/char/tile-srom.c @@ -20,7 +20,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h> -#include <linux/init.h>  #include <linux/kernel.h>	/* printk() */  #include <linux/slab.h>		/* kmalloc() */  #include <linux/fs.h>		/* everything... */ diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index e95e0ab0bd8..100cd1de993 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -222,7 +222,7 @@ static int tlclk_open(struct inode *inode, struct file *filp)  	/* This device is wired through the FPGA IO space of the ATCA blade  	 * we can't share this IRQ */  	result = request_irq(telclk_interrupt, &tlclk_interrupt, -			     IRQF_DISABLED, "telco_clock", tlclk_interrupt); +			     0, "telco_clock", tlclk_interrupt);  	if (result == -EBUSY)  		printk(KERN_ERR "tlclk: Interrupt can't be reserved.\n");  	else diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 94c0c74434e..c54cac3f8bc 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -33,6 +33,15 @@ config TCG_TIS  	  from within Linux.  To compile this driver as a module, choose  	  M here; the module will be called tpm_tis. +config TCG_TIS_I2C_ATMEL +	tristate "TPM Interface Specification 1.2 Interface (I2C - Atmel)" +	depends on I2C +	---help--- +	  If you have an Atmel I2C TPM security chip say Yes and it will be +	  accessible from within Linux. +	  To compile this driver as a module, choose M here; the module will +	  be called tpm_tis_i2c_atmel. +  config TCG_TIS_I2C_INFINEON  	tristate "TPM Interface Specification 1.2 Interface (I2C - Infineon)"  	depends on I2C @@ -42,7 +51,17 @@ config TCG_TIS_I2C_INFINEON  	  Specification 0.20 say Yes and it will be accessible from within  	  Linux.  	  To compile this driver as a module, choose M here; the module -	  will be called tpm_tis_i2c_infineon. +	  will be called tpm_i2c_infineon. + +config TCG_TIS_I2C_NUVOTON +	tristate "TPM Interface Specification 1.2 Interface (I2C - Nuvoton)" +	depends on I2C +	---help--- +	  If you have a TPM security chip with an I2C interface from +	  Nuvoton Technology Corp. say Yes and it will be accessible +	  from within Linux. +	  To compile this driver as a module, choose M here; the module +	  will be called tpm_i2c_nuvoton.  config TCG_NSC  	tristate "National Semiconductor TPM Interface" @@ -55,7 +74,7 @@ config TCG_NSC  config TCG_ATMEL  	tristate "Atmel TPM Interface" -	depends on PPC64 || HAS_IOPORT +	depends on PPC64 || HAS_IOPORT_MAP  	---help---  	  If you have a TPM security chip from Atmel say Yes and it   	  will be accessible from within Linux.  To compile this driver  @@ -82,14 +101,14 @@ config TCG_IBMVTPM  	  as a module, choose M here; the module will be called tpm_ibmvtpm.  config TCG_ST33_I2C -        tristate "STMicroelectronics ST33 I2C TPM" -        depends on I2C -        depends on GPIOLIB -        ---help--- -        If you have a TPM security chip from STMicroelectronics working with -        an I2C bus say Yes and it will be accessible from within Linux. -        To compile this driver as a module, choose M here; the module will be -        called tpm_stm_st33_i2c. +	tristate "STMicroelectronics ST33 I2C TPM" +	depends on I2C +	depends on GPIOLIB +	---help--- +	  If you have a TPM security chip from STMicroelectronics working with +	  an I2C bus say Yes and it will be accessible from within Linux. +	  To compile this driver as a module, choose M here; the module will be +	  called tpm_stm_st33_i2c.  config TCG_XEN  	tristate "XEN TPM Interface" diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index eb41ff97d0a..4d85dd681b8 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,17 +2,20 @@  # Makefile for the kernel tpm device drivers.  #  obj-$(CONFIG_TCG_TPM) += tpm.o +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o +tpm-$(CONFIG_ACPI) += tpm_ppi.o +  ifdef CONFIG_ACPI -	obj-$(CONFIG_TCG_TPM) += tpm_bios.o -	tpm_bios-objs += tpm_eventlog.o tpm_acpi.o tpm_ppi.o +	tpm-y += tpm_eventlog.o tpm_acpi.o  else  ifdef CONFIG_TCG_IBMVTPM -	obj-$(CONFIG_TCG_TPM) += tpm_bios.o -	tpm_bios-objs += tpm_eventlog.o tpm_of.o +	tpm-y += tpm_eventlog.o tpm_of.o  endif  endif  obj-$(CONFIG_TCG_TIS) += tpm_tis.o +obj-$(CONFIG_TCG_TIS_I2C_ATMEL) += tpm_i2c_atmel.o  obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o +obj-$(CONFIG_TCG_TIS_I2C_NUVOTON) += tpm_i2c_nuvoton.o  obj-$(CONFIG_TCG_NSC) += tpm_nsc.o  obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o  obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c new file mode 100644 index 00000000000..d9b774e02a1 --- /dev/null +++ b/drivers/char/tpm/tpm-dev.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2004 IBM Corporation + * Authors: + * Leendert van Doorn <leendert@watson.ibm.com> + * Dave Safford <safford@watson.ibm.com> + * Reiner Sailer <sailer@watson.ibm.com> + * Kylene Hall <kjhall@us.ibm.com> + * + * Copyright (C) 2013 Obsidian Research Corp + * Jason Gunthorpe <jgunthorpe@obsidianresearch.com> + * + * Device file system interface to the TPM + * + * 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. + * + */ +#include <linux/miscdevice.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include "tpm.h" + +struct file_priv { +	struct tpm_chip *chip; + +	/* Data passed to and from the tpm via the read/write calls */ +	atomic_t data_pending; +	struct mutex buffer_mutex; + +	struct timer_list user_read_timer;      /* user needs to claim result */ +	struct work_struct work; + +	u8 data_buffer[TPM_BUFSIZE]; +}; + +static void user_reader_timeout(unsigned long ptr) +{ +	struct file_priv *priv = (struct file_priv *)ptr; + +	schedule_work(&priv->work); +} + +static void timeout_work(struct work_struct *work) +{ +	struct file_priv *priv = container_of(work, struct file_priv, work); + +	mutex_lock(&priv->buffer_mutex); +	atomic_set(&priv->data_pending, 0); +	memset(priv->data_buffer, 0, sizeof(priv->data_buffer)); +	mutex_unlock(&priv->buffer_mutex); +} + +static int tpm_open(struct inode *inode, struct file *file) +{ +	struct miscdevice *misc = file->private_data; +	struct tpm_chip *chip = container_of(misc, struct tpm_chip, +					     vendor.miscdev); +	struct file_priv *priv; + +	/* It's assured that the chip will be opened just once, +	 * by the check of is_open variable, which is protected +	 * by driver_lock. */ +	if (test_and_set_bit(0, &chip->is_open)) { +		dev_dbg(chip->dev, "Another process owns this TPM\n"); +		return -EBUSY; +	} + +	priv = kzalloc(sizeof(*priv), GFP_KERNEL); +	if (priv == NULL) { +		clear_bit(0, &chip->is_open); +		return -ENOMEM; +	} + +	priv->chip = chip; +	atomic_set(&priv->data_pending, 0); +	mutex_init(&priv->buffer_mutex); +	setup_timer(&priv->user_read_timer, user_reader_timeout, +			(unsigned long)priv); +	INIT_WORK(&priv->work, timeout_work); + +	file->private_data = priv; +	get_device(chip->dev); +	return 0; +} + +static ssize_t tpm_read(struct file *file, char __user *buf, +			size_t size, loff_t *off) +{ +	struct file_priv *priv = file->private_data; +	ssize_t ret_size; +	int rc; + +	del_singleshot_timer_sync(&priv->user_read_timer); +	flush_work(&priv->work); +	ret_size = atomic_read(&priv->data_pending); +	if (ret_size > 0) {	/* relay data */ +		ssize_t orig_ret_size = ret_size; +		if (size < ret_size) +			ret_size = size; + +		mutex_lock(&priv->buffer_mutex); +		rc = copy_to_user(buf, priv->data_buffer, ret_size); +		memset(priv->data_buffer, 0, orig_ret_size); +		if (rc) +			ret_size = -EFAULT; + +		mutex_unlock(&priv->buffer_mutex); +	} + +	atomic_set(&priv->data_pending, 0); + +	return ret_size; +} + +static ssize_t tpm_write(struct file *file, const char __user *buf, +			 size_t size, loff_t *off) +{ +	struct file_priv *priv = file->private_data; +	size_t in_size = size; +	ssize_t out_size; + +	/* cannot perform a write until the read has cleared +	   either via tpm_read or a user_read_timer timeout. +	   This also prevents splitted buffered writes from blocking here. +	*/ +	if (atomic_read(&priv->data_pending) != 0) +		return -EBUSY; + +	if (in_size > TPM_BUFSIZE) +		return -E2BIG; + +	mutex_lock(&priv->buffer_mutex); + +	if (copy_from_user +	    (priv->data_buffer, (void __user *) buf, in_size)) { +		mutex_unlock(&priv->buffer_mutex); +		return -EFAULT; +	} + +	/* atomic tpm command send and result receive */ +	out_size = tpm_transmit(priv->chip, priv->data_buffer, +				sizeof(priv->data_buffer)); +	if (out_size < 0) { +		mutex_unlock(&priv->buffer_mutex); +		return out_size; +	} + +	atomic_set(&priv->data_pending, out_size); +	mutex_unlock(&priv->buffer_mutex); + +	/* Set a timeout by which the reader must come claim the result */ +	mod_timer(&priv->user_read_timer, jiffies + (60 * HZ)); + +	return in_size; +} + +/* + * Called on file close + */ +static int tpm_release(struct inode *inode, struct file *file) +{ +	struct file_priv *priv = file->private_data; + +	del_singleshot_timer_sync(&priv->user_read_timer); +	flush_work(&priv->work); +	file->private_data = NULL; +	atomic_set(&priv->data_pending, 0); +	clear_bit(0, &priv->chip->is_open); +	put_device(priv->chip->dev); +	kfree(priv); +	return 0; +} + +static const struct file_operations tpm_fops = { +	.owner = THIS_MODULE, +	.llseek = no_llseek, +	.open = tpm_open, +	.read = tpm_read, +	.write = tpm_write, +	.release = tpm_release, +}; + +int tpm_dev_add_device(struct tpm_chip *chip) +{ +	int rc; + +	chip->vendor.miscdev.fops = &tpm_fops; +	if (chip->dev_num == 0) +		chip->vendor.miscdev.minor = TPM_MINOR; +	else +		chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; + +	chip->vendor.miscdev.name = chip->devname; +	chip->vendor.miscdev.parent = chip->dev; + +	rc = misc_register(&chip->vendor.miscdev); +	if (rc) { +		chip->vendor.miscdev.name = NULL; +		dev_err(chip->dev, +			"unable to misc_register %s, minor %d err=%d\n", +			chip->vendor.miscdev.name, +			chip->vendor.miscdev.minor, rc); +	} +	return rc; +} + +void tpm_dev_del_device(struct tpm_chip *chip) +{ +	if (chip->vendor.miscdev.name) +		misc_deregister(&chip->vendor.miscdev); +} diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm-interface.c index e3c974a6c52..62e10fd1e1c 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm-interface.c @@ -10,13 +10,13 @@   * Maintained by: <tpmdd-devel@lists.sourceforge.net>   *   * Device driver for TCG/TCPA TPM (trusted platform module). - * Specifications at www.trustedcomputinggroup.org	  + * Specifications at www.trustedcomputinggroup.org   *   * 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. - *  + *   * Note, the TPM chip is not interrupt driven (only polling)   * and can have very long timeouts (minutes!). Hence the unusual   * calls to msleep. @@ -32,13 +32,6 @@  #include "tpm.h"  #include "tpm_eventlog.h" -enum tpm_duration { -	TPM_SHORT = 0, -	TPM_MEDIUM = 1, -	TPM_LONG = 2, -	TPM_UNDEFINED, -}; -  #define TPM_MAX_ORDINAL 243  #define TSC_MAX_ORDINAL 12  #define TPM_PROTECTED_COMMAND 0x00 @@ -312,23 +305,6 @@ static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {  	TPM_MEDIUM,  }; -static void user_reader_timeout(unsigned long ptr) -{ -	struct tpm_chip *chip = (struct tpm_chip *) ptr; - -	schedule_work(&chip->work); -} - -static void timeout_work(struct work_struct *work) -{ -	struct tpm_chip *chip = container_of(work, struct tpm_chip, work); - -	mutex_lock(&chip->buffer_mutex); -	atomic_set(&chip->data_pending, 0); -	memset(chip->data_buffer, 0, TPM_BUFSIZE); -	mutex_unlock(&chip->buffer_mutex); -} -  /*   * Returns max number of jiffies to wait   */ @@ -355,8 +331,8 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);  /*   * Internal kernel interface to transmit TPM commands   */ -static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, -			    size_t bufsiz) +ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, +		     size_t bufsiz)  {  	ssize_t rc;  	u32 count, ordinal; @@ -371,13 +347,14 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,  		return -ENODATA;  	if (count > bufsiz) {  		dev_err(chip->dev, -			"invalid count value %x %zx \n", count, bufsiz); +			"invalid count value %x %zx\n", count, bufsiz);  		return -E2BIG;  	}  	mutex_lock(&chip->tpm_mutex); -	if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) { +	rc = chip->ops->send(chip, (u8 *) buf, count); +	if (rc < 0) {  		dev_err(chip->dev,  			"tpm_transmit: tpm_send: error %zd\n", rc);  		goto out; @@ -388,12 +365,12 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,  	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);  	do { -		u8 status = chip->vendor.status(chip); -		if ((status & chip->vendor.req_complete_mask) == -		    chip->vendor.req_complete_val) +		u8 status = chip->ops->status(chip); +		if ((status & chip->ops->req_complete_mask) == +		    chip->ops->req_complete_val)  			goto out_recv; -		if (chip->vendor.req_canceled(chip, status)) { +		if (chip->ops->req_canceled(chip, status)) {  			dev_err(chip->dev, "Operation Canceled\n");  			rc = -ECANCELED;  			goto out; @@ -403,13 +380,13 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,  		rmb();  	} while (time_before(jiffies, stop)); -	chip->vendor.cancel(chip); +	chip->ops->cancel(chip);  	dev_err(chip->dev, "Operation Timed out\n");  	rc = -ETIME;  	goto out;  out_recv: -	rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz); +	rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);  	if (rc < 0)  		dev_err(chip->dev,  			"tpm_transmit: tpm_recv: error %zd\n", rc); @@ -421,30 +398,12 @@ out:  #define TPM_DIGEST_SIZE 20  #define TPM_RET_CODE_IDX 6 -enum tpm_capabilities { -	TPM_CAP_FLAG = cpu_to_be32(4), -	TPM_CAP_PROP = cpu_to_be32(5), -	CAP_VERSION_1_1 = cpu_to_be32(0x06), -	CAP_VERSION_1_2 = cpu_to_be32(0x1A) -}; - -enum tpm_sub_capabilities { -	TPM_CAP_PROP_PCR = cpu_to_be32(0x101), -	TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103), -	TPM_CAP_FLAG_PERM = cpu_to_be32(0x108), -	TPM_CAP_FLAG_VOL = cpu_to_be32(0x109), -	TPM_CAP_PROP_OWNER = cpu_to_be32(0x111), -	TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), -	TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), - -}; -  static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,  			    int len, const char *desc)  {  	int err; -	len = tpm_transmit(chip,(u8 *) cmd, len); +	len = tpm_transmit(chip, (u8 *) cmd, len);  	if (len <  0)  		return len;  	else if (len < TPM_HEADER_SIZE) @@ -458,7 +417,6 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,  }  #define TPM_INTERNAL_RESULT_SIZE 200 -#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)  #define TPM_ORD_GET_CAP cpu_to_be32(101)  #define TPM_ORD_GET_RANDOM cpu_to_be32(70) @@ -658,70 +616,6 @@ static int tpm_continue_selftest(struct tpm_chip *chip)  	return rc;  } -ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, -			char *buf) -{ -	cap_t cap; -	ssize_t rc; - -	rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, -			 "attempting to determine the permanent enabled state"); -	if (rc) -		return 0; - -	rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); -	return rc; -} -EXPORT_SYMBOL_GPL(tpm_show_enabled); - -ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, -			char *buf) -{ -	cap_t cap; -	ssize_t rc; - -	rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, -			 "attempting to determine the permanent active state"); -	if (rc) -		return 0; - -	rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); -	return rc; -} -EXPORT_SYMBOL_GPL(tpm_show_active); - -ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, -			char *buf) -{ -	cap_t cap; -	ssize_t rc; - -	rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap, -			 "attempting to determine the owner state"); -	if (rc) -		return 0; - -	rc = sprintf(buf, "%d\n", cap.owned); -	return rc; -} -EXPORT_SYMBOL_GPL(tpm_show_owned); - -ssize_t tpm_show_temp_deactivated(struct device * dev, -				struct device_attribute * attr, char *buf) -{ -	cap_t cap; -	ssize_t rc; - -	rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap, -			 "attempting to determine the temporary state"); -	if (rc) -		return 0; - -	rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); -	return rc; -} -EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); -  /*   * tpm_chip_find_get - return tpm_chip for given chip number   */ @@ -751,7 +645,7 @@ static struct tpm_input_header pcrread_header = {  	.ordinal = TPM_ORDINAL_PCRREAD  }; -static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) +int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)  {  	int rc;  	struct tpm_cmd_t cmd; @@ -769,10 +663,10 @@ static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)  /**   * tpm_pcr_read - read a pcr value - * @chip_num: 	tpm idx # or ANY + * @chip_num:	tpm idx # or ANY   * @pcr_idx:	pcr idx to retrieve - * @res_buf: 	TPM_PCR value - * 		size of res_buf is 20 bytes (or NULL if you don't care) + * @res_buf:	TPM_PCR value + *		size of res_buf is 20 bytes (or NULL if you don't care)   *   * The TPM driver should be built-in, but for whatever reason it   * isn't, protect against the chip disappearing, by incrementing @@ -786,7 +680,7 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)  	chip = tpm_chip_find_get(chip_num);  	if (chip == NULL)  		return -ENODEV; -	rc = __tpm_pcr_read(chip, pcr_idx, res_buf); +	rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);  	tpm_chip_put(chip);  	return rc;  } @@ -794,9 +688,9 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read);  /**   * tpm_pcr_extend - extend pcr value with hash - * @chip_num: 	tpm idx # or AN& + * @chip_num:	tpm idx # or AN&   * @pcr_idx:	pcr idx to extend - * @hash: 	hash value used to extend pcr value + * @hash:	hash value used to extend pcr value   *   * The TPM driver should be built-in, but for whatever reason it   * isn't, protect against the chip disappearing, by incrementing @@ -847,8 +741,7 @@ int tpm_do_selftest(struct tpm_chip *chip)  	unsigned long duration;  	struct tpm_cmd_t cmd; -	duration = tpm_calc_ordinal_duration(chip, -	                                     TPM_ORD_CONTINUE_SELFTEST); +	duration = tpm_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST);  	loops = jiffies_to_msecs(duration) / delay_msec; @@ -911,206 +804,15 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)  }  EXPORT_SYMBOL_GPL(tpm_send); -ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, -		      char *buf) -{ -	cap_t cap; -	u8 digest[TPM_DIGEST_SIZE]; -	ssize_t rc; -	int i, j, num_pcrs; -	char *str = buf; -	struct tpm_chip *chip = dev_get_drvdata(dev); - -	rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, -			"attempting to determine the number of PCRS"); -	if (rc) -		return 0; - -	num_pcrs = be32_to_cpu(cap.num_pcrs); -	for (i = 0; i < num_pcrs; i++) { -		rc = __tpm_pcr_read(chip, i, digest); -		if (rc) -			break; -		str += sprintf(str, "PCR-%02d: ", i); -		for (j = 0; j < TPM_DIGEST_SIZE; j++) -			str += sprintf(str, "%02X ", digest[j]); -		str += sprintf(str, "\n"); -	} -	return str - buf; -} -EXPORT_SYMBOL_GPL(tpm_show_pcrs); - -#define  READ_PUBEK_RESULT_SIZE 314 -#define TPM_ORD_READPUBEK cpu_to_be32(124) -static struct tpm_input_header tpm_readpubek_header = { -	.tag = TPM_TAG_RQU_COMMAND, -	.length = cpu_to_be32(30), -	.ordinal = TPM_ORD_READPUBEK -}; - -ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, -		       char *buf) -{ -	u8 *data; -	struct tpm_cmd_t tpm_cmd; -	ssize_t err; -	int i, rc; -	char *str = buf; - -	struct tpm_chip *chip = dev_get_drvdata(dev); - -	tpm_cmd.header.in = tpm_readpubek_header; -	err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, -			"attempting to read the PUBEK"); -	if (err) -		goto out; - -	/*  -	   ignore header 10 bytes -	   algorithm 32 bits (1 == RSA ) -	   encscheme 16 bits -	   sigscheme 16 bits -	   parameters (RSA 12->bytes: keybit, #primes, expbit)   -	   keylenbytes 32 bits -	   256 byte modulus -	   ignore checksum 20 bytes -	 */ -	data = tpm_cmd.params.readpubek_out_buffer; -	str += -	    sprintf(str, -		    "Algorithm: %02X %02X %02X %02X\n" -		    "Encscheme: %02X %02X\n" -		    "Sigscheme: %02X %02X\n" -		    "Parameters: %02X %02X %02X %02X " -		    "%02X %02X %02X %02X " -		    "%02X %02X %02X %02X\n" -		    "Modulus length: %d\n" -		    "Modulus:\n", -		    data[0], data[1], data[2], data[3], -		    data[4], data[5], -		    data[6], data[7], -		    data[12], data[13], data[14], data[15], -		    data[16], data[17], data[18], data[19], -		    data[20], data[21], data[22], data[23], -		    be32_to_cpu(*((__be32 *) (data + 24)))); - -	for (i = 0; i < 256; i++) { -		str += sprintf(str, "%02X ", data[i + 28]); -		if ((i + 1) % 16 == 0) -			str += sprintf(str, "\n"); -	} -out: -	rc = str - buf; -	return rc; -} -EXPORT_SYMBOL_GPL(tpm_show_pubek); - - -ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, -		      char *buf) +static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, +					bool check_cancel, bool *canceled)  { -	cap_t cap; -	ssize_t rc; -	char *str = buf; - -	rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, -			"attempting to determine the manufacturer"); -	if (rc) -		return 0; -	str += sprintf(str, "Manufacturer: 0x%x\n", -		       be32_to_cpu(cap.manufacturer_id)); - -	rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, -		        "attempting to determine the 1.1 version"); -	if (rc) -		return 0; -	str += sprintf(str, -		       "TCG version: %d.%d\nFirmware version: %d.%d\n", -		       cap.tpm_version.Major, cap.tpm_version.Minor, -		       cap.tpm_version.revMajor, cap.tpm_version.revMinor); -	return str - buf; -} -EXPORT_SYMBOL_GPL(tpm_show_caps); - -ssize_t tpm_show_caps_1_2(struct device * dev, -			  struct device_attribute * attr, char *buf) -{ -	cap_t cap; -	ssize_t rc; -	char *str = buf; - -	rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, -			"attempting to determine the manufacturer"); -	if (rc) -		return 0; -	str += sprintf(str, "Manufacturer: 0x%x\n", -		       be32_to_cpu(cap.manufacturer_id)); -	rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, -			 "attempting to determine the 1.2 version"); -	if (rc) -		return 0; -	str += sprintf(str, -		       "TCG version: %d.%d\nFirmware version: %d.%d\n", -		       cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor, -		       cap.tpm_version_1_2.revMajor, -		       cap.tpm_version_1_2.revMinor); -	return str - buf; -} -EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); - -ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr, -			  char *buf) -{ -	struct tpm_chip *chip = dev_get_drvdata(dev); - -	if (chip->vendor.duration[TPM_LONG] == 0) -		return 0; - -	return sprintf(buf, "%d %d %d [%s]\n", -		       jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), -		       jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), -		       jiffies_to_usecs(chip->vendor.duration[TPM_LONG]), -		       chip->vendor.duration_adjusted -		       ? "adjusted" : "original"); -} -EXPORT_SYMBOL_GPL(tpm_show_durations); - -ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr, -			  char *buf) -{ -	struct tpm_chip *chip = dev_get_drvdata(dev); - -	return sprintf(buf, "%d %d %d %d [%s]\n", -		       jiffies_to_usecs(chip->vendor.timeout_a), -		       jiffies_to_usecs(chip->vendor.timeout_b), -		       jiffies_to_usecs(chip->vendor.timeout_c), -		       jiffies_to_usecs(chip->vendor.timeout_d), -		       chip->vendor.timeout_adjusted -		       ? "adjusted" : "original"); -} -EXPORT_SYMBOL_GPL(tpm_show_timeouts); - -ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, -			const char *buf, size_t count) -{ -	struct tpm_chip *chip = dev_get_drvdata(dev); -	if (chip == NULL) -		return 0; - -	chip->vendor.cancel(chip); -	return count; -} -EXPORT_SYMBOL_GPL(tpm_store_cancel); - -static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, bool check_cancel, -				   bool *canceled) -{ -	u8 status = chip->vendor.status(chip); +	u8 status = chip->ops->status(chip);  	*canceled = false;  	if ((status & mask) == mask)  		return true; -	if (check_cancel && chip->vendor.req_canceled(chip, status)) { +	if (check_cancel && chip->ops->req_canceled(chip, status)) {  		*canceled = true;  		return true;  	} @@ -1126,7 +828,7 @@ int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,  	bool canceled = false;  	/* check current status */ -	status = chip->vendor.status(chip); +	status = chip->ops->status(chip);  	if ((status & mask) == mask)  		return 0; @@ -1153,7 +855,7 @@ again:  	} else {  		do {  			msleep(TPM_TIMEOUT); -			status = chip->vendor.status(chip); +			status = chip->ops->status(chip);  			if ((status & mask) == mask)  				return 0;  		} while (time_before(jiffies, stop)); @@ -1161,140 +863,6 @@ again:  	return -ETIME;  }  EXPORT_SYMBOL_GPL(wait_for_tpm_stat); -/* - * Device file system interface to the TPM - * - * It's assured that the chip will be opened just once, - * by the check of is_open variable, which is protected - * by driver_lock. - */ -int tpm_open(struct inode *inode, struct file *file) -{ -	int minor = iminor(inode); -	struct tpm_chip *chip = NULL, *pos; - -	rcu_read_lock(); -	list_for_each_entry_rcu(pos, &tpm_chip_list, list) { -		if (pos->vendor.miscdev.minor == minor) { -			chip = pos; -			get_device(chip->dev); -			break; -		} -	} -	rcu_read_unlock(); - -	if (!chip) -		return -ENODEV; - -	if (test_and_set_bit(0, &chip->is_open)) { -		dev_dbg(chip->dev, "Another process owns this TPM\n"); -		put_device(chip->dev); -		return -EBUSY; -	} - -	chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL); -	if (chip->data_buffer == NULL) { -		clear_bit(0, &chip->is_open); -		put_device(chip->dev); -		return -ENOMEM; -	} - -	atomic_set(&chip->data_pending, 0); - -	file->private_data = chip; -	return 0; -} -EXPORT_SYMBOL_GPL(tpm_open); - -/* - * Called on file close - */ -int tpm_release(struct inode *inode, struct file *file) -{ -	struct tpm_chip *chip = file->private_data; - -	del_singleshot_timer_sync(&chip->user_read_timer); -	flush_work(&chip->work); -	file->private_data = NULL; -	atomic_set(&chip->data_pending, 0); -	kzfree(chip->data_buffer); -	clear_bit(0, &chip->is_open); -	put_device(chip->dev); -	return 0; -} -EXPORT_SYMBOL_GPL(tpm_release); - -ssize_t tpm_write(struct file *file, const char __user *buf, -		  size_t size, loff_t *off) -{ -	struct tpm_chip *chip = file->private_data; -	size_t in_size = size; -	ssize_t out_size; - -	/* cannot perform a write until the read has cleared -	   either via tpm_read or a user_read_timer timeout. -	   This also prevents splitted buffered writes from blocking here. -	*/ -	if (atomic_read(&chip->data_pending) != 0) -		return -EBUSY; - -	if (in_size > TPM_BUFSIZE) -		return -E2BIG; - -	mutex_lock(&chip->buffer_mutex); - -	if (copy_from_user -	    (chip->data_buffer, (void __user *) buf, in_size)) { -		mutex_unlock(&chip->buffer_mutex); -		return -EFAULT; -	} - -	/* atomic tpm command send and result receive */ -	out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); -	if (out_size < 0) { -		mutex_unlock(&chip->buffer_mutex); -		return out_size; -	} - -	atomic_set(&chip->data_pending, out_size); -	mutex_unlock(&chip->buffer_mutex); - -	/* Set a timeout by which the reader must come claim the result */ -	mod_timer(&chip->user_read_timer, jiffies + (60 * HZ)); - -	return in_size; -} -EXPORT_SYMBOL_GPL(tpm_write); - -ssize_t tpm_read(struct file *file, char __user *buf, -		 size_t size, loff_t *off) -{ -	struct tpm_chip *chip = file->private_data; -	ssize_t ret_size; -	int rc; - -	del_singleshot_timer_sync(&chip->user_read_timer); -	flush_work(&chip->work); -	ret_size = atomic_read(&chip->data_pending); -	if (ret_size > 0) {	/* relay data */ -		ssize_t orig_ret_size = ret_size; -		if (size < ret_size) -			ret_size = size; - -		mutex_lock(&chip->buffer_mutex); -		rc = copy_to_user(buf, chip->data_buffer, ret_size); -		memset(chip->data_buffer, 0, orig_ret_size); -		if (rc) -			ret_size = -EFAULT; - -		mutex_unlock(&chip->buffer_mutex); -	} - -	atomic_set(&chip->data_pending, 0); - -	return ret_size; -} -EXPORT_SYMBOL_GPL(tpm_read);  void tpm_remove_hardware(struct device *dev)  { @@ -1310,8 +878,8 @@ void tpm_remove_hardware(struct device *dev)  	spin_unlock(&driver_lock);  	synchronize_rcu(); -	misc_deregister(&chip->vendor.miscdev); -	sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); +	tpm_dev_del_device(chip); +	tpm_sysfs_del_device(chip);  	tpm_remove_ppi(&dev->kobj);  	tpm_bios_log_teardown(chip->bios_dir); @@ -1459,11 +1027,7 @@ void tpm_dev_vendor_release(struct tpm_chip *chip)  	if (!chip)  		return; -	if (chip->vendor.release) -		chip->vendor.release(chip->dev); -  	clear_bit(chip->dev_num, dev_mask); -	kfree(chip->vendor.miscdev.name);  }  EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); @@ -1472,7 +1036,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);   * Once all references to platform device are down to 0,   * release all allocated structures.   */ -void tpm_dev_release(struct device *dev) +static void tpm_dev_release(struct device *dev)  {  	struct tpm_chip *chip = dev_get_drvdata(dev); @@ -1484,81 +1048,56 @@ void tpm_dev_release(struct device *dev)  	chip->release(dev);  	kfree(chip);  } -EXPORT_SYMBOL_GPL(tpm_dev_release);  /* - * Called from tpm_<specific>.c probe function only for devices  + * Called from tpm_<specific>.c probe function only for devices   * the driver has determined it should claim.  Prior to calling   * this function the specific probe function has called pci_enable_device   * upon errant exit from this function specific probe function should call   * pci_disable_device   */  struct tpm_chip *tpm_register_hardware(struct device *dev, -					const struct tpm_vendor_specific *entry) +				       const struct tpm_class_ops *ops)  { -#define DEVNAME_SIZE 7 - -	char *devname;  	struct tpm_chip *chip;  	/* Driver specific per-device data */  	chip = kzalloc(sizeof(*chip), GFP_KERNEL); -	devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); -	if (chip == NULL || devname == NULL) -		goto out_free; +	if (chip == NULL) +		return NULL; -	mutex_init(&chip->buffer_mutex);  	mutex_init(&chip->tpm_mutex);  	INIT_LIST_HEAD(&chip->list); -	INIT_WORK(&chip->work, timeout_work); - -	setup_timer(&chip->user_read_timer, user_reader_timeout, -			(unsigned long)chip); - -	memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); - +	chip->ops = ops;  	chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);  	if (chip->dev_num >= TPM_NUM_DEVICES) {  		dev_err(dev, "No available tpm device numbers\n");  		goto out_free; -	} else if (chip->dev_num == 0) -		chip->vendor.miscdev.minor = TPM_MINOR; -	else -		chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; +	}  	set_bit(chip->dev_num, dev_mask); -	scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); -	chip->vendor.miscdev.name = devname; +	scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm", +		  chip->dev_num); -	chip->vendor.miscdev.parent = dev;  	chip->dev = get_device(dev);  	chip->release = dev->release;  	dev->release = tpm_dev_release;  	dev_set_drvdata(dev, chip); -	if (misc_register(&chip->vendor.miscdev)) { -		dev_err(chip->dev, -			"unable to misc_register %s, minor %d\n", -			chip->vendor.miscdev.name, -			chip->vendor.miscdev.minor); +	if (tpm_dev_add_device(chip))  		goto put_device; -	} -	if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { -		misc_deregister(&chip->vendor.miscdev); -		goto put_device; -	} +	if (tpm_sysfs_add_device(chip)) +		goto del_misc; -	if (tpm_add_ppi(&dev->kobj)) { -		misc_deregister(&chip->vendor.miscdev); -		goto put_device; -	} +	if (tpm_add_ppi(&dev->kobj)) +		goto del_misc; -	chip->bios_dir = tpm_bios_log_setup(devname); +	chip->bios_dir = tpm_bios_log_setup(chip->devname);  	/* Make chip available */  	spin_lock(&driver_lock); @@ -1567,11 +1106,12 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,  	return chip; +del_misc: +	tpm_dev_del_device(chip);  put_device:  	put_device(chip->dev);  out_free:  	kfree(chip); -	kfree(devname);  	return NULL;  }  EXPORT_SYMBOL_GPL(tpm_register_hardware); diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c new file mode 100644 index 00000000000..01730a27ae0 --- /dev/null +++ b/drivers/char/tpm/tpm-sysfs.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2004 IBM Corporation + * Authors: + * Leendert van Doorn <leendert@watson.ibm.com> + * Dave Safford <safford@watson.ibm.com> + * Reiner Sailer <sailer@watson.ibm.com> + * Kylene Hall <kjhall@us.ibm.com> + * + * Copyright (C) 2013 Obsidian Research Corp + * Jason Gunthorpe <jgunthorpe@obsidianresearch.com> + * + * sysfs filesystem inspection interface to the TPM + * + * 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. + * + */ +#include <linux/device.h> +#include "tpm.h" + +/* XXX for now this helper is duplicated in tpm-interface.c */ +static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, +			    int len, const char *desc) +{ +	int err; + +	len = tpm_transmit(chip, (u8 *) cmd, len); +	if (len <  0) +		return len; +	else if (len < TPM_HEADER_SIZE) +		return -EFAULT; + +	err = be32_to_cpu(cmd->header.out.return_code); +	if (err != 0 && desc) +		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); + +	return err; +} + +#define READ_PUBEK_RESULT_SIZE 314 +#define TPM_ORD_READPUBEK cpu_to_be32(124) +static struct tpm_input_header tpm_readpubek_header = { +	.tag = TPM_TAG_RQU_COMMAND, +	.length = cpu_to_be32(30), +	.ordinal = TPM_ORD_READPUBEK +}; +static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, +			  char *buf) +{ +	u8 *data; +	struct tpm_cmd_t tpm_cmd; +	ssize_t err; +	int i, rc; +	char *str = buf; + +	struct tpm_chip *chip = dev_get_drvdata(dev); + +	tpm_cmd.header.in = tpm_readpubek_header; +	err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, +			   "attempting to read the PUBEK"); +	if (err) +		goto out; + +	/* +	   ignore header 10 bytes +	   algorithm 32 bits (1 == RSA ) +	   encscheme 16 bits +	   sigscheme 16 bits +	   parameters (RSA 12->bytes: keybit, #primes, expbit) +	   keylenbytes 32 bits +	   256 byte modulus +	   ignore checksum 20 bytes +	 */ +	data = tpm_cmd.params.readpubek_out_buffer; +	str += +	    sprintf(str, +		    "Algorithm: %02X %02X %02X %02X\n" +		    "Encscheme: %02X %02X\n" +		    "Sigscheme: %02X %02X\n" +		    "Parameters: %02X %02X %02X %02X " +		    "%02X %02X %02X %02X " +		    "%02X %02X %02X %02X\n" +		    "Modulus length: %d\n" +		    "Modulus:\n", +		    data[0], data[1], data[2], data[3], +		    data[4], data[5], +		    data[6], data[7], +		    data[12], data[13], data[14], data[15], +		    data[16], data[17], data[18], data[19], +		    data[20], data[21], data[22], data[23], +		    be32_to_cpu(*((__be32 *) (data + 24)))); + +	for (i = 0; i < 256; i++) { +		str += sprintf(str, "%02X ", data[i + 28]); +		if ((i + 1) % 16 == 0) +			str += sprintf(str, "\n"); +	} +out: +	rc = str - buf; +	return rc; +} +static DEVICE_ATTR_RO(pubek); + +static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, +			 char *buf) +{ +	cap_t cap; +	u8 digest[TPM_DIGEST_SIZE]; +	ssize_t rc; +	int i, j, num_pcrs; +	char *str = buf; +	struct tpm_chip *chip = dev_get_drvdata(dev); + +	rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, +			"attempting to determine the number of PCRS"); +	if (rc) +		return 0; + +	num_pcrs = be32_to_cpu(cap.num_pcrs); +	for (i = 0; i < num_pcrs; i++) { +		rc = tpm_pcr_read_dev(chip, i, digest); +		if (rc) +			break; +		str += sprintf(str, "PCR-%02d: ", i); +		for (j = 0; j < TPM_DIGEST_SIZE; j++) +			str += sprintf(str, "%02X ", digest[j]); +		str += sprintf(str, "\n"); +	} +	return str - buf; +} +static DEVICE_ATTR_RO(pcrs); + +static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, +		     char *buf) +{ +	cap_t cap; +	ssize_t rc; + +	rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, +			 "attempting to determine the permanent enabled state"); +	if (rc) +		return 0; + +	rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); +	return rc; +} +static DEVICE_ATTR_RO(enabled); + +static ssize_t active_show(struct device *dev, struct device_attribute *attr, +		    char *buf) +{ +	cap_t cap; +	ssize_t rc; + +	rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, +			 "attempting to determine the permanent active state"); +	if (rc) +		return 0; + +	rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); +	return rc; +} +static DEVICE_ATTR_RO(active); + +static ssize_t owned_show(struct device *dev, struct device_attribute *attr, +			  char *buf) +{ +	cap_t cap; +	ssize_t rc; + +	rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap, +			 "attempting to determine the owner state"); +	if (rc) +		return 0; + +	rc = sprintf(buf, "%d\n", cap.owned); +	return rc; +} +static DEVICE_ATTR_RO(owned); + +static ssize_t temp_deactivated_show(struct device *dev, +				     struct device_attribute *attr, char *buf) +{ +	cap_t cap; +	ssize_t rc; + +	rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap, +			 "attempting to determine the temporary state"); +	if (rc) +		return 0; + +	rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); +	return rc; +} +static DEVICE_ATTR_RO(temp_deactivated); + +static ssize_t caps_show(struct device *dev, struct device_attribute *attr, +			 char *buf) +{ +	cap_t cap; +	ssize_t rc; +	char *str = buf; + +	rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, +			"attempting to determine the manufacturer"); +	if (rc) +		return 0; +	str += sprintf(str, "Manufacturer: 0x%x\n", +		       be32_to_cpu(cap.manufacturer_id)); + +	/* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ +	rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, +			 "attempting to determine the 1.2 version"); +	if (!rc) { +		str += sprintf(str, +			       "TCG version: %d.%d\nFirmware version: %d.%d\n", +			       cap.tpm_version_1_2.Major, +			       cap.tpm_version_1_2.Minor, +			       cap.tpm_version_1_2.revMajor, +			       cap.tpm_version_1_2.revMinor); +	} else { +		/* Otherwise just use TPM_STRUCT_VER */ +		rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, +				"attempting to determine the 1.1 version"); +		if (rc) +			return 0; +		str += sprintf(str, +			       "TCG version: %d.%d\nFirmware version: %d.%d\n", +			       cap.tpm_version.Major, +			       cap.tpm_version.Minor, +			       cap.tpm_version.revMajor, +			       cap.tpm_version.revMinor); +	} + +	return str - buf; +} +static DEVICE_ATTR_RO(caps); + +static ssize_t cancel_store(struct device *dev, struct device_attribute *attr, +			    const char *buf, size_t count) +{ +	struct tpm_chip *chip = dev_get_drvdata(dev); +	if (chip == NULL) +		return 0; + +	chip->ops->cancel(chip); +	return count; +} +static DEVICE_ATTR_WO(cancel); + +static ssize_t durations_show(struct device *dev, struct device_attribute *attr, +			      char *buf) +{ +	struct tpm_chip *chip = dev_get_drvdata(dev); + +	if (chip->vendor.duration[TPM_LONG] == 0) +		return 0; + +	return sprintf(buf, "%d %d %d [%s]\n", +		       jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), +		       jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), +		       jiffies_to_usecs(chip->vendor.duration[TPM_LONG]), +		       chip->vendor.duration_adjusted +		       ? "adjusted" : "original"); +} +static DEVICE_ATTR_RO(durations); + +static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr, +			     char *buf) +{ +	struct tpm_chip *chip = dev_get_drvdata(dev); + +	return sprintf(buf, "%d %d %d %d [%s]\n", +		       jiffies_to_usecs(chip->vendor.timeout_a), +		       jiffies_to_usecs(chip->vendor.timeout_b), +		       jiffies_to_usecs(chip->vendor.timeout_c), +		       jiffies_to_usecs(chip->vendor.timeout_d), +		       chip->vendor.timeout_adjusted +		       ? "adjusted" : "original"); +} +static DEVICE_ATTR_RO(timeouts); + +static struct attribute *tpm_dev_attrs[] = { +	&dev_attr_pubek.attr, +	&dev_attr_pcrs.attr, +	&dev_attr_enabled.attr, +	&dev_attr_active.attr, +	&dev_attr_owned.attr, +	&dev_attr_temp_deactivated.attr, +	&dev_attr_caps.attr, +	&dev_attr_cancel.attr, +	&dev_attr_durations.attr, +	&dev_attr_timeouts.attr, +	NULL, +}; + +static const struct attribute_group tpm_dev_group = { +	.attrs = tpm_dev_attrs, +}; + +int tpm_sysfs_add_device(struct tpm_chip *chip) +{ +	int err; +	err = sysfs_create_group(&chip->dev->kobj, +				 &tpm_dev_group); + +	if (err) +		dev_err(chip->dev, +			"failed to create sysfs attributes, %d\n", err); +	return err; +} + +void tpm_sysfs_del_device(struct tpm_chip *chip) +{ +	sysfs_remove_group(&chip->dev->kobj, &tpm_dev_group); +} diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index a7bfc176ed4..e4d0888d2ea 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -46,6 +46,14 @@ enum tpm_addr {  	TPM_ADDR = 0x4E,  }; +/* Indexes the duration array */ +enum tpm_duration { +	TPM_SHORT = 0, +	TPM_MEDIUM = 1, +	TPM_LONG = 2, +	TPM_UNDEFINED, +}; +  #define TPM_WARN_RETRY          0x800  #define TPM_WARN_DOING_SELFTEST 0x802  #define TPM_ERR_DEACTIVATED     0x6 @@ -53,35 +61,9 @@ enum tpm_addr {  #define TPM_ERR_INVALID_POSTINIT 38  #define TPM_HEADER_SIZE		10 -extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, -				char *); -extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, -				char *); -extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, -				char *); -extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr, -				char *); -extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, -				const char *, size_t); -extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr, -				char *); -extern ssize_t tpm_show_active(struct device *, struct device_attribute *attr, -				char *); -extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr, -				char *); -extern ssize_t tpm_show_temp_deactivated(struct device *, -					 struct device_attribute *attr, char *); -extern ssize_t tpm_show_durations(struct device *, -				  struct device_attribute *attr, char *); -extern ssize_t tpm_show_timeouts(struct device *, -				 struct device_attribute *attr, char *); -  struct tpm_chip;  struct tpm_vendor_specific { -	const u8 req_complete_mask; -	const u8 req_complete_val; -	bool (*req_canceled)(struct tpm_chip *chip, u8 status);  	void __iomem *iobase;		/* ioremapped address */  	unsigned long base;		/* TPM base address */ @@ -91,13 +73,7 @@ struct tpm_vendor_specific {  	int region_size;  	int have_region; -	int (*recv) (struct tpm_chip *, u8 *, size_t); -	int (*send) (struct tpm_chip *, u8 *, size_t); -	void (*cancel) (struct tpm_chip *); -	u8 (*status) (struct tpm_chip *); -	void (*release) (struct device *);  	struct miscdevice miscdev; -	struct attribute_group *attr_group;  	struct list_head list;  	int locality;  	unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ @@ -120,18 +96,13 @@ struct tpm_vendor_specific {  struct tpm_chip {  	struct device *dev;	/* Device stuff */ +	const struct tpm_class_ops *ops;  	int dev_num;		/* /dev/tpm# */ +	char devname[7];  	unsigned long is_open;	/* only one allowed */  	int time_expired; -	/* Data passed to and from the tpm via the read/write calls */ -	u8 *data_buffer; -	atomic_t data_pending; -	struct mutex buffer_mutex; - -	struct timer_list user_read_timer;	/* user needs to claim result */ -	struct work_struct work;  	struct mutex tpm_mutex;	/* tpm is processing */  	struct tpm_vendor_specific vendor; @@ -172,6 +143,8 @@ struct tpm_output_header {  	__be32	return_code;  } __packed; +#define TPM_TAG_RQU_COMMAND cpu_to_be16(193) +  struct	stclear_flags_t {  	__be16	tag;  	u8	deactivated; @@ -245,6 +218,24 @@ typedef union {  	struct duration_t duration;  } cap_t; +enum tpm_capabilities { +	TPM_CAP_FLAG = cpu_to_be32(4), +	TPM_CAP_PROP = cpu_to_be32(5), +	CAP_VERSION_1_1 = cpu_to_be32(0x06), +	CAP_VERSION_1_2 = cpu_to_be32(0x1A) +}; + +enum tpm_sub_capabilities { +	TPM_CAP_PROP_PCR = cpu_to_be32(0x101), +	TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103), +	TPM_CAP_FLAG_PERM = cpu_to_be32(0x108), +	TPM_CAP_FLAG_VOL = cpu_to_be32(0x109), +	TPM_CAP_PROP_OWNER = cpu_to_be32(0x111), +	TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), +	TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), + +}; +  struct	tpm_getcap_params_in {  	__be32	cap;  	__be32	subcap_size; @@ -324,25 +315,28 @@ struct tpm_cmd_t {  ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *); +ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, +		     size_t bufsiz);  extern int tpm_get_timeouts(struct tpm_chip *);  extern void tpm_gen_interrupt(struct tpm_chip *);  extern int tpm_do_selftest(struct tpm_chip *);  extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);  extern struct tpm_chip* tpm_register_hardware(struct device *, -				 const struct tpm_vendor_specific *); -extern int tpm_open(struct inode *, struct file *); -extern int tpm_release(struct inode *, struct file *); -extern void tpm_dev_release(struct device *dev); +					      const struct tpm_class_ops *ops);  extern void tpm_dev_vendor_release(struct tpm_chip *); -extern ssize_t tpm_write(struct file *, const char __user *, size_t, -			 loff_t *); -extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);  extern void tpm_remove_hardware(struct device *);  extern int tpm_pm_suspend(struct device *);  extern int tpm_pm_resume(struct device *);  extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,  			     wait_queue_head_t *, bool); +int tpm_dev_add_device(struct tpm_chip *chip); +void tpm_dev_del_device(struct tpm_chip *chip); +int tpm_sysfs_add_device(struct tpm_chip *chip); +void tpm_sysfs_del_device(struct tpm_chip *chip); + +int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); +  #ifdef CONFIG_ACPI  extern int tpm_add_ppi(struct kobject *);  extern void tpm_remove_ppi(struct kobject *); diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index 64420b3396a..565a9478cb9 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -23,7 +23,7 @@  #include <linux/security.h>  #include <linux/module.h>  #include <linux/slab.h> -#include <acpi/acpi.h> +#include <linux/acpi.h>  #include "tpm.h"  #include "tpm_eventlog.h" @@ -95,7 +95,7 @@ int read_log(struct tpm_bios_log *log)  	log->bios_event_log_end = log->bios_event_log + len; -	virt = acpi_os_map_memory(start, len); +	virt = acpi_os_map_iomem(start, len);  	if (!virt) {  		kfree(log->bios_event_log);  		printk("%s: ERROR - Unable to map memory\n", __func__); @@ -104,6 +104,6 @@ int read_log(struct tpm_bios_log *log)  	memcpy_fromio(log->bios_event_log, virt, len); -	acpi_os_unmap_memory(virt, len); +	acpi_os_unmap_iomem(virt, len);  	return 0;  } diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 99d6820c611..6069d13ae4a 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -121,31 +121,7 @@ static bool tpm_atml_req_canceled(struct tpm_chip *chip, u8 status)  	return (status == ATML_STATUS_READY);  } -static const struct file_operations atmel_ops = { -	.owner = THIS_MODULE, -	.llseek = no_llseek, -	.open = tpm_open, -	.read = tpm_read, -	.write = tpm_write, -	.release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); -static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); - -static struct attribute* atmel_attrs[] = { -	&dev_attr_pubek.attr, -	&dev_attr_pcrs.attr, -	&dev_attr_caps.attr, -	&dev_attr_cancel.attr, -	NULL, -}; - -static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; - -static const struct tpm_vendor_specific tpm_atmel = { +static const struct tpm_class_ops tpm_atmel = {  	.recv = tpm_atml_recv,  	.send = tpm_atml_send,  	.cancel = tpm_atml_cancel, @@ -153,8 +129,6 @@ static const struct tpm_vendor_specific tpm_atmel = {  	.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,  	.req_complete_val = ATML_STATUS_DATA_AVAIL,  	.req_canceled = tpm_atml_req_canceled, -	.attr_group = &atmel_attr_grp, -	.miscdev = { .fops = &atmel_ops, },  };  static struct platform_device *pdev; @@ -202,7 +176,7 @@ static int __init init_atmel(void)  	have_region =  	    (atmel_request_region -	     (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; +	     (base, region_size, "tpm_atmel0") == NULL) ? 0 : 1;  	pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0);  	if (IS_ERR(pdev)) { diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 84ddc557b8f..59f7cb28260 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -406,7 +406,6 @@ out_tpm:  out:  	return NULL;  } -EXPORT_SYMBOL_GPL(tpm_bios_log_setup);  void tpm_bios_log_teardown(struct dentry **lst)  { @@ -415,5 +414,3 @@ void tpm_bios_log_teardown(struct dentry **lst)  	for (i = 0; i < 3; i++)  		securityfs_remove(lst[i]);  } -EXPORT_SYMBOL_GPL(tpm_bios_log_teardown); -MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c new file mode 100644 index 00000000000..77272925dee --- /dev/null +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -0,0 +1,244 @@ +/* + * ATMEL I2C TPM AT97SC3204T + * + * Copyright (C) 2012 V Lab Technologies + *  Teddy Reed <teddy@prosauce.org> + * Copyright (C) 2013, Obsidian Research Corp. + *  Jason Gunthorpe <jgunthorpe@obsidianresearch.com> + * Device driver for ATMEL I2C TPMs. + * + * Teddy Reed determined the basic I2C command flow, unlike other I2C TPM + * devices the raw TCG formatted TPM command data is written via I2C and then + * raw TCG formatted TPM command data is returned via I2C. + * + * TGC status/locality/etc functions seen in the LPC implementation do not + * seem to be present. + * + * 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, see http://www.gnu.org/licenses/>. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include "tpm.h" + +#define I2C_DRIVER_NAME "tpm_i2c_atmel" + +#define TPM_I2C_SHORT_TIMEOUT  750     /* ms */ +#define TPM_I2C_LONG_TIMEOUT   2000    /* 2 sec */ + +#define ATMEL_STS_OK 1 + +struct priv_data { +	size_t len; +	/* This is the amount we read on the first try. 25 was chosen to fit a +	 * fair number of read responses in the buffer so a 2nd retry can be +	 * avoided in small message cases. */ +	u8 buffer[sizeof(struct tpm_output_header) + 25]; +}; + +static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ +	struct priv_data *priv = chip->vendor.priv; +	struct i2c_client *client = to_i2c_client(chip->dev); +	s32 status; + +	priv->len = 0; + +	if (len <= 2) +		return -EIO; + +	status = i2c_master_send(client, buf, len); + +	dev_dbg(chip->dev, +		"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__, +		(int)min_t(size_t, 64, len), buf, len, status); +	return status; +} + +static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ +	struct priv_data *priv = chip->vendor.priv; +	struct i2c_client *client = to_i2c_client(chip->dev); +	struct tpm_output_header *hdr = +		(struct tpm_output_header *)priv->buffer; +	u32 expected_len; +	int rc; + +	if (priv->len == 0) +		return -EIO; + +	/* Get the message size from the message header, if we didn't get the +	 * whole message in read_status then we need to re-read the +	 * message. */ +	expected_len = be32_to_cpu(hdr->length); +	if (expected_len > count) +		return -ENOMEM; + +	if (priv->len >= expected_len) { +		dev_dbg(chip->dev, +			"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__, +			(int)min_t(size_t, 64, expected_len), buf, count, +			expected_len); +		memcpy(buf, priv->buffer, expected_len); +		return expected_len; +	} + +	rc = i2c_master_recv(client, buf, expected_len); +	dev_dbg(chip->dev, +		"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__, +		(int)min_t(size_t, 64, expected_len), buf, count, +		expected_len); +	return rc; +} + +static void i2c_atmel_cancel(struct tpm_chip *chip) +{ +	dev_err(chip->dev, "TPM operation cancellation was requested, but is not supported"); +} + +static u8 i2c_atmel_read_status(struct tpm_chip *chip) +{ +	struct priv_data *priv = chip->vendor.priv; +	struct i2c_client *client = to_i2c_client(chip->dev); +	int rc; + +	/* The TPM fails the I2C read until it is ready, so we do the entire +	 * transfer here and buffer it locally. This way the common code can +	 * properly handle the timeouts. */ +	priv->len = 0; +	memset(priv->buffer, 0, sizeof(priv->buffer)); + + +	/* Once the TPM has completed the command the command remains readable +	 * until another command is issued. */ +	rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer)); +	dev_dbg(chip->dev, +		"%s: sts=%d", __func__, rc); +	if (rc <= 0) +		return 0; + +	priv->len = rc; + +	return ATMEL_STS_OK; +} + +static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status) +{ +	return false; +} + +static const struct tpm_class_ops i2c_atmel = { +	.status = i2c_atmel_read_status, +	.recv = i2c_atmel_recv, +	.send = i2c_atmel_send, +	.cancel = i2c_atmel_cancel, +	.req_complete_mask = ATMEL_STS_OK, +	.req_complete_val = ATMEL_STS_OK, +	.req_canceled = i2c_atmel_req_canceled, +}; + +static int i2c_atmel_probe(struct i2c_client *client, +			   const struct i2c_device_id *id) +{ +	int rc; +	struct tpm_chip *chip; +	struct device *dev = &client->dev; + +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) +		return -ENODEV; + +	chip = tpm_register_hardware(dev, &i2c_atmel); +	if (!chip) { +		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__); +		return -ENODEV; +	} + +	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), +					 GFP_KERNEL); + +	/* Default timeouts */ +	chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); +	chip->vendor.timeout_b = msecs_to_jiffies(TPM_I2C_LONG_TIMEOUT); +	chip->vendor.timeout_c = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); +	chip->vendor.timeout_d = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); +	chip->vendor.irq = 0; + +	/* There is no known way to probe for this device, and all version +	 * information seems to be read via TPM commands. Thus we rely on the +	 * TPM startup process in the common code to detect the device. */ +	if (tpm_get_timeouts(chip)) { +		rc = -ENODEV; +		goto out_err; +	} + +	if (tpm_do_selftest(chip)) { +		rc = -ENODEV; +		goto out_err; +	} + +	return 0; + +out_err: +	tpm_dev_vendor_release(chip); +	tpm_remove_hardware(chip->dev); +	return rc; +} + +static int i2c_atmel_remove(struct i2c_client *client) +{ +	struct device *dev = &(client->dev); +	struct tpm_chip *chip = dev_get_drvdata(dev); + +	if (chip) +		tpm_dev_vendor_release(chip); +	tpm_remove_hardware(dev); +	kfree(chip); +	return 0; +} + +static const struct i2c_device_id i2c_atmel_id[] = { +	{I2C_DRIVER_NAME, 0}, +	{} +}; +MODULE_DEVICE_TABLE(i2c, i2c_atmel_id); + +#ifdef CONFIG_OF +static const struct of_device_id i2c_atmel_of_match[] = { +	{.compatible = "atmel,at97sc3204t"}, +	{}, +}; +MODULE_DEVICE_TABLE(of, i2c_atmel_of_match); +#endif + +static SIMPLE_DEV_PM_OPS(i2c_atmel_pm_ops, tpm_pm_suspend, tpm_pm_resume); + +static struct i2c_driver i2c_atmel_driver = { +	.id_table = i2c_atmel_id, +	.probe = i2c_atmel_probe, +	.remove = i2c_atmel_remove, +	.driver = { +		.name = I2C_DRIVER_NAME, +		.owner = THIS_MODULE, +		.pm = &i2c_atmel_pm_ops, +		.of_match_table = of_match_ptr(i2c_atmel_of_match), +	}, +}; + +module_i2c_driver(i2c_atmel_driver); + +MODULE_AUTHOR("Jason Gunthorpe <jgunthorpe@obsidianresearch.com>"); +MODULE_DESCRIPTION("Atmel TPM I2C Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index b8735de8ce9..472af4bb1b6 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -21,7 +21,6 @@   *   *   */ -#include <linux/init.h>  #include <linux/i2c.h>  #include <linux/module.h>  #include <linux/wait.h> @@ -566,45 +565,7 @@ static bool tpm_tis_i2c_req_canceled(struct tpm_chip *chip, u8 status)  	return (status == TPM_STS_COMMAND_READY);  } -static const struct file_operations tis_ops = { -	.owner = THIS_MODULE, -	.llseek = no_llseek, -	.open = tpm_open, -	.read = tpm_read, -	.write = tpm_write, -	.release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); -static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); -static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); -static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); -static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); -static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); -static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); - -static struct attribute *tis_attrs[] = { -	&dev_attr_pubek.attr, -	&dev_attr_pcrs.attr, -	&dev_attr_enabled.attr, -	&dev_attr_active.attr, -	&dev_attr_owned.attr, -	&dev_attr_temp_deactivated.attr, -	&dev_attr_caps.attr, -	&dev_attr_cancel.attr, -	&dev_attr_durations.attr, -	&dev_attr_timeouts.attr, -	NULL, -}; - -static struct attribute_group tis_attr_grp = { -	.attrs = tis_attrs -}; - -static struct tpm_vendor_specific tpm_tis_i2c = { +static const struct tpm_class_ops tpm_tis_i2c = {  	.status = tpm_tis_i2c_status,  	.recv = tpm_tis_i2c_recv,  	.send = tpm_tis_i2c_send, @@ -612,8 +573,6 @@ static struct tpm_vendor_specific tpm_tis_i2c = {  	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,  	.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,  	.req_canceled = tpm_tis_i2c_req_canceled, -	.attr_group = &tis_attr_grp, -	.miscdev.fops = &tis_ops,  };  static int tpm_tis_i2c_init(struct device *dev) @@ -685,7 +644,6 @@ out_vendor:  	chip->dev->release = NULL;  	chip->release = NULL;  	tpm_dev.client = NULL; -	dev_set_drvdata(chip->dev, chip);  out_err:  	return rc;  } @@ -766,7 +724,6 @@ static int tpm_tis_i2c_remove(struct i2c_client *client)  	chip->dev->release = NULL;  	chip->release = NULL;  	tpm_dev.client = NULL; -	dev_set_drvdata(chip->dev, chip);  	return 0;  } diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c new file mode 100644 index 00000000000..7b158efd49f --- /dev/null +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -0,0 +1,669 @@ +/****************************************************************************** + * Nuvoton TPM I2C Device Driver Interface for WPCT301/NPCT501, + * based on the TCG TPM Interface Spec version 1.2. + * Specifications at www.trustedcomputinggroup.org + * + * Copyright (C) 2011, Nuvoton Technology Corporation. + *  Dan Morav <dan.morav@nuvoton.com> + * Copyright (C) 2013, Obsidian Research Corp. + *  Jason Gunthorpe <jgunthorpe@obsidianresearch.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. + * + * 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/>. + * + * Nuvoton contact information: APC.Support@nuvoton.com + *****************************************************************************/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/wait.h> +#include <linux/i2c.h> +#include "tpm.h" + +/* I2C interface offsets */ +#define TPM_STS                0x00 +#define TPM_BURST_COUNT        0x01 +#define TPM_DATA_FIFO_W        0x20 +#define TPM_DATA_FIFO_R        0x40 +#define TPM_VID_DID_RID        0x60 +/* TPM command header size */ +#define TPM_HEADER_SIZE        10 +#define TPM_RETRY      5 +/* + * I2C bus device maximum buffer size w/o counting I2C address or command + * i.e. max size required for I2C write is 34 = addr, command, 32 bytes data + */ +#define TPM_I2C_MAX_BUF_SIZE           32 +#define TPM_I2C_RETRY_COUNT            32 +#define TPM_I2C_BUS_DELAY              1       /* msec */ +#define TPM_I2C_RETRY_DELAY_SHORT      2       /* msec */ +#define TPM_I2C_RETRY_DELAY_LONG       10      /* msec */ + +#define I2C_DRIVER_NAME "tpm_i2c_nuvoton" + +struct priv_data { +	unsigned int intrs; +}; + +static s32 i2c_nuvoton_read_buf(struct i2c_client *client, u8 offset, u8 size, +				u8 *data) +{ +	s32 status; + +	status = i2c_smbus_read_i2c_block_data(client, offset, size, data); +	dev_dbg(&client->dev, +		"%s(offset=%u size=%u data=%*ph) -> sts=%d\n", __func__, +		offset, size, (int)size, data, status); +	return status; +} + +static s32 i2c_nuvoton_write_buf(struct i2c_client *client, u8 offset, u8 size, +				 u8 *data) +{ +	s32 status; + +	status = i2c_smbus_write_i2c_block_data(client, offset, size, data); +	dev_dbg(&client->dev, +		"%s(offset=%u size=%u data=%*ph) -> sts=%d\n", __func__, +		offset, size, (int)size, data, status); +	return status; +} + +#define TPM_STS_VALID          0x80 +#define TPM_STS_COMMAND_READY  0x40 +#define TPM_STS_GO             0x20 +#define TPM_STS_DATA_AVAIL     0x10 +#define TPM_STS_EXPECT         0x08 +#define TPM_STS_RESPONSE_RETRY 0x02 +#define TPM_STS_ERR_VAL        0x07    /* bit2...bit0 reads always 0 */ + +#define TPM_I2C_SHORT_TIMEOUT  750     /* ms */ +#define TPM_I2C_LONG_TIMEOUT   2000    /* 2 sec */ + +/* read TPM_STS register */ +static u8 i2c_nuvoton_read_status(struct tpm_chip *chip) +{ +	struct i2c_client *client = to_i2c_client(chip->dev); +	s32 status; +	u8 data; + +	status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data); +	if (status <= 0) { +		dev_err(chip->dev, "%s() error return %d\n", __func__, +			status); +		data = TPM_STS_ERR_VAL; +	} + +	return data; +} + +/* write byte to TPM_STS register */ +static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data) +{ +	s32 status; +	int i; + +	/* this causes the current command to be aborted */ +	for (i = 0, status = -1; i < TPM_I2C_RETRY_COUNT && status < 0; i++) { +		status = i2c_nuvoton_write_buf(client, TPM_STS, 1, &data); +		msleep(TPM_I2C_BUS_DELAY); +	} +	return status; +} + +/* write commandReady to TPM_STS register */ +static void i2c_nuvoton_ready(struct tpm_chip *chip) +{ +	struct i2c_client *client = to_i2c_client(chip->dev); +	s32 status; + +	/* this causes the current command to be aborted */ +	status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY); +	if (status < 0) +		dev_err(chip->dev, +			"%s() fail to write TPM_STS.commandReady\n", __func__); +} + +/* read burstCount field from TPM_STS register + * return -1 on fail to read */ +static int i2c_nuvoton_get_burstcount(struct i2c_client *client, +				      struct tpm_chip *chip) +{ +	unsigned long stop = jiffies + chip->vendor.timeout_d; +	s32 status; +	int burst_count = -1; +	u8 data; + +	/* wait for burstcount to be non-zero */ +	do { +		/* in I2C burstCount is 1 byte */ +		status = i2c_nuvoton_read_buf(client, TPM_BURST_COUNT, 1, +					      &data); +		if (status > 0 && data > 0) { +			burst_count = min_t(u8, TPM_I2C_MAX_BUF_SIZE, data); +			break; +		} +		msleep(TPM_I2C_BUS_DELAY); +	} while (time_before(jiffies, stop)); + +	return burst_count; +} + +/* + * WPCT301/NPCT501 SINT# supports only dataAvail + * any call to this function which is not waiting for dataAvail will + * set queue to NULL to avoid waiting for interrupt + */ +static bool i2c_nuvoton_check_status(struct tpm_chip *chip, u8 mask, u8 value) +{ +	u8 status = i2c_nuvoton_read_status(chip); +	return (status != TPM_STS_ERR_VAL) && ((status & mask) == value); +} + +static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value, +				     u32 timeout, wait_queue_head_t *queue) +{ +	if (chip->vendor.irq && queue) { +		s32 rc; +		struct priv_data *priv = chip->vendor.priv; +		unsigned int cur_intrs = priv->intrs; + +		enable_irq(chip->vendor.irq); +		rc = wait_event_interruptible_timeout(*queue, +						      cur_intrs != priv->intrs, +						      timeout); +		if (rc > 0) +			return 0; +		/* At this point we know that the SINT pin is asserted, so we +		 * do not need to do i2c_nuvoton_check_status */ +	} else { +		unsigned long ten_msec, stop; +		bool status_valid; + +		/* check current status */ +		status_valid = i2c_nuvoton_check_status(chip, mask, value); +		if (status_valid) +			return 0; + +		/* use polling to wait for the event */ +		ten_msec = jiffies + msecs_to_jiffies(TPM_I2C_RETRY_DELAY_LONG); +		stop = jiffies + timeout; +		do { +			if (time_before(jiffies, ten_msec)) +				msleep(TPM_I2C_RETRY_DELAY_SHORT); +			else +				msleep(TPM_I2C_RETRY_DELAY_LONG); +			status_valid = i2c_nuvoton_check_status(chip, mask, +								value); +			if (status_valid) +				return 0; +		} while (time_before(jiffies, stop)); +	} +	dev_err(chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask, +		value); +	return -ETIMEDOUT; +} + +/* wait for dataAvail field to be set in the TPM_STS register */ +static int i2c_nuvoton_wait_for_data_avail(struct tpm_chip *chip, u32 timeout, +					   wait_queue_head_t *queue) +{ +	return i2c_nuvoton_wait_for_stat(chip, +					 TPM_STS_DATA_AVAIL | TPM_STS_VALID, +					 TPM_STS_DATA_AVAIL | TPM_STS_VALID, +					 timeout, queue); +} + +/* Read @count bytes into @buf from TPM_RD_FIFO register */ +static int i2c_nuvoton_recv_data(struct i2c_client *client, +				 struct tpm_chip *chip, u8 *buf, size_t count) +{ +	s32 rc; +	int burst_count, bytes2read, size = 0; + +	while (size < count && +	       i2c_nuvoton_wait_for_data_avail(chip, +					       chip->vendor.timeout_c, +					       &chip->vendor.read_queue) == 0) { +		burst_count = i2c_nuvoton_get_burstcount(client, chip); +		if (burst_count < 0) { +			dev_err(chip->dev, +				"%s() fail to read burstCount=%d\n", __func__, +				burst_count); +			return -EIO; +		} +		bytes2read = min_t(size_t, burst_count, count - size); +		rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R, +					  bytes2read, &buf[size]); +		if (rc < 0) { +			dev_err(chip->dev, +				"%s() fail on i2c_nuvoton_read_buf()=%d\n", +				__func__, rc); +			return -EIO; +		} +		dev_dbg(chip->dev, "%s(%d):", __func__, bytes2read); +		size += bytes2read; +	} + +	return size; +} + +/* Read TPM command results */ +static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ +	struct device *dev = chip->dev; +	struct i2c_client *client = to_i2c_client(dev); +	s32 rc; +	int expected, status, burst_count, retries, size = 0; + +	if (count < TPM_HEADER_SIZE) { +		i2c_nuvoton_ready(chip);    /* return to idle */ +		dev_err(dev, "%s() count < header size\n", __func__); +		return -EIO; +	} +	for (retries = 0; retries < TPM_RETRY; retries++) { +		if (retries > 0) { +			/* if this is not the first trial, set responseRetry */ +			i2c_nuvoton_write_status(client, +						 TPM_STS_RESPONSE_RETRY); +		} +		/* +		 * read first available (> 10 bytes), including: +		 * tag, paramsize, and result +		 */ +		status = i2c_nuvoton_wait_for_data_avail( +			chip, chip->vendor.timeout_c, &chip->vendor.read_queue); +		if (status != 0) { +			dev_err(dev, "%s() timeout on dataAvail\n", __func__); +			size = -ETIMEDOUT; +			continue; +		} +		burst_count = i2c_nuvoton_get_burstcount(client, chip); +		if (burst_count < 0) { +			dev_err(dev, "%s() fail to get burstCount\n", __func__); +			size = -EIO; +			continue; +		} +		size = i2c_nuvoton_recv_data(client, chip, buf, +					     burst_count); +		if (size < TPM_HEADER_SIZE) { +			dev_err(dev, "%s() fail to read header\n", __func__); +			size = -EIO; +			continue; +		} +		/* +		 * convert number of expected bytes field from big endian 32 bit +		 * to machine native +		 */ +		expected = be32_to_cpu(*(__be32 *) (buf + 2)); +		if (expected > count) { +			dev_err(dev, "%s() expected > count\n", __func__); +			size = -EIO; +			continue; +		} +		rc = i2c_nuvoton_recv_data(client, chip, &buf[size], +					   expected - size); +		size += rc; +		if (rc < 0 || size < expected) { +			dev_err(dev, "%s() fail to read remainder of result\n", +				__func__); +			size = -EIO; +			continue; +		} +		if (i2c_nuvoton_wait_for_stat( +			    chip, TPM_STS_VALID | TPM_STS_DATA_AVAIL, +			    TPM_STS_VALID, chip->vendor.timeout_c, +			    NULL)) { +			dev_err(dev, "%s() error left over data\n", __func__); +			size = -ETIMEDOUT; +			continue; +		} +		break; +	} +	i2c_nuvoton_ready(chip); +	dev_dbg(chip->dev, "%s() -> %d\n", __func__, size); +	return size; +} + +/* + * Send TPM command. + * + * If interrupts are used (signaled by an irq set in the vendor structure) + * tpm.c can skip polling for the data to be available as the interrupt is + * waited for here + */ +static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ +	struct device *dev = chip->dev; +	struct i2c_client *client = to_i2c_client(dev); +	u32 ordinal; +	size_t count = 0; +	int burst_count, bytes2write, retries, rc = -EIO; + +	for (retries = 0; retries < TPM_RETRY; retries++) { +		i2c_nuvoton_ready(chip); +		if (i2c_nuvoton_wait_for_stat(chip, TPM_STS_COMMAND_READY, +					      TPM_STS_COMMAND_READY, +					      chip->vendor.timeout_b, NULL)) { +			dev_err(dev, "%s() timeout on commandReady\n", +				__func__); +			rc = -EIO; +			continue; +		} +		rc = 0; +		while (count < len - 1) { +			burst_count = i2c_nuvoton_get_burstcount(client, +								 chip); +			if (burst_count < 0) { +				dev_err(dev, "%s() fail get burstCount\n", +					__func__); +				rc = -EIO; +				break; +			} +			bytes2write = min_t(size_t, burst_count, +					    len - 1 - count); +			rc = i2c_nuvoton_write_buf(client, TPM_DATA_FIFO_W, +						   bytes2write, &buf[count]); +			if (rc < 0) { +				dev_err(dev, "%s() fail i2cWriteBuf\n", +					__func__); +				break; +			} +			dev_dbg(dev, "%s(%d):", __func__, bytes2write); +			count += bytes2write; +			rc = i2c_nuvoton_wait_for_stat(chip, +						       TPM_STS_VALID | +						       TPM_STS_EXPECT, +						       TPM_STS_VALID | +						       TPM_STS_EXPECT, +						       chip->vendor.timeout_c, +						       NULL); +			if (rc < 0) { +				dev_err(dev, "%s() timeout on Expect\n", +					__func__); +				rc = -ETIMEDOUT; +				break; +			} +		} +		if (rc < 0) +			continue; + +		/* write last byte */ +		rc = i2c_nuvoton_write_buf(client, TPM_DATA_FIFO_W, 1, +					   &buf[count]); +		if (rc < 0) { +			dev_err(dev, "%s() fail to write last byte\n", +				__func__); +			rc = -EIO; +			continue; +		} +		dev_dbg(dev, "%s(last): %02x", __func__, buf[count]); +		rc = i2c_nuvoton_wait_for_stat(chip, +					       TPM_STS_VALID | TPM_STS_EXPECT, +					       TPM_STS_VALID, +					       chip->vendor.timeout_c, NULL); +		if (rc) { +			dev_err(dev, "%s() timeout on Expect to clear\n", +				__func__); +			rc = -ETIMEDOUT; +			continue; +		} +		break; +	} +	if (rc < 0) { +		/* retries == TPM_RETRY */ +		i2c_nuvoton_ready(chip); +		return rc; +	} +	/* execute the TPM command */ +	rc = i2c_nuvoton_write_status(client, TPM_STS_GO); +	if (rc < 0) { +		dev_err(dev, "%s() fail to write Go\n", __func__); +		i2c_nuvoton_ready(chip); +		return rc; +	} +	ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); +	rc = i2c_nuvoton_wait_for_data_avail(chip, +					     tpm_calc_ordinal_duration(chip, +								       ordinal), +					     &chip->vendor.read_queue); +	if (rc) { +		dev_err(dev, "%s() timeout command duration\n", __func__); +		i2c_nuvoton_ready(chip); +		return rc; +	} + +	dev_dbg(dev, "%s() -> %zd\n", __func__, len); +	return len; +} + +static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status) +{ +	return (status == TPM_STS_COMMAND_READY); +} + +static const struct tpm_class_ops tpm_i2c = { +	.status = i2c_nuvoton_read_status, +	.recv = i2c_nuvoton_recv, +	.send = i2c_nuvoton_send, +	.cancel = i2c_nuvoton_ready, +	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, +	.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, +	.req_canceled = i2c_nuvoton_req_canceled, +}; + +/* The only purpose for the handler is to signal to any waiting threads that + * the interrupt is currently being asserted. The driver does not do any + * processing triggered by interrupts, and the chip provides no way to mask at + * the source (plus that would be slow over I2C). Run the IRQ as a one-shot, + * this means it cannot be shared. */ +static irqreturn_t i2c_nuvoton_int_handler(int dummy, void *dev_id) +{ +	struct tpm_chip *chip = dev_id; +	struct priv_data *priv = chip->vendor.priv; + +	priv->intrs++; +	wake_up(&chip->vendor.read_queue); +	disable_irq_nosync(chip->vendor.irq); +	return IRQ_HANDLED; +} + +static int get_vid(struct i2c_client *client, u32 *res) +{ +	static const u8 vid_did_rid_value[] = { 0x50, 0x10, 0xfe }; +	u32 temp; +	s32 rc; + +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) +		return -ENODEV; +	rc = i2c_nuvoton_read_buf(client, TPM_VID_DID_RID, 4, (u8 *)&temp); +	if (rc < 0) +		return rc; + +	/* check WPCT301 values - ignore RID */ +	if (memcmp(&temp, vid_did_rid_value, sizeof(vid_did_rid_value))) { +		/* +		 * f/w rev 2.81 has an issue where the VID_DID_RID is not +		 * reporting the right value. so give it another chance at +		 * offset 0x20 (FIFO_W). +		 */ +		rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_W, 4, +					  (u8 *) (&temp)); +		if (rc < 0) +			return rc; + +		/* check WPCT301 values - ignore RID */ +		if (memcmp(&temp, vid_did_rid_value, +			   sizeof(vid_did_rid_value))) +			return -ENODEV; +	} + +	*res = temp; +	return 0; +} + +static int i2c_nuvoton_probe(struct i2c_client *client, +			     const struct i2c_device_id *id) +{ +	int rc; +	struct tpm_chip *chip; +	struct device *dev = &client->dev; +	u32 vid = 0; + +	rc = get_vid(client, &vid); +	if (rc) +		return rc; + +	dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid, +		 (u8) (vid >> 16), (u8) (vid >> 24)); + +	chip = tpm_register_hardware(dev, &tpm_i2c); +	if (!chip) { +		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__); +		return -ENODEV; +	} + +	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), +					 GFP_KERNEL); +	init_waitqueue_head(&chip->vendor.read_queue); +	init_waitqueue_head(&chip->vendor.int_queue); + +	/* Default timeouts */ +	chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); +	chip->vendor.timeout_b = msecs_to_jiffies(TPM_I2C_LONG_TIMEOUT); +	chip->vendor.timeout_c = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); +	chip->vendor.timeout_d = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); + +	/* +	 * I2C intfcaps (interrupt capabilitieis) in the chip are hard coded to: +	 *   TPM_INTF_INT_LEVEL_LOW | TPM_INTF_DATA_AVAIL_INT +	 * The IRQ should be set in the i2c_board_info (which is done +	 * automatically in of_i2c_register_devices, for device tree users */ +	chip->vendor.irq = client->irq; + +	if (chip->vendor.irq) { +		dev_dbg(dev, "%s() chip-vendor.irq\n", __func__); +		rc = devm_request_irq(dev, chip->vendor.irq, +				      i2c_nuvoton_int_handler, +				      IRQF_TRIGGER_LOW, +				      chip->vendor.miscdev.name, +				      chip); +		if (rc) { +			dev_err(dev, "%s() Unable to request irq: %d for use\n", +				__func__, chip->vendor.irq); +			chip->vendor.irq = 0; +		} else { +			/* Clear any pending interrupt */ +			i2c_nuvoton_ready(chip); +			/* - wait for TPM_STS==0xA0 (stsValid, commandReady) */ +			rc = i2c_nuvoton_wait_for_stat(chip, +						       TPM_STS_COMMAND_READY, +						       TPM_STS_COMMAND_READY, +						       chip->vendor.timeout_b, +						       NULL); +			if (rc == 0) { +				/* +				 * TIS is in ready state +				 * write dummy byte to enter reception state +				 * TPM_DATA_FIFO_W <- rc (0) +				 */ +				rc = i2c_nuvoton_write_buf(client, +							   TPM_DATA_FIFO_W, +							   1, (u8 *) (&rc)); +				if (rc < 0) +					goto out_err; +				/* TPM_STS <- 0x40 (commandReady) */ +				i2c_nuvoton_ready(chip); +			} else { +				/* +				 * timeout_b reached - command was +				 * aborted. TIS should now be in idle state - +				 * only TPM_STS_VALID should be set +				 */ +				if (i2c_nuvoton_read_status(chip) != +				    TPM_STS_VALID) { +					rc = -EIO; +					goto out_err; +				} +			} +		} +	} + +	if (tpm_get_timeouts(chip)) { +		rc = -ENODEV; +		goto out_err; +	} + +	if (tpm_do_selftest(chip)) { +		rc = -ENODEV; +		goto out_err; +	} + +	return 0; + +out_err: +	tpm_dev_vendor_release(chip); +	tpm_remove_hardware(chip->dev); +	return rc; +} + +static int i2c_nuvoton_remove(struct i2c_client *client) +{ +	struct device *dev = &(client->dev); +	struct tpm_chip *chip = dev_get_drvdata(dev); + +	if (chip) +		tpm_dev_vendor_release(chip); +	tpm_remove_hardware(dev); +	kfree(chip); +	return 0; +} + + +static const struct i2c_device_id i2c_nuvoton_id[] = { +	{I2C_DRIVER_NAME, 0}, +	{} +}; +MODULE_DEVICE_TABLE(i2c, i2c_nuvoton_id); + +#ifdef CONFIG_OF +static const struct of_device_id i2c_nuvoton_of_match[] = { +	{.compatible = "nuvoton,npct501"}, +	{.compatible = "winbond,wpct301"}, +	{}, +}; +MODULE_DEVICE_TABLE(of, i2c_nuvoton_of_match); +#endif + +static SIMPLE_DEV_PM_OPS(i2c_nuvoton_pm_ops, tpm_pm_suspend, tpm_pm_resume); + +static struct i2c_driver i2c_nuvoton_driver = { +	.id_table = i2c_nuvoton_id, +	.probe = i2c_nuvoton_probe, +	.remove = i2c_nuvoton_remove, +	.driver = { +		.name = I2C_DRIVER_NAME, +		.owner = THIS_MODULE, +		.pm = &i2c_nuvoton_pm_ops, +		.of_match_table = of_match_ptr(i2c_nuvoton_of_match), +	}, +}; + +module_i2c_driver(i2c_nuvoton_driver); + +MODULE_AUTHOR("Dan Morav (dan.morav@nuvoton.com)"); +MODULE_DESCRIPTION("Nuvoton TPM I2C Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 5bb8e2ddd3b..3b7bf216289 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -38,7 +38,6 @@  #include <linux/miscdevice.h>  #include <linux/kernel.h>  #include <linux/delay.h> -#include <linux/init.h>  #include <linux/wait.h>  #include <linux/string.h>  #include <linux/interrupt.h> @@ -410,6 +409,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)  			     &chip->vendor.read_queue)  	       == 0) {  		burstcnt = get_burstcount(chip); +		if (burstcnt < 0) +			return burstcnt;  		len = min_t(int, burstcnt, count - size);  		I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len);  		size += len; @@ -451,7 +452,8 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)  static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,  			    size_t len)  { -	u32 status, burstcnt = 0, i, size; +	u32 status, i, size; +	int burstcnt = 0;  	int ret;  	u8 data;  	struct i2c_client *client; @@ -482,6 +484,8 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,  	for (i = 0; i < len - 1;) {  		burstcnt = get_burstcount(chip); +		if (burstcnt < 0) +			return burstcnt;  		size = min_t(int, len - i - 1, burstcnt);  		ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);  		if (ret < 0) @@ -559,7 +563,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,  	}  out: -	chip->vendor.cancel(chip); +	chip->ops->cancel(chip);  	release_locality(chip);  	return size;  } @@ -569,40 +573,7 @@ static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status)  	return (status == TPM_STS_COMMAND_READY);  } -static const struct file_operations tpm_st33_i2c_fops = { -	.owner = THIS_MODULE, -	.llseek = no_llseek, -	.read = tpm_read, -	.write = tpm_write, -	.open = tpm_open, -	.release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); -static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); -static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); -static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); -static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); - -static struct attribute *stm_tpm_attrs[] = { -	&dev_attr_pubek.attr, -	&dev_attr_pcrs.attr, -	&dev_attr_enabled.attr, -	&dev_attr_active.attr, -	&dev_attr_owned.attr, -	&dev_attr_temp_deactivated.attr, -	&dev_attr_caps.attr, -	&dev_attr_cancel.attr, NULL, -}; - -static struct attribute_group stm_tpm_attr_grp = { -	.attrs = stm_tpm_attrs -}; - -static struct tpm_vendor_specific st_i2c_tpm = { +static const struct tpm_class_ops st_i2c_tpm = {  	.send = tpm_stm_i2c_send,  	.recv = tpm_stm_i2c_recv,  	.cancel = tpm_stm_i2c_cancel, @@ -610,8 +581,6 @@ static struct tpm_vendor_specific st_i2c_tpm = {  	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,  	.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,  	.req_canceled = tpm_st33_i2c_req_canceled, -	.attr_group = &stm_tpm_attr_grp, -	.miscdev = {.fops = &tpm_st33_i2c_fops,},  };  static int interrupts; @@ -746,8 +715,6 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)  	tpm_get_timeouts(chip); -	i2c_set_clientdata(client, chip); -  	dev_info(chip->dev, "TPM I2C Initialized\n");  	return 0;  _irq_set: @@ -807,24 +774,18 @@ static int tpm_st33_i2c_remove(struct i2c_client *client)  #ifdef CONFIG_PM_SLEEP  /*   * tpm_st33_i2c_pm_suspend suspend the TPM device - * Added: Work around when suspend and no tpm application is running, suspend - * may fail because chip->data_buffer is not set (only set in tpm_open in Linux - * TPM core)   * @param: client, the i2c_client drescription (TPM I2C description).   * @param: mesg, the power management message.   * @return: 0 in case of success.   */  static int tpm_st33_i2c_pm_suspend(struct device *dev)  { -	struct tpm_chip *chip = dev_get_drvdata(dev);  	struct st33zp24_platform_data *pin_infos = dev->platform_data;  	int ret = 0;  	if (power_mgt) {  		gpio_set_value(pin_infos->io_lpcpd, 0);  	} else { -		if (chip->data_buffer == NULL) -			chip->data_buffer = pin_infos->tpm_i2c_buffer[0];  		ret = tpm_pm_suspend(dev);  	}  	return ret; @@ -845,12 +806,10 @@ static int tpm_st33_i2c_pm_resume(struct device *dev)  	if (power_mgt) {  		gpio_set_value(pin_infos->io_lpcpd, 1);  		ret = wait_for_serirq_timeout(chip, -					  (chip->vendor.status(chip) & +					  (chip->ops->status(chip) &  					  TPM_STS_VALID) == TPM_STS_VALID,  					  chip->vendor.timeout_b);  	} else { -		if (chip->data_buffer == NULL) -			chip->data_buffer = pin_infos->tpm_i2c_buffer[0];  		ret = tpm_pm_resume(dev);  		if (!ret)  			tpm_do_selftest(chip); diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 56b07c35a13..af74c57e509 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -98,7 +98,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)  	if (count < len) {  		dev_err(ibmvtpm->dev, -			"Invalid size in recv: count=%ld, crq_size=%d\n", +			"Invalid size in recv: count=%zd, crq_size=%d\n",  			count, len);  		return -EIO;  	} @@ -136,7 +136,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)  	if (count > ibmvtpm->rtce_size) {  		dev_err(ibmvtpm->dev, -			"Invalid size in send: count=%ld, rtce_size=%d\n", +			"Invalid size in send: count=%zd, rtce_size=%d\n",  			count, ibmvtpm->rtce_size);  		return -EIO;  	} @@ -403,43 +403,7 @@ static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status)  	return (status == 0);  } -static const struct file_operations ibmvtpm_ops = { -	.owner = THIS_MODULE, -	.llseek = no_llseek, -	.open = tpm_open, -	.read = tpm_read, -	.write = tpm_write, -	.release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); -static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); -static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); -static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, -		   NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); -static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); -static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); -static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); - -static struct attribute *ibmvtpm_attrs[] = { -	&dev_attr_pubek.attr, -	&dev_attr_pcrs.attr, -	&dev_attr_enabled.attr, -	&dev_attr_active.attr, -	&dev_attr_owned.attr, -	&dev_attr_temp_deactivated.attr, -	&dev_attr_caps.attr, -	&dev_attr_cancel.attr, -	&dev_attr_durations.attr, -	&dev_attr_timeouts.attr, NULL, -}; - -static struct attribute_group ibmvtpm_attr_grp = { .attrs = ibmvtpm_attrs }; - -static const struct tpm_vendor_specific tpm_ibmvtpm = { +static const struct tpm_class_ops tpm_ibmvtpm = {  	.recv = tpm_ibmvtpm_recv,  	.send = tpm_ibmvtpm_send,  	.cancel = tpm_ibmvtpm_cancel, @@ -447,8 +411,6 @@ static const struct tpm_vendor_specific tpm_ibmvtpm = {  	.req_complete_mask = 0,  	.req_complete_val = 0,  	.req_canceled = tpm_ibmvtpm_req_canceled, -	.attr_group = &ibmvtpm_attr_grp, -	.miscdev = { .fops = &ibmvtpm_ops, },  };  static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = { @@ -507,7 +469,6 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,  			dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg);  			return;  		} -		return;  	case IBMVTPM_VALID_CMD:  		switch (crq->msg) {  		case VTPM_GET_RTCE_BUFFER_SIZE_RES: diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 2b480c2960b..dc0a2554034 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -371,39 +371,13 @@ static u8 tpm_inf_status(struct tpm_chip *chip)  	return tpm_data_in(STAT);  } -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); -static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); - -static struct attribute *inf_attrs[] = { -	&dev_attr_pubek.attr, -	&dev_attr_pcrs.attr, -	&dev_attr_caps.attr, -	&dev_attr_cancel.attr, -	NULL, -}; - -static struct attribute_group inf_attr_grp = {.attrs = inf_attrs }; - -static const struct file_operations inf_ops = { -	.owner = THIS_MODULE, -	.llseek = no_llseek, -	.open = tpm_open, -	.read = tpm_read, -	.write = tpm_write, -	.release = tpm_release, -}; - -static const struct tpm_vendor_specific tpm_inf = { +static const struct tpm_class_ops tpm_inf = {  	.recv = tpm_inf_recv,  	.send = tpm_inf_send,  	.cancel = tpm_inf_cancel,  	.status = tpm_inf_status,  	.req_complete_mask = 0,  	.req_complete_val = 0, -	.attr_group = &inf_attr_grp, -	.miscdev = {.fops = &inf_ops,},  };  static const struct pnp_device_id tpm_inf_pnp_tbl[] = { diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 770c46f8eb3..3179ec9cffd 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -232,31 +232,7 @@ static bool tpm_nsc_req_canceled(struct tpm_chip *chip, u8 status)  	return (status == NSC_STATUS_RDY);  } -static const struct file_operations nsc_ops = { -	.owner = THIS_MODULE, -	.llseek = no_llseek, -	.open = tpm_open, -	.read = tpm_read, -	.write = tpm_write, -	.release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); -static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel); - -static struct attribute * nsc_attrs[] = { -	&dev_attr_pubek.attr, -	&dev_attr_pcrs.attr, -	&dev_attr_caps.attr, -	&dev_attr_cancel.attr, -	NULL, -}; - -static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; - -static const struct tpm_vendor_specific tpm_nsc = { +static const struct tpm_class_ops tpm_nsc = {  	.recv = tpm_nsc_recv,  	.send = tpm_nsc_send,  	.cancel = tpm_nsc_cancel, @@ -264,8 +240,6 @@ static const struct tpm_vendor_specific tpm_nsc = {  	.req_complete_mask = NSC_STATUS_OBF,  	.req_complete_val = NSC_STATUS_OBF,  	.req_canceled = tpm_nsc_req_canceled, -	.attr_group = &nsc_attr_grp, -	.miscdev = { .fops = &nsc_ops, },  };  static struct platform_device *pdev = NULL; diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 2168d15bc72..61dcc8011ec 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -1,16 +1,6 @@  #include <linux/acpi.h> -#include <acpi/acpi_drivers.h>  #include "tpm.h" -static const u8 tpm_ppi_uuid[] = { -	0xA6, 0xFA, 0xDD, 0x3D, -	0x1B, 0x36, -	0xB4, 0x4E, -	0xA4, 0x24, -	0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 -}; -static char *tpm_device_name = "TPM"; -  #define TPM_PPI_REVISION_ID	1  #define TPM_PPI_FN_VERSION	1  #define TPM_PPI_FN_SUBREQ	2 @@ -24,247 +14,178 @@ static char *tpm_device_name = "TPM";  #define PPI_VS_REQ_END		255  #define PPI_VERSION_LEN		3 +static const u8 tpm_ppi_uuid[] = { +	0xA6, 0xFA, 0xDD, 0x3D, +	0x1B, 0x36, +	0xB4, 0x4E, +	0xA4, 0x24, +	0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 +}; + +static char tpm_ppi_version[PPI_VERSION_LEN + 1]; +static acpi_handle tpm_ppi_handle; +  static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,  				void **return_value)  { -	acpi_status status; -	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; -	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); -	if (strstr(buffer.pointer, context) != NULL) { -		*return_value = handle; -		kfree(buffer.pointer); -		return AE_CTRL_TERMINATE; +	union acpi_object *obj; + +	if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, +			    1 << TPM_PPI_FN_VERSION)) +		return AE_OK; + +	/* Cache version string */ +	obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid, +				      TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, +				      NULL, ACPI_TYPE_STRING); +	if (obj) { +		strlcpy(tpm_ppi_version, obj->string.pointer, +			PPI_VERSION_LEN + 1); +		ACPI_FREE(obj);  	} -	return AE_OK; + +	*return_value = handle; + +	return AE_CTRL_TERMINATE;  } -static inline void ppi_assign_params(union acpi_object params[4], -				     u64 function_num) +static inline union acpi_object * +tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4)  { -	params[0].type = ACPI_TYPE_BUFFER; -	params[0].buffer.length = sizeof(tpm_ppi_uuid); -	params[0].buffer.pointer = (char *)tpm_ppi_uuid; -	params[1].type = ACPI_TYPE_INTEGER; -	params[1].integer.value = TPM_PPI_REVISION_ID; -	params[2].type = ACPI_TYPE_INTEGER; -	params[2].integer.value = function_num; -	params[3].type = ACPI_TYPE_PACKAGE; -	params[3].package.count = 0; -	params[3].package.elements = NULL; +	BUG_ON(!tpm_ppi_handle); +	return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid, +				       TPM_PPI_REVISION_ID, func, argv4, type);  }  static ssize_t tpm_show_ppi_version(struct device *dev,  				    struct device_attribute *attr, char *buf)  { -	acpi_handle handle; -	acpi_status status; -	struct acpi_object_list input; -	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -	union acpi_object params[4]; -	union acpi_object *obj; - -	input.count = 4; -	ppi_assign_params(params, TPM_PPI_FN_VERSION); -	input.pointer = params; -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, -				     ACPI_UINT32_MAX, ppi_callback, NULL, -				     tpm_device_name, &handle); -	if (ACPI_FAILURE(status)) -		return -ENXIO; - -	status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, -					 ACPI_TYPE_STRING); -	if (ACPI_FAILURE(status)) -		return -ENOMEM; -	obj = (union acpi_object *)output.pointer; -	status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer); -	kfree(output.pointer); -	return status; +	return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version);  }  static ssize_t tpm_show_ppi_request(struct device *dev,  				    struct device_attribute *attr, char *buf)  { -	acpi_handle handle; -	acpi_status status; -	struct acpi_object_list input; -	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -	union acpi_object params[4]; -	union acpi_object *ret_obj; - -	input.count = 4; -	ppi_assign_params(params, TPM_PPI_FN_GETREQ); -	input.pointer = params; -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, -				     ACPI_UINT32_MAX, ppi_callback, NULL, -				     tpm_device_name, &handle); -	if (ACPI_FAILURE(status)) +	ssize_t size = -EINVAL; +	union acpi_object *obj; + +	obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL); +	if (!obj)  		return -ENXIO; -	status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, -					    ACPI_TYPE_PACKAGE); -	if (ACPI_FAILURE(status)) -		return -ENOMEM;  	/*  	 * output.pointer should be of package type, including two integers.  	 * The first is function return code, 0 means success and 1 means  	 * error. The second is pending TPM operation requested by the OS, 0  	 * means none and >0 means operation value.  	 */ -	ret_obj = ((union acpi_object *)output.pointer)->package.elements; -	if (ret_obj->type == ACPI_TYPE_INTEGER) { -		if (ret_obj->integer.value) { -			status = -EFAULT; -			goto cleanup; -		} -		ret_obj++; -		if (ret_obj->type == ACPI_TYPE_INTEGER) -			status = scnprintf(buf, PAGE_SIZE, "%llu\n", -					   ret_obj->integer.value); +	if (obj->package.count == 2 && +	    obj->package.elements[0].type == ACPI_TYPE_INTEGER && +	    obj->package.elements[1].type == ACPI_TYPE_INTEGER) { +		if (obj->package.elements[0].integer.value) +			size = -EFAULT;  		else -			status = -EINVAL; -	} else { -		status = -EINVAL; +			size = scnprintf(buf, PAGE_SIZE, "%llu\n", +				 obj->package.elements[1].integer.value);  	} -cleanup: -	kfree(output.pointer); -	return status; + +	ACPI_FREE(obj); + +	return size;  }  static ssize_t tpm_store_ppi_request(struct device *dev,  				     struct device_attribute *attr,  				     const char *buf, size_t count)  { -	char version[PPI_VERSION_LEN + 1]; -	acpi_handle handle; -	acpi_status status; -	struct acpi_object_list input; -	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -	union acpi_object params[4]; -	union acpi_object obj;  	u32 req;  	u64 ret; +	int func = TPM_PPI_FN_SUBREQ; +	union acpi_object *obj, tmp; +	union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); -	input.count = 4; -	ppi_assign_params(params, TPM_PPI_FN_VERSION); -	input.pointer = params; -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, -				     ACPI_UINT32_MAX, ppi_callback, NULL, -				     tpm_device_name, &handle); -	if (ACPI_FAILURE(status)) -		return -ENXIO; - -	status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, -					    ACPI_TYPE_STRING); -	if (ACPI_FAILURE(status)) -		return -ENOMEM; -	strlcpy(version, -		((union acpi_object *)output.pointer)->string.pointer, -		PPI_VERSION_LEN + 1); -	kfree(output.pointer); -	output.length = ACPI_ALLOCATE_BUFFER; -	output.pointer = NULL;  	/*  	 * the function to submit TPM operation request to pre-os environment  	 * is updated with function index from SUBREQ to SUBREQ2 since PPI  	 * version 1.1  	 */ -	if (strcmp(version, "1.1") == -1) -		params[2].integer.value = TPM_PPI_FN_SUBREQ; -	else -		params[2].integer.value = TPM_PPI_FN_SUBREQ2; +	if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, +			   1 << TPM_PPI_FN_SUBREQ2)) +		func = TPM_PPI_FN_SUBREQ2; +  	/*  	 * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS  	 * accept buffer/string/integer type, but some BIOS accept buffer/  	 * string/package type. For PPI version 1.0 and 1.1, use buffer type  	 * for compatibility, and use package type since 1.2 according to spec.  	 */ -	if (strcmp(version, "1.2") == -1) { -		params[3].type = ACPI_TYPE_BUFFER; -		params[3].buffer.length = sizeof(req); -		sscanf(buf, "%d", &req); -		params[3].buffer.pointer = (char *)&req; +	if (strcmp(tpm_ppi_version, "1.2") < 0) { +		if (sscanf(buf, "%d", &req) != 1) +			return -EINVAL; +		argv4.type = ACPI_TYPE_BUFFER; +		argv4.buffer.length = sizeof(req); +		argv4.buffer.pointer = (u8 *)&req;  	} else { -		params[3].package.count = 1; -		obj.type = ACPI_TYPE_INTEGER; -		sscanf(buf, "%llu", &obj.integer.value); -		params[3].package.elements = &obj; +		tmp.type = ACPI_TYPE_INTEGER; +		if (sscanf(buf, "%llu", &tmp.integer.value) != 1) +			return -EINVAL; +	} + +	obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4); +	if (!obj) { +		return -ENXIO; +	} else { +		ret = obj->integer.value; +		ACPI_FREE(obj);  	} -	status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, -					    ACPI_TYPE_INTEGER); -	if (ACPI_FAILURE(status)) -		return -ENOMEM; -	ret = ((union acpi_object *)output.pointer)->integer.value;  	if (ret == 0) -		status = (acpi_status)count; -	else if (ret == 1) -		status = -EPERM; -	else -		status = -EFAULT; -	kfree(output.pointer); -	return status; +		return (acpi_status)count; + +	return (ret == 1) ? -EPERM : -EFAULT;  }  static ssize_t tpm_show_ppi_transition_action(struct device *dev,  					      struct device_attribute *attr,  					      char *buf)  { -	char version[PPI_VERSION_LEN + 1]; -	acpi_handle handle; -	acpi_status status; -	struct acpi_object_list input; -	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -	union acpi_object params[4];  	u32 ret; -	char *info[] = { +	acpi_status status; +	union acpi_object *obj = NULL; +	union acpi_object tmp = { +		.buffer.type = ACPI_TYPE_BUFFER, +		.buffer.length = 0, +		.buffer.pointer = NULL +	}; + +	static char *info[] = {  		"None",  		"Shutdown",  		"Reboot",  		"OS Vendor-specific",  		"Error",  	}; -	input.count = 4; -	ppi_assign_params(params, TPM_PPI_FN_VERSION); -	input.pointer = params; -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, -				     ACPI_UINT32_MAX, ppi_callback, NULL, -				     tpm_device_name, &handle); -	if (ACPI_FAILURE(status)) -		return -ENXIO; -	status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, -					    ACPI_TYPE_STRING); -	if (ACPI_FAILURE(status)) -		return -ENOMEM; -	strlcpy(version, -		((union acpi_object *)output.pointer)->string.pointer, -		PPI_VERSION_LEN + 1);  	/*  	 * PPI spec defines params[3].type as empty package, but some platforms  	 * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for  	 * compatibility, define params[3].type as buffer, if PPI version < 1.2  	 */ -	if (strcmp(version, "1.2") == -1) { -		params[3].type = ACPI_TYPE_BUFFER; -		params[3].buffer.length =  0; -		params[3].buffer.pointer = NULL; +	if (strcmp(tpm_ppi_version, "1.2") < 0) +		obj = &tmp; +	obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj); +	if (!obj) { +		return -ENXIO; +	} else { +		ret = obj->integer.value; +		ACPI_FREE(obj);  	} -	params[2].integer.value = TPM_PPI_FN_GETACT; -	kfree(output.pointer); -	output.length = ACPI_ALLOCATE_BUFFER; -	output.pointer = NULL; -	status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, -					    ACPI_TYPE_INTEGER); -	if (ACPI_FAILURE(status)) -		return -ENOMEM; -	ret = ((union acpi_object *)output.pointer)->integer.value; +  	if (ret < ARRAY_SIZE(info) - 1)  		status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]);  	else  		status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret,  				   info[ARRAY_SIZE(info)-1]); -	kfree(output.pointer);  	return status;  } @@ -272,27 +193,14 @@ static ssize_t tpm_show_ppi_response(struct device *dev,  				     struct device_attribute *attr,  				     char *buf)  { -	acpi_handle handle; -	acpi_status status; -	struct acpi_object_list input; -	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -	union acpi_object params[4]; -	union acpi_object *ret_obj; -	u64 req; - -	input.count = 4; -	ppi_assign_params(params, TPM_PPI_FN_GETRSP); -	input.pointer = params; -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, -				     ACPI_UINT32_MAX, ppi_callback, NULL, -				     tpm_device_name, &handle); -	if (ACPI_FAILURE(status)) +	acpi_status status = -EINVAL; +	union acpi_object *obj, *ret_obj; +	u64 req, res; + +	obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL); +	if (!obj)  		return -ENXIO; -	status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, -					    ACPI_TYPE_PACKAGE); -	if (ACPI_FAILURE(status)) -		return -ENOMEM;  	/*  	 * parameter output.pointer should be of package type, including  	 * 3 integers. The first means function return code, the second means @@ -300,115 +208,82 @@ static ssize_t tpm_show_ppi_response(struct device *dev,  	 * the most recent TPM operation request. Only if the first is 0, and  	 * the second integer is not 0, the response makes sense.  	 */ -	ret_obj = ((union acpi_object *)output.pointer)->package.elements; -	if (ret_obj->type != ACPI_TYPE_INTEGER) { -		status = -EINVAL; +	ret_obj = obj->package.elements; +	if (obj->package.count < 3 || +	    ret_obj[0].type != ACPI_TYPE_INTEGER || +	    ret_obj[1].type != ACPI_TYPE_INTEGER || +	    ret_obj[2].type != ACPI_TYPE_INTEGER)  		goto cleanup; -	} -	if (ret_obj->integer.value) { + +	if (ret_obj[0].integer.value) {  		status = -EFAULT;  		goto cleanup;  	} -	ret_obj++; -	if (ret_obj->type != ACPI_TYPE_INTEGER) { -		status = -EINVAL; -		goto cleanup; -	} -	if (ret_obj->integer.value) { -		req = ret_obj->integer.value; -		ret_obj++; -		if (ret_obj->type != ACPI_TYPE_INTEGER) { -			status = -EINVAL; -			goto cleanup; -		} -		if (ret_obj->integer.value == 0) + +	req = ret_obj[1].integer.value; +	res = ret_obj[2].integer.value; +	if (req) { +		if (res == 0)  			status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,  					   "0: Success"); -		else if (ret_obj->integer.value == 0xFFFFFFF0) +		else if (res == 0xFFFFFFF0)  			status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,  					   "0xFFFFFFF0: User Abort"); -		else if (ret_obj->integer.value == 0xFFFFFFF1) +		else if (res == 0xFFFFFFF1)  			status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,  					   "0xFFFFFFF1: BIOS Failure"); -		else if (ret_obj->integer.value >= 1 && -			 ret_obj->integer.value <= 0x00000FFF) +		else if (res >= 1 && res <= 0x00000FFF)  			status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", -					   req, ret_obj->integer.value, -					   "Corresponding TPM error"); +					   req, res, "Corresponding TPM error");  		else  			status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", -					   req, ret_obj->integer.value, -					   "Error"); +					   req, res, "Error");  	} else {  		status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", -				   ret_obj->integer.value, "No Recent Request"); +				   req, "No Recent Request");  	} +  cleanup: -	kfree(output.pointer); +	ACPI_FREE(obj);  	return status;  }  static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)  { -	char *str = buf; -	char version[PPI_VERSION_LEN + 1]; -	acpi_handle handle; -	acpi_status status; -	struct acpi_object_list input; -	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -	union acpi_object params[4]; -	union acpi_object obj;  	int i;  	u32 ret; -	char *info[] = { +	char *str = buf; +	union acpi_object *obj, tmp; +	union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp); + +	static char *info[] = {  		"Not implemented",  		"BIOS only",  		"Blocked for OS by BIOS",  		"User required",  		"User not required",  	}; -	input.count = 4; -	ppi_assign_params(params, TPM_PPI_FN_VERSION); -	input.pointer = params; -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, -				     ACPI_UINT32_MAX, ppi_callback, NULL, -				     tpm_device_name, &handle); -	if (ACPI_FAILURE(status)) -		return -ENXIO; -	status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, -					 ACPI_TYPE_STRING); -	if (ACPI_FAILURE(status)) -		return -ENOMEM; - -	strlcpy(version, -		((union acpi_object *)output.pointer)->string.pointer, -		PPI_VERSION_LEN + 1); -	kfree(output.pointer); -	output.length = ACPI_ALLOCATE_BUFFER; -	output.pointer = NULL; -	if (strcmp(version, "1.2") == -1) +	if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, +			    1 << TPM_PPI_FN_GETOPR))  		return -EPERM; -	params[2].integer.value = TPM_PPI_FN_GETOPR; -	params[3].package.count = 1; -	obj.type = ACPI_TYPE_INTEGER; -	params[3].package.elements = &obj; +	tmp.integer.type = ACPI_TYPE_INTEGER;  	for (i = start; i <= end; i++) { -		obj.integer.value = i; -		status = acpi_evaluate_object_typed(handle, "_DSM", -			 &input, &output, ACPI_TYPE_INTEGER); -		if (ACPI_FAILURE(status)) +		tmp.integer.value = i; +		obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv); +		if (!obj) {  			return -ENOMEM; +		} else { +			ret = obj->integer.value; +			ACPI_FREE(obj); +		} -		ret = ((union acpi_object *)output.pointer)->integer.value;  		if (ret > 0 && ret < ARRAY_SIZE(info))  			str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n",  					 i, ret, info[ret]); -		kfree(output.pointer); -		output.length = ACPI_ALLOCATE_BUFFER; -		output.pointer = NULL;  	} +  	return str - buf;  } @@ -450,14 +325,14 @@ static struct attribute_group ppi_attr_grp = {  int tpm_add_ppi(struct kobject *parent)  { -	return sysfs_create_group(parent, &ppi_attr_grp); +	/* Cache TPM ACPI handle and version string */ +	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, +			    ppi_callback, NULL, NULL, &tpm_ppi_handle); +	return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0;  } -EXPORT_SYMBOL_GPL(tpm_add_ppi);  void tpm_remove_ppi(struct kobject *parent)  { -	sysfs_remove_group(parent, &ppi_attr_grp); +	if (tpm_ppi_handle) +		sysfs_remove_group(parent, &ppi_attr_grp);  } -EXPORT_SYMBOL_GPL(tpm_remove_ppi); - -MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 5796d0157ce..a9ed2270c25 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -432,45 +432,7 @@ static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)  	}  } -static const struct file_operations tis_ops = { -	.owner = THIS_MODULE, -	.llseek = no_llseek, -	.open = tpm_open, -	.read = tpm_read, -	.write = tpm_write, -	.release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); -static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); -static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); -static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, -		   NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); -static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); -static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); -static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); - -static struct attribute *tis_attrs[] = { -	&dev_attr_pubek.attr, -	&dev_attr_pcrs.attr, -	&dev_attr_enabled.attr, -	&dev_attr_active.attr, -	&dev_attr_owned.attr, -	&dev_attr_temp_deactivated.attr, -	&dev_attr_caps.attr, -	&dev_attr_cancel.attr, -	&dev_attr_durations.attr, -	&dev_attr_timeouts.attr, NULL, -}; - -static struct attribute_group tis_attr_grp = { -	.attrs = tis_attrs -}; - -static struct tpm_vendor_specific tpm_tis = { +static const struct tpm_class_ops tpm_tis = {  	.status = tpm_tis_status,  	.recv = tpm_tis_recv,  	.send = tpm_tis_send, @@ -478,9 +440,6 @@ static struct tpm_vendor_specific tpm_tis = {  	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,  	.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,  	.req_canceled = tpm_tis_req_canceled, -	.attr_group = &tis_attr_grp, -	.miscdev = { -		    .fops = &tis_ops,},  };  static irqreturn_t tis_int_probe(int irq, void *dev_id) @@ -743,7 +702,7 @@ out_err:  	return rc;  } -#if defined(CONFIG_PNP) || defined(CONFIG_PM_SLEEP) +#ifdef CONFIG_PM_SLEEP  static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)  {  	u32 intmask; @@ -764,9 +723,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)  	iowrite32(intmask,  		  chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));  } -#endif -#ifdef CONFIG_PM_SLEEP  static int tpm_tis_resume(struct device *dev)  {  	struct tpm_chip *chip = dev_get_drvdata(dev); @@ -835,11 +792,9 @@ static struct pnp_driver tis_pnp_driver = {  	.id_table = tpm_pnp_tbl,  	.probe = tpm_tis_pnp_init,  	.remove = tpm_tis_pnp_remove, -#ifdef CONFIG_PM_SLEEP  	.driver	= {  		.pm = &tpm_tis_pm,  	}, -#endif  };  #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 06189e55b4e..2064b452704 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -10,12 +10,14 @@  #include <linux/errno.h>  #include <linux/err.h>  #include <linux/interrupt.h> +#include <xen/xen.h>  #include <xen/events.h>  #include <xen/interface/io/tpmif.h>  #include <xen/grant_table.h>  #include <xen/xenbus.h>  #include <xen/page.h>  #include "tpm.h" +#include <xen/platform_pci.h>  struct tpm_private {  	struct tpm_chip *chip; @@ -142,46 +144,7 @@ static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)  	return length;  } -static const struct file_operations vtpm_ops = { -	.owner = THIS_MODULE, -	.llseek = no_llseek, -	.open = tpm_open, -	.read = tpm_read, -	.write = tpm_write, -	.release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); -static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); -static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); -static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, -		NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); -static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); -static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); -static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); - -static struct attribute *vtpm_attrs[] = { -	&dev_attr_pubek.attr, -	&dev_attr_pcrs.attr, -	&dev_attr_enabled.attr, -	&dev_attr_active.attr, -	&dev_attr_owned.attr, -	&dev_attr_temp_deactivated.attr, -	&dev_attr_caps.attr, -	&dev_attr_cancel.attr, -	&dev_attr_durations.attr, -	&dev_attr_timeouts.attr, -	NULL, -}; - -static struct attribute_group vtpm_attr_grp = { -	.attrs = vtpm_attrs, -}; - -static const struct tpm_vendor_specific tpm_vtpm = { +static const struct tpm_class_ops tpm_vtpm = {  	.status = vtpm_status,  	.recv = vtpm_recv,  	.send = vtpm_send, @@ -189,10 +152,6 @@ static const struct tpm_vendor_specific tpm_vtpm = {  	.req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,  	.req_complete_val  = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,  	.req_canceled      = vtpm_req_canceled, -	.attr_group = &vtpm_attr_grp, -	.miscdev = { -		.fops = &vtpm_ops, -	},  };  static irqreturn_t tpmif_interrupt(int dummy, void *dev_id) @@ -350,8 +309,6 @@ static int tpmfront_probe(struct xenbus_device *dev,  	tpm_get_timeouts(priv->chip); -	dev_set_drvdata(&dev->dev, priv->chip); -  	return rv;  } @@ -422,6 +379,9 @@ static int __init xen_tpmfront_init(void)  	if (!xen_domain())  		return -ENODEV; +	if (!xen_has_pv_devices()) +		return -ENODEV; +  	return xenbus_register_frontend(&tpmfront_driver);  }  module_init(xen_tpmfront_init); diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index d5d2e4a985a..a15ce4ef39c 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -17,7 +17,7 @@  #include <linux/device.h>  #include <linux/serial.h>  #include <linux/tty.h> -#include <linux/export.h> +#include <linux/module.h>  struct ttyprintk_port {  	struct tty_port port; @@ -210,10 +210,19 @@ static int __init ttyprintk_init(void)  	return 0;  error: -	tty_unregister_driver(ttyprintk_driver);  	put_tty_driver(ttyprintk_driver);  	tty_port_destroy(&tpk_port.port); -	ttyprintk_driver = NULL;  	return ret;  } -module_init(ttyprintk_init); + +static void __exit ttyprintk_exit(void) +{ +	tty_unregister_driver(ttyprintk_driver); +	put_tty_driver(ttyprintk_driver); +	tty_port_destroy(&tpk_port.port); +} + +device_initcall(ttyprintk_init); +module_exit(ttyprintk_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index b79cf3e1b79..60aafb8a1f2 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -577,7 +577,8 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,  	spin_lock(&portdev->c_ovq_lock);  	if (virtqueue_add_outbuf(vq, sg, 1, &cpkt, GFP_ATOMIC) == 0) {  		virtqueue_kick(vq); -		while (!virtqueue_get_buf(vq, &len)) +		while (!virtqueue_get_buf(vq, &len) +			&& !virtqueue_is_broken(vq))  			cpu_relax();  	}  	spin_unlock(&portdev->c_ovq_lock); @@ -650,7 +651,8 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,  	 * we need to kmalloc a GFP_ATOMIC buffer each time the  	 * console driver writes something out.  	 */ -	while (!virtqueue_get_buf(out_vq, &len)) +	while (!virtqueue_get_buf(out_vq, &len) +		&& !virtqueue_is_broken(out_vq))  		cpu_relax();  done:  	spin_unlock_irqrestore(&port->outvq_lock, flags); @@ -888,12 +890,10 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,  	} else {  		/* Failback to copying a page */  		struct page *page = alloc_page(GFP_KERNEL); -		char *src = buf->ops->map(pipe, buf, 1); -		char *dst; +		char *src;  		if (!page)  			return -ENOMEM; -		dst = kmap(page);  		offset = sd->pos & ~PAGE_MASK; @@ -901,10 +901,9 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,  		if (len + offset > PAGE_SIZE)  			len = PAGE_SIZE - offset; -		memcpy(dst + offset, src + buf->offset, len); - -		kunmap(page); -		buf->ops->unmap(pipe, buf, src); +		src = kmap_atomic(buf->page); +		memcpy(page_address(page) + offset, src + buf->offset, len); +		kunmap_atomic(src);  		sg_set_page(&(sgl->sg[sgl->n]), page, len, offset);  	} @@ -1837,12 +1836,8 @@ static void config_intr(struct virtio_device *vdev)  		struct port *port;  		u16 rows, cols; -		vdev->config->get(vdev, -				  offsetof(struct virtio_console_config, cols), -				  &cols, sizeof(u16)); -		vdev->config->get(vdev, -				  offsetof(struct virtio_console_config, rows), -				  &rows, sizeof(u16)); +		virtio_cread(vdev, struct virtio_console_config, cols, &cols); +		virtio_cread(vdev, struct virtio_console_config, rows, &rows);  		port = find_port_by_id(portdev, 0);  		set_console_size(port, rows, cols); @@ -2014,10 +2009,9 @@ static int virtcons_probe(struct virtio_device *vdev)  	/* Don't test MULTIPORT at all if we're rproc: not a valid feature! */  	if (!is_rproc_serial(vdev) && -	    virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT, -				  offsetof(struct virtio_console_config, -					   max_nr_ports), -				  &portdev->config.max_nr_ports) == 0) { +	    virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT, +				 struct virtio_console_config, max_nr_ports, +				 &portdev->config.max_nr_ports) == 0) {  		multiport = true;  	} @@ -2142,7 +2136,7 @@ static struct virtio_device_id rproc_serial_id_table[] = {  static unsigned int rproc_serial_features[] = {  }; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int virtcons_freeze(struct virtio_device *vdev)  {  	struct ports_device *portdev; @@ -2220,7 +2214,7 @@ static struct virtio_driver virtio_console = {  	.probe =	virtcons_probe,  	.remove =	virtcons_remove,  	.config_changed = config_intr, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.freeze =	virtcons_freeze,  	.restore =	virtcons_restore,  #endif diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 5224da5202d..f6345f932e4 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -721,7 +721,7 @@ static int hwicap_remove(struct device *dev)  {  	struct hwicap_drvdata *drvdata; -	drvdata = (struct hwicap_drvdata *)dev_get_drvdata(dev); +	drvdata = dev_get_drvdata(dev);  	if (!drvdata)  		return 0; @@ -731,7 +731,6 @@ static int hwicap_remove(struct device *dev)  	iounmap(drvdata->base_address);  	release_mem_region(drvdata->mem_start, drvdata->mem_size);  	kfree(drvdata); -	dev_set_drvdata(dev, NULL);  	mutex_lock(&icap_sem);  	probed_devices[MINOR(dev->devt)-XHWICAP_MINOR] = 0;  | 
