diff options
Diffstat (limited to 'drivers/char')
46 files changed, 1134 insertions, 1456 deletions
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/generic.c b/drivers/char/agp/generic.c index a0df182f6f7..f39437addb5 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -1396,8 +1396,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..5c85350f4c3 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -64,7 +64,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 +94,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 +169,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 +183,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 +192,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 +210,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 +291,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 +611,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 +638,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 +649,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 +664,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 +691,7 @@ static int intel_fake_agp_fetch_size(void) return 0; } +#endif static void i830_cleanup(void) { @@ -787,20 +790,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 +828,7 @@ static int intel_fake_agp_configure(void) return 0; } +#endif static bool i830_check_flags(unsigned int flags) { @@ -863,6 +867,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 +933,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 +947,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 +989,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 +1116,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 +1127,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 +1143,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 +1165,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 +1383,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/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/hpet.c b/drivers/char/hpet.c index 5d9c31dfc90..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. diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index e6939e13e33..d915707d2ba 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,17 @@ 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); + set_cpus_allowed_ptr(current, cpumask_of(0)); + if (smp_processor_id() != 0) { + rc = -EBUSY; + goto out; + } #if defined(CONFIG_X86_64) asm volatile("pushq %%rax\n\t" @@ -148,7 +167,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 +193,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; + rc = -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, }; - - return i8k_smm(®s) ? : regs.eax; +out: + set_cpus_allowed_ptr(current, old_mask); + free_cpumask_var(old_mask); + return rc; } /* @@ -203,7 +214,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 +238,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 +264,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 +290,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 +308,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 +323,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 +343,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 +487,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 +509,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 +556,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 = { @@ -671,7 +721,23 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = { 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 */ + }, + { } }; /* @@ -679,8 +745,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 @@ -689,49 +754,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; } @@ -754,10 +800,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: @@ -767,7 +809,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/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index a22a7a50274..f5e4cd7617f 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 */ @@ -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..6a4bdc18955 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) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 15e4a603193..03f41896d09 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1358,7 +1358,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 +1368,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 +1849,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 +2071,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 +2146,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 +2184,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 +2266,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 +2574,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 +2682,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 +2724,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 +2750,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 +2788,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); 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..92c5937f80c 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> 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/nwbutton.c b/drivers/char/nwbutton.c index 1fd00dc0689..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; } 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/tpm/Makefile b/drivers/char/tpm/Makefile index b80a4000dae..4d85dd681b8 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o -tpm-y := tpm-interface.o +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-$(CONFIG_ACPI) += tpm_ppi.o ifdef CONFIG_ACPI 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-interface.c b/drivers/char/tpm/tpm-interface.c index 6ae41d33763..62e10fd1e1c 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -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; @@ -377,7 +353,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, mutex_lock(&chip->tpm_mutex); - rc = chip->vendor.send(chip, (u8 *) buf, count); + rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); @@ -389,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; @@ -404,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); @@ -422,24 +398,6 @@ 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) { @@ -459,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) @@ -659,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 */ @@ -752,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; @@ -787,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; } @@ -911,196 +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) -{ - 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; -} -EXPORT_SYMBOL_GPL(tpm_show_caps); - -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; } @@ -1116,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; @@ -1143,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)); @@ -1151,127 +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) -{ - struct miscdevice *misc = file->private_data; - struct tpm_chip *chip = container_of(misc, struct tpm_chip, - vendor.miscdev); - - if (test_and_set_bit(0, &chip->is_open)) { - dev_dbg(chip->dev, "Another process owns this TPM\n"); - return -EBUSY; - } - - chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL); - if (chip->data_buffer == NULL) { - clear_bit(0, &chip->is_open); - return -ENOMEM; - } - - atomic_set(&chip->data_pending, 0); - - file->private_data = chip; - get_device(chip->dev); - 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) { @@ -1287,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); @@ -1436,9 +1027,6 @@ 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); } EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); @@ -1448,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); @@ -1460,7 +1048,6 @@ 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 @@ -1470,7 +1057,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_release); * pci_disable_device */ struct tpm_chip *tpm_register_hardware(struct device *dev, - const struct tpm_vendor_specific *entry) + const struct tpm_class_ops *ops) { struct tpm_chip *chip; @@ -1480,56 +1067,35 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, 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(chip->devname, sizeof(chip->devname), "%s%d", "tpm", chip->dev_num); - chip->vendor.miscdev.name = chip->devname; - 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(chip->devname); @@ -1540,6 +1106,8 @@ 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: 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 f3284787219..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,33 +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_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 */ @@ -89,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 */ @@ -118,19 +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; @@ -171,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; @@ -244,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; @@ -323,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..b9a57fa4b71 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" diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index c9a528d25d2..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; diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index c3cd7fe481a..77272925dee 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -135,50 +135,12 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip) return ATMEL_STS_OK; } -static const struct file_operations i2c_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(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 *i2c_atmel_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 i2c_atmel_attr_grp = { - .attrs = i2c_atmel_attrs -}; - static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status) { - return 0; + return false; } -static const struct tpm_vendor_specific i2c_atmel = { +static const struct tpm_class_ops i2c_atmel = { .status = i2c_atmel_read_status, .recv = i2c_atmel_recv, .send = i2c_atmel_send, @@ -186,8 +148,6 @@ static const struct tpm_vendor_specific i2c_atmel = { .req_complete_mask = ATMEL_STS_OK, .req_complete_val = ATMEL_STS_OK, .req_canceled = i2c_atmel_req_canceled, - .attr_group = &i2c_atmel_attr_grp, - .miscdev.fops = &i2c_atmel_ops, }; static int i2c_atmel_probe(struct i2c_client *client, diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index fefd2aa5c81..52b9b2b2f30 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -566,45 +566,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, 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 +574,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) diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 6276fea01ff..7b158efd49f 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -178,7 +178,6 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value, { if (chip->vendor.irq && queue) { s32 rc; - DEFINE_WAIT(wait); struct priv_data *priv = chip->vendor.priv; unsigned int cur_intrs = priv->intrs; @@ -456,45 +455,7 @@ static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status) return (status == TPM_STS_COMMAND_READY); } -static const struct file_operations i2c_nuvoton_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 *i2c_nuvoton_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 i2c_nuvoton_attr_grp = { - .attrs = i2c_nuvoton_attrs -}; - -static const struct tpm_vendor_specific tpm_i2c = { +static const struct tpm_class_ops tpm_i2c = { .status = i2c_nuvoton_read_status, .recv = i2c_nuvoton_recv, .send = i2c_nuvoton_send, @@ -502,8 +463,6 @@ static const struct tpm_vendor_specific tpm_i2c = { .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, - .attr_group = &i2c_nuvoton_attr_grp, - .miscdev.fops = &i2c_nuvoton_ops, }; /* The only purpose for the handler is to signal to any waiting threads that diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index a0d6ceb5d00..5b0dd8ef74c 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -410,6 +410,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 +453,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 +485,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 +564,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 +574,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, 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 +582,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; @@ -837,7 +807,7 @@ 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 { diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 2783a42aa73..af74c57e509 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -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, 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 e1f3337a0cf..b3ea223585b 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,250 +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 = AE_OK; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) { - if (strstr(buffer.pointer, context) != NULL) { - *return_value = handle; - status = AE_CTRL_TERMINATE; - } - kfree(buffer.pointer); + 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 status; + *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 { + 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 { - params[3].package.count = 1; - obj.type = ACPI_TYPE_INTEGER; - sscanf(buf, "%llu", &obj.integer.value); - params[3].package.elements = &obj; + 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; } @@ -275,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 @@ -303,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; } @@ -453,6 +325,12 @@ static struct attribute_group ppi_attr_grp = { int tpm_add_ppi(struct kobject *parent) { + /* 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); + if (tpm_ppi_handle == NULL) + return -ENODEV; + return sysfs_create_group(parent, &ppi_attr_grp); } diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 1b74459c072..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, 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 c8ff4df8177..2064b452704 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -17,6 +17,7 @@ #include <xen/xenbus.h> #include <xen/page.h> #include "tpm.h" +#include <xen/platform_pci.h> struct tpm_private { struct tpm_chip *chip; @@ -143,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, @@ -190,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) @@ -421,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..daea84c4174 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -216,4 +216,4 @@ error: ttyprintk_driver = NULL; return ret; } -module_init(ttyprintk_init); +device_initcall(ttyprintk_init); |