diff --git a/[refs] b/[refs] index ab975840d084..c4721063cbbd 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 93e1b7d42e1edb4ddde6257e9a02513fef26f715 +refs/heads/master: 7daa411b810d7eadfaabe3765ec5f827893dbb30 diff --git a/trunk/arch/powerpc/kernel/iommu.c b/trunk/arch/powerpc/kernel/iommu.c index d9a7fdef59b9..4eba60a32890 100644 --- a/trunk/arch/powerpc/kernel/iommu.c +++ b/trunk/arch/powerpc/kernel/iommu.c @@ -61,6 +61,7 @@ __setup("iommu=", setup_iommu); static unsigned long iommu_range_alloc(struct iommu_table *tbl, unsigned long npages, unsigned long *handle, + unsigned long mask, unsigned int align_order) { unsigned long n, end, i, start; @@ -97,9 +98,21 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, */ if (start >= limit) start = largealloc ? tbl->it_largehint : tbl->it_hint; - + again: + if (limit + tbl->it_offset > mask) { + limit = mask - tbl->it_offset + 1; + /* If we're constrained on address range, first try + * at the masked hint to avoid O(n) search complexity, + * but on second pass, start at 0. + */ + if ((start & mask) >= limit || pass > 0) + start = 0; + else + start &= mask; + } + n = find_next_zero_bit(tbl->it_map, limit, start); /* Align allocation */ @@ -150,14 +163,14 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *page, unsigned int npages, enum dma_data_direction direction, - unsigned int align_order) + unsigned long mask, unsigned int align_order) { unsigned long entry, flags; dma_addr_t ret = DMA_ERROR_CODE; - + spin_lock_irqsave(&(tbl->it_lock), flags); - entry = iommu_range_alloc(tbl, npages, NULL, align_order); + entry = iommu_range_alloc(tbl, npages, NULL, mask, align_order); if (unlikely(entry == DMA_ERROR_CODE)) { spin_unlock_irqrestore(&(tbl->it_lock), flags); @@ -236,7 +249,7 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, int iommu_map_sg(struct device *dev, struct iommu_table *tbl, struct scatterlist *sglist, int nelems, - enum dma_data_direction direction) + unsigned long mask, enum dma_data_direction direction) { dma_addr_t dma_next = 0, dma_addr; unsigned long flags; @@ -274,7 +287,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, vaddr = (unsigned long)page_address(s->page) + s->offset; npages = PAGE_ALIGN(vaddr + slen) - (vaddr & PAGE_MASK); npages >>= PAGE_SHIFT; - entry = iommu_range_alloc(tbl, npages, &handle, 0); + entry = iommu_range_alloc(tbl, npages, &handle, mask >> PAGE_SHIFT, 0); DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen); @@ -479,7 +492,8 @@ void iommu_free_table(struct device_node *dn) * byte within the page as vaddr. */ dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, - size_t size, enum dma_data_direction direction) + size_t size, unsigned long mask, + enum dma_data_direction direction) { dma_addr_t dma_handle = DMA_ERROR_CODE; unsigned long uaddr; @@ -492,7 +506,8 @@ dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, npages >>= PAGE_SHIFT; if (tbl) { - dma_handle = iommu_alloc(tbl, vaddr, npages, direction, 0); + dma_handle = iommu_alloc(tbl, vaddr, npages, direction, + mask >> PAGE_SHIFT, 0); if (dma_handle == DMA_ERROR_CODE) { if (printk_ratelimit()) { printk(KERN_INFO "iommu_alloc failed, " @@ -521,7 +536,7 @@ void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, * to the dma address (mapping) of the first page. */ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, - dma_addr_t *dma_handle, gfp_t flag) + dma_addr_t *dma_handle, unsigned long mask, gfp_t flag) { void *ret = NULL; dma_addr_t mapping; @@ -551,7 +566,8 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, memset(ret, 0, size); /* Set up tces to cover the allocated range */ - mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL, order); + mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL, + mask >> PAGE_SHIFT, order); if (mapping == DMA_ERROR_CODE) { free_pages((unsigned long)ret, order); ret = NULL; diff --git a/trunk/arch/powerpc/kernel/pci_iommu.c b/trunk/arch/powerpc/kernel/pci_iommu.c index c336f3e31cff..c1d95e14bbed 100644 --- a/trunk/arch/powerpc/kernel/pci_iommu.c +++ b/trunk/arch/powerpc/kernel/pci_iommu.c @@ -59,6 +59,25 @@ static inline struct iommu_table *devnode_table(struct device *dev) } +static inline unsigned long device_to_mask(struct device *hwdev) +{ + struct pci_dev *pdev; + + if (!hwdev) { + pdev = ppc64_isabridge_dev; + if (!pdev) /* This is the best guess we can do */ + return 0xfffffffful; + } else + pdev = to_pci_dev(hwdev); + + if (pdev->dma_mask) + return pdev->dma_mask; + + /* Assume devices without mask can take 32 bit addresses */ + return 0xfffffffful; +} + + /* Allocates a contiguous real buffer and creates mappings over it. * Returns the virtual address of the buffer and sets dma_handle * to the dma address (mapping) of the first page. @@ -67,7 +86,7 @@ static void *pci_iommu_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { return iommu_alloc_coherent(devnode_table(hwdev), size, dma_handle, - flag); + device_to_mask(hwdev), flag); } static void pci_iommu_free_coherent(struct device *hwdev, size_t size, @@ -85,7 +104,8 @@ static void pci_iommu_free_coherent(struct device *hwdev, size_t size, static dma_addr_t pci_iommu_map_single(struct device *hwdev, void *vaddr, size_t size, enum dma_data_direction direction) { - return iommu_map_single(devnode_table(hwdev), vaddr, size, direction); + return iommu_map_single(devnode_table(hwdev), vaddr, size, + device_to_mask(hwdev), direction); } @@ -100,7 +120,7 @@ static int pci_iommu_map_sg(struct device *pdev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { return iommu_map_sg(pdev, devnode_table(pdev), sglist, - nelems, direction); + nelems, device_to_mask(pdev), direction); } static void pci_iommu_unmap_sg(struct device *pdev, struct scatterlist *sglist, @@ -112,7 +132,19 @@ static void pci_iommu_unmap_sg(struct device *pdev, struct scatterlist *sglist, /* We support DMA to/from any memory page via the iommu */ static int pci_iommu_dma_supported(struct device *dev, u64 mask) { - return 1; + struct iommu_table *tbl = devnode_table(dev); + + if (!tbl || tbl->it_offset > mask) { + printk(KERN_INFO "Warning: IOMMU table offset too big for device mask\n"); + if (tbl) + printk(KERN_INFO "mask: 0x%08lx, table offset: 0x%08lx\n", + mask, tbl->it_offset); + else + printk(KERN_INFO "mask: 0x%08lx, table unavailable\n", + mask); + return 0; + } else + return 1; } void pci_iommu_init(void) diff --git a/trunk/arch/powerpc/kernel/vio.c b/trunk/arch/powerpc/kernel/vio.c index 13c655ba2841..971020cf3f7d 100644 --- a/trunk/arch/powerpc/kernel/vio.c +++ b/trunk/arch/powerpc/kernel/vio.c @@ -202,7 +202,7 @@ static dma_addr_t vio_map_single(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { return iommu_map_single(to_vio_dev(dev)->iommu_table, vaddr, size, - direction); + ~0ul, direction); } static void vio_unmap_single(struct device *dev, dma_addr_t dma_handle, @@ -216,7 +216,7 @@ static int vio_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { return iommu_map_sg(dev, to_vio_dev(dev)->iommu_table, sglist, - nelems, direction); + nelems, ~0ul, direction); } static void vio_unmap_sg(struct device *dev, struct scatterlist *sglist, @@ -229,7 +229,7 @@ static void *vio_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { return iommu_alloc_coherent(to_vio_dev(dev)->iommu_table, size, - dma_handle, flag); + dma_handle, ~0ul, flag); } static void vio_free_coherent(struct device *dev, size_t size, diff --git a/trunk/arch/x86_64/ia32/Makefile b/trunk/arch/x86_64/ia32/Makefile index e9263b4975e0..929e6b0771f8 100644 --- a/trunk/arch/x86_64/ia32/Makefile +++ b/trunk/arch/x86_64/ia32/Makefile @@ -27,5 +27,5 @@ $(obj)/vsyscall-sysenter.so $(obj)/vsyscall-syscall.so: \ $(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE $(call if_changed,syscall) -AFLAGS_vsyscall-sysenter.o = -m32 -Wa,-32 -AFLAGS_vsyscall-syscall.o = -m32 -Wa,-32 +AFLAGS_vsyscall-sysenter.o = -m32 +AFLAGS_vsyscall-syscall.o = -m32 diff --git a/trunk/arch/x86_64/kernel/pci-gart.c b/trunk/arch/x86_64/kernel/pci-gart.c index 9d3d76c85ae7..a6c01e121266 100644 --- a/trunk/arch/x86_64/kernel/pci-gart.c +++ b/trunk/arch/x86_64/kernel/pci-gart.c @@ -112,6 +112,10 @@ static unsigned long alloc_iommu(int size) static void free_iommu(unsigned long offset, int size) { unsigned long flags; + if (size == 1) { + clear_bit(offset, iommu_gart_bitmap); + return; + } spin_lock_irqsave(&iommu_bitmap_lock, flags); __clear_bit_string(iommu_gart_bitmap, offset, size); spin_unlock_irqrestore(&iommu_bitmap_lock, flags); diff --git a/trunk/arch/x86_64/mm/numa.c b/trunk/arch/x86_64/mm/numa.c index b2fac14baac0..cc02573a3271 100644 --- a/trunk/arch/x86_64/mm/numa.c +++ b/trunk/arch/x86_64/mm/numa.c @@ -188,13 +188,11 @@ void __init setup_node_zones(int nodeid) memory. */ memmapsize = sizeof(struct page) * (end_pfn-start_pfn); limit = end_pfn << PAGE_SHIFT; -#ifdef CONFIG_FLAT_NODE_MEM_MAP NODE_DATA(nodeid)->node_mem_map = __alloc_bootmem_core(NODE_DATA(nodeid)->bdata, memmapsize, SMP_CACHE_BYTES, round_down(limit - memmapsize, PAGE_SIZE), limit); -#endif size_zones(zones, holes, start_pfn, end_pfn); free_area_init_node(nodeid, NODE_DATA(nodeid), zones, diff --git a/trunk/drivers/char/snsc.c b/trunk/drivers/char/snsc.c index 56c8243cdb73..b543821d8cb4 100644 --- a/trunk/drivers/char/snsc.c +++ b/trunk/drivers/char/snsc.c @@ -390,8 +390,7 @@ scdrv_init(void) format_module_id(devnamep, geo_module(geoid), MODULE_FORMAT_BRIEF); devnamep = devname + strlen(devname); - sprintf(devnamep, "^%d#%d", geo_slot(geoid), - geo_slab(geoid)); + sprintf(devnamep, "#%d", geo_slab(geoid)); /* allocate sysctl device data */ scd = kzalloc(sizeof (struct sysctl_data_s), diff --git a/trunk/drivers/char/tpm/Kconfig b/trunk/drivers/char/tpm/Kconfig index 1efde3b27619..a6873bf89ffa 100644 --- a/trunk/drivers/char/tpm/Kconfig +++ b/trunk/drivers/char/tpm/Kconfig @@ -20,18 +20,9 @@ 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 && PNPACPI + depends on TCG_TPM ---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/trunk/drivers/char/tpm/Makefile b/trunk/drivers/char/tpm/Makefile index ea3a1e02a824..ba4582d160fd 100644 --- a/trunk/drivers/char/tpm/Makefile +++ b/trunk/drivers/char/tpm/Makefile @@ -5,7 +5,6 @@ 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/trunk/drivers/char/tpm/tpm.c b/trunk/drivers/char/tpm/tpm.c index 6889e7db3aff..5a3870477ef1 100644 --- a/trunk/drivers/char/tpm/tpm.c +++ b/trunk/drivers/char/tpm/tpm.c @@ -32,291 +32,12 @@ 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 { - 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 DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); - -/* - * 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 int dev_mask[TPM_NUM_MASK_ENTRIES]; static void user_reader_timeout(unsigned long ptr) { @@ -325,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; @@ -335,32 +56,6 @@ 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]; - if (duration <= 0) - return 2 * 60 * HZ; - else - return duration; -} -EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); - /* * Internal kernel interface to transmit TPM commands */ @@ -368,11 +63,11 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, size_t bufsiz) { ssize_t rc; - u32 count, ordinal; + u32 count; 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) { @@ -383,23 +78,21 @@ 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; } - if (chip->vendor.irq) - goto out_recv; - - stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); + 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; @@ -409,13 +102,14 @@ 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); @@ -425,247 +119,17 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, } #define TPM_DIGEST_SIZE 20 -#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_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, -}; - -/* - * 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[] = { +#define CAP_PCR_RESULT_SIZE 18 +static const u8 cap_pcr[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 22, /* length */ 0, 0, 0, 101, /* TPM_ORD_GetCapability */ - 0, 0, 0, 0, /* TPM_CAP_ */ - 0, 0, 0, 4, /* TPM_CAP_SUB_ size */ - 0, 0, 1, 0 /* TPM_CAP_SUB_ */ + 0, 0, 0, 5, + 0, 0, 0, 4, + 0, 0, 1, 1 }; -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; -} - -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 = msecs_to_jiffies(timeout); - timeout = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); - if (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 = msecs_to_jiffies(timeout); - timeout = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); - if (timeout) - chip->vendor.timeout_d = msecs_to_jiffies(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] = - msecs_to_jiffies(be32_to_cpu - (*((__be32 *) (data + - TPM_GET_CAP_RET_UINT32_1_IDX)))); - chip->vendor.duration[TPM_MEDIUM] = - msecs_to_jiffies(be32_to_cpu - (*((__be32 *) (data + - TPM_GET_CAP_RET_UINT32_2_IDX)))); - chip->vendor.duration[TPM_LONG] = - msecs_to_jiffies(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); - +#define READ_PCR_RESULT_SIZE 30 static const u8 pcrread[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 14, /* length */ @@ -676,8 +140,8 @@ static const u8 pcrread[] = { ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, char *buf) { - u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)), 30)]; - ssize_t rc; + u8 data[READ_PCR_RESULT_SIZE]; + ssize_t len; int i, j, num_pcrs; __be32 index; char *str = buf; @@ -686,24 +150,29 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, 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_PCR; - - rc = transmit_cmd(chip, data, sizeof(data), - "attempting to determine the number of PCRS"); - if (rc) + 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)))); 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); - rc = transmit_cmd(chip, data, sizeof(data), - "attempting to read a PCR"); - if (rc) + 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); goto out; + } str += sprintf(str, "PCR-%02d: ", i); for (j = 0; j < TPM_DIGEST_SIZE; j++) str += sprintf(str, "%02X ", *(data + 10 + j)); @@ -725,7 +194,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, char *buf) { u8 *data; - ssize_t err; + ssize_t len; int i, rc; char *str = buf; @@ -739,10 +208,14 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, memcpy(data, readpubek, sizeof(readpubek)); - err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE, - "attempting to read the PUBEK"); - if (err) + 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; goto out; + } /* ignore header 10 bytes @@ -772,68 +245,36 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, if ((i + 1) % 16 == 0) str += sprintf(str, "\n"); } -out: rc = str - buf; +out: kfree(data); return rc; } EXPORT_SYMBOL_GPL(tpm_show_pubek); -#define CAP_VERSION_1_1 6 -#define CAP_VERSION_1_2 0x1A -#define CAP_VERSION_IDX 13 +#define CAP_VER_RESULT_SIZE 18 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, 0, + 0, 0, 0, 6, 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[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; - ssize_t rc; - 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; - - 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 + 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; - - 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); - -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)]; + u8 data[sizeof(cap_manufacturer)]; ssize_t len; char *str = buf; @@ -841,40 +282,29 @@ ssize_t tpm_show_caps_1_2(struct device * 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; + memcpy(data, cap_manufacturer, sizeof(cap_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; - } + if ((len = tpm_transmit(chip, data, sizeof(data))) < + CAP_MANUFACTURER_RESULT_SIZE) + return len; str += sprintf(str, "Manufacturer: 0x%x\n", - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); + be32_to_cpu(*((__be32 *) (data + 14)))); 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]); + 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]); -out: return str - buf; } -EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); +EXPORT_SYMBOL_GPL(tpm_show_caps); ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -883,7 +313,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); @@ -899,7 +329,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; } @@ -957,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; @@ -989,10 +419,11 @@ 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; @@ -1031,13 +462,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); - clear_bit(chip->dev_num, dev_mask); + dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= + ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); kfree(chip); @@ -1088,18 +520,18 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); * upon errant exit from this function specific probe function should call * pci_disable_device */ -struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific - *entry) +int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) { #define DEVNAME_SIZE 7 char *devname; struct tpm_chip *chip; + int i, j; /* Driver specific per-device data */ chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) - return NULL; + return -ENOMEM; init_MUTEX(&chip->buffer_mutex); init_MUTEX(&chip->tpm_mutex); @@ -1111,37 +543,45 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend chip->user_read_timer.function = user_reader_timeout; chip->user_read_timer.data = (unsigned long) chip; - memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); + chip->vendor = entry; + + 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; + } - if (chip->dev_num >= TPM_NUM_DEVICES) { +dev_num_search_complete: + if (chip->dev_num < 0) { dev_err(dev, "No available tpm device numbers\n"); kfree(chip); - return NULL; + 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; - - set_bit(chip->dev_num, dev_mask); + 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); - clear_bit(chip->dev_num, dev_mask); kfree(chip); - return NULL; + dev_mask[i] &= !(1 << j); + return -ENODEV; } spin_lock(&driver_lock); @@ -1152,11 +592,11 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend 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); - return chip; + return 0; } EXPORT_SYMBOL_GPL(tpm_register_hardware); diff --git a/trunk/drivers/char/tpm/tpm.h b/trunk/drivers/char/tpm/tpm.h index 54a4c804e25f..dec0224b4478 100644 --- a/trunk/drivers/char/tpm/tpm.h +++ b/trunk/drivers/char/tpm/tpm.h @@ -42,30 +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; struct tpm_vendor_specific { - const u8 req_complete_mask; - const u8 req_complete_val; - const u8 req_canceled; + u8 req_complete_mask; + u8 req_complete_val; + u8 req_canceled; void __iomem *iobase; /* ioremapped address */ unsigned long base; /* TPM base address */ - int irq; - int region_size; int have_region; @@ -75,13 +63,6 @@ struct tpm_vendor_specific { u8 (*status) (struct tpm_chip *); struct miscdevice miscdev; struct attribute_group *attr_group; - struct list_head list; - int locality; - unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ - unsigned long duration[3]; /* jiffies */ - - wait_queue_head_t read_queue; - wait_queue_head_t int_queue; }; struct tpm_chip { @@ -100,15 +81,13 @@ 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; 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); @@ -121,12 +100,8 @@ 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 *); +extern int tpm_register_hardware(struct device *, + 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/trunk/drivers/char/tpm/tpm_atmel.c b/trunk/drivers/char/tpm/tpm_atmel.c index 58a258cec153..ff3654964fe3 100644 --- a/trunk/drivers/char/tpm/tpm_atmel.c +++ b/trunk/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 = { @@ -140,7 +140,7 @@ static struct attribute* atmel_attrs[] = { static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; -static const struct tpm_vendor_specific tpm_atmel = { +static struct tpm_vendor_specific tpm_atmel = { .recv = tpm_atml_recv, .send = tpm_atml_send, .cancel = tpm_atml_cancel, @@ -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.iobase); + if (chip->vendor->have_region) + atmel_release_region(chip->vendor->base, + chip->vendor->region_size); + atmel_put_base_addr(chip->vendor); tpm_remove_hardware(chip->dev); platform_device_unregister(pdev); } @@ -179,22 +179,18 @@ 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 ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) { + if ((tpm_atmel.iobase = atmel_get_base_addr(&tpm_atmel)) == NULL) { rc = -ENODEV; goto err_unreg_drv; } - have_region = + tpm_atmel.have_region = (atmel_request_region - (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; - + (tpm_atmel.base, tpm_atmel.region_size, + "tpm_atmel0") == NULL) ? 0 : 1; if (IS_ERR (pdev = @@ -203,25 +199,17 @@ static int __init init_atmel(void) goto err_rel_reg; } - if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) { - rc = -ENODEV; + if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) 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(iobase); - if (have_region) - atmel_release_region(base, - region_size); + atmel_put_base_addr(&tpm_atmel); + if (tpm_atmel.have_region) + atmel_release_region(tpm_atmel.base, + tpm_atmel.region_size); err_unreg_drv: driver_unregister(&atml_drv); return rc; diff --git a/trunk/drivers/char/tpm/tpm_atmel.h b/trunk/drivers/char/tpm/tpm_atmel.h index 2e68eeb8a2cd..d3478aaadd77 100644 --- a/trunk/drivers/char/tpm/tpm_atmel.h +++ b/trunk/drivers/char/tpm/tpm_atmel.h @@ -28,12 +28,13 @@ #define atmel_request_region request_mem_region #define atmel_release_region release_mem_region -static inline void atmel_put_base_addr(void __iomem *iobase) +static inline void atmel_put_base_addr(struct tpm_vendor_specific + *vendor) { - iounmap(iobase); + iounmap(vendor->iobase); } -static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) +static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific *vendor) { struct device_node *dn; unsigned long address, size; @@ -70,9 +71,9 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) else size = reg[naddrc]; - *base = address; - *region_size = size; - return ioremap(*base, *region_size); + vendor->base = address; + vendor->region_size = size; + return ioremap(vendor->base, vendor->region_size); } #else #define atmel_getb(chip, offset) inb(chip->vendor->base + offset) @@ -105,12 +106,14 @@ static int atmel_verify_tpm11(void) return 0; } -static inline void atmel_put_base_addr(void __iomem *iobase) +static inline void atmel_put_base_addr(struct tpm_vendor_specific + *vendor) { } /* Determine where to talk to device */ -static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) +static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific + *vendor) { int lo, hi; @@ -120,9 +123,9 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); - *base = (hi << 8) | lo; - *region_size = 2; + vendor->base = (hi << 8) | lo; + vendor->region_size = 2; - return ioport_map(*base, *region_size); + return ioport_map(vendor->base, vendor->region_size); } #endif diff --git a/trunk/drivers/char/tpm/tpm_bios.c b/trunk/drivers/char/tpm/tpm_bios.c index e45f0d3d12de..537aa45d8c67 100644 --- a/trunk/drivers/char/tpm/tpm_bios.c +++ b/trunk/drivers/char/tpm/tpm_bios.c @@ -29,11 +29,6 @@ #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; @@ -41,18 +36,9 @@ struct tpm_bios_log { struct acpi_tcpa { struct acpi_table_header hdr; - 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; - }; + u16 reserved; + u32 log_max_len __attribute__ ((packed)); + u32 log_start_addr __attribute__ ((packed)); }; struct tcpa_event { @@ -134,7 +120,6 @@ 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 */ @@ -321,7 +306,6 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) /* 5th: delimiter */ seq_putc(m, '\0'); - kfree(eventname); return 0; } @@ -369,7 +353,6 @@ 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; } @@ -393,7 +376,6 @@ 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 @@ -414,37 +396,27 @@ static int read_log(struct tpm_bios_log *log) return -EIO; } - 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) { + if (buff->log_max_len == 0) { printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); return -EIO; } /* malloc EventLog space */ - log->bios_event_log = kmalloc(len, GFP_KERNEL); + log->bios_event_log = kmalloc(buff->log_max_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 + len; + log->bios_event_log_end = log->bios_event_log + buff->log_max_len; - acpi_os_map_memory(start, len, (void *) &virt); + acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, (void *) &virt); - memcpy(log->bios_event_log, virt, len); + memcpy(log->bios_event_log, virt, buff->log_max_len); - acpi_os_unmap_memory(virt, len); + acpi_os_unmap_memory(virt, buff->log_max_len); return 0; } diff --git a/trunk/drivers/char/tpm/tpm_infineon.c b/trunk/drivers/char/tpm/tpm_infineon.c index adfff21beb21..24095f6ee6da 100644 --- a/trunk/drivers/char/tpm/tpm_infineon.c +++ b/trunk/drivers/char/tpm/tpm_infineon.c @@ -15,7 +15,6 @@ * License. */ -#include #include #include "tpm.h" @@ -105,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; @@ -125,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; @@ -139,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; @@ -158,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 @@ -205,7 +204,7 @@ static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count) 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) { @@ -220,7 +219,7 @@ static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count) 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)) { @@ -269,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) { @@ -320,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); @@ -347,7 +346,7 @@ static struct file_operations inf_ops = { .release = tpm_release, }; -static const struct tpm_vendor_specific tpm_inf = { +static struct tpm_vendor_specific tpm_inf = { .recv = tpm_inf_recv, .send = tpm_inf_send, .cancel = tpm_inf_cancel, @@ -376,7 +375,6 @@ 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) && @@ -397,13 +395,14 @@ 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; } @@ -443,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); @@ -453,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%x\n", - TPM_INF_BASE); + "Could not set IO-ports to 0x%lx\n", + tpm_inf.base); rc = -EIO; goto err_release_region; } @@ -467,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 0x%02x%02x, " - "vendor id 0x%x%x (Infineon), " - "product id 0x%02x%02x" + "chip version %02x%02x, " + "vendor id %x%x (Infineon), " + "product id %02x%02x" "%s\n", TPM_INF_ADDR, TPM_INF_BASE, @@ -483,10 +482,11 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, vendorid[0], vendorid[1], productid[0], productid[1], chipname); - if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) { + rc = tpm_register_hardware(&dev->dev, &tpm_inf); + if (rc < 0) { + rc = -ENODEV; goto err_release_region; } - chip->vendor.base = TPM_INF_BASE; return 0; } else { rc = -ENODEV; @@ -494,7 +494,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,8 +506,7 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) struct tpm_chip *chip = pnp_get_drvdata(dev); if (chip) { - release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); - release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); + release_region(chip->vendor->base, TPM_INF_PORT_LEN); tpm_remove_hardware(chip->dev); } } @@ -521,7 +520,7 @@ static struct pnp_driver tpm_inf_pnp = { }, .id_table = tpm_pnp_tbl, .probe = tpm_inf_pnp_probe, - .remove = __devexit_p(tpm_inf_pnp_remove), + .remove = tpm_inf_pnp_remove, }; static int __init init_inf(void) @@ -539,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.8"); +MODULE_VERSION("1.7"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/char/tpm/tpm_nsc.c b/trunk/drivers/char/tpm/tpm_nsc.c index 4c8bc06c7d95..680a8e331887 100644 --- a/trunk/drivers/char/tpm/tpm_nsc.c +++ b/trunk/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 = { @@ -250,7 +250,7 @@ static struct attribute * nsc_attrs[] = { static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; -static const struct tpm_vendor_specific tpm_nsc = { +static struct tpm_vendor_specific tpm_nsc = { .recv = tpm_nsc_recv, .send = tpm_nsc_send, .cancel = tpm_nsc_cancel, @@ -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); } } @@ -286,8 +286,7 @@ 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) { @@ -301,7 +300,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); - base = (hi<<8) | lo; + tpm_nsc.base = (hi<<8) | lo; /* enable the DPM module */ tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); @@ -321,15 +320,13 @@ static int __init init_nsc(void) if ((rc = platform_device_register(pdev)) < 0) goto err_free_dev; - if (request_region(base, 2, "tpm_nsc0") == NULL ) { + if (request_region(tpm_nsc.base, 2, "tpm_nsc0") == NULL ) { rc = -EBUSY; goto err_unreg_dev; } - if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) { - rc = -ENODEV; + if ((rc = tpm_register_hardware(&pdev->dev, &tpm_nsc)) < 0) goto err_rel_reg; - } dev_dbg(&pdev->dev, "NSC TPM detected\n"); dev_dbg(&pdev->dev, @@ -364,12 +361,10 @@ 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(base, 2); + release_region(tpm_nsc.base, 2); err_unreg_dev: platform_device_unregister(pdev); err_free_dev: diff --git a/trunk/drivers/char/tpm/tpm_tis.c b/trunk/drivers/char/tpm/tpm_tis.c deleted file mode 100644 index b9cae9a238bb..000000000000 --- a/trunk/drivers/char/tpm/tpm_tis.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * 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 -#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, -}; - -enum tis_defaults { - TIS_MEM_BASE = 0xFED4000, - TIS_MEM_LEN = 0x5000, - 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)) -#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), - chip->vendor.timeout_a); - if (rc > 0) - return l; - - } else { - /* wait for burstcount */ - stop = jiffies + chip->vendor.timeout_a; - 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 + chip->vendor.timeout_d; - 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, unsigned long 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), timeout); - if (rc > 0) - return 0; - } else { - stop = jiffies + timeout; - 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 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) -{ - 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 (!start) - start = TIS_MEM_BASE; - if (!len) - len = TIS_MEM_LEN; - - 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 = 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", - 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)); - 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; - } - - /* 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", - chip->vendor.irq); - 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 */ - {"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 = { - .name = "tpm_tis", - .id_table = tpm_pnp_tbl, - .probe = tpm_tis_pnp_init, - .suspend = tpm_tis_pnp_suspend, - .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); -} - -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"); diff --git a/trunk/drivers/isdn/gigaset/bas-gigaset.c b/trunk/drivers/isdn/gigaset/bas-gigaset.c index eb41aba3ddef..f86ed6af3aa2 100644 --- a/trunk/drivers/isdn/gigaset/bas-gigaset.c +++ b/trunk/drivers/isdn/gigaset/bas-gigaset.c @@ -5,6 +5,8 @@ * Tilman Schmidt , * Stefan Eilers. * + * Based on usb-gigaset.c. + * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -44,20 +46,19 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode"); #define GIGASET_DEVFSNAME "gig/bas/" #define GIGASET_DEVNAME "ttyGB" -/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */ -#define IF_WRITEBUF 264 +#define IF_WRITEBUF 256 //FIXME /* Values for the Gigaset 307x */ #define USB_GIGA_VENDOR_ID 0x0681 -#define USB_3070_PRODUCT_ID 0x0001 -#define USB_3075_PRODUCT_ID 0x0002 +#define USB_GIGA_PRODUCT_ID 0x0001 +#define USB_4175_PRODUCT_ID 0x0002 #define USB_SX303_PRODUCT_ID 0x0021 #define USB_SX353_PRODUCT_ID 0x0022 /* table of devices that work with this driver */ static struct usb_device_id gigaset_table [] = { - { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3070_PRODUCT_ID) }, - { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3075_PRODUCT_ID) }, + { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_GIGA_PRODUCT_ID) }, + { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_4175_PRODUCT_ID) }, { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX303_PRODUCT_ID) }, { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX353_PRODUCT_ID) }, { } /* Terminating entry */ @@ -76,10 +77,6 @@ static int gigaset_probe(struct usb_interface *interface, /* Function will be called if the device is unplugged */ static void gigaset_disconnect(struct usb_interface *interface); -static void read_ctrl_callback(struct urb *, struct pt_regs *); -static void stopurbs(struct bas_bc_state *); -static int atwrite_submit(struct cardstate *, unsigned char *, int); -static int start_cbsend(struct cardstate *); /*==============================================================================*/ @@ -114,14 +111,12 @@ struct bas_cardstate { }; /* status of direct USB connection to 307x base (bits in basstate) */ -#define BS_ATOPEN 0x001 /* AT channel open */ -#define BS_B1OPEN 0x002 /* B channel 1 open */ -#define BS_B2OPEN 0x004 /* B channel 2 open */ -#define BS_ATREADY 0x008 /* base ready for AT command */ -#define BS_INIT 0x010 /* base has signalled INIT_OK */ -#define BS_ATTIMER 0x020 /* waiting for HD_READY_SEND_ATDATA */ -#define BS_ATRDPEND 0x040 /* urb_cmd_in in use */ -#define BS_ATWRPEND 0x080 /* urb_cmd_out in use */ +#define BS_ATOPEN 0x001 +#define BS_B1OPEN 0x002 +#define BS_B2OPEN 0x004 +#define BS_ATREADY 0x008 +#define BS_INIT 0x010 +#define BS_ATTIMER 0x020 static struct gigaset_driver *driver = NULL; @@ -135,47 +130,6 @@ static struct usb_driver gigaset_usb_driver = { .id_table = gigaset_table, }; -/* get message text for usb_submit_urb return code - */ -static char *get_usb_rcmsg(int rc) -{ - static char unkmsg[28]; - - switch (rc) { - case 0: - return "success"; - case -ENOMEM: - return "out of memory"; - case -ENODEV: - return "device not present"; - case -ENOENT: - return "endpoint not present"; - case -ENXIO: - return "URB type not supported"; - case -EINVAL: - return "invalid argument"; - case -EAGAIN: - return "start frame too early or too much scheduled"; - case -EFBIG: - return "too many isochronous frames requested"; - case -EPIPE: - return "endpoint stalled"; - case -EMSGSIZE: - return "invalid packet size"; - case -ENOSPC: - return "would overcommit USB bandwidth"; - case -ESHUTDOWN: - return "device shut down"; - case -EPERM: - return "reject flag set"; - case -EHOSTUNREACH: - return "device suspended"; - default: - snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", rc); - return unkmsg; - } -} - /* get message text for USB status code */ static char *get_usb_statmsg(int status) @@ -186,37 +140,43 @@ static char *get_usb_statmsg(int status) case 0: return "success"; case -ENOENT: - return "unlinked (sync)"; + return "canceled"; + case -ECONNRESET: + return "canceled (async)"; case -EINPROGRESS: return "pending"; case -EPROTO: - return "bit stuffing error, timeout, or unknown USB error"; + return "bit stuffing or unknown USB error"; case -EILSEQ: - return "CRC mismatch, timeout, or unknown USB error"; - case -ETIMEDOUT: - return "timed out"; + return "Illegal byte sequence (CRC mismatch)"; case -EPIPE: - return "endpoint stalled"; - case -ECOMM: - return "IN buffer overrun"; + return "babble detect or endpoint stalled"; case -ENOSR: - return "OUT buffer underrun"; - case -EOVERFLOW: - return "too much data"; + return "buffer error"; + case -ETIMEDOUT: + return "timed out"; + case -ENODEV: + return "device not present"; case -EREMOTEIO: return "short packet detected"; - case -ENODEV: - return "device removed"; case -EXDEV: return "partial isochronous transfer"; case -EINVAL: return "invalid argument"; - case -ECONNRESET: - return "unlinked (async)"; + case -ENXIO: + return "URB already queued"; + case -EAGAIN: + return "isochronous start frame too early or too much scheduled"; + case -EFBIG: + return "too many isochronous frames requested"; + case -EMSGSIZE: + return "endpoint message size zero"; case -ESHUTDOWN: - return "device shut down"; + return "endpoint shutdown"; + case -EBUSY: + return "another request pending"; default: - snprintf(unkmsg, sizeof(unkmsg), "unknown status %d", status); + snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", status); return unkmsg; } } @@ -317,17 +277,18 @@ static inline void error_hangup(struct bc_state *bcs) gig_dbg(DEBUG_ANY, "%s: scheduling HUP for channel %d", __func__, bcs->channel); - if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) - dev_err(cs->dev, "event queue full\n"); + if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { + //FIXME what should we do? + return; + } gigaset_schedule_event(cs); } /* error_reset * reset Gigaset device because of an unrecoverable error - * This function may be called from any context, and should take care of - * scheduling the necessary actions for execution outside of interrupt context. - * Right now, it just generates a kernel message calling for help. + * This function may be called from any context and takes care of scheduling + * the necessary actions for execution outside of interrupt context. * argument: * controller state structure */ @@ -403,38 +364,36 @@ static void cmd_in_timeout(unsigned long data) { struct cardstate *cs = (struct cardstate *) data; struct bas_cardstate *ucs = cs->hw.bas; + unsigned long flags; + spin_lock_irqsave(&cs->lock, flags); + if (unlikely(!cs->connected)) { + gig_dbg(DEBUG_USBREQ, "%s: disconnected", __func__); + spin_unlock_irqrestore(&cs->lock, flags); + return; + } if (!ucs->rcvbuf_size) { gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); + spin_unlock_irqrestore(&cs->lock, flags); return; } + spin_unlock_irqrestore(&cs->lock, flags); dev_err(cs->dev, "timeout reading AT response\n"); error_reset(cs); //FIXME retry? } -/* set/clear bits in base connection state, return previous state - */ -inline static int update_basstate(struct bas_cardstate *ucs, - int set, int clear) -{ - unsigned long flags; - int state; - spin_lock_irqsave(&ucs->lock, flags); - state = atomic_read(&ucs->basstate); - atomic_set(&ucs->basstate, (state & ~clear) | set); - spin_unlock_irqrestore(&ucs->lock, flags); - return state; -} +static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs); /* atread_submit - * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout + * submit an HD_READ_ATMESSAGE command URB * parameters: * cs controller state structure * timeout timeout in 1/10 sec., 0: none * return value: * 0 on success + * -EINVAL if a NULL pointer is encountered somewhere * -EBUSY if another request is pending * any URB submission error code */ @@ -446,7 +405,7 @@ static int atread_submit(struct cardstate *cs, int timeout) gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", ucs->rcvbuf_size); - if (update_basstate(ucs, BS_ATRDPEND, 0) & BS_ATRDPEND) { + if (ucs->urb_cmd_in->status == -EINPROGRESS) { dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: URB busy\n"); return -EBUSY; @@ -464,7 +423,6 @@ static int atread_submit(struct cardstate *cs, int timeout) read_ctrl_callback, cs->inbuf); if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { - update_basstate(ucs, 0, BS_ATRDPEND); dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", get_usb_statmsg(ret)); return ret; @@ -480,6 +438,26 @@ static int atread_submit(struct cardstate *cs, int timeout) return 0; } +static void stopurbs(struct bas_bc_state *); +static int start_cbsend(struct cardstate *); + +/* set/clear bits in base connection state + */ +inline static void update_basstate(struct bas_cardstate *ucs, + int set, int clear) +{ + unsigned long flags; + int state; + + spin_lock_irqsave(&ucs->lock, flags); + state = atomic_read(&ucs->basstate); + state &= ~clear; + state |= set; + atomic_set(&ucs->basstate, state); + spin_unlock_irqrestore(&ucs->lock, flags); +} + + /* read_int_callback * USB completion handler for interrupt pipe input * called by the USB subsystem in interrupt context @@ -493,25 +471,20 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) struct bas_cardstate *ucs = cs->hw.bas; struct bc_state *bcs; unsigned long flags; - int rc; + int status; unsigned l; int channel; switch (urb->status) { case 0: /* success */ break; - case -ENOENT: /* cancelled */ - case -ECONNRESET: /* cancelled (async) */ + case -ENOENT: /* canceled */ + case -ECONNRESET: /* canceled (async) */ case -EINPROGRESS: /* pending */ /* ignore silently */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(urb->status)); return; - case -ENODEV: /* device removed */ - case -ESHUTDOWN: /* device shut down */ - //FIXME use this as disconnect indicator? - gig_dbg(DEBUG_USBREQ, "%s: device disconnected", __func__); - return; default: /* severe trouble */ dev_warn(cs->dev, "interrupt read: %s\n", get_usb_statmsg(urb->status)); @@ -519,13 +492,6 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) goto resubmit; } - /* drop incomplete packets even if the missing bytes wouldn't matter */ - if (unlikely(urb->actual_length < 3)) { - dev_warn(cs->dev, "incomplete interrupt packet (%d bytes)\n", - urb->actual_length); - goto resubmit; - } - l = (unsigned) ucs->int_in_buf[1] + (((unsigned) ucs->int_in_buf[2]) << 8); @@ -592,28 +558,25 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) } spin_lock_irqsave(&cs->lock, flags); if (ucs->rcvbuf_size) { - /* throw away previous buffer - we have no queue */ + spin_unlock_irqrestore(&cs->lock, flags); dev_err(cs->dev, - "receive AT data overrun, %d bytes lost\n", - ucs->rcvbuf_size); - kfree(ucs->rcvbuf); - ucs->rcvbuf_size = 0; + "receive AT data overrun, %d bytes lost\n", l); + error_reset(cs); //FIXME reschedule + break; } if ((ucs->rcvbuf = kmalloc(l, GFP_ATOMIC)) == NULL) { spin_unlock_irqrestore(&cs->lock, flags); - dev_err(cs->dev, "out of memory receiving AT data\n"); - error_reset(cs); + dev_err(cs->dev, "out of memory, %d bytes lost\n", l); + error_reset(cs); //FIXME reschedule break; } ucs->rcvbuf_size = l; ucs->retry_cmd_in = 0; - if ((rc = atread_submit(cs, BAS_TIMEOUT)) < 0) { + if ((status = atread_submit(cs, BAS_TIMEOUT)) < 0) { kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; - if (rc != -ENODEV) - //FIXME corrective action? - error_reset(cs); + error_reset(cs); //FIXME reschedule } spin_unlock_irqrestore(&cs->lock, flags); break; @@ -635,10 +598,12 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) check_pending(ucs); resubmit: - rc = usb_submit_urb(urb, SLAB_ATOMIC); - if (unlikely(rc != 0 && rc != -ENODEV)) { + spin_lock_irqsave(&cs->lock, flags); + status = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&cs->lock, flags); + if (unlikely(status)) { dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", - get_usb_rcmsg(rc)); + get_usb_statmsg(status)); error_reset(cs); } } @@ -657,12 +622,18 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) struct bas_cardstate *ucs = cs->hw.bas; int have_data = 0; unsigned numbytes; - int rc; + unsigned long flags; - update_basstate(ucs, 0, BS_ATRDPEND); + spin_lock_irqsave(&cs->lock, flags); + if (unlikely(!cs->connected)) { + warn("%s: disconnected", __func__); + spin_unlock_irqrestore(&cs->lock, flags); + return; + } if (!ucs->rcvbuf_size) { dev_warn(cs->dev, "%s: no receive in progress\n", __func__); + spin_unlock_irqrestore(&cs->lock, flags); return; } @@ -695,11 +666,9 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) } break; - case -ENOENT: /* cancelled */ - case -ECONNRESET: /* cancelled (async) */ + case -ENOENT: /* canceled */ + case -ECONNRESET: /* canceled (async) */ case -EINPROGRESS: /* pending */ - case -ENODEV: /* device removed */ - case -ESHUTDOWN: /* device shut down */ /* no action necessary */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(urb->status)); @@ -712,11 +681,11 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) if (ucs->retry_cmd_in++ < BAS_RETRY) { dev_notice(cs->dev, "control read: retry %d\n", ucs->retry_cmd_in); - rc = atread_submit(cs, BAS_TIMEOUT); - if (rc >= 0 || rc == -ENODEV) - /* resubmitted or disconnected */ - /* - bypass regular exit block */ + if (atread_submit(cs, BAS_TIMEOUT) >= 0) { + /* resubmitted - bypass regular exit block */ + spin_unlock_irqrestore(&cs->lock, flags); return; + } } else { dev_err(cs->dev, "control read: giving up after %d tries\n", @@ -728,6 +697,7 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; + spin_unlock_irqrestore(&cs->lock, flags); if (have_data) { gig_dbg(DEBUG_INTR, "%s-->BH", __func__); gigaset_schedule_event(cs); @@ -749,11 +719,8 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs) int i, rc; /* status codes not worth bothering the tasklet with */ - if (unlikely(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -EINPROGRESS || - urb->status == -ENODEV || - urb->status == -ESHUTDOWN)) { + if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || + urb->status == -EINPROGRESS)) { gig_dbg(DEBUG_ISO, "%s: %s", __func__, get_usb_statmsg(urb->status)); return; @@ -773,9 +740,9 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs) for (i = 0; i < BAS_NUMFRAMES; i++) { ubc->isoinlost += urb->iso_frame_desc[i].actual_length; if (unlikely(urb->iso_frame_desc[i].status != 0 && - urb->iso_frame_desc[i].status != - -EINPROGRESS)) + urb->iso_frame_desc[i].status != -EINPROGRESS)) { ubc->loststatus = urb->iso_frame_desc[i].status; + } urb->iso_frame_desc[i].status = 0; urb->iso_frame_desc[i].actual_length = 0; } @@ -787,10 +754,10 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs) gig_dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", __func__); rc = usb_submit_urb(urb, SLAB_ATOMIC); - if (unlikely(rc != 0 && rc != -ENODEV)) { + if (unlikely(rc != 0)) { dev_err(bcs->cs->dev, "could not resubmit isochronous read " - "URB: %s\n", get_usb_rcmsg(rc)); + "URB: %s\n", get_usb_statmsg(rc)); dump_urb(DEBUG_ISO, "isoc read", urb); error_hangup(bcs); } @@ -813,11 +780,8 @@ static void write_iso_callback(struct urb *urb, struct pt_regs *regs) unsigned long flags; /* status codes not worth bothering the tasklet with */ - if (unlikely(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -EINPROGRESS || - urb->status == -ENODEV || - urb->status == -ESHUTDOWN)) { + if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || + urb->status == -EINPROGRESS)) { gig_dbg(DEBUG_ISO, "%s: %s", __func__, get_usb_statmsg(urb->status)); return; @@ -858,6 +822,7 @@ static int starturbs(struct bc_state *bcs) for (k = 0; k < BAS_INURBS; k++) { urb = ubc->isoinurbs[k]; if (!urb) { + dev_err(bcs->cs->dev, "isoinurbs[%d]==NULL\n", k); rc = -EFAULT; goto error; } @@ -879,8 +844,12 @@ static int starturbs(struct bc_state *bcs) } dump_urb(DEBUG_ISO, "Initial isoc read", urb); - if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) + if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { + dev_err(bcs->cs->dev, + "could not submit isochronous read URB %d: %s\n", + k, get_usb_statmsg(rc)); goto error; + } } /* initialize L2 transmission */ @@ -890,6 +859,7 @@ static int starturbs(struct bc_state *bcs) for (k = 0; k < BAS_OUTURBS; ++k) { urb = ubc->isoouturbs[k].urb; if (!urb) { + dev_err(bcs->cs->dev, "isoouturbs[%d].urb==NULL\n", k); rc = -EFAULT; goto error; } @@ -915,8 +885,12 @@ static int starturbs(struct bc_state *bcs) for (k = 0; k < 2; ++k) { dump_urb(DEBUG_ISO, "Initial isoc write", urb); rc = usb_submit_urb(ubc->isoouturbs[k].urb, SLAB_ATOMIC); - if (rc != 0) + if (rc != 0) { + dev_err(bcs->cs->dev, + "could not submit isochronous write URB %d: %s\n", + k, get_usb_statmsg(rc)); goto error; + } } dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb); ubc->isooutfree = &ubc->isoouturbs[2]; @@ -942,15 +916,15 @@ static void stopurbs(struct bas_bc_state *ubc) for (k = 0; k < BAS_INURBS; ++k) { rc = usb_unlink_urb(ubc->isoinurbs[k]); gig_dbg(DEBUG_ISO, - "%s: isoc input URB %d unlinked, result = %s", - __func__, k, get_usb_rcmsg(rc)); + "%s: isoc input URB %d unlinked, result = %d", + __func__, k, rc); } for (k = 0; k < BAS_OUTURBS; ++k) { rc = usb_unlink_urb(ubc->isoouturbs[k].urb); gig_dbg(DEBUG_ISO, - "%s: isoc output URB %d unlinked, result = %s", - __func__, k, get_usb_rcmsg(rc)); + "%s: isoc output URB %d unlinked, result = %d", + __func__, k, rc); } } @@ -960,7 +934,7 @@ static void stopurbs(struct bas_bc_state *ubc) /* submit_iso_write_urb * fill and submit the next isochronous write URB * parameters: - * ucx context structure containing URB + * bcs B channel state structure * return value: * number of frames submitted in URB * 0 if URB not submitted because no data available (isooutbuf busy) @@ -972,6 +946,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) struct bas_bc_state *ubc = ucx->bcs->hw.bas; struct usb_iso_packet_descriptor *ifd; int corrbytes, nframe, rc; + unsigned long flags; /* urb->dev is clobbered by USB subsystem */ urb->dev = ucx->bcs->cs->hw.bas->udev; @@ -1017,22 +992,20 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) ifd->status = 0; ifd->actual_length = 0; } - if (unlikely(nframe == 0)) - return 0; /* no data to send */ - urb->number_of_packets = nframe; + if ((urb->number_of_packets = nframe) > 0) { + spin_lock_irqsave(&ucx->bcs->cs->lock, flags); + rc = ucx->bcs->cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&ucx->bcs->cs->lock, flags); - rc = usb_submit_urb(urb, SLAB_ATOMIC); - if (unlikely(rc)) { - if (rc == -ENODEV) - /* device removed - give up silently */ - gig_dbg(DEBUG_ISO, "%s: disconnected", __func__); - else + if (rc) { dev_err(ucx->bcs->cs->dev, "could not submit isochronous write URB: %s\n", - get_usb_rcmsg(rc)); - return rc; + get_usb_statmsg(rc)); + dump_urb(DEBUG_ISO, "isoc write", urb); + return rc; + } + ++ubc->numsub; } - ++ubc->numsub; return nframe; } @@ -1055,7 +1028,6 @@ static void write_iso_tasklet(unsigned long data) int i; struct sk_buff *skb; int len; - int rc; /* loop while completed URBs arrive in time */ for (;;) { @@ -1085,8 +1057,7 @@ static void write_iso_tasklet(unsigned long data) ubc->isooutfree = NULL; spin_unlock_irqrestore(&ubc->isooutlock, flags); if (next) { - rc = submit_iso_write_urb(next); - if (unlikely(rc <= 0 && rc != -ENODEV)) { + if (submit_iso_write_urb(next) <= 0) { /* could not submit URB, put it back */ spin_lock_irqsave(&ubc->isooutlock, flags); if (ubc->isooutfree == NULL) { @@ -1106,18 +1077,17 @@ static void write_iso_tasklet(unsigned long data) /* process completed URB */ urb = done->urb; switch (urb->status) { - case -EXDEV: /* partial completion */ - gig_dbg(DEBUG_ISO, "%s: URB partially completed", - __func__); - /* fall through - what's the difference anyway? */ case 0: /* normal completion */ - /* inspect individual frames - * assumptions (for lack of documentation): - * - actual_length bytes of first frame in error are + break; + case -EXDEV: /* inspect individual frames */ + /* assumptions (for lack of documentation): + * - actual_length bytes of the frame in error are * successfully sent * - all following frames are not sent at all */ - offset = done->limit; /* default (no error) */ + gig_dbg(DEBUG_ISO, "%s: URB partially completed", + __func__); + offset = done->limit; /* just in case */ for (i = 0; i < BAS_NUMFRAMES; i++) { ifd = &urb->iso_frame_desc[i]; if (ifd->status || @@ -1152,7 +1122,7 @@ static void write_iso_tasklet(unsigned long data) } #endif break; - case -EPIPE: /* stall - probably underrun */ + case -EPIPE: //FIXME is this the code for "underrun"? dev_err(cs->dev, "isochronous write stalled\n"); error_hangup(bcs); break; @@ -1172,8 +1142,7 @@ static void write_iso_tasklet(unsigned long data) spin_unlock_irqrestore(&ubc->isooutlock, flags); if (next) { /* only one URB still active - resubmit one */ - rc = submit_iso_write_urb(next); - if (unlikely(rc <= 0 && rc != -ENODEV)) { + if (submit_iso_write_urb(next) <= 0) { /* couldn't submit */ error_hangup(bcs); } @@ -1253,9 +1222,10 @@ static void read_iso_tasklet(unsigned long data) break; case -ENOENT: case -ECONNRESET: - case -EINPROGRESS: - gig_dbg(DEBUG_ISO, "%s: %s", - __func__, get_usb_statmsg(urb->status)); + gig_dbg(DEBUG_ISO, "%s: URB canceled", __func__); + continue; /* -> skip */ + case -EINPROGRESS: /* huh? */ + gig_dbg(DEBUG_ISO, "%s: URB still pending", __func__); continue; /* -> skip */ case -EPIPE: dev_err(cs->dev, "isochronous read stalled\n"); @@ -1320,11 +1290,13 @@ static void read_iso_tasklet(unsigned long data) urb->dev = bcs->cs->hw.bas->udev; urb->transfer_flags = URB_ISO_ASAP; urb->number_of_packets = BAS_NUMFRAMES; - rc = usb_submit_urb(urb, SLAB_ATOMIC); - if (unlikely(rc != 0 && rc != -ENODEV)) { + spin_lock_irqsave(&cs->lock, flags); + rc = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&cs->lock, flags); + if (rc) { dev_err(cs->dev, "could not resubmit isochronous read URB: %s\n", - get_usb_rcmsg(rc)); + get_usb_statmsg(rc)); dump_urb(DEBUG_ISO, "resubmit iso read", urb); error_hangup(bcs); } @@ -1425,6 +1397,7 @@ static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) * timeout timeout in seconds (0: no timeout) * return value: * 0 on success + * -EINVAL if a NULL pointer is encountered somewhere * -EBUSY if another request is pending * any URB submission error code */ @@ -1445,6 +1418,12 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) req, ucs->pending); return -EBUSY; } + if (ucs->urb_ctrl->status == -EINPROGRESS) { + spin_unlock_irqrestore(&ucs->lock, flags); + dev_err(bcs->cs->dev, + "could not submit request 0x%02x: URB busy\n", req); + return -EBUSY; + } ucs->dr_ctrl.bRequestType = OUT_VENDOR_REQ; ucs->dr_ctrl.bRequest = req; @@ -1486,36 +1465,22 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) static int gigaset_init_bchannel(struct bc_state *bcs) { int req, ret; - unsigned long flags; - - spin_lock_irqsave(&bcs->cs->lock, flags); - if (unlikely(!bcs->cs->connected)) { - gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - return -ENODEV; - } if ((ret = starturbs(bcs)) < 0) { dev_err(bcs->cs->dev, - "could not start isochronous I/O for channel B%d: %s\n", - bcs->channel + 1, - ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret)); - if (ret != -ENODEV) - error_hangup(bcs); - spin_unlock_irqrestore(&bcs->cs->lock, flags); + "could not start isochronous I/O for channel %d\n", + bcs->channel + 1); + error_hangup(bcs); return ret; } req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) { - dev_err(bcs->cs->dev, "could not open channel B%d\n", - bcs->channel + 1); + dev_err(bcs->cs->dev, "could not open channel %d: %s\n", + bcs->channel + 1, get_usb_statmsg(ret)); stopurbs(bcs->hw.bas); - if (ret != -ENODEV) - error_hangup(bcs); + error_hangup(bcs); } - - spin_unlock_irqrestore(&bcs->cs->lock, flags); return ret; } @@ -1532,30 +1497,19 @@ static int gigaset_init_bchannel(struct bc_state *bcs) static int gigaset_close_bchannel(struct bc_state *bcs) { int req, ret; - unsigned long flags; - - spin_lock_irqsave(&bcs->cs->lock, flags); - if (unlikely(!bcs->cs->connected)) { - spin_unlock_irqrestore(&bcs->cs->lock, flags); - gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); - return -ENODEV; - } if (!(atomic_read(&bcs->cs->hw.bas->basstate) & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) { /* channel not running: just signal common.c */ - spin_unlock_irqrestore(&bcs->cs->lock, flags); gigaset_bchannel_down(bcs); return 0; } - /* channel running: tell device to close it */ req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) - dev_err(bcs->cs->dev, "closing channel B%d failed\n", - bcs->channel + 1); - - spin_unlock_irqrestore(&bcs->cs->lock, flags); + dev_err(bcs->cs->dev, + "could not submit HD_CLOSE_BxCHANNEL request: %s\n", + get_usb_statmsg(ret)); return ret; } @@ -1591,6 +1545,8 @@ static void complete_cb(struct cardstate *cs) kfree(cb); } +static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len); + /* write_command_callback * USB completion handler for AT command transmission * called by the USB subsystem in interrupt context @@ -1604,17 +1560,13 @@ static void write_command_callback(struct urb *urb, struct pt_regs *regs) struct bas_cardstate *ucs = cs->hw.bas; unsigned long flags; - update_basstate(ucs, 0, BS_ATWRPEND); - /* check status */ switch (urb->status) { case 0: /* normal completion */ break; - case -ENOENT: /* cancelled */ - case -ECONNRESET: /* cancelled (async) */ + case -ENOENT: /* canceled */ + case -ECONNRESET: /* canceled (async) */ case -EINPROGRESS: /* pending */ - case -ENODEV: /* device removed */ - case -ESHUTDOWN: /* device shut down */ /* ignore silently */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(urb->status)); @@ -1675,17 +1627,19 @@ static void atrdy_timeout(unsigned long data) * len length of command to send * return value: * 0 on success + * -EFAULT if a NULL pointer is encountered somewhere * -EBUSY if another request is pending * any URB submission error code */ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) { struct bas_cardstate *ucs = cs->hw.bas; - int rc; + unsigned long flags; + int ret; gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len); - if (update_basstate(ucs, BS_ATWRPEND, 0) & BS_ATWRPEND) { + if (ucs->urb_cmd_out->status == -EINPROGRESS) { dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: URB busy\n"); return -EBUSY; @@ -1700,22 +1654,29 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) usb_sndctrlpipe(ucs->udev, 0), (unsigned char*) &ucs->dr_cmd_out, buf, len, write_command_callback, cs); - rc = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC); - if (unlikely(rc)) { - update_basstate(ucs, 0, BS_ATWRPEND); + + spin_lock_irqsave(&cs->lock, flags); + ret = cs->connected ? usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&cs->lock, flags); + + if (ret) { dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n", - get_usb_rcmsg(rc)); - return rc; + get_usb_statmsg(ret)); + return ret; } - /* submitted successfully, start timeout if necessary */ - if (!(update_basstate(ucs, BS_ATTIMER, BS_ATREADY) & BS_ATTIMER)) { + /* submitted successfully */ + update_basstate(ucs, 0, BS_ATREADY); + + /* start timeout if necessary */ + if (!(atomic_read(&ucs->basstate) & BS_ATTIMER)) { gig_dbg(DEBUG_OUTPUT, "setting ATREADY timeout of %d/10 secs", ATRDY_TIMEOUT); ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10; ucs->timer_atrdy.data = (unsigned long) cs; ucs->timer_atrdy.function = atrdy_timeout; add_timer(&ucs->timer_atrdy); + update_basstate(ucs, BS_ATTIMER, 0); } return 0; } @@ -1741,6 +1702,7 @@ static int start_cbsend(struct cardstate *cs) gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open"); rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT); if (rc < 0) { + dev_err(cs->dev, "could not open AT channel\n"); /* flush command queue */ spin_lock_irqsave(&cs->cmdlock, flags); while (cs->cmdbuf != NULL) @@ -1824,14 +1786,8 @@ static int gigaset_write_cmd(struct cardstate *cs, cs->lastcmdbuf = cb; spin_unlock_irqrestore(&cs->cmdlock, flags); - spin_lock_irqsave(&cs->lock, flags); - if (unlikely(!cs->connected)) { - spin_unlock_irqrestore(&cs->lock, flags); - gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); - return -ENODEV; - } status = start_cbsend(cs); - spin_unlock_irqrestore(&cs->lock, flags); + return status < 0 ? status : len; } @@ -1893,32 +1849,12 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) */ static int gigaset_freebcshw(struct bc_state *bcs) { - struct bas_bc_state *ubc = bcs->hw.bas; - int i; - - if (!ubc) + if (!bcs->hw.bas) return 0; - /* kill URBs and tasklets before freeing - better safe than sorry */ - atomic_set(&ubc->running, 0); - for (i = 0; i < BAS_OUTURBS; ++i) - if (ubc->isoouturbs[i].urb) { - gig_dbg(DEBUG_INIT, "%s: killing iso out URB %d", - __func__, i); - usb_kill_urb(ubc->isoouturbs[i].urb); - usb_free_urb(ubc->isoouturbs[i].urb); - } - for (i = 0; i < BAS_INURBS; ++i) - if (ubc->isoinurbs[i]) { - gig_dbg(DEBUG_INIT, "%s: killing iso in URB %d", - __func__, i); - usb_kill_urb(ubc->isoinurbs[i]); - usb_free_urb(ubc->isoinurbs[i]); - } - tasklet_kill(&ubc->sent_tasklet); - tasklet_kill(&ubc->rcvd_tasklet); - kfree(ubc->isooutbuf); - kfree(ubc); + if (bcs->hw.bas->isooutbuf) + kfree(bcs->hw.bas->isooutbuf); + kfree(bcs->hw.bas); bcs->hw.bas = NULL; return 1; } @@ -1995,9 +1931,13 @@ static void gigaset_reinitbcshw(struct bc_state *bcs) static void gigaset_freecshw(struct cardstate *cs) { - /* timers, URBs and rcvbuf are disposed of in disconnect */ + struct bas_cardstate *ucs = cs->hw.bas; + + del_timer(&ucs->timer_ctrl); + del_timer(&ucs->timer_atrdy); + del_timer(&ucs->timer_cmd_in); + kfree(cs->hw.bas); - cs->hw.bas = NULL; } static int gigaset_initcshw(struct cardstate *cs) @@ -2101,13 +2041,23 @@ static int gigaset_probe(struct usb_interface *interface, struct bas_bc_state *ubc; struct usb_endpoint_descriptor *endpoint; int i, j; - int rc; + int ret; gig_dbg(DEBUG_ANY, "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", __func__, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); + /* See if the device offered us matches what we can accept */ + if ((le16_to_cpu(udev->descriptor.idVendor) != USB_GIGA_VENDOR_ID) || + (le16_to_cpu(udev->descriptor.idProduct) != USB_GIGA_PRODUCT_ID && + le16_to_cpu(udev->descriptor.idProduct) != USB_4175_PRODUCT_ID && + le16_to_cpu(udev->descriptor.idProduct) != USB_SX303_PRODUCT_ID && + le16_to_cpu(udev->descriptor.idProduct) != USB_SX353_PRODUCT_ID)) { + gig_dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__); + return -ENODEV; + } + /* set required alternate setting */ hostif = interface->cur_altsetting; if (hostif->desc.bAlternateSetting != 3) { @@ -2155,22 +2105,45 @@ static int gigaset_probe(struct usb_interface *interface, * - three for the different uses of the default control pipe * - three for each isochronous pipe */ - if (!(ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL)) || - !(ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL)) || - !(ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL)) || - !(ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL))) - goto allocerr; + ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL); + if (!ucs->urb_int_in) { + dev_err(cs->dev, "no free urbs available\n"); + goto error; + } + ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL); + if (!ucs->urb_cmd_in) { + dev_err(cs->dev, "no free urbs available\n"); + goto error; + } + ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL); + if (!ucs->urb_cmd_out) { + dev_err(cs->dev, "no free urbs available\n"); + goto error; + } + ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL); + if (!ucs->urb_ctrl) { + dev_err(cs->dev, "no free urbs available\n"); + goto error; + } for (j = 0; j < 2; ++j) { ubc = cs->bcs[j].hw.bas; - for (i = 0; i < BAS_OUTURBS; ++i) - if (!(ubc->isoouturbs[i].urb = - usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL))) - goto allocerr; - for (i = 0; i < BAS_INURBS; ++i) - if (!(ubc->isoinurbs[i] = - usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL))) - goto allocerr; + for (i = 0; i < BAS_OUTURBS; ++i) { + ubc->isoouturbs[i].urb = + usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL); + if (!ubc->isoouturbs[i].urb) { + dev_err(cs->dev, "no free urbs available\n"); + goto error; + } + } + for (i = 0; i < BAS_INURBS; ++i) { + ubc->isoinurbs[i] = + usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL); + if (!ubc->isoinurbs[i]) { + dev_err(cs->dev, "no free urbs available\n"); + goto error; + } + } } ucs->rcvbuf = NULL; @@ -2183,14 +2156,15 @@ static int gigaset_probe(struct usb_interface *interface, (endpoint->bEndpointAddress) & 0x0f), ucs->int_in_buf, 3, read_int_callback, cs, endpoint->bInterval); - if ((rc = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL)) != 0) { + ret = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL); + if (ret) { dev_err(cs->dev, "could not submit interrupt URB: %s\n", - get_usb_rcmsg(rc)); + get_usb_statmsg(ret)); goto error; } /* tell the device that the driver is ready */ - if ((rc = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0) + if ((ret = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0) goto error; /* tell common part that the device is ready */ @@ -2205,8 +2179,6 @@ static int gigaset_probe(struct usb_interface *interface, return 0; -allocerr: - dev_err(cs->dev, "could not allocate URBs\n"); error: freeurbs(cs); usb_set_intfdata(interface, NULL); @@ -2221,34 +2193,19 @@ static void gigaset_disconnect(struct usb_interface *interface) { struct cardstate *cs; struct bas_cardstate *ucs; - int j; cs = usb_get_intfdata(interface); ucs = cs->hw.bas; dev_info(cs->dev, "disconnecting Gigaset base\n"); - - /* mark base as not ready, all channels disconnected */ - atomic_set(&ucs->basstate, 0); - - /* tell LL all channels are down */ - //FIXME shouldn't gigaset_stop() do this? - for (j = 0; j < 2; ++j) - gigaset_bchannel_down(cs->bcs + j); - - /* stop driver (common part) */ gigaset_stop(cs); - - /* stop timers and URBs, free ressources */ - del_timer_sync(&ucs->timer_ctrl); - del_timer_sync(&ucs->timer_atrdy); - del_timer_sync(&ucs->timer_cmd_in); freeurbs(cs); usb_set_intfdata(interface, NULL); kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; + atomic_set(&ucs->basstate, 0); usb_put_dev(ucs->udev); ucs->interface = NULL; ucs->udev = NULL; @@ -2320,8 +2277,6 @@ error: if (cardstate) */ static void __exit bas_gigaset_exit(void) { - struct bas_cardstate *ucs = cardstate->hw.bas; - gigaset_blockdriver(driver); /* => probe will fail * => no gigaset_start any more */ @@ -2329,26 +2284,14 @@ static void __exit bas_gigaset_exit(void) gigaset_shutdown(cardstate); /* from now on, no isdn callback should be possible */ - /* close all still open channels */ - if (atomic_read(&ucs->basstate) & BS_B1OPEN) { - gig_dbg(DEBUG_INIT, "closing B1 channel"); - usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), - HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0, - NULL, 0, BAS_TIMEOUT); - } - if (atomic_read(&ucs->basstate) & BS_B2OPEN) { - gig_dbg(DEBUG_INIT, "closing B2 channel"); - usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), - HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0, - NULL, 0, BAS_TIMEOUT); - } - if (atomic_read(&ucs->basstate) & BS_ATOPEN) { - gig_dbg(DEBUG_INIT, "closing AT channel"); - usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), - HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0, - NULL, 0, BAS_TIMEOUT); + if (atomic_read(&cardstate->hw.bas->basstate) & BS_ATOPEN) { + gig_dbg(DEBUG_ANY, "closing AT channel"); + if (req_submit(cardstate->bcs, + HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) { + /* successfully submitted */ + //FIXME wait for completion? + } } - atomic_set(&ucs->basstate, 0); /* deregister this driver with the USB subsystem */ usb_deregister(&gigaset_usb_driver); diff --git a/trunk/drivers/isdn/gigaset/common.c b/trunk/drivers/isdn/gigaset/common.c index e55767b2ccd3..749b3da1236e 100644 --- a/trunk/drivers/isdn/gigaset/common.c +++ b/trunk/drivers/isdn/gigaset/common.c @@ -781,7 +781,8 @@ error: if (cs) } EXPORT_SYMBOL_GPL(gigaset_initcs); -/* ReInitialize the b-channel structure on hangup */ +/* ReInitialize the b-channel structure */ +/* e.g. called on hangup, disconnect */ void gigaset_bcs_reinit(struct bc_state *bcs) { struct sk_buff *skb; diff --git a/trunk/drivers/isdn/gigaset/ev-layer.c b/trunk/drivers/isdn/gigaset/ev-layer.c index 18e05c09b71c..1ba3424a286b 100644 --- a/trunk/drivers/isdn/gigaset/ev-layer.c +++ b/trunk/drivers/isdn/gigaset/ev-layer.c @@ -373,9 +373,6 @@ struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */ {EV_TIMEOUT, 750,750, -1, 0, 0, {ACT_CONNTIMEOUT}}, - /* B channel closed (general case) */ - {EV_BC_CLOSED, -1, -1, -1, -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME - /* misc. */ {EV_PROTO_L2, -1, -1, -1, -1,-1, {ACT_PROTO_L2}}, //FIXME diff --git a/trunk/drivers/isdn/gigaset/gigaset.h b/trunk/drivers/isdn/gigaset/gigaset.h index 22b9693f7c0a..9d21ba8757b0 100644 --- a/trunk/drivers/isdn/gigaset/gigaset.h +++ b/trunk/drivers/isdn/gigaset/gigaset.h @@ -75,7 +75,7 @@ extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */ * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and * DEBUG_INTR. */ -enum debuglevel { +enum debuglevel { /* up to 24 bits (atomic_t) */ DEBUG_REG = 0x0002, /* serial port I/O register operations */ DEBUG_OPEN = 0x0004, /* open/close serial port */ DEBUG_INTR = 0x0008, /* interrupt processing */ @@ -141,7 +141,7 @@ enum debuglevel { printk(KERN_DEBUG KBUILD_MODNAME ": " format "\n", \ ## arg); \ } while (0) -#define DEBUG_DEFAULT (DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ) +#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ) #else @@ -627,7 +627,8 @@ struct gigaset_ops { /* Called by gigaset_freecs() for freeing bcs->hw.xxx */ int (*freebcshw)(struct bc_state *bcs); - /* Called by gigaset_bchannel_down() for resetting bcs->hw.xxx */ + /* Called by gigaset_stop() or gigaset_bchannel_down() for resetting + bcs->hw.xxx */ void (*reinitbcshw)(struct bc_state *bcs); /* Called by gigaset_initcs() for setting up cs->hw.xxx */ diff --git a/trunk/drivers/isdn/gigaset/i4l.c b/trunk/drivers/isdn/gigaset/i4l.c index 1654fa413575..0815dbfb8291 100644 --- a/trunk/drivers/isdn/gigaset/i4l.c +++ b/trunk/drivers/isdn/gigaset/i4l.c @@ -73,7 +73,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack, len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]); /* pass to device-specific module */ - return cs->ops->send_skb(bcs, skb); + return cs->ops->send_skb(bcs, skb); //FIXME cs->ops->send_skb() must handle !cs->connected correctly } void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) diff --git a/trunk/drivers/isdn/gigaset/isocdata.c b/trunk/drivers/isdn/gigaset/isocdata.c index 8667daaa1a82..45f017ed6e8c 100644 --- a/trunk/drivers/isdn/gigaset/isocdata.c +++ b/trunk/drivers/isdn/gigaset/isocdata.c @@ -992,18 +992,14 @@ int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb) int len = skb->len; unsigned long flags; - spin_lock_irqsave(&bcs->cs->lock, flags); - if (!bcs->cs->connected) { - spin_unlock_irqrestore(&bcs->cs->lock, flags); - return -ENODEV; - } - skb_queue_tail(&bcs->squeue, skb); gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d", __func__, skb_queue_len(&bcs->squeue)); /* tasklet submits URB if necessary */ - tasklet_schedule(&bcs->hw.bas->sent_tasklet); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->cs->connected) + tasklet_schedule(&bcs->hw.bas->sent_tasklet); spin_unlock_irqrestore(&bcs->cs->lock, flags); return len; /* ok so far */ diff --git a/trunk/fs/reiserfs/xattr_acl.c b/trunk/fs/reiserfs/xattr_acl.c index 97ae1b92bc47..58c418fbca2c 100644 --- a/trunk/fs/reiserfs/xattr_acl.c +++ b/trunk/fs/reiserfs/xattr_acl.c @@ -408,9 +408,8 @@ int reiserfs_cache_default_acl(struct inode *inode) acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT); reiserfs_read_unlock_xattrs(inode->i_sb); reiserfs_read_unlock_xattr_i(inode); - ret = (acl && !IS_ERR(acl)); - if (ret) - posix_acl_release(acl); + ret = acl ? 1 : 0; + posix_acl_release(acl); } return ret; diff --git a/trunk/include/asm-powerpc/iommu.h b/trunk/include/asm-powerpc/iommu.h index d5677cbec200..18ca29e9105a 100644 --- a/trunk/include/asm-powerpc/iommu.h +++ b/trunk/include/asm-powerpc/iommu.h @@ -70,17 +70,18 @@ extern void iommu_free_table(struct device_node *dn); extern struct iommu_table *iommu_init_table(struct iommu_table * tbl); extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, - struct scatterlist *sglist, int nelems, + struct scatterlist *sglist, int nelems, unsigned long mask, enum dma_data_direction direction); extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, int nelems, enum dma_data_direction direction); extern void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, - dma_addr_t *dma_handle, gfp_t flag); + dma_addr_t *dma_handle, unsigned long mask, gfp_t flag); extern void iommu_free_coherent(struct iommu_table *tbl, size_t size, void *vaddr, dma_addr_t dma_handle); extern dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, - size_t size, enum dma_data_direction direction); + size_t size, unsigned long mask, + enum dma_data_direction direction); extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction); diff --git a/trunk/mm/shmem.c b/trunk/mm/shmem.c index 4c5e68e4e9ae..37eaf42ed2c6 100644 --- a/trunk/mm/shmem.c +++ b/trunk/mm/shmem.c @@ -46,8 +46,6 @@ #include #include #include -#include - #include #include #include @@ -2175,7 +2173,6 @@ static struct address_space_operations shmem_aops = { .prepare_write = shmem_prepare_write, .commit_write = simple_commit_write, #endif - .migratepage = migrate_page, }; static struct file_operations shmem_file_operations = {