From 86678dfddba55a7b9e2ea084d59be6500fec2256 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Apr 2006 18:10:11 +1000 Subject: [PATCH] drm: Fix issue reported by Coverity in drivers/char/drm/via_irq.c This patch tries to fix an issue reported in drivers/char/drm/via_irq.c by Coverity, please review and apply if correct. Error reported: CID: 3444 Checker: REVERSE_INULL (help) File: /export2/p4-coverity/mc2/linux26/drivers/char/drm/via_irq.c Function: via_driver_irq_wait Description: Pointer "dev_priv" dereferenced before NULL check Patch Description: Move de-referencing dev_priv to after the NULL check. Signed-off-by: Jayachandran C. Signed-off-by: Dave Airlie --- drivers/char/drm/via_irq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index 6152415644e9..1228fa55355b 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c @@ -198,7 +198,7 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, unsigned int cur_irq_sequence; drm_via_irq_t *cur_irq = dev_priv->via_irqs; int ret = 0; - maskarray_t *masks = dev_priv->irq_masks; + maskarray_t *masks; int real_irq; DRM_DEBUG("%s\n", __FUNCTION__); @@ -221,7 +221,8 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, __FUNCTION__, irq); return DRM_ERR(EINVAL); } - + + masks = dev_priv->irq_masks; cur_irq += real_irq; if (masks[real_irq][2] && !force_sequence) { -- cgit v1.2.3 From 195b3a2d57b81d30e3129575ef6c8a95b2c936b7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Apr 2006 18:12:18 +1000 Subject: drm: drm_pci needs dma-mapping.h On alpha: WARNING: "dma_free_coherent" [drivers/char/drm/drm.ko] undefined! WARNING: "dma_alloc_coherent" [drivers/char/drm/drm.ko] undefined! Signed-off-by: Andrew Morton Signed-off-by: Dave Airlie --- drivers/char/drm/drm_pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/drm/drm_pci.c b/drivers/char/drm/drm_pci.c index b28ca9cea8a2..86a0f1c22091 100644 --- a/drivers/char/drm/drm_pci.c +++ b/drivers/char/drm/drm_pci.c @@ -37,6 +37,7 @@ */ #include +#include #include "drmP.h" /**********************************************************************/ -- cgit v1.2.3 From 11bab7d2c86fe486e3581ac3dcdb349478ffb899 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Apr 2006 18:13:13 +1000 Subject: drm: remove master setting from add/remove context Clients can do this in the miniglx setups. Signed-off-by: Dave Airlie --- drivers/char/drm/drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index dc6bbe8a18dc..3c0b882a8e72 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -75,8 +75,8 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, DRM_AUTH}, [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, -- cgit v1.2.3 From 31f64bd101ea256f9fc4a7f1f1706d6417d5550a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Apr 2006 16:55:43 +1000 Subject: drm: deline a few large inlines in DRM code This patch moves a few large functions from drm_memory.h to drm_memory.c, with the following effect: text data bss dec hex filename 46305 1304 20 47629 ba0d new/drm.ko 46367 1304 20 47691 ba4b org/drm.ko 12969 1372 0 14341 3805 new/i810.ko 14712 1372 0 16084 3ed4 org/i810.ko 16447 1364 0 17811 4593 new/i830.ko 18198 1364 0 19562 4c6a org/i830.ko 11875 1324 0 13199 338f new/i915.ko 13025 1324 0 14349 380d org/i915.ko 23936 29288 0 53224 cfe8 new/mga.ko 27280 29288 0 56568 dcf8 org/mga.ko Please apply. Signed-off-by: Denis Vlasenko Signed-off-by: Dave Airlie --- drivers/char/drm/drm_memory.c | 117 ++++++++++++++++++++++++++++++++++++++++++ drivers/char/drm/drm_memory.h | 116 ++++------------------------------------- 2 files changed, 127 insertions(+), 106 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c index dddf8de66143..7ea00e3372fd 100644 --- a/drivers/char/drm/drm_memory.c +++ b/drivers/char/drm/drm_memory.c @@ -80,6 +80,71 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) } #if __OS_HAS_AGP +/* + * Find the drm_map that covers the range [offset, offset+size). + */ +drm_map_t *drm_lookup_map(unsigned long offset, + unsigned long size, drm_device_t * dev) +{ + struct list_head *list; + drm_map_list_t *r_list; + drm_map_t *map; + + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *) list; + map = r_list->map; + if (!map) + continue; + if (map->offset <= offset + && (offset + size) <= (map->offset + map->size)) + return map; + } + return NULL; +} + +void *agp_remap(unsigned long offset, unsigned long size, + drm_device_t * dev) +{ + unsigned long *phys_addr_map, i, num_pages = + PAGE_ALIGN(size) / PAGE_SIZE; + struct drm_agp_mem *agpmem; + struct page **page_map; + void *addr; + + size = PAGE_ALIGN(size); + +#ifdef __alpha__ + offset -= dev->hose->mem_space->start; +#endif + + for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) + if (agpmem->bound <= offset + && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >= + (offset + size)) + break; + if (!agpmem) + return NULL; + + /* + * OK, we're mapping AGP space on a chipset/platform on which memory accesses by + * the CPU do not get remapped by the GART. We fix this by using the kernel's + * page-table instead (that's probably faster anyhow...). + */ + /* note: use vmalloc() because num_pages could be large... */ + page_map = vmalloc(num_pages * sizeof(struct page *)); + if (!page_map) + return NULL; + + phys_addr_map = + agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE; + for (i = 0; i < num_pages; ++i) + page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT); + addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); + vfree(page_map); + + return addr; +} + /** Wrapper around agp_allocate_memory() */ DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type) { @@ -104,4 +169,56 @@ int drm_unbind_agp(DRM_AGP_MEM * handle) return drm_agp_unbind_memory(handle); } #endif /* agp */ + +void *drm_ioremap(unsigned long offset, unsigned long size, + drm_device_t * dev) +{ + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { + drm_map_t *map = drm_lookup_map(offset, size, dev); + + if (map && map->type == _DRM_AGP) + return agp_remap(offset, size, dev); + } + return ioremap(offset, size); +} +EXPORT_SYMBOL(drm_ioremap); + +void *drm_ioremap_nocache(unsigned long offset, + unsigned long size, drm_device_t * dev) +{ + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { + drm_map_t *map = drm_lookup_map(offset, size, dev); + + if (map && map->type == _DRM_AGP) + return agp_remap(offset, size, dev); + } + return ioremap_nocache(offset, size); +} + +void drm_ioremapfree(void *pt, unsigned long size, + drm_device_t * dev) +{ + /* + * This is a bit ugly. It would be much cleaner if the DRM API would use separate + * routines for handling mappings in the AGP space. Hopefully this can be done in + * a future revision of the interface... + */ + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture + && ((unsigned long)pt >= VMALLOC_START + && (unsigned long)pt < VMALLOC_END)) { + unsigned long offset; + drm_map_t *map; + + offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK); + map = drm_lookup_map(offset, size, dev); + if (map && map->type == _DRM_AGP) { + vunmap(pt); + return; + } + } + + iounmap(pt); +} +EXPORT_SYMBOL(drm_ioremapfree); + #endif /* debug_memory */ diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h index 3732a61c3762..645a08878e55 100644 --- a/drivers/char/drm/drm_memory.h +++ b/drivers/char/drm/drm_memory.h @@ -60,67 +60,11 @@ /* * Find the drm_map that covers the range [offset, offset+size). */ -static inline drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - struct list_head *list; - drm_map_list_t *r_list; - drm_map_t *map; - - list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *) list; - map = r_list->map; - if (!map) - continue; - if (map->offset <= offset - && (offset + size) <= (map->offset + map->size)) - return map; - } - return NULL; -} - -static inline void *agp_remap(unsigned long offset, unsigned long size, - drm_device_t * dev) -{ - unsigned long *phys_addr_map, i, num_pages = - PAGE_ALIGN(size) / PAGE_SIZE; - struct drm_agp_mem *agpmem; - struct page **page_map; - void *addr; - - size = PAGE_ALIGN(size); - -#ifdef __alpha__ - offset -= dev->hose->mem_space->start; -#endif +drm_map_t *drm_lookup_map(unsigned long offset, + unsigned long size, drm_device_t * dev); - for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) - if (agpmem->bound <= offset - && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >= - (offset + size)) - break; - if (!agpmem) - return NULL; - - /* - * OK, we're mapping AGP space on a chipset/platform on which memory accesses by - * the CPU do not get remapped by the GART. We fix this by using the kernel's - * page-table instead (that's probably faster anyhow...). - */ - /* note: use vmalloc() because num_pages could be large... */ - page_map = vmalloc(num_pages * sizeof(struct page *)); - if (!page_map) - return NULL; - - phys_addr_map = - agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE; - for (i = 0; i < num_pages; ++i) - page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT); - addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); - vfree(page_map); - - return addr; -} +void *agp_remap(unsigned long offset, unsigned long size, + drm_device_t * dev); static inline unsigned long drm_follow_page(void *vaddr) { @@ -152,51 +96,11 @@ static inline unsigned long drm_follow_page(void *vaddr) #endif -static inline void *drm_ioremap(unsigned long offset, unsigned long size, - drm_device_t * dev) -{ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { - drm_map_t *map = drm_lookup_map(offset, size, dev); +void *drm_ioremap(unsigned long offset, unsigned long size, + drm_device_t * dev); - if (map && map->type == _DRM_AGP) - return agp_remap(offset, size, dev); - } - return ioremap(offset, size); -} +void *drm_ioremap_nocache(unsigned long offset, + unsigned long size, drm_device_t * dev); -static inline void *drm_ioremap_nocache(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { - drm_map_t *map = drm_lookup_map(offset, size, dev); - - if (map && map->type == _DRM_AGP) - return agp_remap(offset, size, dev); - } - return ioremap_nocache(offset, size); -} - -static inline void drm_ioremapfree(void *pt, unsigned long size, - drm_device_t * dev) -{ - /* - * This is a bit ugly. It would be much cleaner if the DRM API would use separate - * routines for handling mappings in the AGP space. Hopefully this can be done in - * a future revision of the interface... - */ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture - && ((unsigned long)pt >= VMALLOC_START - && (unsigned long)pt < VMALLOC_END)) { - unsigned long offset; - drm_map_t *map; - - offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK); - map = drm_lookup_map(offset, size, dev); - if (map && map->type == _DRM_AGP) { - vunmap(pt); - return; - } - } - - iounmap(pt); -} +void drm_ioremapfree(void *pt, unsigned long size, + drm_device_t * dev); -- cgit v1.2.3 From 20ac94378de59d61dc39f10ed5530485e4ac8c07 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 13 Apr 2006 04:49:07 -0600 Subject: [PATCH] do_SAK: Don't recursively take the tasklist_lock By calling send_sig do_SAK is recursively taking the tasklist_lock, which is silly. In addition I just audited the kernel and this was the only place where tasklist_lock is taken inside of task_lock. So this one line change is a general worthwhile cleanup and it increases our options on how to fix the ptrace_attach races. Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index f70a47eadb52..841f0bd3eaaf 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2734,7 +2734,7 @@ static void __do_SAK(void *arg) printk(KERN_NOTICE "SAK: killed process %d" " (%s): fd#%d opened to the tty\n", p->pid, p->comm, i); - send_sig(SIGKILL, p, 1); + force_sig(SIGKILL, p); break; } } -- cgit v1.2.3 From 1f60245479ca6d4d3f2cf4a47c7dd18caf5afdf2 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 14 Apr 2006 17:25:30 -0700 Subject: [efficeon-agp] Add missing memory mask Original patch by Benjamin Herrenschmidt after debugging by Brian Hinz. Cc: Benjamin Herrenschmidt Cc: Brian Hinz Signed-off-by: H. Peter Anvin Signed-off-by: Linus Torvalds --- drivers/char/agp/efficeon-agp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index fed0a87448d8..86a966b65236 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -64,6 +64,12 @@ static struct gatt_mask efficeon_generic_masks[] = {.mask = 0x00000001, .type = 0} }; +/* This function does the same thing as mask_memory() for this chipset... */ +static inline unsigned long efficeon_mask_memory(unsigned long addr) +{ + return addr | 0x00000001; +} + static struct aper_size_info_lvl2 efficeon_generic_sizes[4] = { {256, 65536, 0}, @@ -251,7 +257,7 @@ static int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int t last_page = NULL; for (i = 0; i < count; i++) { int index = pg_start + i; - unsigned long insert = mem->memory[i]; + unsigned long insert = efficeon_mask_memory(mem->memory[i]); page = (unsigned int *) efficeon_private.l1_table[index >> 10]; -- cgit v1.2.3 From 031de96af0e7ed6ad4a7ec2b74a77bf9782f966e Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 10 Apr 2006 23:18:27 -0700 Subject: drivers/char/drm/drm_memory.c: possible cleanups - #if 0 the following unused global function: - drm_ioremap_nocache() - make the following needlessly global functions static: - agp_remap() - drm_lookup_map() Signed-off-by: Adrian Bunk Cc: Dave Airlie Signed-off-by: Andrew Morton --- drivers/char/drm/drmP.h | 4 ++-- drivers/char/drm/drm_memory.c | 25 +++++++++++++++++++++---- drivers/char/drm/drm_memory.h | 24 ------------------------ drivers/char/drm/drm_memory_debug.h | 2 ++ 4 files changed, 25 insertions(+), 30 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index edc72a6348a7..e1aadae00623 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -815,8 +815,6 @@ extern int drm_mem_info(char *buf, char **start, off_t offset, extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area); extern void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t * dev); -extern void *drm_ioremap_nocache(unsigned long offset, unsigned long size, - drm_device_t * dev); extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev); extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type); @@ -1022,11 +1020,13 @@ static __inline__ void drm_core_ioremap(struct drm_map *map, map->handle = drm_ioremap(map->offset, map->size, dev); } +#if 0 static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, struct drm_device *dev) { map->handle = drm_ioremap_nocache(map->offset, map->size, dev); } +#endif /* 0 */ static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c index 7ea00e3372fd..7e3318e1d1c6 100644 --- a/drivers/char/drm/drm_memory.c +++ b/drivers/char/drm/drm_memory.c @@ -83,8 +83,8 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) /* * Find the drm_map that covers the range [offset, offset+size). */ -drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev) +static drm_map_t *drm_lookup_map(unsigned long offset, + unsigned long size, drm_device_t * dev) { struct list_head *list; drm_map_list_t *r_list; @@ -102,8 +102,8 @@ drm_map_t *drm_lookup_map(unsigned long offset, return NULL; } -void *agp_remap(unsigned long offset, unsigned long size, - drm_device_t * dev) +static void *agp_remap(unsigned long offset, unsigned long size, + drm_device_t * dev) { unsigned long *phys_addr_map, i, num_pages = PAGE_ALIGN(size) / PAGE_SIZE; @@ -168,6 +168,21 @@ int drm_unbind_agp(DRM_AGP_MEM * handle) { return drm_agp_unbind_memory(handle); } + +#else /* __OS_HAS_AGP */ + +static inline drm_map_t *drm_lookup_map(unsigned long offset, + unsigned long size, drm_device_t * dev) +{ + return NULL; +} + +static inline void *agp_remap(unsigned long offset, unsigned long size, + drm_device_t * dev) +{ + return NULL; +} + #endif /* agp */ void *drm_ioremap(unsigned long offset, unsigned long size, @@ -183,6 +198,7 @@ void *drm_ioremap(unsigned long offset, unsigned long size, } EXPORT_SYMBOL(drm_ioremap); +#if 0 void *drm_ioremap_nocache(unsigned long offset, unsigned long size, drm_device_t * dev) { @@ -194,6 +210,7 @@ void *drm_ioremap_nocache(unsigned long offset, } return ioremap_nocache(offset, size); } +#endif /* 0 */ void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev) diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h index 645a08878e55..714d9aedcff5 100644 --- a/drivers/char/drm/drm_memory.h +++ b/drivers/char/drm/drm_memory.h @@ -57,15 +57,6 @@ # endif #endif -/* - * Find the drm_map that covers the range [offset, offset+size). - */ -drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev); - -void *agp_remap(unsigned long offset, unsigned long size, - drm_device_t * dev); - static inline unsigned long drm_follow_page(void *vaddr) { pgd_t *pgd = pgd_offset_k((unsigned long)vaddr); @@ -77,18 +68,6 @@ static inline unsigned long drm_follow_page(void *vaddr) #else /* __OS_HAS_AGP */ -static inline drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - return NULL; -} - -static inline void *agp_remap(unsigned long offset, unsigned long size, - drm_device_t * dev) -{ - return NULL; -} - static inline unsigned long drm_follow_page(void *vaddr) { return 0; @@ -99,8 +78,5 @@ static inline unsigned long drm_follow_page(void *vaddr) void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t * dev); -void *drm_ioremap_nocache(unsigned long offset, - unsigned long size, drm_device_t * dev); - void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev); diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h index 7868341817da..6543b9a14c42 100644 --- a/drivers/char/drm/drm_memory_debug.h +++ b/drivers/char/drm/drm_memory_debug.h @@ -229,6 +229,7 @@ void *drm_ioremap (unsigned long offset, unsigned long size, return pt; } +#if 0 void *drm_ioremap_nocache (unsigned long offset, unsigned long size, drm_device_t * dev) { void *pt; @@ -251,6 +252,7 @@ void *drm_ioremap_nocache (unsigned long offset, unsigned long size, spin_unlock(&drm_mem_lock); return pt; } +#endif /* 0 */ void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) { int alloc_count; -- cgit v1.2.3 From d253258c80117c2afaa644554e613201992e4ee9 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 10 Apr 2006 23:18:28 -0700 Subject: drm: Fix further issues in drivers/char/drm/via_irq.c Fix de-reference of 'dev_priv' before NULL check. Signed-off-by: Jayachandran C. Cc: Dave Airlie Signed-off-by: Andrew Morton --- drivers/char/drm/via_irq.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index 1228fa55355b..c33d068cde19 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c @@ -196,7 +196,7 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; unsigned int cur_irq_sequence; - drm_via_irq_t *cur_irq = dev_priv->via_irqs; + drm_via_irq_t *cur_irq; int ret = 0; maskarray_t *masks; int real_irq; @@ -223,7 +223,7 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, } masks = dev_priv->irq_masks; - cur_irq += real_irq; + cur_irq = dev_priv->via_irqs + real_irq; if (masks[real_irq][2] && !force_sequence) { DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ, @@ -248,11 +248,12 @@ void via_driver_irq_preinstall(drm_device_t * dev) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; u32 status; - drm_via_irq_t *cur_irq = dev_priv->via_irqs; + drm_via_irq_t *cur_irq; int i; DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv); if (dev_priv) { + cur_irq = dev_priv->via_irqs; dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE; dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING; -- cgit v1.2.3 From ca99c1da080345e227cfb083c330a184d42e27f3 Mon Sep 17 00:00:00 2001 From: Dipankar Sarma Date: Tue, 18 Apr 2006 22:21:46 -0700 Subject: [PATCH] Fix file lookup without ref There are places in the kernel where we look up files in fd tables and access the file structure without holding refereces to the file. So, we need special care to avoid the race between looking up files in the fd table and tearing down of the file in another CPU. Otherwise, one might see a NULL f_dentry or such torn down version of the file. This patch fixes those special places where such a race may happen. Signed-off-by: Dipankar Sarma Acked-by: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 8 ++++++-- fs/locks.c | 9 +++++++-- fs/proc/base.c | 21 +++++++++++++++------ 3 files changed, 28 insertions(+), 10 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 841f0bd3eaaf..f07637a8f88f 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2723,7 +2723,11 @@ static void __do_SAK(void *arg) } task_lock(p); if (p->files) { - rcu_read_lock(); + /* + * We don't take a ref to the file, so we must + * hold ->file_lock instead. + */ + spin_lock(&p->files->file_lock); fdt = files_fdtable(p->files); for (i=0; i < fdt->max_fds; i++) { filp = fcheck_files(p->files, i); @@ -2738,7 +2742,7 @@ static void __do_SAK(void *arg) break; } } - rcu_read_unlock(); + spin_unlock(&p->files->file_lock); } task_unlock(p); } while_each_thread(g, p); diff --git a/fs/locks.c b/fs/locks.c index dda83d6cd48b..efad798824dc 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2230,7 +2230,12 @@ void steal_locks(fl_owner_t from) lock_kernel(); j = 0; - rcu_read_lock(); + + /* + * We are not taking a ref to the file structures, so + * we need to acquire ->file_lock. + */ + spin_lock(&files->file_lock); fdt = files_fdtable(files); for (;;) { unsigned long set; @@ -2248,7 +2253,7 @@ void steal_locks(fl_owner_t from) set >>= 1; } } - rcu_read_unlock(); + spin_unlock(&files->file_lock); unlock_kernel(); } EXPORT_SYMBOL(steal_locks); diff --git a/fs/proc/base.c b/fs/proc/base.c index a3a3eecef689..6cc77dc3f3ff 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -297,16 +297,20 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm files = get_files_struct(task); if (files) { - rcu_read_lock(); + /* + * We are not taking a ref to the file structure, so we must + * hold ->file_lock. + */ + spin_lock(&files->file_lock); file = fcheck_files(files, fd); if (file) { *mnt = mntget(file->f_vfsmnt); *dentry = dget(file->f_dentry); - rcu_read_unlock(); + spin_unlock(&files->file_lock); put_files_struct(files); return 0; } - rcu_read_unlock(); + spin_unlock(&files->file_lock); put_files_struct(files); } return -ENOENT; @@ -1523,7 +1527,12 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, if (!files) goto out_unlock; inode->i_mode = S_IFLNK; - rcu_read_lock(); + + /* + * We are not taking a ref to the file structure, so we must + * hold ->file_lock. + */ + spin_lock(&files->file_lock); file = fcheck_files(files, fd); if (!file) goto out_unlock2; @@ -1531,7 +1540,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, inode->i_mode |= S_IRUSR | S_IXUSR; if (file->f_mode & 2) inode->i_mode |= S_IWUSR | S_IXUSR; - rcu_read_unlock(); + spin_unlock(&files->file_lock); put_files_struct(files); inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; @@ -1541,7 +1550,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, return NULL; out_unlock2: - rcu_read_unlock(); + spin_unlock(&files->file_lock); put_files_struct(files); out_unlock: iput(inode); -- cgit v1.2.3 From 7420884c038f326bdac3a8ded856033523e7684e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 18 Apr 2006 22:21:52 -0700 Subject: [PATCH] IPMI: fix devinit placement gcc complains about __devinit in the wrong location: drivers/char/ipmi/ipmi_si_intf.c:2205: warning: '__section__' attribute does not apply to types Signed-off-by: Randy Dunlap Acked-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index a86c0f29953e..b36eef0e9d19 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2198,11 +2198,11 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info) } } -static struct ipmi_default_vals +static __devinitdata struct ipmi_default_vals { int type; int port; -} __devinit ipmi_defaults[] = +} ipmi_defaults[] = { { .type = SI_KCS, .port = 0xca2 }, { .type = SI_SMIC, .port = 0xca9 }, -- cgit v1.2.3 From 3fb0cb5d0f8b915a75677e8e8e4a4a4e481f03f7 Mon Sep 17 00:00:00 2001 From: Heikki Orsila Date: Tue, 18 Apr 2006 22:21:55 -0700 Subject: [PATCH] Open IPMI BT overflow I was looking into random driver code and found a suspicious looking memcpy() in drivers/char/ipmi/ipmi_bt_sm.c on 2.6.17-rc1: if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1; ... memcpy(bt->write_data + 3, data + 1, size - 1); where sizeof bt->write_data is IPMI_MAX_MSG_LENGTH. It looks like the memcpy would overflow by 2 bytes if size == IPMI_MAX_MSG_LENGTH. A patch attached to limit size to (IPMI_MAX_LENGTH - 2). Cc: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_bt_sm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 58dcdee1cd71..0030cd8e2e95 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -165,7 +165,7 @@ static int bt_start_transaction(struct si_sm_data *bt, { unsigned int i; - if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) + if ((size < 2) || (size > (IPMI_MAX_MSG_LENGTH - 2))) return -1; if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED)) -- cgit v1.2.3 From 0324680064fd89d6ad52e89a4ccf16dec3ea3caa Mon Sep 17 00:00:00 2001 From: Thayumanavar Sachithanantham Date: Thu, 20 Apr 2006 02:43:15 -0700 Subject: [PATCH] cs5535_gpio.c: call cdev_del() during module_exit to unmap kobject references and other cleanups During module unloading, cdev_del() must be called to unmap cdev related kobject references and other cleanups(such as inode->i_cdev being set to NULL) which prevents the OOPS upon subsequent loading, usage and unloading of modules(as seen in the mail thread http://marc.theaimsgroup.com/?l=linux-kernel&m=114533640609018&w=2). Also, remove unneeded test of gpio_base. Signed-off-by: Thayumanavar Sachithanantham Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/cs5535_gpio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c index 5d72f50de1ac..46d66037b917 100644 --- a/drivers/char/cs5535_gpio.c +++ b/drivers/char/cs5535_gpio.c @@ -241,9 +241,10 @@ static int __init cs5535_gpio_init(void) static void __exit cs5535_gpio_cleanup(void) { dev_t dev_id = MKDEV(major, 0); + + cdev_del(&cs5535_gpio_cdev); unregister_chrdev_region(dev_id, CS5535_GPIO_COUNT); - if (gpio_base != 0) - release_region(gpio_base, CS5535_GPIO_SIZE); + release_region(gpio_base, CS5535_GPIO_SIZE); } module_init(cs5535_gpio_init); -- cgit v1.2.3 From bf104e641c5a6567cc00d4ae9d8510cef9f63b18 Mon Sep 17 00:00:00 2001 From: Arnaud MAZIN Date: Thu, 20 Apr 2006 02:43:20 -0700 Subject: [PATCH] sonypi: correct detection of new ICH7-based laptops Add a test to detect the ICH7 based Core Duo SONY laptops (such as the SZ1) as type3 models. Signed-off-by: Arnaud MAZIN < arnaud.mazin@gmail.com> Acked-by: Stelian Pop Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/sonypi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index f8dd8527c6aa..a90f5d97df35 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1341,6 +1341,9 @@ static int __devinit sonypi_probe(struct platform_device *dev) else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; + else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_ICH7_1, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; else sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; -- cgit v1.2.3 From 8c4335a87c9785d2102ab23f09393038e1663314 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sat, 22 Apr 2006 02:36:15 -0700 Subject: [PATCH] Altix snsc: duplicate kobject fix from: Greg Howard Fix Altix system controller (snsc) device names to include the slot number of the blade whose associated system controller is the target of the device interface. Including the slot number avoids a problem we're currently having where slots within the same enclosure are attempting to create multiple kobjects with identical names. Signed-off-by: Greg Howard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/snsc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index b543821d8cb4..56c8243cdb73 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -390,7 +390,8 @@ scdrv_init(void) format_module_id(devnamep, geo_module(geoid), MODULE_FORMAT_BRIEF); devnamep = devname + strlen(devname); - sprintf(devnamep, "#%d", geo_slab(geoid)); + sprintf(devnamep, "^%d#%d", geo_slot(geoid), + geo_slab(geoid)); /* allocate sysctl device data */ scd = kzalloc(sizeof (struct sysctl_data_s), -- cgit v1.2.3 From 59e89f3a091d5cf93f4b176aedcfded61ece5252 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:36:35 -0700 Subject: [PATCH] tpm: fix memory leak The eventname was kmalloc'd and not freed in the *_show functions. This bug was found by Coverity. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_bios.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 537aa45d8c67..0549e2a35df8 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -306,6 +306,7 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) /* 5th: delimiter */ seq_putc(m, '\0'); + kfree(eventname); return 0; } @@ -353,6 +354,7 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) /* 4th: eventname <= max + \'0' delimiter */ seq_printf(m, " %s\n", eventname); + kfree(eventname); return 0; } -- cgit v1.2.3 From 7c69a47f1badf40dfa2febac71df98d32b1b56d7 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:36:46 -0700 Subject: [PATCH] tpm: fix missing string A string corresponding to the tcpa_pc_event_id POST_CONTENTS was missing causing an overflow bug when access was attempted in the get_event_name function. This bug was found by Coverity. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_bios.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 0549e2a35df8..5bcbaef53798 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -120,6 +120,7 @@ static const char* tcpa_pc_event_id_strings[] = { "S-CRTM Version", "S-CRTM Contents", "S-CRTM POST Contents", + "POST Contents", }; /* returns pointer to start of pos. entry of tcg log */ -- cgit v1.2.3 From 3c2f606a098b07f053904ec8b8f4d0e101c28b35 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:36:56 -0700 Subject: [PATCH] tpm: spacing cleanups The following patch set contains numerous changes to the base tpm driver (tpm.c) to support the next generation of TPM chips. The changes include new sysfs files because of more relevant data being available, a function to access the timeout and duration values for the chip, and changes to make use of those duration values. Duration in the TPM specification is defined as the maximum amount of time the chip could take to return the results. Commands are in one of three categories short, medium and long. Also included are cleanups of how the commands for the sysfs files are composed to reduce a bunch of redundant arrays. This patch: Fix minor spacing issues. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 5a3870477ef1..379c5d465579 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -46,7 +46,7 @@ static void user_reader_timeout(unsigned long ptr) schedule_work(&chip->work); } -static void timeout_work(void * ptr) +static void timeout_work(void *ptr) { struct tpm_chip *chip = ptr; @@ -387,7 +387,7 @@ int tpm_release(struct inode *inode, struct file *file) EXPORT_SYMBOL_GPL(tpm_release); ssize_t tpm_write(struct file *file, const char __user *buf, - size_t size, loff_t * off) + size_t size, loff_t *off) { struct tpm_chip *chip = file->private_data; int in_size = size, out_size; @@ -419,11 +419,10 @@ ssize_t tpm_write(struct file *file, const char __user *buf, return in_size; } - EXPORT_SYMBOL_GPL(tpm_write); -ssize_t tpm_read(struct file * file, char __user *buf, - size_t size, loff_t * off) +ssize_t tpm_read(struct file *file, char __user *buf, + size_t size, loff_t *off) { struct tpm_chip *chip = file->private_data; int ret_size; -- cgit v1.2.3 From beed53a1aaeaae4eb93297c23f1598a726716adf Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:05 -0700 Subject: [PATCH] tpm: reorganize sysfs files Many of the sysfs files were calling the TPM_GetCapability command with array. Since for 1.2 more sysfs files of this type are coming I am generalizing the array so there can be one array and the unique parts can be filled in just before the command is called. Signed-off-by: Kylene Hall Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 145 +++++++++++++++++++++++++++++-------------------- 1 file changed, 86 insertions(+), 59 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 379c5d465579..187bcdaf7bf6 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -119,17 +119,57 @@ out: } #define TPM_DIGEST_SIZE 20 -#define CAP_PCR_RESULT_SIZE 18 -static const u8 cap_pcr[] = { +#define TPM_ERROR_SIZE 10 +#define TPM_RET_CODE_IDX 6 +#define TPM_GET_CAP_RET_SIZE_IDX 10 +#define TPM_GET_CAP_RET_UINT32_1_IDX 14 +#define TPM_GET_CAP_RET_UINT32_2_IDX 18 +#define TPM_GET_CAP_RET_UINT32_3_IDX 22 +#define TPM_GET_CAP_RET_UINT32_4_IDX 26 + +#define TPM_CAP_IDX 13 +#define TPM_CAP_SUBCAP_IDX 21 + +enum tpm_capabilities { + TPM_CAP_PROP = 5, +}; + +enum tpm_sub_capabilities { + TPM_CAP_PROP_PCR = 0x1, + TPM_CAP_PROP_MANUFACTURER = 0x3, +}; + +/* + * This is a semi generic GetCapability command for use + * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG + * and their associated sub_capabilities. + */ + +static const u8 tpm_cap[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 22, /* length */ 0, 0, 0, 101, /* TPM_ORD_GetCapability */ - 0, 0, 0, 5, - 0, 0, 0, 4, - 0, 0, 1, 1 + 0, 0, 0, 0, /* TPM_CAP_ */ + 0, 0, 0, 4, /* TPM_CAP_SUB_ size */ + 0, 0, 1, 0 /* TPM_CAP_SUB_ */ }; -#define READ_PCR_RESULT_SIZE 30 +static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, + char *desc) +{ + int err; + + len = tpm_transmit(chip, data, len); + if (len < 0) + return len; + if (len == TPM_ERROR_SIZE) { + err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))); + dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); + return err; + } + return 0; +} + static const u8 pcrread[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 14, /* length */ @@ -140,8 +180,8 @@ static const u8 pcrread[] = { ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, char *buf) { - u8 data[READ_PCR_RESULT_SIZE]; - ssize_t len; + u8 data[30]; + ssize_t rc; int i, j, num_pcrs; __be32 index; char *str = buf; @@ -150,29 +190,24 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, if (chip == NULL) return -ENODEV; - memcpy(data, cap_pcr, sizeof(cap_pcr)); - if ((len = tpm_transmit(chip, data, sizeof(data))) - < CAP_PCR_RESULT_SIZE) { - dev_dbg(chip->dev, "A TPM error (%d) occurred " - "attempting to determine the number of PCRS\n", - be32_to_cpu(*((__be32 *) (data + 6)))); + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the number of PCRS"); + if (rc) return 0; - } num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); - for (i = 0; i < num_pcrs; i++) { memcpy(data, pcrread, sizeof(pcrread)); index = cpu_to_be32(i); memcpy(data + 10, &index, 4); - if ((len = tpm_transmit(chip, data, sizeof(data))) - < READ_PCR_RESULT_SIZE){ - dev_dbg(chip->dev, "A TPM error (%d) occurred" - " attempting to read PCR %d of %d\n", - be32_to_cpu(*((__be32 *) (data + 6))), - i, num_pcrs); + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to read a PCR"); + if (rc) goto out; - } str += sprintf(str, "PCR-%02d: ", i); for (j = 0; j < TPM_DIGEST_SIZE; j++) str += sprintf(str, "%02X ", *(data + 10 + j)); @@ -194,7 +229,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, char *buf) { u8 *data; - ssize_t len; + ssize_t err; int i, rc; char *str = buf; @@ -208,14 +243,10 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, memcpy(data, readpubek, sizeof(readpubek)); - if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) < - READ_PUBEK_RESULT_SIZE) { - dev_dbg(chip->dev, "A TPM error (%d) occurred " - "attempting to read the PUBEK\n", - be32_to_cpu(*((__be32 *) (data + 6)))); - rc = 0; + err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE, + "attempting to read the PUBEK"); + if (err) goto out; - } /* ignore header 10 bytes @@ -245,63 +276,59 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, if ((i + 1) % 16 == 0) str += sprintf(str, "\n"); } - rc = str - buf; out: + rc = str - buf; kfree(data); return rc; } EXPORT_SYMBOL_GPL(tpm_show_pubek); -#define CAP_VER_RESULT_SIZE 18 +#define CAP_VERSION_1_1 6 +#define CAP_VERSION_IDX 13 static const u8 cap_version[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 18, /* length */ 0, 0, 0, 101, /* TPM_ORD_GetCapability */ - 0, 0, 0, 6, + 0, 0, 0, 0, 0, 0, 0, 0 }; -#define CAP_MANUFACTURER_RESULT_SIZE 18 -static const u8 cap_manufacturer[] = { - 0, 193, /* TPM_TAG_RQU_COMMAND */ - 0, 0, 0, 22, /* length */ - 0, 0, 0, 101, /* TPM_ORD_GetCapability */ - 0, 0, 0, 5, - 0, 0, 0, 4, - 0, 0, 1, 3 -}; - ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, char *buf) { - u8 data[sizeof(cap_manufacturer)]; - ssize_t len; + u8 data[30]; + ssize_t rc; char *str = buf; struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) return -ENODEV; - memcpy(data, cap_manufacturer, sizeof(cap_manufacturer)); + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; - if ((len = tpm_transmit(chip, data, sizeof(data))) < - CAP_MANUFACTURER_RESULT_SIZE) - return len; + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the manufacturer"); + if (rc) + return 0; str += sprintf(str, "Manufacturer: 0x%x\n", - be32_to_cpu(*((__be32 *) (data + 14)))); + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); memcpy(data, cap_version, sizeof(cap_version)); + data[CAP_VERSION_IDX] = CAP_VERSION_1_1; + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the 1.1 version"); + if (rc) + goto out; - if ((len = tpm_transmit(chip, data, sizeof(data))) < - CAP_VER_RESULT_SIZE) - return len; - - str += - sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", - (int) data[14], (int) data[15], (int) data[16], - (int) data[17]); + str += sprintf(str, + "TCG version: %d.%d\nFirmware version: %d.%d\n", + (int) data[14], (int) data[15], (int) data[16], + (int) data[17]); +out: return str - buf; } EXPORT_SYMBOL_GPL(tpm_show_caps); -- cgit v1.2.3 From 90dda520c1962d55a0e1d2571deed0d75fd6d6f1 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:15 -0700 Subject: [PATCH] tpm: chip struct update To assist with chip management and better support the possibility of having multiple TPMs in the system of the same kind, the struct tpm_vendor_specific member of the tpm_chip was changed from a pointer to an instance. This patch changes that declaration and fixes up all accesses to the structure member except in tpm_infineon which is coming in a patch from Marcel Selhorst. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 48 +++++++++++++++++++++----------------------- drivers/char/tpm/tpm.h | 2 +- drivers/char/tpm/tpm_atmel.c | 26 ++++++++++++------------ drivers/char/tpm/tpm_nsc.c | 32 ++++++++++++++--------------- 4 files changed, 53 insertions(+), 55 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 187bcdaf7bf6..50013eb8cf1e 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -78,7 +78,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, down(&chip->tpm_mutex); - if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { + if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) { dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; @@ -86,13 +86,12 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, stop = jiffies + 2 * 60 * HZ; do { - u8 status = chip->vendor->status(chip); - if ((status & chip->vendor->req_complete_mask) == - chip->vendor->req_complete_val) { + u8 status = chip->vendor.status(chip); + if ((status & chip->vendor.req_complete_mask) == + chip->vendor.req_complete_val) goto out_recv; - } - if ((status == chip->vendor->req_canceled)) { + if ((status == chip->vendor.req_canceled)) { dev_err(chip->dev, "Operation Canceled\n"); rc = -ECANCELED; goto out; @@ -102,14 +101,13 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, rmb(); } while (time_before(jiffies, stop)); - - chip->vendor->cancel(chip); + chip->vendor.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->vendor.recv(chip, (u8 *) buf, bufsiz); if (rc < 0) dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); @@ -340,7 +338,7 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, if (chip == NULL) return 0; - chip->vendor->cancel(chip); + chip->vendor.cancel(chip); return count; } EXPORT_SYMBOL_GPL(tpm_store_cancel); @@ -356,7 +354,7 @@ int tpm_open(struct inode *inode, struct file *file) spin_lock(&driver_lock); list_for_each_entry(pos, &tpm_chip_list, list) { - if (pos->vendor->miscdev.minor == minor) { + if (pos->vendor.miscdev.minor == minor) { chip = pos; break; } @@ -488,14 +486,14 @@ void tpm_remove_hardware(struct device *dev) spin_unlock(&driver_lock); dev_set_drvdata(dev, NULL); - misc_deregister(&chip->vendor->miscdev); - kfree(chip->vendor->miscdev.name); + misc_deregister(&chip->vendor.miscdev); + kfree(chip->vendor.miscdev.name); - sysfs_remove_group(&dev->kobj, chip->vendor->attr_group); + sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); tpm_bios_log_teardown(chip->bios_dir); - dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= - ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); + dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES] &= + ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); kfree(chip); @@ -569,7 +567,7 @@ int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) chip->user_read_timer.function = user_reader_timeout; chip->user_read_timer.data = (unsigned long) chip; - chip->vendor = entry; + memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); chip->dev_num = -1; @@ -588,22 +586,22 @@ dev_num_search_complete: kfree(chip); return -ENODEV; } else if (chip->dev_num == 0) - chip->vendor->miscdev.minor = TPM_MINOR; + chip->vendor.miscdev.minor = TPM_MINOR; else - chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR; + chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); - chip->vendor->miscdev.name = devname; + chip->vendor.miscdev.name = devname; - chip->vendor->miscdev.dev = dev; + chip->vendor.miscdev.dev = dev; chip->dev = get_device(dev); - if (misc_register(&chip->vendor->miscdev)) { + 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); + chip->vendor.miscdev.name, + chip->vendor.miscdev.minor); put_device(dev); kfree(chip); dev_mask[i] &= !(1 << j); @@ -618,7 +616,7 @@ dev_num_search_complete: spin_unlock(&driver_lock); - sysfs_create_group(&dev->kobj, chip->vendor->attr_group); + sysfs_create_group(&dev->kobj, chip->vendor.attr_group); chip->bios_dir = tpm_bios_log_setup(devname); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index dec0224b4478..a203963efaab 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -81,7 +81,7 @@ struct tpm_chip { struct work_struct work; struct semaphore tpm_mutex; /* tpm is processing */ - struct tpm_vendor_specific *vendor; + struct tpm_vendor_specific vendor; struct dentry **bios_dir; diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index ff3654964fe3..26787976ef1a 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -47,12 +47,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) return -EIO; for (i = 0; i < 6; i++) { - status = ioread8(chip->vendor->iobase + 1); + status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { dev_err(chip->dev, "error reading header\n"); return -EIO; } - *buf++ = ioread8(chip->vendor->iobase); + *buf++ = ioread8(chip->vendor.iobase); } /* size of the data received */ @@ -63,7 +63,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) dev_err(chip->dev, "Recv size(%d) less than available space\n", size); for (; i < size; i++) { /* clear the waiting data anyway */ - status = ioread8(chip->vendor->iobase + 1); + status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { dev_err(chip->dev, "error reading data\n"); return -EIO; @@ -74,16 +74,16 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) /* read all the data available */ for (; i < size; i++) { - status = ioread8(chip->vendor->iobase + 1); + status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { dev_err(chip->dev, "error reading data\n"); return -EIO; } - *buf++ = ioread8(chip->vendor->iobase); + *buf++ = ioread8(chip->vendor.iobase); } /* make sure data available is gone */ - status = ioread8(chip->vendor->iobase + 1); + status = ioread8(chip->vendor.iobase + 1); if (status & ATML_STATUS_DATA_AVAIL) { dev_err(chip->dev, "data available is stuck\n"); @@ -100,7 +100,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) dev_dbg(chip->dev, "tpm_atml_send:\n"); for (i = 0; i < count; i++) { dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); - iowrite8(buf[i], chip->vendor->iobase); + iowrite8(buf[i], chip->vendor.iobase); } return count; @@ -108,12 +108,12 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) static void tpm_atml_cancel(struct tpm_chip *chip) { - iowrite8(ATML_STATUS_ABORT, chip->vendor->iobase + 1); + iowrite8(ATML_STATUS_ABORT, chip->vendor.iobase + 1); } static u8 tpm_atml_status(struct tpm_chip *chip) { - return ioread8(chip->vendor->iobase + 1); + return ioread8(chip->vendor.iobase + 1); } static struct file_operations atmel_ops = { @@ -159,10 +159,10 @@ static void atml_plat_remove(void) struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); if (chip) { - if (chip->vendor->have_region) - atmel_release_region(chip->vendor->base, - chip->vendor->region_size); - atmel_put_base_addr(chip->vendor); + if (chip->vendor.have_region) + atmel_release_region(chip->vendor.base, + chip->vendor.region_size); + atmel_put_base_addr(chip->vendor.iobase); tpm_remove_hardware(chip->dev); platform_device_unregister(pdev); } diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 680a8e331887..3dbbe9686c76 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -71,7 +71,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) unsigned long stop; /* status immediately available check */ - *data = inb(chip->vendor->base + NSC_STATUS); + *data = inb(chip->vendor.base + NSC_STATUS); if ((*data & mask) == val) return 0; @@ -79,7 +79,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) stop = jiffies + 10 * HZ; do { msleep(TPM_TIMEOUT); - *data = inb(chip->vendor->base + 1); + *data = inb(chip->vendor.base + 1); if ((*data & mask) == val) return 0; } @@ -94,9 +94,9 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) unsigned long stop; /* status immediately available check */ - status = inb(chip->vendor->base + NSC_STATUS); + status = inb(chip->vendor.base + NSC_STATUS); if (status & NSC_STATUS_OBF) - status = inb(chip->vendor->base + NSC_DATA); + status = inb(chip->vendor.base + NSC_DATA); if (status & NSC_STATUS_RDY) return 0; @@ -104,9 +104,9 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) stop = jiffies + 100; do { msleep(TPM_TIMEOUT); - status = inb(chip->vendor->base + NSC_STATUS); + status = inb(chip->vendor.base + NSC_STATUS); if (status & NSC_STATUS_OBF) - status = inb(chip->vendor->base + NSC_DATA); + status = inb(chip->vendor.base + NSC_DATA); if (status & NSC_STATUS_RDY) return 0; } @@ -132,7 +132,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; } if ((data = - inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) { + inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) { dev_err(chip->dev, "not in normal mode (0x%x)\n", data); return -EIO; @@ -148,7 +148,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) } if (data & NSC_STATUS_F0) break; - *p = inb(chip->vendor->base + NSC_DATA); + *p = inb(chip->vendor.base + NSC_DATA); } if ((data & NSC_STATUS_F0) == 0 && @@ -156,7 +156,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) dev_err(chip->dev, "F0 not set\n"); return -EIO; } - if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) { + if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) { dev_err(chip->dev, "expected end of command(0x%x)\n", data); return -EIO; @@ -182,7 +182,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) * fix it. Not sure why this is needed, we followed the flow * chart in the manual to the letter. */ - outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND); + outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND); if (nsc_wait_for_ready(chip) != 0) return -EIO; @@ -192,7 +192,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; } - outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND); + outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND); if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) { dev_err(chip->dev, "IBR timeout\n"); return -EIO; @@ -204,26 +204,26 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) "IBF timeout (while writing data)\n"); return -EIO; } - outb(buf[i], chip->vendor->base + NSC_DATA); + outb(buf[i], chip->vendor.base + NSC_DATA); } if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { dev_err(chip->dev, "IBF timeout\n"); return -EIO; } - outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND); + outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND); return count; } static void tpm_nsc_cancel(struct tpm_chip *chip) { - outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND); + outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND); } static u8 tpm_nsc_status(struct tpm_chip *chip) { - return inb(chip->vendor->base + NSC_STATUS); + return inb(chip->vendor.base + NSC_STATUS); } static struct file_operations nsc_ops = { @@ -268,7 +268,7 @@ static void __devexit tpm_nsc_remove(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); if ( chip ) { - release_region(chip->vendor->base, 2); + release_region(chip->vendor.base, 2); tpm_remove_hardware(chip->dev); } } -- cgit v1.2.3 From e0dd03caf20d040a0a86b6bd74028ec9bda545f5 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:26 -0700 Subject: [PATCH] tpm: return chip from tpm_register_hardware Changes in the 1.2 TPM Specification make it necessary to update some fields of the chip structure in the initialization function after it is registered with tpm.c thus tpm_register_hardware was modified to return a pointer to the structure. This patch makes that change and the associated changes in tpm_atmel and tpm_nsc. The changes to tpm_infineon will be coming in a patch from Marcel Selhorst. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 11 ++++++----- drivers/char/tpm/tpm.h | 10 +++++----- drivers/char/tpm/tpm_atmel.c | 32 ++++++++++++++++++++++---------- drivers/char/tpm/tpm_atmel.h | 25 +++++++++++-------------- drivers/char/tpm/tpm_nsc.c | 17 +++++++++++------ 5 files changed, 55 insertions(+), 40 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 50013eb8cf1e..5e58296f2832 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -544,7 +544,8 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); * upon errant exit from this function specific probe function should call * pci_disable_device */ -int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) +struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific + *entry) { #define DEVNAME_SIZE 7 @@ -555,7 +556,7 @@ int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) /* Driver specific per-device data */ chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) - return -ENOMEM; + return NULL; init_MUTEX(&chip->buffer_mutex); init_MUTEX(&chip->tpm_mutex); @@ -584,7 +585,7 @@ dev_num_search_complete: if (chip->dev_num < 0) { dev_err(dev, "No available tpm device numbers\n"); kfree(chip); - return -ENODEV; + return NULL; } else if (chip->dev_num == 0) chip->vendor.miscdev.minor = TPM_MINOR; else @@ -605,7 +606,7 @@ dev_num_search_complete: put_device(dev); kfree(chip); dev_mask[i] &= !(1 << j); - return -ENODEV; + return NULL; } spin_lock(&driver_lock); @@ -620,7 +621,7 @@ dev_num_search_complete: chip->bios_dir = tpm_bios_log_setup(devname); - return 0; + return chip; } EXPORT_SYMBOL_GPL(tpm_register_hardware); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index a203963efaab..4f005345bf37 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -48,9 +48,9 @@ extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, struct tpm_chip; struct tpm_vendor_specific { - u8 req_complete_mask; - u8 req_complete_val; - u8 req_canceled; + const u8 req_complete_mask; + const u8 req_complete_val; + const u8 req_canceled; void __iomem *iobase; /* ioremapped address */ unsigned long base; /* TPM base address */ @@ -100,8 +100,8 @@ static inline void tpm_write_index(int base, int index, int value) outb(value & 0xFF, base+1); } -extern int tpm_register_hardware(struct device *, - struct tpm_vendor_specific *); +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 ssize_t tpm_write(struct file *, const char __user *, size_t, diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 26787976ef1a..58a258cec153 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -140,7 +140,7 @@ static struct attribute* atmel_attrs[] = { static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; -static struct tpm_vendor_specific tpm_atmel = { +static const struct tpm_vendor_specific tpm_atmel = { .recv = tpm_atml_recv, .send = tpm_atml_send, .cancel = tpm_atml_cancel, @@ -179,18 +179,22 @@ static struct device_driver atml_drv = { static int __init init_atmel(void) { int rc = 0; + void __iomem *iobase = NULL; + int have_region, region_size; + unsigned long base; + struct tpm_chip *chip; driver_register(&atml_drv); - if ((tpm_atmel.iobase = atmel_get_base_addr(&tpm_atmel)) == NULL) { + if ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) { rc = -ENODEV; goto err_unreg_drv; } - tpm_atmel.have_region = + have_region = (atmel_request_region - (tpm_atmel.base, tpm_atmel.region_size, - "tpm_atmel0") == NULL) ? 0 : 1; + (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; + if (IS_ERR (pdev = @@ -199,17 +203,25 @@ static int __init init_atmel(void) goto err_rel_reg; } - if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) + if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) { + rc = -ENODEV; goto err_unreg_dev; + } + + chip->vendor.iobase = iobase; + chip->vendor.base = base; + chip->vendor.have_region = have_region; + chip->vendor.region_size = region_size; + return 0; err_unreg_dev: platform_device_unregister(pdev); err_rel_reg: - atmel_put_base_addr(&tpm_atmel); - if (tpm_atmel.have_region) - atmel_release_region(tpm_atmel.base, - tpm_atmel.region_size); + atmel_put_base_addr(iobase); + if (have_region) + atmel_release_region(base, + region_size); err_unreg_drv: driver_unregister(&atml_drv); return rc; diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h index d3478aaadd77..2e68eeb8a2cd 100644 --- a/drivers/char/tpm/tpm_atmel.h +++ b/drivers/char/tpm/tpm_atmel.h @@ -28,13 +28,12 @@ #define atmel_request_region request_mem_region #define atmel_release_region release_mem_region -static inline void atmel_put_base_addr(struct tpm_vendor_specific - *vendor) +static inline void atmel_put_base_addr(void __iomem *iobase) { - iounmap(vendor->iobase); + iounmap(iobase); } -static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific *vendor) +static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) { struct device_node *dn; unsigned long address, size; @@ -71,9 +70,9 @@ static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific *vendor) else size = reg[naddrc]; - vendor->base = address; - vendor->region_size = size; - return ioremap(vendor->base, vendor->region_size); + *base = address; + *region_size = size; + return ioremap(*base, *region_size); } #else #define atmel_getb(chip, offset) inb(chip->vendor->base + offset) @@ -106,14 +105,12 @@ static int atmel_verify_tpm11(void) return 0; } -static inline void atmel_put_base_addr(struct tpm_vendor_specific - *vendor) +static inline void atmel_put_base_addr(void __iomem *iobase) { } /* Determine where to talk to device */ -static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific - *vendor) +static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) { int lo, hi; @@ -123,9 +120,9 @@ static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); - vendor->base = (hi << 8) | lo; - vendor->region_size = 2; + *base = (hi << 8) | lo; + *region_size = 2; - return ioport_map(vendor->base, vendor->region_size); + return ioport_map(*base, *region_size); } #endif diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 3dbbe9686c76..4c8bc06c7d95 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -250,7 +250,7 @@ static struct attribute * nsc_attrs[] = { static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; -static struct tpm_vendor_specific tpm_nsc = { +static const struct tpm_vendor_specific tpm_nsc = { .recv = tpm_nsc_recv, .send = tpm_nsc_send, .cancel = tpm_nsc_cancel, @@ -286,7 +286,8 @@ static int __init init_nsc(void) int rc = 0; int lo, hi; int nscAddrBase = TPM_ADDR; - + struct tpm_chip *chip; + unsigned long base; /* verify that it is a National part (SID) */ if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) { @@ -300,7 +301,7 @@ static int __init init_nsc(void) hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); - tpm_nsc.base = (hi<<8) | lo; + base = (hi<<8) | lo; /* enable the DPM module */ tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); @@ -320,13 +321,15 @@ static int __init init_nsc(void) if ((rc = platform_device_register(pdev)) < 0) goto err_free_dev; - if (request_region(tpm_nsc.base, 2, "tpm_nsc0") == NULL ) { + if (request_region(base, 2, "tpm_nsc0") == NULL ) { rc = -EBUSY; goto err_unreg_dev; } - if ((rc = tpm_register_hardware(&pdev->dev, &tpm_nsc)) < 0) + if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) { + rc = -ENODEV; goto err_rel_reg; + } dev_dbg(&pdev->dev, "NSC TPM detected\n"); dev_dbg(&pdev->dev, @@ -361,10 +364,12 @@ static int __init init_nsc(void) "NSC TPM revision %d\n", tpm_read_index(nscAddrBase, 0x27) & 0x1F); + chip->vendor.base = base; + return 0; err_rel_reg: - release_region(tpm_nsc.base, 2); + release_region(base, 2); err_unreg_dev: platform_device_unregister(pdev); err_free_dev: -- cgit v1.2.3 From 9e18ee19179a7742999d0e2d4bfcba75b5562439 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:38 -0700 Subject: [PATCH] tpm: command duration update With the TPM 1.2 Specification, each command is classified as short, medium or long and the chip tells you the maximum amount of time for a response to each class of command. This patch provides and array of the classifications and a function to determine how long the response should be waited for. Also, it uses that information in the command processing to determine how long to poll for. The function is exported so the 1.2 driver can use the functionality to determine how long to wait for a DataAvailable interrupt if interrupts are being used. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++++- drivers/char/tpm/tpm.h | 2 + 2 files changed, 311 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 5e58296f2832..e54bcb4e4e3e 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -35,10 +35,290 @@ enum tpm_const { TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) }; +enum tpm_duration { + TPM_SHORT = 0, + TPM_MEDIUM = 1, + TPM_LONG = 2, + TPM_UNDEFINED, +}; + +#define TPM_MAX_ORDINAL 243 +#define TPM_MAX_PROTECTED_ORDINAL 12 +#define TPM_PROTECTED_ORDINAL_MASK 0xFF + static LIST_HEAD(tpm_chip_list); static DEFINE_SPINLOCK(driver_lock); static int dev_mask[TPM_NUM_MASK_ENTRIES]; +/* + * Array with one entry per ordinal defining the maximum amount + * of time the chip could take to return the result. The ordinal + * designation of short, medium or long is defined in a table in + * TCG Specification TPM Main Part 2 TPM Structures Section 17. The + * values of the SHORT, MEDIUM, and LONG durations are retrieved + * from the chip during initialization with a call to tpm_get_timeouts. + */ +static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = { + TPM_UNDEFINED, /* 0 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 5 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 10 */ + TPM_SHORT, +}; + +static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { + TPM_UNDEFINED, /* 0 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 5 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 10 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_LONG, + TPM_LONG, + TPM_MEDIUM, /* 15 */ + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, + TPM_LONG, + TPM_SHORT, /* 20 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, /* 25 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 30 */ + TPM_LONG, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 35 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 40 */ + TPM_LONG, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 45 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_LONG, + TPM_MEDIUM, /* 50 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 55 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 60 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 65 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 70 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 75 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 80 */ + TPM_UNDEFINED, + TPM_MEDIUM, + TPM_LONG, + TPM_SHORT, + TPM_UNDEFINED, /* 85 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 90 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 95 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 100 */ + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 105 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 110 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 115 */ + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 120 */ + TPM_LONG, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 125 */ + TPM_SHORT, + TPM_LONG, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 130 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_SHORT, + TPM_MEDIUM, + TPM_UNDEFINED, /* 135 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 140 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 145 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 150 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 155 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 160 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 165 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 170 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 175 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 180 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, /* 185 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 190 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 195 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 200 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 205 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 210 */ + TPM_UNDEFINED, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_UNDEFINED, /* 215 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 220 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 225 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 230 */ + TPM_LONG, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 235 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 240 */ + TPM_UNDEFINED, + TPM_MEDIUM, +}; + static void user_reader_timeout(unsigned long ptr) { struct tpm_chip *chip = (struct tpm_chip *) ptr; @@ -56,6 +336,32 @@ static void timeout_work(void *ptr) up(&chip->buffer_mutex); } +/* + * Returns max number of jiffies to wait + */ +unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, + u32 ordinal) +{ + int duration_idx = TPM_UNDEFINED; + int duration = 0; + + if (ordinal < TPM_MAX_ORDINAL) + duration_idx = tpm_ordinal_duration[ordinal]; + else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < + TPM_MAX_PROTECTED_ORDINAL) + duration_idx = + tpm_protected_ordinal_duration[ordinal & + TPM_PROTECTED_ORDINAL_MASK]; + + if (duration_idx != TPM_UNDEFINED) + duration = chip->vendor.duration[duration_idx] * HZ / 1000; + if (duration <= 0) + return 2 * 60 * HZ; + else + return duration; +} +EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); + /* * Internal kernel interface to transmit TPM commands */ @@ -63,11 +369,11 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, size_t bufsiz) { ssize_t rc; - u32 count; + u32 count, ordinal; unsigned long stop; count = be32_to_cpu(*((__be32 *) (buf + 2))); - + ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); if (count == 0) return -ENODATA; if (count > bufsiz) { @@ -84,7 +390,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, goto out; } - stop = jiffies + 2 * 60 * HZ; + stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->vendor.status(chip); if ((status & chip->vendor.req_complete_mask) == diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 4f005345bf37..1d28485b8fb3 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -63,6 +63,7 @@ struct tpm_vendor_specific { u8 (*status) (struct tpm_chip *); struct miscdevice miscdev; struct attribute_group *attr_group; + u32 duration[3]; }; struct tpm_chip { @@ -100,6 +101,7 @@ static inline void tpm_write_index(int base, int index, int value) outb(value & 0xFF, base+1); } +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 *); -- cgit v1.2.3 From 08e96e486dd1345ae0ad70247387d0d4fd346889 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:50 -0700 Subject: [PATCH] tpm: new 1.2 sysfs files Many of the sysfs files were calling the TPM_GetCapability command with array. Since for 1.2 more sysfs files of this type are coming I am generalizing the array so there can be one array and the unique parts can be filled in just before the command is called. This updated version of the patch breaks the multi-value sysfs file into separate files pointed out by Greg. It also addresses the code redundancy and ugliness in the tpm_show_* functions pointed out on another patch by Dave Hansen. Signed-off-by: Kylene Hall Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++- drivers/char/tpm/tpm.h | 14 +++ 2 files changed, 247 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index e54bcb4e4e3e..24c4423d4851 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -430,17 +430,27 @@ out: #define TPM_GET_CAP_RET_UINT32_2_IDX 18 #define TPM_GET_CAP_RET_UINT32_3_IDX 22 #define TPM_GET_CAP_RET_UINT32_4_IDX 26 +#define TPM_GET_CAP_PERM_DISABLE_IDX 16 +#define TPM_GET_CAP_PERM_INACTIVE_IDX 18 +#define TPM_GET_CAP_RET_BOOL_1_IDX 14 +#define TPM_GET_CAP_TEMP_INACTIVE_IDX 16 #define TPM_CAP_IDX 13 #define TPM_CAP_SUBCAP_IDX 21 enum tpm_capabilities { + TPM_CAP_FLAG = 4, TPM_CAP_PROP = 5, }; enum tpm_sub_capabilities { TPM_CAP_PROP_PCR = 0x1, TPM_CAP_PROP_MANUFACTURER = 0x3, + TPM_CAP_FLAG_PERM = 0x8, + TPM_CAP_FLAG_VOL = 0x9, + TPM_CAP_PROP_OWNER = 0x11, + TPM_CAP_PROP_TIS_TIMEOUT = 0x15, + TPM_CAP_PROP_TIS_DURATION = 0x20, }; /* @@ -474,6 +484,180 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, return 0; } +void tpm_gen_interrupt(struct tpm_chip *chip) +{ + u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; + ssize_t rc; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the timeouts"); +} +EXPORT_SYMBOL_GPL(tpm_gen_interrupt); + +void tpm_get_timeouts(struct tpm_chip *chip) +{ + u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; + ssize_t rc; + u32 timeout; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the timeouts"); + if (rc) + goto duration; + + if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) + != 4 * sizeof(u32)) + goto duration; + + /* Don't overwrite default if value is 0 */ + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); + if (timeout) + chip->vendor.timeout_a = timeout; + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); + if (timeout) + chip->vendor.timeout_b = timeout; + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); + if (timeout) + chip->vendor.timeout_c = timeout; + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); + if (timeout) + chip->vendor.timeout_d = timeout; + +duration: + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the durations"); + if (rc) + return; + + if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) + != 3 * sizeof(u32)) + return; + + chip->vendor.duration[TPM_SHORT] = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); + chip->vendor.duration[TPM_MEDIUM] = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); + chip->vendor.duration[TPM_LONG] = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); +} +EXPORT_SYMBOL_GPL(tpm_get_timeouts); + +void tpm_continue_selftest(struct tpm_chip *chip) +{ + u8 data[] = { + 0, 193, /* TPM_TAG_RQU_COMMAND */ + 0, 0, 0, 10, /* length */ + 0, 0, 0, 83, /* TPM_ORD_GetCapability */ + }; + + tpm_transmit(chip, data, sizeof(data)); +} +EXPORT_SYMBOL_GPL(tpm_continue_selftest); + +ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, + char *buf) +{ + u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; + ssize_t rc; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_FLAG; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; + + rc = transmit_cmd(chip, data, sizeof(data), + "attemtping to determine the permanent state"); + if (rc) + return 0; + return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); +} +EXPORT_SYMBOL_GPL(tpm_show_enabled); + +ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, + char *buf) +{ + u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; + ssize_t rc; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_FLAG; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; + + rc = transmit_cmd(chip, data, sizeof(data), + "attemtping to determine the permanent state"); + if (rc) + return 0; + return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); +} +EXPORT_SYMBOL_GPL(tpm_show_active); + +ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, + char *buf) +{ + u8 data[sizeof(tpm_cap)]; + ssize_t rc; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the owner state"); + if (rc) + return 0; + return sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); +} +EXPORT_SYMBOL_GPL(tpm_show_owned); + +ssize_t tpm_show_temp_deactivated(struct device * dev, + struct device_attribute * attr, char *buf) +{ + u8 data[sizeof(tpm_cap)]; + ssize_t rc; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_FLAG; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the temporary state"); + if (rc) + return 0; + return sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); +} +EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); + static const u8 pcrread[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 14, /* length */ @@ -484,7 +668,7 @@ static const u8 pcrread[] = { ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, char *buf) { - u8 data[30]; + u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)), 30)]; ssize_t rc; int i, j, num_pcrs; __be32 index; @@ -588,6 +772,7 @@ out: EXPORT_SYMBOL_GPL(tpm_show_pubek); #define CAP_VERSION_1_1 6 +#define CAP_VERSION_1_2 0x1A #define CAP_VERSION_IDX 13 static const u8 cap_version[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ @@ -600,7 +785,7 @@ static const u8 cap_version[] = { ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, char *buf) { - u8 data[30]; + u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; ssize_t rc; char *str = buf; @@ -637,6 +822,52 @@ out: } EXPORT_SYMBOL_GPL(tpm_show_caps); +ssize_t tpm_show_caps_1_2(struct device * dev, + struct device_attribute * attr, char *buf) +{ + u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; + ssize_t len; + char *str = buf; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; + + if ((len = tpm_transmit(chip, data, sizeof(data))) <= + TPM_ERROR_SIZE) { + dev_dbg(chip->dev, "A TPM error (%d) occurred " + "attempting to determine the manufacturer\n", + be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); + return 0; + } + + str += sprintf(str, "Manufacturer: 0x%x\n", + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); + + memcpy(data, cap_version, sizeof(cap_version)); + data[CAP_VERSION_IDX] = CAP_VERSION_1_2; + + if ((len = tpm_transmit(chip, data, sizeof(data))) <= + TPM_ERROR_SIZE) { + dev_err(chip->dev, "A TPM error (%d) occurred " + "attempting to determine the 1.2 version\n", + be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); + goto out; + } + str += sprintf(str, + "TCG version: %d.%d\nFirmware version: %d.%d\n", + (int) data[16], (int) data[17], (int) data[18], + (int) data[19]); + +out: + return str - buf; +} +EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); + ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 1d28485b8fb3..75d105c4e65d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -42,8 +42,18 @@ extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, char *); extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, char *); +extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr, + char *); extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, const char *, size_t); +extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr, + char *); +extern ssize_t tpm_show_active(struct device *, struct device_attribute *attr, + char *); +extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr, + char *); +extern ssize_t tpm_show_temp_deactivated(struct device *, + struct device_attribute *attr, char *); struct tpm_chip; @@ -63,6 +73,7 @@ struct tpm_vendor_specific { u8 (*status) (struct tpm_chip *); struct miscdevice miscdev; struct attribute_group *attr_group; + u32 timeout_a, timeout_b, timeout_c, timeout_d; u32 duration[3]; }; @@ -101,6 +112,9 @@ static inline void tpm_write_index(int base, int index, int value) outb(value & 0xFF, base+1); } +extern void tpm_get_timeouts(struct tpm_chip *); +extern void tpm_gen_interrupt(struct tpm_chip *); +extern void tpm_continue_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 *); -- cgit v1.2.3 From 27084efee0c3dc0eb15b5ed750aa9f1adb3983c3 Mon Sep 17 00:00:00 2001 From: Leendert van Doorn Date: Sat, 22 Apr 2006 02:38:03 -0700 Subject: [PATCH] tpm: driver for next generation TPM chips The driver for the next generation of TPM chips version 1.2 including support for interrupts. The Trusted Computing Group has written the TPM Interface Specification (TIS) which defines a common interface for all manufacturer's 1.2 TPM's thus the name tpm_tis. Signed-off-by: Leendert van Doorn Signed-off-by: Kylene Hall Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/Kconfig | 11 +- drivers/char/tpm/Makefile | 1 + drivers/char/tpm/tpm.c | 3 + drivers/char/tpm/tpm.h | 9 + drivers/char/tpm/tpm_tis.c | 647 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 670 insertions(+), 1 deletion(-) create mode 100644 drivers/char/tpm/tpm_tis.c (limited to 'drivers/char') diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index a6873bf89ffa..1efde3b27619 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -20,9 +20,18 @@ config TCG_TPM Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI and CONFIG_PNPACPI. +config TCG_TIS + tristate "TPM Interface Specification 1.2 Interface" + depends on TCG_TPM + ---help--- + If you have a TPM security chip that is compliant with the + TCG TIS 1.2 TPM specification say Yes and it will be accessible + from within Linux. To compile this driver as a module, choose + M here; the module will be called tpm_tis. + config TCG_NSC tristate "National Semiconductor TPM Interface" - depends on TCG_TPM + depends on TCG_TPM && PNPACPI ---help--- If you have a TPM security chip from National Semicondutor say Yes and it will be accessible from within Linux. To diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index ba4582d160fd..ea3a1e02a824 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_TCG_TPM) += tpm.o ifdef CONFIG_ACPI obj-$(CONFIG_TCG_TPM) += tpm_bios.o endif +obj-$(CONFIG_TCG_TIS) += tpm_tis.o obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 24c4423d4851..150c86af7809 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -390,6 +390,9 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, goto out; } + if (chip->vendor.irq) + goto out_recv; + stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->vendor.status(chip); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 75d105c4e65d..24541a556d02 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -64,6 +64,8 @@ struct tpm_vendor_specific { void __iomem *iobase; /* ioremapped address */ unsigned long base; /* TPM base address */ + int irq; + int region_size; int have_region; @@ -73,8 +75,13 @@ struct tpm_vendor_specific { u8 (*status) (struct tpm_chip *); struct miscdevice miscdev; struct attribute_group *attr_group; + struct list_head list; + int locality; u32 timeout_a, timeout_b, timeout_c, timeout_d; u32 duration[3]; + + wait_queue_head_t read_queue; + wait_queue_head_t int_queue; }; struct tpm_chip { @@ -100,6 +107,8 @@ struct tpm_chip { struct list_head list; }; +#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) + static inline int tpm_read_index(int base, int index) { outb(index, base); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c new file mode 100644 index 000000000000..02759307f736 --- /dev/null +++ b/drivers/char/tpm/tpm_tis.c @@ -0,0 +1,647 @@ +/* + * Copyright (C) 2005, 2006 IBM Corporation + * + * Authors: + * Leendert van Doorn + * Kylene Hall + * + * Device driver for TCG/TCPA TPM (trusted platform module). + * Specifications at www.trustedcomputinggroup.org + * + * This device driver implements the TPM interface as defined in + * the TCG TPM Interface Spec version 1.2, revision 1.0. + * + * 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 +#include +#include +#include "tpm.h" + +#define TPM_HEADER_SIZE 10 + +enum tis_access { + TPM_ACCESS_VALID = 0x80, + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, + TPM_ACCESS_REQUEST_PENDING = 0x04, + TPM_ACCESS_REQUEST_USE = 0x02, +}; + +enum tis_status { + TPM_STS_VALID = 0x80, + TPM_STS_COMMAND_READY = 0x40, + TPM_STS_GO = 0x20, + TPM_STS_DATA_AVAIL = 0x10, + TPM_STS_DATA_EXPECT = 0x08, +}; + +enum tis_int_flags { + TPM_GLOBAL_INT_ENABLE = 0x80000000, + TPM_INTF_BURST_COUNT_STATIC = 0x100, + TPM_INTF_CMD_READY_INT = 0x080, + TPM_INTF_INT_EDGE_FALLING = 0x040, + TPM_INTF_INT_EDGE_RISING = 0x020, + TPM_INTF_INT_LEVEL_LOW = 0x010, + TPM_INTF_INT_LEVEL_HIGH = 0x008, + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, + TPM_INTF_STS_VALID_INT = 0x002, + TPM_INTF_DATA_AVAIL_INT = 0x001, +}; + +#define TPM_ACCESS(l) (0x0000 | ((l) << 12)) +#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) +#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12)) +#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12)) +#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12)) +#define TPM_STS(l) (0x0018 | ((l) << 12)) +#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12)) + +#define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) +#define TPM_RID(l) (0x0F04 | ((l) << 12)) + +static LIST_HEAD(tis_chips); +static DEFINE_SPINLOCK(tis_lock); + +static int check_locality(struct tpm_chip *chip, int l) +{ + if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) & + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) + return chip->vendor.locality = l; + + return -1; +} + +static void release_locality(struct tpm_chip *chip, int l, int force) +{ + if (force || (ioread8(chip->vendor.iobase + TPM_ACCESS(l)) & + (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == + (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) + iowrite8(TPM_ACCESS_ACTIVE_LOCALITY, + chip->vendor.iobase + TPM_ACCESS(l)); +} + +static int request_locality(struct tpm_chip *chip, int l) +{ + unsigned long stop; + long rc; + + if (check_locality(chip, l) >= 0) + return l; + + iowrite8(TPM_ACCESS_REQUEST_USE, + chip->vendor.iobase + TPM_ACCESS(l)); + + if (chip->vendor.irq) { + rc = wait_event_interruptible_timeout(chip->vendor. + int_queue, + (check_locality + (chip, l) >= 0), + msecs_to_jiffies + (chip->vendor. + timeout_a)); + if (rc > 0) + return l; + + } else { + /* wait for burstcount */ + stop = jiffies + (HZ * chip->vendor.timeout_a / 1000); + do { + if (check_locality(chip, l) >= 0) + return l; + msleep(TPM_TIMEOUT); + } + while (time_before(jiffies, stop)); + } + return -1; +} + +static u8 tpm_tis_status(struct tpm_chip *chip) +{ + return ioread8(chip->vendor.iobase + + TPM_STS(chip->vendor.locality)); +} + +static void tpm_tis_ready(struct tpm_chip *chip) +{ + /* this causes the current command to be aborted */ + iowrite8(TPM_STS_COMMAND_READY, + chip->vendor.iobase + TPM_STS(chip->vendor.locality)); +} + +static int get_burstcount(struct tpm_chip *chip) +{ + unsigned long stop; + int burstcnt; + + /* wait for burstcount */ + /* which timeout value, spec has 2 answers (c & d) */ + stop = jiffies + (HZ * chip->vendor.timeout_d / 1000); + do { + burstcnt = ioread8(chip->vendor.iobase + + TPM_STS(chip->vendor.locality) + 1); + burstcnt += ioread8(chip->vendor.iobase + + TPM_STS(chip->vendor.locality) + + 2) << 8; + if (burstcnt) + return burstcnt; + msleep(TPM_TIMEOUT); + } while (time_before(jiffies, stop)); + return -EBUSY; +} + +static int wait_for_stat(struct tpm_chip *chip, u8 mask, u32 timeout, + wait_queue_head_t *queue) +{ + unsigned long stop; + long rc; + u8 status; + + /* check current status */ + status = tpm_tis_status(chip); + if ((status & mask) == mask) + return 0; + + if (chip->vendor.irq) { + rc = wait_event_interruptible_timeout(*queue, + ((tpm_tis_status + (chip) & mask) == + mask), + msecs_to_jiffies + (timeout)); + if (rc > 0) + return 0; + } else { + stop = jiffies + (HZ * timeout / 1000); + do { + msleep(TPM_TIMEOUT); + status = tpm_tis_status(chip); + if ((status & mask) == mask) + return 0; + } while (time_before(jiffies, stop)); + } + return -ETIME; +} + +static int recv_data(struct tpm_chip *chip, u8 * buf, size_t count) +{ + int size = 0, burstcnt; + while (size < count && + wait_for_stat(chip, + TPM_STS_DATA_AVAIL | TPM_STS_VALID, + chip->vendor.timeout_c, + &chip->vendor.read_queue) + == 0) { + burstcnt = get_burstcount(chip); + for (; burstcnt > 0 && size < count; burstcnt--) + buf[size++] = ioread8(chip->vendor.iobase + + TPM_DATA_FIFO(chip->vendor. + locality)); + } + return size; +} + +static int tpm_tis_recv(struct tpm_chip *chip, u8 * buf, size_t count) +{ + int size = 0; + int expected, status; + + if (count < TPM_HEADER_SIZE) { + size = -EIO; + goto out; + } + + /* read first 10 bytes, including tag, paramsize, and result */ + if ((size = + recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) { + dev_err(chip->dev, "Unable to read header\n"); + goto out; + } + + expected = be32_to_cpu(*(__be32 *) (buf + 2)); + if (expected > count) { + size = -EIO; + goto out; + } + + if ((size += + recv_data(chip, &buf[TPM_HEADER_SIZE], + expected - TPM_HEADER_SIZE)) < expected) { + dev_err(chip->dev, "Unable to read remainder of result\n"); + size = -ETIME; + goto out; + } + + wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, + &chip->vendor.int_queue); + status = tpm_tis_status(chip); + if (status & TPM_STS_DATA_AVAIL) { /* retry? */ + dev_err(chip->dev, "Error left over data\n"); + size = -EIO; + goto out; + } + +out: + tpm_tis_ready(chip); + release_locality(chip, chip->vendor.locality, 0); + return size; +} + +/* + * If interrupts are used (signaled by an irq set in the vendor structure) + * tpm.c can skip polling for the data to be available as the interrupt is + * waited for here + */ +static int tpm_tis_send(struct tpm_chip *chip, u8 * buf, size_t len) +{ + int rc, status, burstcnt; + size_t count = 0; + u32 ordinal; + + if (request_locality(chip, 0) < 0) + return -EBUSY; + + status = tpm_tis_status(chip); + if ((status & TPM_STS_COMMAND_READY) == 0) { + tpm_tis_ready(chip); + if (wait_for_stat + (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, + &chip->vendor.int_queue) < 0) { + rc = -ETIME; + goto out_err; + } + } + + while (count < len - 1) { + burstcnt = get_burstcount(chip); + for (; burstcnt > 0 && count < len - 1; burstcnt--) { + iowrite8(buf[count], chip->vendor.iobase + + TPM_DATA_FIFO(chip->vendor.locality)); + count++; + } + + wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, + &chip->vendor.int_queue); + status = tpm_tis_status(chip); + if ((status & TPM_STS_DATA_EXPECT) == 0) { + rc = -EIO; + goto out_err; + } + } + + /* write last byte */ + iowrite8(buf[count], + chip->vendor.iobase + + TPM_DATA_FIFO(chip->vendor.locality)); + wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, + &chip->vendor.int_queue); + status = tpm_tis_status(chip); + if ((status & TPM_STS_DATA_EXPECT) != 0) { + rc = -EIO; + goto out_err; + } + + /* go and do it */ + iowrite8(TPM_STS_GO, + chip->vendor.iobase + TPM_STS(chip->vendor.locality)); + + if (chip->vendor.irq) { + ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); + if (wait_for_stat + (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, + tpm_calc_ordinal_duration(chip, ordinal), + &chip->vendor.read_queue) < 0) { + rc = -ETIME; + goto out_err; + } + } + return len; +out_err: + tpm_tis_ready(chip); + release_locality(chip, chip->vendor.locality, 0); + return rc; +} + +static struct file_operations tis_ops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = tpm_open, + .read = tpm_read, + .write = tpm_write, + .release = tpm_release, +}; + +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); +static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); +static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); +static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); +static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, + NULL); +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); +static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); + +static 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, NULL, +}; + +static struct attribute_group tis_attr_grp = { + .attrs = tis_attrs +}; + +static struct tpm_vendor_specific tpm_tis = { + .status = tpm_tis_status, + .recv = tpm_tis_recv, + .send = tpm_tis_send, + .cancel = tpm_tis_ready, + .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_canceled = TPM_STS_COMMAND_READY, + .attr_group = &tis_attr_grp, + .miscdev = { + .fops = &tis_ops,}, +}; + +static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs + *regs) +{ + struct tpm_chip *chip = (struct tpm_chip *) dev_id; + u32 interrupt; + + interrupt = ioread32(chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + + if (interrupt == 0) + return IRQ_NONE; + + chip->vendor.irq = irq; + + /* Clear interrupts handled with TPM_EOI */ + iowrite32(interrupt, + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + return IRQ_HANDLED; +} + +static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs + *regs) +{ + struct tpm_chip *chip = (struct tpm_chip *) dev_id; + u32 interrupt; + int i; + + interrupt = ioread32(chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + + if (interrupt == 0) + return IRQ_NONE; + + if (interrupt & TPM_INTF_DATA_AVAIL_INT) + wake_up_interruptible(&chip->vendor.read_queue); + if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) + for (i = 0; i < 5; i++) + if (check_locality(chip, i) >= 0) + break; + if (interrupt & + (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | + TPM_INTF_CMD_READY_INT)) + wake_up_interruptible(&chip->vendor.int_queue); + + /* Clear interrupts handled with TPM_EOI */ + iowrite32(interrupt, + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + return IRQ_HANDLED; +} + +static int __devinit tpm_tis_pnp_init(struct pnp_dev + *pnp_dev, const struct + pnp_device_id + *pnp_id) +{ + u32 vendor, intfcaps, intmask; + int rc, i; + unsigned long start, len; + struct tpm_chip *chip; + + start = pnp_mem_start(pnp_dev, 0); + len = pnp_mem_len(pnp_dev, 0); + + if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis))) + return -ENODEV; + + chip->vendor.iobase = ioremap(start, len); + if (!chip->vendor.iobase) { + rc = -EIO; + goto out_err; + } + + vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); + if ((vendor & 0xFFFF) == 0xFFFF) { + rc = -ENODEV; + goto out_err; + } + + /* Default timeouts */ + chip->vendor.timeout_a = 750; /* ms */ + chip->vendor.timeout_b = 2000; /* 2 sec */ + chip->vendor.timeout_c = 750; /* ms */ + chip->vendor.timeout_d = 750; /* ms */ + + dev_info(&pnp_dev->dev, + "1.2 TPM (device-id 0x%X, rev-id %d)\n", + vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); + + /* Figure out the capabilities */ + intfcaps = + ioread32(chip->vendor.iobase + + TPM_INTF_CAPS(chip->vendor.locality)); + dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n", + intfcaps); + if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) + dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n"); + if (intfcaps & TPM_INTF_CMD_READY_INT) + dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n"); + if (intfcaps & TPM_INTF_INT_EDGE_FALLING) + dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n"); + if (intfcaps & TPM_INTF_INT_EDGE_RISING) + dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_LOW) + dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) + dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n"); + if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) + dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n"); + if (intfcaps & TPM_INTF_STS_VALID_INT) + dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n"); + if (intfcaps & TPM_INTF_DATA_AVAIL_INT) + dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n"); + + if (request_locality(chip, 0) != 0) { + rc = -ENODEV; + goto out_err; + } + + /* INTERRUPT Setup */ + init_waitqueue_head(&chip->vendor.read_queue); + init_waitqueue_head(&chip->vendor.int_queue); + + intmask = + ioread32(chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + + intmask |= TPM_INTF_CMD_READY_INT + | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT + | TPM_INTF_STS_VALID_INT; + + iowrite32(intmask, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + + chip->vendor.irq = + ioread8(chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + + for (i = 3; i < 16 && chip->vendor.irq == 0; i++) { + iowrite8(i, + chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + if (request_irq + (i, tis_int_probe, SA_SHIRQ, + chip->vendor.miscdev.name, chip) != 0) { + dev_info(chip->dev, + "Unable to request irq: %d for probe\n", + i); + continue; + } + + /* Clear all existing */ + iowrite32(ioread32 + (chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)), + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + + /* Turn on */ + iowrite32(intmask | TPM_GLOBAL_INT_ENABLE, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + + /* Generate Interrupts */ + tpm_gen_interrupt(chip); + + /* Turn off */ + iowrite32(intmask, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + free_irq(i, chip); + } + if (chip->vendor.irq) { + iowrite8(chip->vendor.irq, + chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + if (request_irq + (chip->vendor.irq, tis_int_handler, SA_SHIRQ, + chip->vendor.miscdev.name, chip) != 0) { + dev_info(chip->dev, + "Unable to request irq: %d for use\n", i); + chip->vendor.irq = 0; + } else { + /* Clear all existing */ + iowrite32(ioread32 + (chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)), + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + + /* Turn on */ + iowrite32(intmask | TPM_GLOBAL_INT_ENABLE, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + } + } + + INIT_LIST_HEAD(&chip->vendor.list); + spin_lock(&tis_lock); + list_add(&chip->vendor.list, &tis_chips); + spin_unlock(&tis_lock); + + tpm_get_timeouts(chip); + tpm_continue_selftest(chip); + + return 0; +out_err: + if (chip->vendor.iobase) + iounmap(chip->vendor.iobase); + tpm_remove_hardware(chip->dev); + return rc; +} + +static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg) +{ + return tpm_pm_suspend(&dev->dev, msg); +} + +static int tpm_tis_pnp_resume(struct pnp_dev *dev) +{ + return tpm_pm_resume(&dev->dev); +} + +static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { + {"PNP0C31", 0}, /* TPM */ + {"", 0} +}; + +static struct pnp_driver tis_pnp_driver = { + .name = "tpm_tis", + .id_table = tpm_pnp_tbl, + .probe = tpm_tis_pnp_init, + .suspend = tpm_tis_pnp_suspend, + .resume = tpm_tis_pnp_resume, +}; + +static int __init init_tis(void) +{ + return pnp_register_driver(&tis_pnp_driver); +} + +static void __exit cleanup_tis(void) +{ + struct tpm_vendor_specific *i, *j; + struct tpm_chip *chip; + spin_lock(&tis_lock); + list_for_each_entry_safe(i, j, &tis_chips, list) { + chip = to_tpm_chip(i); + iowrite32(~TPM_GLOBAL_INT_ENABLE & + ioread32(chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor. + locality)), + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + release_locality(chip, chip->vendor.locality, 1); + if (chip->vendor.irq) + free_irq(chip->vendor.irq, chip); + iounmap(i->iobase); + list_del(&i->list); + tpm_remove_hardware(chip->dev); + } + spin_unlock(&tis_lock); + pnp_unregister_driver(&tis_pnp_driver); +} + +module_init(init_tis); +module_exit(cleanup_tis); +MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); +MODULE_DESCRIPTION("TPM Driver"); +MODULE_VERSION("2.0"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 36b20020e537036c4f9eb5b69140c88ead5da7dc Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:38:19 -0700 Subject: [PATCH] tpm: msecs_to_jiffies cleanups The timeout and duration values used in the tpm driver are not exposed to userspace. This patch converts the storage units to jiffies with msecs_to_jiffies. They were always being used in jiffies so this simplifies things removing the need for calculation all over the place. The change necessitated a type change in the tpm_chip struct to hold jiffies. Signed-off-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 22 ++++++++++++++-------- drivers/char/tpm/tpm.h | 4 ++-- drivers/char/tpm/tpm_tis.c | 32 ++++++++++++++++---------------- 3 files changed, 32 insertions(+), 26 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 150c86af7809..160dc080d580 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -354,7 +354,7 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, TPM_PROTECTED_ORDINAL_MASK]; if (duration_idx != TPM_UNDEFINED) - duration = chip->vendor.duration[duration_idx] * HZ / 1000; + duration = chip->vendor.duration[duration_idx]; if (duration <= 0) return 2 * 60 * HZ; else @@ -524,19 +524,19 @@ void tpm_get_timeouts(struct tpm_chip *chip) timeout = be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); if (timeout) - chip->vendor.timeout_a = timeout; + chip->vendor.timeout_a = msecs_to_jiffies(timeout); timeout = be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); if (timeout) - chip->vendor.timeout_b = timeout; + chip->vendor.timeout_b = msecs_to_jiffies(timeout); timeout = be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); if (timeout) - chip->vendor.timeout_c = timeout; + chip->vendor.timeout_c = msecs_to_jiffies(timeout); timeout = be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); if (timeout) - chip->vendor.timeout_d = timeout; + chip->vendor.timeout_d = msecs_to_jiffies(timeout); duration: memcpy(data, tpm_cap, sizeof(tpm_cap)); @@ -553,11 +553,17 @@ duration: return; chip->vendor.duration[TPM_SHORT] = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); + msecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_1_IDX)))); chip->vendor.duration[TPM_MEDIUM] = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); + msecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_2_IDX)))); chip->vendor.duration[TPM_LONG] = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); + msecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_3_IDX)))); } EXPORT_SYMBOL_GPL(tpm_get_timeouts); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 24541a556d02..54a4c804e25f 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -77,8 +77,8 @@ struct tpm_vendor_specific { struct attribute_group *attr_group; struct list_head list; int locality; - u32 timeout_a, timeout_b, timeout_c, timeout_d; - u32 duration[3]; + unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ + unsigned long duration[3]; /* jiffies */ wait_queue_head_t read_queue; wait_queue_head_t int_queue; diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 02759307f736..1cb5a7f0755d 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -51,6 +51,11 @@ enum tis_int_flags { TPM_INTF_DATA_AVAIL_INT = 0x001, }; +enum tis_defaults { + TIS_SHORT_TIMEOUT = 750, /* ms */ + TIS_LONG_TIMEOUT = 2000, /* 2 sec */ +}; + #define TPM_ACCESS(l) (0x0000 | ((l) << 12)) #define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) #define TPM_INT_VECTOR(l) (0x000C | ((l) << 12)) @@ -96,19 +101,16 @@ static int request_locality(struct tpm_chip *chip, int l) chip->vendor.iobase + TPM_ACCESS(l)); if (chip->vendor.irq) { - rc = wait_event_interruptible_timeout(chip->vendor. - int_queue, + rc = wait_event_interruptible_timeout(chip->vendor.int_queue, (check_locality (chip, l) >= 0), - msecs_to_jiffies - (chip->vendor. - timeout_a)); + chip->vendor.timeout_a); if (rc > 0) return l; } else { /* wait for burstcount */ - stop = jiffies + (HZ * chip->vendor.timeout_a / 1000); + stop = jiffies + chip->vendor.timeout_a; do { if (check_locality(chip, l) >= 0) return l; @@ -139,7 +141,7 @@ static int get_burstcount(struct tpm_chip *chip) /* wait for burstcount */ /* which timeout value, spec has 2 answers (c & d) */ - stop = jiffies + (HZ * chip->vendor.timeout_d / 1000); + stop = jiffies + chip->vendor.timeout_d; do { burstcnt = ioread8(chip->vendor.iobase + TPM_STS(chip->vendor.locality) + 1); @@ -153,7 +155,7 @@ static int get_burstcount(struct tpm_chip *chip) return -EBUSY; } -static int wait_for_stat(struct tpm_chip *chip, u8 mask, u32 timeout, +static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, wait_queue_head_t *queue) { unsigned long stop; @@ -169,13 +171,11 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u32 timeout, rc = wait_event_interruptible_timeout(*queue, ((tpm_tis_status (chip) & mask) == - mask), - msecs_to_jiffies - (timeout)); + mask), timeout); if (rc > 0) return 0; } else { - stop = jiffies + (HZ * timeout / 1000); + stop = jiffies + timeout; do { msleep(TPM_TIMEOUT); status = tpm_tis_status(chip); @@ -453,10 +453,10 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev } /* Default timeouts */ - chip->vendor.timeout_a = 750; /* ms */ - chip->vendor.timeout_b = 2000; /* 2 sec */ - chip->vendor.timeout_c = 750; /* ms */ - chip->vendor.timeout_d = 750; /* ms */ + chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); + chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); dev_info(&pnp_dev->dev, "1.2 TPM (device-id 0x%X, rev-id %d)\n", -- cgit v1.2.3 From 10685a95301d02fde2b10f6047e405c69d2af82a Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:38:32 -0700 Subject: [PATCH] tpm: use clear_bit Use set_bit() and clear_bit() for dev_mask manipulation. Signed-off-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 160dc080d580..6889e7db3aff 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -32,7 +32,6 @@ enum tpm_const { TPM_MINOR = 224, /* officially assigned */ TPM_BUFSIZE = 2048, TPM_NUM_DEVICES = 256, - TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) }; enum tpm_duration { @@ -48,7 +47,7 @@ enum tpm_duration { static LIST_HEAD(tpm_chip_list); static DEFINE_SPINLOCK(driver_lock); -static int dev_mask[TPM_NUM_MASK_ENTRIES]; +static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); /* * Array with one entry per ordinal defining the maximum amount @@ -1038,8 +1037,7 @@ void tpm_remove_hardware(struct device *dev) sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); tpm_bios_log_teardown(chip->bios_dir); - dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES] &= - ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); + clear_bit(chip->dev_num, dev_mask); kfree(chip); @@ -1097,7 +1095,6 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend char *devname; struct tpm_chip *chip; - int i, j; /* Driver specific per-device data */ chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -1116,19 +1113,9 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); - chip->dev_num = -1; + chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); - for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++) - for (j = 0; j < 8 * sizeof(int); j++) - if ((dev_mask[i] & (1 << j)) == 0) { - chip->dev_num = - i * TPM_NUM_MASK_ENTRIES + j; - dev_mask[i] |= 1 << j; - goto dev_num_search_complete; - } - -dev_num_search_complete: - if (chip->dev_num < 0) { + if (chip->dev_num >= TPM_NUM_DEVICES) { dev_err(dev, "No available tpm device numbers\n"); kfree(chip); return NULL; @@ -1137,6 +1124,8 @@ dev_num_search_complete: else chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; + set_bit(chip->dev_num, dev_mask); + devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor.miscdev.name = devname; @@ -1150,8 +1139,8 @@ dev_num_search_complete: chip->vendor.miscdev.name, chip->vendor.miscdev.minor); put_device(dev); + clear_bit(chip->dev_num, dev_mask); kfree(chip); - dev_mask[i] &= !(1 << j); return NULL; } -- cgit v1.2.3 From e496f540540f0a0bffcc3f83785f9954dacf1b83 Mon Sep 17 00:00:00 2001 From: Marcel Selhorst Date: Sat, 22 Apr 2006 02:38:42 -0700 Subject: [PATCH] tpm: tpm_infineon updated to latest interface changes Apply the latest changes in the TPM interface to the Infineon TPM-driver. Signed-off-by: Marcel Selhorst Acked-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_infineon.c | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 24095f6ee6da..90cae8f9fe21 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -104,7 +104,7 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo) if (clear_wrfifo) { for (i = 0; i < 4096; i++) { - status = inb(chip->vendor->base + WRFIFO); + status = inb(chip->vendor.base + WRFIFO); if (status == 0xff) { if (check == 5) break; @@ -124,8 +124,8 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo) */ i = 0; do { - status = inb(chip->vendor->base + RDFIFO); - status = inb(chip->vendor->base + STAT); + status = inb(chip->vendor.base + RDFIFO); + status = inb(chip->vendor.base + STAT); i++; if (i == TPM_MAX_TRIES) return -EIO; @@ -138,7 +138,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) int status; int i; for (i = 0; i < TPM_MAX_TRIES; i++) { - status = inb(chip->vendor->base + STAT); + status = inb(chip->vendor.base + STAT); /* check the status-register if wait_for_bit is set */ if (status & 1 << wait_for_bit) break; @@ -157,7 +157,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) { wait(chip, STAT_XFE); - outb(sendbyte, chip->vendor->base + WRFIFO); + outb(sendbyte, chip->vendor.base + WRFIFO); } /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more @@ -204,7 +204,7 @@ recv_begin: ret = wait(chip, STAT_RDA); if (ret) return -EIO; - buf[i] = inb(chip->vendor->base + RDFIFO); + buf[i] = inb(chip->vendor.base + RDFIFO); } if (buf[0] != TPM_VL_VER) { @@ -219,7 +219,7 @@ recv_begin: for (i = 0; i < size; i++) { wait(chip, STAT_RDA); - buf[i] = inb(chip->vendor->base + RDFIFO); + buf[i] = inb(chip->vendor.base + RDFIFO); } if ((size == 0x6D00) && (buf[1] == 0x80)) { @@ -268,7 +268,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) u8 count_high, count_low, count_4, count_3, count_2, count_1; /* Disabling Reset, LP and IRQC */ - outb(RESET_LP_IRQC_DISABLE, chip->vendor->base + CMD); + outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD); ret = empty_fifo(chip, 1); if (ret) { @@ -319,7 +319,7 @@ static void tpm_inf_cancel(struct tpm_chip *chip) static u8 tpm_inf_status(struct tpm_chip *chip) { - return inb(chip->vendor->base + STAT); + return inb(chip->vendor.base + STAT); } static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); @@ -346,7 +346,7 @@ static struct file_operations inf_ops = { .release = tpm_release, }; -static struct tpm_vendor_specific tpm_inf = { +static const struct tpm_vendor_specific tpm_inf = { .recv = tpm_inf_recv, .send = tpm_inf_send, .cancel = tpm_inf_cancel, @@ -375,6 +375,7 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, int version[2]; int productid[2]; char chipname[20]; + struct tpm_chip *chip; /* read IO-ports through PnP */ if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && @@ -395,14 +396,13 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, goto err_last; } /* publish my base address and request region */ - tpm_inf.base = TPM_INF_BASE; if (request_region - (tpm_inf.base, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { + (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { rc = -EINVAL; goto err_last; } - if (request_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN, - "tpm_infineon0") == NULL) { + if (request_region + (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) { rc = -EINVAL; goto err_last; } @@ -442,9 +442,9 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, /* configure TPM with IO-ports */ outb(IOLIMH, TPM_INF_ADDR); - outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA); + outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA); outb(IOLIML, TPM_INF_ADDR); - outb((tpm_inf.base & 0xff), TPM_INF_DATA); + outb((TPM_INF_BASE & 0xff), TPM_INF_DATA); /* control if IO-ports are set correctly */ outb(IOLIMH, TPM_INF_ADDR); @@ -452,10 +452,10 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, outb(IOLIML, TPM_INF_ADDR); iol = inb(TPM_INF_DATA); - if ((ioh << 8 | iol) != tpm_inf.base) { + if ((ioh << 8 | iol) != TPM_INF_BASE) { dev_err(&dev->dev, - "Could not set IO-ports to 0x%lx\n", - tpm_inf.base); + "Could not set IO-ports to 0x%x\n", + TPM_INF_BASE); rc = -EIO; goto err_release_region; } @@ -466,15 +466,15 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); /* disable RESET, LP and IRQC */ - outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); + outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD); /* Finally, we're done, print some infos */ dev_info(&dev->dev, "TPM found: " "config base 0x%x, " "io base 0x%x, " - "chip version %02x%02x, " - "vendor id %x%x (Infineon), " - "product id %02x%02x" + "chip version 0x%02x%02x, " + "vendor id 0x%x%x (Infineon), " + "product id 0x%02x%02x" "%s\n", TPM_INF_ADDR, TPM_INF_BASE, @@ -482,11 +482,10 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, vendorid[0], vendorid[1], productid[0], productid[1], chipname); - rc = tpm_register_hardware(&dev->dev, &tpm_inf); - if (rc < 0) { - rc = -ENODEV; + if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) { goto err_release_region; } + chip->vendor.base = TPM_INF_BASE; return 0; } else { rc = -ENODEV; @@ -494,7 +493,7 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, } err_release_region: - release_region(tpm_inf.base, TPM_INF_PORT_LEN); + release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); err_last: @@ -506,7 +505,8 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) struct tpm_chip *chip = pnp_get_drvdata(dev); if (chip) { - release_region(chip->vendor->base, TPM_INF_PORT_LEN); + release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); + release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); tpm_remove_hardware(chip->dev); } } @@ -538,5 +538,5 @@ module_exit(cleanup_inf); MODULE_AUTHOR("Marcel Selhorst "); MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); -MODULE_VERSION("1.7"); +MODULE_VERSION("1.8"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From b09d53009db21228adde29b468eb4583e66cbe7c Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:38:55 -0700 Subject: [PATCH] tpm: check mem start and len The memory start and length values obtained from the ACPI entry need to be checked and filled in with the default values from the specification if they don't exist. This patch fills in the default values and uses them appropriately. Signed-off-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 1cb5a7f0755d..9c0727bf28b7 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -52,6 +52,8 @@ enum tis_int_flags { }; enum tis_defaults { + TIS_MEM_BASE = 0xFED4000, + TIS_MEM_LEN = 0x5000, TIS_SHORT_TIMEOUT = 750, /* ms */ TIS_LONG_TIMEOUT = 2000, /* 2 sec */ }; @@ -437,6 +439,11 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev start = pnp_mem_start(pnp_dev, 0); len = pnp_mem_len(pnp_dev, 0); + if (!start) + start = TIS_MEM_BASE; + if (!len) + len = TIS_MEM_LEN; + if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis))) return -ENODEV; -- cgit v1.2.3 From 8b006db604527c566dc1dd0aebae37714143aaef Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:39:07 -0700 Subject: [PATCH] tpm: update bios log code for 1.2 The acpi table which contains the BIOS log events was updated for 1.2. There are now client and server modes as defined in the specifications with slightly different formats. Additionally, the start field was even too small for the 1.1 version but had been working anyway. This patch updates the code to deal with any of the three types of headers probperly (1.1, 1.2 client and 1.2 server). Signed-off-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_bios.c | 49 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 5bcbaef53798..e45f0d3d12de 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -29,6 +29,11 @@ #define MAX_TEXT_EVENT 1000 /* Max event string length */ #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ +enum bios_platform_class { + BIOS_CLIENT = 0x00, + BIOS_SERVER = 0x01, +}; + struct tpm_bios_log { void *bios_event_log; void *bios_event_log_end; @@ -36,9 +41,18 @@ struct tpm_bios_log { struct acpi_tcpa { struct acpi_table_header hdr; - u16 reserved; - u32 log_max_len __attribute__ ((packed)); - u32 log_start_addr __attribute__ ((packed)); + u16 platform_class; + union { + struct client_hdr { + u32 log_max_len __attribute__ ((packed)); + u64 log_start_addr __attribute__ ((packed)); + } client; + struct server_hdr { + u16 reserved; + u64 log_max_len __attribute__ ((packed)); + u64 log_start_addr __attribute__ ((packed)); + } server; + }; }; struct tcpa_event { @@ -379,6 +393,7 @@ static int read_log(struct tpm_bios_log *log) struct acpi_tcpa *buff; acpi_status status; struct acpi_table_header *virt; + u64 len, start; if (log->bios_event_log != NULL) { printk(KERN_ERR @@ -399,27 +414,37 @@ static int read_log(struct tpm_bios_log *log) return -EIO; } - if (buff->log_max_len == 0) { + switch(buff->platform_class) { + case BIOS_SERVER: + len = buff->server.log_max_len; + start = buff->server.log_start_addr; + break; + case BIOS_CLIENT: + default: + len = buff->client.log_max_len; + start = buff->client.log_start_addr; + break; + } + if (!len) { printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); return -EIO; } /* malloc EventLog space */ - log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL); + log->bios_event_log = kmalloc(len, GFP_KERNEL); if (!log->bios_event_log) { - printk - ("%s: ERROR - Not enough Memory for BIOS measurements\n", - __func__); + printk("%s: ERROR - Not enough Memory for BIOS measurements\n", + __func__); return -ENOMEM; } - log->bios_event_log_end = log->bios_event_log + buff->log_max_len; + log->bios_event_log_end = log->bios_event_log + len; - acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, (void *) &virt); + acpi_os_map_memory(start, len, (void *) &virt); - memcpy(log->bios_event_log, virt, buff->log_max_len); + memcpy(log->bios_event_log, virt, len); - acpi_os_unmap_memory(virt, buff->log_max_len); + acpi_os_unmap_memory(virt, len); return 0; } -- cgit v1.2.3 From 397c718299d848ff305ecd955838a9bd32f1f881 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 22 Apr 2006 02:39:18 -0700 Subject: [PATCH] tpm_infineon section fixup Use __devexit_p() for the exit/remove function to protect against discarding it. WARNING: drivers/char/tpm/tpm_infineon.o - Section mismatch: reference to .exit.text:tpm_inf_pnp_remove from .data between 'tpm_inf_pnp' (at offset 0x20) and 'tpm_inf' Signed-off-by: Randy Dunlap Cc: Kylene Jo Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_infineon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 90cae8f9fe21..adfff21beb21 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -15,6 +15,7 @@ * License. */ +#include #include #include "tpm.h" @@ -520,7 +521,7 @@ static struct pnp_driver tpm_inf_pnp = { }, .id_table = tpm_pnp_tbl, .probe = tpm_inf_pnp_probe, - .remove = tpm_inf_pnp_remove, + .remove = __devexit_p(tpm_inf_pnp_remove), }; static int __init init_inf(void) -- cgit v1.2.3 From cb5354253af2bc30ed449b8be4b3bddf3b3a2746 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:39:31 -0700 Subject: [PATCH] tpm: spacing cleanups 2 Fixes minor spacing issues. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 9c0727bf28b7..398514745d3f 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -54,8 +54,8 @@ enum tis_int_flags { enum tis_defaults { TIS_MEM_BASE = 0xFED4000, TIS_MEM_LEN = 0x5000, - TIS_SHORT_TIMEOUT = 750, /* ms */ - TIS_LONG_TIMEOUT = 2000, /* 2 sec */ + TIS_SHORT_TIMEOUT = 750, /* ms */ + TIS_LONG_TIMEOUT = 2000, /* 2 sec */ }; #define TPM_ACCESS(l) (0x0000 | ((l) << 12)) @@ -188,7 +188,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, return -ETIME; } -static int recv_data(struct tpm_chip *chip, u8 * buf, size_t count) +static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0, burstcnt; while (size < count && @@ -206,7 +206,7 @@ static int recv_data(struct tpm_chip *chip, u8 * buf, size_t count) return size; } -static int tpm_tis_recv(struct tpm_chip *chip, u8 * buf, size_t count) +static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0; int expected, status; @@ -257,7 +257,7 @@ out: * tpm.c can skip polling for the data to be available as the interrupt is * waited for here */ -static int tpm_tis_send(struct tpm_chip *chip, u8 * buf, size_t len) +static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) { int rc, status, burstcnt; size_t count = 0; @@ -374,8 +374,7 @@ static struct tpm_vendor_specific tpm_tis = { .fops = &tis_ops,}, }; -static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs - *regs) +static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs) { struct tpm_chip *chip = (struct tpm_chip *) dev_id; u32 interrupt; @@ -395,8 +394,7 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs return IRQ_HANDLED; } -static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs - *regs) +static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs) { struct tpm_chip *chip = (struct tpm_chip *) dev_id; u32 interrupt; @@ -426,10 +424,8 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs return IRQ_HANDLED; } -static int __devinit tpm_tis_pnp_init(struct pnp_dev - *pnp_dev, const struct - pnp_device_id - *pnp_id) +static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, + const struct pnp_device_id *pnp_id) { u32 vendor, intfcaps, intmask; int rc, i; -- cgit v1.2.3 From 5713556843aee24f484f445db6540f9fef976439 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:39:44 -0700 Subject: [PATCH] tpm: add interrupt module parameter This patch adds a boolean module parameter that allows the user to turn interrupt support on and off. The default behavior is to attempt to use interrupts. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 78 +++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 35 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 398514745d3f..447f76388067 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -16,6 +16,9 @@ * published by the Free Software Foundation, version 2 of the * License. */ +#include +#include +#include #include #include #include @@ -424,6 +427,10 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } +static int interrupts = 1; +module_param(interrupts, bool, 0444); +MODULE_PARM_DESC(interrupts, "Enable interrupts"); + static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, const struct pnp_device_id *pnp_id) { @@ -510,44 +517,44 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, iowrite32(intmask, chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); + if (interrupts) { + chip->vendor.irq = + ioread8(chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + + for (i = 3; i < 16 && chip->vendor.irq == 0; i++) { + iowrite8(i, chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + if (request_irq + (i, tis_int_probe, SA_SHIRQ, + chip->vendor.miscdev.name, chip) != 0) { + dev_info(chip->dev, + "Unable to request irq: %d for probe\n", + i); + continue; + } - chip->vendor.irq = - ioread8(chip->vendor.iobase + - TPM_INT_VECTOR(chip->vendor.locality)); - - for (i = 3; i < 16 && chip->vendor.irq == 0; i++) { - iowrite8(i, - chip->vendor.iobase + - TPM_INT_VECTOR(chip->vendor.locality)); - if (request_irq - (i, tis_int_probe, SA_SHIRQ, - chip->vendor.miscdev.name, chip) != 0) { - dev_info(chip->dev, - "Unable to request irq: %d for probe\n", - i); - continue; - } - - /* Clear all existing */ - iowrite32(ioread32 - (chip->vendor.iobase + - TPM_INT_STATUS(chip->vendor.locality)), - chip->vendor.iobase + - TPM_INT_STATUS(chip->vendor.locality)); + /* Clear all existing */ + iowrite32(ioread32 + (chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)), + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); - /* Turn on */ - iowrite32(intmask | TPM_GLOBAL_INT_ENABLE, - chip->vendor.iobase + - TPM_INT_ENABLE(chip->vendor.locality)); + /* Turn on */ + iowrite32(intmask | TPM_GLOBAL_INT_ENABLE, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); - /* Generate Interrupts */ - tpm_gen_interrupt(chip); + /* Generate Interrupts */ + tpm_gen_interrupt(chip); - /* Turn off */ - iowrite32(intmask, - chip->vendor.iobase + - TPM_INT_ENABLE(chip->vendor.locality)); - free_irq(i, chip); + /* Turn off */ + iowrite32(intmask, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + free_irq(i, chip); + } } if (chip->vendor.irq) { iowrite8(chip->vendor.irq, @@ -557,7 +564,8 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, (chip->vendor.irq, tis_int_handler, SA_SHIRQ, chip->vendor.miscdev.name, chip) != 0) { dev_info(chip->dev, - "Unable to request irq: %d for use\n", i); + "Unable to request irq: %d for use\n", + chip->vendor.irq); chip->vendor.irq = 0; } else { /* Clear all existing */ -- cgit v1.2.3 From 93e1b7d42e1edb4ddde6257e9a02513fef26f715 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:39:52 -0700 Subject: [PATCH] tpm: add HID module parameter I recently found that not all BIOS manufacturers are using the specified generic PNP id in their TPM ACPI table entry. I have added the vendor specific IDs that I know about and added a module parameter that a user can specify another HID to the probe list if their device isn't being found by the default list. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 447f76388067..b9cae9a238bb 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -610,7 +610,13 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { {"PNP0C31", 0}, /* TPM */ - {"", 0} + {"ATM1200", 0}, /* Atmel */ + {"IFX0102", 0}, /* Infineon */ + {"BCM0101", 0}, /* Broadcom */ + {"NSC1200", 0}, /* National */ + /* Add new here */ + {"", 0}, /* User Specified */ + {"", 0} /* Terminator */ }; static struct pnp_driver tis_pnp_driver = { @@ -621,6 +627,11 @@ static struct pnp_driver tis_pnp_driver = { .resume = tpm_tis_pnp_resume, }; +#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 +module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id, + sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); +MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); + static int __init init_tis(void) { return pnp_register_driver(&tis_pnp_driver); -- cgit v1.2.3 From caa98c41c0db9bfda5bc9a0e680f304283089268 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 23 Apr 2006 18:14:00 +1000 Subject: drm: fixup r300 scratch on BE machines This fixes the r300 scratch stuff to work on PPC, from Ben Herrenschmidt on IRC. Signed-off-by: Dave Airlie --- drivers/char/drm/r300_cmdbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c index b108c7f913b2..26bdf2ca59d7 100644 --- a/drivers/char/drm/r300_cmdbuf.c +++ b/drivers/char/drm/r300_cmdbuf.c @@ -723,7 +723,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv, dev_priv->scratch_ages[header.scratch.reg]++; - ref_age_base = *(u32 **)cmdbuf->buf; + ref_age_base = (u32 *)(unsigned long)*((uint64_t *)cmdbuf->buf); cmdbuf->buf += sizeof(u64); cmdbuf->bufsz -= sizeof(u64); -- cgit v1.2.3 From 5d23fafb1bf8ef071738026c2e5071a92186d5f8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 23 Apr 2006 18:26:40 +1000 Subject: drm: possible cleanups This patch contains the following possible cleanups: - make the following needlessly global function static: - drm_bufs.c: drm_addbufs_fb() - remove the following unused EXPORT_SYMBOL's: - drm_agpsupport.c: drm_agp_bind_memory - drm_bufs.c: drm_rmmap_locked - drm_bufs.c: drm_rmmap - drm_stub.c: drm_get_dev Signed-off-by: Adrian Bunk Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 1 - drivers/char/drm/drm_agpsupport.c | 2 -- drivers/char/drm/drm_bufs.c | 5 +---- drivers/char/drm/drm_stub.c | 2 -- 4 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index e1aadae00623..cb76e5ca9a23 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -889,7 +889,6 @@ extern int drm_lock_free(drm_device_t * dev, /* Buffer management support (drm_bufs.h) */ extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request); extern int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request); -extern int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request); extern int drm_addmap(drm_device_t * dev, unsigned int offset, unsigned int size, drm_map_type_t type, drm_map_flags_t flags, drm_local_map_t ** map_ptr); diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c index fabc930c67a2..40bfd9b01e39 100644 --- a/drivers/char/drm/drm_agpsupport.c +++ b/drivers/char/drm/drm_agpsupport.c @@ -503,8 +503,6 @@ int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start) return agp_bind_memory(handle, start); } -EXPORT_SYMBOL(drm_agp_bind_memory); - /** Calls agp_unbind_memory() */ int drm_agp_unbind_memory(DRM_AGP_MEM * handle) { diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 8a9cf12e6183..006b06d29727 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -386,7 +386,6 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) return 0; } -EXPORT_SYMBOL(drm_rmmap_locked); int drm_rmmap(drm_device_t *dev, drm_local_map_t *map) { @@ -398,7 +397,6 @@ int drm_rmmap(drm_device_t *dev, drm_local_map_t *map) return ret; } -EXPORT_SYMBOL(drm_rmmap); /* The rmmap ioctl appears to be unnecessary. All mappings are torn down on * the last close of the device, and this is necessary for cleanup when things @@ -1053,7 +1051,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) return 0; } -int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) +static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) { drm_device_dma_t *dma = dev->dma; drm_buf_entry_t *entry; @@ -1212,7 +1210,6 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) atomic_dec(&dev->buf_alloc); return 0; } -EXPORT_SYMBOL(drm_addbufs_fb); /** diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index 68073e14fdec..9a842a36bb27 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c @@ -229,8 +229,6 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, return ret; } -EXPORT_SYMBOL(drm_get_dev); - /** * Put a device minor number. * -- cgit v1.2.3 From 77426d7210430b70a7f5b21c05c4e7505528937d Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Wed, 26 Apr 2006 00:14:10 -0400 Subject: Input: allow using several chords for braille For coping with bad keyboards, permit to type a braille pattern by pressing several chords. By default, only one chord is needed. Signed-off-by: Samuel Thibault Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 935670a3cd98..5755b7e5f187 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -860,9 +860,32 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struc } /* by default, 300ms interval for combination release */ -static long brl_timeout = 300; -MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for combination on first release, < 0 for dead characters)"); -module_param(brl_timeout, long, 0644); +static unsigned brl_timeout = 300; +MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)"); +module_param(brl_timeout, uint, 0644); + +static unsigned brl_nbchords = 1; +MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)"); +module_param(brl_nbchords, uint, 0644); + +static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag, struct pt_regs *regs) +{ + static unsigned long chords; + static unsigned committed; + + if (!brl_nbchords) + k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag, regs); + else { + committed |= pattern; + chords++; + if (chords == brl_nbchords) { + k_unicode(vc, BRL_UC_ROW | committed, up_flag, regs); + chords = 0; + committed = 0; + } + } +} + static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) { static unsigned pressed,committing; @@ -882,11 +905,6 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct if (value > 8) return; - if (brl_timeout < 0) { - k_deadunicode(vc, BRL_UC_ROW | (1 << (value - 1)), up_flag, regs); - return; - } - if (up_flag) { if (brl_timeout) { if (!committing || @@ -897,13 +915,13 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pressed &= ~(1 << (value - 1)); if (!pressed) { if (committing) { - k_unicode(vc, BRL_UC_ROW | committing, 0, regs); + k_brlcommit(vc, committing, 0, regs); committing = 0; } } } else { if (committing) { - k_unicode(vc, BRL_UC_ROW | committing, 0, regs); + k_brlcommit(vc, committing, 0, regs); committing = 0; } pressed &= ~(1 << (value - 1)); -- cgit v1.2.3 From 1ebd32fc54bd04de6b3944587f25513c0681f98e Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 26 Apr 2006 14:40:08 +0200 Subject: [PATCH] splice: add ->splice_write support for /dev/null Useful for testing. Signed-off-by: Jens Axboe --- drivers/char/mem.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 66719f9d294c..1fa9fa157c12 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -578,6 +579,18 @@ static ssize_t write_null(struct file * file, const char __user * buf, return count; } +static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf, + struct splice_desc *sd) +{ + return sd->len; +} + +static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); +} + #ifdef CONFIG_MMU /* * For fun, we are using the MMU for this. @@ -785,6 +798,7 @@ static struct file_operations null_fops = { .llseek = null_lseek, .read = read_null, .write = write_null, + .splice_write = splice_write_null, }; #if defined(CONFIG_ISA) || !defined(__mc68000__) -- cgit v1.2.3 From 1ac3836ce689e594b20c7c9855f64a63751c2d10 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 27 Apr 2006 18:39:19 -0700 Subject: [PATCH] tipar oops fix If compiled into the kernel, parport_register_driver() is called before the parport driver has been initalised. This means that it is expected that tp_count is 0 after the parport_register_driver() call() - tipar's attach function will not be called until later during bootup. Signed-off-by: Daniel Drake Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tipar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index eb2eb3e12d6a..079db5a935a1 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -515,7 +515,7 @@ tipar_init_module(void) err = PTR_ERR(tipar_class); goto out_chrdev; } - if (parport_register_driver(&tipar_driver) || tp_count == 0) { + if (parport_register_driver(&tipar_driver)) { printk(KERN_ERR "tipar: unable to register with parport\n"); err = -EIO; goto out_class; -- cgit v1.2.3 From d698f1c72629ff43d0cb6b9f1d17c491c057a0d9 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Thu, 27 Apr 2006 18:39:20 -0700 Subject: [PATCH] fix array overrun in drivers/char/mwave/mwavedd.c this fixes coverity id #489. Since the last element in the array is always ARRAY_SIZE-1 we have to check for ipcnum >= ARRAY_SIZE() Signed-off-by: Eric Sesterhenn Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mwave/mwavedd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index 8666171e187b..d3ba2f860ef0 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c @@ -271,7 +271,7 @@ static int mwave_ioctl(struct inode *inode, struct file *file, ipcnum, pDrvData->IPCs[ipcnum].usIntCount); - if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) { + if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) { PRINTK_ERROR(KERN_ERR_MWAVE "mwavedd::mwave_ioctl:" " IOCTL_MW_REGISTER_IPC:" -- cgit v1.2.3 From f3537ea7b9c2f10397a8b68cd006981d7c615431 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Mon, 1 May 2006 12:16:17 -0700 Subject: [PATCH] genrtc: fix read on 64-bit platforms Fix genrtc's read() routine for 64-bit platforms. Current gen_rtc_read() stores 64bit integer and returns 8 even if an user tried to read a 32bit integer. Signed-off-by: Atsushi Nemoto Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/genrtc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index d3a2bc36129b..588fca542a98 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -200,13 +200,13 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf, /* first test allows optimizer to nuke this case for 32-bit machines */ if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) { unsigned int uidata = data; - retval = put_user(uidata, (unsigned long __user *)buf); + retval = put_user(uidata, (unsigned int __user *)buf) ?: + sizeof(unsigned int); } else { - retval = put_user(data, (unsigned long __user *)buf); + retval = put_user(data, (unsigned long __user *)buf) ?: + sizeof(unsigned long); } - if (!retval) - retval = sizeof(unsigned long); out: current->state = TASK_RUNNING; remove_wait_queue(&gen_rtc_wait, &wait); -- cgit v1.2.3 From 7fc5b1e3a170d865f625e609c087cf8d84fd285d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 10 May 2006 13:28:52 +0200 Subject: [Cardman 40x0] Fix udev device creation This patch corrects the order of the calls to register_chrdev() and pcmcia_register_driver(). Now udev correctly creates userspace device files /dev/cmmN and /dev/cmxN respectively. Based on an earlier patch by Jan Niehusmann . Signed-off-by: Harald Welte Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/cm4000_cs.c | 10 ++++++---- drivers/char/pcmcia/cm4040_cs.c | 11 +++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 02114a0bd0d9..128b2632512d 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1981,10 +1981,6 @@ static int __init cmm_init(void) if (!cmm_class) return -1; - rc = pcmcia_register_driver(&cm4000_driver); - if (rc < 0) - return rc; - major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME @@ -1992,6 +1988,12 @@ static int __init cmm_init(void) return -1; } + rc = pcmcia_register_driver(&cm4000_driver); + if (rc < 0) { + unregister_chrdev(major, DEVICE_NAME); + return rc; + } + return 0; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 29efa64580a8..47a8465bf95b 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -724,16 +724,19 @@ static int __init cm4040_init(void) if (!cmx_class) return -1; - rc = pcmcia_register_driver(&reader_driver); - if (rc < 0) - return rc; - major = register_chrdev(0, DEVICE_NAME, &reader_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); return -1; } + + rc = pcmcia_register_driver(&reader_driver); + if (rc < 0) { + unregister_chrdev(major, DEVICE_NAME); + return rc; + } + return 0; } -- cgit v1.2.3 From 94585136606e0598a93ec145d9a899c8ec9b2208 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Mon, 15 May 2006 09:43:53 -0700 Subject: [PATCH] tpm: update module dependencies The TIS driver is dependent upon information from the ACPI table for device discovery thus it compiles but does no actual work without this dependency. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 1efde3b27619..fe00c7dfb649 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -22,7 +22,7 @@ config TCG_TPM config TCG_TIS tristate "TPM Interface Specification 1.2 Interface" - depends on TCG_TPM + depends on TCG_TPM && PNPACPI ---help--- If you have a TPM security chip that is compliant with the TCG TIS 1.2 TPM specification say Yes and it will be accessible -- cgit v1.2.3 From 2a7362f52a17e8dbeab57c00c3c45fcfeb0dff54 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Mon, 15 May 2006 09:44:25 -0700 Subject: [PATCH] tpm: fix constant Fix the constant used for the base address when it cannot be determined from ACPI. It was off by one order of magnitude. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index b9cae9a238bb..f621168f38ae 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -55,7 +55,7 @@ enum tis_int_flags { }; enum tis_defaults { - TIS_MEM_BASE = 0xFED4000, + TIS_MEM_BASE = 0xFED40000, TIS_MEM_LEN = 0x5000, TIS_SHORT_TIMEOUT = 750, /* ms */ TIS_LONG_TIMEOUT = 2000, /* 2 sec */ -- cgit v1.2.3 From 655fdeab809a5612b0eab6aee873b00d26404ca7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 15 May 2006 09:44:26 -0700 Subject: [PATCH] Final rio polish Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 2 +- drivers/char/rio/host.h | 9 -------- drivers/char/rio/rioboot.c | 1 + drivers/char/rio/rioctrl.c | 43 ++++++++++++++++++++++------------ drivers/char/rio/rioioctl.h | 56 ++++----------------------------------------- 5 files changed, 35 insertions(+), 76 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 402296670d3a..78d928f9d9f1 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -291,7 +291,7 @@ config SX config RIO tristate "Specialix RIO system support" - depends on SERIAL_NONSTANDARD && !64BIT + depends on SERIAL_NONSTANDARD help This is a driver for the Specialix RIO, a smart serial card which drives an outboard box that can support up to 128 ports. Product diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h index 3ec73d1a279a..179cdbea712b 100644 --- a/drivers/char/rio/host.h +++ b/drivers/char/rio/host.h @@ -33,12 +33,6 @@ #ifndef __rio_host_h__ #define __rio_host_h__ -#ifdef SCCS_LABELS -#ifndef lint -static char *_host_h_sccs_ = "@(#)host.h 1.2"; -#endif -#endif - /* ** the host structure - one per host card in the system. */ @@ -77,9 +71,6 @@ struct Host { #define RC_STARTUP 1 #define RC_RUNNING 2 #define RC_STUFFED 3 -#define RC_SOMETHING 4 -#define RC_SOMETHING_NEW 5 -#define RC_SOMETHING_ELSE 6 #define RC_READY 7 #define RUN_STATE 7 /* diff --git a/drivers/char/rio/rioboot.c b/drivers/char/rio/rioboot.c index acda9326c2ef..290143addd34 100644 --- a/drivers/char/rio/rioboot.c +++ b/drivers/char/rio/rioboot.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c index d31aba62bb7f..75b2557c37ec 100644 --- a/drivers/char/rio/rioctrl.c +++ b/drivers/char/rio/rioctrl.c @@ -1394,14 +1394,17 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) return RIO_FAIL; } - if (((int) ((char) PortP->InUse) == -1) || !(CmdBlkP = RIOGetCmdBlk())) { - rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block for command %d on port %d\n", Cmd, PortP->PortNum); + if ((PortP->InUse == (typeof(PortP->InUse))-1) || + !(CmdBlkP = RIOGetCmdBlk())) { + rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block " + "for command %d on port %d\n", Cmd, PortP->PortNum); return RIO_FAIL; } - rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n", CmdBlkP, PortP->InUse); + rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n", + CmdBlkP, PortP->InUse); - PktCmdP = (struct PktCmd_M *) &CmdBlkP->Packet.data[0]; + PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0]; CmdBlkP->Packet.src_unit = 0; if (PortP->SecondBlock) @@ -1425,38 +1428,46 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) switch (Cmd) { case MEMDUMP: - rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p (addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr); + rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p " + "(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr); PktCmdP->SubCommand = MEMDUMP; PktCmdP->SubAddr = SubCmd.Addr; break; case FCLOSE: - rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n", + CmdBlkP); break; case READ_REGISTER: - rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) command blk %p\n", (int) SubCmd.Addr, CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) " + "command blk %p\n", (int) SubCmd.Addr, CmdBlkP); PktCmdP->SubCommand = READ_REGISTER; PktCmdP->SubAddr = SubCmd.Addr; break; case RESUME: - rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n", + CmdBlkP); break; case RFLUSH: - rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n", + CmdBlkP); CmdBlkP->PostFuncP = RIORFlushEnable; break; case SUSPEND: - rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n", + CmdBlkP); break; case MGET: - rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n", + CmdBlkP); break; case MSET: case MBIC: case MBIS: CmdBlkP->Packet.data[4] = (char) PortP->ModemLines; - rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command " + "blk %p\n", CmdBlkP); break; case WFLUSH: @@ -1465,12 +1476,14 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) ** allowed then we should not bother sending any more to the ** RTA. */ - if ((int) ((char) PortP->WflushFlag) == (int) -1) { - rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, WflushFlag about to wrap!"); + if (PortP->WflushFlag == (typeof(PortP->WflushFlag))-1) { + rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, " + "WflushFlag about to wrap!"); RIOFreeCmdBlk(CmdBlkP); return (RIO_FAIL); } else { - rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command " + "blk %p\n", CmdBlkP); CmdBlkP->PostFuncP = RIOWFlushMark; } break; diff --git a/drivers/char/rio/rioioctl.h b/drivers/char/rio/rioioctl.h index 14b83fae75c8..e8af5b30519e 100644 --- a/drivers/char/rio/rioioctl.h +++ b/drivers/char/rio/rioioctl.h @@ -33,10 +33,6 @@ #ifndef __rioioctl_h__ #define __rioioctl_h__ -#ifdef SCCS_LABELS -static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h 1.2"; -#endif - /* ** RIO device driver - user ioctls and associated structures. */ @@ -44,55 +40,13 @@ static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h 1.2"; struct portStats { int port; int gather; - ulong txchars; - ulong rxchars; - ulong opens; - ulong closes; - ulong ioctls; + unsigned long txchars; + unsigned long rxchars; + unsigned long opens; + unsigned long closes; + unsigned long ioctls; }; - -#define rIOC ('r'<<8) -#define TCRIOSTATE (rIOC | 1) -#define TCRIOXPON (rIOC | 2) -#define TCRIOXPOFF (rIOC | 3) -#define TCRIOXPCPS (rIOC | 4) -#define TCRIOXPRINT (rIOC | 5) -#define TCRIOIXANYON (rIOC | 6) -#define TCRIOIXANYOFF (rIOC | 7) -#define TCRIOIXONON (rIOC | 8) -#define TCRIOIXONOFF (rIOC | 9) -#define TCRIOMBIS (rIOC | 10) -#define TCRIOMBIC (rIOC | 11) -#define TCRIOTRIAD (rIOC | 12) -#define TCRIOTSTATE (rIOC | 13) - -/* -** 15.10.1998 ARG - ESIL 0761 part fix -** Add RIO ioctls for manipulating RTS and CTS flow control, (as LynxOS -** appears to not support hardware flow control). -*/ -#define TCRIOCTSFLOWEN (rIOC | 14) /* enable CTS flow control */ -#define TCRIOCTSFLOWDIS (rIOC | 15) /* disable CTS flow control */ -#define TCRIORTSFLOWEN (rIOC | 16) /* enable RTS flow control */ -#define TCRIORTSFLOWDIS (rIOC | 17) /* disable RTS flow control */ - -/* -** 09.12.1998 ARG - ESIL 0776 part fix -** Definition for 'RIOC' also appears in daemon.h, so we'd better do a -** #ifndef here first. -** 'RIO_QUICK_CHECK' also #define'd here as this ioctl is now -** allowed to be used by customers. -** -** 05.02.1999 ARG - -** This is what I've decied to do with ioctls etc., which are intended to be -** invoked from users applications : -** Anything that needs to be defined here will be removed from daemon.h, that -** way it won't end up having to be defined/maintained in two places. The only -** consequence of this is that this file should now be #include'd by daemon.h -** -** 'stats' ioctls now #define'd here as they are to be used by customers. -*/ #define RIOC ('R'<<8)|('i'<<16)|('o'<<24) #define RIO_QUICK_CHECK (RIOC | 105) -- cgit v1.2.3 From bb53a76116a8af13ee2581c85c02fe40e0c1a599 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 15 May 2006 09:44:27 -0700 Subject: [PATCH] tpm_register_hardware gcc 4.1 warning fix drivers/char/tpm/tpm.c: In function 'tpm_register_hardware': drivers/char/tpm/tpm.c:1157: warning: assignment from incompatible pointer type Signed-off-by: Daniel Walker Acked-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 54a4c804e25f..050ced247f68 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -140,7 +140,7 @@ extern int tpm_pm_resume(struct device *); extern struct dentry ** tpm_bios_log_setup(char *); extern void tpm_bios_log_teardown(struct dentry **); #else -static inline struct dentry* tpm_bios_log_setup(char *name) +static inline struct dentry ** tpm_bios_log_setup(char *name) { return NULL; } -- cgit v1.2.3 From 7071e522a58cb1b3469e4cd8664ef03a32076349 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 3 Apr 2006 16:04:48 -0700 Subject: [WATCHDOG] sc1200wdt.c printk fix Fix printk output. sc1200wdt: build 20020303<3>sc1200wdt: io parameter must be specified Signed-off-by: Dave Jones Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/sc1200wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c index 515ce7572049..20b88f9b7be2 100644 --- a/drivers/char/watchdog/sc1200wdt.c +++ b/drivers/char/watchdog/sc1200wdt.c @@ -377,7 +377,7 @@ static int __init sc1200wdt_init(void) { int ret; - printk(banner); + printk("%s\n", banner); spin_lock_init(&sc1200wdt_lock); sema_init(&open_sem, 1); -- cgit v1.2.3 From 03a8e359cf760a876f4da9b5c0c165c49564f95a Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sun, 16 Apr 2006 12:52:35 +0200 Subject: [WATCHDOG] i8xx_tco.c - remove support for ICH6 + ICH7 Temporary remove support for ICH6 + ICH7. In these newer TCO's the watchdog timer has changed: the TCO_TMR register is not at the TCOBASE+0x1 offset, but changed it's place to TCOBASE+0x12 and became 10 bit long [0:9]. (Kernel BUG 6031). ICH6 + ICH7 support will be added in a new driver. Code is under test. Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/i8xx_tco.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index a13395e2c372..fa2ba9ebe42a 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c @@ -33,11 +33,6 @@ * 82801E (C-ICH) : document number 273599-001, 273645-002, * 82801EB (ICH5) : document number 252516-001, 252517-003, * 82801ER (ICH5R) : document number 252516-001, 252517-003, - * 82801FB (ICH6) : document number 301473-002, 301474-007, - * 82801FR (ICH6R) : document number 301473-002, 301474-007, - * 82801FBM (ICH6-M) : document number 301473-002, 301474-007, - * 82801FW (ICH6W) : document number 301473-001, 301474-007, - * 82801FRW (ICH6RW) : document number 301473-001, 301474-007 * * 20000710 Nils Faerber * Initial Version 0.01 @@ -66,6 +61,10 @@ * 20050807 Wim Van Sebroeck * 0.08 Make sure that the watchdog is only "armed" when started. * (Kernel Bug 4251) + * 20060416 Wim Van Sebroeck + * 0.09 Remove support for the ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW and + * ICH7 chipsets. (See Kernel Bug 6031 - other code will support these + * chipsets) */ /* @@ -90,7 +89,7 @@ #include "i8xx_tco.h" /* Module and version information */ -#define TCO_VERSION "0.08" +#define TCO_VERSION "0.09" #define TCO_MODULE_NAME "i8xx TCO timer" #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION #define PFX TCO_MODULE_NAME ": " @@ -391,11 +390,6 @@ static struct pci_device_id i8xx_tco_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, /* End of list */ }; -- cgit v1.2.3 From 655516c80ccb3ab2ba2d3063715889b00552a8b3 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 19 Apr 2006 23:02:56 +0100 Subject: [WATCHDOG] s3c2410_wdt.c stop watchdog after boot If the s3c2410 watchdog timer is not enabled by the driver at startup, ensure that it is stopped in-case the boot process has enabled it. Signed-off-by: Ben Dooks Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/s3c2410_wdt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 9dc54736e4eb..1ea04e9b2b0b 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -423,6 +423,12 @@ static int s3c2410wdt_probe(struct platform_device *pdev) if (tmr_atboot && started == 0) { printk(KERN_INFO PFX "Starting Watchdog Timer\n"); s3c2410wdt_start(); + } else if (!tmr_atboot) { + /* if we're not enabling the watchdog, then ensure it is + * disabled if it has been left running from the bootloader + * or other source */ + + s3c2410wdt_stop(); } return 0; -- cgit v1.2.3 From 283a12c53b9abeed89491da4a1eda98f5764947b Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 28 Mar 2006 09:38:45 +0200 Subject: [AGPGART] Enable SIS AGP driver on x86-64 for EM64T systems Enable SIS AGP driver on x86-64 for EM64T systems Untested so far Signed-off-by: Andi Kleen Signed-off-by: Dave Jones --- drivers/char/agp/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 0b9cf9c59a21..7c88c060a9e6 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -86,7 +86,7 @@ config AGP_NVIDIA config AGP_SIS tristate "SiS chipset support" - depends on AGP && X86_32 + depends on AGP help This option gives you AGP support for the GLX component of X on Silicon Integrated Systems [SiS] chipsets. -- cgit v1.2.3 From ca2797ffaabc1f73cf8a73a30f709f0c1a6bef34 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 21 May 2006 17:11:42 -0400 Subject: [AGPGART] Fix Nforce3 suspend on amd64. kernel.org bugzilla #6206 Based on patch from Serge Belyshev Signed-off-by: Dave Jones --- drivers/char/agp/amd64-agp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 36517d4d1ad9..ac3c33a2e37d 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -617,6 +617,9 @@ static int agp_amd64_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); + if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) + nforce3_agp_init(pdev); + return amd_8151_configure(); } -- cgit v1.2.3 From 7dd1d9b85cfb63eebf48fa13d3c5d25a3deb3a25 Mon Sep 17 00:00:00 2001 From: Magnus Kessler Date: Mon, 22 May 2006 10:53:10 +0100 Subject: [AGPGART] VIA PT880 Ultra support. This patch enables agpgart on a Via "PT880 Ultra" based motherboard (Asus P4V800D-X). The PCI ID of the PT880 Ultra is 0x0308 instead of 0x0258 of the PT880. The patched via-agp passes testgart. Signed-off-by: Magnus Kessler Signed-off-by: Dave Jones --- drivers/char/agp/via-agp.c | 7 +++++++ include/linux/pci_ids.h | 1 + 2 files changed, 8 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 97b0a890ba7f..b8ec25d17478 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -345,6 +345,12 @@ static struct agp_device_ids via_agp_device_ids[] __devinitdata = .chipset_name = "PT880", }, + /* PT880 Ultra */ + { + .device_id = PCI_DEVICE_ID_VIA_PT880ULTRA, + .chipset_name = "PT880 Ultra", + }, + /* PT890 */ { .device_id = PCI_DEVICE_ID_VIA_8783_0, @@ -511,6 +517,7 @@ static struct pci_device_id agp_via_pci_table[] = { ID(PCI_DEVICE_ID_VIA_8763_0), ID(PCI_DEVICE_ID_VIA_8378_0), ID(PCI_DEVICE_ID_VIA_PT880), + ID(PCI_DEVICE_ID_VIA_PT880ULTRA), ID(PCI_DEVICE_ID_VIA_8783_0), ID(PCI_DEVICE_ID_VIA_PX8X0_0), ID(PCI_DEVICE_ID_VIA_3269_0), diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d6fe048376ab..590dc6dca315 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1231,6 +1231,7 @@ #define PCI_DEVICE_ID_VIA_8380_0 0x0204 #define PCI_DEVICE_ID_VIA_3238_0 0x0238 #define PCI_DEVICE_ID_VIA_PT880 0x0258 +#define PCI_DEVICE_ID_VIA_PT880ULTRA 0x0308 #define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259 #define PCI_DEVICE_ID_VIA_3269_0 0x0269 #define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282 -- cgit v1.2.3 From ff4547f4aa9823908e9866495598fc65772c2a09 Mon Sep 17 00:00:00 2001 From: Tobias Powalowski Date: Mon, 22 May 2006 22:35:28 -0700 Subject: [PATCH] tty_insert_flip_string_flags() license fix We still don't have the tty layer licensing compatibility quite right. tty_insert_flip_char() used to be inlined in include/linux/tty_flip.h. It is now out-of-lined and hence needs EXPORT_SYMBOL() to be back-compatible. One known offender is the Intel Modem driver. Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index f07637a8f88f..a88b94a82b14 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -398,7 +398,7 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, while (unlikely(size > copied)); return copied; } -EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags); +EXPORT_SYMBOL(tty_insert_flip_string_flags); void tty_schedule_flip(struct tty_struct *tty) { -- cgit v1.2.3 From 087377a4307e18225f6452af5e71fe763c088c4e Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Thu, 25 May 2006 18:44:27 -0700 Subject: [PATCH] tpm: fix bug for TPM on ThinkPad T60 and Z60 The TPM chip on the ThinkPad T60 and Z60 machines is returning 0xFFFF for the vendor ID which is a check the driver made to double check it was actually talking to the memory mapped space of a TPM. This patch removes the check since it isn't absolutely necessary and was causing device discovery to fail on these machines. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index f621168f38ae..8ea70625f7ea 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -457,10 +457,6 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, } vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); - if ((vendor & 0xFFFF) == 0xFFFF) { - rc = -ENODEV; - goto out_err; - } /* Default timeouts */ chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); -- cgit v1.2.3 From de66a695bef17264b2472c06e981c068bfa0636e Mon Sep 17 00:00:00 2001 From: Seiji Munetoh Date: Tue, 30 May 2006 21:25:47 -0700 Subject: [PATCH] tpm: bios log parsing fixes From: Seiji Munetoh Fix "tcpa_pc_event" misalignment between enum, strings and TCG PC spec and output of the event which contains a hash data. Signed-off-by: Seiji Munetoh Acked-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_bios.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index e45f0d3d12de..60380174f245 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -105,6 +105,12 @@ static const char* tcpa_event_type_strings[] = { "Non-Host Info" }; +struct tcpa_pc_event { + u32 event_id; + u32 event_size; + u8 event_data[0]; +}; + enum tcpa_pc_event_ids { SMBIOS = 1, BIS_CERT, @@ -114,14 +120,15 @@ enum tcpa_pc_event_ids { NVRAM, OPTION_ROM_EXEC, OPTION_ROM_CONFIG, - OPTION_ROM_MICROCODE, + OPTION_ROM_MICROCODE = 10, S_CRTM_VERSION, S_CRTM_CONTENTS, POST_CONTENTS, + HOST_TABLE_OF_DEVICES, }; static const char* tcpa_pc_event_id_strings[] = { - "" + "", "SMBIOS", "BIS Certificate", "POST BIOS ", @@ -130,11 +137,12 @@ static const char* tcpa_pc_event_id_strings[] = { "NVRAM", "Option ROM", "Option ROM config", - "Option ROM microcode", + "", + "Option ROM microcode ", "S-CRTM Version", - "S-CRTM Contents", - "S-CRTM POST Contents", - "POST Contents", + "S-CRTM Contents ", + "POST Contents ", + "Table of Devices", }; /* returns pointer to start of pos. entry of tcg log */ @@ -206,7 +214,7 @@ static int get_event_name(char *dest, struct tcpa_event *event, const char *name = ""; char data[40] = ""; int i, n_len = 0, d_len = 0; - u32 event_id; + struct tcpa_pc_event *pc_event; switch(event->event_type) { case PREBOOT: @@ -235,31 +243,32 @@ static int get_event_name(char *dest, struct tcpa_event *event, } break; case EVENT_TAG: - event_id = be32_to_cpu(*((u32 *)event_entry)); + pc_event = (struct tcpa_pc_event *)event_entry; /* ToDo Row data -> Base64 */ - switch (event_id) { + switch (pc_event->event_id) { case SMBIOS: case BIS_CERT: case CMOS: case NVRAM: case OPTION_ROM_EXEC: case OPTION_ROM_CONFIG: - case OPTION_ROM_MICROCODE: case S_CRTM_VERSION: - case S_CRTM_CONTENTS: - case POST_CONTENTS: - name = tcpa_pc_event_id_strings[event_id]; + name = tcpa_pc_event_id_strings[pc_event->event_id]; n_len = strlen(name); break; + /* hash data */ case POST_BIOS_ROM: case ESCD: - name = tcpa_pc_event_id_strings[event_id]; + case OPTION_ROM_MICROCODE: + case S_CRTM_CONTENTS: + case POST_CONTENTS: + name = tcpa_pc_event_id_strings[pc_event->event_id]; n_len = strlen(name); for (i = 0; i < 20; i++) - d_len += sprintf(data, "%02x", - event_entry[8 + i]); + d_len += sprintf(&data[2*i], "%02x", + pc_event->event_data[i]); break; default: break; -- cgit v1.2.3 From 44d7aff035118e8c3993aa3fa05d358d1008e982 Mon Sep 17 00:00:00 2001 From: Seiji Munetoh Date: Tue, 30 May 2006 21:25:52 -0700 Subject: [PATCH] tpm: more bios log parsing fixes From: Seiji Munetoh Change the binary output format to actual ACPI TCPA log structure since the current format does not contain all event-data information that need to verify the PCRs in TPM. tpm_binary_bios_measurements_show() uses get_event_name() to convert the binary event-data to ascii format, and puts them as binary. However, to verify the PCRs, the event-data must be a actual binary event-data used by SHA1 calc. in BIOS. So, I think actual ACPI TCPA log is good for this binary output format. That way, any userland tools easily parse this data with reference to TCG PC specification. Signed-off-by: Seiji Munetoh Acked-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_bios.c | 48 ++++----------------------------------------- 1 file changed, 4 insertions(+), 44 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 60380174f245..a611972024e6 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -284,53 +284,13 @@ static int get_event_name(char *dest, struct tcpa_event *event, static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) { + struct tcpa_event *event = v; + char *data = v; + int i; - char *eventname; - char data[4]; - u32 help; - int i, len; - struct tcpa_event *event = (struct tcpa_event *) v; - unsigned char *event_entry = - (unsigned char *) (v + sizeof(struct tcpa_event)); - - eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); - if (!eventname) { - printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", - __func__); - return -ENOMEM; - } - - /* 1st: PCR used is in little-endian format (4 bytes) */ - help = le32_to_cpu(event->pcr_index); - memcpy(data, &help, 4); - for (i = 0; i < 4; i++) - seq_putc(m, data[i]); - - /* 2nd: SHA1 (20 bytes) */ - for (i = 0; i < 20; i++) - seq_putc(m, event->pcr_value[i]); - - /* 3rd: event type identifier (4 bytes) */ - help = le32_to_cpu(event->event_type); - memcpy(data, &help, 4); - for (i = 0; i < 4; i++) + for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++) seq_putc(m, data[i]); - len = 0; - - len += get_event_name(eventname, event, event_entry); - - /* 4th: filename <= 255 + \'0' delimiter */ - if (len > TCG_EVENT_NAME_LEN_MAX) - len = TCG_EVENT_NAME_LEN_MAX; - - for (i = 0; i < len; i++) - seq_putc(m, eventname[i]); - - /* 5th: delimiter */ - seq_putc(m, '\0'); - - kfree(eventname); return 0; } -- cgit v1.2.3 From d61a3ead268084cc271d7b2aa2950fc822a37cf5 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 30 May 2006 21:25:57 -0700 Subject: [PATCH] IPMI: reserve I/O ports separately From: Corey Minyard This patch is pretty important to get in for IPMI, new systems have been changing the way ACPI and IPMI interact, and this works around the problems for now. This is a temporary fix until we get proper ACPI handling in IPMI. Fixed releasing already-allocated regions when a later request fails, and forward-ported it to HEAD. Some BIOSes reserve disjoint I/O regions in their ACPI tables for the IPMI controller. This causes problems when trying to register the entire I/O region. Therefore we must register each I/O port separately. Signed-off-by: Jordan Hargrave Signed-off-by: Matt Domsch Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b36eef0e9d19..02a7dd7a8a55 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1184,20 +1184,20 @@ static void port_outl(struct si_sm_io *io, unsigned int offset, static void port_cleanup(struct smi_info *info) { unsigned int addr = info->io.addr_data; - int mapsize; + int idx; if (addr) { - mapsize = ((info->io_size * info->io.regspacing) - - (info->io.regspacing - info->io.regsize)); - - release_region (addr, mapsize); + for (idx = 0; idx < info->io_size; idx++) { + release_region(addr + idx * info->io.regspacing, + info->io.regsize); + } } } static int port_setup(struct smi_info *info) { unsigned int addr = info->io.addr_data; - int mapsize; + int idx; if (!addr) return -ENODEV; @@ -1225,16 +1225,22 @@ static int port_setup(struct smi_info *info) return -EINVAL; } - /* Calculate the total amount of memory to claim. This is an - * unusual looking calculation, but it avoids claiming any - * more memory than it has to. It will claim everything - * between the first address to the end of the last full - * register. */ - mapsize = ((info->io_size * info->io.regspacing) - - (info->io.regspacing - info->io.regsize)); - - if (request_region(addr, mapsize, DEVICE_NAME) == NULL) - return -EIO; + /* Some BIOSes reserve disjoint I/O regions in their ACPI + * tables. This causes problems when trying to register the + * entire I/O region. Therefore we must register each I/O + * port separately. + */ + for (idx = 0; idx < info->io_size; idx++) { + if (request_region(addr + idx * info->io.regspacing, + info->io.regsize, DEVICE_NAME) == NULL) { + /* Undo allocations */ + while (idx--) { + release_region(addr + idx * info->io.regspacing, + info->io.regsize); + } + return -EIO; + } + } return 0; } -- cgit v1.2.3 From 760f1fce030ccc620ec430a8aff8fc604e7891ed Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 30 May 2006 21:26:03 -0700 Subject: [PATCH] revert "swsusp add check for suspension of X controlled devices" From: Andrew Morton Revert commit ff4da2e262d2509fe1bacff70dd00934be569c66. It broke APM suspend, probably because APM doesn't switch back to a VT when suspending. Tracked down by Matt Mackall Rafael sayeth: "It only fixed the theoretical issue that a quick-handed user could switch to X after processes have been frozen and before the devices are suspended. With the current userland suspend tools it shouldn't be necessary." Cc: Pavel Machek Cc: "Rafael J. Wysocki" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/power/suspend.c | 5 +---- drivers/char/vt.c | 8 -------- include/linux/vt_kern.h | 5 ----- 3 files changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers/char') diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 662209d3f42d..2a769cc6f5f9 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -8,7 +8,6 @@ * */ -#include #include #include #include @@ -66,6 +65,7 @@ int suspend_device(struct device * dev, pm_message_t state) return error; } + /** * device_suspend - Save state and stop all devices in system. * @state: Power state to put each device in. @@ -85,9 +85,6 @@ int device_suspend(pm_message_t state) { int error = 0; - if (!is_console_suspend_safe()) - return -EINVAL; - down(&dpm_sem); down(&dpm_list_sem); while (!list_empty(&dpm_active) && error == 0) { diff --git a/drivers/char/vt.c b/drivers/char/vt.c index acc5d47844eb..6c94879e0b99 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -3238,14 +3238,6 @@ void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org) } } -int is_console_suspend_safe(void) -{ - /* It is unsafe to suspend devices while X has control of the - * hardware. Make sure we are running on a kernel-controlled console. - */ - return vc_cons[fg_console].d->vc_mode == KD_TEXT; -} - /* * Visible symbols for modules */ diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 530ae3f4248c..fab5aed8ca31 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -73,11 +73,6 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc); int vt_waitactive(int vt); void change_console(struct vc_data *new_vc); void reset_vc(struct vc_data *vc); -#ifdef CONFIG_VT -int is_console_suspend_safe(void); -#else -static inline int is_console_suspend_safe(void) { return 1; } -#endif /* * vc_screen.c shares this temporary buffer with the console write code so that -- cgit v1.2.3 From 2b0dd802ba1ff9b7001f5f9bd9b4d192a4aabf81 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 1 Jun 2006 18:29:20 +0200 Subject: [PATCH] pcmcia: fix zeroing of cm4000_cs.c data Fix the incorrect calculation of how much to zero out in struct cm4000_dev on device initialization. Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/cm4000_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 128b2632512d..eab5394da666 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -149,7 +149,7 @@ struct cm4000_dev { #define ZERO_DEV(dev) \ memset(&dev->atr_csum,0, \ sizeof(struct cm4000_dev) - \ - /*link*/ sizeof(struct pcmcia_device) - \ + /*link*/ sizeof(struct pcmcia_device *) - \ /*node*/ sizeof(dev_node_t) - \ /*atr*/ MAX_ATR*sizeof(char) - \ /*rbuf*/ 512*sizeof(char) - \ -- cgit v1.2.3