diff options
author | Jiri Kosina <jkosina@suse.cz> | 2012-10-28 14:28:52 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-10-28 14:29:19 -0400 |
commit | 3bd7bf1f0fe14f591c089ae61bbfa9bd356f178a (patch) | |
tree | 0058693cc9e70b7461dae551f8a19aff2efd13ca /drivers/char | |
parent | f16f84937d769c893492160b1a8c3672e3992beb (diff) | |
parent | e657e078d3dfa9f96976db7a2b5fd7d7c9f1f1a6 (diff) |
Merge branch 'master' into for-next
Sync up with Linus' tree to be able to apply Cesar's patch
against newer version of the code.
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/char')
41 files changed, 2962 insertions, 509 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ea6f6325f9ba..72bedad6bf8c 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -418,8 +418,8 @@ config APPLICOM | |||
418 | If unsure, say N. | 418 | If unsure, say N. |
419 | 419 | ||
420 | config SONYPI | 420 | config SONYPI |
421 | tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)" | 421 | tristate "Sony Vaio Programmable I/O Control Device support" |
422 | depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT | 422 | depends on X86 && PCI && INPUT && !64BIT |
423 | ---help--- | 423 | ---help--- |
424 | This driver enables access to the Sony Programmable I/O Control | 424 | This driver enables access to the Sony Programmable I/O Control |
425 | Device which can be found in many (all ?) Sony Vaio laptops. | 425 | Device which can be found in many (all ?) Sony Vaio laptops. |
@@ -566,7 +566,7 @@ source "drivers/char/tpm/Kconfig" | |||
566 | 566 | ||
567 | config TELCLOCK | 567 | config TELCLOCK |
568 | tristate "Telecom clock driver for ATCA SBC" | 568 | tristate "Telecom clock driver for ATCA SBC" |
569 | depends on EXPERIMENTAL && X86 | 569 | depends on X86 |
570 | default n | 570 | default n |
571 | help | 571 | help |
572 | The telecom clock device is specific to the MPCBL0010 and MPCBL0050 | 572 | The telecom clock device is specific to the MPCBL0010 and MPCBL0050 |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index d0b27a39f1d4..7ff1d0d208a7 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -52,7 +52,6 @@ obj-$(CONFIG_TELCLOCK) += tlclk.o | |||
52 | obj-$(CONFIG_MWAVE) += mwave/ | 52 | obj-$(CONFIG_MWAVE) += mwave/ |
53 | obj-$(CONFIG_AGP) += agp/ | 53 | obj-$(CONFIG_AGP) += agp/ |
54 | obj-$(CONFIG_PCMCIA) += pcmcia/ | 54 | obj-$(CONFIG_PCMCIA) += pcmcia/ |
55 | obj-$(CONFIG_IPMI_HANDLER) += ipmi/ | ||
56 | 55 | ||
57 | obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o | 56 | obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o |
58 | obj-$(CONFIG_TCG_TPM) += tpm/ | 57 | obj-$(CONFIG_TCG_TPM) += tpm/ |
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 58e32f7c3229..38390f7c6ab6 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c | |||
@@ -84,40 +84,33 @@ static struct _intel_private { | |||
84 | #define IS_IRONLAKE intel_private.driver->is_ironlake | 84 | #define IS_IRONLAKE intel_private.driver->is_ironlake |
85 | #define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable | 85 | #define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable |
86 | 86 | ||
87 | int intel_gtt_map_memory(struct page **pages, unsigned int num_entries, | 87 | static int intel_gtt_map_memory(struct page **pages, |
88 | struct scatterlist **sg_list, int *num_sg) | 88 | unsigned int num_entries, |
89 | struct sg_table *st) | ||
89 | { | 90 | { |
90 | struct sg_table st; | ||
91 | struct scatterlist *sg; | 91 | struct scatterlist *sg; |
92 | int i; | 92 | int i; |
93 | 93 | ||
94 | if (*sg_list) | ||
95 | return 0; /* already mapped (for e.g. resume */ | ||
96 | |||
97 | DBG("try mapping %lu pages\n", (unsigned long)num_entries); | 94 | DBG("try mapping %lu pages\n", (unsigned long)num_entries); |
98 | 95 | ||
99 | if (sg_alloc_table(&st, num_entries, GFP_KERNEL)) | 96 | if (sg_alloc_table(st, num_entries, GFP_KERNEL)) |
100 | goto err; | 97 | goto err; |
101 | 98 | ||
102 | *sg_list = sg = st.sgl; | 99 | for_each_sg(st->sgl, sg, num_entries, i) |
103 | |||
104 | for (i = 0 ; i < num_entries; i++, sg = sg_next(sg)) | ||
105 | sg_set_page(sg, pages[i], PAGE_SIZE, 0); | 100 | sg_set_page(sg, pages[i], PAGE_SIZE, 0); |
106 | 101 | ||
107 | *num_sg = pci_map_sg(intel_private.pcidev, *sg_list, | 102 | if (!pci_map_sg(intel_private.pcidev, |
108 | num_entries, PCI_DMA_BIDIRECTIONAL); | 103 | st->sgl, st->nents, PCI_DMA_BIDIRECTIONAL)) |
109 | if (unlikely(!*num_sg)) | ||
110 | goto err; | 104 | goto err; |
111 | 105 | ||
112 | return 0; | 106 | return 0; |
113 | 107 | ||
114 | err: | 108 | err: |
115 | sg_free_table(&st); | 109 | sg_free_table(st); |
116 | return -ENOMEM; | 110 | return -ENOMEM; |
117 | } | 111 | } |
118 | EXPORT_SYMBOL(intel_gtt_map_memory); | ||
119 | 112 | ||
120 | void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg) | 113 | static void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg) |
121 | { | 114 | { |
122 | struct sg_table st; | 115 | struct sg_table st; |
123 | DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); | 116 | DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); |
@@ -130,7 +123,6 @@ void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg) | |||
130 | 123 | ||
131 | sg_free_table(&st); | 124 | sg_free_table(&st); |
132 | } | 125 | } |
133 | EXPORT_SYMBOL(intel_gtt_unmap_memory); | ||
134 | 126 | ||
135 | static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) | 127 | static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) |
136 | { | 128 | { |
@@ -674,9 +666,14 @@ static int intel_gtt_init(void) | |||
674 | 666 | ||
675 | gtt_map_size = intel_private.base.gtt_total_entries * 4; | 667 | gtt_map_size = intel_private.base.gtt_total_entries * 4; |
676 | 668 | ||
677 | intel_private.gtt = ioremap(intel_private.gtt_bus_addr, | 669 | intel_private.gtt = NULL; |
678 | gtt_map_size); | 670 | if (INTEL_GTT_GEN < 6 && INTEL_GTT_GEN > 2) |
679 | if (!intel_private.gtt) { | 671 | intel_private.gtt = ioremap_wc(intel_private.gtt_bus_addr, |
672 | gtt_map_size); | ||
673 | if (intel_private.gtt == NULL) | ||
674 | intel_private.gtt = ioremap(intel_private.gtt_bus_addr, | ||
675 | gtt_map_size); | ||
676 | if (intel_private.gtt == NULL) { | ||
680 | intel_private.driver->cleanup(); | 677 | intel_private.driver->cleanup(); |
681 | iounmap(intel_private.registers); | 678 | iounmap(intel_private.registers); |
682 | return -ENOMEM; | 679 | return -ENOMEM; |
@@ -879,8 +876,7 @@ static bool i830_check_flags(unsigned int flags) | |||
879 | return false; | 876 | return false; |
880 | } | 877 | } |
881 | 878 | ||
882 | void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, | 879 | void intel_gtt_insert_sg_entries(struct sg_table *st, |
883 | unsigned int sg_len, | ||
884 | unsigned int pg_start, | 880 | unsigned int pg_start, |
885 | unsigned int flags) | 881 | unsigned int flags) |
886 | { | 882 | { |
@@ -892,12 +888,11 @@ void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, | |||
892 | 888 | ||
893 | /* sg may merge pages, but we have to separate | 889 | /* sg may merge pages, but we have to separate |
894 | * per-page addr for GTT */ | 890 | * per-page addr for GTT */ |
895 | for_each_sg(sg_list, sg, sg_len, i) { | 891 | for_each_sg(st->sgl, sg, st->nents, i) { |
896 | len = sg_dma_len(sg) >> PAGE_SHIFT; | 892 | len = sg_dma_len(sg) >> PAGE_SHIFT; |
897 | for (m = 0; m < len; m++) { | 893 | for (m = 0; m < len; m++) { |
898 | dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); | 894 | dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); |
899 | intel_private.driver->write_entry(addr, | 895 | intel_private.driver->write_entry(addr, j, flags); |
900 | j, flags); | ||
901 | j++; | 896 | j++; |
902 | } | 897 | } |
903 | } | 898 | } |
@@ -905,8 +900,10 @@ void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, | |||
905 | } | 900 | } |
906 | EXPORT_SYMBOL(intel_gtt_insert_sg_entries); | 901 | EXPORT_SYMBOL(intel_gtt_insert_sg_entries); |
907 | 902 | ||
908 | void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, | 903 | static void intel_gtt_insert_pages(unsigned int first_entry, |
909 | struct page **pages, unsigned int flags) | 904 | unsigned int num_entries, |
905 | struct page **pages, | ||
906 | unsigned int flags) | ||
910 | { | 907 | { |
911 | int i, j; | 908 | int i, j; |
912 | 909 | ||
@@ -917,7 +914,6 @@ void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, | |||
917 | } | 914 | } |
918 | readl(intel_private.gtt+j-1); | 915 | readl(intel_private.gtt+j-1); |
919 | } | 916 | } |
920 | EXPORT_SYMBOL(intel_gtt_insert_pages); | ||
921 | 917 | ||
922 | static int intel_fake_agp_insert_entries(struct agp_memory *mem, | 918 | static int intel_fake_agp_insert_entries(struct agp_memory *mem, |
923 | off_t pg_start, int type) | 919 | off_t pg_start, int type) |
@@ -953,13 +949,15 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, | |||
953 | global_cache_flush(); | 949 | global_cache_flush(); |
954 | 950 | ||
955 | if (intel_private.base.needs_dmar) { | 951 | if (intel_private.base.needs_dmar) { |
956 | ret = intel_gtt_map_memory(mem->pages, mem->page_count, | 952 | struct sg_table st; |
957 | &mem->sg_list, &mem->num_sg); | 953 | |
954 | ret = intel_gtt_map_memory(mem->pages, mem->page_count, &st); | ||
958 | if (ret != 0) | 955 | if (ret != 0) |
959 | return ret; | 956 | return ret; |
960 | 957 | ||
961 | intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg, | 958 | intel_gtt_insert_sg_entries(&st, pg_start, type); |
962 | pg_start, type); | 959 | mem->sg_list = st.sgl; |
960 | mem->num_sg = st.nents; | ||
963 | } else | 961 | } else |
964 | intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages, | 962 | intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages, |
965 | type); | 963 | type); |
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 192000377737..3a5af2f9b015 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c | |||
@@ -289,12 +289,11 @@ static int __devinit agp_sgi_init(void) | |||
289 | 289 | ||
290 | j = 0; | 290 | j = 0; |
291 | list_for_each_entry(info, &tioca_list, ca_list) { | 291 | list_for_each_entry(info, &tioca_list, ca_list) { |
292 | struct list_head *tmp; | ||
293 | if (list_empty(info->ca_devices)) | 292 | if (list_empty(info->ca_devices)) |
294 | continue; | 293 | continue; |
295 | list_for_each(tmp, info->ca_devices) { | 294 | list_for_each_entry(pdev, info->ca_devices, bus_list) { |
296 | u8 cap_ptr; | 295 | u8 cap_ptr; |
297 | pdev = pci_dev_b(tmp); | 296 | |
298 | if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) | 297 | if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) |
299 | continue; | 298 | continue; |
300 | cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); | 299 | cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); |
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index aab9605f0b43..24ffd8cec51e 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c | |||
@@ -74,21 +74,21 @@ static inline void netwinder_ds1620_reset(void) | |||
74 | 74 | ||
75 | static inline void netwinder_lock(unsigned long *flags) | 75 | static inline void netwinder_lock(unsigned long *flags) |
76 | { | 76 | { |
77 | spin_lock_irqsave(&nw_gpio_lock, *flags); | 77 | raw_spin_lock_irqsave(&nw_gpio_lock, *flags); |
78 | } | 78 | } |
79 | 79 | ||
80 | static inline void netwinder_unlock(unsigned long *flags) | 80 | static inline void netwinder_unlock(unsigned long *flags) |
81 | { | 81 | { |
82 | spin_unlock_irqrestore(&nw_gpio_lock, *flags); | 82 | raw_spin_unlock_irqrestore(&nw_gpio_lock, *flags); |
83 | } | 83 | } |
84 | 84 | ||
85 | static inline void netwinder_set_fan(int i) | 85 | static inline void netwinder_set_fan(int i) |
86 | { | 86 | { |
87 | unsigned long flags; | 87 | unsigned long flags; |
88 | 88 | ||
89 | spin_lock_irqsave(&nw_gpio_lock, flags); | 89 | raw_spin_lock_irqsave(&nw_gpio_lock, flags); |
90 | nw_gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0); | 90 | nw_gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0); |
91 | spin_unlock_irqrestore(&nw_gpio_lock, flags); | 91 | raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); |
92 | } | 92 | } |
93 | 93 | ||
94 | static inline int netwinder_get_fan(void) | 94 | static inline int netwinder_get_fan(void) |
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 7c0d391996b5..fbd9b2b850ef 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
@@ -289,3 +289,16 @@ config HW_RANDOM_EXYNOS | |||
289 | module will be called exynos-rng. | 289 | module will be called exynos-rng. |
290 | 290 | ||
291 | If unsure, say Y. | 291 | If unsure, say Y. |
292 | |||
293 | config HW_RANDOM_TPM | ||
294 | tristate "TPM HW Random Number Generator support" | ||
295 | depends on HW_RANDOM && TCG_TPM | ||
296 | default HW_RANDOM | ||
297 | ---help--- | ||
298 | This driver provides kernel-side support for the Random Number | ||
299 | Generator in the Trusted Platform Module | ||
300 | |||
301 | To compile this driver as a module, choose M here: the | ||
302 | module will be called tpm-rng. | ||
303 | |||
304 | If unsure, say Y. | ||
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 39a757ca15b6..1fd7eec9fbf6 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile | |||
@@ -25,3 +25,4 @@ obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o | |||
25 | obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o | 25 | obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o |
26 | obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o | 26 | obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o |
27 | obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o | 27 | obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o |
28 | obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o | ||
diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c index 85074de5042e..f05d85713fd3 100644 --- a/drivers/char/hw_random/mxc-rnga.c +++ b/drivers/char/hw_random/mxc-rnga.c | |||
@@ -59,16 +59,21 @@ | |||
59 | #define RNGA_STATUS_LAST_READ_STATUS 0x00000002 | 59 | #define RNGA_STATUS_LAST_READ_STATUS 0x00000002 |
60 | #define RNGA_STATUS_SECURITY_VIOLATION 0x00000001 | 60 | #define RNGA_STATUS_SECURITY_VIOLATION 0x00000001 |
61 | 61 | ||
62 | static struct platform_device *rng_dev; | 62 | struct mxc_rng { |
63 | struct device *dev; | ||
64 | struct hwrng rng; | ||
65 | void __iomem *mem; | ||
66 | struct clk *clk; | ||
67 | }; | ||
63 | 68 | ||
64 | static int mxc_rnga_data_present(struct hwrng *rng, int wait) | 69 | static int mxc_rnga_data_present(struct hwrng *rng, int wait) |
65 | { | 70 | { |
66 | void __iomem *rng_base = (void __iomem *)rng->priv; | ||
67 | int i; | 71 | int i; |
72 | struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); | ||
68 | 73 | ||
69 | for (i = 0; i < 20; i++) { | 74 | for (i = 0; i < 20; i++) { |
70 | /* how many random numbers are in FIFO? [0-16] */ | 75 | /* how many random numbers are in FIFO? [0-16] */ |
71 | int level = (__raw_readl(rng_base + RNGA_STATUS) & | 76 | int level = (__raw_readl(mxc_rng->mem + RNGA_STATUS) & |
72 | RNGA_STATUS_LEVEL_MASK) >> 8; | 77 | RNGA_STATUS_LEVEL_MASK) >> 8; |
73 | if (level || !wait) | 78 | if (level || !wait) |
74 | return !!level; | 79 | return !!level; |
@@ -81,20 +86,20 @@ static int mxc_rnga_data_read(struct hwrng *rng, u32 * data) | |||
81 | { | 86 | { |
82 | int err; | 87 | int err; |
83 | u32 ctrl; | 88 | u32 ctrl; |
84 | void __iomem *rng_base = (void __iomem *)rng->priv; | 89 | struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); |
85 | 90 | ||
86 | /* retrieve a random number from FIFO */ | 91 | /* retrieve a random number from FIFO */ |
87 | *data = __raw_readl(rng_base + RNGA_OUTPUT_FIFO); | 92 | *data = __raw_readl(mxc_rng->mem + RNGA_OUTPUT_FIFO); |
88 | 93 | ||
89 | /* some error while reading this random number? */ | 94 | /* some error while reading this random number? */ |
90 | err = __raw_readl(rng_base + RNGA_STATUS) & RNGA_STATUS_ERROR_INT; | 95 | err = __raw_readl(mxc_rng->mem + RNGA_STATUS) & RNGA_STATUS_ERROR_INT; |
91 | 96 | ||
92 | /* if error: clear error interrupt, but doesn't return random number */ | 97 | /* if error: clear error interrupt, but doesn't return random number */ |
93 | if (err) { | 98 | if (err) { |
94 | dev_dbg(&rng_dev->dev, "Error while reading random number!\n"); | 99 | dev_dbg(mxc_rng->dev, "Error while reading random number!\n"); |
95 | ctrl = __raw_readl(rng_base + RNGA_CONTROL); | 100 | ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); |
96 | __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT, | 101 | __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT, |
97 | rng_base + RNGA_CONTROL); | 102 | mxc_rng->mem + RNGA_CONTROL); |
98 | return 0; | 103 | return 0; |
99 | } else | 104 | } else |
100 | return 4; | 105 | return 4; |
@@ -103,22 +108,22 @@ static int mxc_rnga_data_read(struct hwrng *rng, u32 * data) | |||
103 | static int mxc_rnga_init(struct hwrng *rng) | 108 | static int mxc_rnga_init(struct hwrng *rng) |
104 | { | 109 | { |
105 | u32 ctrl, osc; | 110 | u32 ctrl, osc; |
106 | void __iomem *rng_base = (void __iomem *)rng->priv; | 111 | struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); |
107 | 112 | ||
108 | /* wake up */ | 113 | /* wake up */ |
109 | ctrl = __raw_readl(rng_base + RNGA_CONTROL); | 114 | ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); |
110 | __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, rng_base + RNGA_CONTROL); | 115 | __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, mxc_rng->mem + RNGA_CONTROL); |
111 | 116 | ||
112 | /* verify if oscillator is working */ | 117 | /* verify if oscillator is working */ |
113 | osc = __raw_readl(rng_base + RNGA_STATUS); | 118 | osc = __raw_readl(mxc_rng->mem + RNGA_STATUS); |
114 | if (osc & RNGA_STATUS_OSC_DEAD) { | 119 | if (osc & RNGA_STATUS_OSC_DEAD) { |
115 | dev_err(&rng_dev->dev, "RNGA Oscillator is dead!\n"); | 120 | dev_err(mxc_rng->dev, "RNGA Oscillator is dead!\n"); |
116 | return -ENODEV; | 121 | return -ENODEV; |
117 | } | 122 | } |
118 | 123 | ||
119 | /* go running */ | 124 | /* go running */ |
120 | ctrl = __raw_readl(rng_base + RNGA_CONTROL); | 125 | ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); |
121 | __raw_writel(ctrl | RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); | 126 | __raw_writel(ctrl | RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL); |
122 | 127 | ||
123 | return 0; | 128 | return 0; |
124 | } | 129 | } |
@@ -126,40 +131,40 @@ static int mxc_rnga_init(struct hwrng *rng) | |||
126 | static void mxc_rnga_cleanup(struct hwrng *rng) | 131 | static void mxc_rnga_cleanup(struct hwrng *rng) |
127 | { | 132 | { |
128 | u32 ctrl; | 133 | u32 ctrl; |
129 | void __iomem *rng_base = (void __iomem *)rng->priv; | 134 | struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); |
130 | 135 | ||
131 | ctrl = __raw_readl(rng_base + RNGA_CONTROL); | 136 | ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); |
132 | 137 | ||
133 | /* stop rnga */ | 138 | /* stop rnga */ |
134 | __raw_writel(ctrl & ~RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); | 139 | __raw_writel(ctrl & ~RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL); |
135 | } | 140 | } |
136 | 141 | ||
137 | static struct hwrng mxc_rnga = { | ||
138 | .name = "mxc-rnga", | ||
139 | .init = mxc_rnga_init, | ||
140 | .cleanup = mxc_rnga_cleanup, | ||
141 | .data_present = mxc_rnga_data_present, | ||
142 | .data_read = mxc_rnga_data_read | ||
143 | }; | ||
144 | |||
145 | static int __init mxc_rnga_probe(struct platform_device *pdev) | 142 | static int __init mxc_rnga_probe(struct platform_device *pdev) |
146 | { | 143 | { |
147 | int err = -ENODEV; | 144 | int err = -ENODEV; |
148 | struct clk *clk; | ||
149 | struct resource *res, *mem; | 145 | struct resource *res, *mem; |
150 | void __iomem *rng_base = NULL; | 146 | struct mxc_rng *mxc_rng; |
151 | 147 | ||
152 | if (rng_dev) | 148 | mxc_rng = devm_kzalloc(&pdev->dev, sizeof(struct mxc_rng), |
153 | return -EBUSY; | 149 | GFP_KERNEL); |
154 | 150 | if (!mxc_rng) | |
155 | clk = clk_get(&pdev->dev, "rng"); | 151 | return -ENOMEM; |
156 | if (IS_ERR(clk)) { | 152 | |
153 | mxc_rng->dev = &pdev->dev; | ||
154 | mxc_rng->rng.name = "mxc-rnga"; | ||
155 | mxc_rng->rng.init = mxc_rnga_init; | ||
156 | mxc_rng->rng.cleanup = mxc_rnga_cleanup, | ||
157 | mxc_rng->rng.data_present = mxc_rnga_data_present, | ||
158 | mxc_rng->rng.data_read = mxc_rnga_data_read, | ||
159 | |||
160 | mxc_rng->clk = devm_clk_get(&pdev->dev, NULL); | ||
161 | if (IS_ERR(mxc_rng->clk)) { | ||
157 | dev_err(&pdev->dev, "Could not get rng_clk!\n"); | 162 | dev_err(&pdev->dev, "Could not get rng_clk!\n"); |
158 | err = PTR_ERR(clk); | 163 | err = PTR_ERR(mxc_rng->clk); |
159 | goto out; | 164 | goto out; |
160 | } | 165 | } |
161 | 166 | ||
162 | clk_enable(clk); | 167 | clk_prepare_enable(mxc_rng->clk); |
163 | 168 | ||
164 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 169 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
165 | if (!res) { | 170 | if (!res) { |
@@ -173,36 +178,27 @@ static int __init mxc_rnga_probe(struct platform_device *pdev) | |||
173 | goto err_region; | 178 | goto err_region; |
174 | } | 179 | } |
175 | 180 | ||
176 | rng_base = ioremap(res->start, resource_size(res)); | 181 | mxc_rng->mem = ioremap(res->start, resource_size(res)); |
177 | if (!rng_base) { | 182 | if (!mxc_rng->mem) { |
178 | err = -ENOMEM; | 183 | err = -ENOMEM; |
179 | goto err_ioremap; | 184 | goto err_ioremap; |
180 | } | 185 | } |
181 | 186 | ||
182 | mxc_rnga.priv = (unsigned long)rng_base; | 187 | err = hwrng_register(&mxc_rng->rng); |
183 | |||
184 | err = hwrng_register(&mxc_rnga); | ||
185 | if (err) { | 188 | if (err) { |
186 | dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err); | 189 | dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err); |
187 | goto err_register; | 190 | goto err_ioremap; |
188 | } | 191 | } |
189 | 192 | ||
190 | rng_dev = pdev; | ||
191 | |||
192 | dev_info(&pdev->dev, "MXC RNGA Registered.\n"); | 193 | dev_info(&pdev->dev, "MXC RNGA Registered.\n"); |
193 | 194 | ||
194 | return 0; | 195 | return 0; |
195 | 196 | ||
196 | err_register: | ||
197 | iounmap(rng_base); | ||
198 | rng_base = NULL; | ||
199 | |||
200 | err_ioremap: | 197 | err_ioremap: |
201 | release_mem_region(res->start, resource_size(res)); | 198 | release_mem_region(res->start, resource_size(res)); |
202 | 199 | ||
203 | err_region: | 200 | err_region: |
204 | clk_disable(clk); | 201 | clk_disable_unprepare(mxc_rng->clk); |
205 | clk_put(clk); | ||
206 | 202 | ||
207 | out: | 203 | out: |
208 | return err; | 204 | return err; |
@@ -211,17 +207,15 @@ out: | |||
211 | static int __exit mxc_rnga_remove(struct platform_device *pdev) | 207 | static int __exit mxc_rnga_remove(struct platform_device *pdev) |
212 | { | 208 | { |
213 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 209 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
214 | void __iomem *rng_base = (void __iomem *)mxc_rnga.priv; | 210 | struct mxc_rng *mxc_rng = platform_get_drvdata(pdev); |
215 | struct clk *clk = clk_get(&pdev->dev, "rng"); | ||
216 | 211 | ||
217 | hwrng_unregister(&mxc_rnga); | 212 | hwrng_unregister(&mxc_rng->rng); |
218 | 213 | ||
219 | iounmap(rng_base); | 214 | iounmap(mxc_rng->mem); |
220 | 215 | ||
221 | release_mem_region(res->start, resource_size(res)); | 216 | release_mem_region(res->start, resource_size(res)); |
222 | 217 | ||
223 | clk_disable(clk); | 218 | clk_disable_unprepare(mxc_rng->clk); |
224 | clk_put(clk); | ||
225 | 219 | ||
226 | return 0; | 220 | return 0; |
227 | } | 221 | } |
diff --git a/drivers/char/hw_random/octeon-rng.c b/drivers/char/hw_random/octeon-rng.c index 0943edc782a1..5c34c092af71 100644 --- a/drivers/char/hw_random/octeon-rng.c +++ b/drivers/char/hw_random/octeon-rng.c | |||
@@ -75,42 +75,35 @@ static int __devinit octeon_rng_probe(struct platform_device *pdev) | |||
75 | 75 | ||
76 | res_ports = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 76 | res_ports = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
77 | if (!res_ports) | 77 | if (!res_ports) |
78 | goto err_ports; | 78 | return -ENOENT; |
79 | 79 | ||
80 | res_result = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 80 | res_result = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
81 | if (!res_result) | 81 | if (!res_result) |
82 | goto err_ports; | 82 | return -ENOENT; |
83 | 83 | ||
84 | 84 | ||
85 | rng->control_status = devm_ioremap_nocache(&pdev->dev, | 85 | rng->control_status = devm_ioremap_nocache(&pdev->dev, |
86 | res_ports->start, | 86 | res_ports->start, |
87 | sizeof(u64)); | 87 | sizeof(u64)); |
88 | if (!rng->control_status) | 88 | if (!rng->control_status) |
89 | goto err_ports; | 89 | return -ENOENT; |
90 | 90 | ||
91 | rng->result = devm_ioremap_nocache(&pdev->dev, | 91 | rng->result = devm_ioremap_nocache(&pdev->dev, |
92 | res_result->start, | 92 | res_result->start, |
93 | sizeof(u64)); | 93 | sizeof(u64)); |
94 | if (!rng->result) | 94 | if (!rng->result) |
95 | goto err_r; | 95 | return -ENOENT; |
96 | 96 | ||
97 | rng->ops = ops; | 97 | rng->ops = ops; |
98 | 98 | ||
99 | dev_set_drvdata(&pdev->dev, &rng->ops); | 99 | dev_set_drvdata(&pdev->dev, &rng->ops); |
100 | ret = hwrng_register(&rng->ops); | 100 | ret = hwrng_register(&rng->ops); |
101 | if (ret) | 101 | if (ret) |
102 | goto err; | 102 | return -ENOENT; |
103 | 103 | ||
104 | dev_info(&pdev->dev, "Octeon Random Number Generator\n"); | 104 | dev_info(&pdev->dev, "Octeon Random Number Generator\n"); |
105 | 105 | ||
106 | return 0; | 106 | return 0; |
107 | err: | ||
108 | devm_iounmap(&pdev->dev, rng->control_status); | ||
109 | err_r: | ||
110 | devm_iounmap(&pdev->dev, rng->result); | ||
111 | err_ports: | ||
112 | devm_kfree(&pdev->dev, rng); | ||
113 | return -ENOENT; | ||
114 | } | 107 | } |
115 | 108 | ||
116 | static int __exit octeon_rng_remove(struct platform_device *pdev) | 109 | static int __exit octeon_rng_remove(struct platform_device *pdev) |
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 4fbdceb6f773..a5effd813abd 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c | |||
@@ -18,11 +18,12 @@ | |||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/random.h> | 20 | #include <linux/random.h> |
21 | #include <linux/clk.h> | ||
22 | #include <linux/err.h> | 21 | #include <linux/err.h> |
23 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
24 | #include <linux/hw_random.h> | 23 | #include <linux/hw_random.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | ||
26 | #include <linux/pm_runtime.h> | ||
26 | 27 | ||
27 | #include <asm/io.h> | 28 | #include <asm/io.h> |
28 | 29 | ||
@@ -46,26 +47,36 @@ | |||
46 | #define RNG_SYSSTATUS 0x44 /* System status | 47 | #define RNG_SYSSTATUS 0x44 /* System status |
47 | [0] = RESETDONE */ | 48 | [0] = RESETDONE */ |
48 | 49 | ||
49 | static void __iomem *rng_base; | 50 | /** |
50 | static struct clk *rng_ick; | 51 | * struct omap_rng_private_data - RNG IP block-specific data |
51 | static struct platform_device *rng_dev; | 52 | * @base: virtual address of the beginning of the RNG IP block registers |
53 | * @mem_res: struct resource * for the IP block registers physical memory | ||
54 | */ | ||
55 | struct omap_rng_private_data { | ||
56 | void __iomem *base; | ||
57 | struct resource *mem_res; | ||
58 | }; | ||
52 | 59 | ||
53 | static inline u32 omap_rng_read_reg(int reg) | 60 | static inline u32 omap_rng_read_reg(struct omap_rng_private_data *priv, int reg) |
54 | { | 61 | { |
55 | return __raw_readl(rng_base + reg); | 62 | return __raw_readl(priv->base + reg); |
56 | } | 63 | } |
57 | 64 | ||
58 | static inline void omap_rng_write_reg(int reg, u32 val) | 65 | static inline void omap_rng_write_reg(struct omap_rng_private_data *priv, |
66 | int reg, u32 val) | ||
59 | { | 67 | { |
60 | __raw_writel(val, rng_base + reg); | 68 | __raw_writel(val, priv->base + reg); |
61 | } | 69 | } |
62 | 70 | ||
63 | static int omap_rng_data_present(struct hwrng *rng, int wait) | 71 | static int omap_rng_data_present(struct hwrng *rng, int wait) |
64 | { | 72 | { |
73 | struct omap_rng_private_data *priv; | ||
65 | int data, i; | 74 | int data, i; |
66 | 75 | ||
76 | priv = (struct omap_rng_private_data *)rng->priv; | ||
77 | |||
67 | for (i = 0; i < 20; i++) { | 78 | for (i = 0; i < 20; i++) { |
68 | data = omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; | 79 | data = omap_rng_read_reg(priv, RNG_STAT_REG) ? 0 : 1; |
69 | if (data || !wait) | 80 | if (data || !wait) |
70 | break; | 81 | break; |
71 | /* RNG produces data fast enough (2+ MBit/sec, even | 82 | /* RNG produces data fast enough (2+ MBit/sec, even |
@@ -80,9 +91,13 @@ static int omap_rng_data_present(struct hwrng *rng, int wait) | |||
80 | 91 | ||
81 | static int omap_rng_data_read(struct hwrng *rng, u32 *data) | 92 | static int omap_rng_data_read(struct hwrng *rng, u32 *data) |
82 | { | 93 | { |
83 | *data = omap_rng_read_reg(RNG_OUT_REG); | 94 | struct omap_rng_private_data *priv; |
95 | |||
96 | priv = (struct omap_rng_private_data *)rng->priv; | ||
97 | |||
98 | *data = omap_rng_read_reg(priv, RNG_OUT_REG); | ||
84 | 99 | ||
85 | return 4; | 100 | return sizeof(u32); |
86 | } | 101 | } |
87 | 102 | ||
88 | static struct hwrng omap_rng_ops = { | 103 | static struct hwrng omap_rng_ops = { |
@@ -93,69 +108,68 @@ static struct hwrng omap_rng_ops = { | |||
93 | 108 | ||
94 | static int __devinit omap_rng_probe(struct platform_device *pdev) | 109 | static int __devinit omap_rng_probe(struct platform_device *pdev) |
95 | { | 110 | { |
96 | struct resource *res; | 111 | struct omap_rng_private_data *priv; |
97 | int ret; | 112 | int ret; |
98 | 113 | ||
99 | /* | 114 | priv = kzalloc(sizeof(struct omap_rng_private_data), GFP_KERNEL); |
100 | * A bit ugly, and it will never actually happen but there can | 115 | if (!priv) { |
101 | * be only one RNG and this catches any bork | 116 | dev_err(&pdev->dev, "could not allocate memory\n"); |
102 | */ | 117 | return -ENOMEM; |
103 | if (rng_dev) | 118 | }; |
104 | return -EBUSY; | ||
105 | |||
106 | if (cpu_is_omap24xx()) { | ||
107 | rng_ick = clk_get(&pdev->dev, "ick"); | ||
108 | if (IS_ERR(rng_ick)) { | ||
109 | dev_err(&pdev->dev, "Could not get rng_ick\n"); | ||
110 | ret = PTR_ERR(rng_ick); | ||
111 | return ret; | ||
112 | } else | ||
113 | clk_enable(rng_ick); | ||
114 | } | ||
115 | 119 | ||
116 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 120 | omap_rng_ops.priv = (unsigned long)priv; |
121 | dev_set_drvdata(&pdev->dev, priv); | ||
117 | 122 | ||
118 | rng_base = devm_request_and_ioremap(&pdev->dev, res); | 123 | priv->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
119 | if (!rng_base) { | 124 | if (!priv->mem_res) { |
125 | ret = -ENOENT; | ||
126 | goto err_ioremap; | ||
127 | } | ||
128 | |||
129 | priv->base = devm_request_and_ioremap(&pdev->dev, priv->mem_res); | ||
130 | if (!priv->base) { | ||
120 | ret = -ENOMEM; | 131 | ret = -ENOMEM; |
121 | goto err_ioremap; | 132 | goto err_ioremap; |
122 | } | 133 | } |
123 | dev_set_drvdata(&pdev->dev, res); | 134 | dev_set_drvdata(&pdev->dev, priv); |
135 | |||
136 | pm_runtime_enable(&pdev->dev); | ||
137 | pm_runtime_get_sync(&pdev->dev); | ||
124 | 138 | ||
125 | ret = hwrng_register(&omap_rng_ops); | 139 | ret = hwrng_register(&omap_rng_ops); |
126 | if (ret) | 140 | if (ret) |
127 | goto err_register; | 141 | goto err_register; |
128 | 142 | ||
129 | dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", | 143 | dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", |
130 | omap_rng_read_reg(RNG_REV_REG)); | 144 | omap_rng_read_reg(priv, RNG_REV_REG)); |
131 | omap_rng_write_reg(RNG_MASK_REG, 0x1); | ||
132 | 145 | ||
133 | rng_dev = pdev; | 146 | omap_rng_write_reg(priv, RNG_MASK_REG, 0x1); |
134 | 147 | ||
135 | return 0; | 148 | return 0; |
136 | 149 | ||
137 | err_register: | 150 | err_register: |
138 | rng_base = NULL; | 151 | priv->base = NULL; |
152 | pm_runtime_disable(&pdev->dev); | ||
139 | err_ioremap: | 153 | err_ioremap: |
140 | if (cpu_is_omap24xx()) { | 154 | kfree(priv); |
141 | clk_disable(rng_ick); | 155 | |
142 | clk_put(rng_ick); | ||
143 | } | ||
144 | return ret; | 156 | return ret; |
145 | } | 157 | } |
146 | 158 | ||
147 | static int __exit omap_rng_remove(struct platform_device *pdev) | 159 | static int __exit omap_rng_remove(struct platform_device *pdev) |
148 | { | 160 | { |
161 | struct omap_rng_private_data *priv = dev_get_drvdata(&pdev->dev); | ||
162 | |||
149 | hwrng_unregister(&omap_rng_ops); | 163 | hwrng_unregister(&omap_rng_ops); |
150 | 164 | ||
151 | omap_rng_write_reg(RNG_MASK_REG, 0x0); | 165 | omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); |
152 | 166 | ||
153 | if (cpu_is_omap24xx()) { | 167 | pm_runtime_put_sync(&pdev->dev); |
154 | clk_disable(rng_ick); | 168 | pm_runtime_disable(&pdev->dev); |
155 | clk_put(rng_ick); | 169 | |
156 | } | 170 | release_mem_region(priv->mem_res->start, resource_size(priv->mem_res)); |
157 | 171 | ||
158 | rng_base = NULL; | 172 | kfree(priv); |
159 | 173 | ||
160 | return 0; | 174 | return 0; |
161 | } | 175 | } |
@@ -164,13 +178,21 @@ static int __exit omap_rng_remove(struct platform_device *pdev) | |||
164 | 178 | ||
165 | static int omap_rng_suspend(struct device *dev) | 179 | static int omap_rng_suspend(struct device *dev) |
166 | { | 180 | { |
167 | omap_rng_write_reg(RNG_MASK_REG, 0x0); | 181 | struct omap_rng_private_data *priv = dev_get_drvdata(dev); |
182 | |||
183 | omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); | ||
184 | pm_runtime_put_sync(dev); | ||
185 | |||
168 | return 0; | 186 | return 0; |
169 | } | 187 | } |
170 | 188 | ||
171 | static int omap_rng_resume(struct device *dev) | 189 | static int omap_rng_resume(struct device *dev) |
172 | { | 190 | { |
173 | omap_rng_write_reg(RNG_MASK_REG, 0x1); | 191 | struct omap_rng_private_data *priv = dev_get_drvdata(dev); |
192 | |||
193 | pm_runtime_get_sync(dev); | ||
194 | omap_rng_write_reg(priv, RNG_MASK_REG, 0x1); | ||
195 | |||
174 | return 0; | 196 | return 0; |
175 | } | 197 | } |
176 | 198 | ||
@@ -198,9 +220,6 @@ static struct platform_driver omap_rng_driver = { | |||
198 | 220 | ||
199 | static int __init omap_rng_init(void) | 221 | static int __init omap_rng_init(void) |
200 | { | 222 | { |
201 | if (!cpu_is_omap16xx() && !cpu_is_omap24xx()) | ||
202 | return -ENODEV; | ||
203 | |||
204 | return platform_driver_register(&omap_rng_driver); | 223 | return platform_driver_register(&omap_rng_driver); |
205 | } | 224 | } |
206 | 225 | ||
diff --git a/drivers/char/hw_random/tpm-rng.c b/drivers/char/hw_random/tpm-rng.c new file mode 100644 index 000000000000..d6d448266f07 --- /dev/null +++ b/drivers/char/hw_random/tpm-rng.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Kent Yoder IBM Corporation | ||
3 | * | ||
4 | * HWRNG interfaces to pull RNG data from a TPM | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/hw_random.h> | ||
22 | #include <linux/tpm.h> | ||
23 | |||
24 | #define MODULE_NAME "tpm-rng" | ||
25 | |||
26 | static int tpm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) | ||
27 | { | ||
28 | return tpm_get_random(TPM_ANY_NUM, data, max); | ||
29 | } | ||
30 | |||
31 | static struct hwrng tpm_rng = { | ||
32 | .name = MODULE_NAME, | ||
33 | .read = tpm_rng_read, | ||
34 | }; | ||
35 | |||
36 | static int __init rng_init(void) | ||
37 | { | ||
38 | return hwrng_register(&tpm_rng); | ||
39 | } | ||
40 | module_init(rng_init); | ||
41 | |||
42 | static void __exit rng_exit(void) | ||
43 | { | ||
44 | hwrng_unregister(&tpm_rng); | ||
45 | } | ||
46 | module_exit(rng_exit); | ||
47 | |||
48 | MODULE_LICENSE("GPL v2"); | ||
49 | MODULE_AUTHOR("Kent Yoder <key@linux.vnet.ibm.com>"); | ||
50 | MODULE_DESCRIPTION("RNG driver for TPM devices"); | ||
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 2c29942b1326..a0c84bb30856 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -1880,7 +1880,7 @@ int ipmi_request_supply_msgs(ipmi_user_t user, | |||
1880 | struct ipmi_recv_msg *supplied_recv, | 1880 | struct ipmi_recv_msg *supplied_recv, |
1881 | int priority) | 1881 | int priority) |
1882 | { | 1882 | { |
1883 | unsigned char saddr, lun; | 1883 | unsigned char saddr = 0, lun = 0; |
1884 | int rv; | 1884 | int rv; |
1885 | 1885 | ||
1886 | if (!user) | 1886 | if (!user) |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 83f85cf7fb1b..32a6c7e256bd 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -2424,6 +2424,38 @@ static void ipmi_pci_cleanup(struct smi_info *info) | |||
2424 | pci_disable_device(pdev); | 2424 | pci_disable_device(pdev); |
2425 | } | 2425 | } |
2426 | 2426 | ||
2427 | static int __devinit ipmi_pci_probe_regspacing(struct smi_info *info) | ||
2428 | { | ||
2429 | if (info->si_type == SI_KCS) { | ||
2430 | unsigned char status; | ||
2431 | int regspacing; | ||
2432 | |||
2433 | info->io.regsize = DEFAULT_REGSIZE; | ||
2434 | info->io.regshift = 0; | ||
2435 | info->io_size = 2; | ||
2436 | info->handlers = &kcs_smi_handlers; | ||
2437 | |||
2438 | /* detect 1, 4, 16byte spacing */ | ||
2439 | for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) { | ||
2440 | info->io.regspacing = regspacing; | ||
2441 | if (info->io_setup(info)) { | ||
2442 | dev_err(info->dev, | ||
2443 | "Could not setup I/O space\n"); | ||
2444 | return DEFAULT_REGSPACING; | ||
2445 | } | ||
2446 | /* write invalid cmd */ | ||
2447 | info->io.outputb(&info->io, 1, 0x10); | ||
2448 | /* read status back */ | ||
2449 | status = info->io.inputb(&info->io, 1); | ||
2450 | info->io_cleanup(info); | ||
2451 | if (status) | ||
2452 | return regspacing; | ||
2453 | regspacing *= 4; | ||
2454 | } | ||
2455 | } | ||
2456 | return DEFAULT_REGSPACING; | ||
2457 | } | ||
2458 | |||
2427 | static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | 2459 | static int __devinit ipmi_pci_probe(struct pci_dev *pdev, |
2428 | const struct pci_device_id *ent) | 2460 | const struct pci_device_id *ent) |
2429 | { | 2461 | { |
@@ -2476,8 +2508,8 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | |||
2476 | } | 2508 | } |
2477 | info->io.addr_data = pci_resource_start(pdev, 0); | 2509 | info->io.addr_data = pci_resource_start(pdev, 0); |
2478 | 2510 | ||
2479 | info->io.regspacing = DEFAULT_REGSPACING; | 2511 | info->io.regspacing = ipmi_pci_probe_regspacing(info); |
2480 | info->io.regsize = DEFAULT_REGSPACING; | 2512 | info->io.regsize = DEFAULT_REGSIZE; |
2481 | info->io.regshift = 0; | 2513 | info->io.regshift = 0; |
2482 | 2514 | ||
2483 | info->irq = pdev->irq; | 2515 | info->irq = pdev->irq; |
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 47ff7e470d87..f74e892711dd 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c | |||
@@ -507,7 +507,7 @@ static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) | |||
507 | 507 | ||
508 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | 508 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
509 | 509 | ||
510 | /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ | 510 | /* Remap-pfn-range will mark the range VM_IO */ |
511 | if (remap_pfn_range(vma, | 511 | if (remap_pfn_range(vma, |
512 | vma->vm_start, | 512 | vma->vm_start, |
513 | __pa(soft->gscr_addr) >> PAGE_SHIFT, | 513 | __pa(soft->gscr_addr) >> PAGE_SHIFT, |
@@ -799,7 +799,7 @@ static int mbcs_remove(struct cx_dev *dev) | |||
799 | return 0; | 799 | return 0; |
800 | } | 800 | } |
801 | 801 | ||
802 | static const struct cx_device_id __devinitdata mbcs_id_table[] = { | 802 | static const struct cx_device_id __devinitconst mbcs_id_table[] = { |
803 | { | 803 | { |
804 | .part_num = MBCS_PART_NUM, | 804 | .part_num = MBCS_PART_NUM, |
805 | .mfg_num = MBCS_MFG_NUM, | 805 | .mfg_num = MBCS_MFG_NUM, |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index e5eedfa24c91..0537903c985b 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -322,7 +322,7 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma) | |||
322 | 322 | ||
323 | vma->vm_ops = &mmap_mem_ops; | 323 | vma->vm_ops = &mmap_mem_ops; |
324 | 324 | ||
325 | /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ | 325 | /* Remap-pfn-range will mark the range VM_IO */ |
326 | if (remap_pfn_range(vma, | 326 | if (remap_pfn_range(vma, |
327 | vma->vm_start, | 327 | vma->vm_start, |
328 | vma->vm_pgoff, | 328 | vma->vm_pgoff, |
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index 33dc2298af73..3d6c0671e996 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c | |||
@@ -826,7 +826,7 @@ static int __init mmtimer_init(void) | |||
826 | 826 | ||
827 | /* Allocate list of node ptrs to mmtimer_t's */ | 827 | /* Allocate list of node ptrs to mmtimer_t's */ |
828 | timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL); | 828 | timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL); |
829 | if (timers == NULL) { | 829 | if (!timers) { |
830 | printk(KERN_ERR "%s: failed to allocate memory for device\n", | 830 | printk(KERN_ERR "%s: failed to allocate memory for device\n", |
831 | MMTIMER_NAME); | 831 | MMTIMER_NAME); |
832 | goto out3; | 832 | goto out3; |
@@ -848,7 +848,6 @@ static int __init mmtimer_init(void) | |||
848 | return 0; | 848 | return 0; |
849 | 849 | ||
850 | out3: | 850 | out3: |
851 | kfree(timers); | ||
852 | misc_deregister(&mmtimer_miscdev); | 851 | misc_deregister(&mmtimer_miscdev); |
853 | out2: | 852 | out2: |
854 | free_irq(SGI_MMTIMER_VECTOR, NULL); | 853 | free_irq(SGI_MMTIMER_VECTOR, NULL); |
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 845f97fd1832..e1f60f968fdd 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c | |||
@@ -286,7 +286,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, | |||
286 | atomic_set(&vdata->refcnt, 1); | 286 | atomic_set(&vdata->refcnt, 1); |
287 | vma->vm_private_data = vdata; | 287 | vma->vm_private_data = vdata; |
288 | 288 | ||
289 | vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND); | 289 | vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; |
290 | if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED) | 290 | if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED) |
291 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | 291 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
292 | vma->vm_ops = &mspec_vm_ops; | 292 | vma->vm_ops = &mspec_vm_ops; |
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index 1d82d5838f0c..164544afd680 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c | |||
@@ -430,7 +430,7 @@ static ssize_t mwave_write(struct file *file, const char __user *buf, | |||
430 | 430 | ||
431 | static int register_serial_portandirq(unsigned int port, int irq) | 431 | static int register_serial_portandirq(unsigned int port, int irq) |
432 | { | 432 | { |
433 | struct uart_port uart; | 433 | struct uart_8250_port uart; |
434 | 434 | ||
435 | switch ( port ) { | 435 | switch ( port ) { |
436 | case 0x3f8: | 436 | case 0x3f8: |
@@ -462,14 +462,14 @@ static int register_serial_portandirq(unsigned int port, int irq) | |||
462 | } /* switch */ | 462 | } /* switch */ |
463 | /* irq is okay */ | 463 | /* irq is okay */ |
464 | 464 | ||
465 | memset(&uart, 0, sizeof(struct uart_port)); | 465 | memset(&uart, 0, sizeof(uart)); |
466 | 466 | ||
467 | uart.uartclk = 1843200; | 467 | uart.port.uartclk = 1843200; |
468 | uart.iobase = port; | 468 | uart.port.iobase = port; |
469 | uart.irq = irq; | 469 | uart.port.irq = irq; |
470 | uart.iotype = UPIO_PORT; | 470 | uart.port.iotype = UPIO_PORT; |
471 | uart.flags = UPF_SHARE_IRQ; | 471 | uart.port.flags = UPF_SHARE_IRQ; |
472 | return serial8250_register_port(&uart); | 472 | return serial8250_register_8250_port(&uart); |
473 | } | 473 | } |
474 | 474 | ||
475 | 475 | ||
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 04a480f86c6c..cfdfe493c6af 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c | |||
@@ -93,9 +93,9 @@ int button_del_callback (void (*callback) (void)) | |||
93 | button_callback_list [lp].count = 0; | 93 | button_callback_list [lp].count = 0; |
94 | callback_count--; | 94 | callback_count--; |
95 | return 0; | 95 | return 0; |
96 | }; | 96 | } |
97 | lp--; | 97 | lp--; |
98 | }; | 98 | } |
99 | return -EINVAL; | 99 | return -EINVAL; |
100 | } | 100 | } |
101 | 101 | ||
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index d45c3345b4af..e371480d3639 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c | |||
@@ -30,7 +30,6 @@ | |||
30 | 30 | ||
31 | #include <asm/hardware/dec21285.h> | 31 | #include <asm/hardware/dec21285.h> |
32 | #include <asm/io.h> | 32 | #include <asm/io.h> |
33 | #include <asm/leds.h> | ||
34 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
35 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
36 | 35 | ||
@@ -179,9 +178,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf, | |||
179 | 178 | ||
180 | written = 0; | 179 | written = 0; |
181 | 180 | ||
182 | leds_event(led_claim); | ||
183 | leds_event(led_green_on); | ||
184 | |||
185 | nBlock = (int) p >> 16; //block # of 64K bytes | 181 | nBlock = (int) p >> 16; //block # of 64K bytes |
186 | 182 | ||
187 | /* | 183 | /* |
@@ -258,11 +254,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf, | |||
258 | printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written); | 254 | printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written); |
259 | } | 255 | } |
260 | 256 | ||
261 | /* | ||
262 | * restore reg on exit | ||
263 | */ | ||
264 | leds_event(led_release); | ||
265 | |||
266 | mutex_unlock(&nwflash_mutex); | 257 | mutex_unlock(&nwflash_mutex); |
267 | 258 | ||
268 | return written; | 259 | return written; |
@@ -334,11 +325,6 @@ static int erase_block(int nBlock) | |||
334 | int temp, temp1; | 325 | int temp, temp1; |
335 | 326 | ||
336 | /* | 327 | /* |
337 | * orange LED == erase | ||
338 | */ | ||
339 | leds_event(led_amber_on); | ||
340 | |||
341 | /* | ||
342 | * reset footbridge to the correct offset 0 (...0..3) | 328 | * reset footbridge to the correct offset 0 (...0..3) |
343 | */ | 329 | */ |
344 | *CSR_ROMWRITEREG = 0; | 330 | *CSR_ROMWRITEREG = 0; |
@@ -446,12 +432,6 @@ static int write_block(unsigned long p, const char __user *buf, int count) | |||
446 | unsigned long timeout; | 432 | unsigned long timeout; |
447 | unsigned long timeout1; | 433 | unsigned long timeout1; |
448 | 434 | ||
449 | /* | ||
450 | * red LED == write | ||
451 | */ | ||
452 | leds_event(led_amber_off); | ||
453 | leds_event(led_red_on); | ||
454 | |||
455 | pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); | 435 | pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); |
456 | 436 | ||
457 | /* | 437 | /* |
@@ -558,17 +538,9 @@ static int write_block(unsigned long p, const char __user *buf, int count) | |||
558 | pWritePtr - FLASH_BASE); | 538 | pWritePtr - FLASH_BASE); |
559 | 539 | ||
560 | /* | 540 | /* |
561 | * no LED == waiting | ||
562 | */ | ||
563 | leds_event(led_amber_off); | ||
564 | /* | ||
565 | * wait couple ms | 541 | * wait couple ms |
566 | */ | 542 | */ |
567 | msleep(10); | 543 | msleep(10); |
568 | /* | ||
569 | * red LED == write | ||
570 | */ | ||
571 | leds_event(led_red_on); | ||
572 | 544 | ||
573 | goto WriteRetry; | 545 | goto WriteRetry; |
574 | } else { | 546 | } else { |
@@ -583,12 +555,6 @@ static int write_block(unsigned long p, const char __user *buf, int count) | |||
583 | } | 555 | } |
584 | } | 556 | } |
585 | 557 | ||
586 | /* | ||
587 | * green LED == read/verify | ||
588 | */ | ||
589 | leds_event(led_amber_off); | ||
590 | leds_event(led_green_on); | ||
591 | |||
592 | msleep(10); | 558 | msleep(10); |
593 | 559 | ||
594 | pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); | 560 | pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); |
@@ -617,9 +583,9 @@ static void kick_open(void) | |||
617 | * we want to write a bit pattern XXX1 to Xilinx to enable | 583 | * we want to write a bit pattern XXX1 to Xilinx to enable |
618 | * the write gate, which will be open for about the next 2ms. | 584 | * the write gate, which will be open for about the next 2ms. |
619 | */ | 585 | */ |
620 | spin_lock_irqsave(&nw_gpio_lock, flags); | 586 | raw_spin_lock_irqsave(&nw_gpio_lock, flags); |
621 | nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE); | 587 | nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE); |
622 | spin_unlock_irqrestore(&nw_gpio_lock, flags); | 588 | raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); |
623 | 589 | ||
624 | /* | 590 | /* |
625 | * let the ISA bus to catch on... | 591 | * let the ISA bus to catch on... |
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 0a484b4a1b02..21721d25e388 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c | |||
@@ -891,6 +891,14 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty) | |||
891 | int work = 0; | 891 | int work = 0; |
892 | struct mgsl_icount *icount = &info->icount; | 892 | struct mgsl_icount *icount = &info->icount; |
893 | 893 | ||
894 | if (!tty) { | ||
895 | /* tty is not available anymore */ | ||
896 | issue_command(info, CHA, CMD_RXRESET); | ||
897 | if (debug_level >= DEBUG_LEVEL_ISR) | ||
898 | printk("%s(%d):rx_ready_async(tty=NULL)\n",__FILE__,__LINE__); | ||
899 | return; | ||
900 | } | ||
901 | |||
894 | if (tcd) { | 902 | if (tcd) { |
895 | /* early termination, get FIFO count from RBCL register */ | 903 | /* early termination, get FIFO count from RBCL register */ |
896 | fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); | 904 | fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); |
@@ -980,7 +988,7 @@ static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty) | |||
980 | else | 988 | else |
981 | #endif | 989 | #endif |
982 | { | 990 | { |
983 | if (tty->stopped || tty->hw_stopped) { | 991 | if (tty && (tty->stopped || tty->hw_stopped)) { |
984 | tx_stop(info); | 992 | tx_stop(info); |
985 | return; | 993 | return; |
986 | } | 994 | } |
@@ -1000,7 +1008,7 @@ static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty) | |||
1000 | if (!info->tx_active) | 1008 | if (!info->tx_active) |
1001 | return; | 1009 | return; |
1002 | } else { | 1010 | } else { |
1003 | if (tty->stopped || tty->hw_stopped) { | 1011 | if (tty && (tty->stopped || tty->hw_stopped)) { |
1004 | tx_stop(info); | 1012 | tx_stop(info); |
1005 | return; | 1013 | return; |
1006 | } | 1014 | } |
@@ -1050,13 +1058,12 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) | |||
1050 | wake_up_interruptible(&info->status_event_wait_q); | 1058 | wake_up_interruptible(&info->status_event_wait_q); |
1051 | wake_up_interruptible(&info->event_wait_q); | 1059 | wake_up_interruptible(&info->event_wait_q); |
1052 | 1060 | ||
1053 | if (info->port.flags & ASYNC_CTS_FLOW) { | 1061 | if (tty && tty_port_cts_enabled(&info->port)) { |
1054 | if (tty->hw_stopped) { | 1062 | if (tty->hw_stopped) { |
1055 | if (info->serial_signals & SerialSignal_CTS) { | 1063 | if (info->serial_signals & SerialSignal_CTS) { |
1056 | if (debug_level >= DEBUG_LEVEL_ISR) | 1064 | if (debug_level >= DEBUG_LEVEL_ISR) |
1057 | printk("CTS tx start..."); | 1065 | printk("CTS tx start..."); |
1058 | if (tty) | 1066 | tty->hw_stopped = 0; |
1059 | tty->hw_stopped = 0; | ||
1060 | tx_start(info, tty); | 1067 | tx_start(info, tty); |
1061 | info->pending_bh |= BH_TRANSMIT; | 1068 | info->pending_bh |= BH_TRANSMIT; |
1062 | return; | 1069 | return; |
@@ -1065,8 +1072,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) | |||
1065 | if (!(info->serial_signals & SerialSignal_CTS)) { | 1072 | if (!(info->serial_signals & SerialSignal_CTS)) { |
1066 | if (debug_level >= DEBUG_LEVEL_ISR) | 1073 | if (debug_level >= DEBUG_LEVEL_ISR) |
1067 | printk("CTS tx stop..."); | 1074 | printk("CTS tx stop..."); |
1068 | if (tty) | 1075 | tty->hw_stopped = 1; |
1069 | tty->hw_stopped = 1; | ||
1070 | tx_stop(info); | 1076 | tx_stop(info); |
1071 | } | 1077 | } |
1072 | } | 1078 | } |
@@ -1344,7 +1350,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) | |||
1344 | /* TODO:disable interrupts instead of reset to preserve signal states */ | 1350 | /* TODO:disable interrupts instead of reset to preserve signal states */ |
1345 | reset_device(info); | 1351 | reset_device(info); |
1346 | 1352 | ||
1347 | if (!tty || tty->termios->c_cflag & HUPCL) { | 1353 | if (!tty || tty->termios.c_cflag & HUPCL) { |
1348 | info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); | 1354 | info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); |
1349 | set_signals(info); | 1355 | set_signals(info); |
1350 | } | 1356 | } |
@@ -1385,7 +1391,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) | |||
1385 | port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); | 1391 | port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); |
1386 | get_signals(info); | 1392 | get_signals(info); |
1387 | 1393 | ||
1388 | if (info->netcount || (tty && (tty->termios->c_cflag & CREAD))) | 1394 | if (info->netcount || (tty && (tty->termios.c_cflag & CREAD))) |
1389 | rx_start(info); | 1395 | rx_start(info); |
1390 | 1396 | ||
1391 | spin_unlock_irqrestore(&info->lock,flags); | 1397 | spin_unlock_irqrestore(&info->lock,flags); |
@@ -1398,14 +1404,14 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) | |||
1398 | unsigned cflag; | 1404 | unsigned cflag; |
1399 | int bits_per_char; | 1405 | int bits_per_char; |
1400 | 1406 | ||
1401 | if (!tty || !tty->termios) | 1407 | if (!tty) |
1402 | return; | 1408 | return; |
1403 | 1409 | ||
1404 | if (debug_level >= DEBUG_LEVEL_INFO) | 1410 | if (debug_level >= DEBUG_LEVEL_INFO) |
1405 | printk("%s(%d):mgslpc_change_params(%s)\n", | 1411 | printk("%s(%d):mgslpc_change_params(%s)\n", |
1406 | __FILE__,__LINE__, info->device_name ); | 1412 | __FILE__,__LINE__, info->device_name ); |
1407 | 1413 | ||
1408 | cflag = tty->termios->c_cflag; | 1414 | cflag = tty->termios.c_cflag; |
1409 | 1415 | ||
1410 | /* if B0 rate (hangup) specified then negate DTR and RTS */ | 1416 | /* if B0 rate (hangup) specified then negate DTR and RTS */ |
1411 | /* otherwise assert DTR and RTS */ | 1417 | /* otherwise assert DTR and RTS */ |
@@ -1728,7 +1734,7 @@ static void mgslpc_throttle(struct tty_struct * tty) | |||
1728 | if (I_IXOFF(tty)) | 1734 | if (I_IXOFF(tty)) |
1729 | mgslpc_send_xchar(tty, STOP_CHAR(tty)); | 1735 | mgslpc_send_xchar(tty, STOP_CHAR(tty)); |
1730 | 1736 | ||
1731 | if (tty->termios->c_cflag & CRTSCTS) { | 1737 | if (tty->termios.c_cflag & CRTSCTS) { |
1732 | spin_lock_irqsave(&info->lock,flags); | 1738 | spin_lock_irqsave(&info->lock,flags); |
1733 | info->serial_signals &= ~SerialSignal_RTS; | 1739 | info->serial_signals &= ~SerialSignal_RTS; |
1734 | set_signals(info); | 1740 | set_signals(info); |
@@ -1757,7 +1763,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty) | |||
1757 | mgslpc_send_xchar(tty, START_CHAR(tty)); | 1763 | mgslpc_send_xchar(tty, START_CHAR(tty)); |
1758 | } | 1764 | } |
1759 | 1765 | ||
1760 | if (tty->termios->c_cflag & CRTSCTS) { | 1766 | if (tty->termios.c_cflag & CRTSCTS) { |
1761 | spin_lock_irqsave(&info->lock,flags); | 1767 | spin_lock_irqsave(&info->lock,flags); |
1762 | info->serial_signals |= SerialSignal_RTS; | 1768 | info->serial_signals |= SerialSignal_RTS; |
1763 | set_signals(info); | 1769 | set_signals(info); |
@@ -2293,8 +2299,8 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term | |||
2293 | tty->driver->name ); | 2299 | tty->driver->name ); |
2294 | 2300 | ||
2295 | /* just return if nothing has changed */ | 2301 | /* just return if nothing has changed */ |
2296 | if ((tty->termios->c_cflag == old_termios->c_cflag) | 2302 | if ((tty->termios.c_cflag == old_termios->c_cflag) |
2297 | && (RELEVANT_IFLAG(tty->termios->c_iflag) | 2303 | && (RELEVANT_IFLAG(tty->termios.c_iflag) |
2298 | == RELEVANT_IFLAG(old_termios->c_iflag))) | 2304 | == RELEVANT_IFLAG(old_termios->c_iflag))) |
2299 | return; | 2305 | return; |
2300 | 2306 | ||
@@ -2302,7 +2308,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term | |||
2302 | 2308 | ||
2303 | /* Handle transition to B0 status */ | 2309 | /* Handle transition to B0 status */ |
2304 | if (old_termios->c_cflag & CBAUD && | 2310 | if (old_termios->c_cflag & CBAUD && |
2305 | !(tty->termios->c_cflag & CBAUD)) { | 2311 | !(tty->termios.c_cflag & CBAUD)) { |
2306 | info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | 2312 | info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); |
2307 | spin_lock_irqsave(&info->lock,flags); | 2313 | spin_lock_irqsave(&info->lock,flags); |
2308 | set_signals(info); | 2314 | set_signals(info); |
@@ -2311,9 +2317,9 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term | |||
2311 | 2317 | ||
2312 | /* Handle transition away from B0 status */ | 2318 | /* Handle transition away from B0 status */ |
2313 | if (!(old_termios->c_cflag & CBAUD) && | 2319 | if (!(old_termios->c_cflag & CBAUD) && |
2314 | tty->termios->c_cflag & CBAUD) { | 2320 | tty->termios.c_cflag & CBAUD) { |
2315 | info->serial_signals |= SerialSignal_DTR; | 2321 | info->serial_signals |= SerialSignal_DTR; |
2316 | if (!(tty->termios->c_cflag & CRTSCTS) || | 2322 | if (!(tty->termios.c_cflag & CRTSCTS) || |
2317 | !test_bit(TTY_THROTTLED, &tty->flags)) { | 2323 | !test_bit(TTY_THROTTLED, &tty->flags)) { |
2318 | info->serial_signals |= SerialSignal_RTS; | 2324 | info->serial_signals |= SerialSignal_RTS; |
2319 | } | 2325 | } |
@@ -2324,7 +2330,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term | |||
2324 | 2330 | ||
2325 | /* Handle turning off CRTSCTS */ | 2331 | /* Handle turning off CRTSCTS */ |
2326 | if (old_termios->c_cflag & CRTSCTS && | 2332 | if (old_termios->c_cflag & CRTSCTS && |
2327 | !(tty->termios->c_cflag & CRTSCTS)) { | 2333 | !(tty->termios.c_cflag & CRTSCTS)) { |
2328 | tty->hw_stopped = 0; | 2334 | tty->hw_stopped = 0; |
2329 | tx_release(tty); | 2335 | tx_release(tty); |
2330 | } | 2336 | } |
@@ -2731,6 +2737,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info) | |||
2731 | #if SYNCLINK_GENERIC_HDLC | 2737 | #if SYNCLINK_GENERIC_HDLC |
2732 | hdlcdev_init(info); | 2738 | hdlcdev_init(info); |
2733 | #endif | 2739 | #endif |
2740 | tty_port_register_device(&info->port, serial_driver, info->line, | ||
2741 | &info->p_dev->dev); | ||
2734 | } | 2742 | } |
2735 | 2743 | ||
2736 | static void mgslpc_remove_device(MGSLPC_INFO *remove_info) | 2744 | static void mgslpc_remove_device(MGSLPC_INFO *remove_info) |
@@ -2744,6 +2752,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info) | |||
2744 | last->next_device = info->next_device; | 2752 | last->next_device = info->next_device; |
2745 | else | 2753 | else |
2746 | mgslpc_device_list = info->next_device; | 2754 | mgslpc_device_list = info->next_device; |
2755 | tty_unregister_device(serial_driver, info->line); | ||
2747 | #if SYNCLINK_GENERIC_HDLC | 2756 | #if SYNCLINK_GENERIC_HDLC |
2748 | hdlcdev_exit(info); | 2757 | hdlcdev_exit(info); |
2749 | #endif | 2758 | #endif |
@@ -2798,77 +2807,63 @@ static const struct tty_operations mgslpc_ops = { | |||
2798 | .proc_fops = &mgslpc_proc_fops, | 2807 | .proc_fops = &mgslpc_proc_fops, |
2799 | }; | 2808 | }; |
2800 | 2809 | ||
2801 | static void synclink_cs_cleanup(void) | 2810 | static int __init synclink_cs_init(void) |
2802 | { | 2811 | { |
2803 | int rc; | 2812 | int rc; |
2804 | 2813 | ||
2805 | while(mgslpc_device_list) | 2814 | if (break_on_load) { |
2806 | mgslpc_remove_device(mgslpc_device_list); | 2815 | mgslpc_get_text_ptr(); |
2807 | 2816 | BREAKPOINT(); | |
2808 | if (serial_driver) { | ||
2809 | if ((rc = tty_unregister_driver(serial_driver))) | ||
2810 | printk("%s(%d) failed to unregister tty driver err=%d\n", | ||
2811 | __FILE__,__LINE__,rc); | ||
2812 | put_tty_driver(serial_driver); | ||
2813 | } | 2817 | } |
2814 | 2818 | ||
2815 | pcmcia_unregister_driver(&mgslpc_driver); | 2819 | serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT, |
2816 | } | 2820 | TTY_DRIVER_REAL_RAW | |
2817 | 2821 | TTY_DRIVER_DYNAMIC_DEV); | |
2818 | static int __init synclink_cs_init(void) | 2822 | if (IS_ERR(serial_driver)) { |
2819 | { | 2823 | rc = PTR_ERR(serial_driver); |
2820 | int rc; | 2824 | goto err; |
2821 | 2825 | } | |
2822 | if (break_on_load) { | ||
2823 | mgslpc_get_text_ptr(); | ||
2824 | BREAKPOINT(); | ||
2825 | } | ||
2826 | |||
2827 | if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0) | ||
2828 | return rc; | ||
2829 | |||
2830 | serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT); | ||
2831 | if (!serial_driver) { | ||
2832 | rc = -ENOMEM; | ||
2833 | goto error; | ||
2834 | } | ||
2835 | 2826 | ||
2836 | /* Initialize the tty_driver structure */ | 2827 | /* Initialize the tty_driver structure */ |
2837 | 2828 | serial_driver->driver_name = "synclink_cs"; | |
2838 | serial_driver->driver_name = "synclink_cs"; | 2829 | serial_driver->name = "ttySLP"; |
2839 | serial_driver->name = "ttySLP"; | 2830 | serial_driver->major = ttymajor; |
2840 | serial_driver->major = ttymajor; | 2831 | serial_driver->minor_start = 64; |
2841 | serial_driver->minor_start = 64; | 2832 | serial_driver->type = TTY_DRIVER_TYPE_SERIAL; |
2842 | serial_driver->type = TTY_DRIVER_TYPE_SERIAL; | 2833 | serial_driver->subtype = SERIAL_TYPE_NORMAL; |
2843 | serial_driver->subtype = SERIAL_TYPE_NORMAL; | 2834 | serial_driver->init_termios = tty_std_termios; |
2844 | serial_driver->init_termios = tty_std_termios; | 2835 | serial_driver->init_termios.c_cflag = |
2845 | serial_driver->init_termios.c_cflag = | 2836 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; |
2846 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | 2837 | tty_set_operations(serial_driver, &mgslpc_ops); |
2847 | serial_driver->flags = TTY_DRIVER_REAL_RAW; | 2838 | |
2848 | tty_set_operations(serial_driver, &mgslpc_ops); | 2839 | rc = tty_register_driver(serial_driver); |
2849 | 2840 | if (rc < 0) { | |
2850 | if ((rc = tty_register_driver(serial_driver)) < 0) { | 2841 | printk(KERN_ERR "%s(%d):Couldn't register serial driver\n", |
2851 | printk("%s(%d):Couldn't register serial driver\n", | 2842 | __FILE__, __LINE__); |
2852 | __FILE__,__LINE__); | 2843 | goto err_put_tty; |
2853 | put_tty_driver(serial_driver); | 2844 | } |
2854 | serial_driver = NULL; | ||
2855 | goto error; | ||
2856 | } | ||
2857 | 2845 | ||
2858 | printk("%s %s, tty major#%d\n", | 2846 | rc = pcmcia_register_driver(&mgslpc_driver); |
2859 | driver_name, driver_version, | 2847 | if (rc < 0) |
2860 | serial_driver->major); | 2848 | goto err_unreg_tty; |
2861 | 2849 | ||
2862 | return 0; | 2850 | printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version, |
2851 | serial_driver->major); | ||
2863 | 2852 | ||
2864 | error: | 2853 | return 0; |
2865 | synclink_cs_cleanup(); | 2854 | err_unreg_tty: |
2866 | return rc; | 2855 | tty_unregister_driver(serial_driver); |
2856 | err_put_tty: | ||
2857 | put_tty_driver(serial_driver); | ||
2858 | err: | ||
2859 | return rc; | ||
2867 | } | 2860 | } |
2868 | 2861 | ||
2869 | static void __exit synclink_cs_exit(void) | 2862 | static void __exit synclink_cs_exit(void) |
2870 | { | 2863 | { |
2871 | synclink_cs_cleanup(); | 2864 | pcmcia_unregister_driver(&mgslpc_driver); |
2865 | tty_unregister_driver(serial_driver); | ||
2866 | put_tty_driver(serial_driver); | ||
2872 | } | 2867 | } |
2873 | 2868 | ||
2874 | module_init(synclink_cs_init); | 2869 | module_init(synclink_cs_init); |
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 99c51b4b07e7..1cd49241e60e 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c | |||
@@ -779,7 +779,8 @@ static int __init ppdev_init (void) | |||
779 | err = PTR_ERR(ppdev_class); | 779 | err = PTR_ERR(ppdev_class); |
780 | goto out_chrdev; | 780 | goto out_chrdev; |
781 | } | 781 | } |
782 | if (parport_register_driver(&pp_driver)) { | 782 | err = parport_register_driver(&pp_driver); |
783 | if (err < 0) { | ||
783 | printk (KERN_WARNING CHRDEV ": unable to register with parport\n"); | 784 | printk (KERN_WARNING CHRDEV ": unable to register with parport\n"); |
784 | goto out_class; | 785 | goto out_class; |
785 | } | 786 | } |
diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 54a3a6d09819..0bb207eaef2f 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c | |||
@@ -285,7 +285,7 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd, | |||
285 | 285 | ||
286 | static const struct file_operations raw_fops = { | 286 | static const struct file_operations raw_fops = { |
287 | .read = do_sync_read, | 287 | .read = do_sync_read, |
288 | .aio_read = generic_file_aio_read, | 288 | .aio_read = blkdev_aio_read, |
289 | .write = do_sync_write, | 289 | .write = do_sync_write, |
290 | .aio_write = blkdev_aio_write, | 290 | .aio_write = blkdev_aio_write, |
291 | .fsync = blkdev_fsync, | 291 | .fsync = blkdev_fsync, |
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index af9437488b6c..91470fdbab2a 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c | |||
@@ -411,7 +411,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) | |||
411 | case RTC_IRQP_READ: | 411 | case RTC_IRQP_READ: |
412 | case RTC_IRQP_SET: | 412 | case RTC_IRQP_SET: |
413 | return -EINVAL; | 413 | return -EINVAL; |
414 | }; | 414 | } |
415 | } | 415 | } |
416 | #endif | 416 | #endif |
417 | 417 | ||
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index f87780502b41..9b4f0116ff21 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c | |||
@@ -1433,7 +1433,7 @@ static int __devexit sonypi_remove(struct platform_device *dev) | |||
1433 | sonypi_disable(); | 1433 | sonypi_disable(); |
1434 | 1434 | ||
1435 | synchronize_irq(sonypi_device.irq); | 1435 | synchronize_irq(sonypi_device.irq); |
1436 | flush_work_sync(&sonypi_device.input_work); | 1436 | flush_work(&sonypi_device.input_work); |
1437 | 1437 | ||
1438 | if (useinput) { | 1438 | if (useinput) { |
1439 | input_unregister_device(sonypi_device.input_key_dev); | 1439 | input_unregister_device(sonypi_device.input_key_dev); |
@@ -1456,7 +1456,7 @@ static int __devexit sonypi_remove(struct platform_device *dev) | |||
1456 | return 0; | 1456 | return 0; |
1457 | } | 1457 | } |
1458 | 1458 | ||
1459 | #ifdef CONFIG_PM | 1459 | #ifdef CONFIG_PM_SLEEP |
1460 | static int old_camera_power; | 1460 | static int old_camera_power; |
1461 | 1461 | ||
1462 | static int sonypi_suspend(struct device *dev) | 1462 | static int sonypi_suspend(struct device *dev) |
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index ce29e7cce528..e95e0ab0bd87 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c | |||
@@ -784,8 +784,10 @@ static int __init tlclk_init(void) | |||
784 | } | 784 | } |
785 | tlclk_major = ret; | 785 | tlclk_major = ret; |
786 | alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL); | 786 | alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL); |
787 | if (!alarm_events) | 787 | if (!alarm_events) { |
788 | ret = -ENOMEM; | ||
788 | goto out1; | 789 | goto out1; |
790 | } | ||
789 | 791 | ||
790 | /* Read telecom clock IRQ number (Set by BIOS) */ | 792 | /* Read telecom clock IRQ number (Set by BIOS) */ |
791 | if (!request_region(TLCLK_BASE, 8, "telco_clock")) { | 793 | if (!request_region(TLCLK_BASE, 8, "telco_clock")) { |
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index a048199ce866..915875e431d2 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig | |||
@@ -33,6 +33,17 @@ config TCG_TIS | |||
33 | from within Linux. To compile this driver as a module, choose | 33 | from within Linux. To compile this driver as a module, choose |
34 | M here; the module will be called tpm_tis. | 34 | M here; the module will be called tpm_tis. |
35 | 35 | ||
36 | config TCG_TIS_I2C_INFINEON | ||
37 | tristate "TPM Interface Specification 1.2 Interface (I2C - Infineon)" | ||
38 | depends on I2C | ||
39 | ---help--- | ||
40 | If you have a TPM security chip that is compliant with the | ||
41 | TCG TIS 1.2 TPM specification and Infineon's I2C Protocol Stack | ||
42 | Specification 0.20 say Yes and it will be accessible from within | ||
43 | Linux. | ||
44 | To compile this driver as a module, choose M here; the module | ||
45 | will be called tpm_tis_i2c_infineon. | ||
46 | |||
36 | config TCG_NSC | 47 | config TCG_NSC |
37 | tristate "National Semiconductor TPM Interface" | 48 | tristate "National Semiconductor TPM Interface" |
38 | depends on X86 | 49 | depends on X86 |
@@ -62,4 +73,12 @@ config TCG_INFINEON | |||
62 | Further information on this driver and the supported hardware | 73 | Further information on this driver and the supported hardware |
63 | can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ | 74 | can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ |
64 | 75 | ||
76 | config TCG_IBMVTPM | ||
77 | tristate "IBM VTPM Interface" | ||
78 | depends on PPC64 | ||
79 | ---help--- | ||
80 | If you have IBM virtual TPM (VTPM) support say Yes and it | ||
81 | will be accessible from within Linux. To compile this driver | ||
82 | as a module, choose M here; the module will be called tpm_ibmvtpm. | ||
83 | |||
65 | endif # TCG_TPM | 84 | endif # TCG_TPM |
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index ea3a1e02a824..5b3fc8bc6c13 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile | |||
@@ -4,8 +4,16 @@ | |||
4 | obj-$(CONFIG_TCG_TPM) += tpm.o | 4 | obj-$(CONFIG_TCG_TPM) += tpm.o |
5 | ifdef CONFIG_ACPI | 5 | ifdef CONFIG_ACPI |
6 | obj-$(CONFIG_TCG_TPM) += tpm_bios.o | 6 | obj-$(CONFIG_TCG_TPM) += tpm_bios.o |
7 | tpm_bios-objs += tpm_eventlog.o tpm_acpi.o tpm_ppi.o | ||
8 | else | ||
9 | ifdef CONFIG_TCG_IBMVTPM | ||
10 | obj-$(CONFIG_TCG_TPM) += tpm_bios.o | ||
11 | tpm_bios-objs += tpm_eventlog.o tpm_of.o | ||
12 | endif | ||
7 | endif | 13 | endif |
8 | obj-$(CONFIG_TCG_TIS) += tpm_tis.o | 14 | obj-$(CONFIG_TCG_TIS) += tpm_tis.o |
15 | obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o | ||
9 | obj-$(CONFIG_TCG_NSC) += tpm_nsc.o | 16 | obj-$(CONFIG_TCG_NSC) += tpm_nsc.o |
10 | obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o | 17 | obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o |
11 | obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o | 18 | obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o |
19 | obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o | ||
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 817f0ee202b6..93211df52aab 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -30,12 +30,7 @@ | |||
30 | #include <linux/freezer.h> | 30 | #include <linux/freezer.h> |
31 | 31 | ||
32 | #include "tpm.h" | 32 | #include "tpm.h" |
33 | 33 | #include "tpm_eventlog.h" | |
34 | enum tpm_const { | ||
35 | TPM_MINOR = 224, /* officially assigned */ | ||
36 | TPM_BUFSIZE = 4096, | ||
37 | TPM_NUM_DEVICES = 256, | ||
38 | }; | ||
39 | 34 | ||
40 | enum tpm_duration { | 35 | enum tpm_duration { |
41 | TPM_SHORT = 0, | 36 | TPM_SHORT = 0, |
@@ -482,6 +477,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, | |||
482 | #define TPM_INTERNAL_RESULT_SIZE 200 | 477 | #define TPM_INTERNAL_RESULT_SIZE 200 |
483 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) | 478 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) |
484 | #define TPM_ORD_GET_CAP cpu_to_be32(101) | 479 | #define TPM_ORD_GET_CAP cpu_to_be32(101) |
480 | #define TPM_ORD_GET_RANDOM cpu_to_be32(70) | ||
485 | 481 | ||
486 | static const struct tpm_input_header tpm_getcap_header = { | 482 | static const struct tpm_input_header tpm_getcap_header = { |
487 | .tag = TPM_TAG_RQU_COMMAND, | 483 | .tag = TPM_TAG_RQU_COMMAND, |
@@ -919,7 +915,7 @@ EXPORT_SYMBOL_GPL(tpm_show_pcrs); | |||
919 | 915 | ||
920 | #define READ_PUBEK_RESULT_SIZE 314 | 916 | #define READ_PUBEK_RESULT_SIZE 314 |
921 | #define TPM_ORD_READPUBEK cpu_to_be32(124) | 917 | #define TPM_ORD_READPUBEK cpu_to_be32(124) |
922 | struct tpm_input_header tpm_readpubek_header = { | 918 | static struct tpm_input_header tpm_readpubek_header = { |
923 | .tag = TPM_TAG_RQU_COMMAND, | 919 | .tag = TPM_TAG_RQU_COMMAND, |
924 | .length = cpu_to_be32(30), | 920 | .length = cpu_to_be32(30), |
925 | .ordinal = TPM_ORD_READPUBEK | 921 | .ordinal = TPM_ORD_READPUBEK |
@@ -1172,10 +1168,10 @@ int tpm_release(struct inode *inode, struct file *file) | |||
1172 | struct tpm_chip *chip = file->private_data; | 1168 | struct tpm_chip *chip = file->private_data; |
1173 | 1169 | ||
1174 | del_singleshot_timer_sync(&chip->user_read_timer); | 1170 | del_singleshot_timer_sync(&chip->user_read_timer); |
1175 | flush_work_sync(&chip->work); | 1171 | flush_work(&chip->work); |
1176 | file->private_data = NULL; | 1172 | file->private_data = NULL; |
1177 | atomic_set(&chip->data_pending, 0); | 1173 | atomic_set(&chip->data_pending, 0); |
1178 | kfree(chip->data_buffer); | 1174 | kzfree(chip->data_buffer); |
1179 | clear_bit(0, &chip->is_open); | 1175 | clear_bit(0, &chip->is_open); |
1180 | put_device(chip->dev); | 1176 | put_device(chip->dev); |
1181 | return 0; | 1177 | return 0; |
@@ -1186,17 +1182,20 @@ ssize_t tpm_write(struct file *file, const char __user *buf, | |||
1186 | size_t size, loff_t *off) | 1182 | size_t size, loff_t *off) |
1187 | { | 1183 | { |
1188 | struct tpm_chip *chip = file->private_data; | 1184 | struct tpm_chip *chip = file->private_data; |
1189 | size_t in_size = size, out_size; | 1185 | size_t in_size = size; |
1186 | ssize_t out_size; | ||
1190 | 1187 | ||
1191 | /* cannot perform a write until the read has cleared | 1188 | /* cannot perform a write until the read has cleared |
1192 | either via tpm_read or a user_read_timer timeout */ | 1189 | either via tpm_read or a user_read_timer timeout. |
1193 | while (atomic_read(&chip->data_pending) != 0) | 1190 | This also prevents splitted buffered writes from blocking here. |
1194 | msleep(TPM_TIMEOUT); | 1191 | */ |
1195 | 1192 | if (atomic_read(&chip->data_pending) != 0) | |
1196 | mutex_lock(&chip->buffer_mutex); | 1193 | return -EBUSY; |
1197 | 1194 | ||
1198 | if (in_size > TPM_BUFSIZE) | 1195 | if (in_size > TPM_BUFSIZE) |
1199 | in_size = TPM_BUFSIZE; | 1196 | return -E2BIG; |
1197 | |||
1198 | mutex_lock(&chip->buffer_mutex); | ||
1200 | 1199 | ||
1201 | if (copy_from_user | 1200 | if (copy_from_user |
1202 | (chip->data_buffer, (void __user *) buf, in_size)) { | 1201 | (chip->data_buffer, (void __user *) buf, in_size)) { |
@@ -1206,6 +1205,10 @@ ssize_t tpm_write(struct file *file, const char __user *buf, | |||
1206 | 1205 | ||
1207 | /* atomic tpm command send and result receive */ | 1206 | /* atomic tpm command send and result receive */ |
1208 | out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); | 1207 | out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); |
1208 | if (out_size < 0) { | ||
1209 | mutex_unlock(&chip->buffer_mutex); | ||
1210 | return out_size; | ||
1211 | } | ||
1209 | 1212 | ||
1210 | atomic_set(&chip->data_pending, out_size); | 1213 | atomic_set(&chip->data_pending, out_size); |
1211 | mutex_unlock(&chip->buffer_mutex); | 1214 | mutex_unlock(&chip->buffer_mutex); |
@@ -1225,9 +1228,8 @@ ssize_t tpm_read(struct file *file, char __user *buf, | |||
1225 | int rc; | 1228 | int rc; |
1226 | 1229 | ||
1227 | del_singleshot_timer_sync(&chip->user_read_timer); | 1230 | del_singleshot_timer_sync(&chip->user_read_timer); |
1228 | flush_work_sync(&chip->work); | 1231 | flush_work(&chip->work); |
1229 | ret_size = atomic_read(&chip->data_pending); | 1232 | ret_size = atomic_read(&chip->data_pending); |
1230 | atomic_set(&chip->data_pending, 0); | ||
1231 | if (ret_size > 0) { /* relay data */ | 1233 | if (ret_size > 0) { /* relay data */ |
1232 | ssize_t orig_ret_size = ret_size; | 1234 | ssize_t orig_ret_size = ret_size; |
1233 | if (size < ret_size) | 1235 | if (size < ret_size) |
@@ -1242,6 +1244,8 @@ ssize_t tpm_read(struct file *file, char __user *buf, | |||
1242 | mutex_unlock(&chip->buffer_mutex); | 1244 | mutex_unlock(&chip->buffer_mutex); |
1243 | } | 1245 | } |
1244 | 1246 | ||
1247 | atomic_set(&chip->data_pending, 0); | ||
1248 | |||
1245 | return ret_size; | 1249 | return ret_size; |
1246 | } | 1250 | } |
1247 | EXPORT_SYMBOL_GPL(tpm_read); | 1251 | EXPORT_SYMBOL_GPL(tpm_read); |
@@ -1262,6 +1266,7 @@ void tpm_remove_hardware(struct device *dev) | |||
1262 | 1266 | ||
1263 | misc_deregister(&chip->vendor.miscdev); | 1267 | misc_deregister(&chip->vendor.miscdev); |
1264 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); | 1268 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); |
1269 | tpm_remove_ppi(&dev->kobj); | ||
1265 | tpm_bios_log_teardown(chip->bios_dir); | 1270 | tpm_bios_log_teardown(chip->bios_dir); |
1266 | 1271 | ||
1267 | /* write it this way to be explicit (chip->dev == dev) */ | 1272 | /* write it this way to be explicit (chip->dev == dev) */ |
@@ -1326,6 +1331,58 @@ int tpm_pm_resume(struct device *dev) | |||
1326 | } | 1331 | } |
1327 | EXPORT_SYMBOL_GPL(tpm_pm_resume); | 1332 | EXPORT_SYMBOL_GPL(tpm_pm_resume); |
1328 | 1333 | ||
1334 | #define TPM_GETRANDOM_RESULT_SIZE 18 | ||
1335 | static struct tpm_input_header tpm_getrandom_header = { | ||
1336 | .tag = TPM_TAG_RQU_COMMAND, | ||
1337 | .length = cpu_to_be32(14), | ||
1338 | .ordinal = TPM_ORD_GET_RANDOM | ||
1339 | }; | ||
1340 | |||
1341 | /** | ||
1342 | * tpm_get_random() - Get random bytes from the tpm's RNG | ||
1343 | * @chip_num: A specific chip number for the request or TPM_ANY_NUM | ||
1344 | * @out: destination buffer for the random bytes | ||
1345 | * @max: the max number of bytes to write to @out | ||
1346 | * | ||
1347 | * Returns < 0 on error and the number of bytes read on success | ||
1348 | */ | ||
1349 | int tpm_get_random(u32 chip_num, u8 *out, size_t max) | ||
1350 | { | ||
1351 | struct tpm_chip *chip; | ||
1352 | struct tpm_cmd_t tpm_cmd; | ||
1353 | u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); | ||
1354 | int err, total = 0, retries = 5; | ||
1355 | u8 *dest = out; | ||
1356 | |||
1357 | chip = tpm_chip_find_get(chip_num); | ||
1358 | if (chip == NULL) | ||
1359 | return -ENODEV; | ||
1360 | |||
1361 | if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) | ||
1362 | return -EINVAL; | ||
1363 | |||
1364 | do { | ||
1365 | tpm_cmd.header.in = tpm_getrandom_header; | ||
1366 | tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); | ||
1367 | |||
1368 | err = transmit_cmd(chip, &tpm_cmd, | ||
1369 | TPM_GETRANDOM_RESULT_SIZE + num_bytes, | ||
1370 | "attempting get random"); | ||
1371 | if (err) | ||
1372 | break; | ||
1373 | |||
1374 | recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); | ||
1375 | memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); | ||
1376 | |||
1377 | dest += recd; | ||
1378 | total += recd; | ||
1379 | num_bytes -= recd; | ||
1380 | } while (retries-- && total < max); | ||
1381 | |||
1382 | return total ? total : -EIO; | ||
1383 | } | ||
1384 | EXPORT_SYMBOL_GPL(tpm_get_random); | ||
1385 | |||
1329 | /* In case vendor provided release function, call it too.*/ | 1386 | /* In case vendor provided release function, call it too.*/ |
1330 | 1387 | ||
1331 | void tpm_dev_vendor_release(struct tpm_chip *chip) | 1388 | void tpm_dev_vendor_release(struct tpm_chip *chip) |
@@ -1346,7 +1403,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); | |||
1346 | * Once all references to platform device are down to 0, | 1403 | * Once all references to platform device are down to 0, |
1347 | * release all allocated structures. | 1404 | * release all allocated structures. |
1348 | */ | 1405 | */ |
1349 | void tpm_dev_release(struct device *dev) | 1406 | static void tpm_dev_release(struct device *dev) |
1350 | { | 1407 | { |
1351 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1408 | struct tpm_chip *chip = dev_get_drvdata(dev); |
1352 | 1409 | ||
@@ -1427,6 +1484,11 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
1427 | goto put_device; | 1484 | goto put_device; |
1428 | } | 1485 | } |
1429 | 1486 | ||
1487 | if (tpm_add_ppi(&dev->kobj)) { | ||
1488 | misc_deregister(&chip->vendor.miscdev); | ||
1489 | goto put_device; | ||
1490 | } | ||
1491 | |||
1430 | chip->bios_dir = tpm_bios_log_setup(devname); | 1492 | chip->bios_dir = tpm_bios_log_setup(devname); |
1431 | 1493 | ||
1432 | /* Make chip available */ | 1494 | /* Make chip available */ |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 917f727e6740..8ef7649a50aa 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -28,6 +28,12 @@ | |||
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/tpm.h> | 29 | #include <linux/tpm.h> |
30 | 30 | ||
31 | enum tpm_const { | ||
32 | TPM_MINOR = 224, /* officially assigned */ | ||
33 | TPM_BUFSIZE = 4096, | ||
34 | TPM_NUM_DEVICES = 256, | ||
35 | }; | ||
36 | |||
31 | enum tpm_timeout { | 37 | enum tpm_timeout { |
32 | TPM_TIMEOUT = 5, /* msecs */ | 38 | TPM_TIMEOUT = 5, /* msecs */ |
33 | }; | 39 | }; |
@@ -94,6 +100,7 @@ struct tpm_vendor_specific { | |||
94 | bool timeout_adjusted; | 100 | bool timeout_adjusted; |
95 | unsigned long duration[3]; /* jiffies */ | 101 | unsigned long duration[3]; /* jiffies */ |
96 | bool duration_adjusted; | 102 | bool duration_adjusted; |
103 | void *data; | ||
97 | 104 | ||
98 | wait_queue_head_t read_queue; | 105 | wait_queue_head_t read_queue; |
99 | wait_queue_head_t int_queue; | 106 | wait_queue_head_t int_queue; |
@@ -269,6 +276,21 @@ struct tpm_pcrextend_in { | |||
269 | u8 hash[TPM_DIGEST_SIZE]; | 276 | u8 hash[TPM_DIGEST_SIZE]; |
270 | }__attribute__((packed)); | 277 | }__attribute__((packed)); |
271 | 278 | ||
279 | /* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18 | ||
280 | * bytes, but 128 is still a relatively large number of random bytes and | ||
281 | * anything much bigger causes users of struct tpm_cmd_t to start getting | ||
282 | * compiler warnings about stack frame size. */ | ||
283 | #define TPM_MAX_RNG_DATA 128 | ||
284 | |||
285 | struct tpm_getrandom_out { | ||
286 | __be32 rng_data_len; | ||
287 | u8 rng_data[TPM_MAX_RNG_DATA]; | ||
288 | }__attribute__((packed)); | ||
289 | |||
290 | struct tpm_getrandom_in { | ||
291 | __be32 num_bytes; | ||
292 | }__attribute__((packed)); | ||
293 | |||
272 | typedef union { | 294 | typedef union { |
273 | struct tpm_getcap_params_out getcap_out; | 295 | struct tpm_getcap_params_out getcap_out; |
274 | struct tpm_readpubek_params_out readpubek_out; | 296 | struct tpm_readpubek_params_out readpubek_out; |
@@ -277,6 +299,8 @@ typedef union { | |||
277 | struct tpm_pcrread_in pcrread_in; | 299 | struct tpm_pcrread_in pcrread_in; |
278 | struct tpm_pcrread_out pcrread_out; | 300 | struct tpm_pcrread_out pcrread_out; |
279 | struct tpm_pcrextend_in pcrextend_in; | 301 | struct tpm_pcrextend_in pcrextend_in; |
302 | struct tpm_getrandom_in getrandom_in; | ||
303 | struct tpm_getrandom_out getrandom_out; | ||
280 | } tpm_cmd_params; | 304 | } tpm_cmd_params; |
281 | 305 | ||
282 | struct tpm_cmd_t { | 306 | struct tpm_cmd_t { |
@@ -303,15 +327,17 @@ extern int tpm_pm_suspend(struct device *); | |||
303 | extern int tpm_pm_resume(struct device *); | 327 | extern int tpm_pm_resume(struct device *); |
304 | extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, | 328 | extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, |
305 | wait_queue_head_t *); | 329 | wait_queue_head_t *); |
330 | |||
306 | #ifdef CONFIG_ACPI | 331 | #ifdef CONFIG_ACPI |
307 | extern struct dentry ** tpm_bios_log_setup(char *); | 332 | extern int tpm_add_ppi(struct kobject *); |
308 | extern void tpm_bios_log_teardown(struct dentry **); | 333 | extern void tpm_remove_ppi(struct kobject *); |
309 | #else | 334 | #else |
310 | static inline struct dentry ** tpm_bios_log_setup(char *name) | 335 | static inline int tpm_add_ppi(struct kobject *parent) |
311 | { | 336 | { |
312 | return NULL; | 337 | return 0; |
313 | } | 338 | } |
314 | static inline void tpm_bios_log_teardown(struct dentry **dir) | 339 | |
340 | static inline void tpm_remove_ppi(struct kobject *parent) | ||
315 | { | 341 | { |
316 | } | 342 | } |
317 | #endif | 343 | #endif |
diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c new file mode 100644 index 000000000000..56051d0c97a2 --- /dev/null +++ b/drivers/char/tpm/tpm_acpi.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Seiji Munetoh <munetoh@jp.ibm.com> | ||
6 | * Stefan Berger <stefanb@us.ibm.com> | ||
7 | * Reiner Sailer <sailer@watson.ibm.com> | ||
8 | * Kylene Hall <kjhall@us.ibm.com> | ||
9 | * | ||
10 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
11 | * | ||
12 | * Access to the eventlog extended by the TCG BIOS of PC platform | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version | ||
17 | * 2 of the License, or (at your option) any later version. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/security.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <acpi/acpi.h> | ||
27 | |||
28 | #include "tpm.h" | ||
29 | #include "tpm_eventlog.h" | ||
30 | |||
31 | struct acpi_tcpa { | ||
32 | struct acpi_table_header hdr; | ||
33 | u16 platform_class; | ||
34 | union { | ||
35 | struct client_hdr { | ||
36 | u32 log_max_len __attribute__ ((packed)); | ||
37 | u64 log_start_addr __attribute__ ((packed)); | ||
38 | } client; | ||
39 | struct server_hdr { | ||
40 | u16 reserved; | ||
41 | u64 log_max_len __attribute__ ((packed)); | ||
42 | u64 log_start_addr __attribute__ ((packed)); | ||
43 | } server; | ||
44 | }; | ||
45 | }; | ||
46 | |||
47 | /* read binary bios log */ | ||
48 | int read_log(struct tpm_bios_log *log) | ||
49 | { | ||
50 | struct acpi_tcpa *buff; | ||
51 | acpi_status status; | ||
52 | void __iomem *virt; | ||
53 | u64 len, start; | ||
54 | |||
55 | if (log->bios_event_log != NULL) { | ||
56 | printk(KERN_ERR | ||
57 | "%s: ERROR - Eventlog already initialized\n", | ||
58 | __func__); | ||
59 | return -EFAULT; | ||
60 | } | ||
61 | |||
62 | /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ | ||
63 | status = acpi_get_table(ACPI_SIG_TCPA, 1, | ||
64 | (struct acpi_table_header **)&buff); | ||
65 | |||
66 | if (ACPI_FAILURE(status)) { | ||
67 | printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", | ||
68 | __func__); | ||
69 | return -EIO; | ||
70 | } | ||
71 | |||
72 | switch(buff->platform_class) { | ||
73 | case BIOS_SERVER: | ||
74 | len = buff->server.log_max_len; | ||
75 | start = buff->server.log_start_addr; | ||
76 | break; | ||
77 | case BIOS_CLIENT: | ||
78 | default: | ||
79 | len = buff->client.log_max_len; | ||
80 | start = buff->client.log_start_addr; | ||
81 | break; | ||
82 | } | ||
83 | if (!len) { | ||
84 | printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); | ||
85 | return -EIO; | ||
86 | } | ||
87 | |||
88 | /* malloc EventLog space */ | ||
89 | log->bios_event_log = kmalloc(len, GFP_KERNEL); | ||
90 | if (!log->bios_event_log) { | ||
91 | printk("%s: ERROR - Not enough Memory for BIOS measurements\n", | ||
92 | __func__); | ||
93 | return -ENOMEM; | ||
94 | } | ||
95 | |||
96 | log->bios_event_log_end = log->bios_event_log + len; | ||
97 | |||
98 | virt = acpi_os_map_memory(start, len); | ||
99 | if (!virt) { | ||
100 | kfree(log->bios_event_log); | ||
101 | printk("%s: ERROR - Unable to map memory\n", __func__); | ||
102 | return -EIO; | ||
103 | } | ||
104 | |||
105 | memcpy_fromio(log->bios_event_log, virt, len); | ||
106 | |||
107 | acpi_os_unmap_memory(virt, len); | ||
108 | return 0; | ||
109 | } | ||
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_eventlog.c index 0636520fa9bf..84ddc557b8f8 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_eventlog.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005 IBM Corporation | 2 | * Copyright (C) 2005, 2012 IBM Corporation |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Kent Yoder <key@linux.vnet.ibm.com> | ||
5 | * Seiji Munetoh <munetoh@jp.ibm.com> | 6 | * Seiji Munetoh <munetoh@jp.ibm.com> |
6 | * Stefan Berger <stefanb@us.ibm.com> | 7 | * Stefan Berger <stefanb@us.ibm.com> |
7 | * Reiner Sailer <sailer@watson.ibm.com> | 8 | * Reiner Sailer <sailer@watson.ibm.com> |
@@ -9,7 +10,7 @@ | |||
9 | * | 10 | * |
10 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | 11 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> |
11 | * | 12 | * |
12 | * Access to the eventlog extended by the TCG BIOS of PC platform | 13 | * Access to the eventlog created by a system's firmware / BIOS |
13 | * | 14 | * |
14 | * This program is free software; you can redistribute it and/or | 15 | * This program is free software; you can redistribute it and/or |
15 | * modify it under the terms of the GNU General Public License | 16 | * modify it under the terms of the GNU General Public License |
@@ -23,67 +24,10 @@ | |||
23 | #include <linux/security.h> | 24 | #include <linux/security.h> |
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
25 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
26 | #include <acpi/acpi.h> | ||
27 | #include "tpm.h" | ||
28 | |||
29 | #define TCG_EVENT_NAME_LEN_MAX 255 | ||
30 | #define MAX_TEXT_EVENT 1000 /* Max event string length */ | ||
31 | #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ | ||
32 | |||
33 | enum bios_platform_class { | ||
34 | BIOS_CLIENT = 0x00, | ||
35 | BIOS_SERVER = 0x01, | ||
36 | }; | ||
37 | |||
38 | struct tpm_bios_log { | ||
39 | void *bios_event_log; | ||
40 | void *bios_event_log_end; | ||
41 | }; | ||
42 | |||
43 | struct acpi_tcpa { | ||
44 | struct acpi_table_header hdr; | ||
45 | u16 platform_class; | ||
46 | union { | ||
47 | struct client_hdr { | ||
48 | u32 log_max_len __attribute__ ((packed)); | ||
49 | u64 log_start_addr __attribute__ ((packed)); | ||
50 | } client; | ||
51 | struct server_hdr { | ||
52 | u16 reserved; | ||
53 | u64 log_max_len __attribute__ ((packed)); | ||
54 | u64 log_start_addr __attribute__ ((packed)); | ||
55 | } server; | ||
56 | }; | ||
57 | }; | ||
58 | 27 | ||
59 | struct tcpa_event { | 28 | #include "tpm.h" |
60 | u32 pcr_index; | 29 | #include "tpm_eventlog.h" |
61 | u32 event_type; | ||
62 | u8 pcr_value[20]; /* SHA1 */ | ||
63 | u32 event_size; | ||
64 | u8 event_data[0]; | ||
65 | }; | ||
66 | 30 | ||
67 | enum tcpa_event_types { | ||
68 | PREBOOT = 0, | ||
69 | POST_CODE, | ||
70 | UNUSED, | ||
71 | NO_ACTION, | ||
72 | SEPARATOR, | ||
73 | ACTION, | ||
74 | EVENT_TAG, | ||
75 | SCRTM_CONTENTS, | ||
76 | SCRTM_VERSION, | ||
77 | CPU_MICROCODE, | ||
78 | PLATFORM_CONFIG_FLAGS, | ||
79 | TABLE_OF_DEVICES, | ||
80 | COMPACT_HASH, | ||
81 | IPL, | ||
82 | IPL_PARTITION_DATA, | ||
83 | NONHOST_CODE, | ||
84 | NONHOST_CONFIG, | ||
85 | NONHOST_INFO, | ||
86 | }; | ||
87 | 31 | ||
88 | static const char* tcpa_event_type_strings[] = { | 32 | static const char* tcpa_event_type_strings[] = { |
89 | "PREBOOT", | 33 | "PREBOOT", |
@@ -106,28 +50,6 @@ static const char* tcpa_event_type_strings[] = { | |||
106 | "Non-Host Info" | 50 | "Non-Host Info" |
107 | }; | 51 | }; |
108 | 52 | ||
109 | struct tcpa_pc_event { | ||
110 | u32 event_id; | ||
111 | u32 event_size; | ||
112 | u8 event_data[0]; | ||
113 | }; | ||
114 | |||
115 | enum tcpa_pc_event_ids { | ||
116 | SMBIOS = 1, | ||
117 | BIS_CERT, | ||
118 | POST_BIOS_ROM, | ||
119 | ESCD, | ||
120 | CMOS, | ||
121 | NVRAM, | ||
122 | OPTION_ROM_EXEC, | ||
123 | OPTION_ROM_CONFIG, | ||
124 | OPTION_ROM_MICROCODE = 10, | ||
125 | S_CRTM_VERSION, | ||
126 | S_CRTM_CONTENTS, | ||
127 | POST_CONTENTS, | ||
128 | HOST_TABLE_OF_DEVICES, | ||
129 | }; | ||
130 | |||
131 | static const char* tcpa_pc_event_id_strings[] = { | 53 | static const char* tcpa_pc_event_id_strings[] = { |
132 | "", | 54 | "", |
133 | "SMBIOS", | 55 | "SMBIOS", |
@@ -358,65 +280,6 @@ static const struct seq_operations tpm_binary_b_measurments_seqops = { | |||
358 | .show = tpm_binary_bios_measurements_show, | 280 | .show = tpm_binary_bios_measurements_show, |
359 | }; | 281 | }; |
360 | 282 | ||
361 | /* read binary bios log */ | ||
362 | static int read_log(struct tpm_bios_log *log) | ||
363 | { | ||
364 | struct acpi_tcpa *buff; | ||
365 | acpi_status status; | ||
366 | struct acpi_table_header *virt; | ||
367 | u64 len, start; | ||
368 | |||
369 | if (log->bios_event_log != NULL) { | ||
370 | printk(KERN_ERR | ||
371 | "%s: ERROR - Eventlog already initialized\n", | ||
372 | __func__); | ||
373 | return -EFAULT; | ||
374 | } | ||
375 | |||
376 | /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ | ||
377 | status = acpi_get_table(ACPI_SIG_TCPA, 1, | ||
378 | (struct acpi_table_header **)&buff); | ||
379 | |||
380 | if (ACPI_FAILURE(status)) { | ||
381 | printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", | ||
382 | __func__); | ||
383 | return -EIO; | ||
384 | } | ||
385 | |||
386 | switch(buff->platform_class) { | ||
387 | case BIOS_SERVER: | ||
388 | len = buff->server.log_max_len; | ||
389 | start = buff->server.log_start_addr; | ||
390 | break; | ||
391 | case BIOS_CLIENT: | ||
392 | default: | ||
393 | len = buff->client.log_max_len; | ||
394 | start = buff->client.log_start_addr; | ||
395 | break; | ||
396 | } | ||
397 | if (!len) { | ||
398 | printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); | ||
399 | return -EIO; | ||
400 | } | ||
401 | |||
402 | /* malloc EventLog space */ | ||
403 | log->bios_event_log = kmalloc(len, GFP_KERNEL); | ||
404 | if (!log->bios_event_log) { | ||
405 | printk("%s: ERROR - Not enough Memory for BIOS measurements\n", | ||
406 | __func__); | ||
407 | return -ENOMEM; | ||
408 | } | ||
409 | |||
410 | log->bios_event_log_end = log->bios_event_log + len; | ||
411 | |||
412 | virt = acpi_os_map_memory(start, len); | ||
413 | |||
414 | memcpy(log->bios_event_log, virt, len); | ||
415 | |||
416 | acpi_os_unmap_memory(virt, len); | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static int tpm_ascii_bios_measurements_open(struct inode *inode, | 283 | static int tpm_ascii_bios_measurements_open(struct inode *inode, |
421 | struct file *file) | 284 | struct file *file) |
422 | { | 285 | { |
diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h new file mode 100644 index 000000000000..e7da086d6928 --- /dev/null +++ b/drivers/char/tpm/tpm_eventlog.h | |||
@@ -0,0 +1,86 @@ | |||
1 | |||
2 | #ifndef __TPM_EVENTLOG_H__ | ||
3 | #define __TPM_EVENTLOG_H__ | ||
4 | |||
5 | #define TCG_EVENT_NAME_LEN_MAX 255 | ||
6 | #define MAX_TEXT_EVENT 1000 /* Max event string length */ | ||
7 | #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ | ||
8 | |||
9 | enum bios_platform_class { | ||
10 | BIOS_CLIENT = 0x00, | ||
11 | BIOS_SERVER = 0x01, | ||
12 | }; | ||
13 | |||
14 | struct tpm_bios_log { | ||
15 | void *bios_event_log; | ||
16 | void *bios_event_log_end; | ||
17 | }; | ||
18 | |||
19 | struct tcpa_event { | ||
20 | u32 pcr_index; | ||
21 | u32 event_type; | ||
22 | u8 pcr_value[20]; /* SHA1 */ | ||
23 | u32 event_size; | ||
24 | u8 event_data[0]; | ||
25 | }; | ||
26 | |||
27 | enum tcpa_event_types { | ||
28 | PREBOOT = 0, | ||
29 | POST_CODE, | ||
30 | UNUSED, | ||
31 | NO_ACTION, | ||
32 | SEPARATOR, | ||
33 | ACTION, | ||
34 | EVENT_TAG, | ||
35 | SCRTM_CONTENTS, | ||
36 | SCRTM_VERSION, | ||
37 | CPU_MICROCODE, | ||
38 | PLATFORM_CONFIG_FLAGS, | ||
39 | TABLE_OF_DEVICES, | ||
40 | COMPACT_HASH, | ||
41 | IPL, | ||
42 | IPL_PARTITION_DATA, | ||
43 | NONHOST_CODE, | ||
44 | NONHOST_CONFIG, | ||
45 | NONHOST_INFO, | ||
46 | }; | ||
47 | |||
48 | struct tcpa_pc_event { | ||
49 | u32 event_id; | ||
50 | u32 event_size; | ||
51 | u8 event_data[0]; | ||
52 | }; | ||
53 | |||
54 | enum tcpa_pc_event_ids { | ||
55 | SMBIOS = 1, | ||
56 | BIS_CERT, | ||
57 | POST_BIOS_ROM, | ||
58 | ESCD, | ||
59 | CMOS, | ||
60 | NVRAM, | ||
61 | OPTION_ROM_EXEC, | ||
62 | OPTION_ROM_CONFIG, | ||
63 | OPTION_ROM_MICROCODE = 10, | ||
64 | S_CRTM_VERSION, | ||
65 | S_CRTM_CONTENTS, | ||
66 | POST_CONTENTS, | ||
67 | HOST_TABLE_OF_DEVICES, | ||
68 | }; | ||
69 | |||
70 | int read_log(struct tpm_bios_log *log); | ||
71 | |||
72 | #if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \ | ||
73 | defined(CONFIG_ACPI) | ||
74 | extern struct dentry **tpm_bios_log_setup(char *); | ||
75 | extern void tpm_bios_log_teardown(struct dentry **); | ||
76 | #else | ||
77 | static inline struct dentry **tpm_bios_log_setup(char *name) | ||
78 | { | ||
79 | return NULL; | ||
80 | } | ||
81 | static inline void tpm_bios_log_teardown(struct dentry **dir) | ||
82 | { | ||
83 | } | ||
84 | #endif | ||
85 | |||
86 | #endif | ||
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c new file mode 100644 index 000000000000..5a831aec9d4b --- /dev/null +++ b/drivers/char/tpm/tpm_i2c_infineon.c | |||
@@ -0,0 +1,695 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Infineon Technologies | ||
3 | * | ||
4 | * Authors: | ||
5 | * Peter Huewe <peter.huewe@infineon.com> | ||
6 | * | ||
7 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
8 | * Specifications at www.trustedcomputinggroup.org | ||
9 | * | ||
10 | * This device driver implements the TPM interface as defined in | ||
11 | * the TCG TPM Interface Spec version 1.2, revision 1.0 and the | ||
12 | * Infineon I2C Protocol Stack Specification v0.20. | ||
13 | * | ||
14 | * It is based on the original tpm_tis device driver from Leendert van | ||
15 | * Dorn and Kyleen Hall. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or | ||
18 | * modify it under the terms of the GNU General Public License as | ||
19 | * published by the Free Software Foundation, version 2 of the | ||
20 | * License. | ||
21 | * | ||
22 | * | ||
23 | */ | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/wait.h> | ||
29 | #include "tpm.h" | ||
30 | |||
31 | /* max. buffer size supported by our TPM */ | ||
32 | #define TPM_BUFSIZE 1260 | ||
33 | |||
34 | /* max. number of iterations after I2C NAK */ | ||
35 | #define MAX_COUNT 3 | ||
36 | |||
37 | #define SLEEP_DURATION_LOW 55 | ||
38 | #define SLEEP_DURATION_HI 65 | ||
39 | |||
40 | /* max. number of iterations after I2C NAK for 'long' commands | ||
41 | * we need this especially for sending TPM_READY, since the cleanup after the | ||
42 | * transtion to the ready state may take some time, but it is unpredictable | ||
43 | * how long it will take. | ||
44 | */ | ||
45 | #define MAX_COUNT_LONG 50 | ||
46 | |||
47 | #define SLEEP_DURATION_LONG_LOW 200 | ||
48 | #define SLEEP_DURATION_LONG_HI 220 | ||
49 | |||
50 | /* After sending TPM_READY to 'reset' the TPM we have to sleep even longer */ | ||
51 | #define SLEEP_DURATION_RESET_LOW 2400 | ||
52 | #define SLEEP_DURATION_RESET_HI 2600 | ||
53 | |||
54 | /* we want to use usleep_range instead of msleep for the 5ms TPM_TIMEOUT */ | ||
55 | #define TPM_TIMEOUT_US_LOW (TPM_TIMEOUT * 1000) | ||
56 | #define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000) | ||
57 | |||
58 | /* expected value for DIDVID register */ | ||
59 | #define TPM_TIS_I2C_DID_VID 0x000b15d1L | ||
60 | |||
61 | /* Structure to store I2C TPM specific stuff */ | ||
62 | struct tpm_inf_dev { | ||
63 | struct i2c_client *client; | ||
64 | u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */ | ||
65 | struct tpm_chip *chip; | ||
66 | }; | ||
67 | |||
68 | static struct tpm_inf_dev tpm_dev; | ||
69 | static struct i2c_driver tpm_tis_i2c_driver; | ||
70 | |||
71 | /* | ||
72 | * iic_tpm_read() - read from TPM register | ||
73 | * @addr: register address to read from | ||
74 | * @buffer: provided by caller | ||
75 | * @len: number of bytes to read | ||
76 | * | ||
77 | * Read len bytes from TPM register and put them into | ||
78 | * buffer (little-endian format, i.e. first byte is put into buffer[0]). | ||
79 | * | ||
80 | * NOTE: TPM is big-endian for multi-byte values. Multi-byte | ||
81 | * values have to be swapped. | ||
82 | * | ||
83 | * NOTE: We can't unfortunately use the combined read/write functions | ||
84 | * provided by the i2c core as the TPM currently does not support the | ||
85 | * repeated start condition and due to it's special requirements. | ||
86 | * The i2c_smbus* functions do not work for this chip. | ||
87 | * | ||
88 | * Return -EIO on error, 0 on success. | ||
89 | */ | ||
90 | static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) | ||
91 | { | ||
92 | |||
93 | struct i2c_msg msg1 = { tpm_dev.client->addr, 0, 1, &addr }; | ||
94 | struct i2c_msg msg2 = { tpm_dev.client->addr, I2C_M_RD, len, buffer }; | ||
95 | |||
96 | int rc; | ||
97 | int count; | ||
98 | |||
99 | /* Lock the adapter for the duration of the whole sequence. */ | ||
100 | if (!tpm_dev.client->adapter->algo->master_xfer) | ||
101 | return -EOPNOTSUPP; | ||
102 | i2c_lock_adapter(tpm_dev.client->adapter); | ||
103 | |||
104 | for (count = 0; count < MAX_COUNT; count++) { | ||
105 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); | ||
106 | if (rc > 0) | ||
107 | break; /* break here to skip sleep */ | ||
108 | |||
109 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
110 | } | ||
111 | |||
112 | if (rc <= 0) | ||
113 | goto out; | ||
114 | |||
115 | /* After the TPM has successfully received the register address it needs | ||
116 | * some time, thus we're sleeping here again, before retrieving the data | ||
117 | */ | ||
118 | for (count = 0; count < MAX_COUNT; count++) { | ||
119 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
120 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1); | ||
121 | if (rc > 0) | ||
122 | break; | ||
123 | |||
124 | } | ||
125 | |||
126 | out: | ||
127 | i2c_unlock_adapter(tpm_dev.client->adapter); | ||
128 | if (rc <= 0) | ||
129 | return -EIO; | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, | ||
135 | unsigned int sleep_low, | ||
136 | unsigned int sleep_hi, u8 max_count) | ||
137 | { | ||
138 | int rc = -EIO; | ||
139 | int count; | ||
140 | |||
141 | struct i2c_msg msg1 = { tpm_dev.client->addr, 0, len + 1, tpm_dev.buf }; | ||
142 | |||
143 | if (len > TPM_BUFSIZE) | ||
144 | return -EINVAL; | ||
145 | |||
146 | if (!tpm_dev.client->adapter->algo->master_xfer) | ||
147 | return -EOPNOTSUPP; | ||
148 | i2c_lock_adapter(tpm_dev.client->adapter); | ||
149 | |||
150 | /* prepend the 'register address' to the buffer */ | ||
151 | tpm_dev.buf[0] = addr; | ||
152 | memcpy(&(tpm_dev.buf[1]), buffer, len); | ||
153 | |||
154 | /* | ||
155 | * NOTE: We have to use these special mechanisms here and unfortunately | ||
156 | * cannot rely on the standard behavior of i2c_transfer. | ||
157 | */ | ||
158 | for (count = 0; count < max_count; count++) { | ||
159 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); | ||
160 | if (rc > 0) | ||
161 | break; | ||
162 | |||
163 | usleep_range(sleep_low, sleep_hi); | ||
164 | } | ||
165 | |||
166 | i2c_unlock_adapter(tpm_dev.client->adapter); | ||
167 | if (rc <= 0) | ||
168 | return -EIO; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * iic_tpm_write() - write to TPM register | ||
175 | * @addr: register address to write to | ||
176 | * @buffer: containing data to be written | ||
177 | * @len: number of bytes to write | ||
178 | * | ||
179 | * Write len bytes from provided buffer to TPM register (little | ||
180 | * endian format, i.e. buffer[0] is written as first byte). | ||
181 | * | ||
182 | * NOTE: TPM is big-endian for multi-byte values. Multi-byte | ||
183 | * values have to be swapped. | ||
184 | * | ||
185 | * NOTE: use this function instead of the iic_tpm_write_generic function. | ||
186 | * | ||
187 | * Return -EIO on error, 0 on success | ||
188 | */ | ||
189 | static int iic_tpm_write(u8 addr, u8 *buffer, size_t len) | ||
190 | { | ||
191 | return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LOW, | ||
192 | SLEEP_DURATION_HI, MAX_COUNT); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * This function is needed especially for the cleanup situation after | ||
197 | * sending TPM_READY | ||
198 | * */ | ||
199 | static int iic_tpm_write_long(u8 addr, u8 *buffer, size_t len) | ||
200 | { | ||
201 | return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG_LOW, | ||
202 | SLEEP_DURATION_LONG_HI, MAX_COUNT_LONG); | ||
203 | } | ||
204 | |||
205 | enum tis_access { | ||
206 | TPM_ACCESS_VALID = 0x80, | ||
207 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | ||
208 | TPM_ACCESS_REQUEST_PENDING = 0x04, | ||
209 | TPM_ACCESS_REQUEST_USE = 0x02, | ||
210 | }; | ||
211 | |||
212 | enum tis_status { | ||
213 | TPM_STS_VALID = 0x80, | ||
214 | TPM_STS_COMMAND_READY = 0x40, | ||
215 | TPM_STS_GO = 0x20, | ||
216 | TPM_STS_DATA_AVAIL = 0x10, | ||
217 | TPM_STS_DATA_EXPECT = 0x08, | ||
218 | }; | ||
219 | |||
220 | enum tis_defaults { | ||
221 | TIS_SHORT_TIMEOUT = 750, /* ms */ | ||
222 | TIS_LONG_TIMEOUT = 2000, /* 2 sec */ | ||
223 | }; | ||
224 | |||
225 | #define TPM_ACCESS(l) (0x0000 | ((l) << 4)) | ||
226 | #define TPM_STS(l) (0x0001 | ((l) << 4)) | ||
227 | #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) | ||
228 | #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) | ||
229 | |||
230 | static int check_locality(struct tpm_chip *chip, int loc) | ||
231 | { | ||
232 | u8 buf; | ||
233 | int rc; | ||
234 | |||
235 | rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1); | ||
236 | if (rc < 0) | ||
237 | return rc; | ||
238 | |||
239 | if ((buf & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == | ||
240 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { | ||
241 | chip->vendor.locality = loc; | ||
242 | return loc; | ||
243 | } | ||
244 | |||
245 | return -EIO; | ||
246 | } | ||
247 | |||
248 | /* implementation similar to tpm_tis */ | ||
249 | static void release_locality(struct tpm_chip *chip, int loc, int force) | ||
250 | { | ||
251 | u8 buf; | ||
252 | if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0) | ||
253 | return; | ||
254 | |||
255 | if (force || (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == | ||
256 | (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) { | ||
257 | buf = TPM_ACCESS_ACTIVE_LOCALITY; | ||
258 | iic_tpm_write(TPM_ACCESS(loc), &buf, 1); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | static int request_locality(struct tpm_chip *chip, int loc) | ||
263 | { | ||
264 | unsigned long stop; | ||
265 | u8 buf = TPM_ACCESS_REQUEST_USE; | ||
266 | |||
267 | if (check_locality(chip, loc) >= 0) | ||
268 | return loc; | ||
269 | |||
270 | iic_tpm_write(TPM_ACCESS(loc), &buf, 1); | ||
271 | |||
272 | /* wait for burstcount */ | ||
273 | stop = jiffies + chip->vendor.timeout_a; | ||
274 | do { | ||
275 | if (check_locality(chip, loc) >= 0) | ||
276 | return loc; | ||
277 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); | ||
278 | } while (time_before(jiffies, stop)); | ||
279 | |||
280 | return -ETIME; | ||
281 | } | ||
282 | |||
283 | static u8 tpm_tis_i2c_status(struct tpm_chip *chip) | ||
284 | { | ||
285 | /* NOTE: since I2C read may fail, return 0 in this case --> time-out */ | ||
286 | u8 buf; | ||
287 | if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) | ||
288 | return 0; | ||
289 | else | ||
290 | return buf; | ||
291 | } | ||
292 | |||
293 | static void tpm_tis_i2c_ready(struct tpm_chip *chip) | ||
294 | { | ||
295 | /* this causes the current command to be aborted */ | ||
296 | u8 buf = TPM_STS_COMMAND_READY; | ||
297 | iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); | ||
298 | } | ||
299 | |||
300 | static ssize_t get_burstcount(struct tpm_chip *chip) | ||
301 | { | ||
302 | unsigned long stop; | ||
303 | ssize_t burstcnt; | ||
304 | u8 buf[3]; | ||
305 | |||
306 | /* wait for burstcount */ | ||
307 | /* which timeout value, spec has 2 answers (c & d) */ | ||
308 | stop = jiffies + chip->vendor.timeout_d; | ||
309 | do { | ||
310 | /* Note: STS is little endian */ | ||
311 | if (iic_tpm_read(TPM_STS(chip->vendor.locality)+1, buf, 3) < 0) | ||
312 | burstcnt = 0; | ||
313 | else | ||
314 | burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | ||
315 | |||
316 | if (burstcnt) | ||
317 | return burstcnt; | ||
318 | |||
319 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); | ||
320 | } while (time_before(jiffies, stop)); | ||
321 | return -EBUSY; | ||
322 | } | ||
323 | |||
324 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | ||
325 | int *status) | ||
326 | { | ||
327 | unsigned long stop; | ||
328 | |||
329 | /* check current status */ | ||
330 | *status = tpm_tis_i2c_status(chip); | ||
331 | if ((*status & mask) == mask) | ||
332 | return 0; | ||
333 | |||
334 | stop = jiffies + timeout; | ||
335 | do { | ||
336 | /* since we just checked the status, give the TPM some time */ | ||
337 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); | ||
338 | *status = tpm_tis_i2c_status(chip); | ||
339 | if ((*status & mask) == mask) | ||
340 | return 0; | ||
341 | |||
342 | } while (time_before(jiffies, stop)); | ||
343 | |||
344 | return -ETIME; | ||
345 | } | ||
346 | |||
347 | static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | ||
348 | { | ||
349 | size_t size = 0; | ||
350 | ssize_t burstcnt; | ||
351 | u8 retries = 0; | ||
352 | int rc; | ||
353 | |||
354 | while (size < count) { | ||
355 | burstcnt = get_burstcount(chip); | ||
356 | |||
357 | /* burstcnt < 0 = TPM is busy */ | ||
358 | if (burstcnt < 0) | ||
359 | return burstcnt; | ||
360 | |||
361 | /* limit received data to max. left */ | ||
362 | if (burstcnt > (count - size)) | ||
363 | burstcnt = count - size; | ||
364 | |||
365 | rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality), | ||
366 | &(buf[size]), burstcnt); | ||
367 | if (rc == 0) | ||
368 | size += burstcnt; | ||
369 | else if (rc < 0) | ||
370 | retries++; | ||
371 | |||
372 | /* avoid endless loop in case of broken HW */ | ||
373 | if (retries > MAX_COUNT_LONG) | ||
374 | return -EIO; | ||
375 | |||
376 | } | ||
377 | return size; | ||
378 | } | ||
379 | |||
380 | static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) | ||
381 | { | ||
382 | int size = 0; | ||
383 | int expected, status; | ||
384 | |||
385 | if (count < TPM_HEADER_SIZE) { | ||
386 | size = -EIO; | ||
387 | goto out; | ||
388 | } | ||
389 | |||
390 | /* read first 10 bytes, including tag, paramsize, and result */ | ||
391 | size = recv_data(chip, buf, TPM_HEADER_SIZE); | ||
392 | if (size < TPM_HEADER_SIZE) { | ||
393 | dev_err(chip->dev, "Unable to read header\n"); | ||
394 | goto out; | ||
395 | } | ||
396 | |||
397 | expected = be32_to_cpu(*(__be32 *)(buf + 2)); | ||
398 | if ((size_t) expected > count) { | ||
399 | size = -EIO; | ||
400 | goto out; | ||
401 | } | ||
402 | |||
403 | size += recv_data(chip, &buf[TPM_HEADER_SIZE], | ||
404 | expected - TPM_HEADER_SIZE); | ||
405 | if (size < expected) { | ||
406 | dev_err(chip->dev, "Unable to read remainder of result\n"); | ||
407 | size = -ETIME; | ||
408 | goto out; | ||
409 | } | ||
410 | |||
411 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); | ||
412 | if (status & TPM_STS_DATA_AVAIL) { /* retry? */ | ||
413 | dev_err(chip->dev, "Error left over data\n"); | ||
414 | size = -EIO; | ||
415 | goto out; | ||
416 | } | ||
417 | |||
418 | out: | ||
419 | tpm_tis_i2c_ready(chip); | ||
420 | /* The TPM needs some time to clean up here, | ||
421 | * so we sleep rather than keeping the bus busy | ||
422 | */ | ||
423 | usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI); | ||
424 | release_locality(chip, chip->vendor.locality, 0); | ||
425 | return size; | ||
426 | } | ||
427 | |||
428 | static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) | ||
429 | { | ||
430 | int rc, status; | ||
431 | ssize_t burstcnt; | ||
432 | size_t count = 0; | ||
433 | u8 retries = 0; | ||
434 | u8 sts = TPM_STS_GO; | ||
435 | |||
436 | if (len > TPM_BUFSIZE) | ||
437 | return -E2BIG; /* command is too long for our tpm, sorry */ | ||
438 | |||
439 | if (request_locality(chip, 0) < 0) | ||
440 | return -EBUSY; | ||
441 | |||
442 | status = tpm_tis_i2c_status(chip); | ||
443 | if ((status & TPM_STS_COMMAND_READY) == 0) { | ||
444 | tpm_tis_i2c_ready(chip); | ||
445 | if (wait_for_stat | ||
446 | (chip, TPM_STS_COMMAND_READY, | ||
447 | chip->vendor.timeout_b, &status) < 0) { | ||
448 | rc = -ETIME; | ||
449 | goto out_err; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | while (count < len - 1) { | ||
454 | burstcnt = get_burstcount(chip); | ||
455 | |||
456 | /* burstcnt < 0 = TPM is busy */ | ||
457 | if (burstcnt < 0) | ||
458 | return burstcnt; | ||
459 | |||
460 | if (burstcnt > (len - 1 - count)) | ||
461 | burstcnt = len - 1 - count; | ||
462 | |||
463 | rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), | ||
464 | &(buf[count]), burstcnt); | ||
465 | if (rc == 0) | ||
466 | count += burstcnt; | ||
467 | else if (rc < 0) | ||
468 | retries++; | ||
469 | |||
470 | /* avoid endless loop in case of broken HW */ | ||
471 | if (retries > MAX_COUNT_LONG) { | ||
472 | rc = -EIO; | ||
473 | goto out_err; | ||
474 | } | ||
475 | |||
476 | wait_for_stat(chip, TPM_STS_VALID, | ||
477 | chip->vendor.timeout_c, &status); | ||
478 | |||
479 | if ((status & TPM_STS_DATA_EXPECT) == 0) { | ||
480 | rc = -EIO; | ||
481 | goto out_err; | ||
482 | } | ||
483 | |||
484 | } | ||
485 | |||
486 | /* write last byte */ | ||
487 | iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); | ||
488 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); | ||
489 | if ((status & TPM_STS_DATA_EXPECT) != 0) { | ||
490 | rc = -EIO; | ||
491 | goto out_err; | ||
492 | } | ||
493 | |||
494 | /* go and do it */ | ||
495 | iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); | ||
496 | |||
497 | return len; | ||
498 | out_err: | ||
499 | tpm_tis_i2c_ready(chip); | ||
500 | /* The TPM needs some time to clean up here, | ||
501 | * so we sleep rather than keeping the bus busy | ||
502 | */ | ||
503 | usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI); | ||
504 | release_locality(chip, chip->vendor.locality, 0); | ||
505 | return rc; | ||
506 | } | ||
507 | |||
508 | static const struct file_operations tis_ops = { | ||
509 | .owner = THIS_MODULE, | ||
510 | .llseek = no_llseek, | ||
511 | .open = tpm_open, | ||
512 | .read = tpm_read, | ||
513 | .write = tpm_write, | ||
514 | .release = tpm_release, | ||
515 | }; | ||
516 | |||
517 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
518 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
519 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
520 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
521 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
522 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); | ||
523 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); | ||
524 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
525 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
526 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
527 | |||
528 | static struct attribute *tis_attrs[] = { | ||
529 | &dev_attr_pubek.attr, | ||
530 | &dev_attr_pcrs.attr, | ||
531 | &dev_attr_enabled.attr, | ||
532 | &dev_attr_active.attr, | ||
533 | &dev_attr_owned.attr, | ||
534 | &dev_attr_temp_deactivated.attr, | ||
535 | &dev_attr_caps.attr, | ||
536 | &dev_attr_cancel.attr, | ||
537 | &dev_attr_durations.attr, | ||
538 | &dev_attr_timeouts.attr, | ||
539 | NULL, | ||
540 | }; | ||
541 | |||
542 | static struct attribute_group tis_attr_grp = { | ||
543 | .attrs = tis_attrs | ||
544 | }; | ||
545 | |||
546 | static struct tpm_vendor_specific tpm_tis_i2c = { | ||
547 | .status = tpm_tis_i2c_status, | ||
548 | .recv = tpm_tis_i2c_recv, | ||
549 | .send = tpm_tis_i2c_send, | ||
550 | .cancel = tpm_tis_i2c_ready, | ||
551 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | ||
552 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | ||
553 | .req_canceled = TPM_STS_COMMAND_READY, | ||
554 | .attr_group = &tis_attr_grp, | ||
555 | .miscdev.fops = &tis_ops, | ||
556 | }; | ||
557 | |||
558 | static int __devinit tpm_tis_i2c_init(struct device *dev) | ||
559 | { | ||
560 | u32 vendor; | ||
561 | int rc = 0; | ||
562 | struct tpm_chip *chip; | ||
563 | |||
564 | chip = tpm_register_hardware(dev, &tpm_tis_i2c); | ||
565 | if (!chip) { | ||
566 | rc = -ENODEV; | ||
567 | goto out_err; | ||
568 | } | ||
569 | |||
570 | /* Disable interrupts */ | ||
571 | chip->vendor.irq = 0; | ||
572 | |||
573 | /* Default timeouts */ | ||
574 | chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
575 | chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); | ||
576 | chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
577 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
578 | |||
579 | if (request_locality(chip, 0) != 0) { | ||
580 | rc = -ENODEV; | ||
581 | goto out_vendor; | ||
582 | } | ||
583 | |||
584 | /* read four bytes from DID_VID register */ | ||
585 | if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) { | ||
586 | rc = -EIO; | ||
587 | goto out_release; | ||
588 | } | ||
589 | |||
590 | /* create DID_VID register value, after swapping to little-endian */ | ||
591 | vendor = be32_to_cpu((__be32) vendor); | ||
592 | |||
593 | if (vendor != TPM_TIS_I2C_DID_VID) { | ||
594 | rc = -ENODEV; | ||
595 | goto out_release; | ||
596 | } | ||
597 | |||
598 | dev_info(dev, "1.2 TPM (device-id 0x%X)\n", vendor >> 16); | ||
599 | |||
600 | INIT_LIST_HEAD(&chip->vendor.list); | ||
601 | tpm_dev.chip = chip; | ||
602 | |||
603 | tpm_get_timeouts(chip); | ||
604 | tpm_do_selftest(chip); | ||
605 | |||
606 | return 0; | ||
607 | |||
608 | out_release: | ||
609 | release_locality(chip, chip->vendor.locality, 1); | ||
610 | |||
611 | out_vendor: | ||
612 | /* close file handles */ | ||
613 | tpm_dev_vendor_release(chip); | ||
614 | |||
615 | /* remove hardware */ | ||
616 | tpm_remove_hardware(chip->dev); | ||
617 | |||
618 | /* reset these pointers, otherwise we oops */ | ||
619 | chip->dev->release = NULL; | ||
620 | chip->release = NULL; | ||
621 | tpm_dev.client = NULL; | ||
622 | dev_set_drvdata(chip->dev, chip); | ||
623 | out_err: | ||
624 | return rc; | ||
625 | } | ||
626 | |||
627 | static const struct i2c_device_id tpm_tis_i2c_table[] = { | ||
628 | {"tpm_i2c_infineon", 0}, | ||
629 | {}, | ||
630 | }; | ||
631 | |||
632 | MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table); | ||
633 | static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume); | ||
634 | |||
635 | static int __devinit tpm_tis_i2c_probe(struct i2c_client *client, | ||
636 | const struct i2c_device_id *id) | ||
637 | { | ||
638 | int rc; | ||
639 | if (tpm_dev.client != NULL) | ||
640 | return -EBUSY; /* We only support one client */ | ||
641 | |||
642 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
643 | dev_err(&client->dev, | ||
644 | "no algorithms associated to the i2c bus\n"); | ||
645 | return -ENODEV; | ||
646 | } | ||
647 | |||
648 | client->driver = &tpm_tis_i2c_driver; | ||
649 | tpm_dev.client = client; | ||
650 | rc = tpm_tis_i2c_init(&client->dev); | ||
651 | if (rc != 0) { | ||
652 | client->driver = NULL; | ||
653 | tpm_dev.client = NULL; | ||
654 | rc = -ENODEV; | ||
655 | } | ||
656 | return rc; | ||
657 | } | ||
658 | |||
659 | static int __devexit tpm_tis_i2c_remove(struct i2c_client *client) | ||
660 | { | ||
661 | struct tpm_chip *chip = tpm_dev.chip; | ||
662 | release_locality(chip, chip->vendor.locality, 1); | ||
663 | |||
664 | /* close file handles */ | ||
665 | tpm_dev_vendor_release(chip); | ||
666 | |||
667 | /* remove hardware */ | ||
668 | tpm_remove_hardware(chip->dev); | ||
669 | |||
670 | /* reset these pointers, otherwise we oops */ | ||
671 | chip->dev->release = NULL; | ||
672 | chip->release = NULL; | ||
673 | tpm_dev.client = NULL; | ||
674 | dev_set_drvdata(chip->dev, chip); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static struct i2c_driver tpm_tis_i2c_driver = { | ||
680 | |||
681 | .id_table = tpm_tis_i2c_table, | ||
682 | .probe = tpm_tis_i2c_probe, | ||
683 | .remove = tpm_tis_i2c_remove, | ||
684 | .driver = { | ||
685 | .name = "tpm_i2c_infineon", | ||
686 | .owner = THIS_MODULE, | ||
687 | .pm = &tpm_tis_i2c_ops, | ||
688 | }, | ||
689 | }; | ||
690 | |||
691 | module_i2c_driver(tpm_tis_i2c_driver); | ||
692 | MODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>"); | ||
693 | MODULE_DESCRIPTION("TPM TIS I2C Infineon Driver"); | ||
694 | MODULE_VERSION("2.1.5"); | ||
695 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c new file mode 100644 index 000000000000..efc4ab36a9d6 --- /dev/null +++ b/drivers/char/tpm/tpm_ibmvtpm.c | |||
@@ -0,0 +1,749 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 IBM Corporation | ||
3 | * | ||
4 | * Author: Ashley Lai <adlai@us.ibm.com> | ||
5 | * | ||
6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
7 | * | ||
8 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
9 | * Specifications at www.trustedcomputinggroup.org | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation, version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/dma-mapping.h> | ||
19 | #include <linux/dmapool.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <asm/vio.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/list.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/wait.h> | ||
28 | #include <asm/prom.h> | ||
29 | |||
30 | #include "tpm.h" | ||
31 | #include "tpm_ibmvtpm.h" | ||
32 | |||
33 | static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm"; | ||
34 | |||
35 | static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = { | ||
36 | { "IBM,vtpm", "IBM,vtpm"}, | ||
37 | { "", "" } | ||
38 | }; | ||
39 | MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table); | ||
40 | |||
41 | DECLARE_WAIT_QUEUE_HEAD(wq); | ||
42 | |||
43 | /** | ||
44 | * ibmvtpm_send_crq - Send a CRQ request | ||
45 | * @vdev: vio device struct | ||
46 | * @w1: first word | ||
47 | * @w2: second word | ||
48 | * | ||
49 | * Return value: | ||
50 | * 0 -Sucess | ||
51 | * Non-zero - Failure | ||
52 | */ | ||
53 | static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2) | ||
54 | { | ||
55 | return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, w1, w2); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * ibmvtpm_get_data - Retrieve ibm vtpm data | ||
60 | * @dev: device struct | ||
61 | * | ||
62 | * Return value: | ||
63 | * vtpm device struct | ||
64 | */ | ||
65 | static struct ibmvtpm_dev *ibmvtpm_get_data(const struct device *dev) | ||
66 | { | ||
67 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
68 | if (chip) | ||
69 | return (struct ibmvtpm_dev *)chip->vendor.data; | ||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * tpm_ibmvtpm_recv - Receive data after send | ||
75 | * @chip: tpm chip struct | ||
76 | * @buf: buffer to read | ||
77 | * count: size of buffer | ||
78 | * | ||
79 | * Return value: | ||
80 | * Number of bytes read | ||
81 | */ | ||
82 | static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) | ||
83 | { | ||
84 | struct ibmvtpm_dev *ibmvtpm; | ||
85 | u16 len; | ||
86 | |||
87 | ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data; | ||
88 | |||
89 | if (!ibmvtpm->rtce_buf) { | ||
90 | dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n"); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0); | ||
95 | |||
96 | if (count < ibmvtpm->crq_res.len) { | ||
97 | dev_err(ibmvtpm->dev, | ||
98 | "Invalid size in recv: count=%ld, crq_size=%d\n", | ||
99 | count, ibmvtpm->crq_res.len); | ||
100 | return -EIO; | ||
101 | } | ||
102 | |||
103 | spin_lock(&ibmvtpm->rtce_lock); | ||
104 | memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, ibmvtpm->crq_res.len); | ||
105 | memset(ibmvtpm->rtce_buf, 0, ibmvtpm->crq_res.len); | ||
106 | ibmvtpm->crq_res.valid = 0; | ||
107 | ibmvtpm->crq_res.msg = 0; | ||
108 | len = ibmvtpm->crq_res.len; | ||
109 | ibmvtpm->crq_res.len = 0; | ||
110 | spin_unlock(&ibmvtpm->rtce_lock); | ||
111 | return len; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * tpm_ibmvtpm_send - Send tpm request | ||
116 | * @chip: tpm chip struct | ||
117 | * @buf: buffer contains data to send | ||
118 | * count: size of buffer | ||
119 | * | ||
120 | * Return value: | ||
121 | * Number of bytes sent | ||
122 | */ | ||
123 | static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) | ||
124 | { | ||
125 | struct ibmvtpm_dev *ibmvtpm; | ||
126 | struct ibmvtpm_crq crq; | ||
127 | u64 *word = (u64 *) &crq; | ||
128 | int rc; | ||
129 | |||
130 | ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data; | ||
131 | |||
132 | if (!ibmvtpm->rtce_buf) { | ||
133 | dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n"); | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | if (count > ibmvtpm->rtce_size) { | ||
138 | dev_err(ibmvtpm->dev, | ||
139 | "Invalid size in send: count=%ld, rtce_size=%d\n", | ||
140 | count, ibmvtpm->rtce_size); | ||
141 | return -EIO; | ||
142 | } | ||
143 | |||
144 | spin_lock(&ibmvtpm->rtce_lock); | ||
145 | memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); | ||
146 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
147 | crq.msg = (u8)VTPM_TPM_COMMAND; | ||
148 | crq.len = (u16)count; | ||
149 | crq.data = ibmvtpm->rtce_dma_handle; | ||
150 | |||
151 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]); | ||
152 | if (rc != H_SUCCESS) { | ||
153 | dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); | ||
154 | rc = 0; | ||
155 | } else | ||
156 | rc = count; | ||
157 | |||
158 | spin_unlock(&ibmvtpm->rtce_lock); | ||
159 | return rc; | ||
160 | } | ||
161 | |||
162 | static void tpm_ibmvtpm_cancel(struct tpm_chip *chip) | ||
163 | { | ||
164 | return; | ||
165 | } | ||
166 | |||
167 | static u8 tpm_ibmvtpm_status(struct tpm_chip *chip) | ||
168 | { | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size | ||
174 | * @ibmvtpm: vtpm device struct | ||
175 | * | ||
176 | * Return value: | ||
177 | * 0 - Success | ||
178 | * Non-zero - Failure | ||
179 | */ | ||
180 | static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) | ||
181 | { | ||
182 | struct ibmvtpm_crq crq; | ||
183 | u64 *buf = (u64 *) &crq; | ||
184 | int rc; | ||
185 | |||
186 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
187 | crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE; | ||
188 | |||
189 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); | ||
190 | if (rc != H_SUCCESS) | ||
191 | dev_err(ibmvtpm->dev, | ||
192 | "ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc); | ||
193 | |||
194 | return rc; | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version | ||
199 | * - Note that this is vtpm version and not tpm version | ||
200 | * @ibmvtpm: vtpm device struct | ||
201 | * | ||
202 | * Return value: | ||
203 | * 0 - Success | ||
204 | * Non-zero - Failure | ||
205 | */ | ||
206 | static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) | ||
207 | { | ||
208 | struct ibmvtpm_crq crq; | ||
209 | u64 *buf = (u64 *) &crq; | ||
210 | int rc; | ||
211 | |||
212 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
213 | crq.msg = (u8)VTPM_GET_VERSION; | ||
214 | |||
215 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); | ||
216 | if (rc != H_SUCCESS) | ||
217 | dev_err(ibmvtpm->dev, | ||
218 | "ibmvtpm_crq_get_version failed rc=%d\n", rc); | ||
219 | |||
220 | return rc; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message | ||
225 | * @ibmvtpm: vtpm device struct | ||
226 | * | ||
227 | * Return value: | ||
228 | * 0 - Success | ||
229 | * Non-zero - Failure | ||
230 | */ | ||
231 | static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm) | ||
232 | { | ||
233 | int rc; | ||
234 | |||
235 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_COMP_CMD, 0); | ||
236 | if (rc != H_SUCCESS) | ||
237 | dev_err(ibmvtpm->dev, | ||
238 | "ibmvtpm_crq_send_init_complete failed rc=%d\n", rc); | ||
239 | |||
240 | return rc; | ||
241 | } | ||
242 | |||
243 | /** | ||
244 | * ibmvtpm_crq_send_init - Send a CRQ initialize message | ||
245 | * @ibmvtpm: vtpm device struct | ||
246 | * | ||
247 | * Return value: | ||
248 | * 0 - Success | ||
249 | * Non-zero - Failure | ||
250 | */ | ||
251 | static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) | ||
252 | { | ||
253 | int rc; | ||
254 | |||
255 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_CMD, 0); | ||
256 | if (rc != H_SUCCESS) | ||
257 | dev_err(ibmvtpm->dev, | ||
258 | "ibmvtpm_crq_send_init failed rc=%d\n", rc); | ||
259 | |||
260 | return rc; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * tpm_ibmvtpm_remove - ibm vtpm remove entry point | ||
265 | * @vdev: vio device struct | ||
266 | * | ||
267 | * Return value: | ||
268 | * 0 | ||
269 | */ | ||
270 | static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev) | ||
271 | { | ||
272 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); | ||
273 | int rc = 0; | ||
274 | |||
275 | free_irq(vdev->irq, ibmvtpm); | ||
276 | tasklet_kill(&ibmvtpm->tasklet); | ||
277 | |||
278 | do { | ||
279 | if (rc) | ||
280 | msleep(100); | ||
281 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | ||
282 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
283 | |||
284 | dma_unmap_single(ibmvtpm->dev, ibmvtpm->crq_dma_handle, | ||
285 | CRQ_RES_BUF_SIZE, DMA_BIDIRECTIONAL); | ||
286 | free_page((unsigned long)ibmvtpm->crq_queue.crq_addr); | ||
287 | |||
288 | if (ibmvtpm->rtce_buf) { | ||
289 | dma_unmap_single(ibmvtpm->dev, ibmvtpm->rtce_dma_handle, | ||
290 | ibmvtpm->rtce_size, DMA_BIDIRECTIONAL); | ||
291 | kfree(ibmvtpm->rtce_buf); | ||
292 | } | ||
293 | |||
294 | tpm_remove_hardware(ibmvtpm->dev); | ||
295 | |||
296 | kfree(ibmvtpm); | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | /** | ||
302 | * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver | ||
303 | * @vdev: vio device struct | ||
304 | * | ||
305 | * Return value: | ||
306 | * Number of bytes the driver needs to DMA map | ||
307 | */ | ||
308 | static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) | ||
309 | { | ||
310 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); | ||
311 | return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size; | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * tpm_ibmvtpm_suspend - Suspend | ||
316 | * @dev: device struct | ||
317 | * | ||
318 | * Return value: | ||
319 | * 0 | ||
320 | */ | ||
321 | static int tpm_ibmvtpm_suspend(struct device *dev) | ||
322 | { | ||
323 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev); | ||
324 | struct ibmvtpm_crq crq; | ||
325 | u64 *buf = (u64 *) &crq; | ||
326 | int rc = 0; | ||
327 | |||
328 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
329 | crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND; | ||
330 | |||
331 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); | ||
332 | if (rc != H_SUCCESS) | ||
333 | dev_err(ibmvtpm->dev, | ||
334 | "tpm_ibmvtpm_suspend failed rc=%d\n", rc); | ||
335 | |||
336 | return rc; | ||
337 | } | ||
338 | |||
339 | /** | ||
340 | * ibmvtpm_reset_crq - Reset CRQ | ||
341 | * @ibmvtpm: ibm vtpm struct | ||
342 | * | ||
343 | * Return value: | ||
344 | * 0 - Success | ||
345 | * Non-zero - Failure | ||
346 | */ | ||
347 | static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm) | ||
348 | { | ||
349 | int rc = 0; | ||
350 | |||
351 | do { | ||
352 | if (rc) | ||
353 | msleep(100); | ||
354 | rc = plpar_hcall_norets(H_FREE_CRQ, | ||
355 | ibmvtpm->vdev->unit_address); | ||
356 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
357 | |||
358 | memset(ibmvtpm->crq_queue.crq_addr, 0, CRQ_RES_BUF_SIZE); | ||
359 | ibmvtpm->crq_queue.index = 0; | ||
360 | |||
361 | return plpar_hcall_norets(H_REG_CRQ, ibmvtpm->vdev->unit_address, | ||
362 | ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE); | ||
363 | } | ||
364 | |||
365 | /** | ||
366 | * tpm_ibmvtpm_resume - Resume from suspend | ||
367 | * @dev: device struct | ||
368 | * | ||
369 | * Return value: | ||
370 | * 0 | ||
371 | */ | ||
372 | static int tpm_ibmvtpm_resume(struct device *dev) | ||
373 | { | ||
374 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev); | ||
375 | unsigned long flags; | ||
376 | int rc = 0; | ||
377 | |||
378 | do { | ||
379 | if (rc) | ||
380 | msleep(100); | ||
381 | rc = plpar_hcall_norets(H_ENABLE_CRQ, | ||
382 | ibmvtpm->vdev->unit_address); | ||
383 | } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
384 | |||
385 | if (rc) { | ||
386 | dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc); | ||
387 | return rc; | ||
388 | } | ||
389 | |||
390 | spin_lock_irqsave(&ibmvtpm->lock, flags); | ||
391 | vio_disable_interrupts(ibmvtpm->vdev); | ||
392 | tasklet_schedule(&ibmvtpm->tasklet); | ||
393 | spin_unlock_irqrestore(&ibmvtpm->lock, flags); | ||
394 | |||
395 | rc = ibmvtpm_crq_send_init(ibmvtpm); | ||
396 | if (rc) | ||
397 | dev_err(dev, "Error send_init rc=%d\n", rc); | ||
398 | |||
399 | return rc; | ||
400 | } | ||
401 | |||
402 | static const struct file_operations ibmvtpm_ops = { | ||
403 | .owner = THIS_MODULE, | ||
404 | .llseek = no_llseek, | ||
405 | .open = tpm_open, | ||
406 | .read = tpm_read, | ||
407 | .write = tpm_write, | ||
408 | .release = tpm_release, | ||
409 | }; | ||
410 | |||
411 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
412 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
413 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
414 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
415 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
416 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, | ||
417 | NULL); | ||
418 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); | ||
419 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
420 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
421 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
422 | |||
423 | static struct attribute *ibmvtpm_attrs[] = { | ||
424 | &dev_attr_pubek.attr, | ||
425 | &dev_attr_pcrs.attr, | ||
426 | &dev_attr_enabled.attr, | ||
427 | &dev_attr_active.attr, | ||
428 | &dev_attr_owned.attr, | ||
429 | &dev_attr_temp_deactivated.attr, | ||
430 | &dev_attr_caps.attr, | ||
431 | &dev_attr_cancel.attr, | ||
432 | &dev_attr_durations.attr, | ||
433 | &dev_attr_timeouts.attr, NULL, | ||
434 | }; | ||
435 | |||
436 | static struct attribute_group ibmvtpm_attr_grp = { .attrs = ibmvtpm_attrs }; | ||
437 | |||
438 | static const struct tpm_vendor_specific tpm_ibmvtpm = { | ||
439 | .recv = tpm_ibmvtpm_recv, | ||
440 | .send = tpm_ibmvtpm_send, | ||
441 | .cancel = tpm_ibmvtpm_cancel, | ||
442 | .status = tpm_ibmvtpm_status, | ||
443 | .req_complete_mask = 0, | ||
444 | .req_complete_val = 0, | ||
445 | .req_canceled = 0, | ||
446 | .attr_group = &ibmvtpm_attr_grp, | ||
447 | .miscdev = { .fops = &ibmvtpm_ops, }, | ||
448 | }; | ||
449 | |||
450 | static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = { | ||
451 | .suspend = tpm_ibmvtpm_suspend, | ||
452 | .resume = tpm_ibmvtpm_resume, | ||
453 | }; | ||
454 | |||
455 | /** | ||
456 | * ibmvtpm_crq_get_next - Get next responded crq | ||
457 | * @ibmvtpm vtpm device struct | ||
458 | * | ||
459 | * Return value: | ||
460 | * vtpm crq pointer | ||
461 | */ | ||
462 | static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm) | ||
463 | { | ||
464 | struct ibmvtpm_crq_queue *crq_q = &ibmvtpm->crq_queue; | ||
465 | struct ibmvtpm_crq *crq = &crq_q->crq_addr[crq_q->index]; | ||
466 | |||
467 | if (crq->valid & VTPM_MSG_RES) { | ||
468 | if (++crq_q->index == crq_q->num_entry) | ||
469 | crq_q->index = 0; | ||
470 | rmb(); | ||
471 | } else | ||
472 | crq = NULL; | ||
473 | return crq; | ||
474 | } | ||
475 | |||
476 | /** | ||
477 | * ibmvtpm_crq_process - Process responded crq | ||
478 | * @crq crq to be processed | ||
479 | * @ibmvtpm vtpm device struct | ||
480 | * | ||
481 | * Return value: | ||
482 | * Nothing | ||
483 | */ | ||
484 | static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, | ||
485 | struct ibmvtpm_dev *ibmvtpm) | ||
486 | { | ||
487 | int rc = 0; | ||
488 | |||
489 | switch (crq->valid) { | ||
490 | case VALID_INIT_CRQ: | ||
491 | switch (crq->msg) { | ||
492 | case INIT_CRQ_RES: | ||
493 | dev_info(ibmvtpm->dev, "CRQ initialized\n"); | ||
494 | rc = ibmvtpm_crq_send_init_complete(ibmvtpm); | ||
495 | if (rc) | ||
496 | dev_err(ibmvtpm->dev, "Unable to send CRQ init complete rc=%d\n", rc); | ||
497 | return; | ||
498 | case INIT_CRQ_COMP_RES: | ||
499 | dev_info(ibmvtpm->dev, | ||
500 | "CRQ initialization completed\n"); | ||
501 | return; | ||
502 | default: | ||
503 | dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg); | ||
504 | return; | ||
505 | } | ||
506 | return; | ||
507 | case IBMVTPM_VALID_CMD: | ||
508 | switch (crq->msg) { | ||
509 | case VTPM_GET_RTCE_BUFFER_SIZE_RES: | ||
510 | if (crq->len <= 0) { | ||
511 | dev_err(ibmvtpm->dev, "Invalid rtce size\n"); | ||
512 | return; | ||
513 | } | ||
514 | ibmvtpm->rtce_size = crq->len; | ||
515 | ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size, | ||
516 | GFP_KERNEL); | ||
517 | if (!ibmvtpm->rtce_buf) { | ||
518 | dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n"); | ||
519 | return; | ||
520 | } | ||
521 | |||
522 | ibmvtpm->rtce_dma_handle = dma_map_single(ibmvtpm->dev, | ||
523 | ibmvtpm->rtce_buf, ibmvtpm->rtce_size, | ||
524 | DMA_BIDIRECTIONAL); | ||
525 | |||
526 | if (dma_mapping_error(ibmvtpm->dev, | ||
527 | ibmvtpm->rtce_dma_handle)) { | ||
528 | kfree(ibmvtpm->rtce_buf); | ||
529 | ibmvtpm->rtce_buf = NULL; | ||
530 | dev_err(ibmvtpm->dev, "Failed to dma map rtce buffer\n"); | ||
531 | } | ||
532 | |||
533 | return; | ||
534 | case VTPM_GET_VERSION_RES: | ||
535 | ibmvtpm->vtpm_version = crq->data; | ||
536 | return; | ||
537 | case VTPM_TPM_COMMAND_RES: | ||
538 | ibmvtpm->crq_res.valid = crq->valid; | ||
539 | ibmvtpm->crq_res.msg = crq->msg; | ||
540 | ibmvtpm->crq_res.len = crq->len; | ||
541 | ibmvtpm->crq_res.data = crq->data; | ||
542 | wake_up_interruptible(&wq); | ||
543 | return; | ||
544 | default: | ||
545 | return; | ||
546 | } | ||
547 | } | ||
548 | return; | ||
549 | } | ||
550 | |||
551 | /** | ||
552 | * ibmvtpm_interrupt - Interrupt handler | ||
553 | * @irq: irq number to handle | ||
554 | * @vtpm_instance: vtpm that received interrupt | ||
555 | * | ||
556 | * Returns: | ||
557 | * IRQ_HANDLED | ||
558 | **/ | ||
559 | static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance) | ||
560 | { | ||
561 | struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance; | ||
562 | unsigned long flags; | ||
563 | |||
564 | spin_lock_irqsave(&ibmvtpm->lock, flags); | ||
565 | vio_disable_interrupts(ibmvtpm->vdev); | ||
566 | tasklet_schedule(&ibmvtpm->tasklet); | ||
567 | spin_unlock_irqrestore(&ibmvtpm->lock, flags); | ||
568 | |||
569 | return IRQ_HANDLED; | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * ibmvtpm_tasklet - Interrupt handler tasklet | ||
574 | * @data: ibm vtpm device struct | ||
575 | * | ||
576 | * Returns: | ||
577 | * Nothing | ||
578 | **/ | ||
579 | static void ibmvtpm_tasklet(void *data) | ||
580 | { | ||
581 | struct ibmvtpm_dev *ibmvtpm = data; | ||
582 | struct ibmvtpm_crq *crq; | ||
583 | unsigned long flags; | ||
584 | |||
585 | spin_lock_irqsave(&ibmvtpm->lock, flags); | ||
586 | while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) { | ||
587 | ibmvtpm_crq_process(crq, ibmvtpm); | ||
588 | crq->valid = 0; | ||
589 | wmb(); | ||
590 | } | ||
591 | |||
592 | vio_enable_interrupts(ibmvtpm->vdev); | ||
593 | spin_unlock_irqrestore(&ibmvtpm->lock, flags); | ||
594 | } | ||
595 | |||
596 | /** | ||
597 | * tpm_ibmvtpm_probe - ibm vtpm initialize entry point | ||
598 | * @vio_dev: vio device struct | ||
599 | * @id: vio device id struct | ||
600 | * | ||
601 | * Return value: | ||
602 | * 0 - Success | ||
603 | * Non-zero - Failure | ||
604 | */ | ||
605 | static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev, | ||
606 | const struct vio_device_id *id) | ||
607 | { | ||
608 | struct ibmvtpm_dev *ibmvtpm; | ||
609 | struct device *dev = &vio_dev->dev; | ||
610 | struct ibmvtpm_crq_queue *crq_q; | ||
611 | struct tpm_chip *chip; | ||
612 | int rc = -ENOMEM, rc1; | ||
613 | |||
614 | chip = tpm_register_hardware(dev, &tpm_ibmvtpm); | ||
615 | if (!chip) { | ||
616 | dev_err(dev, "tpm_register_hardware failed\n"); | ||
617 | return -ENODEV; | ||
618 | } | ||
619 | |||
620 | ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL); | ||
621 | if (!ibmvtpm) { | ||
622 | dev_err(dev, "kzalloc for ibmvtpm failed\n"); | ||
623 | goto cleanup; | ||
624 | } | ||
625 | |||
626 | crq_q = &ibmvtpm->crq_queue; | ||
627 | crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL); | ||
628 | if (!crq_q->crq_addr) { | ||
629 | dev_err(dev, "Unable to allocate memory for crq_addr\n"); | ||
630 | goto cleanup; | ||
631 | } | ||
632 | |||
633 | crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr); | ||
634 | ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr, | ||
635 | CRQ_RES_BUF_SIZE, | ||
636 | DMA_BIDIRECTIONAL); | ||
637 | |||
638 | if (dma_mapping_error(dev, ibmvtpm->crq_dma_handle)) { | ||
639 | dev_err(dev, "dma mapping failed\n"); | ||
640 | goto cleanup; | ||
641 | } | ||
642 | |||
643 | rc = plpar_hcall_norets(H_REG_CRQ, vio_dev->unit_address, | ||
644 | ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE); | ||
645 | if (rc == H_RESOURCE) | ||
646 | rc = ibmvtpm_reset_crq(ibmvtpm); | ||
647 | |||
648 | if (rc) { | ||
649 | dev_err(dev, "Unable to register CRQ rc=%d\n", rc); | ||
650 | goto reg_crq_cleanup; | ||
651 | } | ||
652 | |||
653 | tasklet_init(&ibmvtpm->tasklet, (void *)ibmvtpm_tasklet, | ||
654 | (unsigned long)ibmvtpm); | ||
655 | |||
656 | rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0, | ||
657 | tpm_ibmvtpm_driver_name, ibmvtpm); | ||
658 | if (rc) { | ||
659 | dev_err(dev, "Error %d register irq 0x%x\n", rc, vio_dev->irq); | ||
660 | goto init_irq_cleanup; | ||
661 | } | ||
662 | |||
663 | rc = vio_enable_interrupts(vio_dev); | ||
664 | if (rc) { | ||
665 | dev_err(dev, "Error %d enabling interrupts\n", rc); | ||
666 | goto init_irq_cleanup; | ||
667 | } | ||
668 | |||
669 | crq_q->index = 0; | ||
670 | |||
671 | ibmvtpm->dev = dev; | ||
672 | ibmvtpm->vdev = vio_dev; | ||
673 | chip->vendor.data = (void *)ibmvtpm; | ||
674 | |||
675 | spin_lock_init(&ibmvtpm->lock); | ||
676 | spin_lock_init(&ibmvtpm->rtce_lock); | ||
677 | |||
678 | rc = ibmvtpm_crq_send_init(ibmvtpm); | ||
679 | if (rc) | ||
680 | goto init_irq_cleanup; | ||
681 | |||
682 | rc = ibmvtpm_crq_get_version(ibmvtpm); | ||
683 | if (rc) | ||
684 | goto init_irq_cleanup; | ||
685 | |||
686 | rc = ibmvtpm_crq_get_rtce_size(ibmvtpm); | ||
687 | if (rc) | ||
688 | goto init_irq_cleanup; | ||
689 | |||
690 | return rc; | ||
691 | init_irq_cleanup: | ||
692 | tasklet_kill(&ibmvtpm->tasklet); | ||
693 | do { | ||
694 | rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address); | ||
695 | } while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1)); | ||
696 | reg_crq_cleanup: | ||
697 | dma_unmap_single(dev, ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE, | ||
698 | DMA_BIDIRECTIONAL); | ||
699 | cleanup: | ||
700 | if (ibmvtpm) { | ||
701 | if (crq_q->crq_addr) | ||
702 | free_page((unsigned long)crq_q->crq_addr); | ||
703 | kfree(ibmvtpm); | ||
704 | } | ||
705 | |||
706 | tpm_remove_hardware(dev); | ||
707 | |||
708 | return rc; | ||
709 | } | ||
710 | |||
711 | static struct vio_driver ibmvtpm_driver = { | ||
712 | .id_table = tpm_ibmvtpm_device_table, | ||
713 | .probe = tpm_ibmvtpm_probe, | ||
714 | .remove = tpm_ibmvtpm_remove, | ||
715 | .get_desired_dma = tpm_ibmvtpm_get_desired_dma, | ||
716 | .name = tpm_ibmvtpm_driver_name, | ||
717 | .pm = &tpm_ibmvtpm_pm_ops, | ||
718 | }; | ||
719 | |||
720 | /** | ||
721 | * ibmvtpm_module_init - Initialize ibm vtpm module | ||
722 | * | ||
723 | * Return value: | ||
724 | * 0 -Success | ||
725 | * Non-zero - Failure | ||
726 | */ | ||
727 | static int __init ibmvtpm_module_init(void) | ||
728 | { | ||
729 | return vio_register_driver(&ibmvtpm_driver); | ||
730 | } | ||
731 | |||
732 | /** | ||
733 | * ibmvtpm_module_exit - Teardown ibm vtpm module | ||
734 | * | ||
735 | * Return value: | ||
736 | * Nothing | ||
737 | */ | ||
738 | static void __exit ibmvtpm_module_exit(void) | ||
739 | { | ||
740 | vio_unregister_driver(&ibmvtpm_driver); | ||
741 | } | ||
742 | |||
743 | module_init(ibmvtpm_module_init); | ||
744 | module_exit(ibmvtpm_module_exit); | ||
745 | |||
746 | MODULE_AUTHOR("adlai@us.ibm.com"); | ||
747 | MODULE_DESCRIPTION("IBM vTPM Driver"); | ||
748 | MODULE_VERSION("1.0"); | ||
749 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h new file mode 100644 index 000000000000..4296eb4b4d82 --- /dev/null +++ b/drivers/char/tpm/tpm_ibmvtpm.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 IBM Corporation | ||
3 | * | ||
4 | * Author: Ashley Lai <adlai@us.ibm.com> | ||
5 | * | ||
6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
7 | * | ||
8 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
9 | * Specifications at www.trustedcomputinggroup.org | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation, version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef __TPM_IBMVTPM_H__ | ||
19 | #define __TPM_IBMVTPM_H__ | ||
20 | |||
21 | /* vTPM Message Format 1 */ | ||
22 | struct ibmvtpm_crq { | ||
23 | u8 valid; | ||
24 | u8 msg; | ||
25 | u16 len; | ||
26 | u32 data; | ||
27 | u64 reserved; | ||
28 | } __attribute__((packed, aligned(8))); | ||
29 | |||
30 | struct ibmvtpm_crq_queue { | ||
31 | struct ibmvtpm_crq *crq_addr; | ||
32 | u32 index; | ||
33 | u32 num_entry; | ||
34 | }; | ||
35 | |||
36 | struct ibmvtpm_dev { | ||
37 | struct device *dev; | ||
38 | struct vio_dev *vdev; | ||
39 | struct ibmvtpm_crq_queue crq_queue; | ||
40 | dma_addr_t crq_dma_handle; | ||
41 | spinlock_t lock; | ||
42 | struct tasklet_struct tasklet; | ||
43 | u32 rtce_size; | ||
44 | void __iomem *rtce_buf; | ||
45 | dma_addr_t rtce_dma_handle; | ||
46 | spinlock_t rtce_lock; | ||
47 | struct ibmvtpm_crq crq_res; | ||
48 | u32 vtpm_version; | ||
49 | }; | ||
50 | |||
51 | #define CRQ_RES_BUF_SIZE PAGE_SIZE | ||
52 | |||
53 | /* Initialize CRQ */ | ||
54 | #define INIT_CRQ_CMD 0xC001000000000000LL /* Init cmd */ | ||
55 | #define INIT_CRQ_COMP_CMD 0xC002000000000000LL /* Init complete cmd */ | ||
56 | #define INIT_CRQ_RES 0x01 /* Init respond */ | ||
57 | #define INIT_CRQ_COMP_RES 0x02 /* Init complete respond */ | ||
58 | #define VALID_INIT_CRQ 0xC0 /* Valid command for init crq */ | ||
59 | |||
60 | /* vTPM CRQ response is the message type | 0x80 */ | ||
61 | #define VTPM_MSG_RES 0x80 | ||
62 | #define IBMVTPM_VALID_CMD 0x80 | ||
63 | |||
64 | /* vTPM CRQ message types */ | ||
65 | #define VTPM_GET_VERSION 0x01 | ||
66 | #define VTPM_GET_VERSION_RES (0x01 | VTPM_MSG_RES) | ||
67 | |||
68 | #define VTPM_TPM_COMMAND 0x02 | ||
69 | #define VTPM_TPM_COMMAND_RES (0x02 | VTPM_MSG_RES) | ||
70 | |||
71 | #define VTPM_GET_RTCE_BUFFER_SIZE 0x03 | ||
72 | #define VTPM_GET_RTCE_BUFFER_SIZE_RES (0x03 | VTPM_MSG_RES) | ||
73 | |||
74 | #define VTPM_PREPARE_TO_SUSPEND 0x04 | ||
75 | #define VTPM_PREPARE_TO_SUSPEND_RES (0x04 | VTPM_MSG_RES) | ||
76 | |||
77 | #endif | ||
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c new file mode 100644 index 000000000000..98ba2bd1a355 --- /dev/null +++ b/drivers/char/tpm/tpm_of.c | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * Copyright 2012 IBM Corporation | ||
3 | * | ||
4 | * Author: Ashley Lai <adlai@us.ibm.com> | ||
5 | * | ||
6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
7 | * | ||
8 | * Read the event log created by the firmware on PPC64 | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/slab.h> | ||
18 | #include <linux/of.h> | ||
19 | |||
20 | #include "tpm.h" | ||
21 | #include "tpm_eventlog.h" | ||
22 | |||
23 | int read_log(struct tpm_bios_log *log) | ||
24 | { | ||
25 | struct device_node *np; | ||
26 | const u32 *sizep; | ||
27 | const __be64 *basep; | ||
28 | |||
29 | if (log->bios_event_log != NULL) { | ||
30 | pr_err("%s: ERROR - Eventlog already initialized\n", __func__); | ||
31 | return -EFAULT; | ||
32 | } | ||
33 | |||
34 | np = of_find_node_by_name(NULL, "ibm,vtpm"); | ||
35 | if (!np) { | ||
36 | pr_err("%s: ERROR - IBMVTPM not supported\n", __func__); | ||
37 | return -ENODEV; | ||
38 | } | ||
39 | |||
40 | sizep = of_get_property(np, "linux,sml-size", NULL); | ||
41 | if (sizep == NULL) { | ||
42 | pr_err("%s: ERROR - SML size not found\n", __func__); | ||
43 | goto cleanup_eio; | ||
44 | } | ||
45 | if (*sizep == 0) { | ||
46 | pr_err("%s: ERROR - event log area empty\n", __func__); | ||
47 | goto cleanup_eio; | ||
48 | } | ||
49 | |||
50 | basep = of_get_property(np, "linux,sml-base", NULL); | ||
51 | if (basep == NULL) { | ||
52 | pr_err(KERN_ERR "%s: ERROR - SML not found\n", __func__); | ||
53 | goto cleanup_eio; | ||
54 | } | ||
55 | |||
56 | of_node_put(np); | ||
57 | log->bios_event_log = kmalloc(*sizep, GFP_KERNEL); | ||
58 | if (!log->bios_event_log) { | ||
59 | pr_err("%s: ERROR - Not enough memory for BIOS measurements\n", | ||
60 | __func__); | ||
61 | return -ENOMEM; | ||
62 | } | ||
63 | |||
64 | log->bios_event_log_end = log->bios_event_log + *sizep; | ||
65 | |||
66 | memcpy(log->bios_event_log, __va(be64_to_cpup(basep)), *sizep); | ||
67 | |||
68 | return 0; | ||
69 | |||
70 | cleanup_eio: | ||
71 | of_node_put(np); | ||
72 | return -EIO; | ||
73 | } | ||
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c new file mode 100644 index 000000000000..720ebcf29fdf --- /dev/null +++ b/drivers/char/tpm/tpm_ppi.c | |||
@@ -0,0 +1,463 @@ | |||
1 | #include <linux/acpi.h> | ||
2 | #include <acpi/acpi_drivers.h> | ||
3 | #include "tpm.h" | ||
4 | |||
5 | static const u8 tpm_ppi_uuid[] = { | ||
6 | 0xA6, 0xFA, 0xDD, 0x3D, | ||
7 | 0x1B, 0x36, | ||
8 | 0xB4, 0x4E, | ||
9 | 0xA4, 0x24, | ||
10 | 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 | ||
11 | }; | ||
12 | static char *tpm_device_name = "TPM"; | ||
13 | |||
14 | #define TPM_PPI_REVISION_ID 1 | ||
15 | #define TPM_PPI_FN_VERSION 1 | ||
16 | #define TPM_PPI_FN_SUBREQ 2 | ||
17 | #define TPM_PPI_FN_GETREQ 3 | ||
18 | #define TPM_PPI_FN_GETACT 4 | ||
19 | #define TPM_PPI_FN_GETRSP 5 | ||
20 | #define TPM_PPI_FN_SUBREQ2 7 | ||
21 | #define TPM_PPI_FN_GETOPR 8 | ||
22 | #define PPI_TPM_REQ_MAX 22 | ||
23 | #define PPI_VS_REQ_START 128 | ||
24 | #define PPI_VS_REQ_END 255 | ||
25 | #define PPI_VERSION_LEN 3 | ||
26 | |||
27 | static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, | ||
28 | void **return_value) | ||
29 | { | ||
30 | acpi_status status; | ||
31 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
32 | status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | ||
33 | if (strstr(buffer.pointer, context) != NULL) { | ||
34 | *return_value = handle; | ||
35 | kfree(buffer.pointer); | ||
36 | return AE_CTRL_TERMINATE; | ||
37 | } | ||
38 | return AE_OK; | ||
39 | } | ||
40 | |||
41 | static inline void ppi_assign_params(union acpi_object params[4], | ||
42 | u64 function_num) | ||
43 | { | ||
44 | params[0].type = ACPI_TYPE_BUFFER; | ||
45 | params[0].buffer.length = sizeof(tpm_ppi_uuid); | ||
46 | params[0].buffer.pointer = (char *)tpm_ppi_uuid; | ||
47 | params[1].type = ACPI_TYPE_INTEGER; | ||
48 | params[1].integer.value = TPM_PPI_REVISION_ID; | ||
49 | params[2].type = ACPI_TYPE_INTEGER; | ||
50 | params[2].integer.value = function_num; | ||
51 | params[3].type = ACPI_TYPE_PACKAGE; | ||
52 | params[3].package.count = 0; | ||
53 | params[3].package.elements = NULL; | ||
54 | } | ||
55 | |||
56 | static ssize_t tpm_show_ppi_version(struct device *dev, | ||
57 | struct device_attribute *attr, char *buf) | ||
58 | { | ||
59 | acpi_handle handle; | ||
60 | acpi_status status; | ||
61 | struct acpi_object_list input; | ||
62 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
63 | union acpi_object params[4]; | ||
64 | union acpi_object *obj; | ||
65 | |||
66 | input.count = 4; | ||
67 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
68 | input.pointer = params; | ||
69 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
70 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
71 | tpm_device_name, &handle); | ||
72 | if (ACPI_FAILURE(status)) | ||
73 | return -ENXIO; | ||
74 | |||
75 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
76 | ACPI_TYPE_STRING); | ||
77 | if (ACPI_FAILURE(status)) | ||
78 | return -ENOMEM; | ||
79 | obj = (union acpi_object *)output.pointer; | ||
80 | status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer); | ||
81 | kfree(output.pointer); | ||
82 | return status; | ||
83 | } | ||
84 | |||
85 | static ssize_t tpm_show_ppi_request(struct device *dev, | ||
86 | struct device_attribute *attr, char *buf) | ||
87 | { | ||
88 | acpi_handle handle; | ||
89 | acpi_status status; | ||
90 | struct acpi_object_list input; | ||
91 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
92 | union acpi_object params[4]; | ||
93 | union acpi_object *ret_obj; | ||
94 | |||
95 | input.count = 4; | ||
96 | ppi_assign_params(params, TPM_PPI_FN_GETREQ); | ||
97 | input.pointer = params; | ||
98 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
99 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
100 | tpm_device_name, &handle); | ||
101 | if (ACPI_FAILURE(status)) | ||
102 | return -ENXIO; | ||
103 | |||
104 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
105 | ACPI_TYPE_PACKAGE); | ||
106 | if (ACPI_FAILURE(status)) | ||
107 | return -ENOMEM; | ||
108 | /* | ||
109 | * output.pointer should be of package type, including two integers. | ||
110 | * The first is function return code, 0 means success and 1 means | ||
111 | * error. The second is pending TPM operation requested by the OS, 0 | ||
112 | * means none and >0 means operation value. | ||
113 | */ | ||
114 | ret_obj = ((union acpi_object *)output.pointer)->package.elements; | ||
115 | if (ret_obj->type == ACPI_TYPE_INTEGER) { | ||
116 | if (ret_obj->integer.value) { | ||
117 | status = -EFAULT; | ||
118 | goto cleanup; | ||
119 | } | ||
120 | ret_obj++; | ||
121 | if (ret_obj->type == ACPI_TYPE_INTEGER) | ||
122 | status = scnprintf(buf, PAGE_SIZE, "%llu\n", | ||
123 | ret_obj->integer.value); | ||
124 | else | ||
125 | status = -EINVAL; | ||
126 | } else { | ||
127 | status = -EINVAL; | ||
128 | } | ||
129 | cleanup: | ||
130 | kfree(output.pointer); | ||
131 | return status; | ||
132 | } | ||
133 | |||
134 | static ssize_t tpm_store_ppi_request(struct device *dev, | ||
135 | struct device_attribute *attr, | ||
136 | const char *buf, size_t count) | ||
137 | { | ||
138 | char version[PPI_VERSION_LEN + 1]; | ||
139 | acpi_handle handle; | ||
140 | acpi_status status; | ||
141 | struct acpi_object_list input; | ||
142 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
143 | union acpi_object params[4]; | ||
144 | union acpi_object obj; | ||
145 | u32 req; | ||
146 | u64 ret; | ||
147 | |||
148 | input.count = 4; | ||
149 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
150 | input.pointer = params; | ||
151 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
152 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
153 | tpm_device_name, &handle); | ||
154 | if (ACPI_FAILURE(status)) | ||
155 | return -ENXIO; | ||
156 | |||
157 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
158 | ACPI_TYPE_STRING); | ||
159 | if (ACPI_FAILURE(status)) | ||
160 | return -ENOMEM; | ||
161 | strncpy(version, | ||
162 | ((union acpi_object *)output.pointer)->string.pointer, | ||
163 | PPI_VERSION_LEN); | ||
164 | kfree(output.pointer); | ||
165 | output.length = ACPI_ALLOCATE_BUFFER; | ||
166 | output.pointer = NULL; | ||
167 | /* | ||
168 | * the function to submit TPM operation request to pre-os environment | ||
169 | * is updated with function index from SUBREQ to SUBREQ2 since PPI | ||
170 | * version 1.1 | ||
171 | */ | ||
172 | if (strcmp(version, "1.1") == -1) | ||
173 | params[2].integer.value = TPM_PPI_FN_SUBREQ; | ||
174 | else | ||
175 | params[2].integer.value = TPM_PPI_FN_SUBREQ2; | ||
176 | /* | ||
177 | * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS | ||
178 | * accept buffer/string/integer type, but some BIOS accept buffer/ | ||
179 | * string/package type. For PPI version 1.0 and 1.1, use buffer type | ||
180 | * for compatibility, and use package type since 1.2 according to spec. | ||
181 | */ | ||
182 | if (strcmp(version, "1.2") == -1) { | ||
183 | params[3].type = ACPI_TYPE_BUFFER; | ||
184 | params[3].buffer.length = sizeof(req); | ||
185 | sscanf(buf, "%d", &req); | ||
186 | params[3].buffer.pointer = (char *)&req; | ||
187 | } else { | ||
188 | params[3].package.count = 1; | ||
189 | obj.type = ACPI_TYPE_INTEGER; | ||
190 | sscanf(buf, "%llu", &obj.integer.value); | ||
191 | params[3].package.elements = &obj; | ||
192 | } | ||
193 | |||
194 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
195 | ACPI_TYPE_INTEGER); | ||
196 | if (ACPI_FAILURE(status)) | ||
197 | return -ENOMEM; | ||
198 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
199 | if (ret == 0) | ||
200 | status = (acpi_status)count; | ||
201 | else if (ret == 1) | ||
202 | status = -EPERM; | ||
203 | else | ||
204 | status = -EFAULT; | ||
205 | kfree(output.pointer); | ||
206 | return status; | ||
207 | } | ||
208 | |||
209 | static ssize_t tpm_show_ppi_transition_action(struct device *dev, | ||
210 | struct device_attribute *attr, | ||
211 | char *buf) | ||
212 | { | ||
213 | char version[PPI_VERSION_LEN + 1]; | ||
214 | acpi_handle handle; | ||
215 | acpi_status status; | ||
216 | struct acpi_object_list input; | ||
217 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
218 | union acpi_object params[4]; | ||
219 | u32 ret; | ||
220 | char *info[] = { | ||
221 | "None", | ||
222 | "Shutdown", | ||
223 | "Reboot", | ||
224 | "OS Vendor-specific", | ||
225 | "Error", | ||
226 | }; | ||
227 | input.count = 4; | ||
228 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
229 | input.pointer = params; | ||
230 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
231 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
232 | tpm_device_name, &handle); | ||
233 | if (ACPI_FAILURE(status)) | ||
234 | return -ENXIO; | ||
235 | |||
236 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
237 | ACPI_TYPE_STRING); | ||
238 | if (ACPI_FAILURE(status)) | ||
239 | return -ENOMEM; | ||
240 | strncpy(version, | ||
241 | ((union acpi_object *)output.pointer)->string.pointer, | ||
242 | PPI_VERSION_LEN); | ||
243 | /* | ||
244 | * PPI spec defines params[3].type as empty package, but some platforms | ||
245 | * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for | ||
246 | * compatibility, define params[3].type as buffer, if PPI version < 1.2 | ||
247 | */ | ||
248 | if (strcmp(version, "1.2") == -1) { | ||
249 | params[3].type = ACPI_TYPE_BUFFER; | ||
250 | params[3].buffer.length = 0; | ||
251 | params[3].buffer.pointer = NULL; | ||
252 | } | ||
253 | params[2].integer.value = TPM_PPI_FN_GETACT; | ||
254 | kfree(output.pointer); | ||
255 | output.length = ACPI_ALLOCATE_BUFFER; | ||
256 | output.pointer = NULL; | ||
257 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
258 | ACPI_TYPE_INTEGER); | ||
259 | if (ACPI_FAILURE(status)) | ||
260 | return -ENOMEM; | ||
261 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
262 | if (ret < ARRAY_SIZE(info) - 1) | ||
263 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); | ||
264 | else | ||
265 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, | ||
266 | info[ARRAY_SIZE(info)-1]); | ||
267 | kfree(output.pointer); | ||
268 | return status; | ||
269 | } | ||
270 | |||
271 | static ssize_t tpm_show_ppi_response(struct device *dev, | ||
272 | struct device_attribute *attr, | ||
273 | char *buf) | ||
274 | { | ||
275 | acpi_handle handle; | ||
276 | acpi_status status; | ||
277 | struct acpi_object_list input; | ||
278 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
279 | union acpi_object params[4]; | ||
280 | union acpi_object *ret_obj; | ||
281 | u64 req; | ||
282 | |||
283 | input.count = 4; | ||
284 | ppi_assign_params(params, TPM_PPI_FN_GETRSP); | ||
285 | input.pointer = params; | ||
286 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
287 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
288 | tpm_device_name, &handle); | ||
289 | if (ACPI_FAILURE(status)) | ||
290 | return -ENXIO; | ||
291 | |||
292 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
293 | ACPI_TYPE_PACKAGE); | ||
294 | if (ACPI_FAILURE(status)) | ||
295 | return -ENOMEM; | ||
296 | /* | ||
297 | * parameter output.pointer should be of package type, including | ||
298 | * 3 integers. The first means function return code, the second means | ||
299 | * most recent TPM operation request, and the last means response to | ||
300 | * the most recent TPM operation request. Only if the first is 0, and | ||
301 | * the second integer is not 0, the response makes sense. | ||
302 | */ | ||
303 | ret_obj = ((union acpi_object *)output.pointer)->package.elements; | ||
304 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
305 | status = -EINVAL; | ||
306 | goto cleanup; | ||
307 | } | ||
308 | if (ret_obj->integer.value) { | ||
309 | status = -EFAULT; | ||
310 | goto cleanup; | ||
311 | } | ||
312 | ret_obj++; | ||
313 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
314 | status = -EINVAL; | ||
315 | goto cleanup; | ||
316 | } | ||
317 | if (ret_obj->integer.value) { | ||
318 | req = ret_obj->integer.value; | ||
319 | ret_obj++; | ||
320 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
321 | status = -EINVAL; | ||
322 | goto cleanup; | ||
323 | } | ||
324 | if (ret_obj->integer.value == 0) | ||
325 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | ||
326 | "0: Success"); | ||
327 | else if (ret_obj->integer.value == 0xFFFFFFF0) | ||
328 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | ||
329 | "0xFFFFFFF0: User Abort"); | ||
330 | else if (ret_obj->integer.value == 0xFFFFFFF1) | ||
331 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | ||
332 | "0xFFFFFFF1: BIOS Failure"); | ||
333 | else if (ret_obj->integer.value >= 1 && | ||
334 | ret_obj->integer.value <= 0x00000FFF) | ||
335 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", | ||
336 | req, ret_obj->integer.value, | ||
337 | "Corresponding TPM error"); | ||
338 | else | ||
339 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", | ||
340 | req, ret_obj->integer.value, | ||
341 | "Error"); | ||
342 | } else { | ||
343 | status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", | ||
344 | ret_obj->integer.value, "No Recent Request"); | ||
345 | } | ||
346 | cleanup: | ||
347 | kfree(output.pointer); | ||
348 | return status; | ||
349 | } | ||
350 | |||
351 | static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) | ||
352 | { | ||
353 | char *str = buf; | ||
354 | char version[PPI_VERSION_LEN]; | ||
355 | acpi_handle handle; | ||
356 | acpi_status status; | ||
357 | struct acpi_object_list input; | ||
358 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
359 | union acpi_object params[4]; | ||
360 | union acpi_object obj; | ||
361 | int i; | ||
362 | u32 ret; | ||
363 | char *info[] = { | ||
364 | "Not implemented", | ||
365 | "BIOS only", | ||
366 | "Blocked for OS by BIOS", | ||
367 | "User required", | ||
368 | "User not required", | ||
369 | }; | ||
370 | input.count = 4; | ||
371 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
372 | input.pointer = params; | ||
373 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
374 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
375 | tpm_device_name, &handle); | ||
376 | if (ACPI_FAILURE(status)) | ||
377 | return -ENXIO; | ||
378 | |||
379 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
380 | ACPI_TYPE_STRING); | ||
381 | if (ACPI_FAILURE(status)) | ||
382 | return -ENOMEM; | ||
383 | |||
384 | strncpy(version, | ||
385 | ((union acpi_object *)output.pointer)->string.pointer, | ||
386 | PPI_VERSION_LEN); | ||
387 | kfree(output.pointer); | ||
388 | output.length = ACPI_ALLOCATE_BUFFER; | ||
389 | output.pointer = NULL; | ||
390 | if (strcmp(version, "1.2") == -1) | ||
391 | return -EPERM; | ||
392 | |||
393 | params[2].integer.value = TPM_PPI_FN_GETOPR; | ||
394 | params[3].package.count = 1; | ||
395 | obj.type = ACPI_TYPE_INTEGER; | ||
396 | params[3].package.elements = &obj; | ||
397 | for (i = start; i <= end; i++) { | ||
398 | obj.integer.value = i; | ||
399 | status = acpi_evaluate_object_typed(handle, "_DSM", | ||
400 | &input, &output, ACPI_TYPE_INTEGER); | ||
401 | if (ACPI_FAILURE(status)) | ||
402 | return -ENOMEM; | ||
403 | |||
404 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
405 | if (ret > 0 && ret < ARRAY_SIZE(info)) | ||
406 | str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", | ||
407 | i, ret, info[ret]); | ||
408 | kfree(output.pointer); | ||
409 | output.length = ACPI_ALLOCATE_BUFFER; | ||
410 | output.pointer = NULL; | ||
411 | } | ||
412 | return str - buf; | ||
413 | } | ||
414 | |||
415 | static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, | ||
416 | struct device_attribute *attr, | ||
417 | char *buf) | ||
418 | { | ||
419 | return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX); | ||
420 | } | ||
421 | |||
422 | static ssize_t tpm_show_ppi_vs_operations(struct device *dev, | ||
423 | struct device_attribute *attr, | ||
424 | char *buf) | ||
425 | { | ||
426 | return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END); | ||
427 | } | ||
428 | |||
429 | static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); | ||
430 | static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP, | ||
431 | tpm_show_ppi_request, tpm_store_ppi_request); | ||
432 | static DEVICE_ATTR(transition_action, S_IRUGO, | ||
433 | tpm_show_ppi_transition_action, NULL); | ||
434 | static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL); | ||
435 | static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL); | ||
436 | static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL); | ||
437 | |||
438 | static struct attribute *ppi_attrs[] = { | ||
439 | &dev_attr_version.attr, | ||
440 | &dev_attr_request.attr, | ||
441 | &dev_attr_transition_action.attr, | ||
442 | &dev_attr_response.attr, | ||
443 | &dev_attr_tcg_operations.attr, | ||
444 | &dev_attr_vs_operations.attr, NULL, | ||
445 | }; | ||
446 | static struct attribute_group ppi_attr_grp = { | ||
447 | .name = "ppi", | ||
448 | .attrs = ppi_attrs | ||
449 | }; | ||
450 | |||
451 | int tpm_add_ppi(struct kobject *parent) | ||
452 | { | ||
453 | return sysfs_create_group(parent, &ppi_attr_grp); | ||
454 | } | ||
455 | EXPORT_SYMBOL_GPL(tpm_add_ppi); | ||
456 | |||
457 | void tpm_remove_ppi(struct kobject *parent) | ||
458 | { | ||
459 | sysfs_remove_group(parent, &ppi_attr_grp); | ||
460 | } | ||
461 | EXPORT_SYMBOL_GPL(tpm_remove_ppi); | ||
462 | |||
463 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index c4be3519a587..6bdf2671254f 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
@@ -705,6 +705,7 @@ out_err: | |||
705 | return rc; | 705 | return rc; |
706 | } | 706 | } |
707 | 707 | ||
708 | #if defined(CONFIG_PNP) || defined(CONFIG_PM_SLEEP) | ||
708 | static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) | 709 | static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) |
709 | { | 710 | { |
710 | u32 intmask; | 711 | u32 intmask; |
@@ -725,7 +726,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) | |||
725 | iowrite32(intmask, | 726 | iowrite32(intmask, |
726 | chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); | 727 | chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); |
727 | } | 728 | } |
728 | 729 | #endif | |
729 | 730 | ||
730 | #ifdef CONFIG_PNP | 731 | #ifdef CONFIG_PNP |
731 | static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, | 732 | static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, |
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 46b77ede84c0..af98f6d6509b 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c | |||
@@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count) | |||
67 | tmp[tpk_curr + 1] = '\0'; | 67 | tmp[tpk_curr + 1] = '\0'; |
68 | printk(KERN_INFO "%s%s", tpk_tag, tmp); | 68 | printk(KERN_INFO "%s%s", tpk_tag, tmp); |
69 | tpk_curr = 0; | 69 | tpk_curr = 0; |
70 | if (buf[i + 1] == '\n') | 70 | if ((i + 1) < count && buf[i + 1] == '\n') |
71 | i++; | 71 | i++; |
72 | break; | 72 | break; |
73 | case '\n': | 73 | case '\n': |
@@ -178,11 +178,17 @@ static struct tty_driver *ttyprintk_driver; | |||
178 | static int __init ttyprintk_init(void) | 178 | static int __init ttyprintk_init(void) |
179 | { | 179 | { |
180 | int ret = -ENOMEM; | 180 | int ret = -ENOMEM; |
181 | void *rp; | ||
182 | 181 | ||
183 | ttyprintk_driver = alloc_tty_driver(1); | 182 | tty_port_init(&tpk_port.port); |
184 | if (!ttyprintk_driver) | 183 | tpk_port.port.ops = &null_ops; |
185 | return ret; | 184 | mutex_init(&tpk_port.port_write_mutex); |
185 | |||
186 | ttyprintk_driver = tty_alloc_driver(1, | ||
187 | TTY_DRIVER_RESET_TERMIOS | | ||
188 | TTY_DRIVER_REAL_RAW | | ||
189 | TTY_DRIVER_UNNUMBERED_NODE); | ||
190 | if (IS_ERR(ttyprintk_driver)) | ||
191 | return PTR_ERR(ttyprintk_driver); | ||
186 | 192 | ||
187 | ttyprintk_driver->driver_name = "ttyprintk"; | 193 | ttyprintk_driver->driver_name = "ttyprintk"; |
188 | ttyprintk_driver->name = "ttyprintk"; | 194 | ttyprintk_driver->name = "ttyprintk"; |
@@ -191,9 +197,8 @@ static int __init ttyprintk_init(void) | |||
191 | ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE; | 197 | ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE; |
192 | ttyprintk_driver->init_termios = tty_std_termios; | 198 | ttyprintk_driver->init_termios = tty_std_termios; |
193 | ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; | 199 | ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; |
194 | ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS | | ||
195 | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | ||
196 | tty_set_operations(ttyprintk_driver, &ttyprintk_ops); | 200 | tty_set_operations(ttyprintk_driver, &ttyprintk_ops); |
201 | tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0); | ||
197 | 202 | ||
198 | ret = tty_register_driver(ttyprintk_driver); | 203 | ret = tty_register_driver(ttyprintk_driver); |
199 | if (ret < 0) { | 204 | if (ret < 0) { |
@@ -201,22 +206,10 @@ static int __init ttyprintk_init(void) | |||
201 | goto error; | 206 | goto error; |
202 | } | 207 | } |
203 | 208 | ||
204 | /* create our unnumbered device */ | ||
205 | rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL, | ||
206 | ttyprintk_driver->name); | ||
207 | if (IS_ERR(rp)) { | ||
208 | printk(KERN_ERR "Couldn't create ttyprintk device\n"); | ||
209 | ret = PTR_ERR(rp); | ||
210 | goto error; | ||
211 | } | ||
212 | |||
213 | tty_port_init(&tpk_port.port); | ||
214 | tpk_port.port.ops = &null_ops; | ||
215 | mutex_init(&tpk_port.port_write_mutex); | ||
216 | |||
217 | return 0; | 209 | return 0; |
218 | 210 | ||
219 | error: | 211 | error: |
212 | tty_unregister_driver(ttyprintk_driver); | ||
220 | put_tty_driver(ttyprintk_driver); | 213 | put_tty_driver(ttyprintk_driver); |
221 | ttyprintk_driver = NULL; | 214 | ttyprintk_driver = NULL; |
222 | return ret; | 215 | return ret; |
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f5451c76..8ab9c3d4bf13 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/freezer.h> | 25 | #include <linux/freezer.h> |
26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
27 | #include <linux/splice.h> | ||
28 | #include <linux/pagemap.h> | ||
27 | #include <linux/init.h> | 29 | #include <linux/init.h> |
28 | #include <linux/list.h> | 30 | #include <linux/list.h> |
29 | #include <linux/poll.h> | 31 | #include <linux/poll.h> |
@@ -474,26 +476,53 @@ static ssize_t send_control_msg(struct port *port, unsigned int event, | |||
474 | return 0; | 476 | return 0; |
475 | } | 477 | } |
476 | 478 | ||
479 | struct buffer_token { | ||
480 | union { | ||
481 | void *buf; | ||
482 | struct scatterlist *sg; | ||
483 | } u; | ||
484 | /* If sgpages == 0 then buf is used, else sg is used */ | ||
485 | unsigned int sgpages; | ||
486 | }; | ||
487 | |||
488 | static void reclaim_sg_pages(struct scatterlist *sg, unsigned int nrpages) | ||
489 | { | ||
490 | int i; | ||
491 | struct page *page; | ||
492 | |||
493 | for (i = 0; i < nrpages; i++) { | ||
494 | page = sg_page(&sg[i]); | ||
495 | if (!page) | ||
496 | break; | ||
497 | put_page(page); | ||
498 | } | ||
499 | kfree(sg); | ||
500 | } | ||
501 | |||
477 | /* Callers must take the port->outvq_lock */ | 502 | /* Callers must take the port->outvq_lock */ |
478 | static void reclaim_consumed_buffers(struct port *port) | 503 | static void reclaim_consumed_buffers(struct port *port) |
479 | { | 504 | { |
480 | void *buf; | 505 | struct buffer_token *tok; |
481 | unsigned int len; | 506 | unsigned int len; |
482 | 507 | ||
483 | if (!port->portdev) { | 508 | if (!port->portdev) { |
484 | /* Device has been unplugged. vqs are already gone. */ | 509 | /* Device has been unplugged. vqs are already gone. */ |
485 | return; | 510 | return; |
486 | } | 511 | } |
487 | while ((buf = virtqueue_get_buf(port->out_vq, &len))) { | 512 | while ((tok = virtqueue_get_buf(port->out_vq, &len))) { |
488 | kfree(buf); | 513 | if (tok->sgpages) |
514 | reclaim_sg_pages(tok->u.sg, tok->sgpages); | ||
515 | else | ||
516 | kfree(tok->u.buf); | ||
517 | kfree(tok); | ||
489 | port->outvq_full = false; | 518 | port->outvq_full = false; |
490 | } | 519 | } |
491 | } | 520 | } |
492 | 521 | ||
493 | static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, | 522 | static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, |
494 | bool nonblock) | 523 | int nents, size_t in_count, |
524 | struct buffer_token *tok, bool nonblock) | ||
495 | { | 525 | { |
496 | struct scatterlist sg[1]; | ||
497 | struct virtqueue *out_vq; | 526 | struct virtqueue *out_vq; |
498 | ssize_t ret; | 527 | ssize_t ret; |
499 | unsigned long flags; | 528 | unsigned long flags; |
@@ -505,8 +534,7 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, | |||
505 | 534 | ||
506 | reclaim_consumed_buffers(port); | 535 | reclaim_consumed_buffers(port); |
507 | 536 | ||
508 | sg_init_one(sg, in_buf, in_count); | 537 | ret = virtqueue_add_buf(out_vq, sg, nents, 0, tok, GFP_ATOMIC); |
509 | ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf, GFP_ATOMIC); | ||
510 | 538 | ||
511 | /* Tell Host to go! */ | 539 | /* Tell Host to go! */ |
512 | virtqueue_kick(out_vq); | 540 | virtqueue_kick(out_vq); |
@@ -544,6 +572,37 @@ done: | |||
544 | return in_count; | 572 | return in_count; |
545 | } | 573 | } |
546 | 574 | ||
575 | static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, | ||
576 | bool nonblock) | ||
577 | { | ||
578 | struct scatterlist sg[1]; | ||
579 | struct buffer_token *tok; | ||
580 | |||
581 | tok = kmalloc(sizeof(*tok), GFP_ATOMIC); | ||
582 | if (!tok) | ||
583 | return -ENOMEM; | ||
584 | tok->sgpages = 0; | ||
585 | tok->u.buf = in_buf; | ||
586 | |||
587 | sg_init_one(sg, in_buf, in_count); | ||
588 | |||
589 | return __send_to_port(port, sg, 1, in_count, tok, nonblock); | ||
590 | } | ||
591 | |||
592 | static ssize_t send_pages(struct port *port, struct scatterlist *sg, int nents, | ||
593 | size_t in_count, bool nonblock) | ||
594 | { | ||
595 | struct buffer_token *tok; | ||
596 | |||
597 | tok = kmalloc(sizeof(*tok), GFP_ATOMIC); | ||
598 | if (!tok) | ||
599 | return -ENOMEM; | ||
600 | tok->sgpages = nents; | ||
601 | tok->u.sg = sg; | ||
602 | |||
603 | return __send_to_port(port, sg, nents, in_count, tok, nonblock); | ||
604 | } | ||
605 | |||
547 | /* | 606 | /* |
548 | * Give out the data that's requested from the buffer that we have | 607 | * Give out the data that's requested from the buffer that we have |
549 | * queued up. | 608 | * queued up. |
@@ -665,6 +724,26 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf, | |||
665 | return fill_readbuf(port, ubuf, count, true); | 724 | return fill_readbuf(port, ubuf, count, true); |
666 | } | 725 | } |
667 | 726 | ||
727 | static int wait_port_writable(struct port *port, bool nonblock) | ||
728 | { | ||
729 | int ret; | ||
730 | |||
731 | if (will_write_block(port)) { | ||
732 | if (nonblock) | ||
733 | return -EAGAIN; | ||
734 | |||
735 | ret = wait_event_freezable(port->waitqueue, | ||
736 | !will_write_block(port)); | ||
737 | if (ret < 0) | ||
738 | return ret; | ||
739 | } | ||
740 | /* Port got hot-unplugged. */ | ||
741 | if (!port->guest_connected) | ||
742 | return -ENODEV; | ||
743 | |||
744 | return 0; | ||
745 | } | ||
746 | |||
668 | static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, | 747 | static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, |
669 | size_t count, loff_t *offp) | 748 | size_t count, loff_t *offp) |
670 | { | 749 | { |
@@ -681,18 +760,9 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, | |||
681 | 760 | ||
682 | nonblock = filp->f_flags & O_NONBLOCK; | 761 | nonblock = filp->f_flags & O_NONBLOCK; |
683 | 762 | ||
684 | if (will_write_block(port)) { | 763 | ret = wait_port_writable(port, nonblock); |
685 | if (nonblock) | 764 | if (ret < 0) |
686 | return -EAGAIN; | 765 | return ret; |
687 | |||
688 | ret = wait_event_freezable(port->waitqueue, | ||
689 | !will_write_block(port)); | ||
690 | if (ret < 0) | ||
691 | return ret; | ||
692 | } | ||
693 | /* Port got hot-unplugged. */ | ||
694 | if (!port->guest_connected) | ||
695 | return -ENODEV; | ||
696 | 766 | ||
697 | count = min((size_t)(32 * 1024), count); | 767 | count = min((size_t)(32 * 1024), count); |
698 | 768 | ||
@@ -725,6 +795,93 @@ out: | |||
725 | return ret; | 795 | return ret; |
726 | } | 796 | } |
727 | 797 | ||
798 | struct sg_list { | ||
799 | unsigned int n; | ||
800 | unsigned int size; | ||
801 | size_t len; | ||
802 | struct scatterlist *sg; | ||
803 | }; | ||
804 | |||
805 | static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | ||
806 | struct splice_desc *sd) | ||
807 | { | ||
808 | struct sg_list *sgl = sd->u.data; | ||
809 | unsigned int offset, len; | ||
810 | |||
811 | if (sgl->n == sgl->size) | ||
812 | return 0; | ||
813 | |||
814 | /* Try lock this page */ | ||
815 | if (buf->ops->steal(pipe, buf) == 0) { | ||
816 | /* Get reference and unlock page for moving */ | ||
817 | get_page(buf->page); | ||
818 | unlock_page(buf->page); | ||
819 | |||
820 | len = min(buf->len, sd->len); | ||
821 | sg_set_page(&(sgl->sg[sgl->n]), buf->page, len, buf->offset); | ||
822 | } else { | ||
823 | /* Failback to copying a page */ | ||
824 | struct page *page = alloc_page(GFP_KERNEL); | ||
825 | char *src = buf->ops->map(pipe, buf, 1); | ||
826 | char *dst; | ||
827 | |||
828 | if (!page) | ||
829 | return -ENOMEM; | ||
830 | dst = kmap(page); | ||
831 | |||
832 | offset = sd->pos & ~PAGE_MASK; | ||
833 | |||
834 | len = sd->len; | ||
835 | if (len + offset > PAGE_SIZE) | ||
836 | len = PAGE_SIZE - offset; | ||
837 | |||
838 | memcpy(dst + offset, src + buf->offset, len); | ||
839 | |||
840 | kunmap(page); | ||
841 | buf->ops->unmap(pipe, buf, src); | ||
842 | |||
843 | sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); | ||
844 | } | ||
845 | sgl->n++; | ||
846 | sgl->len += len; | ||
847 | |||
848 | return len; | ||
849 | } | ||
850 | |||
851 | /* Faster zero-copy write by splicing */ | ||
852 | static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, | ||
853 | struct file *filp, loff_t *ppos, | ||
854 | size_t len, unsigned int flags) | ||
855 | { | ||
856 | struct port *port = filp->private_data; | ||
857 | struct sg_list sgl; | ||
858 | ssize_t ret; | ||
859 | struct splice_desc sd = { | ||
860 | .total_len = len, | ||
861 | .flags = flags, | ||
862 | .pos = *ppos, | ||
863 | .u.data = &sgl, | ||
864 | }; | ||
865 | |||
866 | ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK); | ||
867 | if (ret < 0) | ||
868 | return ret; | ||
869 | |||
870 | sgl.n = 0; | ||
871 | sgl.len = 0; | ||
872 | sgl.size = pipe->nrbufs; | ||
873 | sgl.sg = kmalloc(sizeof(struct scatterlist) * sgl.size, GFP_KERNEL); | ||
874 | if (unlikely(!sgl.sg)) | ||
875 | return -ENOMEM; | ||
876 | |||
877 | sg_init_table(sgl.sg, sgl.size); | ||
878 | ret = __splice_from_pipe(pipe, &sd, pipe_to_sg); | ||
879 | if (likely(ret > 0)) | ||
880 | ret = send_pages(port, sgl.sg, sgl.n, sgl.len, true); | ||
881 | |||
882 | return ret; | ||
883 | } | ||
884 | |||
728 | static unsigned int port_fops_poll(struct file *filp, poll_table *wait) | 885 | static unsigned int port_fops_poll(struct file *filp, poll_table *wait) |
729 | { | 886 | { |
730 | struct port *port; | 887 | struct port *port; |
@@ -856,6 +1013,7 @@ static const struct file_operations port_fops = { | |||
856 | .open = port_fops_open, | 1013 | .open = port_fops_open, |
857 | .read = port_fops_read, | 1014 | .read = port_fops_read, |
858 | .write = port_fops_write, | 1015 | .write = port_fops_write, |
1016 | .splice_write = port_fops_splice_write, | ||
859 | .poll = port_fops_poll, | 1017 | .poll = port_fops_poll, |
860 | .release = port_fops_release, | 1018 | .release = port_fops_release, |
861 | .fasync = port_fops_fasync, | 1019 | .fasync = port_fops_fasync, |
@@ -1941,7 +2099,17 @@ static int __init init(void) | |||
1941 | INIT_LIST_HEAD(&pdrvdata.consoles); | 2099 | INIT_LIST_HEAD(&pdrvdata.consoles); |
1942 | INIT_LIST_HEAD(&pdrvdata.portdevs); | 2100 | INIT_LIST_HEAD(&pdrvdata.portdevs); |
1943 | 2101 | ||
1944 | return register_virtio_driver(&virtio_console); | 2102 | err = register_virtio_driver(&virtio_console); |
2103 | if (err < 0) { | ||
2104 | pr_err("Error %d registering virtio driver\n", err); | ||
2105 | goto free; | ||
2106 | } | ||
2107 | return 0; | ||
2108 | free: | ||
2109 | if (pdrvdata.debugfs_dir) | ||
2110 | debugfs_remove_recursive(pdrvdata.debugfs_dir); | ||
2111 | class_destroy(pdrvdata.class); | ||
2112 | return err; | ||
1945 | } | 2113 | } |
1946 | 2114 | ||
1947 | static void __exit fini(void) | 2115 | static void __exit fini(void) |