diff options
135 files changed, 8217 insertions, 1867 deletions
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index ac3d0018140..ddb05e98af0 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl | |||
@@ -719,6 +719,62 @@ framework to set up sysfs files for this region. Simply leave it alone. | |||
719 | </para> | 719 | </para> |
720 | </sect1> | 720 | </sect1> |
721 | 721 | ||
722 | <sect1 id="using uio_dmem_genirq"> | ||
723 | <title>Using uio_dmem_genirq for platform devices</title> | ||
724 | <para> | ||
725 | In addition to statically allocated memory ranges, they may also be | ||
726 | a desire to use dynamically allocated regions in a user space driver. | ||
727 | In particular, being able to access memory made available through the | ||
728 | dma-mapping API, may be particularly useful. The | ||
729 | <varname>uio_dmem_genirq</varname> driver provides a way to accomplish | ||
730 | this. | ||
731 | </para> | ||
732 | <para> | ||
733 | This driver is used in a similar manner to the | ||
734 | <varname>"uio_pdrv_genirq"</varname> driver with respect to interrupt | ||
735 | configuration and handling. | ||
736 | </para> | ||
737 | <para> | ||
738 | Set the <varname>.name</varname> element of | ||
739 | <varname>struct platform_device</varname> to | ||
740 | <varname>"uio_dmem_genirq"</varname> to use this driver. | ||
741 | </para> | ||
742 | <para> | ||
743 | When using this driver, fill in the <varname>.platform_data</varname> | ||
744 | element of <varname>struct platform_device</varname>, which is of type | ||
745 | <varname>struct uio_dmem_genirq_pdata</varname> and which contains the | ||
746 | following elements: | ||
747 | </para> | ||
748 | <itemizedlist> | ||
749 | <listitem><varname>struct uio_info uioinfo</varname>: The same | ||
750 | structure used as the <varname>uio_pdrv_genirq</varname> platform | ||
751 | data</listitem> | ||
752 | <listitem><varname>unsigned int *dynamic_region_sizes</varname>: | ||
753 | Pointer to list of sizes of dynamic memory regions to be mapped into | ||
754 | user space. | ||
755 | </listitem> | ||
756 | <listitem><varname>unsigned int num_dynamic_regions</varname>: | ||
757 | Number of elements in <varname>dynamic_region_sizes</varname> array. | ||
758 | </listitem> | ||
759 | </itemizedlist> | ||
760 | <para> | ||
761 | The dynamic regions defined in the platform data will be appended to | ||
762 | the <varname> mem[] </varname> array after the platform device | ||
763 | resources, which implies that the total number of static and dynamic | ||
764 | memory regions cannot exceed <varname>MAX_UIO_MAPS</varname>. | ||
765 | </para> | ||
766 | <para> | ||
767 | The dynamic memory regions will be allocated when the UIO device file, | ||
768 | <varname>/dev/uioX</varname> is opened. | ||
769 | Simiar to static memory resources, the memory region information for | ||
770 | dynamic regions is then visible via sysfs at | ||
771 | <varname>/sys/class/uio/uioX/maps/mapY/*</varname>. | ||
772 | The dynmaic memory regions will be freed when the UIO device file is | ||
773 | closed. When no processes are holding the device file open, the address | ||
774 | returned to userspace is ~0. | ||
775 | </para> | ||
776 | </sect1> | ||
777 | |||
722 | </chapter> | 778 | </chapter> |
723 | 779 | ||
724 | <chapter id="userspace_driver" xreflabel="Writing a driver in user space"> | 780 | <chapter id="userspace_driver" xreflabel="Writing a driver in user space"> |
diff --git a/MAINTAINERS b/MAINTAINERS index cf7ff78f019..e360784991f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -3596,7 +3596,6 @@ S: Maintained | |||
3596 | F: drivers/hv/ | 3596 | F: drivers/hv/ |
3597 | F: drivers/hid/hid-hyperv.c | 3597 | F: drivers/hid/hid-hyperv.c |
3598 | F: drivers/net/hyperv/ | 3598 | F: drivers/net/hyperv/ |
3599 | F: drivers/staging/hv/ | ||
3600 | 3599 | ||
3601 | I2C OVER PARALLEL PORT | 3600 | I2C OVER PARALLEL PORT |
3602 | M: Jean Delvare <khali@linux-fr.org> | 3601 | M: Jean Delvare <khali@linux-fr.org> |
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 42f042ee4ad..652b56086de 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h | |||
@@ -374,7 +374,7 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr); | |||
374 | 374 | ||
375 | #ifdef CONFIG_MMU | 375 | #ifdef CONFIG_MMU |
376 | #define ARCH_HAS_VALID_PHYS_ADDR_RANGE | 376 | #define ARCH_HAS_VALID_PHYS_ADDR_RANGE |
377 | extern int valid_phys_addr_range(unsigned long addr, size_t size); | 377 | extern int valid_phys_addr_range(phys_addr_t addr, size_t size); |
378 | extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); | 378 | extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); |
379 | extern int devmem_is_allowed(unsigned long pfn); | 379 | extern int devmem_is_allowed(unsigned long pfn); |
380 | #endif | 380 | #endif |
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index ce8cb1970d7..89f2b7f7b04 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c | |||
@@ -279,7 +279,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm) | |||
279 | * You really shouldn't be using read() or write() on /dev/mem. This | 279 | * You really shouldn't be using read() or write() on /dev/mem. This |
280 | * might go away in the future. | 280 | * might go away in the future. |
281 | */ | 281 | */ |
282 | int valid_phys_addr_range(unsigned long addr, size_t size) | 282 | int valid_phys_addr_range(phys_addr_t addr, size_t size) |
283 | { | 283 | { |
284 | if (addr < PHYS_OFFSET) | 284 | if (addr < PHYS_OFFSET) |
285 | return 0; | 285 | return 0; |
diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h index 2c26321c28c..74a7cc3293b 100644 --- a/arch/ia64/include/asm/io.h +++ b/arch/ia64/include/asm/io.h | |||
@@ -90,7 +90,7 @@ phys_to_virt (unsigned long address) | |||
90 | 90 | ||
91 | #define ARCH_HAS_VALID_PHYS_ADDR_RANGE | 91 | #define ARCH_HAS_VALID_PHYS_ADDR_RANGE |
92 | extern u64 kern_mem_attribute (unsigned long phys_addr, unsigned long size); | 92 | extern u64 kern_mem_attribute (unsigned long phys_addr, unsigned long size); |
93 | extern int valid_phys_addr_range (unsigned long addr, size_t count); /* efi.c */ | 93 | extern int valid_phys_addr_range (phys_addr_t addr, size_t count); /* efi.c */ |
94 | extern int valid_mmap_phys_addr_range (unsigned long pfn, size_t count); | 94 | extern int valid_mmap_phys_addr_range (unsigned long pfn, size_t count); |
95 | 95 | ||
96 | /* | 96 | /* |
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index d37bbd48637..f034563aeae 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c | |||
@@ -870,7 +870,7 @@ kern_mem_attribute (unsigned long phys_addr, unsigned long size) | |||
870 | EXPORT_SYMBOL(kern_mem_attribute); | 870 | EXPORT_SYMBOL(kern_mem_attribute); |
871 | 871 | ||
872 | int | 872 | int |
873 | valid_phys_addr_range (unsigned long phys_addr, unsigned long size) | 873 | valid_phys_addr_range (phys_addr_t phys_addr, unsigned long size) |
874 | { | 874 | { |
875 | u64 attr; | 875 | u64 attr; |
876 | 876 | ||
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 73a23f4617a..629db2ad791 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h | |||
@@ -382,7 +382,7 @@ static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; } | |||
382 | #define xlate_dev_kmem_ptr(p) p | 382 | #define xlate_dev_kmem_ptr(p) p |
383 | 383 | ||
384 | #define ARCH_HAS_VALID_PHYS_ADDR_RANGE | 384 | #define ARCH_HAS_VALID_PHYS_ADDR_RANGE |
385 | int valid_phys_addr_range(unsigned long addr, size_t size); | 385 | int valid_phys_addr_range(phys_addr_t addr, size_t size); |
386 | int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); | 386 | int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); |
387 | 387 | ||
388 | #endif /* __KERNEL__ */ | 388 | #endif /* __KERNEL__ */ |
diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index afeb710ec5c..80bf494ddbc 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c | |||
@@ -238,7 +238,7 @@ bottomup: | |||
238 | * You really shouldn't be using read() or write() on /dev/mem. This | 238 | * You really shouldn't be using read() or write() on /dev/mem. This |
239 | * might go away in the future. | 239 | * might go away in the future. |
240 | */ | 240 | */ |
241 | int valid_phys_addr_range(unsigned long addr, size_t count) | 241 | int valid_phys_addr_range(phys_addr_t addr, size_t count) |
242 | { | 242 | { |
243 | if (addr < __MEMORY_START) | 243 | if (addr < __MEMORY_START) |
244 | return 0; | 244 | return 0; |
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index fd793519ea2..478493543b3 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c | |||
@@ -249,7 +249,7 @@ static const struct agp_bridge_driver ali_m1541_bridge = { | |||
249 | }; | 249 | }; |
250 | 250 | ||
251 | 251 | ||
252 | static struct agp_device_ids ali_agp_device_ids[] __devinitdata = | 252 | static struct agp_device_ids ali_agp_device_ids[] = |
253 | { | 253 | { |
254 | { | 254 | { |
255 | .device_id = PCI_DEVICE_ID_AL_M1541, | 255 | .device_id = PCI_DEVICE_ID_AL_M1541, |
@@ -374,7 +374,7 @@ found: | |||
374 | return agp_add_bridge(bridge); | 374 | return agp_add_bridge(bridge); |
375 | } | 375 | } |
376 | 376 | ||
377 | static void __devexit agp_ali_remove(struct pci_dev *pdev) | 377 | static void agp_ali_remove(struct pci_dev *pdev) |
378 | { | 378 | { |
379 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 379 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
380 | 380 | ||
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index f7e88787af9..1b2101160e9 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c | |||
@@ -388,7 +388,7 @@ static const struct agp_bridge_driver amd_irongate_driver = { | |||
388 | .agp_type_to_mask_type = agp_generic_type_to_mask_type, | 388 | .agp_type_to_mask_type = agp_generic_type_to_mask_type, |
389 | }; | 389 | }; |
390 | 390 | ||
391 | static struct agp_device_ids amd_agp_device_ids[] __devinitdata = | 391 | static struct agp_device_ids amd_agp_device_ids[] = |
392 | { | 392 | { |
393 | { | 393 | { |
394 | .device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006, | 394 | .device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006, |
@@ -480,7 +480,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, | |||
480 | return agp_add_bridge(bridge); | 480 | return agp_add_bridge(bridge); |
481 | } | 481 | } |
482 | 482 | ||
483 | static void __devexit agp_amdk7_remove(struct pci_dev *pdev) | 483 | static void agp_amdk7_remove(struct pci_dev *pdev) |
484 | { | 484 | { |
485 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 485 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
486 | 486 | ||
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 444f8b6ab41..061d46209b1 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c | |||
@@ -579,7 +579,7 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev, | |||
579 | return 0; | 579 | return 0; |
580 | } | 580 | } |
581 | 581 | ||
582 | static void __devexit agp_amd64_remove(struct pci_dev *pdev) | 582 | static void agp_amd64_remove(struct pci_dev *pdev) |
583 | { | 583 | { |
584 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 584 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
585 | 585 | ||
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index dc30e224349..ed0433576e7 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c | |||
@@ -445,7 +445,7 @@ static const struct agp_bridge_driver ati_generic_bridge = { | |||
445 | }; | 445 | }; |
446 | 446 | ||
447 | 447 | ||
448 | static struct agp_device_ids ati_agp_device_ids[] __devinitdata = | 448 | static struct agp_device_ids ati_agp_device_ids[] = |
449 | { | 449 | { |
450 | { | 450 | { |
451 | .device_id = PCI_DEVICE_ID_ATI_RS100, | 451 | .device_id = PCI_DEVICE_ID_ATI_RS100, |
@@ -533,7 +533,7 @@ found: | |||
533 | return agp_add_bridge(bridge); | 533 | return agp_add_bridge(bridge); |
534 | } | 534 | } |
535 | 535 | ||
536 | static void __devexit agp_ati_remove(struct pci_dev *pdev) | 536 | static void agp_ati_remove(struct pci_dev *pdev) |
537 | { | 537 | { |
538 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 538 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
539 | 539 | ||
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index d607f53d8af..55f3e33a309 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c | |||
@@ -407,7 +407,7 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, | |||
407 | return agp_add_bridge(bridge); | 407 | return agp_add_bridge(bridge); |
408 | } | 408 | } |
409 | 409 | ||
410 | static void __devexit agp_efficeon_remove(struct pci_dev *pdev) | 410 | static void agp_efficeon_remove(struct pci_dev *pdev) |
411 | { | 411 | { |
412 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 412 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
413 | 413 | ||
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 75b763cb3ea..d328b662e50 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c | |||
@@ -611,7 +611,7 @@ static int __devinit agp_intel_i460_probe(struct pci_dev *pdev, | |||
611 | return agp_add_bridge(bridge); | 611 | return agp_add_bridge(bridge); |
612 | } | 612 | } |
613 | 613 | ||
614 | static void __devexit agp_intel_i460_remove(struct pci_dev *pdev) | 614 | static void agp_intel_i460_remove(struct pci_dev *pdev) |
615 | { | 615 | { |
616 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 616 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
617 | 617 | ||
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index b130df0a195..f3a8f52b5a0 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c | |||
@@ -819,7 +819,7 @@ found_gmch: | |||
819 | return err; | 819 | return err; |
820 | } | 820 | } |
821 | 821 | ||
822 | static void __devexit agp_intel_remove(struct pci_dev *pdev) | 822 | static void agp_intel_remove(struct pci_dev *pdev) |
823 | { | 823 | { |
824 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 824 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
825 | 825 | ||
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index b9734a97818..66e0868000f 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c | |||
@@ -388,7 +388,7 @@ static int __devinit agp_nvidia_probe(struct pci_dev *pdev, | |||
388 | return agp_add_bridge(bridge); | 388 | return agp_add_bridge(bridge); |
389 | } | 389 | } |
390 | 390 | ||
391 | static void __devexit agp_nvidia_remove(struct pci_dev *pdev) | 391 | static void agp_nvidia_remove(struct pci_dev *pdev) |
392 | { | 392 | { |
393 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 393 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
394 | 394 | ||
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 3a5af2f9b01..a18791d7718 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c | |||
@@ -327,7 +327,7 @@ static int __devinit agp_sgi_init(void) | |||
327 | return 0; | 327 | return 0; |
328 | } | 328 | } |
329 | 329 | ||
330 | static void __devexit agp_sgi_cleanup(void) | 330 | static void agp_sgi_cleanup(void) |
331 | { | 331 | { |
332 | kfree(sgi_tioca_agp_bridges); | 332 | kfree(sgi_tioca_agp_bridges); |
333 | sgi_tioca_agp_bridges = NULL; | 333 | sgi_tioca_agp_bridges = NULL; |
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 08704ae5395..93d1d31f9d0 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c | |||
@@ -17,8 +17,8 @@ | |||
17 | #define PCI_DEVICE_ID_SI_662 0x0662 | 17 | #define PCI_DEVICE_ID_SI_662 0x0662 |
18 | #define PCI_DEVICE_ID_SI_671 0x0671 | 18 | #define PCI_DEVICE_ID_SI_671 0x0671 |
19 | 19 | ||
20 | static bool __devinitdata agp_sis_force_delay = 0; | 20 | static bool agp_sis_force_delay = 0; |
21 | static int __devinitdata agp_sis_agp_spec = -1; | 21 | static int agp_sis_agp_spec = -1; |
22 | 22 | ||
23 | static int sis_fetch_size(void) | 23 | static int sis_fetch_size(void) |
24 | { | 24 | { |
@@ -148,7 +148,7 @@ static struct agp_bridge_driver sis_driver = { | |||
148 | }; | 148 | }; |
149 | 149 | ||
150 | // chipsets that require the 'delay hack' | 150 | // chipsets that require the 'delay hack' |
151 | static int sis_broken_chipsets[] __devinitdata = { | 151 | static int sis_broken_chipsets[] = { |
152 | PCI_DEVICE_ID_SI_648, | 152 | PCI_DEVICE_ID_SI_648, |
153 | PCI_DEVICE_ID_SI_746, | 153 | PCI_DEVICE_ID_SI_746, |
154 | 0 // terminator | 154 | 0 // terminator |
@@ -211,7 +211,7 @@ static int __devinit agp_sis_probe(struct pci_dev *pdev, | |||
211 | return agp_add_bridge(bridge); | 211 | return agp_add_bridge(bridge); |
212 | } | 212 | } |
213 | 213 | ||
214 | static void __devexit agp_sis_remove(struct pci_dev *pdev) | 214 | static void agp_sis_remove(struct pci_dev *pdev) |
215 | { | 215 | { |
216 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 216 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
217 | 217 | ||
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index f02f9b07fd4..26020fb8d7a 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c | |||
@@ -518,7 +518,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, | |||
518 | return agp_add_bridge(bridge); | 518 | return agp_add_bridge(bridge); |
519 | } | 519 | } |
520 | 520 | ||
521 | static void __devexit agp_serverworks_remove(struct pci_dev *pdev) | 521 | static void agp_serverworks_remove(struct pci_dev *pdev) |
522 | { | 522 | { |
523 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 523 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
524 | 524 | ||
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index a32c492baf5..011967ad3ee 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c | |||
@@ -557,7 +557,7 @@ const struct agp_bridge_driver u3_agp_driver = { | |||
557 | .needs_scratch_page = true, | 557 | .needs_scratch_page = true, |
558 | }; | 558 | }; |
559 | 559 | ||
560 | static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = { | 560 | static struct agp_device_ids uninorth_agp_device_ids[] = { |
561 | { | 561 | { |
562 | .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP, | 562 | .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP, |
563 | .chipset_name = "UniNorth", | 563 | .chipset_name = "UniNorth", |
@@ -663,7 +663,7 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, | |||
663 | return agp_add_bridge(bridge); | 663 | return agp_add_bridge(bridge); |
664 | } | 664 | } |
665 | 665 | ||
666 | static void __devexit agp_uninorth_remove(struct pci_dev *pdev) | 666 | static void agp_uninorth_remove(struct pci_dev *pdev) |
667 | { | 667 | { |
668 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 668 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
669 | 669 | ||
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 8bc38493740..6818595bb86 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c | |||
@@ -224,7 +224,7 @@ static const struct agp_bridge_driver via_driver = { | |||
224 | .agp_type_to_mask_type = agp_generic_type_to_mask_type, | 224 | .agp_type_to_mask_type = agp_generic_type_to_mask_type, |
225 | }; | 225 | }; |
226 | 226 | ||
227 | static struct agp_device_ids via_agp_device_ids[] __devinitdata = | 227 | static struct agp_device_ids via_agp_device_ids[] = |
228 | { | 228 | { |
229 | { | 229 | { |
230 | .device_id = PCI_DEVICE_ID_VIA_82C597_0, | 230 | .device_id = PCI_DEVICE_ID_VIA_82C597_0, |
@@ -485,7 +485,7 @@ static int __devinit agp_via_probe(struct pci_dev *pdev, | |||
485 | return agp_add_bridge(bridge); | 485 | return agp_add_bridge(bridge); |
486 | } | 486 | } |
487 | 487 | ||
488 | static void __devexit agp_via_remove(struct pci_dev *pdev) | 488 | static void agp_via_remove(struct pci_dev *pdev) |
489 | { | 489 | { |
490 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 490 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
491 | 491 | ||
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index dfd7876f127..fe6d4be4829 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -816,7 +816,7 @@ static unsigned long __hpet_calibrate(struct hpets *hpetp) | |||
816 | 816 | ||
817 | static unsigned long hpet_calibrate(struct hpets *hpetp) | 817 | static unsigned long hpet_calibrate(struct hpets *hpetp) |
818 | { | 818 | { |
819 | unsigned long ret = -1; | 819 | unsigned long ret = ~0UL; |
820 | unsigned long tmp; | 820 | unsigned long tmp; |
821 | 821 | ||
822 | /* | 822 | /* |
@@ -1001,6 +1001,9 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) | |||
1001 | irqp = &res->data.extended_irq; | 1001 | irqp = &res->data.extended_irq; |
1002 | 1002 | ||
1003 | for (i = 0; i < irqp->interrupt_count; i++) { | 1003 | for (i = 0; i < irqp->interrupt_count; i++) { |
1004 | if (hdp->hd_nirqs >= HPET_MAX_TIMERS) | ||
1005 | break; | ||
1006 | |||
1004 | irq = acpi_register_gsi(NULL, irqp->interrupts[i], | 1007 | irq = acpi_register_gsi(NULL, irqp->interrupts[i], |
1005 | irqp->triggering, irqp->polarity); | 1008 | irqp->triggering, irqp->polarity); |
1006 | if (irq < 0) | 1009 | if (irq < 0) |
diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index 731c9046cf7..5a4a6e70478 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c | |||
@@ -98,7 +98,7 @@ err_enable: | |||
98 | return ret; | 98 | return ret; |
99 | } | 99 | } |
100 | 100 | ||
101 | static int __devexit atmel_trng_remove(struct platform_device *pdev) | 101 | static int atmel_trng_remove(struct platform_device *pdev) |
102 | { | 102 | { |
103 | struct atmel_trng *trng = platform_get_drvdata(pdev); | 103 | struct atmel_trng *trng = platform_get_drvdata(pdev); |
104 | 104 | ||
diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c index aec6a4277ca..ae95bcb18d4 100644 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ b/drivers/char/hw_random/bcm63xx-rng.c | |||
@@ -145,7 +145,7 @@ out: | |||
145 | return ret; | 145 | return ret; |
146 | } | 146 | } |
147 | 147 | ||
148 | static int __devexit bcm63xx_rng_remove(struct platform_device *pdev) | 148 | static int bcm63xx_rng_remove(struct platform_device *pdev) |
149 | { | 149 | { |
150 | struct hwrng *rng = platform_get_drvdata(pdev); | 150 | struct hwrng *rng = platform_get_drvdata(pdev); |
151 | struct bcm63xx_rng_priv *priv = to_rng_priv(rng); | 151 | struct bcm63xx_rng_priv *priv = to_rng_priv(rng); |
diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index 232ba9ce579..bdc852ea763 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c | |||
@@ -134,7 +134,7 @@ static int __devinit exynos_rng_probe(struct platform_device *pdev) | |||
134 | return hwrng_register(&exynos_rng->rng); | 134 | return hwrng_register(&exynos_rng->rng); |
135 | } | 135 | } |
136 | 136 | ||
137 | static int __devexit exynos_rng_remove(struct platform_device *pdev) | 137 | static int exynos_rng_remove(struct platform_device *pdev) |
138 | { | 138 | { |
139 | struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); | 139 | struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); |
140 | 140 | ||
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index ebd48f0135d..d68a72a08b5 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #define DRV_MODULE_VERSION "0.2" | 25 | #define DRV_MODULE_VERSION "0.2" |
26 | #define DRV_MODULE_RELDATE "July 27, 2011" | 26 | #define DRV_MODULE_RELDATE "July 27, 2011" |
27 | 27 | ||
28 | static char version[] __devinitdata = | 28 | static char version[] = |
29 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | 29 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; |
30 | 30 | ||
31 | MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); | 31 | MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); |
@@ -719,7 +719,7 @@ out: | |||
719 | return err; | 719 | return err; |
720 | } | 720 | } |
721 | 721 | ||
722 | static int __devexit n2rng_remove(struct platform_device *op) | 722 | static int n2rng_remove(struct platform_device *op) |
723 | { | 723 | { |
724 | struct n2rng *np = dev_get_drvdata(&op->dev); | 724 | struct n2rng *np = dev_get_drvdata(&op->dev); |
725 | 725 | ||
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index 3a632673aed..a1f70407cc9 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c | |||
@@ -122,7 +122,7 @@ static int __devinit rng_probe(struct platform_device *ofdev) | |||
122 | return err; | 122 | return err; |
123 | } | 123 | } |
124 | 124 | ||
125 | static int __devexit rng_remove(struct platform_device *dev) | 125 | static int rng_remove(struct platform_device *dev) |
126 | { | 126 | { |
127 | void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv; | 127 | void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv; |
128 | 128 | ||
diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c index 97bd891422c..d4b24c1dd48 100644 --- a/drivers/char/hw_random/picoxcell-rng.c +++ b/drivers/char/hw_random/picoxcell-rng.c | |||
@@ -151,7 +151,7 @@ err_enable: | |||
151 | return ret; | 151 | return ret; |
152 | } | 152 | } |
153 | 153 | ||
154 | static int __devexit picoxcell_trng_remove(struct platform_device *pdev) | 154 | static int picoxcell_trng_remove(struct platform_device *pdev) |
155 | { | 155 | { |
156 | hwrng_unregister(&picoxcell_trng); | 156 | hwrng_unregister(&picoxcell_trng); |
157 | clk_disable(rng_clk); | 157 | clk_disable(rng_clk); |
diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c index c51762c1303..af6506a69cd 100644 --- a/drivers/char/hw_random/ppc4xx-rng.c +++ b/drivers/char/hw_random/ppc4xx-rng.c | |||
@@ -111,7 +111,7 @@ static int __devinit ppc4xx_rng_probe(struct platform_device *dev) | |||
111 | return err; | 111 | return err; |
112 | } | 112 | } |
113 | 113 | ||
114 | static int __devexit ppc4xx_rng_remove(struct platform_device *dev) | 114 | static int ppc4xx_rng_remove(struct platform_device *dev) |
115 | { | 115 | { |
116 | void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv; | 116 | void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv; |
117 | 117 | ||
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index f1a1618db1f..3a1abc9417e 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c | |||
@@ -130,7 +130,7 @@ failed: | |||
130 | return ret; | 130 | return ret; |
131 | } | 131 | } |
132 | 132 | ||
133 | static int __devexit timeriomem_rng_remove(struct platform_device *pdev) | 133 | static int timeriomem_rng_remove(struct platform_device *pdev) |
134 | { | 134 | { |
135 | del_timer_sync(&timeriomem_rng_timer); | 135 | del_timer_sync(&timeriomem_rng_timer); |
136 | hwrng_unregister(&timeriomem_rng_ops); | 136 | hwrng_unregister(&timeriomem_rng_ops); |
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 5708299507d..621f595f1a9 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c | |||
@@ -119,7 +119,7 @@ static int virtrng_probe(struct virtio_device *vdev) | |||
119 | return probe_common(vdev); | 119 | return probe_common(vdev); |
120 | } | 120 | } |
121 | 121 | ||
122 | static void __devexit virtrng_remove(struct virtio_device *vdev) | 122 | static void virtrng_remove(struct virtio_device *vdev) |
123 | { | 123 | { |
124 | remove_common(vdev); | 124 | remove_common(vdev); |
125 | } | 125 | } |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 32a6c7e256b..20ab5b3a891 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -1836,7 +1836,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) | |||
1836 | return rv; | 1836 | return rv; |
1837 | } | 1837 | } |
1838 | 1838 | ||
1839 | static int __devinit hardcode_find_bmc(void) | 1839 | static int hardcode_find_bmc(void) |
1840 | { | 1840 | { |
1841 | int ret = -ENODEV; | 1841 | int ret = -ENODEV; |
1842 | int i; | 1842 | int i; |
@@ -2023,7 +2023,7 @@ struct SPMITable { | |||
2023 | s8 spmi_id[1]; /* A '\0' terminated array starts here. */ | 2023 | s8 spmi_id[1]; /* A '\0' terminated array starts here. */ |
2024 | }; | 2024 | }; |
2025 | 2025 | ||
2026 | static int __devinit try_init_spmi(struct SPMITable *spmi) | 2026 | static int try_init_spmi(struct SPMITable *spmi) |
2027 | { | 2027 | { |
2028 | struct smi_info *info; | 2028 | struct smi_info *info; |
2029 | 2029 | ||
@@ -2106,7 +2106,7 @@ static int __devinit try_init_spmi(struct SPMITable *spmi) | |||
2106 | return 0; | 2106 | return 0; |
2107 | } | 2107 | } |
2108 | 2108 | ||
2109 | static void __devinit spmi_find_bmc(void) | 2109 | static void spmi_find_bmc(void) |
2110 | { | 2110 | { |
2111 | acpi_status status; | 2111 | acpi_status status; |
2112 | struct SPMITable *spmi; | 2112 | struct SPMITable *spmi; |
@@ -2128,7 +2128,7 @@ static void __devinit spmi_find_bmc(void) | |||
2128 | } | 2128 | } |
2129 | } | 2129 | } |
2130 | 2130 | ||
2131 | static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, | 2131 | static int ipmi_pnp_probe(struct pnp_dev *dev, |
2132 | const struct pnp_device_id *dev_id) | 2132 | const struct pnp_device_id *dev_id) |
2133 | { | 2133 | { |
2134 | struct acpi_device *acpi_dev; | 2134 | struct acpi_device *acpi_dev; |
@@ -2228,7 +2228,7 @@ err_free: | |||
2228 | return -EINVAL; | 2228 | return -EINVAL; |
2229 | } | 2229 | } |
2230 | 2230 | ||
2231 | static void __devexit ipmi_pnp_remove(struct pnp_dev *dev) | 2231 | static void ipmi_pnp_remove(struct pnp_dev *dev) |
2232 | { | 2232 | { |
2233 | struct smi_info *info = pnp_get_drvdata(dev); | 2233 | struct smi_info *info = pnp_get_drvdata(dev); |
2234 | 2234 | ||
@@ -2258,7 +2258,7 @@ struct dmi_ipmi_data { | |||
2258 | u8 slave_addr; | 2258 | u8 slave_addr; |
2259 | }; | 2259 | }; |
2260 | 2260 | ||
2261 | static int __devinit decode_dmi(const struct dmi_header *dm, | 2261 | static int decode_dmi(const struct dmi_header *dm, |
2262 | struct dmi_ipmi_data *dmi) | 2262 | struct dmi_ipmi_data *dmi) |
2263 | { | 2263 | { |
2264 | const u8 *data = (const u8 *)dm; | 2264 | const u8 *data = (const u8 *)dm; |
@@ -2320,7 +2320,7 @@ static int __devinit decode_dmi(const struct dmi_header *dm, | |||
2320 | return 0; | 2320 | return 0; |
2321 | } | 2321 | } |
2322 | 2322 | ||
2323 | static void __devinit try_init_dmi(struct dmi_ipmi_data *ipmi_data) | 2323 | static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) |
2324 | { | 2324 | { |
2325 | struct smi_info *info; | 2325 | struct smi_info *info; |
2326 | 2326 | ||
@@ -2388,7 +2388,7 @@ static void __devinit try_init_dmi(struct dmi_ipmi_data *ipmi_data) | |||
2388 | kfree(info); | 2388 | kfree(info); |
2389 | } | 2389 | } |
2390 | 2390 | ||
2391 | static void __devinit dmi_find_bmc(void) | 2391 | static void dmi_find_bmc(void) |
2392 | { | 2392 | { |
2393 | const struct dmi_device *dev = NULL; | 2393 | const struct dmi_device *dev = NULL; |
2394 | struct dmi_ipmi_data data; | 2394 | struct dmi_ipmi_data data; |
@@ -2424,7 +2424,7 @@ 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) | 2427 | static int ipmi_pci_probe_regspacing(struct smi_info *info) |
2428 | { | 2428 | { |
2429 | if (info->si_type == SI_KCS) { | 2429 | if (info->si_type == SI_KCS) { |
2430 | unsigned char status; | 2430 | unsigned char status; |
@@ -2456,7 +2456,7 @@ static int __devinit ipmi_pci_probe_regspacing(struct smi_info *info) | |||
2456 | return DEFAULT_REGSPACING; | 2456 | return DEFAULT_REGSPACING; |
2457 | } | 2457 | } |
2458 | 2458 | ||
2459 | static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | 2459 | static int ipmi_pci_probe(struct pci_dev *pdev, |
2460 | const struct pci_device_id *ent) | 2460 | const struct pci_device_id *ent) |
2461 | { | 2461 | { |
2462 | int rv; | 2462 | int rv; |
@@ -2529,7 +2529,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | |||
2529 | return 0; | 2529 | return 0; |
2530 | } | 2530 | } |
2531 | 2531 | ||
2532 | static void __devexit ipmi_pci_remove(struct pci_dev *pdev) | 2532 | static void ipmi_pci_remove(struct pci_dev *pdev) |
2533 | { | 2533 | { |
2534 | struct smi_info *info = pci_get_drvdata(pdev); | 2534 | struct smi_info *info = pci_get_drvdata(pdev); |
2535 | cleanup_one_si(info); | 2535 | cleanup_one_si(info); |
@@ -2551,7 +2551,7 @@ static struct pci_driver ipmi_pci_driver = { | |||
2551 | #endif /* CONFIG_PCI */ | 2551 | #endif /* CONFIG_PCI */ |
2552 | 2552 | ||
2553 | static struct of_device_id ipmi_match[]; | 2553 | static struct of_device_id ipmi_match[]; |
2554 | static int __devinit ipmi_probe(struct platform_device *dev) | 2554 | static int ipmi_probe(struct platform_device *dev) |
2555 | { | 2555 | { |
2556 | #ifdef CONFIG_OF | 2556 | #ifdef CONFIG_OF |
2557 | const struct of_device_id *match; | 2557 | const struct of_device_id *match; |
@@ -2635,7 +2635,7 @@ static int __devinit ipmi_probe(struct platform_device *dev) | |||
2635 | return 0; | 2635 | return 0; |
2636 | } | 2636 | } |
2637 | 2637 | ||
2638 | static int __devexit ipmi_remove(struct platform_device *dev) | 2638 | static int ipmi_remove(struct platform_device *dev) |
2639 | { | 2639 | { |
2640 | #ifdef CONFIG_OF | 2640 | #ifdef CONFIG_OF |
2641 | cleanup_one_si(dev_get_drvdata(&dev->dev)); | 2641 | cleanup_one_si(dev_get_drvdata(&dev->dev)); |
@@ -3047,7 +3047,7 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info) | |||
3047 | } | 3047 | } |
3048 | } | 3048 | } |
3049 | 3049 | ||
3050 | static __devinitdata struct ipmi_default_vals | 3050 | static struct ipmi_default_vals |
3051 | { | 3051 | { |
3052 | int type; | 3052 | int type; |
3053 | int port; | 3053 | int port; |
@@ -3059,7 +3059,7 @@ static __devinitdata struct ipmi_default_vals | |||
3059 | { .port = 0 } | 3059 | { .port = 0 } |
3060 | }; | 3060 | }; |
3061 | 3061 | ||
3062 | static void __devinit default_find_bmc(void) | 3062 | static void default_find_bmc(void) |
3063 | { | 3063 | { |
3064 | struct smi_info *info; | 3064 | struct smi_info *info; |
3065 | int i; | 3065 | int i; |
@@ -3359,7 +3359,7 @@ static int try_smi_init(struct smi_info *new_smi) | |||
3359 | return rv; | 3359 | return rv; |
3360 | } | 3360 | } |
3361 | 3361 | ||
3362 | static int __devinit init_ipmi_si(void) | 3362 | static int init_ipmi_si(void) |
3363 | { | 3363 | { |
3364 | int i; | 3364 | int i; |
3365 | char *str; | 3365 | char *str; |
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index f74e892711d..e5d3e3f7a49 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c | |||
@@ -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 __devinitconst mbcs_id_table[] = { | 802 | static const struct cx_device_id 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 0537903c985..c6fa3bc2baa 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -48,7 +48,7 @@ static inline unsigned long size_inside_page(unsigned long start, | |||
48 | } | 48 | } |
49 | 49 | ||
50 | #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE | 50 | #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE |
51 | static inline int valid_phys_addr_range(unsigned long addr, size_t count) | 51 | static inline int valid_phys_addr_range(phys_addr_t addr, size_t count) |
52 | { | 52 | { |
53 | return addr + count <= __pa(high_memory); | 53 | return addr + count <= __pa(high_memory); |
54 | } | 54 | } |
@@ -96,7 +96,7 @@ void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr) | |||
96 | static ssize_t read_mem(struct file *file, char __user *buf, | 96 | static ssize_t read_mem(struct file *file, char __user *buf, |
97 | size_t count, loff_t *ppos) | 97 | size_t count, loff_t *ppos) |
98 | { | 98 | { |
99 | unsigned long p = *ppos; | 99 | phys_addr_t p = *ppos; |
100 | ssize_t read, sz; | 100 | ssize_t read, sz; |
101 | char *ptr; | 101 | char *ptr; |
102 | 102 | ||
@@ -153,7 +153,7 @@ static ssize_t read_mem(struct file *file, char __user *buf, | |||
153 | static ssize_t write_mem(struct file *file, const char __user *buf, | 153 | static ssize_t write_mem(struct file *file, const char __user *buf, |
154 | size_t count, loff_t *ppos) | 154 | size_t count, loff_t *ppos) |
155 | { | 155 | { |
156 | unsigned long p = *ppos; | 156 | phys_addr_t p = *ppos; |
157 | ssize_t written, sz; | 157 | ssize_t written, sz; |
158 | unsigned long copied; | 158 | unsigned long copied; |
159 | void *ptr; | 159 | void *ptr; |
@@ -226,7 +226,7 @@ int __weak phys_mem_access_prot_allowed(struct file *file, | |||
226 | * | 226 | * |
227 | */ | 227 | */ |
228 | #ifdef pgprot_noncached | 228 | #ifdef pgprot_noncached |
229 | static int uncached_access(struct file *file, unsigned long addr) | 229 | static int uncached_access(struct file *file, phys_addr_t addr) |
230 | { | 230 | { |
231 | #if defined(CONFIG_IA64) | 231 | #if defined(CONFIG_IA64) |
232 | /* | 232 | /* |
@@ -258,7 +258,7 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, | |||
258 | unsigned long size, pgprot_t vma_prot) | 258 | unsigned long size, pgprot_t vma_prot) |
259 | { | 259 | { |
260 | #ifdef pgprot_noncached | 260 | #ifdef pgprot_noncached |
261 | unsigned long offset = pfn << PAGE_SHIFT; | 261 | phys_addr_t offset = pfn << PAGE_SHIFT; |
262 | 262 | ||
263 | if (uncached_access(file, offset)) | 263 | if (uncached_access(file, offset)) |
264 | return pgprot_noncached(vma_prot); | 264 | return pgprot_noncached(vma_prot); |
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index b304ec05250..3f79a9fb6b1 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c | |||
@@ -345,8 +345,7 @@ static void __exit pc8736x_gpio_cleanup(void) | |||
345 | unregister_chrdev_region(MKDEV(major,0), PC8736X_GPIO_CT); | 345 | unregister_chrdev_region(MKDEV(major,0), PC8736X_GPIO_CT); |
346 | release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE); | 346 | release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE); |
347 | 347 | ||
348 | platform_device_del(pdev); | 348 | platform_device_unregister(pdev); |
349 | platform_device_put(pdev); | ||
350 | } | 349 | } |
351 | 350 | ||
352 | module_init(pc8736x_gpio_init); | 351 | module_init(pc8736x_gpio_init); |
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index 6abdde4da2b..588063ac951 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c | |||
@@ -363,7 +363,7 @@ static struct miscdevice ps3flash_misc = { | |||
363 | .fops = &ps3flash_fops, | 363 | .fops = &ps3flash_fops, |
364 | }; | 364 | }; |
365 | 365 | ||
366 | static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) | 366 | static int ps3flash_probe(struct ps3_system_bus_device *_dev) |
367 | { | 367 | { |
368 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | 368 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); |
369 | struct ps3flash_private *priv; | 369 | struct ps3flash_private *priv; |
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 9b4f0116ff2..d780295a147 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c | |||
@@ -1164,7 +1164,7 @@ static struct acpi_driver sonypi_acpi_driver = { | |||
1164 | }; | 1164 | }; |
1165 | #endif | 1165 | #endif |
1166 | 1166 | ||
1167 | static int __devinit sonypi_create_input_devices(struct platform_device *pdev) | 1167 | static int sonypi_create_input_devices(struct platform_device *pdev) |
1168 | { | 1168 | { |
1169 | struct input_dev *jog_dev; | 1169 | struct input_dev *jog_dev; |
1170 | struct input_dev *key_dev; | 1170 | struct input_dev *key_dev; |
@@ -1225,7 +1225,7 @@ static int __devinit sonypi_create_input_devices(struct platform_device *pdev) | |||
1225 | return error; | 1225 | return error; |
1226 | } | 1226 | } |
1227 | 1227 | ||
1228 | static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, | 1228 | static int sonypi_setup_ioports(struct sonypi_device *dev, |
1229 | const struct sonypi_ioport_list *ioport_list) | 1229 | const struct sonypi_ioport_list *ioport_list) |
1230 | { | 1230 | { |
1231 | /* try to detect if sony-laptop is being used and thus | 1231 | /* try to detect if sony-laptop is being used and thus |
@@ -1265,7 +1265,7 @@ static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, | |||
1265 | return -EBUSY; | 1265 | return -EBUSY; |
1266 | } | 1266 | } |
1267 | 1267 | ||
1268 | static int __devinit sonypi_setup_irq(struct sonypi_device *dev, | 1268 | static int sonypi_setup_irq(struct sonypi_device *dev, |
1269 | const struct sonypi_irq_list *irq_list) | 1269 | const struct sonypi_irq_list *irq_list) |
1270 | { | 1270 | { |
1271 | while (irq_list->irq) { | 1271 | while (irq_list->irq) { |
@@ -1282,7 +1282,7 @@ static int __devinit sonypi_setup_irq(struct sonypi_device *dev, | |||
1282 | return -EBUSY; | 1282 | return -EBUSY; |
1283 | } | 1283 | } |
1284 | 1284 | ||
1285 | static void __devinit sonypi_display_info(void) | 1285 | static void sonypi_display_info(void) |
1286 | { | 1286 | { |
1287 | printk(KERN_INFO "sonypi: detected type%d model, " | 1287 | printk(KERN_INFO "sonypi: detected type%d model, " |
1288 | "verbose = %d, fnkeyinit = %s, camera = %s, " | 1288 | "verbose = %d, fnkeyinit = %s, camera = %s, " |
@@ -1304,7 +1304,7 @@ static void __devinit sonypi_display_info(void) | |||
1304 | sonypi_misc_device.minor); | 1304 | sonypi_misc_device.minor); |
1305 | } | 1305 | } |
1306 | 1306 | ||
1307 | static int __devinit sonypi_probe(struct platform_device *dev) | 1307 | static int sonypi_probe(struct platform_device *dev) |
1308 | { | 1308 | { |
1309 | const struct sonypi_ioport_list *ioport_list; | 1309 | const struct sonypi_ioport_list *ioport_list; |
1310 | const struct sonypi_irq_list *irq_list; | 1310 | const struct sonypi_irq_list *irq_list; |
@@ -1428,7 +1428,7 @@ static int __devinit sonypi_probe(struct platform_device *dev) | |||
1428 | return error; | 1428 | return error; |
1429 | } | 1429 | } |
1430 | 1430 | ||
1431 | static int __devexit sonypi_remove(struct platform_device *dev) | 1431 | static int sonypi_remove(struct platform_device *dev) |
1432 | { | 1432 | { |
1433 | sonypi_disable(); | 1433 | sonypi_disable(); |
1434 | 1434 | ||
@@ -1491,7 +1491,7 @@ static struct platform_driver sonypi_driver = { | |||
1491 | .pm = SONYPI_PM, | 1491 | .pm = SONYPI_PM, |
1492 | }, | 1492 | }, |
1493 | .probe = sonypi_probe, | 1493 | .probe = sonypi_probe, |
1494 | .remove = __devexit_p(sonypi_remove), | 1494 | .remove = sonypi_remove, |
1495 | .shutdown = sonypi_shutdown, | 1495 | .shutdown = sonypi_shutdown, |
1496 | }; | 1496 | }; |
1497 | 1497 | ||
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index ad264185eb1..34c63f85104 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c | |||
@@ -284,7 +284,7 @@ static void tb0219_pci_irq_init(void) | |||
284 | vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW); | 284 | vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW); |
285 | } | 285 | } |
286 | 286 | ||
287 | static int __devinit tb0219_probe(struct platform_device *dev) | 287 | static int tb0219_probe(struct platform_device *dev) |
288 | { | 288 | { |
289 | int retval; | 289 | int retval; |
290 | 290 | ||
@@ -318,7 +318,7 @@ static int __devinit tb0219_probe(struct platform_device *dev) | |||
318 | return 0; | 318 | return 0; |
319 | } | 319 | } |
320 | 320 | ||
321 | static int __devexit tb0219_remove(struct platform_device *dev) | 321 | static int tb0219_remove(struct platform_device *dev) |
322 | { | 322 | { |
323 | _machine_restart = old_machine_restart; | 323 | _machine_restart = old_machine_restart; |
324 | 324 | ||
@@ -334,7 +334,7 @@ static struct platform_device *tb0219_platform_device; | |||
334 | 334 | ||
335 | static struct platform_driver tb0219_device_driver = { | 335 | static struct platform_driver tb0219_device_driver = { |
336 | .probe = tb0219_probe, | 336 | .probe = tb0219_probe, |
337 | .remove = __devexit_p(tb0219_remove), | 337 | .remove = tb0219_remove, |
338 | .driver = { | 338 | .driver = { |
339 | .name = "TB0219", | 339 | .name = "TB0219", |
340 | .owner = THIS_MODULE, | 340 | .owner = THIS_MODULE, |
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index bcdb078c1b8..fb447bd0cb6 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c | |||
@@ -656,7 +656,7 @@ static int tpm_tis_i2c_probe(struct i2c_client *client, | |||
656 | return rc; | 656 | return rc; |
657 | } | 657 | } |
658 | 658 | ||
659 | static int __devexit tpm_tis_i2c_remove(struct i2c_client *client) | 659 | static int tpm_tis_i2c_remove(struct i2c_client *client) |
660 | { | 660 | { |
661 | struct tpm_chip *chip = tpm_dev.chip; | 661 | struct tpm_chip *chip = tpm_dev.chip; |
662 | release_locality(chip, chip->vendor.locality, 1); | 662 | release_locality(chip, chip->vendor.locality, 1); |
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index d9ba6157da9..7da840d487d 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm"; | 33 | static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm"; |
34 | 34 | ||
35 | static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = { | 35 | static struct vio_device_id tpm_ibmvtpm_device_table[] = { |
36 | { "IBM,vtpm", "IBM,vtpm"}, | 36 | { "IBM,vtpm", "IBM,vtpm"}, |
37 | { "", "" } | 37 | { "", "" } |
38 | }; | 38 | }; |
@@ -267,7 +267,7 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) | |||
267 | * Return value: | 267 | * Return value: |
268 | * 0 | 268 | * 0 |
269 | */ | 269 | */ |
270 | static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev) | 270 | static int tpm_ibmvtpm_remove(struct vio_dev *vdev) |
271 | { | 271 | { |
272 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); | 272 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); |
273 | int rc = 0; | 273 | int rc = 0; |
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 0126e809867..2b480c2960b 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c | |||
@@ -594,7 +594,7 @@ err_last: | |||
594 | return rc; | 594 | return rc; |
595 | } | 595 | } |
596 | 596 | ||
597 | static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) | 597 | static void tpm_inf_pnp_remove(struct pnp_dev *dev) |
598 | { | 598 | { |
599 | struct tpm_chip *chip = pnp_get_drvdata(dev); | 599 | struct tpm_chip *chip = pnp_get_drvdata(dev); |
600 | 600 | ||
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 253161c302b..ea31dafbcac 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
@@ -769,7 +769,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) | |||
769 | return ret; | 769 | return ret; |
770 | } | 770 | } |
771 | 771 | ||
772 | static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { | 772 | static struct pnp_device_id tpm_pnp_tbl[] = { |
773 | {"PNP0C31", 0}, /* TPM */ | 773 | {"PNP0C31", 0}, /* TPM */ |
774 | {"ATM1200", 0}, /* Atmel */ | 774 | {"ATM1200", 0}, /* Atmel */ |
775 | {"IFX0102", 0}, /* Infineon */ | 775 | {"IFX0102", 0}, /* Infineon */ |
@@ -783,7 +783,7 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { | |||
783 | }; | 783 | }; |
784 | MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); | 784 | MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); |
785 | 785 | ||
786 | static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev) | 786 | static void tpm_tis_pnp_remove(struct pnp_dev *dev) |
787 | { | 787 | { |
788 | struct tpm_chip *chip = pnp_get_drvdata(dev); | 788 | struct tpm_chip *chip = pnp_get_drvdata(dev); |
789 | 789 | ||
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8ab9c3d4bf1..90493d4ead1 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -1846,7 +1846,7 @@ static void remove_controlq_data(struct ports_device *portdev) | |||
1846 | * config space to see how many ports the host has spawned. We | 1846 | * config space to see how many ports the host has spawned. We |
1847 | * initialize each port found. | 1847 | * initialize each port found. |
1848 | */ | 1848 | */ |
1849 | static int __devinit virtcons_probe(struct virtio_device *vdev) | 1849 | static int virtcons_probe(struct virtio_device *vdev) |
1850 | { | 1850 | { |
1851 | struct ports_device *portdev; | 1851 | struct ports_device *portdev; |
1852 | int err; | 1852 | int err; |
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 2c5d15beea3..5224da5202d 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c | |||
@@ -595,7 +595,7 @@ static const struct file_operations hwicap_fops = { | |||
595 | .llseek = noop_llseek, | 595 | .llseek = noop_llseek, |
596 | }; | 596 | }; |
597 | 597 | ||
598 | static int __devinit hwicap_setup(struct device *dev, int id, | 598 | static int hwicap_setup(struct device *dev, int id, |
599 | const struct resource *regs_res, | 599 | const struct resource *regs_res, |
600 | const struct hwicap_driver_config *config, | 600 | const struct hwicap_driver_config *config, |
601 | const struct config_registers *config_regs) | 601 | const struct config_registers *config_regs) |
@@ -717,7 +717,7 @@ static struct hwicap_driver_config fifo_icap_config = { | |||
717 | .reset = fifo_icap_reset, | 717 | .reset = fifo_icap_reset, |
718 | }; | 718 | }; |
719 | 719 | ||
720 | static int __devexit hwicap_remove(struct device *dev) | 720 | static int hwicap_remove(struct device *dev) |
721 | { | 721 | { |
722 | struct hwicap_drvdata *drvdata; | 722 | struct hwicap_drvdata *drvdata; |
723 | 723 | ||
@@ -740,7 +740,7 @@ static int __devexit hwicap_remove(struct device *dev) | |||
740 | } | 740 | } |
741 | 741 | ||
742 | #ifdef CONFIG_OF | 742 | #ifdef CONFIG_OF |
743 | static int __devinit hwicap_of_probe(struct platform_device *op, | 743 | static int hwicap_of_probe(struct platform_device *op, |
744 | const struct hwicap_driver_config *config) | 744 | const struct hwicap_driver_config *config) |
745 | { | 745 | { |
746 | struct resource res; | 746 | struct resource res; |
@@ -785,8 +785,8 @@ static inline int hwicap_of_probe(struct platform_device *op, | |||
785 | } | 785 | } |
786 | #endif /* CONFIG_OF */ | 786 | #endif /* CONFIG_OF */ |
787 | 787 | ||
788 | static const struct of_device_id __devinitconst hwicap_of_match[]; | 788 | static const struct of_device_id hwicap_of_match[]; |
789 | static int __devinit hwicap_drv_probe(struct platform_device *pdev) | 789 | static int hwicap_drv_probe(struct platform_device *pdev) |
790 | { | 790 | { |
791 | const struct of_device_id *match; | 791 | const struct of_device_id *match; |
792 | struct resource *res; | 792 | struct resource *res; |
@@ -822,14 +822,14 @@ static int __devinit hwicap_drv_probe(struct platform_device *pdev) | |||
822 | &buffer_icap_config, regs); | 822 | &buffer_icap_config, regs); |
823 | } | 823 | } |
824 | 824 | ||
825 | static int __devexit hwicap_drv_remove(struct platform_device *pdev) | 825 | static int hwicap_drv_remove(struct platform_device *pdev) |
826 | { | 826 | { |
827 | return hwicap_remove(&pdev->dev); | 827 | return hwicap_remove(&pdev->dev); |
828 | } | 828 | } |
829 | 829 | ||
830 | #ifdef CONFIG_OF | 830 | #ifdef CONFIG_OF |
831 | /* Match table for device tree binding */ | 831 | /* Match table for device tree binding */ |
832 | static const struct of_device_id __devinitconst hwicap_of_match[] = { | 832 | static const struct of_device_id hwicap_of_match[] = { |
833 | { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config}, | 833 | { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config}, |
834 | { .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config}, | 834 | { .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config}, |
835 | {}, | 835 | {}, |
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index e87196f6d2d..eda2a1aa4ad 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c | |||
@@ -91,7 +91,7 @@ static irqreturn_t adc_jack_irq_thread(int irq, void *_data) | |||
91 | return IRQ_HANDLED; | 91 | return IRQ_HANDLED; |
92 | } | 92 | } |
93 | 93 | ||
94 | static int __devinit adc_jack_probe(struct platform_device *pdev) | 94 | static int adc_jack_probe(struct platform_device *pdev) |
95 | { | 95 | { |
96 | struct adc_jack_data *data; | 96 | struct adc_jack_data *data; |
97 | struct adc_jack_pdata *pdata = pdev->dev.platform_data; | 97 | struct adc_jack_pdata *pdata = pdev->dev.platform_data; |
@@ -175,7 +175,7 @@ out: | |||
175 | return err; | 175 | return err; |
176 | } | 176 | } |
177 | 177 | ||
178 | static int __devexit adc_jack_remove(struct platform_device *pdev) | 178 | static int adc_jack_remove(struct platform_device *pdev) |
179 | { | 179 | { |
180 | struct adc_jack_data *data = platform_get_drvdata(pdev); | 180 | struct adc_jack_data *data = platform_get_drvdata(pdev); |
181 | 181 | ||
@@ -188,7 +188,7 @@ static int __devexit adc_jack_remove(struct platform_device *pdev) | |||
188 | 188 | ||
189 | static struct platform_driver adc_jack_driver = { | 189 | static struct platform_driver adc_jack_driver = { |
190 | .probe = adc_jack_probe, | 190 | .probe = adc_jack_probe, |
191 | .remove = __devexit_p(adc_jack_remove), | 191 | .remove = adc_jack_remove, |
192 | .driver = { | 192 | .driver = { |
193 | .name = "adc-jack", | 193 | .name = "adc-jack", |
194 | .owner = THIS_MODULE, | 194 | .owner = THIS_MODULE, |
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index cdab9e59829..f10f05d4ee9 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c | |||
@@ -337,7 +337,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
337 | return IRQ_HANDLED; | 337 | return IRQ_HANDLED; |
338 | } | 338 | } |
339 | 339 | ||
340 | static int __devinit arizona_extcon_probe(struct platform_device *pdev) | 340 | static int arizona_extcon_probe(struct platform_device *pdev) |
341 | { | 341 | { |
342 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | 342 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); |
343 | struct arizona_pdata *pdata; | 343 | struct arizona_pdata *pdata; |
@@ -517,7 +517,7 @@ err: | |||
517 | return ret; | 517 | return ret; |
518 | } | 518 | } |
519 | 519 | ||
520 | static int __devexit arizona_extcon_remove(struct platform_device *pdev) | 520 | static int arizona_extcon_remove(struct platform_device *pdev) |
521 | { | 521 | { |
522 | struct arizona_extcon_info *info = platform_get_drvdata(pdev); | 522 | struct arizona_extcon_info *info = platform_get_drvdata(pdev); |
523 | struct arizona *arizona = info->arizona; | 523 | struct arizona *arizona = info->arizona; |
@@ -544,7 +544,7 @@ static struct platform_driver arizona_extcon_driver = { | |||
544 | .owner = THIS_MODULE, | 544 | .owner = THIS_MODULE, |
545 | }, | 545 | }, |
546 | .probe = arizona_extcon_probe, | 546 | .probe = arizona_extcon_probe, |
547 | .remove = __devexit_p(arizona_extcon_remove), | 547 | .remove = arizona_extcon_remove, |
548 | }; | 548 | }; |
549 | 549 | ||
550 | module_platform_driver(arizona_extcon_driver); | 550 | module_platform_driver(arizona_extcon_driver); |
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index 71d3ab7b3d8..1b14bfcdc17 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c | |||
@@ -76,7 +76,7 @@ static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf) | |||
76 | return -EINVAL; | 76 | return -EINVAL; |
77 | } | 77 | } |
78 | 78 | ||
79 | static int __devinit gpio_extcon_probe(struct platform_device *pdev) | 79 | static int gpio_extcon_probe(struct platform_device *pdev) |
80 | { | 80 | { |
81 | struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data; | 81 | struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data; |
82 | struct gpio_extcon_data *extcon_data; | 82 | struct gpio_extcon_data *extcon_data; |
@@ -137,7 +137,7 @@ err: | |||
137 | return ret; | 137 | return ret; |
138 | } | 138 | } |
139 | 139 | ||
140 | static int __devexit gpio_extcon_remove(struct platform_device *pdev) | 140 | static int gpio_extcon_remove(struct platform_device *pdev) |
141 | { | 141 | { |
142 | struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev); | 142 | struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev); |
143 | 143 | ||
@@ -150,7 +150,7 @@ static int __devexit gpio_extcon_remove(struct platform_device *pdev) | |||
150 | 150 | ||
151 | static struct platform_driver gpio_extcon_driver = { | 151 | static struct platform_driver gpio_extcon_driver = { |
152 | .probe = gpio_extcon_probe, | 152 | .probe = gpio_extcon_probe, |
153 | .remove = __devexit_p(gpio_extcon_remove), | 153 | .remove = gpio_extcon_remove, |
154 | .driver = { | 154 | .driver = { |
155 | .name = "extcon-gpio", | 155 | .name = "extcon-gpio", |
156 | .owner = THIS_MODULE, | 156 | .owner = THIS_MODULE, |
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index a17d0d91ada..b656dfa401a 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c | |||
@@ -648,7 +648,7 @@ out: | |||
648 | return ret; | 648 | return ret; |
649 | } | 649 | } |
650 | 650 | ||
651 | static int __devinit max77693_muic_probe(struct platform_device *pdev) | 651 | static int max77693_muic_probe(struct platform_device *pdev) |
652 | { | 652 | { |
653 | struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); | 653 | struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); |
654 | struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); | 654 | struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); |
@@ -774,7 +774,7 @@ err_kfree: | |||
774 | return ret; | 774 | return ret; |
775 | } | 775 | } |
776 | 776 | ||
777 | static int __devexit max77693_muic_remove(struct platform_device *pdev) | 777 | static int max77693_muic_remove(struct platform_device *pdev) |
778 | { | 778 | { |
779 | struct max77693_muic_info *info = platform_get_drvdata(pdev); | 779 | struct max77693_muic_info *info = platform_get_drvdata(pdev); |
780 | int i; | 780 | int i; |
@@ -795,7 +795,7 @@ static struct platform_driver max77693_muic_driver = { | |||
795 | .owner = THIS_MODULE, | 795 | .owner = THIS_MODULE, |
796 | }, | 796 | }, |
797 | .probe = max77693_muic_probe, | 797 | .probe = max77693_muic_probe, |
798 | .remove = __devexit_p(max77693_muic_remove), | 798 | .remove = max77693_muic_remove, |
799 | }; | 799 | }; |
800 | 800 | ||
801 | module_platform_driver(max77693_muic_driver); | 801 | module_platform_driver(max77693_muic_driver); |
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 77b66b0cc8f..bad76f51161 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c | |||
@@ -426,7 +426,7 @@ static void max8997_muic_detect_dev(struct max8997_muic_info *info) | |||
426 | max8997_muic_handle_charger_type(info, chg_type); | 426 | max8997_muic_handle_charger_type(info, chg_type); |
427 | } | 427 | } |
428 | 428 | ||
429 | static int __devinit max8997_muic_probe(struct platform_device *pdev) | 429 | static int max8997_muic_probe(struct platform_device *pdev) |
430 | { | 430 | { |
431 | struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); | 431 | struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); |
432 | struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev); | 432 | struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev); |
@@ -508,7 +508,7 @@ err_kfree: | |||
508 | return ret; | 508 | return ret; |
509 | } | 509 | } |
510 | 510 | ||
511 | static int __devexit max8997_muic_remove(struct platform_device *pdev) | 511 | static int max8997_muic_remove(struct platform_device *pdev) |
512 | { | 512 | { |
513 | struct max8997_muic_info *info = platform_get_drvdata(pdev); | 513 | struct max8997_muic_info *info = platform_get_drvdata(pdev); |
514 | int i; | 514 | int i; |
@@ -531,7 +531,7 @@ static struct platform_driver max8997_muic_driver = { | |||
531 | .owner = THIS_MODULE, | 531 | .owner = THIS_MODULE, |
532 | }, | 532 | }, |
533 | .probe = max8997_muic_probe, | 533 | .probe = max8997_muic_probe, |
534 | .remove = __devexit_p(max8997_muic_remove), | 534 | .remove = max8997_muic_remove, |
535 | }; | 535 | }; |
536 | 536 | ||
537 | module_platform_driver(max8997_muic_driver); | 537 | module_platform_driver(max8997_muic_driver); |
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 70f5dde1cc5..b38ef6d8d04 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig | |||
@@ -13,4 +13,10 @@ config HYPERV_UTILS | |||
13 | help | 13 | help |
14 | Select this option to enable the Hyper-V Utilities. | 14 | Select this option to enable the Hyper-V Utilities. |
15 | 15 | ||
16 | config HYPERV_BALLOON | ||
17 | tristate "Microsoft Hyper-V Balloon driver" | ||
18 | depends on HYPERV | ||
19 | help | ||
20 | Select this option to enable Hyper-V Balloon driver. | ||
21 | |||
16 | endmenu | 22 | endmenu |
diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile index a23938b991c..e6abfa02d8b 100644 --- a/drivers/hv/Makefile +++ b/drivers/hv/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | obj-$(CONFIG_HYPERV) += hv_vmbus.o | 1 | obj-$(CONFIG_HYPERV) += hv_vmbus.o |
2 | obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o | 2 | obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o |
3 | obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o | ||
3 | 4 | ||
4 | hv_vmbus-y := vmbus_drv.o \ | 5 | hv_vmbus-y := vmbus_drv.o \ |
5 | hv.o connection.o channel.o \ | 6 | hv.o connection.o channel.o \ |
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index f4c3d28cd1f..773a2f25a8f 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c | |||
@@ -33,14 +33,6 @@ | |||
33 | #define NUM_PAGES_SPANNED(addr, len) \ | 33 | #define NUM_PAGES_SPANNED(addr, len) \ |
34 | ((PAGE_ALIGN(addr + len) >> PAGE_SHIFT) - (addr >> PAGE_SHIFT)) | 34 | ((PAGE_ALIGN(addr + len) >> PAGE_SHIFT) - (addr >> PAGE_SHIFT)) |
35 | 35 | ||
36 | /* Internal routines */ | ||
37 | static int create_gpadl_header( | ||
38 | void *kbuffer, /* must be phys and virt contiguous */ | ||
39 | u32 size, /* page-size multiple */ | ||
40 | struct vmbus_channel_msginfo **msginfo, | ||
41 | u32 *messagecount); | ||
42 | static void vmbus_setevent(struct vmbus_channel *channel); | ||
43 | |||
44 | /* | 36 | /* |
45 | * vmbus_setevent- Trigger an event notification on the specified | 37 | * vmbus_setevent- Trigger an event notification on the specified |
46 | * channel. | 38 | * channel. |
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 2b8b8d4558d..2f84c5cff8d 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
@@ -265,14 +265,9 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) | |||
265 | { | 265 | { |
266 | struct vmbus_channel_offer_channel *offer; | 266 | struct vmbus_channel_offer_channel *offer; |
267 | struct vmbus_channel *newchannel; | 267 | struct vmbus_channel *newchannel; |
268 | uuid_le *guidtype; | ||
269 | uuid_le *guidinstance; | ||
270 | 268 | ||
271 | offer = (struct vmbus_channel_offer_channel *)hdr; | 269 | offer = (struct vmbus_channel_offer_channel *)hdr; |
272 | 270 | ||
273 | guidtype = &offer->offer.if_type; | ||
274 | guidinstance = &offer->offer.if_instance; | ||
275 | |||
276 | /* Allocate the channel object and save this offer. */ | 271 | /* Allocate the channel object and save this offer. */ |
277 | newchannel = alloc_channel(); | 272 | newchannel = alloc_channel(); |
278 | if (!newchannel) { | 273 | if (!newchannel) { |
@@ -470,7 +465,6 @@ static void vmbus_onversion_response( | |||
470 | { | 465 | { |
471 | struct vmbus_channel_msginfo *msginfo; | 466 | struct vmbus_channel_msginfo *msginfo; |
472 | struct vmbus_channel_message_header *requestheader; | 467 | struct vmbus_channel_message_header *requestheader; |
473 | struct vmbus_channel_initiate_contact *initiate; | ||
474 | struct vmbus_channel_version_response *version_response; | 468 | struct vmbus_channel_version_response *version_response; |
475 | unsigned long flags; | 469 | unsigned long flags; |
476 | 470 | ||
@@ -484,8 +478,6 @@ static void vmbus_onversion_response( | |||
484 | 478 | ||
485 | if (requestheader->msgtype == | 479 | if (requestheader->msgtype == |
486 | CHANNELMSG_INITIATE_CONTACT) { | 480 | CHANNELMSG_INITIATE_CONTACT) { |
487 | initiate = | ||
488 | (struct vmbus_channel_initiate_contact *)requestheader; | ||
489 | memcpy(&msginfo->response.version_response, | 481 | memcpy(&msginfo->response.version_response, |
490 | version_response, | 482 | version_response, |
491 | sizeof(struct vmbus_channel_version_response)); | 483 | sizeof(struct vmbus_channel_version_response)); |
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c new file mode 100644 index 00000000000..f6c0011a033 --- /dev/null +++ b/drivers/hv/hv_balloon.c | |||
@@ -0,0 +1,1041 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, Microsoft Corporation. | ||
3 | * | ||
4 | * Author: | ||
5 | * K. Y. Srinivasan <kys@microsoft.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published | ||
9 | * by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
14 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
15 | * details. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/mman.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/kthread.h> | ||
28 | #include <linux/completion.h> | ||
29 | #include <linux/memory_hotplug.h> | ||
30 | #include <linux/memory.h> | ||
31 | #include <linux/notifier.h> | ||
32 | #include <linux/mman.h> | ||
33 | #include <linux/percpu_counter.h> | ||
34 | |||
35 | #include <linux/hyperv.h> | ||
36 | |||
37 | /* | ||
38 | * We begin with definitions supporting the Dynamic Memory protocol | ||
39 | * with the host. | ||
40 | * | ||
41 | * Begin protocol definitions. | ||
42 | */ | ||
43 | |||
44 | |||
45 | |||
46 | /* | ||
47 | * Protocol versions. The low word is the minor version, the high word the major | ||
48 | * version. | ||
49 | * | ||
50 | * History: | ||
51 | * Initial version 1.0 | ||
52 | * Changed to 0.1 on 2009/03/25 | ||
53 | * Changes to 0.2 on 2009/05/14 | ||
54 | * Changes to 0.3 on 2009/12/03 | ||
55 | * Changed to 1.0 on 2011/04/05 | ||
56 | */ | ||
57 | |||
58 | #define DYNMEM_MAKE_VERSION(Major, Minor) ((__u32)(((Major) << 16) | (Minor))) | ||
59 | #define DYNMEM_MAJOR_VERSION(Version) ((__u32)(Version) >> 16) | ||
60 | #define DYNMEM_MINOR_VERSION(Version) ((__u32)(Version) & 0xff) | ||
61 | |||
62 | enum { | ||
63 | DYNMEM_PROTOCOL_VERSION_1 = DYNMEM_MAKE_VERSION(0, 3), | ||
64 | DYNMEM_PROTOCOL_VERSION_2 = DYNMEM_MAKE_VERSION(1, 0), | ||
65 | |||
66 | DYNMEM_PROTOCOL_VERSION_WIN7 = DYNMEM_PROTOCOL_VERSION_1, | ||
67 | DYNMEM_PROTOCOL_VERSION_WIN8 = DYNMEM_PROTOCOL_VERSION_2, | ||
68 | |||
69 | DYNMEM_PROTOCOL_VERSION_CURRENT = DYNMEM_PROTOCOL_VERSION_WIN8 | ||
70 | }; | ||
71 | |||
72 | |||
73 | |||
74 | /* | ||
75 | * Message Types | ||
76 | */ | ||
77 | |||
78 | enum dm_message_type { | ||
79 | /* | ||
80 | * Version 0.3 | ||
81 | */ | ||
82 | DM_ERROR = 0, | ||
83 | DM_VERSION_REQUEST = 1, | ||
84 | DM_VERSION_RESPONSE = 2, | ||
85 | DM_CAPABILITIES_REPORT = 3, | ||
86 | DM_CAPABILITIES_RESPONSE = 4, | ||
87 | DM_STATUS_REPORT = 5, | ||
88 | DM_BALLOON_REQUEST = 6, | ||
89 | DM_BALLOON_RESPONSE = 7, | ||
90 | DM_UNBALLOON_REQUEST = 8, | ||
91 | DM_UNBALLOON_RESPONSE = 9, | ||
92 | DM_MEM_HOT_ADD_REQUEST = 10, | ||
93 | DM_MEM_HOT_ADD_RESPONSE = 11, | ||
94 | DM_VERSION_03_MAX = 11, | ||
95 | /* | ||
96 | * Version 1.0. | ||
97 | */ | ||
98 | DM_INFO_MESSAGE = 12, | ||
99 | DM_VERSION_1_MAX = 12 | ||
100 | }; | ||
101 | |||
102 | |||
103 | /* | ||
104 | * Structures defining the dynamic memory management | ||
105 | * protocol. | ||
106 | */ | ||
107 | |||
108 | union dm_version { | ||
109 | struct { | ||
110 | __u16 minor_version; | ||
111 | __u16 major_version; | ||
112 | }; | ||
113 | __u32 version; | ||
114 | } __packed; | ||
115 | |||
116 | |||
117 | union dm_caps { | ||
118 | struct { | ||
119 | __u64 balloon:1; | ||
120 | __u64 hot_add:1; | ||
121 | __u64 reservedz:62; | ||
122 | } cap_bits; | ||
123 | __u64 caps; | ||
124 | } __packed; | ||
125 | |||
126 | union dm_mem_page_range { | ||
127 | struct { | ||
128 | /* | ||
129 | * The PFN number of the first page in the range. | ||
130 | * 40 bits is the architectural limit of a PFN | ||
131 | * number for AMD64. | ||
132 | */ | ||
133 | __u64 start_page:40; | ||
134 | /* | ||
135 | * The number of pages in the range. | ||
136 | */ | ||
137 | __u64 page_cnt:24; | ||
138 | } finfo; | ||
139 | __u64 page_range; | ||
140 | } __packed; | ||
141 | |||
142 | |||
143 | |||
144 | /* | ||
145 | * The header for all dynamic memory messages: | ||
146 | * | ||
147 | * type: Type of the message. | ||
148 | * size: Size of the message in bytes; including the header. | ||
149 | * trans_id: The guest is responsible for manufacturing this ID. | ||
150 | */ | ||
151 | |||
152 | struct dm_header { | ||
153 | __u16 type; | ||
154 | __u16 size; | ||
155 | __u32 trans_id; | ||
156 | } __packed; | ||
157 | |||
158 | /* | ||
159 | * A generic message format for dynamic memory. | ||
160 | * Specific message formats are defined later in the file. | ||
161 | */ | ||
162 | |||
163 | struct dm_message { | ||
164 | struct dm_header hdr; | ||
165 | __u8 data[]; /* enclosed message */ | ||
166 | } __packed; | ||
167 | |||
168 | |||
169 | /* | ||
170 | * Specific message types supporting the dynamic memory protocol. | ||
171 | */ | ||
172 | |||
173 | /* | ||
174 | * Version negotiation message. Sent from the guest to the host. | ||
175 | * The guest is free to try different versions until the host | ||
176 | * accepts the version. | ||
177 | * | ||
178 | * dm_version: The protocol version requested. | ||
179 | * is_last_attempt: If TRUE, this is the last version guest will request. | ||
180 | * reservedz: Reserved field, set to zero. | ||
181 | */ | ||
182 | |||
183 | struct dm_version_request { | ||
184 | struct dm_header hdr; | ||
185 | union dm_version version; | ||
186 | __u32 is_last_attempt:1; | ||
187 | __u32 reservedz:31; | ||
188 | } __packed; | ||
189 | |||
190 | /* | ||
191 | * Version response message; Host to Guest and indicates | ||
192 | * if the host has accepted the version sent by the guest. | ||
193 | * | ||
194 | * is_accepted: If TRUE, host has accepted the version and the guest | ||
195 | * should proceed to the next stage of the protocol. FALSE indicates that | ||
196 | * guest should re-try with a different version. | ||
197 | * | ||
198 | * reservedz: Reserved field, set to zero. | ||
199 | */ | ||
200 | |||
201 | struct dm_version_response { | ||
202 | struct dm_header hdr; | ||
203 | __u64 is_accepted:1; | ||
204 | __u64 reservedz:63; | ||
205 | } __packed; | ||
206 | |||
207 | /* | ||
208 | * Message reporting capabilities. This is sent from the guest to the | ||
209 | * host. | ||
210 | */ | ||
211 | |||
212 | struct dm_capabilities { | ||
213 | struct dm_header hdr; | ||
214 | union dm_caps caps; | ||
215 | __u64 min_page_cnt; | ||
216 | __u64 max_page_number; | ||
217 | } __packed; | ||
218 | |||
219 | /* | ||
220 | * Response to the capabilities message. This is sent from the host to the | ||
221 | * guest. This message notifies if the host has accepted the guest's | ||
222 | * capabilities. If the host has not accepted, the guest must shutdown | ||
223 | * the service. | ||
224 | * | ||
225 | * is_accepted: Indicates if the host has accepted guest's capabilities. | ||
226 | * reservedz: Must be 0. | ||
227 | */ | ||
228 | |||
229 | struct dm_capabilities_resp_msg { | ||
230 | struct dm_header hdr; | ||
231 | __u64 is_accepted:1; | ||
232 | __u64 reservedz:63; | ||
233 | } __packed; | ||
234 | |||
235 | /* | ||
236 | * This message is used to report memory pressure from the guest. | ||
237 | * This message is not part of any transaction and there is no | ||
238 | * response to this message. | ||
239 | * | ||
240 | * num_avail: Available memory in pages. | ||
241 | * num_committed: Committed memory in pages. | ||
242 | * page_file_size: The accumulated size of all page files | ||
243 | * in the system in pages. | ||
244 | * zero_free: The nunber of zero and free pages. | ||
245 | * page_file_writes: The writes to the page file in pages. | ||
246 | * io_diff: An indicator of file cache efficiency or page file activity, | ||
247 | * calculated as File Cache Page Fault Count - Page Read Count. | ||
248 | * This value is in pages. | ||
249 | * | ||
250 | * Some of these metrics are Windows specific and fortunately | ||
251 | * the algorithm on the host side that computes the guest memory | ||
252 | * pressure only uses num_committed value. | ||
253 | */ | ||
254 | |||
255 | struct dm_status { | ||
256 | struct dm_header hdr; | ||
257 | __u64 num_avail; | ||
258 | __u64 num_committed; | ||
259 | __u64 page_file_size; | ||
260 | __u64 zero_free; | ||
261 | __u32 page_file_writes; | ||
262 | __u32 io_diff; | ||
263 | } __packed; | ||
264 | |||
265 | |||
266 | /* | ||
267 | * Message to ask the guest to allocate memory - balloon up message. | ||
268 | * This message is sent from the host to the guest. The guest may not be | ||
269 | * able to allocate as much memory as requested. | ||
270 | * | ||
271 | * num_pages: number of pages to allocate. | ||
272 | */ | ||
273 | |||
274 | struct dm_balloon { | ||
275 | struct dm_header hdr; | ||
276 | __u32 num_pages; | ||
277 | __u32 reservedz; | ||
278 | } __packed; | ||
279 | |||
280 | |||
281 | /* | ||
282 | * Balloon response message; this message is sent from the guest | ||
283 | * to the host in response to the balloon message. | ||
284 | * | ||
285 | * reservedz: Reserved; must be set to zero. | ||
286 | * more_pages: If FALSE, this is the last message of the transaction. | ||
287 | * if TRUE there will atleast one more message from the guest. | ||
288 | * | ||
289 | * range_count: The number of ranges in the range array. | ||
290 | * | ||
291 | * range_array: An array of page ranges returned to the host. | ||
292 | * | ||
293 | */ | ||
294 | |||
295 | struct dm_balloon_response { | ||
296 | struct dm_header hdr; | ||
297 | __u32 reservedz; | ||
298 | __u32 more_pages:1; | ||
299 | __u32 range_count:31; | ||
300 | union dm_mem_page_range range_array[]; | ||
301 | } __packed; | ||
302 | |||
303 | /* | ||
304 | * Un-balloon message; this message is sent from the host | ||
305 | * to the guest to give guest more memory. | ||
306 | * | ||
307 | * more_pages: If FALSE, this is the last message of the transaction. | ||
308 | * if TRUE there will atleast one more message from the guest. | ||
309 | * | ||
310 | * reservedz: Reserved; must be set to zero. | ||
311 | * | ||
312 | * range_count: The number of ranges in the range array. | ||
313 | * | ||
314 | * range_array: An array of page ranges returned to the host. | ||
315 | * | ||
316 | */ | ||
317 | |||
318 | struct dm_unballoon_request { | ||
319 | struct dm_header hdr; | ||
320 | __u32 more_pages:1; | ||
321 | __u32 reservedz:31; | ||
322 | __u32 range_count; | ||
323 | union dm_mem_page_range range_array[]; | ||
324 | } __packed; | ||
325 | |||
326 | /* | ||
327 | * Un-balloon response message; this message is sent from the guest | ||
328 | * to the host in response to an unballoon request. | ||
329 | * | ||
330 | */ | ||
331 | |||
332 | struct dm_unballoon_response { | ||
333 | struct dm_header hdr; | ||
334 | } __packed; | ||
335 | |||
336 | |||
337 | /* | ||
338 | * Hot add request message. Message sent from the host to the guest. | ||
339 | * | ||
340 | * mem_range: Memory range to hot add. | ||
341 | * | ||
342 | * On Linux we currently don't support this since we cannot hot add | ||
343 | * arbitrary granularity of memory. | ||
344 | */ | ||
345 | |||
346 | struct dm_hot_add { | ||
347 | struct dm_header hdr; | ||
348 | union dm_mem_page_range range; | ||
349 | } __packed; | ||
350 | |||
351 | /* | ||
352 | * Hot add response message. | ||
353 | * This message is sent by the guest to report the status of a hot add request. | ||
354 | * If page_count is less than the requested page count, then the host should | ||
355 | * assume all further hot add requests will fail, since this indicates that | ||
356 | * the guest has hit an upper physical memory barrier. | ||
357 | * | ||
358 | * Hot adds may also fail due to low resources; in this case, the guest must | ||
359 | * not complete this message until the hot add can succeed, and the host must | ||
360 | * not send a new hot add request until the response is sent. | ||
361 | * If VSC fails to hot add memory DYNMEM_NUMBER_OF_UNSUCCESSFUL_HOTADD_ATTEMPTS | ||
362 | * times it fails the request. | ||
363 | * | ||
364 | * | ||
365 | * page_count: number of pages that were successfully hot added. | ||
366 | * | ||
367 | * result: result of the operation 1: success, 0: failure. | ||
368 | * | ||
369 | */ | ||
370 | |||
371 | struct dm_hot_add_response { | ||
372 | struct dm_header hdr; | ||
373 | __u32 page_count; | ||
374 | __u32 result; | ||
375 | } __packed; | ||
376 | |||
377 | /* | ||
378 | * Types of information sent from host to the guest. | ||
379 | */ | ||
380 | |||
381 | enum dm_info_type { | ||
382 | INFO_TYPE_MAX_PAGE_CNT = 0, | ||
383 | MAX_INFO_TYPE | ||
384 | }; | ||
385 | |||
386 | |||
387 | /* | ||
388 | * Header for the information message. | ||
389 | */ | ||
390 | |||
391 | struct dm_info_header { | ||
392 | enum dm_info_type type; | ||
393 | __u32 data_size; | ||
394 | } __packed; | ||
395 | |||
396 | /* | ||
397 | * This message is sent from the host to the guest to pass | ||
398 | * some relevant information (win8 addition). | ||
399 | * | ||
400 | * reserved: no used. | ||
401 | * info_size: size of the information blob. | ||
402 | * info: information blob. | ||
403 | */ | ||
404 | |||
405 | struct dm_info_msg { | ||
406 | struct dm_info_header header; | ||
407 | __u32 reserved; | ||
408 | __u32 info_size; | ||
409 | __u8 info[]; | ||
410 | }; | ||
411 | |||
412 | /* | ||
413 | * End protocol definitions. | ||
414 | */ | ||
415 | |||
416 | static bool hot_add; | ||
417 | static bool do_hot_add; | ||
418 | |||
419 | module_param(hot_add, bool, (S_IRUGO | S_IWUSR)); | ||
420 | MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add"); | ||
421 | |||
422 | static atomic_t trans_id = ATOMIC_INIT(0); | ||
423 | |||
424 | static int dm_ring_size = (5 * PAGE_SIZE); | ||
425 | |||
426 | /* | ||
427 | * Driver specific state. | ||
428 | */ | ||
429 | |||
430 | enum hv_dm_state { | ||
431 | DM_INITIALIZING = 0, | ||
432 | DM_INITIALIZED, | ||
433 | DM_BALLOON_UP, | ||
434 | DM_BALLOON_DOWN, | ||
435 | DM_HOT_ADD, | ||
436 | DM_INIT_ERROR | ||
437 | }; | ||
438 | |||
439 | |||
440 | static __u8 recv_buffer[PAGE_SIZE]; | ||
441 | static __u8 *send_buffer; | ||
442 | #define PAGES_IN_2M 512 | ||
443 | |||
444 | struct hv_dynmem_device { | ||
445 | struct hv_device *dev; | ||
446 | enum hv_dm_state state; | ||
447 | struct completion host_event; | ||
448 | struct completion config_event; | ||
449 | |||
450 | /* | ||
451 | * Number of pages we have currently ballooned out. | ||
452 | */ | ||
453 | unsigned int num_pages_ballooned; | ||
454 | |||
455 | /* | ||
456 | * This thread handles both balloon/hot-add | ||
457 | * requests from the host as well as notifying | ||
458 | * the host with regards to memory pressure in | ||
459 | * the guest. | ||
460 | */ | ||
461 | struct task_struct *thread; | ||
462 | |||
463 | /* | ||
464 | * We start with the highest version we can support | ||
465 | * and downgrade based on the host; we save here the | ||
466 | * next version to try. | ||
467 | */ | ||
468 | __u32 next_version; | ||
469 | }; | ||
470 | |||
471 | static struct hv_dynmem_device dm_device; | ||
472 | |||
473 | static void hot_add_req(struct hv_dynmem_device *dm, struct dm_hot_add *msg) | ||
474 | { | ||
475 | |||
476 | struct dm_hot_add_response resp; | ||
477 | |||
478 | if (do_hot_add) { | ||
479 | |||
480 | pr_info("Memory hot add not supported\n"); | ||
481 | |||
482 | /* | ||
483 | * Currently we do not support hot add. | ||
484 | * Just fail the request. | ||
485 | */ | ||
486 | } | ||
487 | |||
488 | memset(&resp, 0, sizeof(struct dm_hot_add_response)); | ||
489 | resp.hdr.type = DM_MEM_HOT_ADD_RESPONSE; | ||
490 | resp.hdr.size = sizeof(struct dm_hot_add_response); | ||
491 | resp.hdr.trans_id = atomic_inc_return(&trans_id); | ||
492 | |||
493 | resp.page_count = 0; | ||
494 | resp.result = 0; | ||
495 | |||
496 | dm->state = DM_INITIALIZED; | ||
497 | vmbus_sendpacket(dm->dev->channel, &resp, | ||
498 | sizeof(struct dm_hot_add_response), | ||
499 | (unsigned long)NULL, | ||
500 | VM_PKT_DATA_INBAND, 0); | ||
501 | |||
502 | } | ||
503 | |||
504 | static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg) | ||
505 | { | ||
506 | switch (msg->header.type) { | ||
507 | case INFO_TYPE_MAX_PAGE_CNT: | ||
508 | pr_info("Received INFO_TYPE_MAX_PAGE_CNT\n"); | ||
509 | pr_info("Data Size is %d\n", msg->header.data_size); | ||
510 | break; | ||
511 | default: | ||
512 | pr_info("Received Unknown type: %d\n", msg->header.type); | ||
513 | } | ||
514 | } | ||
515 | |||
516 | /* | ||
517 | * Post our status as it relates memory pressure to the | ||
518 | * host. Host expects the guests to post this status | ||
519 | * periodically at 1 second intervals. | ||
520 | * | ||
521 | * The metrics specified in this protocol are very Windows | ||
522 | * specific and so we cook up numbers here to convey our memory | ||
523 | * pressure. | ||
524 | */ | ||
525 | |||
526 | static void post_status(struct hv_dynmem_device *dm) | ||
527 | { | ||
528 | struct dm_status status; | ||
529 | |||
530 | |||
531 | memset(&status, 0, sizeof(struct dm_status)); | ||
532 | status.hdr.type = DM_STATUS_REPORT; | ||
533 | status.hdr.size = sizeof(struct dm_status); | ||
534 | status.hdr.trans_id = atomic_inc_return(&trans_id); | ||
535 | |||
536 | |||
537 | status.num_committed = vm_memory_committed(); | ||
538 | |||
539 | vmbus_sendpacket(dm->dev->channel, &status, | ||
540 | sizeof(struct dm_status), | ||
541 | (unsigned long)NULL, | ||
542 | VM_PKT_DATA_INBAND, 0); | ||
543 | |||
544 | } | ||
545 | |||
546 | |||
547 | |||
548 | static void free_balloon_pages(struct hv_dynmem_device *dm, | ||
549 | union dm_mem_page_range *range_array) | ||
550 | { | ||
551 | int num_pages = range_array->finfo.page_cnt; | ||
552 | __u64 start_frame = range_array->finfo.start_page; | ||
553 | struct page *pg; | ||
554 | int i; | ||
555 | |||
556 | for (i = 0; i < num_pages; i++) { | ||
557 | pg = pfn_to_page(i + start_frame); | ||
558 | __free_page(pg); | ||
559 | dm->num_pages_ballooned--; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | |||
564 | |||
565 | static int alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages, | ||
566 | struct dm_balloon_response *bl_resp, int alloc_unit, | ||
567 | bool *alloc_error) | ||
568 | { | ||
569 | int i = 0; | ||
570 | struct page *pg; | ||
571 | |||
572 | if (num_pages < alloc_unit) | ||
573 | return 0; | ||
574 | |||
575 | for (i = 0; (i * alloc_unit) < num_pages; i++) { | ||
576 | if (bl_resp->hdr.size + sizeof(union dm_mem_page_range) > | ||
577 | PAGE_SIZE) | ||
578 | return i * alloc_unit; | ||
579 | |||
580 | /* | ||
581 | * We execute this code in a thread context. Furthermore, | ||
582 | * we don't want the kernel to try too hard. | ||
583 | */ | ||
584 | pg = alloc_pages(GFP_HIGHUSER | __GFP_NORETRY | | ||
585 | __GFP_NOMEMALLOC | __GFP_NOWARN, | ||
586 | get_order(alloc_unit << PAGE_SHIFT)); | ||
587 | |||
588 | if (!pg) { | ||
589 | *alloc_error = true; | ||
590 | return i * alloc_unit; | ||
591 | } | ||
592 | |||
593 | |||
594 | dm->num_pages_ballooned += alloc_unit; | ||
595 | |||
596 | bl_resp->range_count++; | ||
597 | bl_resp->range_array[i].finfo.start_page = | ||
598 | page_to_pfn(pg); | ||
599 | bl_resp->range_array[i].finfo.page_cnt = alloc_unit; | ||
600 | bl_resp->hdr.size += sizeof(union dm_mem_page_range); | ||
601 | |||
602 | } | ||
603 | |||
604 | return num_pages; | ||
605 | } | ||
606 | |||
607 | |||
608 | |||
609 | static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req) | ||
610 | { | ||
611 | int num_pages = req->num_pages; | ||
612 | int num_ballooned = 0; | ||
613 | struct dm_balloon_response *bl_resp; | ||
614 | int alloc_unit; | ||
615 | int ret; | ||
616 | bool alloc_error = false; | ||
617 | bool done = false; | ||
618 | int i; | ||
619 | |||
620 | |||
621 | /* | ||
622 | * Currently, we only support 4k allocations. | ||
623 | */ | ||
624 | alloc_unit = 1; | ||
625 | |||
626 | while (!done) { | ||
627 | bl_resp = (struct dm_balloon_response *)send_buffer; | ||
628 | memset(send_buffer, 0, PAGE_SIZE); | ||
629 | bl_resp->hdr.type = DM_BALLOON_RESPONSE; | ||
630 | bl_resp->hdr.trans_id = atomic_inc_return(&trans_id); | ||
631 | bl_resp->hdr.size = sizeof(struct dm_balloon_response); | ||
632 | bl_resp->more_pages = 1; | ||
633 | |||
634 | |||
635 | num_pages -= num_ballooned; | ||
636 | num_ballooned = alloc_balloon_pages(dm, num_pages, | ||
637 | bl_resp, alloc_unit, | ||
638 | &alloc_error); | ||
639 | |||
640 | if ((alloc_error) || (num_ballooned == num_pages)) { | ||
641 | bl_resp->more_pages = 0; | ||
642 | done = true; | ||
643 | dm->state = DM_INITIALIZED; | ||
644 | } | ||
645 | |||
646 | /* | ||
647 | * We are pushing a lot of data through the channel; | ||
648 | * deal with transient failures caused because of the | ||
649 | * lack of space in the ring buffer. | ||
650 | */ | ||
651 | |||
652 | do { | ||
653 | ret = vmbus_sendpacket(dm_device.dev->channel, | ||
654 | bl_resp, | ||
655 | bl_resp->hdr.size, | ||
656 | (unsigned long)NULL, | ||
657 | VM_PKT_DATA_INBAND, 0); | ||
658 | |||
659 | if (ret == -EAGAIN) | ||
660 | msleep(20); | ||
661 | |||
662 | } while (ret == -EAGAIN); | ||
663 | |||
664 | if (ret) { | ||
665 | /* | ||
666 | * Free up the memory we allocatted. | ||
667 | */ | ||
668 | pr_info("Balloon response failed\n"); | ||
669 | |||
670 | for (i = 0; i < bl_resp->range_count; i++) | ||
671 | free_balloon_pages(dm, | ||
672 | &bl_resp->range_array[i]); | ||
673 | |||
674 | done = true; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | } | ||
679 | |||
680 | static void balloon_down(struct hv_dynmem_device *dm, | ||
681 | struct dm_unballoon_request *req) | ||
682 | { | ||
683 | union dm_mem_page_range *range_array = req->range_array; | ||
684 | int range_count = req->range_count; | ||
685 | struct dm_unballoon_response resp; | ||
686 | int i; | ||
687 | |||
688 | for (i = 0; i < range_count; i++) | ||
689 | free_balloon_pages(dm, &range_array[i]); | ||
690 | |||
691 | if (req->more_pages == 1) | ||
692 | return; | ||
693 | |||
694 | memset(&resp, 0, sizeof(struct dm_unballoon_response)); | ||
695 | resp.hdr.type = DM_UNBALLOON_RESPONSE; | ||
696 | resp.hdr.trans_id = atomic_inc_return(&trans_id); | ||
697 | resp.hdr.size = sizeof(struct dm_unballoon_response); | ||
698 | |||
699 | vmbus_sendpacket(dm_device.dev->channel, &resp, | ||
700 | sizeof(struct dm_unballoon_response), | ||
701 | (unsigned long)NULL, | ||
702 | VM_PKT_DATA_INBAND, 0); | ||
703 | |||
704 | dm->state = DM_INITIALIZED; | ||
705 | } | ||
706 | |||
707 | static void balloon_onchannelcallback(void *context); | ||
708 | |||
709 | static int dm_thread_func(void *dm_dev) | ||
710 | { | ||
711 | struct hv_dynmem_device *dm = dm_dev; | ||
712 | int t; | ||
713 | unsigned long scan_start; | ||
714 | |||
715 | while (!kthread_should_stop()) { | ||
716 | t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ); | ||
717 | /* | ||
718 | * The host expects us to post information on the memory | ||
719 | * pressure every second. | ||
720 | */ | ||
721 | |||
722 | if (t == 0) | ||
723 | post_status(dm); | ||
724 | |||
725 | scan_start = jiffies; | ||
726 | switch (dm->state) { | ||
727 | case DM_BALLOON_UP: | ||
728 | balloon_up(dm, (struct dm_balloon *)recv_buffer); | ||
729 | break; | ||
730 | |||
731 | case DM_HOT_ADD: | ||
732 | hot_add_req(dm, (struct dm_hot_add *)recv_buffer); | ||
733 | break; | ||
734 | default: | ||
735 | break; | ||
736 | } | ||
737 | |||
738 | if (!time_in_range(jiffies, scan_start, scan_start + HZ)) | ||
739 | post_status(dm); | ||
740 | |||
741 | } | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | |||
747 | static void version_resp(struct hv_dynmem_device *dm, | ||
748 | struct dm_version_response *vresp) | ||
749 | { | ||
750 | struct dm_version_request version_req; | ||
751 | int ret; | ||
752 | |||
753 | if (vresp->is_accepted) { | ||
754 | /* | ||
755 | * We are done; wakeup the | ||
756 | * context waiting for version | ||
757 | * negotiation. | ||
758 | */ | ||
759 | complete(&dm->host_event); | ||
760 | return; | ||
761 | } | ||
762 | /* | ||
763 | * If there are more versions to try, continue | ||
764 | * with negotiations; if not | ||
765 | * shutdown the service since we are not able | ||
766 | * to negotiate a suitable version number | ||
767 | * with the host. | ||
768 | */ | ||
769 | if (dm->next_version == 0) | ||
770 | goto version_error; | ||
771 | |||
772 | dm->next_version = 0; | ||
773 | memset(&version_req, 0, sizeof(struct dm_version_request)); | ||
774 | version_req.hdr.type = DM_VERSION_REQUEST; | ||
775 | version_req.hdr.size = sizeof(struct dm_version_request); | ||
776 | version_req.hdr.trans_id = atomic_inc_return(&trans_id); | ||
777 | version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN7; | ||
778 | version_req.is_last_attempt = 1; | ||
779 | |||
780 | ret = vmbus_sendpacket(dm->dev->channel, &version_req, | ||
781 | sizeof(struct dm_version_request), | ||
782 | (unsigned long)NULL, | ||
783 | VM_PKT_DATA_INBAND, 0); | ||
784 | |||
785 | if (ret) | ||
786 | goto version_error; | ||
787 | |||
788 | return; | ||
789 | |||
790 | version_error: | ||
791 | dm->state = DM_INIT_ERROR; | ||
792 | complete(&dm->host_event); | ||
793 | } | ||
794 | |||
795 | static void cap_resp(struct hv_dynmem_device *dm, | ||
796 | struct dm_capabilities_resp_msg *cap_resp) | ||
797 | { | ||
798 | if (!cap_resp->is_accepted) { | ||
799 | pr_info("Capabilities not accepted by host\n"); | ||
800 | dm->state = DM_INIT_ERROR; | ||
801 | } | ||
802 | complete(&dm->host_event); | ||
803 | } | ||
804 | |||
805 | static void balloon_onchannelcallback(void *context) | ||
806 | { | ||
807 | struct hv_device *dev = context; | ||
808 | u32 recvlen; | ||
809 | u64 requestid; | ||
810 | struct dm_message *dm_msg; | ||
811 | struct dm_header *dm_hdr; | ||
812 | struct hv_dynmem_device *dm = hv_get_drvdata(dev); | ||
813 | |||
814 | memset(recv_buffer, 0, sizeof(recv_buffer)); | ||
815 | vmbus_recvpacket(dev->channel, recv_buffer, | ||
816 | PAGE_SIZE, &recvlen, &requestid); | ||
817 | |||
818 | if (recvlen > 0) { | ||
819 | dm_msg = (struct dm_message *)recv_buffer; | ||
820 | dm_hdr = &dm_msg->hdr; | ||
821 | |||
822 | switch (dm_hdr->type) { | ||
823 | case DM_VERSION_RESPONSE: | ||
824 | version_resp(dm, | ||
825 | (struct dm_version_response *)dm_msg); | ||
826 | break; | ||
827 | |||
828 | case DM_CAPABILITIES_RESPONSE: | ||
829 | cap_resp(dm, | ||
830 | (struct dm_capabilities_resp_msg *)dm_msg); | ||
831 | break; | ||
832 | |||
833 | case DM_BALLOON_REQUEST: | ||
834 | dm->state = DM_BALLOON_UP; | ||
835 | complete(&dm->config_event); | ||
836 | break; | ||
837 | |||
838 | case DM_UNBALLOON_REQUEST: | ||
839 | dm->state = DM_BALLOON_DOWN; | ||
840 | balloon_down(dm, | ||
841 | (struct dm_unballoon_request *)recv_buffer); | ||
842 | break; | ||
843 | |||
844 | case DM_MEM_HOT_ADD_REQUEST: | ||
845 | dm->state = DM_HOT_ADD; | ||
846 | complete(&dm->config_event); | ||
847 | break; | ||
848 | |||
849 | case DM_INFO_MESSAGE: | ||
850 | process_info(dm, (struct dm_info_msg *)dm_msg); | ||
851 | break; | ||
852 | |||
853 | default: | ||
854 | pr_err("Unhandled message: type: %d\n", dm_hdr->type); | ||
855 | |||
856 | } | ||
857 | } | ||
858 | |||
859 | } | ||
860 | |||
861 | static int balloon_probe(struct hv_device *dev, | ||
862 | const struct hv_vmbus_device_id *dev_id) | ||
863 | { | ||
864 | int ret, t; | ||
865 | struct dm_version_request version_req; | ||
866 | struct dm_capabilities cap_msg; | ||
867 | |||
868 | do_hot_add = hot_add; | ||
869 | |||
870 | /* | ||
871 | * First allocate a send buffer. | ||
872 | */ | ||
873 | |||
874 | send_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
875 | if (!send_buffer) | ||
876 | return -ENOMEM; | ||
877 | |||
878 | ret = vmbus_open(dev->channel, dm_ring_size, dm_ring_size, NULL, 0, | ||
879 | balloon_onchannelcallback, dev); | ||
880 | |||
881 | if (ret) | ||
882 | return ret; | ||
883 | |||
884 | dm_device.dev = dev; | ||
885 | dm_device.state = DM_INITIALIZING; | ||
886 | dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7; | ||
887 | init_completion(&dm_device.host_event); | ||
888 | init_completion(&dm_device.config_event); | ||
889 | |||
890 | dm_device.thread = | ||
891 | kthread_run(dm_thread_func, &dm_device, "hv_balloon"); | ||
892 | if (IS_ERR(dm_device.thread)) { | ||
893 | ret = PTR_ERR(dm_device.thread); | ||
894 | goto probe_error0; | ||
895 | } | ||
896 | |||
897 | hv_set_drvdata(dev, &dm_device); | ||
898 | /* | ||
899 | * Initiate the hand shake with the host and negotiate | ||
900 | * a version that the host can support. We start with the | ||
901 | * highest version number and go down if the host cannot | ||
902 | * support it. | ||
903 | */ | ||
904 | memset(&version_req, 0, sizeof(struct dm_version_request)); | ||
905 | version_req.hdr.type = DM_VERSION_REQUEST; | ||
906 | version_req.hdr.size = sizeof(struct dm_version_request); | ||
907 | version_req.hdr.trans_id = atomic_inc_return(&trans_id); | ||
908 | version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN8; | ||
909 | version_req.is_last_attempt = 0; | ||
910 | |||
911 | ret = vmbus_sendpacket(dev->channel, &version_req, | ||
912 | sizeof(struct dm_version_request), | ||
913 | (unsigned long)NULL, | ||
914 | VM_PKT_DATA_INBAND, | ||
915 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | ||
916 | if (ret) | ||
917 | goto probe_error1; | ||
918 | |||
919 | t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); | ||
920 | if (t == 0) { | ||
921 | ret = -ETIMEDOUT; | ||
922 | goto probe_error1; | ||
923 | } | ||
924 | |||
925 | /* | ||
926 | * If we could not negotiate a compatible version with the host | ||
927 | * fail the probe function. | ||
928 | */ | ||
929 | if (dm_device.state == DM_INIT_ERROR) { | ||
930 | ret = -ETIMEDOUT; | ||
931 | goto probe_error1; | ||
932 | } | ||
933 | /* | ||
934 | * Now submit our capabilities to the host. | ||
935 | */ | ||
936 | memset(&cap_msg, 0, sizeof(struct dm_capabilities)); | ||
937 | cap_msg.hdr.type = DM_CAPABILITIES_REPORT; | ||
938 | cap_msg.hdr.size = sizeof(struct dm_capabilities); | ||
939 | cap_msg.hdr.trans_id = atomic_inc_return(&trans_id); | ||
940 | |||
941 | cap_msg.caps.cap_bits.balloon = 1; | ||
942 | /* | ||
943 | * While we currently don't support hot-add, | ||
944 | * we still advertise this capability since the | ||
945 | * host requires that guests partcipating in the | ||
946 | * dynamic memory protocol support hot add. | ||
947 | */ | ||
948 | cap_msg.caps.cap_bits.hot_add = 1; | ||
949 | |||
950 | /* | ||
951 | * Currently the host does not use these | ||
952 | * values and we set them to what is done in the | ||
953 | * Windows driver. | ||
954 | */ | ||
955 | cap_msg.min_page_cnt = 0; | ||
956 | cap_msg.max_page_number = -1; | ||
957 | |||
958 | ret = vmbus_sendpacket(dev->channel, &cap_msg, | ||
959 | sizeof(struct dm_capabilities), | ||
960 | (unsigned long)NULL, | ||
961 | VM_PKT_DATA_INBAND, | ||
962 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | ||
963 | if (ret) | ||
964 | goto probe_error1; | ||
965 | |||
966 | t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); | ||
967 | if (t == 0) { | ||
968 | ret = -ETIMEDOUT; | ||
969 | goto probe_error1; | ||
970 | } | ||
971 | |||
972 | /* | ||
973 | * If the host does not like our capabilities, | ||
974 | * fail the probe function. | ||
975 | */ | ||
976 | if (dm_device.state == DM_INIT_ERROR) { | ||
977 | ret = -ETIMEDOUT; | ||
978 | goto probe_error1; | ||
979 | } | ||
980 | |||
981 | dm_device.state = DM_INITIALIZED; | ||
982 | |||
983 | return 0; | ||
984 | |||
985 | probe_error1: | ||
986 | kthread_stop(dm_device.thread); | ||
987 | |||
988 | probe_error0: | ||
989 | vmbus_close(dev->channel); | ||
990 | return ret; | ||
991 | } | ||
992 | |||
993 | static int balloon_remove(struct hv_device *dev) | ||
994 | { | ||
995 | struct hv_dynmem_device *dm = hv_get_drvdata(dev); | ||
996 | |||
997 | if (dm->num_pages_ballooned != 0) | ||
998 | pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned); | ||
999 | |||
1000 | vmbus_close(dev->channel); | ||
1001 | kthread_stop(dm->thread); | ||
1002 | |||
1003 | return 0; | ||
1004 | } | ||
1005 | |||
1006 | static const struct hv_vmbus_device_id id_table[] = { | ||
1007 | /* Dynamic Memory Class ID */ | ||
1008 | /* 525074DC-8985-46e2-8057-A307DC18A502 */ | ||
1009 | { VMBUS_DEVICE(0xdc, 0x74, 0x50, 0X52, 0x85, 0x89, 0xe2, 0x46, | ||
1010 | 0x80, 0x57, 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02) | ||
1011 | }, | ||
1012 | { }, | ||
1013 | }; | ||
1014 | |||
1015 | MODULE_DEVICE_TABLE(vmbus, id_table); | ||
1016 | |||
1017 | static struct hv_driver balloon_drv = { | ||
1018 | .name = "hv_balloon", | ||
1019 | .id_table = id_table, | ||
1020 | .probe = balloon_probe, | ||
1021 | .remove = balloon_remove, | ||
1022 | }; | ||
1023 | |||
1024 | static int __init init_balloon_drv(void) | ||
1025 | { | ||
1026 | |||
1027 | return vmbus_driver_register(&balloon_drv); | ||
1028 | } | ||
1029 | |||
1030 | static void exit_balloon_drv(void) | ||
1031 | { | ||
1032 | |||
1033 | vmbus_driver_unregister(&balloon_drv); | ||
1034 | } | ||
1035 | |||
1036 | module_init(init_balloon_drv); | ||
1037 | module_exit(exit_balloon_drv); | ||
1038 | |||
1039 | MODULE_DESCRIPTION("Hyper-V Balloon"); | ||
1040 | MODULE_VERSION(HV_DRV_VERSION); | ||
1041 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig index cc0997a0517..4f7a17fd1aa 100644 --- a/drivers/memstick/host/Kconfig +++ b/drivers/memstick/host/Kconfig | |||
@@ -42,3 +42,13 @@ config MEMSTICK_R592 | |||
42 | 42 | ||
43 | To compile this driver as a module, choose M here: the module will | 43 | To compile this driver as a module, choose M here: the module will |
44 | be called r592. | 44 | be called r592. |
45 | |||
46 | config MEMSTICK_REALTEK_PCI | ||
47 | tristate "Realtek PCI-E Memstick Card Interface Driver" | ||
48 | depends on MFD_RTSX_PCI | ||
49 | help | ||
50 | Say Y here to include driver code to support Memstick card interface | ||
51 | of Realtek PCI-E card reader | ||
52 | |||
53 | To compile this driver as a module, choose M here: the module will | ||
54 | be called rtsx_pci_ms. | ||
diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile index 31ba8d378e4..af3459d7686 100644 --- a/drivers/memstick/host/Makefile +++ b/drivers/memstick/host/Makefile | |||
@@ -5,3 +5,4 @@ | |||
5 | obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o | 5 | obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o |
6 | obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o | 6 | obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o |
7 | obj-$(CONFIG_MEMSTICK_R592) += r592.o | 7 | obj-$(CONFIG_MEMSTICK_R592) += r592.o |
8 | obj-$(CONFIG_MEMSTICK_REALTEK_PCI) += rtsx_pci_ms.o | ||
diff --git a/drivers/memstick/host/rtsx_pci_ms.c b/drivers/memstick/host/rtsx_pci_ms.c new file mode 100644 index 00000000000..f5ddb82dadb --- /dev/null +++ b/drivers/memstick/host/rtsx_pci_ms.c | |||
@@ -0,0 +1,641 @@ | |||
1 | /* Realtek PCI-Express Memstick Card Interface driver | ||
2 | * | ||
3 | * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/highmem.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/memstick.h> | ||
28 | #include <linux/mfd/rtsx_pci.h> | ||
29 | #include <asm/unaligned.h> | ||
30 | |||
31 | struct realtek_pci_ms { | ||
32 | struct platform_device *pdev; | ||
33 | struct rtsx_pcr *pcr; | ||
34 | struct memstick_host *msh; | ||
35 | struct memstick_request *req; | ||
36 | |||
37 | struct mutex host_mutex; | ||
38 | struct work_struct handle_req; | ||
39 | |||
40 | u8 ssc_depth; | ||
41 | unsigned int clock; | ||
42 | unsigned char ifmode; | ||
43 | bool eject; | ||
44 | }; | ||
45 | |||
46 | static inline struct device *ms_dev(struct realtek_pci_ms *host) | ||
47 | { | ||
48 | return &(host->pdev->dev); | ||
49 | } | ||
50 | |||
51 | static inline void ms_clear_error(struct realtek_pci_ms *host) | ||
52 | { | ||
53 | rtsx_pci_write_register(host->pcr, CARD_STOP, | ||
54 | MS_STOP | MS_CLR_ERR, MS_STOP | MS_CLR_ERR); | ||
55 | } | ||
56 | |||
57 | #ifdef DEBUG | ||
58 | |||
59 | static void ms_print_debug_regs(struct realtek_pci_ms *host) | ||
60 | { | ||
61 | struct rtsx_pcr *pcr = host->pcr; | ||
62 | u16 i; | ||
63 | u8 *ptr; | ||
64 | |||
65 | /* Print MS host internal registers */ | ||
66 | rtsx_pci_init_cmd(pcr); | ||
67 | for (i = 0xFD40; i <= 0xFD44; i++) | ||
68 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); | ||
69 | for (i = 0xFD52; i <= 0xFD69; i++) | ||
70 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); | ||
71 | rtsx_pci_send_cmd(pcr, 100); | ||
72 | |||
73 | ptr = rtsx_pci_get_cmd_data(pcr); | ||
74 | for (i = 0xFD40; i <= 0xFD44; i++) | ||
75 | dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); | ||
76 | for (i = 0xFD52; i <= 0xFD69; i++) | ||
77 | dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); | ||
78 | } | ||
79 | |||
80 | #else | ||
81 | |||
82 | #define ms_print_debug_regs(host) | ||
83 | |||
84 | #endif | ||
85 | |||
86 | static int ms_power_on(struct realtek_pci_ms *host) | ||
87 | { | ||
88 | struct rtsx_pcr *pcr = host->pcr; | ||
89 | int err; | ||
90 | |||
91 | rtsx_pci_init_cmd(pcr); | ||
92 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, MS_MOD_SEL); | ||
93 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, | ||
94 | CARD_SHARE_MASK, CARD_SHARE_48_MS); | ||
95 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, | ||
96 | MS_CLK_EN, MS_CLK_EN); | ||
97 | err = rtsx_pci_send_cmd(pcr, 100); | ||
98 | if (err < 0) | ||
99 | return err; | ||
100 | |||
101 | err = rtsx_pci_card_pull_ctl_enable(pcr, RTSX_MS_CARD); | ||
102 | if (err < 0) | ||
103 | return err; | ||
104 | |||
105 | err = rtsx_pci_card_power_on(pcr, RTSX_MS_CARD); | ||
106 | if (err < 0) | ||
107 | return err; | ||
108 | |||
109 | /* Wait ms power stable */ | ||
110 | msleep(150); | ||
111 | |||
112 | err = rtsx_pci_write_register(pcr, CARD_OE, | ||
113 | MS_OUTPUT_EN, MS_OUTPUT_EN); | ||
114 | if (err < 0) | ||
115 | return err; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int ms_power_off(struct realtek_pci_ms *host) | ||
121 | { | ||
122 | struct rtsx_pcr *pcr = host->pcr; | ||
123 | int err; | ||
124 | |||
125 | rtsx_pci_init_cmd(pcr); | ||
126 | |||
127 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0); | ||
128 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0); | ||
129 | |||
130 | err = rtsx_pci_send_cmd(pcr, 100); | ||
131 | if (err < 0) | ||
132 | return err; | ||
133 | |||
134 | err = rtsx_pci_card_power_off(pcr, RTSX_MS_CARD); | ||
135 | if (err < 0) | ||
136 | return err; | ||
137 | |||
138 | return rtsx_pci_card_pull_ctl_disable(pcr, RTSX_MS_CARD); | ||
139 | } | ||
140 | |||
141 | static int ms_transfer_data(struct realtek_pci_ms *host, unsigned char data_dir, | ||
142 | u8 tpc, u8 cfg, struct scatterlist *sg) | ||
143 | { | ||
144 | struct rtsx_pcr *pcr = host->pcr; | ||
145 | int err; | ||
146 | unsigned int length = sg->length; | ||
147 | u16 sec_cnt = (u16)(length / 512); | ||
148 | u8 val, trans_mode, dma_dir; | ||
149 | |||
150 | dev_dbg(ms_dev(host), "%s: tpc = 0x%02x, data_dir = %s, length = %d\n", | ||
151 | __func__, tpc, (data_dir == READ) ? "READ" : "WRITE", | ||
152 | length); | ||
153 | |||
154 | if (data_dir == READ) { | ||
155 | dma_dir = DMA_DIR_FROM_CARD; | ||
156 | trans_mode = MS_TM_AUTO_READ; | ||
157 | } else { | ||
158 | dma_dir = DMA_DIR_TO_CARD; | ||
159 | trans_mode = MS_TM_AUTO_WRITE; | ||
160 | } | ||
161 | |||
162 | rtsx_pci_init_cmd(pcr); | ||
163 | |||
164 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); | ||
165 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_SECTOR_CNT_H, | ||
166 | 0xFF, (u8)(sec_cnt >> 8)); | ||
167 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_SECTOR_CNT_L, | ||
168 | 0xFF, (u8)sec_cnt); | ||
169 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); | ||
170 | |||
171 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, | ||
172 | DMA_DONE_INT, DMA_DONE_INT); | ||
173 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, 0xFF, (u8)(length >> 24)); | ||
174 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, 0xFF, (u8)(length >> 16)); | ||
175 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, 0xFF, (u8)(length >> 8)); | ||
176 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)length); | ||
177 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, | ||
178 | 0x03 | DMA_PACK_SIZE_MASK, dma_dir | DMA_EN | DMA_512); | ||
179 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, | ||
180 | 0x01, RING_BUFFER); | ||
181 | |||
182 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER, | ||
183 | 0xFF, MS_TRANSFER_START | trans_mode); | ||
184 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER, | ||
185 | MS_TRANSFER_END, MS_TRANSFER_END); | ||
186 | |||
187 | rtsx_pci_send_cmd_no_wait(pcr); | ||
188 | |||
189 | err = rtsx_pci_transfer_data(pcr, sg, 1, data_dir == READ, 10000); | ||
190 | if (err < 0) { | ||
191 | ms_clear_error(host); | ||
192 | return err; | ||
193 | } | ||
194 | |||
195 | rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val); | ||
196 | if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) | ||
197 | return -EIO; | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int ms_write_bytes(struct realtek_pci_ms *host, u8 tpc, | ||
203 | u8 cfg, u8 cnt, u8 *data, u8 *int_reg) | ||
204 | { | ||
205 | struct rtsx_pcr *pcr = host->pcr; | ||
206 | int err, i; | ||
207 | |||
208 | dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc); | ||
209 | |||
210 | if (!data) | ||
211 | return -EINVAL; | ||
212 | |||
213 | rtsx_pci_init_cmd(pcr); | ||
214 | |||
215 | for (i = 0; i < cnt; i++) | ||
216 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
217 | PPBUF_BASE2 + i, 0xFF, data[i]); | ||
218 | if (cnt % 2) | ||
219 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
220 | PPBUF_BASE2 + i, 0xFF, 0xFF); | ||
221 | |||
222 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); | ||
223 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); | ||
224 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); | ||
225 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, | ||
226 | 0x01, PINGPONG_BUFFER); | ||
227 | |||
228 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER, | ||
229 | 0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES); | ||
230 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER, | ||
231 | MS_TRANSFER_END, MS_TRANSFER_END); | ||
232 | if (int_reg) | ||
233 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); | ||
234 | |||
235 | err = rtsx_pci_send_cmd(pcr, 5000); | ||
236 | if (err < 0) { | ||
237 | u8 val; | ||
238 | |||
239 | rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val); | ||
240 | dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val); | ||
241 | |||
242 | if (int_reg) | ||
243 | *int_reg = val & 0x0F; | ||
244 | |||
245 | ms_print_debug_regs(host); | ||
246 | |||
247 | ms_clear_error(host); | ||
248 | |||
249 | if (!(tpc & 0x08)) { | ||
250 | if (val & MS_CRC16_ERR) | ||
251 | return -EIO; | ||
252 | } else { | ||
253 | if (!(val & 0x80)) { | ||
254 | if (val & (MS_INT_ERR | MS_INT_CMDNK)) | ||
255 | return -EIO; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | return -ETIMEDOUT; | ||
260 | } | ||
261 | |||
262 | if (int_reg) { | ||
263 | u8 *ptr = rtsx_pci_get_cmd_data(pcr) + 1; | ||
264 | *int_reg = *ptr & 0x0F; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int ms_read_bytes(struct realtek_pci_ms *host, u8 tpc, | ||
271 | u8 cfg, u8 cnt, u8 *data, u8 *int_reg) | ||
272 | { | ||
273 | struct rtsx_pcr *pcr = host->pcr; | ||
274 | int err, i; | ||
275 | u8 *ptr; | ||
276 | |||
277 | dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc); | ||
278 | |||
279 | if (!data) | ||
280 | return -EINVAL; | ||
281 | |||
282 | rtsx_pci_init_cmd(pcr); | ||
283 | |||
284 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); | ||
285 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); | ||
286 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); | ||
287 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, | ||
288 | 0x01, PINGPONG_BUFFER); | ||
289 | |||
290 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER, | ||
291 | 0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES); | ||
292 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER, | ||
293 | MS_TRANSFER_END, MS_TRANSFER_END); | ||
294 | for (i = 0; i < cnt - 1; i++) | ||
295 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); | ||
296 | if (cnt % 2) | ||
297 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + cnt, 0, 0); | ||
298 | else | ||
299 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, | ||
300 | PPBUF_BASE2 + cnt - 1, 0, 0); | ||
301 | if (int_reg) | ||
302 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); | ||
303 | |||
304 | err = rtsx_pci_send_cmd(pcr, 5000); | ||
305 | if (err < 0) { | ||
306 | u8 val; | ||
307 | |||
308 | rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val); | ||
309 | dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val); | ||
310 | |||
311 | if (int_reg) | ||
312 | *int_reg = val & 0x0F; | ||
313 | |||
314 | ms_print_debug_regs(host); | ||
315 | |||
316 | ms_clear_error(host); | ||
317 | |||
318 | if (!(tpc & 0x08)) { | ||
319 | if (val & MS_CRC16_ERR) | ||
320 | return -EIO; | ||
321 | } else { | ||
322 | if (!(val & 0x80)) { | ||
323 | if (val & (MS_INT_ERR | MS_INT_CMDNK)) | ||
324 | return -EIO; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | return -ETIMEDOUT; | ||
329 | } | ||
330 | |||
331 | ptr = rtsx_pci_get_cmd_data(pcr) + 1; | ||
332 | for (i = 0; i < cnt; i++) | ||
333 | data[i] = *ptr++; | ||
334 | |||
335 | if (int_reg) | ||
336 | *int_reg = *ptr & 0x0F; | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int rtsx_pci_ms_issue_cmd(struct realtek_pci_ms *host) | ||
342 | { | ||
343 | struct memstick_request *req = host->req; | ||
344 | int err = 0; | ||
345 | u8 cfg = 0, int_reg; | ||
346 | |||
347 | dev_dbg(ms_dev(host), "%s\n", __func__); | ||
348 | |||
349 | if (req->need_card_int) { | ||
350 | if (host->ifmode != MEMSTICK_SERIAL) | ||
351 | cfg = WAIT_INT; | ||
352 | } | ||
353 | |||
354 | if (req->long_data) { | ||
355 | err = ms_transfer_data(host, req->data_dir, | ||
356 | req->tpc, cfg, &(req->sg)); | ||
357 | } else { | ||
358 | if (req->data_dir == READ) { | ||
359 | err = ms_read_bytes(host, req->tpc, cfg, | ||
360 | req->data_len, req->data, &int_reg); | ||
361 | } else { | ||
362 | err = ms_write_bytes(host, req->tpc, cfg, | ||
363 | req->data_len, req->data, &int_reg); | ||
364 | } | ||
365 | } | ||
366 | if (err < 0) | ||
367 | return err; | ||
368 | |||
369 | if (req->need_card_int && (host->ifmode == MEMSTICK_SERIAL)) { | ||
370 | err = ms_read_bytes(host, MS_TPC_GET_INT, | ||
371 | NO_WAIT_INT, 1, &int_reg, NULL); | ||
372 | if (err < 0) | ||
373 | return err; | ||
374 | } | ||
375 | |||
376 | if (req->need_card_int) { | ||
377 | dev_dbg(ms_dev(host), "int_reg: 0x%02x\n", int_reg); | ||
378 | |||
379 | if (int_reg & MS_INT_CMDNK) | ||
380 | req->int_reg |= MEMSTICK_INT_CMDNAK; | ||
381 | if (int_reg & MS_INT_BREQ) | ||
382 | req->int_reg |= MEMSTICK_INT_BREQ; | ||
383 | if (int_reg & MS_INT_ERR) | ||
384 | req->int_reg |= MEMSTICK_INT_ERR; | ||
385 | if (int_reg & MS_INT_CED) | ||
386 | req->int_reg |= MEMSTICK_INT_CED; | ||
387 | } | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static void rtsx_pci_ms_handle_req(struct work_struct *work) | ||
393 | { | ||
394 | struct realtek_pci_ms *host = container_of(work, | ||
395 | struct realtek_pci_ms, handle_req); | ||
396 | struct rtsx_pcr *pcr = host->pcr; | ||
397 | struct memstick_host *msh = host->msh; | ||
398 | int rc; | ||
399 | |||
400 | mutex_lock(&pcr->pcr_mutex); | ||
401 | |||
402 | rtsx_pci_start_run(pcr); | ||
403 | |||
404 | rtsx_pci_switch_clock(host->pcr, host->clock, host->ssc_depth, | ||
405 | false, true, false); | ||
406 | rtsx_pci_write_register(pcr, CARD_SELECT, 0x07, MS_MOD_SEL); | ||
407 | rtsx_pci_write_register(pcr, CARD_SHARE_MODE, | ||
408 | CARD_SHARE_MASK, CARD_SHARE_48_MS); | ||
409 | |||
410 | if (!host->req) { | ||
411 | do { | ||
412 | rc = memstick_next_req(msh, &host->req); | ||
413 | dev_dbg(ms_dev(host), "next req %d\n", rc); | ||
414 | |||
415 | if (!rc) | ||
416 | host->req->error = rtsx_pci_ms_issue_cmd(host); | ||
417 | } while (!rc); | ||
418 | } | ||
419 | |||
420 | mutex_unlock(&pcr->pcr_mutex); | ||
421 | } | ||
422 | |||
423 | static void rtsx_pci_ms_request(struct memstick_host *msh) | ||
424 | { | ||
425 | struct realtek_pci_ms *host = memstick_priv(msh); | ||
426 | |||
427 | dev_dbg(ms_dev(host), "--> %s\n", __func__); | ||
428 | |||
429 | schedule_work(&host->handle_req); | ||
430 | } | ||
431 | |||
432 | static int rtsx_pci_ms_set_param(struct memstick_host *msh, | ||
433 | enum memstick_param param, int value) | ||
434 | { | ||
435 | struct realtek_pci_ms *host = memstick_priv(msh); | ||
436 | struct rtsx_pcr *pcr = host->pcr; | ||
437 | unsigned int clock = 0; | ||
438 | u8 ssc_depth = 0; | ||
439 | int err; | ||
440 | |||
441 | dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n", | ||
442 | __func__, param, value); | ||
443 | |||
444 | switch (param) { | ||
445 | case MEMSTICK_POWER: | ||
446 | if (value == MEMSTICK_POWER_ON) | ||
447 | err = ms_power_on(host); | ||
448 | else if (value == MEMSTICK_POWER_OFF) | ||
449 | err = ms_power_off(host); | ||
450 | else | ||
451 | return -EINVAL; | ||
452 | break; | ||
453 | |||
454 | case MEMSTICK_INTERFACE: | ||
455 | if (value == MEMSTICK_SERIAL) { | ||
456 | clock = 19000000; | ||
457 | ssc_depth = RTSX_SSC_DEPTH_500K; | ||
458 | |||
459 | err = rtsx_pci_write_register(pcr, MS_CFG, | ||
460 | 0x18, MS_BUS_WIDTH_1); | ||
461 | if (err < 0) | ||
462 | return err; | ||
463 | } else if (value == MEMSTICK_PAR4) { | ||
464 | clock = 39000000; | ||
465 | ssc_depth = RTSX_SSC_DEPTH_1M; | ||
466 | |||
467 | err = rtsx_pci_write_register(pcr, MS_CFG, | ||
468 | 0x58, MS_BUS_WIDTH_4 | PUSH_TIME_ODD); | ||
469 | if (err < 0) | ||
470 | return err; | ||
471 | } else { | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | |||
475 | err = rtsx_pci_switch_clock(pcr, clock, | ||
476 | ssc_depth, false, true, false); | ||
477 | if (err < 0) | ||
478 | return err; | ||
479 | |||
480 | host->ssc_depth = ssc_depth; | ||
481 | host->clock = clock; | ||
482 | host->ifmode = value; | ||
483 | break; | ||
484 | } | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | #ifdef CONFIG_PM | ||
490 | |||
491 | static int rtsx_pci_ms_suspend(struct platform_device *pdev, pm_message_t state) | ||
492 | { | ||
493 | struct realtek_pci_ms *host = platform_get_drvdata(pdev); | ||
494 | struct memstick_host *msh = host->msh; | ||
495 | |||
496 | dev_dbg(ms_dev(host), "--> %s\n", __func__); | ||
497 | |||
498 | memstick_suspend_host(msh); | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int rtsx_pci_ms_resume(struct platform_device *pdev) | ||
503 | { | ||
504 | struct realtek_pci_ms *host = platform_get_drvdata(pdev); | ||
505 | struct memstick_host *msh = host->msh; | ||
506 | |||
507 | dev_dbg(ms_dev(host), "--> %s\n", __func__); | ||
508 | |||
509 | memstick_resume_host(msh); | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | #else /* CONFIG_PM */ | ||
514 | |||
515 | #define rtsx_pci_ms_suspend NULL | ||
516 | #define rtsx_pci_ms_resume NULL | ||
517 | |||
518 | #endif /* CONFIG_PM */ | ||
519 | |||
520 | static void rtsx_pci_ms_card_event(struct platform_device *pdev) | ||
521 | { | ||
522 | struct realtek_pci_ms *host = platform_get_drvdata(pdev); | ||
523 | |||
524 | memstick_detect_change(host->msh); | ||
525 | } | ||
526 | |||
527 | static int rtsx_pci_ms_drv_probe(struct platform_device *pdev) | ||
528 | { | ||
529 | struct memstick_host *msh; | ||
530 | struct realtek_pci_ms *host; | ||
531 | struct rtsx_pcr *pcr; | ||
532 | struct pcr_handle *handle = pdev->dev.platform_data; | ||
533 | int rc; | ||
534 | |||
535 | if (!handle) | ||
536 | return -ENXIO; | ||
537 | |||
538 | pcr = handle->pcr; | ||
539 | if (!pcr) | ||
540 | return -ENXIO; | ||
541 | |||
542 | dev_dbg(&(pdev->dev), | ||
543 | ": Realtek PCI-E Memstick controller found\n"); | ||
544 | |||
545 | msh = memstick_alloc_host(sizeof(*host), &pdev->dev); | ||
546 | if (!msh) | ||
547 | return -ENOMEM; | ||
548 | |||
549 | host = memstick_priv(msh); | ||
550 | host->pcr = pcr; | ||
551 | host->msh = msh; | ||
552 | host->pdev = pdev; | ||
553 | platform_set_drvdata(pdev, host); | ||
554 | pcr->slots[RTSX_MS_CARD].p_dev = pdev; | ||
555 | pcr->slots[RTSX_MS_CARD].card_event = rtsx_pci_ms_card_event; | ||
556 | |||
557 | mutex_init(&host->host_mutex); | ||
558 | |||
559 | INIT_WORK(&host->handle_req, rtsx_pci_ms_handle_req); | ||
560 | msh->request = rtsx_pci_ms_request; | ||
561 | msh->set_param = rtsx_pci_ms_set_param; | ||
562 | msh->caps = MEMSTICK_CAP_PAR4; | ||
563 | |||
564 | rc = memstick_add_host(msh); | ||
565 | if (rc) { | ||
566 | memstick_free_host(msh); | ||
567 | return rc; | ||
568 | } | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int rtsx_pci_ms_drv_remove(struct platform_device *pdev) | ||
574 | { | ||
575 | struct realtek_pci_ms *host = platform_get_drvdata(pdev); | ||
576 | struct rtsx_pcr *pcr; | ||
577 | struct memstick_host *msh; | ||
578 | int rc; | ||
579 | |||
580 | if (!host) | ||
581 | return 0; | ||
582 | |||
583 | pcr = host->pcr; | ||
584 | pcr->slots[RTSX_MS_CARD].p_dev = NULL; | ||
585 | pcr->slots[RTSX_MS_CARD].card_event = NULL; | ||
586 | msh = host->msh; | ||
587 | host->eject = true; | ||
588 | |||
589 | mutex_lock(&host->host_mutex); | ||
590 | if (host->req) { | ||
591 | dev_dbg(&(pdev->dev), | ||
592 | "%s: Controller removed during transfer\n", | ||
593 | dev_name(&msh->dev)); | ||
594 | |||
595 | rtsx_pci_complete_unfinished_transfer(pcr); | ||
596 | |||
597 | host->req->error = -ENOMEDIUM; | ||
598 | do { | ||
599 | rc = memstick_next_req(msh, &host->req); | ||
600 | if (!rc) | ||
601 | host->req->error = -ENOMEDIUM; | ||
602 | } while (!rc); | ||
603 | } | ||
604 | mutex_unlock(&host->host_mutex); | ||
605 | |||
606 | memstick_remove_host(msh); | ||
607 | memstick_free_host(msh); | ||
608 | |||
609 | platform_set_drvdata(pdev, NULL); | ||
610 | |||
611 | dev_dbg(&(pdev->dev), | ||
612 | ": Realtek PCI-E Memstick controller has been removed\n"); | ||
613 | |||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static struct platform_device_id rtsx_pci_ms_ids[] = { | ||
618 | { | ||
619 | .name = DRV_NAME_RTSX_PCI_MS, | ||
620 | }, { | ||
621 | /* sentinel */ | ||
622 | } | ||
623 | }; | ||
624 | MODULE_DEVICE_TABLE(platform, rtsx_pci_ms_ids); | ||
625 | |||
626 | static struct platform_driver rtsx_pci_ms_driver = { | ||
627 | .probe = rtsx_pci_ms_drv_probe, | ||
628 | .remove = rtsx_pci_ms_drv_remove, | ||
629 | .id_table = rtsx_pci_ms_ids, | ||
630 | .suspend = rtsx_pci_ms_suspend, | ||
631 | .resume = rtsx_pci_ms_resume, | ||
632 | .driver = { | ||
633 | .owner = THIS_MODULE, | ||
634 | .name = DRV_NAME_RTSX_PCI_MS, | ||
635 | }, | ||
636 | }; | ||
637 | module_platform_driver(rtsx_pci_ms_driver); | ||
638 | |||
639 | MODULE_LICENSE("GPL"); | ||
640 | MODULE_AUTHOR("Wei WANG <wei_wang@realsil.com.cn>"); | ||
641 | MODULE_DESCRIPTION("Realtek PCI-E Memstick Card Host Driver"); | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index acab3ef8a31..2c10938b356 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -63,6 +63,16 @@ config MFD_SM501_GPIO | |||
63 | lines on the SM501. The platform data is used to supply the | 63 | lines on the SM501. The platform data is used to supply the |
64 | base number for the first GPIO line to register. | 64 | base number for the first GPIO line to register. |
65 | 65 | ||
66 | config MFD_RTSX_PCI | ||
67 | tristate "Support for Realtek PCI-E card reader" | ||
68 | depends on PCI | ||
69 | select MFD_CORE | ||
70 | help | ||
71 | This supports for Realtek PCI-Express card reader including rts5209, | ||
72 | rts5229, rtl8411, etc. Realtek card reader supports access to many | ||
73 | types of memory cards, such as Memory Stick, Memory Stick Pro, | ||
74 | Secure Digital and MultiMediaCard. | ||
75 | |||
66 | config MFD_ASIC3 | 76 | config MFD_ASIC3 |
67 | bool "Support for Compaq ASIC3" | 77 | bool "Support for Compaq ASIC3" |
68 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | 78 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d8ccb630ddb..b53db06d1b4 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -9,6 +9,9 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o | |||
9 | obj-$(CONFIG_MFD_SM501) += sm501.o | 9 | obj-$(CONFIG_MFD_SM501) += sm501.o |
10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o | 10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o |
11 | 11 | ||
12 | rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o | ||
13 | obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o | ||
14 | |||
12 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o | 15 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o |
13 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o | 16 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o |
14 | obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o | 17 | obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o |
diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c new file mode 100644 index 00000000000..89f046ca9e4 --- /dev/null +++ b/drivers/mfd/rtl8411.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* Driver for Realtek PCI-Express card reader | ||
2 | * | ||
3 | * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/bitops.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/mfd/rtsx_pci.h> | ||
27 | |||
28 | #include "rtsx_pcr.h" | ||
29 | |||
30 | static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr) | ||
31 | { | ||
32 | u8 val; | ||
33 | |||
34 | rtsx_pci_read_register(pcr, SYS_VER, &val); | ||
35 | return val & 0x0F; | ||
36 | } | ||
37 | |||
38 | static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr) | ||
39 | { | ||
40 | return rtsx_pci_write_register(pcr, CD_PAD_CTL, | ||
41 | CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); | ||
42 | } | ||
43 | |||
44 | static int rtl8411_turn_on_led(struct rtsx_pcr *pcr) | ||
45 | { | ||
46 | return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); | ||
47 | } | ||
48 | |||
49 | static int rtl8411_turn_off_led(struct rtsx_pcr *pcr) | ||
50 | { | ||
51 | return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); | ||
52 | } | ||
53 | |||
54 | static int rtl8411_enable_auto_blink(struct rtsx_pcr *pcr) | ||
55 | { | ||
56 | return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); | ||
57 | } | ||
58 | |||
59 | static int rtl8411_disable_auto_blink(struct rtsx_pcr *pcr) | ||
60 | { | ||
61 | return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); | ||
62 | } | ||
63 | |||
64 | static int rtl8411_card_power_on(struct rtsx_pcr *pcr, int card) | ||
65 | { | ||
66 | int err; | ||
67 | |||
68 | rtsx_pci_init_cmd(pcr); | ||
69 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
70 | BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); | ||
71 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CTL, | ||
72 | BPP_LDO_POWB, BPP_LDO_SUSPEND); | ||
73 | err = rtsx_pci_send_cmd(pcr, 100); | ||
74 | if (err < 0) | ||
75 | return err; | ||
76 | |||
77 | /* To avoid too large in-rush current */ | ||
78 | udelay(150); | ||
79 | |||
80 | err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, | ||
81 | BPP_POWER_MASK, BPP_POWER_10_PERCENT_ON); | ||
82 | if (err < 0) | ||
83 | return err; | ||
84 | |||
85 | udelay(150); | ||
86 | |||
87 | err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, | ||
88 | BPP_POWER_MASK, BPP_POWER_15_PERCENT_ON); | ||
89 | if (err < 0) | ||
90 | return err; | ||
91 | |||
92 | udelay(150); | ||
93 | |||
94 | err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, | ||
95 | BPP_POWER_MASK, BPP_POWER_ON); | ||
96 | if (err < 0) | ||
97 | return err; | ||
98 | |||
99 | return rtsx_pci_write_register(pcr, LDO_CTL, BPP_LDO_POWB, BPP_LDO_ON); | ||
100 | } | ||
101 | |||
102 | static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card) | ||
103 | { | ||
104 | int err; | ||
105 | |||
106 | err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, | ||
107 | BPP_POWER_MASK, BPP_POWER_OFF); | ||
108 | if (err < 0) | ||
109 | return err; | ||
110 | |||
111 | return rtsx_pci_write_register(pcr, LDO_CTL, | ||
112 | BPP_LDO_POWB, BPP_LDO_SUSPEND); | ||
113 | } | ||
114 | |||
115 | static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr) | ||
116 | { | ||
117 | unsigned int card_exist; | ||
118 | |||
119 | card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); | ||
120 | card_exist &= CARD_EXIST; | ||
121 | if (!card_exist) { | ||
122 | /* Enable card CD */ | ||
123 | rtsx_pci_write_register(pcr, CD_PAD_CTL, | ||
124 | CD_DISABLE_MASK, CD_ENABLE); | ||
125 | /* Enable card interrupt */ | ||
126 | rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x00); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | if (hweight32(card_exist) > 1) { | ||
131 | rtsx_pci_write_register(pcr, CARD_PWR_CTL, | ||
132 | BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); | ||
133 | msleep(100); | ||
134 | |||
135 | card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); | ||
136 | if (card_exist & MS_EXIST) | ||
137 | card_exist = MS_EXIST; | ||
138 | else if (card_exist & SD_EXIST) | ||
139 | card_exist = SD_EXIST; | ||
140 | else | ||
141 | card_exist = 0; | ||
142 | |||
143 | rtsx_pci_write_register(pcr, CARD_PWR_CTL, | ||
144 | BPP_POWER_MASK, BPP_POWER_OFF); | ||
145 | |||
146 | dev_dbg(&(pcr->pci->dev), | ||
147 | "After CD deglitch, card_exist = 0x%x\n", | ||
148 | card_exist); | ||
149 | } | ||
150 | |||
151 | if (card_exist & MS_EXIST) { | ||
152 | /* Disable SD interrupt */ | ||
153 | rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x40); | ||
154 | rtsx_pci_write_register(pcr, CD_PAD_CTL, | ||
155 | CD_DISABLE_MASK, MS_CD_EN_ONLY); | ||
156 | } else if (card_exist & SD_EXIST) { | ||
157 | /* Disable MS interrupt */ | ||
158 | rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x80); | ||
159 | rtsx_pci_write_register(pcr, CD_PAD_CTL, | ||
160 | CD_DISABLE_MASK, SD_CD_EN_ONLY); | ||
161 | } | ||
162 | |||
163 | return card_exist; | ||
164 | } | ||
165 | |||
166 | static const struct pcr_ops rtl8411_pcr_ops = { | ||
167 | .extra_init_hw = rtl8411_extra_init_hw, | ||
168 | .optimize_phy = NULL, | ||
169 | .turn_on_led = rtl8411_turn_on_led, | ||
170 | .turn_off_led = rtl8411_turn_off_led, | ||
171 | .enable_auto_blink = rtl8411_enable_auto_blink, | ||
172 | .disable_auto_blink = rtl8411_disable_auto_blink, | ||
173 | .card_power_on = rtl8411_card_power_on, | ||
174 | .card_power_off = rtl8411_card_power_off, | ||
175 | .cd_deglitch = rtl8411_cd_deglitch, | ||
176 | }; | ||
177 | |||
178 | /* SD Pull Control Enable: | ||
179 | * SD_DAT[3:0] ==> pull up | ||
180 | * SD_CD ==> pull up | ||
181 | * SD_WP ==> pull up | ||
182 | * SD_CMD ==> pull up | ||
183 | * SD_CLK ==> pull down | ||
184 | */ | ||
185 | static const u32 rtl8411_sd_pull_ctl_enable_tbl[] = { | ||
186 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), | ||
187 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), | ||
188 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xA9), | ||
189 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), | ||
190 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x09), | ||
191 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), | ||
192 | 0, | ||
193 | }; | ||
194 | |||
195 | /* SD Pull Control Disable: | ||
196 | * SD_DAT[3:0] ==> pull down | ||
197 | * SD_CD ==> pull up | ||
198 | * SD_WP ==> pull down | ||
199 | * SD_CMD ==> pull down | ||
200 | * SD_CLK ==> pull down | ||
201 | */ | ||
202 | static const u32 rtl8411_sd_pull_ctl_disable_tbl[] = { | ||
203 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), | ||
204 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), | ||
205 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), | ||
206 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), | ||
207 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), | ||
208 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), | ||
209 | 0, | ||
210 | }; | ||
211 | |||
212 | /* MS Pull Control Enable: | ||
213 | * MS CD ==> pull up | ||
214 | * others ==> pull down | ||
215 | */ | ||
216 | static const u32 rtl8411_ms_pull_ctl_enable_tbl[] = { | ||
217 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), | ||
218 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), | ||
219 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), | ||
220 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05), | ||
221 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), | ||
222 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), | ||
223 | 0, | ||
224 | }; | ||
225 | |||
226 | /* MS Pull Control Disable: | ||
227 | * MS CD ==> pull up | ||
228 | * others ==> pull down | ||
229 | */ | ||
230 | static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = { | ||
231 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), | ||
232 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), | ||
233 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), | ||
234 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), | ||
235 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), | ||
236 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), | ||
237 | 0, | ||
238 | }; | ||
239 | |||
240 | void rtl8411_init_params(struct rtsx_pcr *pcr) | ||
241 | { | ||
242 | pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; | ||
243 | pcr->num_slots = 2; | ||
244 | pcr->ops = &rtl8411_pcr_ops; | ||
245 | |||
246 | pcr->ic_version = rtl8411_get_ic_version(pcr); | ||
247 | pcr->sd_pull_ctl_enable_tbl = rtl8411_sd_pull_ctl_enable_tbl; | ||
248 | pcr->sd_pull_ctl_disable_tbl = rtl8411_sd_pull_ctl_disable_tbl; | ||
249 | pcr->ms_pull_ctl_enable_tbl = rtl8411_ms_pull_ctl_enable_tbl; | ||
250 | pcr->ms_pull_ctl_disable_tbl = rtl8411_ms_pull_ctl_disable_tbl; | ||
251 | } | ||
diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c new file mode 100644 index 00000000000..283a4f14808 --- /dev/null +++ b/drivers/mfd/rts5209.c | |||
@@ -0,0 +1,223 @@ | |||
1 | /* Driver for Realtek PCI-Express card reader | ||
2 | * | ||
3 | * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/mfd/rtsx_pci.h> | ||
26 | |||
27 | #include "rtsx_pcr.h" | ||
28 | |||
29 | static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr) | ||
30 | { | ||
31 | u8 val; | ||
32 | |||
33 | val = rtsx_pci_readb(pcr, 0x1C); | ||
34 | return val & 0x0F; | ||
35 | } | ||
36 | |||
37 | static void rts5209_init_vendor_cfg(struct rtsx_pcr *pcr) | ||
38 | { | ||
39 | u32 val; | ||
40 | |||
41 | rtsx_pci_read_config_dword(pcr, 0x724, &val); | ||
42 | dev_dbg(&(pcr->pci->dev), "Cfg 0x724: 0x%x\n", val); | ||
43 | |||
44 | if (!(val & 0x80)) { | ||
45 | if (val & 0x08) | ||
46 | pcr->ms_pmos = false; | ||
47 | else | ||
48 | pcr->ms_pmos = true; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | static int rts5209_extra_init_hw(struct rtsx_pcr *pcr) | ||
53 | { | ||
54 | rtsx_pci_init_cmd(pcr); | ||
55 | |||
56 | /* Turn off LED */ | ||
57 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03); | ||
58 | /* Configure GPIO as output */ | ||
59 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03); | ||
60 | |||
61 | return rtsx_pci_send_cmd(pcr, 100); | ||
62 | } | ||
63 | |||
64 | static int rts5209_optimize_phy(struct rtsx_pcr *pcr) | ||
65 | { | ||
66 | return rtsx_pci_write_phy_register(pcr, 0x00, 0xB966); | ||
67 | } | ||
68 | |||
69 | static int rts5209_turn_on_led(struct rtsx_pcr *pcr) | ||
70 | { | ||
71 | return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); | ||
72 | } | ||
73 | |||
74 | static int rts5209_turn_off_led(struct rtsx_pcr *pcr) | ||
75 | { | ||
76 | return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); | ||
77 | } | ||
78 | |||
79 | static int rts5209_enable_auto_blink(struct rtsx_pcr *pcr) | ||
80 | { | ||
81 | return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); | ||
82 | } | ||
83 | |||
84 | static int rts5209_disable_auto_blink(struct rtsx_pcr *pcr) | ||
85 | { | ||
86 | return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); | ||
87 | } | ||
88 | |||
89 | static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card) | ||
90 | { | ||
91 | int err; | ||
92 | u8 pwr_mask, partial_pwr_on, pwr_on; | ||
93 | |||
94 | pwr_mask = SD_POWER_MASK; | ||
95 | partial_pwr_on = SD_PARTIAL_POWER_ON; | ||
96 | pwr_on = SD_POWER_ON; | ||
97 | |||
98 | if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { | ||
99 | pwr_mask = MS_POWER_MASK; | ||
100 | partial_pwr_on = MS_PARTIAL_POWER_ON; | ||
101 | pwr_on = MS_POWER_ON; | ||
102 | } | ||
103 | |||
104 | rtsx_pci_init_cmd(pcr); | ||
105 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
106 | pwr_mask, partial_pwr_on); | ||
107 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
108 | LDO3318_PWR_MASK, 0x04); | ||
109 | err = rtsx_pci_send_cmd(pcr, 100); | ||
110 | if (err < 0) | ||
111 | return err; | ||
112 | |||
113 | /* To avoid too large in-rush current */ | ||
114 | udelay(150); | ||
115 | |||
116 | rtsx_pci_init_cmd(pcr); | ||
117 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask, pwr_on); | ||
118 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
119 | LDO3318_PWR_MASK, 0x00); | ||
120 | err = rtsx_pci_send_cmd(pcr, 100); | ||
121 | if (err < 0) | ||
122 | return err; | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) | ||
128 | { | ||
129 | u8 pwr_mask, pwr_off; | ||
130 | |||
131 | pwr_mask = SD_POWER_MASK; | ||
132 | pwr_off = SD_POWER_OFF; | ||
133 | |||
134 | if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { | ||
135 | pwr_mask = MS_POWER_MASK; | ||
136 | pwr_off = MS_POWER_OFF; | ||
137 | } | ||
138 | |||
139 | rtsx_pci_init_cmd(pcr); | ||
140 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
141 | pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA); | ||
142 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
143 | LDO3318_PWR_MASK, 0X06); | ||
144 | return rtsx_pci_send_cmd(pcr, 100); | ||
145 | } | ||
146 | |||
147 | static const struct pcr_ops rts5209_pcr_ops = { | ||
148 | .extra_init_hw = rts5209_extra_init_hw, | ||
149 | .optimize_phy = rts5209_optimize_phy, | ||
150 | .turn_on_led = rts5209_turn_on_led, | ||
151 | .turn_off_led = rts5209_turn_off_led, | ||
152 | .enable_auto_blink = rts5209_enable_auto_blink, | ||
153 | .disable_auto_blink = rts5209_disable_auto_blink, | ||
154 | .card_power_on = rts5209_card_power_on, | ||
155 | .card_power_off = rts5209_card_power_off, | ||
156 | .cd_deglitch = NULL, | ||
157 | }; | ||
158 | |||
159 | /* SD Pull Control Enable: | ||
160 | * SD_DAT[3:0] ==> pull up | ||
161 | * SD_CD ==> pull up | ||
162 | * SD_WP ==> pull up | ||
163 | * SD_CMD ==> pull up | ||
164 | * SD_CLK ==> pull down | ||
165 | */ | ||
166 | static const u32 rts5209_sd_pull_ctl_enable_tbl[] = { | ||
167 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), | ||
168 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), | ||
169 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), | ||
170 | 0, | ||
171 | }; | ||
172 | |||
173 | /* SD Pull Control Disable: | ||
174 | * SD_DAT[3:0] ==> pull down | ||
175 | * SD_CD ==> pull up | ||
176 | * SD_WP ==> pull down | ||
177 | * SD_CMD ==> pull down | ||
178 | * SD_CLK ==> pull down | ||
179 | */ | ||
180 | static const u32 rts5209_sd_pull_ctl_disable_tbl[] = { | ||
181 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0x55), | ||
182 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), | ||
183 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), | ||
184 | 0, | ||
185 | }; | ||
186 | |||
187 | /* MS Pull Control Enable: | ||
188 | * MS CD ==> pull up | ||
189 | * others ==> pull down | ||
190 | */ | ||
191 | static const u32 rts5209_ms_pull_ctl_enable_tbl[] = { | ||
192 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), | ||
193 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), | ||
194 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), | ||
195 | 0, | ||
196 | }; | ||
197 | |||
198 | /* MS Pull Control Disable: | ||
199 | * MS CD ==> pull up | ||
200 | * others ==> pull down | ||
201 | */ | ||
202 | static const u32 rts5209_ms_pull_ctl_disable_tbl[] = { | ||
203 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), | ||
204 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), | ||
205 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), | ||
206 | 0, | ||
207 | }; | ||
208 | |||
209 | void rts5209_init_params(struct rtsx_pcr *pcr) | ||
210 | { | ||
211 | pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | | ||
212 | EXTRA_CAPS_SD_SDR104 | EXTRA_CAPS_MMC_8BIT; | ||
213 | pcr->num_slots = 2; | ||
214 | pcr->ops = &rts5209_pcr_ops; | ||
215 | |||
216 | rts5209_init_vendor_cfg(pcr); | ||
217 | |||
218 | pcr->ic_version = rts5209_get_ic_version(pcr); | ||
219 | pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl; | ||
220 | pcr->sd_pull_ctl_disable_tbl = rts5209_sd_pull_ctl_disable_tbl; | ||
221 | pcr->ms_pull_ctl_enable_tbl = rts5209_ms_pull_ctl_enable_tbl; | ||
222 | pcr->ms_pull_ctl_disable_tbl = rts5209_ms_pull_ctl_disable_tbl; | ||
223 | } | ||
diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c new file mode 100644 index 00000000000..b9dbab266fd --- /dev/null +++ b/drivers/mfd/rts5229.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* Driver for Realtek PCI-Express card reader | ||
2 | * | ||
3 | * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/mfd/rtsx_pci.h> | ||
26 | |||
27 | #include "rtsx_pcr.h" | ||
28 | |||
29 | static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr) | ||
30 | { | ||
31 | u8 val; | ||
32 | |||
33 | rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); | ||
34 | return val & 0x0F; | ||
35 | } | ||
36 | |||
37 | static int rts5229_extra_init_hw(struct rtsx_pcr *pcr) | ||
38 | { | ||
39 | rtsx_pci_init_cmd(pcr); | ||
40 | |||
41 | /* Configure GPIO as output */ | ||
42 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); | ||
43 | /* Switch LDO3318 source from DV33 to card_3v3 */ | ||
44 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); | ||
45 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); | ||
46 | /* LED shine disabled, set initial shine cycle period */ | ||
47 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); | ||
48 | |||
49 | return rtsx_pci_send_cmd(pcr, 100); | ||
50 | } | ||
51 | |||
52 | static int rts5229_optimize_phy(struct rtsx_pcr *pcr) | ||
53 | { | ||
54 | /* Optimize RX sensitivity */ | ||
55 | return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42); | ||
56 | } | ||
57 | |||
58 | static int rts5229_turn_on_led(struct rtsx_pcr *pcr) | ||
59 | { | ||
60 | return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); | ||
61 | } | ||
62 | |||
63 | static int rts5229_turn_off_led(struct rtsx_pcr *pcr) | ||
64 | { | ||
65 | return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); | ||
66 | } | ||
67 | |||
68 | static int rts5229_enable_auto_blink(struct rtsx_pcr *pcr) | ||
69 | { | ||
70 | return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); | ||
71 | } | ||
72 | |||
73 | static int rts5229_disable_auto_blink(struct rtsx_pcr *pcr) | ||
74 | { | ||
75 | return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); | ||
76 | } | ||
77 | |||
78 | static int rts5229_card_power_on(struct rtsx_pcr *pcr, int card) | ||
79 | { | ||
80 | int err; | ||
81 | |||
82 | rtsx_pci_init_cmd(pcr); | ||
83 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
84 | SD_POWER_MASK, SD_PARTIAL_POWER_ON); | ||
85 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
86 | LDO3318_PWR_MASK, 0x02); | ||
87 | err = rtsx_pci_send_cmd(pcr, 100); | ||
88 | if (err < 0) | ||
89 | return err; | ||
90 | |||
91 | /* To avoid too large in-rush current */ | ||
92 | udelay(150); | ||
93 | |||
94 | rtsx_pci_init_cmd(pcr); | ||
95 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
96 | SD_POWER_MASK, SD_POWER_ON); | ||
97 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
98 | LDO3318_PWR_MASK, 0x06); | ||
99 | err = rtsx_pci_send_cmd(pcr, 100); | ||
100 | if (err < 0) | ||
101 | return err; | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card) | ||
107 | { | ||
108 | rtsx_pci_init_cmd(pcr); | ||
109 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
110 | SD_POWER_MASK | PMOS_STRG_MASK, | ||
111 | SD_POWER_OFF | PMOS_STRG_400mA); | ||
112 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
113 | LDO3318_PWR_MASK, 0X00); | ||
114 | return rtsx_pci_send_cmd(pcr, 100); | ||
115 | } | ||
116 | |||
117 | static const struct pcr_ops rts5229_pcr_ops = { | ||
118 | .extra_init_hw = rts5229_extra_init_hw, | ||
119 | .optimize_phy = rts5229_optimize_phy, | ||
120 | .turn_on_led = rts5229_turn_on_led, | ||
121 | .turn_off_led = rts5229_turn_off_led, | ||
122 | .enable_auto_blink = rts5229_enable_auto_blink, | ||
123 | .disable_auto_blink = rts5229_disable_auto_blink, | ||
124 | .card_power_on = rts5229_card_power_on, | ||
125 | .card_power_off = rts5229_card_power_off, | ||
126 | .cd_deglitch = NULL, | ||
127 | }; | ||
128 | |||
129 | /* SD Pull Control Enable: | ||
130 | * SD_DAT[3:0] ==> pull up | ||
131 | * SD_CD ==> pull up | ||
132 | * SD_WP ==> pull up | ||
133 | * SD_CMD ==> pull up | ||
134 | * SD_CLK ==> pull down | ||
135 | */ | ||
136 | static const u32 rts5229_sd_pull_ctl_enable_tbl1[] = { | ||
137 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), | ||
138 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), | ||
139 | 0, | ||
140 | }; | ||
141 | |||
142 | /* For RTS5229 version C */ | ||
143 | static const u32 rts5229_sd_pull_ctl_enable_tbl2[] = { | ||
144 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), | ||
145 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD9), | ||
146 | 0, | ||
147 | }; | ||
148 | |||
149 | /* SD Pull Control Disable: | ||
150 | * SD_DAT[3:0] ==> pull down | ||
151 | * SD_CD ==> pull up | ||
152 | * SD_WP ==> pull down | ||
153 | * SD_CMD ==> pull down | ||
154 | * SD_CLK ==> pull down | ||
155 | */ | ||
156 | static const u32 rts5229_sd_pull_ctl_disable_tbl1[] = { | ||
157 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), | ||
158 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), | ||
159 | 0, | ||
160 | }; | ||
161 | |||
162 | /* For RTS5229 version C */ | ||
163 | static const u32 rts5229_sd_pull_ctl_disable_tbl2[] = { | ||
164 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), | ||
165 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE5), | ||
166 | 0, | ||
167 | }; | ||
168 | |||
169 | /* MS Pull Control Enable: | ||
170 | * MS CD ==> pull up | ||
171 | * others ==> pull down | ||
172 | */ | ||
173 | static const u32 rts5229_ms_pull_ctl_enable_tbl[] = { | ||
174 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), | ||
175 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), | ||
176 | 0, | ||
177 | }; | ||
178 | |||
179 | /* MS Pull Control Disable: | ||
180 | * MS CD ==> pull up | ||
181 | * others ==> pull down | ||
182 | */ | ||
183 | static const u32 rts5229_ms_pull_ctl_disable_tbl[] = { | ||
184 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), | ||
185 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), | ||
186 | 0, | ||
187 | }; | ||
188 | |||
189 | void rts5229_init_params(struct rtsx_pcr *pcr) | ||
190 | { | ||
191 | pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; | ||
192 | pcr->num_slots = 2; | ||
193 | pcr->ops = &rts5229_pcr_ops; | ||
194 | |||
195 | pcr->ic_version = rts5229_get_ic_version(pcr); | ||
196 | if (pcr->ic_version == IC_VER_C) { | ||
197 | pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2; | ||
198 | pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl2; | ||
199 | } else { | ||
200 | pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl1; | ||
201 | pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl1; | ||
202 | } | ||
203 | pcr->ms_pull_ctl_enable_tbl = rts5229_ms_pull_ctl_enable_tbl; | ||
204 | pcr->ms_pull_ctl_disable_tbl = rts5229_ms_pull_ctl_disable_tbl; | ||
205 | } | ||
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c new file mode 100644 index 00000000000..56d4377c62c --- /dev/null +++ b/drivers/mfd/rtsx_pcr.c | |||
@@ -0,0 +1,1251 @@ | |||
1 | /* Driver for Realtek PCI-Express card reader | ||
2 | * | ||
3 | * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #include <linux/pci.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/highmem.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/idr.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/mfd/core.h> | ||
32 | #include <linux/mfd/rtsx_pci.h> | ||
33 | #include <asm/unaligned.h> | ||
34 | |||
35 | #include "rtsx_pcr.h" | ||
36 | |||
37 | static bool msi_en = true; | ||
38 | module_param(msi_en, bool, S_IRUGO | S_IWUSR); | ||
39 | MODULE_PARM_DESC(msi_en, "Enable MSI"); | ||
40 | |||
41 | static DEFINE_IDR(rtsx_pci_idr); | ||
42 | static DEFINE_SPINLOCK(rtsx_pci_lock); | ||
43 | |||
44 | static struct mfd_cell rtsx_pcr_cells[] = { | ||
45 | [RTSX_SD_CARD] = { | ||
46 | .name = DRV_NAME_RTSX_PCI_SDMMC, | ||
47 | }, | ||
48 | [RTSX_MS_CARD] = { | ||
49 | .name = DRV_NAME_RTSX_PCI_MS, | ||
50 | }, | ||
51 | }; | ||
52 | |||
53 | static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = { | ||
54 | { PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | ||
55 | { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | ||
56 | { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | ||
57 | { 0, } | ||
58 | }; | ||
59 | |||
60 | MODULE_DEVICE_TABLE(pci, rtsx_pci_ids); | ||
61 | |||
62 | void rtsx_pci_start_run(struct rtsx_pcr *pcr) | ||
63 | { | ||
64 | /* If pci device removed, don't queue idle work any more */ | ||
65 | if (pcr->remove_pci) | ||
66 | return; | ||
67 | |||
68 | if (pcr->state != PDEV_STAT_RUN) { | ||
69 | pcr->state = PDEV_STAT_RUN; | ||
70 | if (pcr->ops->enable_auto_blink) | ||
71 | pcr->ops->enable_auto_blink(pcr); | ||
72 | } | ||
73 | |||
74 | mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200)); | ||
75 | } | ||
76 | EXPORT_SYMBOL_GPL(rtsx_pci_start_run); | ||
77 | |||
78 | int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data) | ||
79 | { | ||
80 | int i; | ||
81 | u32 val = HAIMR_WRITE_START; | ||
82 | |||
83 | val |= (u32)(addr & 0x3FFF) << 16; | ||
84 | val |= (u32)mask << 8; | ||
85 | val |= (u32)data; | ||
86 | |||
87 | rtsx_pci_writel(pcr, RTSX_HAIMR, val); | ||
88 | |||
89 | for (i = 0; i < MAX_RW_REG_CNT; i++) { | ||
90 | val = rtsx_pci_readl(pcr, RTSX_HAIMR); | ||
91 | if ((val & HAIMR_TRANS_END) == 0) { | ||
92 | if (data != (u8)val) | ||
93 | return -EIO; | ||
94 | return 0; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | return -ETIMEDOUT; | ||
99 | } | ||
100 | EXPORT_SYMBOL_GPL(rtsx_pci_write_register); | ||
101 | |||
102 | int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data) | ||
103 | { | ||
104 | u32 val = HAIMR_READ_START; | ||
105 | int i; | ||
106 | |||
107 | val |= (u32)(addr & 0x3FFF) << 16; | ||
108 | rtsx_pci_writel(pcr, RTSX_HAIMR, val); | ||
109 | |||
110 | for (i = 0; i < MAX_RW_REG_CNT; i++) { | ||
111 | val = rtsx_pci_readl(pcr, RTSX_HAIMR); | ||
112 | if ((val & HAIMR_TRANS_END) == 0) | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | if (i >= MAX_RW_REG_CNT) | ||
117 | return -ETIMEDOUT; | ||
118 | |||
119 | if (data) | ||
120 | *data = (u8)(val & 0xFF); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | EXPORT_SYMBOL_GPL(rtsx_pci_read_register); | ||
125 | |||
126 | int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val) | ||
127 | { | ||
128 | int err, i, finished = 0; | ||
129 | u8 tmp; | ||
130 | |||
131 | rtsx_pci_init_cmd(pcr); | ||
132 | |||
133 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA0, 0xFF, (u8)val); | ||
134 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA1, 0xFF, (u8)(val >> 8)); | ||
135 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); | ||
136 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x81); | ||
137 | |||
138 | err = rtsx_pci_send_cmd(pcr, 100); | ||
139 | if (err < 0) | ||
140 | return err; | ||
141 | |||
142 | for (i = 0; i < 100000; i++) { | ||
143 | err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); | ||
144 | if (err < 0) | ||
145 | return err; | ||
146 | |||
147 | if (!(tmp & 0x80)) { | ||
148 | finished = 1; | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | if (!finished) | ||
154 | return -ETIMEDOUT; | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(rtsx_pci_write_phy_register); | ||
159 | |||
160 | int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val) | ||
161 | { | ||
162 | int err, i, finished = 0; | ||
163 | u16 data; | ||
164 | u8 *ptr, tmp; | ||
165 | |||
166 | rtsx_pci_init_cmd(pcr); | ||
167 | |||
168 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); | ||
169 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80); | ||
170 | |||
171 | err = rtsx_pci_send_cmd(pcr, 100); | ||
172 | if (err < 0) | ||
173 | return err; | ||
174 | |||
175 | for (i = 0; i < 100000; i++) { | ||
176 | err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); | ||
177 | if (err < 0) | ||
178 | return err; | ||
179 | |||
180 | if (!(tmp & 0x80)) { | ||
181 | finished = 1; | ||
182 | break; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | if (!finished) | ||
187 | return -ETIMEDOUT; | ||
188 | |||
189 | rtsx_pci_init_cmd(pcr); | ||
190 | |||
191 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0); | ||
192 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0); | ||
193 | |||
194 | err = rtsx_pci_send_cmd(pcr, 100); | ||
195 | if (err < 0) | ||
196 | return err; | ||
197 | |||
198 | ptr = rtsx_pci_get_cmd_data(pcr); | ||
199 | data = ((u16)ptr[1] << 8) | ptr[0]; | ||
200 | |||
201 | if (val) | ||
202 | *val = data; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | EXPORT_SYMBOL_GPL(rtsx_pci_read_phy_register); | ||
207 | |||
208 | void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr) | ||
209 | { | ||
210 | rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD); | ||
211 | rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA); | ||
212 | |||
213 | rtsx_pci_write_register(pcr, DMACTL, 0x80, 0x80); | ||
214 | rtsx_pci_write_register(pcr, RBCTL, 0x80, 0x80); | ||
215 | } | ||
216 | EXPORT_SYMBOL_GPL(rtsx_pci_stop_cmd); | ||
217 | |||
218 | void rtsx_pci_add_cmd(struct rtsx_pcr *pcr, | ||
219 | u8 cmd_type, u16 reg_addr, u8 mask, u8 data) | ||
220 | { | ||
221 | unsigned long flags; | ||
222 | u32 val = 0; | ||
223 | u32 *ptr = (u32 *)(pcr->host_cmds_ptr); | ||
224 | |||
225 | val |= (u32)(cmd_type & 0x03) << 30; | ||
226 | val |= (u32)(reg_addr & 0x3FFF) << 16; | ||
227 | val |= (u32)mask << 8; | ||
228 | val |= (u32)data; | ||
229 | |||
230 | spin_lock_irqsave(&pcr->lock, flags); | ||
231 | ptr += pcr->ci; | ||
232 | if (pcr->ci < (HOST_CMDS_BUF_LEN / 4)) { | ||
233 | put_unaligned_le32(val, ptr); | ||
234 | ptr++; | ||
235 | pcr->ci++; | ||
236 | } | ||
237 | spin_unlock_irqrestore(&pcr->lock, flags); | ||
238 | } | ||
239 | EXPORT_SYMBOL_GPL(rtsx_pci_add_cmd); | ||
240 | |||
241 | void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr) | ||
242 | { | ||
243 | u32 val = 1 << 31; | ||
244 | |||
245 | rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); | ||
246 | |||
247 | val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; | ||
248 | /* Hardware Auto Response */ | ||
249 | val |= 0x40000000; | ||
250 | rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); | ||
251 | } | ||
252 | EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd_no_wait); | ||
253 | |||
254 | int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout) | ||
255 | { | ||
256 | struct completion trans_done; | ||
257 | u32 val = 1 << 31; | ||
258 | long timeleft; | ||
259 | unsigned long flags; | ||
260 | int err = 0; | ||
261 | |||
262 | spin_lock_irqsave(&pcr->lock, flags); | ||
263 | |||
264 | /* set up data structures for the wakeup system */ | ||
265 | pcr->done = &trans_done; | ||
266 | pcr->trans_result = TRANS_NOT_READY; | ||
267 | init_completion(&trans_done); | ||
268 | |||
269 | rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); | ||
270 | |||
271 | val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; | ||
272 | /* Hardware Auto Response */ | ||
273 | val |= 0x40000000; | ||
274 | rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); | ||
275 | |||
276 | spin_unlock_irqrestore(&pcr->lock, flags); | ||
277 | |||
278 | /* Wait for TRANS_OK_INT */ | ||
279 | timeleft = wait_for_completion_interruptible_timeout( | ||
280 | &trans_done, msecs_to_jiffies(timeout)); | ||
281 | if (timeleft <= 0) { | ||
282 | dev_dbg(&(pcr->pci->dev), "Timeout (%s %d)\n", | ||
283 | __func__, __LINE__); | ||
284 | err = -ETIMEDOUT; | ||
285 | goto finish_send_cmd; | ||
286 | } | ||
287 | |||
288 | spin_lock_irqsave(&pcr->lock, flags); | ||
289 | if (pcr->trans_result == TRANS_RESULT_FAIL) | ||
290 | err = -EINVAL; | ||
291 | else if (pcr->trans_result == TRANS_RESULT_OK) | ||
292 | err = 0; | ||
293 | else if (pcr->trans_result == TRANS_NO_DEVICE) | ||
294 | err = -ENODEV; | ||
295 | spin_unlock_irqrestore(&pcr->lock, flags); | ||
296 | |||
297 | finish_send_cmd: | ||
298 | spin_lock_irqsave(&pcr->lock, flags); | ||
299 | pcr->done = NULL; | ||
300 | spin_unlock_irqrestore(&pcr->lock, flags); | ||
301 | |||
302 | if ((err < 0) && (err != -ENODEV)) | ||
303 | rtsx_pci_stop_cmd(pcr); | ||
304 | |||
305 | if (pcr->finish_me) | ||
306 | complete(pcr->finish_me); | ||
307 | |||
308 | return err; | ||
309 | } | ||
310 | EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd); | ||
311 | |||
312 | static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr, | ||
313 | dma_addr_t addr, unsigned int len, int end) | ||
314 | { | ||
315 | u64 *ptr = (u64 *)(pcr->host_sg_tbl_ptr) + pcr->sgi; | ||
316 | u64 val; | ||
317 | u8 option = SG_VALID | SG_TRANS_DATA; | ||
318 | |||
319 | dev_dbg(&(pcr->pci->dev), "DMA addr: 0x%x, Len: 0x%x\n", | ||
320 | (unsigned int)addr, len); | ||
321 | |||
322 | if (end) | ||
323 | option |= SG_END; | ||
324 | val = ((u64)addr << 32) | ((u64)len << 12) | option; | ||
325 | |||
326 | put_unaligned_le64(val, ptr); | ||
327 | ptr++; | ||
328 | pcr->sgi++; | ||
329 | } | ||
330 | |||
331 | int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, | ||
332 | int num_sg, bool read, int timeout) | ||
333 | { | ||
334 | struct completion trans_done; | ||
335 | u8 dir; | ||
336 | int err = 0, i, count; | ||
337 | long timeleft; | ||
338 | unsigned long flags; | ||
339 | struct scatterlist *sg; | ||
340 | enum dma_data_direction dma_dir; | ||
341 | u32 val; | ||
342 | dma_addr_t addr; | ||
343 | unsigned int len; | ||
344 | |||
345 | dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg); | ||
346 | |||
347 | /* don't transfer data during abort processing */ | ||
348 | if (pcr->remove_pci) | ||
349 | return -EINVAL; | ||
350 | |||
351 | if ((sglist == NULL) || (num_sg <= 0)) | ||
352 | return -EINVAL; | ||
353 | |||
354 | if (read) { | ||
355 | dir = DEVICE_TO_HOST; | ||
356 | dma_dir = DMA_FROM_DEVICE; | ||
357 | } else { | ||
358 | dir = HOST_TO_DEVICE; | ||
359 | dma_dir = DMA_TO_DEVICE; | ||
360 | } | ||
361 | |||
362 | count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); | ||
363 | if (count < 1) { | ||
364 | dev_err(&(pcr->pci->dev), "scatterlist map failed\n"); | ||
365 | return -EINVAL; | ||
366 | } | ||
367 | dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count); | ||
368 | |||
369 | val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE; | ||
370 | pcr->sgi = 0; | ||
371 | for_each_sg(sglist, sg, count, i) { | ||
372 | addr = sg_dma_address(sg); | ||
373 | len = sg_dma_len(sg); | ||
374 | rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1); | ||
375 | } | ||
376 | |||
377 | spin_lock_irqsave(&pcr->lock, flags); | ||
378 | |||
379 | pcr->done = &trans_done; | ||
380 | pcr->trans_result = TRANS_NOT_READY; | ||
381 | init_completion(&trans_done); | ||
382 | rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr); | ||
383 | rtsx_pci_writel(pcr, RTSX_HDBCTLR, val); | ||
384 | |||
385 | spin_unlock_irqrestore(&pcr->lock, flags); | ||
386 | |||
387 | timeleft = wait_for_completion_interruptible_timeout( | ||
388 | &trans_done, msecs_to_jiffies(timeout)); | ||
389 | if (timeleft <= 0) { | ||
390 | dev_dbg(&(pcr->pci->dev), "Timeout (%s %d)\n", | ||
391 | __func__, __LINE__); | ||
392 | err = -ETIMEDOUT; | ||
393 | goto out; | ||
394 | } | ||
395 | |||
396 | spin_lock_irqsave(&pcr->lock, flags); | ||
397 | |||
398 | if (pcr->trans_result == TRANS_RESULT_FAIL) | ||
399 | err = -EINVAL; | ||
400 | else if (pcr->trans_result == TRANS_NO_DEVICE) | ||
401 | err = -ENODEV; | ||
402 | |||
403 | spin_unlock_irqrestore(&pcr->lock, flags); | ||
404 | |||
405 | out: | ||
406 | spin_lock_irqsave(&pcr->lock, flags); | ||
407 | pcr->done = NULL; | ||
408 | spin_unlock_irqrestore(&pcr->lock, flags); | ||
409 | |||
410 | dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); | ||
411 | |||
412 | if ((err < 0) && (err != -ENODEV)) | ||
413 | rtsx_pci_stop_cmd(pcr); | ||
414 | |||
415 | if (pcr->finish_me) | ||
416 | complete(pcr->finish_me); | ||
417 | |||
418 | return err; | ||
419 | } | ||
420 | EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data); | ||
421 | |||
422 | int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) | ||
423 | { | ||
424 | int err; | ||
425 | int i, j; | ||
426 | u16 reg; | ||
427 | u8 *ptr; | ||
428 | |||
429 | if (buf_len > 512) | ||
430 | buf_len = 512; | ||
431 | |||
432 | ptr = buf; | ||
433 | reg = PPBUF_BASE2; | ||
434 | for (i = 0; i < buf_len / 256; i++) { | ||
435 | rtsx_pci_init_cmd(pcr); | ||
436 | |||
437 | for (j = 0; j < 256; j++) | ||
438 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); | ||
439 | |||
440 | err = rtsx_pci_send_cmd(pcr, 250); | ||
441 | if (err < 0) | ||
442 | return err; | ||
443 | |||
444 | memcpy(ptr, rtsx_pci_get_cmd_data(pcr), 256); | ||
445 | ptr += 256; | ||
446 | } | ||
447 | |||
448 | if (buf_len % 256) { | ||
449 | rtsx_pci_init_cmd(pcr); | ||
450 | |||
451 | for (j = 0; j < buf_len % 256; j++) | ||
452 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); | ||
453 | |||
454 | err = rtsx_pci_send_cmd(pcr, 250); | ||
455 | if (err < 0) | ||
456 | return err; | ||
457 | } | ||
458 | |||
459 | memcpy(ptr, rtsx_pci_get_cmd_data(pcr), buf_len % 256); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | EXPORT_SYMBOL_GPL(rtsx_pci_read_ppbuf); | ||
464 | |||
465 | int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) | ||
466 | { | ||
467 | int err; | ||
468 | int i, j; | ||
469 | u16 reg; | ||
470 | u8 *ptr; | ||
471 | |||
472 | if (buf_len > 512) | ||
473 | buf_len = 512; | ||
474 | |||
475 | ptr = buf; | ||
476 | reg = PPBUF_BASE2; | ||
477 | for (i = 0; i < buf_len / 256; i++) { | ||
478 | rtsx_pci_init_cmd(pcr); | ||
479 | |||
480 | for (j = 0; j < 256; j++) { | ||
481 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
482 | reg++, 0xFF, *ptr); | ||
483 | ptr++; | ||
484 | } | ||
485 | |||
486 | err = rtsx_pci_send_cmd(pcr, 250); | ||
487 | if (err < 0) | ||
488 | return err; | ||
489 | } | ||
490 | |||
491 | if (buf_len % 256) { | ||
492 | rtsx_pci_init_cmd(pcr); | ||
493 | |||
494 | for (j = 0; j < buf_len % 256; j++) { | ||
495 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
496 | reg++, 0xFF, *ptr); | ||
497 | ptr++; | ||
498 | } | ||
499 | |||
500 | err = rtsx_pci_send_cmd(pcr, 250); | ||
501 | if (err < 0) | ||
502 | return err; | ||
503 | } | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | EXPORT_SYMBOL_GPL(rtsx_pci_write_ppbuf); | ||
508 | |||
509 | static int rtsx_pci_set_pull_ctl(struct rtsx_pcr *pcr, const u32 *tbl) | ||
510 | { | ||
511 | int err; | ||
512 | |||
513 | rtsx_pci_init_cmd(pcr); | ||
514 | |||
515 | while (*tbl & 0xFFFF0000) { | ||
516 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
517 | (u16)(*tbl >> 16), 0xFF, (u8)(*tbl)); | ||
518 | tbl++; | ||
519 | } | ||
520 | |||
521 | err = rtsx_pci_send_cmd(pcr, 100); | ||
522 | if (err < 0) | ||
523 | return err; | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card) | ||
529 | { | ||
530 | const u32 *tbl; | ||
531 | |||
532 | if (card == RTSX_SD_CARD) | ||
533 | tbl = pcr->sd_pull_ctl_enable_tbl; | ||
534 | else if (card == RTSX_MS_CARD) | ||
535 | tbl = pcr->ms_pull_ctl_enable_tbl; | ||
536 | else | ||
537 | return -EINVAL; | ||
538 | |||
539 | return rtsx_pci_set_pull_ctl(pcr, tbl); | ||
540 | } | ||
541 | EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_enable); | ||
542 | |||
543 | int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card) | ||
544 | { | ||
545 | const u32 *tbl; | ||
546 | |||
547 | if (card == RTSX_SD_CARD) | ||
548 | tbl = pcr->sd_pull_ctl_disable_tbl; | ||
549 | else if (card == RTSX_MS_CARD) | ||
550 | tbl = pcr->ms_pull_ctl_disable_tbl; | ||
551 | else | ||
552 | return -EINVAL; | ||
553 | |||
554 | |||
555 | return rtsx_pci_set_pull_ctl(pcr, tbl); | ||
556 | } | ||
557 | EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_disable); | ||
558 | |||
559 | static void rtsx_pci_enable_bus_int(struct rtsx_pcr *pcr) | ||
560 | { | ||
561 | pcr->bier = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN | SD_INT_EN; | ||
562 | |||
563 | if (pcr->num_slots > 1) | ||
564 | pcr->bier |= MS_INT_EN; | ||
565 | |||
566 | /* Enable Bus Interrupt */ | ||
567 | rtsx_pci_writel(pcr, RTSX_BIER, pcr->bier); | ||
568 | |||
569 | dev_dbg(&(pcr->pci->dev), "RTSX_BIER: 0x%08x\n", pcr->bier); | ||
570 | } | ||
571 | |||
572 | static inline u8 double_ssc_depth(u8 depth) | ||
573 | { | ||
574 | return ((depth > 1) ? (depth - 1) : depth); | ||
575 | } | ||
576 | |||
577 | static u8 revise_ssc_depth(u8 ssc_depth, u8 div) | ||
578 | { | ||
579 | if (div > CLK_DIV_1) { | ||
580 | if (ssc_depth > (div - 1)) | ||
581 | ssc_depth -= (div - 1); | ||
582 | else | ||
583 | ssc_depth = SSC_DEPTH_4M; | ||
584 | } | ||
585 | |||
586 | return ssc_depth; | ||
587 | } | ||
588 | |||
589 | int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, | ||
590 | u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk) | ||
591 | { | ||
592 | int err, clk; | ||
593 | u8 N, min_N, max_N, clk_divider; | ||
594 | u8 mcu_cnt, div, max_div; | ||
595 | u8 depth[] = { | ||
596 | [RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M, | ||
597 | [RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M, | ||
598 | [RTSX_SSC_DEPTH_1M] = SSC_DEPTH_1M, | ||
599 | [RTSX_SSC_DEPTH_500K] = SSC_DEPTH_500K, | ||
600 | [RTSX_SSC_DEPTH_250K] = SSC_DEPTH_250K, | ||
601 | }; | ||
602 | |||
603 | if (initial_mode) { | ||
604 | /* We use 250k(around) here, in initial stage */ | ||
605 | clk_divider = SD_CLK_DIVIDE_128; | ||
606 | card_clock = 30000000; | ||
607 | } else { | ||
608 | clk_divider = SD_CLK_DIVIDE_0; | ||
609 | } | ||
610 | err = rtsx_pci_write_register(pcr, SD_CFG1, | ||
611 | SD_CLK_DIVIDE_MASK, clk_divider); | ||
612 | if (err < 0) | ||
613 | return err; | ||
614 | |||
615 | card_clock /= 1000000; | ||
616 | dev_dbg(&(pcr->pci->dev), "Switch card clock to %dMHz\n", card_clock); | ||
617 | |||
618 | min_N = 80; | ||
619 | max_N = 208; | ||
620 | max_div = CLK_DIV_8; | ||
621 | |||
622 | clk = card_clock; | ||
623 | if (!initial_mode && double_clk) | ||
624 | clk = card_clock * 2; | ||
625 | dev_dbg(&(pcr->pci->dev), | ||
626 | "Internal SSC clock: %dMHz (cur_clock = %d)\n", | ||
627 | clk, pcr->cur_clock); | ||
628 | |||
629 | if (clk == pcr->cur_clock) | ||
630 | return 0; | ||
631 | |||
632 | N = (u8)(clk - 2); | ||
633 | if ((clk <= 2) || (N > max_N)) | ||
634 | return -EINVAL; | ||
635 | |||
636 | mcu_cnt = (u8)(125/clk + 3); | ||
637 | if (mcu_cnt > 15) | ||
638 | mcu_cnt = 15; | ||
639 | |||
640 | /* Make sure that the SSC clock div_n is equal or greater than min_N */ | ||
641 | div = CLK_DIV_1; | ||
642 | while ((N < min_N) && (div < max_div)) { | ||
643 | N = (N + 2) * 2 - 2; | ||
644 | div++; | ||
645 | } | ||
646 | dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div); | ||
647 | |||
648 | ssc_depth = depth[ssc_depth]; | ||
649 | if (double_clk) | ||
650 | ssc_depth = double_ssc_depth(ssc_depth); | ||
651 | |||
652 | ssc_depth = revise_ssc_depth(ssc_depth, div); | ||
653 | dev_dbg(&(pcr->pci->dev), "ssc_depth = %d\n", ssc_depth); | ||
654 | |||
655 | rtsx_pci_init_cmd(pcr); | ||
656 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, | ||
657 | CLK_LOW_FREQ, CLK_LOW_FREQ); | ||
658 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, | ||
659 | 0xFF, (div << 4) | mcu_cnt); | ||
660 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0); | ||
661 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, | ||
662 | SSC_DEPTH_MASK, ssc_depth); | ||
663 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N); | ||
664 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB); | ||
665 | if (vpclk) { | ||
666 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, | ||
667 | PHASE_NOT_RESET, 0); | ||
668 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, | ||
669 | PHASE_NOT_RESET, PHASE_NOT_RESET); | ||
670 | } | ||
671 | |||
672 | err = rtsx_pci_send_cmd(pcr, 2000); | ||
673 | if (err < 0) | ||
674 | return err; | ||
675 | |||
676 | /* Wait SSC clock stable */ | ||
677 | udelay(10); | ||
678 | err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0); | ||
679 | if (err < 0) | ||
680 | return err; | ||
681 | |||
682 | pcr->cur_clock = clk; | ||
683 | return 0; | ||
684 | } | ||
685 | EXPORT_SYMBOL_GPL(rtsx_pci_switch_clock); | ||
686 | |||
687 | int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card) | ||
688 | { | ||
689 | if (pcr->ops->card_power_on) | ||
690 | return pcr->ops->card_power_on(pcr, card); | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | EXPORT_SYMBOL_GPL(rtsx_pci_card_power_on); | ||
695 | |||
696 | int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card) | ||
697 | { | ||
698 | if (pcr->ops->card_power_off) | ||
699 | return pcr->ops->card_power_off(pcr, card); | ||
700 | |||
701 | return 0; | ||
702 | } | ||
703 | EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off); | ||
704 | |||
705 | unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr) | ||
706 | { | ||
707 | unsigned int val; | ||
708 | |||
709 | val = rtsx_pci_readl(pcr, RTSX_BIPR); | ||
710 | if (pcr->ops->cd_deglitch) | ||
711 | val = pcr->ops->cd_deglitch(pcr); | ||
712 | |||
713 | return val; | ||
714 | } | ||
715 | EXPORT_SYMBOL_GPL(rtsx_pci_card_exist); | ||
716 | |||
717 | void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr) | ||
718 | { | ||
719 | struct completion finish; | ||
720 | |||
721 | pcr->finish_me = &finish; | ||
722 | init_completion(&finish); | ||
723 | |||
724 | if (pcr->done) | ||
725 | complete(pcr->done); | ||
726 | |||
727 | if (!pcr->remove_pci) | ||
728 | rtsx_pci_stop_cmd(pcr); | ||
729 | |||
730 | wait_for_completion_interruptible_timeout(&finish, | ||
731 | msecs_to_jiffies(2)); | ||
732 | pcr->finish_me = NULL; | ||
733 | } | ||
734 | EXPORT_SYMBOL_GPL(rtsx_pci_complete_unfinished_transfer); | ||
735 | |||
736 | static void rtsx_pci_card_detect(struct work_struct *work) | ||
737 | { | ||
738 | struct delayed_work *dwork; | ||
739 | struct rtsx_pcr *pcr; | ||
740 | unsigned long flags; | ||
741 | unsigned int card_detect = 0; | ||
742 | u32 irq_status; | ||
743 | |||
744 | dwork = to_delayed_work(work); | ||
745 | pcr = container_of(dwork, struct rtsx_pcr, carddet_work); | ||
746 | |||
747 | dev_dbg(&(pcr->pci->dev), "--> %s\n", __func__); | ||
748 | |||
749 | spin_lock_irqsave(&pcr->lock, flags); | ||
750 | |||
751 | irq_status = rtsx_pci_readl(pcr, RTSX_BIPR); | ||
752 | dev_dbg(&(pcr->pci->dev), "irq_status: 0x%08x\n", irq_status); | ||
753 | |||
754 | if (pcr->card_inserted || pcr->card_removed) { | ||
755 | dev_dbg(&(pcr->pci->dev), | ||
756 | "card_inserted: 0x%x, card_removed: 0x%x\n", | ||
757 | pcr->card_inserted, pcr->card_removed); | ||
758 | |||
759 | if (pcr->ops->cd_deglitch) | ||
760 | pcr->card_inserted = pcr->ops->cd_deglitch(pcr); | ||
761 | |||
762 | card_detect = pcr->card_inserted | pcr->card_removed; | ||
763 | pcr->card_inserted = 0; | ||
764 | pcr->card_removed = 0; | ||
765 | } | ||
766 | |||
767 | spin_unlock_irqrestore(&pcr->lock, flags); | ||
768 | |||
769 | if (card_detect & SD_EXIST) | ||
770 | pcr->slots[RTSX_SD_CARD].card_event( | ||
771 | pcr->slots[RTSX_SD_CARD].p_dev); | ||
772 | if (card_detect & MS_EXIST) | ||
773 | pcr->slots[RTSX_MS_CARD].card_event( | ||
774 | pcr->slots[RTSX_MS_CARD].p_dev); | ||
775 | } | ||
776 | |||
777 | static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) | ||
778 | { | ||
779 | struct rtsx_pcr *pcr = dev_id; | ||
780 | u32 int_reg; | ||
781 | |||
782 | if (!pcr) | ||
783 | return IRQ_NONE; | ||
784 | |||
785 | spin_lock(&pcr->lock); | ||
786 | |||
787 | int_reg = rtsx_pci_readl(pcr, RTSX_BIPR); | ||
788 | /* Clear interrupt flag */ | ||
789 | rtsx_pci_writel(pcr, RTSX_BIPR, int_reg); | ||
790 | if ((int_reg & pcr->bier) == 0) { | ||
791 | spin_unlock(&pcr->lock); | ||
792 | return IRQ_NONE; | ||
793 | } | ||
794 | if (int_reg == 0xFFFFFFFF) { | ||
795 | spin_unlock(&pcr->lock); | ||
796 | return IRQ_HANDLED; | ||
797 | } | ||
798 | |||
799 | int_reg &= (pcr->bier | 0x7FFFFF); | ||
800 | |||
801 | if (int_reg & SD_INT) { | ||
802 | if (int_reg & SD_EXIST) { | ||
803 | pcr->card_inserted |= SD_EXIST; | ||
804 | } else { | ||
805 | pcr->card_removed |= SD_EXIST; | ||
806 | pcr->card_inserted &= ~SD_EXIST; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | if (int_reg & MS_INT) { | ||
811 | if (int_reg & MS_EXIST) { | ||
812 | pcr->card_inserted |= MS_EXIST; | ||
813 | } else { | ||
814 | pcr->card_removed |= MS_EXIST; | ||
815 | pcr->card_inserted &= ~MS_EXIST; | ||
816 | } | ||
817 | } | ||
818 | |||
819 | if (pcr->card_inserted || pcr->card_removed) | ||
820 | schedule_delayed_work(&pcr->carddet_work, | ||
821 | msecs_to_jiffies(200)); | ||
822 | |||
823 | if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) { | ||
824 | if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) { | ||
825 | pcr->trans_result = TRANS_RESULT_FAIL; | ||
826 | if (pcr->done) | ||
827 | complete(pcr->done); | ||
828 | } else if (int_reg & TRANS_OK_INT) { | ||
829 | pcr->trans_result = TRANS_RESULT_OK; | ||
830 | if (pcr->done) | ||
831 | complete(pcr->done); | ||
832 | } | ||
833 | } | ||
834 | |||
835 | spin_unlock(&pcr->lock); | ||
836 | return IRQ_HANDLED; | ||
837 | } | ||
838 | |||
839 | static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr) | ||
840 | { | ||
841 | dev_info(&(pcr->pci->dev), "%s: pcr->msi_en = %d, pci->irq = %d\n", | ||
842 | __func__, pcr->msi_en, pcr->pci->irq); | ||
843 | |||
844 | if (request_irq(pcr->pci->irq, rtsx_pci_isr, | ||
845 | pcr->msi_en ? 0 : IRQF_SHARED, | ||
846 | DRV_NAME_RTSX_PCI, pcr)) { | ||
847 | dev_err(&(pcr->pci->dev), | ||
848 | "rtsx_sdmmc: unable to grab IRQ %d, disabling device\n", | ||
849 | pcr->pci->irq); | ||
850 | return -1; | ||
851 | } | ||
852 | |||
853 | pcr->irq = pcr->pci->irq; | ||
854 | pci_intx(pcr->pci, !pcr->msi_en); | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static void rtsx_pci_idle_work(struct work_struct *work) | ||
860 | { | ||
861 | struct delayed_work *dwork = to_delayed_work(work); | ||
862 | struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work); | ||
863 | |||
864 | dev_dbg(&(pcr->pci->dev), "--> %s\n", __func__); | ||
865 | |||
866 | mutex_lock(&pcr->pcr_mutex); | ||
867 | |||
868 | pcr->state = PDEV_STAT_IDLE; | ||
869 | |||
870 | if (pcr->ops->disable_auto_blink) | ||
871 | pcr->ops->disable_auto_blink(pcr); | ||
872 | if (pcr->ops->turn_off_led) | ||
873 | pcr->ops->turn_off_led(pcr); | ||
874 | |||
875 | mutex_unlock(&pcr->pcr_mutex); | ||
876 | } | ||
877 | |||
878 | static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) | ||
879 | { | ||
880 | int err; | ||
881 | |||
882 | rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); | ||
883 | |||
884 | rtsx_pci_enable_bus_int(pcr); | ||
885 | |||
886 | /* Power on SSC */ | ||
887 | err = rtsx_pci_write_register(pcr, FPDCTL, SSC_POWER_DOWN, 0); | ||
888 | if (err < 0) | ||
889 | return err; | ||
890 | |||
891 | /* Wait SSC power stable */ | ||
892 | udelay(200); | ||
893 | |||
894 | if (pcr->ops->optimize_phy) { | ||
895 | err = pcr->ops->optimize_phy(pcr); | ||
896 | if (err < 0) | ||
897 | return err; | ||
898 | } | ||
899 | |||
900 | rtsx_pci_init_cmd(pcr); | ||
901 | |||
902 | /* Set mcu_cnt to 7 to ensure data can be sampled properly */ | ||
903 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, 0x07, 0x07); | ||
904 | |||
905 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00); | ||
906 | /* Disable card clock */ | ||
907 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0); | ||
908 | /* Reset ASPM state to default value */ | ||
909 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); | ||
910 | /* Reset delink mode */ | ||
911 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0); | ||
912 | /* Card driving select */ | ||
913 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, | ||
914 | 0x07, DRIVER_TYPE_D); | ||
915 | /* Enable SSC Clock */ | ||
916 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, | ||
917 | 0xFF, SSC_8X_EN | SSC_SEL_4M); | ||
918 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12); | ||
919 | /* Disable cd_pwr_save */ | ||
920 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x16, 0x10); | ||
921 | /* Clear Link Ready Interrupt */ | ||
922 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, | ||
923 | LINK_RDY_INT, LINK_RDY_INT); | ||
924 | /* Enlarge the estimation window of PERST# glitch | ||
925 | * to reduce the chance of invalid card interrupt | ||
926 | */ | ||
927 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PERST_GLITCH_WIDTH, 0xFF, 0x80); | ||
928 | /* Update RC oscillator to 400k | ||
929 | * bit[0] F_HIGH: for RC oscillator, Rst_value is 1'b1 | ||
930 | * 1: 2M 0: 400k | ||
931 | */ | ||
932 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RCCTL, 0x01, 0x00); | ||
933 | /* Set interrupt write clear | ||
934 | * bit 1: U_elbi_if_rd_clr_en | ||
935 | * 1: Enable ELBI interrupt[31:22] & [7:0] flag read clear | ||
936 | * 0: ELBI interrupt flag[31:22] & [7:0] only can be write clear | ||
937 | */ | ||
938 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0); | ||
939 | /* Force CLKREQ# PIN to drive 0 to request clock */ | ||
940 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); | ||
941 | |||
942 | err = rtsx_pci_send_cmd(pcr, 100); | ||
943 | if (err < 0) | ||
944 | return err; | ||
945 | |||
946 | /* Enable clk_request_n to enable clock power management */ | ||
947 | rtsx_pci_write_config_byte(pcr, 0x81, 1); | ||
948 | /* Enter L1 when host tx idle */ | ||
949 | rtsx_pci_write_config_byte(pcr, 0x70F, 0x5B); | ||
950 | |||
951 | if (pcr->ops->extra_init_hw) { | ||
952 | err = pcr->ops->extra_init_hw(pcr); | ||
953 | if (err < 0) | ||
954 | return err; | ||
955 | } | ||
956 | |||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) | ||
961 | { | ||
962 | int err; | ||
963 | |||
964 | spin_lock_init(&pcr->lock); | ||
965 | mutex_init(&pcr->pcr_mutex); | ||
966 | |||
967 | switch (PCI_PID(pcr)) { | ||
968 | default: | ||
969 | case 0x5209: | ||
970 | rts5209_init_params(pcr); | ||
971 | break; | ||
972 | |||
973 | case 0x5229: | ||
974 | rts5229_init_params(pcr); | ||
975 | break; | ||
976 | |||
977 | case 0x5289: | ||
978 | rtl8411_init_params(pcr); | ||
979 | break; | ||
980 | } | ||
981 | |||
982 | dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", | ||
983 | PCI_PID(pcr), pcr->ic_version); | ||
984 | |||
985 | pcr->slots = kcalloc(pcr->num_slots, sizeof(struct rtsx_slot), | ||
986 | GFP_KERNEL); | ||
987 | if (!pcr->slots) | ||
988 | return -ENOMEM; | ||
989 | |||
990 | pcr->state = PDEV_STAT_IDLE; | ||
991 | err = rtsx_pci_init_hw(pcr); | ||
992 | if (err < 0) { | ||
993 | kfree(pcr->slots); | ||
994 | return err; | ||
995 | } | ||
996 | |||
997 | return 0; | ||
998 | } | ||
999 | |||
1000 | static int __devinit rtsx_pci_probe(struct pci_dev *pcidev, | ||
1001 | const struct pci_device_id *id) | ||
1002 | { | ||
1003 | struct rtsx_pcr *pcr; | ||
1004 | struct pcr_handle *handle; | ||
1005 | u32 base, len; | ||
1006 | int ret, i; | ||
1007 | |||
1008 | dev_dbg(&(pcidev->dev), | ||
1009 | ": Realtek PCI-E Card Reader found at %s [%04x:%04x] (rev %x)\n", | ||
1010 | pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, | ||
1011 | (int)pcidev->revision); | ||
1012 | |||
1013 | ret = pci_enable_device(pcidev); | ||
1014 | if (ret) | ||
1015 | return ret; | ||
1016 | |||
1017 | ret = pci_request_regions(pcidev, DRV_NAME_RTSX_PCI); | ||
1018 | if (ret) | ||
1019 | goto disable; | ||
1020 | |||
1021 | pcr = kzalloc(sizeof(*pcr), GFP_KERNEL); | ||
1022 | if (!pcr) { | ||
1023 | ret = -ENOMEM; | ||
1024 | goto release_pci; | ||
1025 | } | ||
1026 | |||
1027 | handle = kzalloc(sizeof(*handle), GFP_KERNEL); | ||
1028 | if (!handle) { | ||
1029 | ret = -ENOMEM; | ||
1030 | goto free_pcr; | ||
1031 | } | ||
1032 | handle->pcr = pcr; | ||
1033 | |||
1034 | if (!idr_pre_get(&rtsx_pci_idr, GFP_KERNEL)) { | ||
1035 | ret = -ENOMEM; | ||
1036 | goto free_handle; | ||
1037 | } | ||
1038 | |||
1039 | spin_lock(&rtsx_pci_lock); | ||
1040 | ret = idr_get_new(&rtsx_pci_idr, pcr, &pcr->id); | ||
1041 | spin_unlock(&rtsx_pci_lock); | ||
1042 | if (ret) | ||
1043 | goto free_handle; | ||
1044 | |||
1045 | pcr->pci = pcidev; | ||
1046 | dev_set_drvdata(&pcidev->dev, handle); | ||
1047 | |||
1048 | len = pci_resource_len(pcidev, 0); | ||
1049 | base = pci_resource_start(pcidev, 0); | ||
1050 | pcr->remap_addr = ioremap_nocache(base, len); | ||
1051 | if (!pcr->remap_addr) { | ||
1052 | ret = -ENOMEM; | ||
1053 | goto free_host; | ||
1054 | } | ||
1055 | |||
1056 | pcr->rtsx_resv_buf = dma_alloc_coherent(&(pcidev->dev), | ||
1057 | RTSX_RESV_BUF_LEN, &(pcr->rtsx_resv_buf_addr), | ||
1058 | GFP_KERNEL); | ||
1059 | if (pcr->rtsx_resv_buf == NULL) { | ||
1060 | ret = -ENXIO; | ||
1061 | goto unmap; | ||
1062 | } | ||
1063 | pcr->host_cmds_ptr = pcr->rtsx_resv_buf; | ||
1064 | pcr->host_cmds_addr = pcr->rtsx_resv_buf_addr; | ||
1065 | pcr->host_sg_tbl_ptr = pcr->rtsx_resv_buf + HOST_CMDS_BUF_LEN; | ||
1066 | pcr->host_sg_tbl_addr = pcr->rtsx_resv_buf_addr + HOST_CMDS_BUF_LEN; | ||
1067 | |||
1068 | pcr->card_inserted = 0; | ||
1069 | pcr->card_removed = 0; | ||
1070 | INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect); | ||
1071 | INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work); | ||
1072 | |||
1073 | pcr->msi_en = msi_en; | ||
1074 | if (pcr->msi_en) { | ||
1075 | ret = pci_enable_msi(pcidev); | ||
1076 | if (ret < 0) | ||
1077 | pcr->msi_en = false; | ||
1078 | } | ||
1079 | |||
1080 | ret = rtsx_pci_acquire_irq(pcr); | ||
1081 | if (ret < 0) | ||
1082 | goto free_dma; | ||
1083 | |||
1084 | pci_set_master(pcidev); | ||
1085 | synchronize_irq(pcr->irq); | ||
1086 | |||
1087 | ret = rtsx_pci_init_chip(pcr); | ||
1088 | if (ret < 0) | ||
1089 | goto disable_irq; | ||
1090 | |||
1091 | for (i = 0; i < ARRAY_SIZE(rtsx_pcr_cells); i++) { | ||
1092 | rtsx_pcr_cells[i].platform_data = handle; | ||
1093 | rtsx_pcr_cells[i].pdata_size = sizeof(*handle); | ||
1094 | } | ||
1095 | ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells, | ||
1096 | ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL); | ||
1097 | if (ret < 0) | ||
1098 | goto disable_irq; | ||
1099 | |||
1100 | schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); | ||
1101 | |||
1102 | return 0; | ||
1103 | |||
1104 | disable_irq: | ||
1105 | free_irq(pcr->irq, (void *)pcr); | ||
1106 | free_dma: | ||
1107 | dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, | ||
1108 | pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); | ||
1109 | unmap: | ||
1110 | iounmap(pcr->remap_addr); | ||
1111 | free_host: | ||
1112 | dev_set_drvdata(&pcidev->dev, NULL); | ||
1113 | free_handle: | ||
1114 | kfree(handle); | ||
1115 | free_pcr: | ||
1116 | kfree(pcr); | ||
1117 | release_pci: | ||
1118 | pci_release_regions(pcidev); | ||
1119 | disable: | ||
1120 | pci_disable_device(pcidev); | ||
1121 | |||
1122 | return ret; | ||
1123 | } | ||
1124 | |||
1125 | static void __devexit rtsx_pci_remove(struct pci_dev *pcidev) | ||
1126 | { | ||
1127 | struct pcr_handle *handle = pci_get_drvdata(pcidev); | ||
1128 | struct rtsx_pcr *pcr = handle->pcr; | ||
1129 | |||
1130 | pcr->remove_pci = true; | ||
1131 | |||
1132 | cancel_delayed_work(&pcr->carddet_work); | ||
1133 | cancel_delayed_work(&pcr->idle_work); | ||
1134 | |||
1135 | mfd_remove_devices(&pcidev->dev); | ||
1136 | |||
1137 | dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, | ||
1138 | pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); | ||
1139 | free_irq(pcr->irq, (void *)pcr); | ||
1140 | if (pcr->msi_en) | ||
1141 | pci_disable_msi(pcr->pci); | ||
1142 | iounmap(pcr->remap_addr); | ||
1143 | |||
1144 | dev_set_drvdata(&pcidev->dev, NULL); | ||
1145 | pci_release_regions(pcidev); | ||
1146 | pci_disable_device(pcidev); | ||
1147 | |||
1148 | spin_lock(&rtsx_pci_lock); | ||
1149 | idr_remove(&rtsx_pci_idr, pcr->id); | ||
1150 | spin_unlock(&rtsx_pci_lock); | ||
1151 | |||
1152 | kfree(pcr->slots); | ||
1153 | kfree(pcr); | ||
1154 | kfree(handle); | ||
1155 | |||
1156 | dev_dbg(&(pcidev->dev), | ||
1157 | ": Realtek PCI-E Card Reader at %s [%04x:%04x] has been removed\n", | ||
1158 | pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device); | ||
1159 | } | ||
1160 | |||
1161 | #ifdef CONFIG_PM | ||
1162 | |||
1163 | static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) | ||
1164 | { | ||
1165 | struct pcr_handle *handle; | ||
1166 | struct rtsx_pcr *pcr; | ||
1167 | int ret = 0; | ||
1168 | |||
1169 | dev_dbg(&(pcidev->dev), "--> %s\n", __func__); | ||
1170 | |||
1171 | handle = pci_get_drvdata(pcidev); | ||
1172 | pcr = handle->pcr; | ||
1173 | |||
1174 | cancel_delayed_work(&pcr->carddet_work); | ||
1175 | cancel_delayed_work(&pcr->idle_work); | ||
1176 | |||
1177 | mutex_lock(&pcr->pcr_mutex); | ||
1178 | |||
1179 | if (pcr->ops->turn_off_led) | ||
1180 | pcr->ops->turn_off_led(pcr); | ||
1181 | |||
1182 | rtsx_pci_writel(pcr, RTSX_BIER, 0); | ||
1183 | pcr->bier = 0; | ||
1184 | |||
1185 | rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08); | ||
1186 | rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x02); | ||
1187 | |||
1188 | pci_save_state(pcidev); | ||
1189 | pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); | ||
1190 | pci_disable_device(pcidev); | ||
1191 | pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); | ||
1192 | |||
1193 | mutex_unlock(&pcr->pcr_mutex); | ||
1194 | return ret; | ||
1195 | } | ||
1196 | |||
1197 | static int rtsx_pci_resume(struct pci_dev *pcidev) | ||
1198 | { | ||
1199 | struct pcr_handle *handle; | ||
1200 | struct rtsx_pcr *pcr; | ||
1201 | int ret = 0; | ||
1202 | |||
1203 | dev_dbg(&(pcidev->dev), "--> %s\n", __func__); | ||
1204 | |||
1205 | handle = pci_get_drvdata(pcidev); | ||
1206 | pcr = handle->pcr; | ||
1207 | |||
1208 | mutex_lock(&pcr->pcr_mutex); | ||
1209 | |||
1210 | pci_set_power_state(pcidev, PCI_D0); | ||
1211 | pci_restore_state(pcidev); | ||
1212 | ret = pci_enable_device(pcidev); | ||
1213 | if (ret) | ||
1214 | goto out; | ||
1215 | pci_set_master(pcidev); | ||
1216 | |||
1217 | ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00); | ||
1218 | if (ret) | ||
1219 | goto out; | ||
1220 | |||
1221 | ret = rtsx_pci_init_hw(pcr); | ||
1222 | if (ret) | ||
1223 | goto out; | ||
1224 | |||
1225 | schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); | ||
1226 | |||
1227 | out: | ||
1228 | mutex_unlock(&pcr->pcr_mutex); | ||
1229 | return ret; | ||
1230 | } | ||
1231 | |||
1232 | #else /* CONFIG_PM */ | ||
1233 | |||
1234 | #define rtsx_pci_suspend NULL | ||
1235 | #define rtsx_pci_resume NULL | ||
1236 | |||
1237 | #endif /* CONFIG_PM */ | ||
1238 | |||
1239 | static struct pci_driver rtsx_pci_driver = { | ||
1240 | .name = DRV_NAME_RTSX_PCI, | ||
1241 | .id_table = rtsx_pci_ids, | ||
1242 | .probe = rtsx_pci_probe, | ||
1243 | .remove = __devexit_p(rtsx_pci_remove), | ||
1244 | .suspend = rtsx_pci_suspend, | ||
1245 | .resume = rtsx_pci_resume, | ||
1246 | }; | ||
1247 | module_pci_driver(rtsx_pci_driver); | ||
1248 | |||
1249 | MODULE_LICENSE("GPL"); | ||
1250 | MODULE_AUTHOR("Wei WANG <wei_wang@realsil.com.cn>"); | ||
1251 | MODULE_DESCRIPTION("Realtek PCI-E Card Reader Driver"); | ||
diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h new file mode 100644 index 00000000000..12462c1df1a --- /dev/null +++ b/drivers/mfd/rtsx_pcr.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* Driver for Realtek PCI-Express card reader | ||
2 | * | ||
3 | * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #ifndef __RTSX_PCR_H | ||
24 | #define __RTSX_PCR_H | ||
25 | |||
26 | #include <linux/mfd/rtsx_pci.h> | ||
27 | |||
28 | void rts5209_init_params(struct rtsx_pcr *pcr); | ||
29 | void rts5229_init_params(struct rtsx_pcr *pcr); | ||
30 | void rtl8411_init_params(struct rtsx_pcr *pcr); | ||
31 | |||
32 | #endif | ||
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 820826270b6..705b881e186 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c | |||
@@ -51,7 +51,7 @@ static const struct ad_dpot_bus_ops bops = { | |||
51 | .write_r8d16 = write_r8d16, | 51 | .write_r8d16 = write_r8d16, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static int __devinit ad_dpot_i2c_probe(struct i2c_client *client, | 54 | static int ad_dpot_i2c_probe(struct i2c_client *client, |
55 | const struct i2c_device_id *id) | 55 | const struct i2c_device_id *id) |
56 | { | 56 | { |
57 | struct ad_dpot_bus_data bdata = { | 57 | struct ad_dpot_bus_data bdata = { |
@@ -68,7 +68,7 @@ static int __devinit ad_dpot_i2c_probe(struct i2c_client *client, | |||
68 | return ad_dpot_probe(&client->dev, &bdata, id->driver_data, id->name); | 68 | return ad_dpot_probe(&client->dev, &bdata, id->driver_data, id->name); |
69 | } | 69 | } |
70 | 70 | ||
71 | static int __devexit ad_dpot_i2c_remove(struct i2c_client *client) | 71 | static int ad_dpot_i2c_remove(struct i2c_client *client) |
72 | { | 72 | { |
73 | return ad_dpot_remove(&client->dev); | 73 | return ad_dpot_remove(&client->dev); |
74 | } | 74 | } |
@@ -109,7 +109,7 @@ static struct i2c_driver ad_dpot_i2c_driver = { | |||
109 | .owner = THIS_MODULE, | 109 | .owner = THIS_MODULE, |
110 | }, | 110 | }, |
111 | .probe = ad_dpot_i2c_probe, | 111 | .probe = ad_dpot_i2c_probe, |
112 | .remove = __devexit_p(ad_dpot_i2c_remove), | 112 | .remove = ad_dpot_i2c_remove, |
113 | .id_table = ad_dpot_id, | 113 | .id_table = ad_dpot_id, |
114 | }; | 114 | }; |
115 | 115 | ||
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index f62317540d0..9da04ede04f 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c | |||
@@ -75,7 +75,7 @@ static const struct ad_dpot_bus_ops bops = { | |||
75 | .write_r8d8 = write16, | 75 | .write_r8d8 = write16, |
76 | .write_r8d16 = write24, | 76 | .write_r8d16 = write24, |
77 | }; | 77 | }; |
78 | static int __devinit ad_dpot_spi_probe(struct spi_device *spi) | 78 | static int ad_dpot_spi_probe(struct spi_device *spi) |
79 | { | 79 | { |
80 | struct ad_dpot_bus_data bdata = { | 80 | struct ad_dpot_bus_data bdata = { |
81 | .client = spi, | 81 | .client = spi, |
@@ -87,7 +87,7 @@ static int __devinit ad_dpot_spi_probe(struct spi_device *spi) | |||
87 | spi_get_device_id(spi)->name); | 87 | spi_get_device_id(spi)->name); |
88 | } | 88 | } |
89 | 89 | ||
90 | static int __devexit ad_dpot_spi_remove(struct spi_device *spi) | 90 | static int ad_dpot_spi_remove(struct spi_device *spi) |
91 | { | 91 | { |
92 | return ad_dpot_remove(&spi->dev); | 92 | return ad_dpot_remove(&spi->dev); |
93 | } | 93 | } |
@@ -131,7 +131,7 @@ static struct spi_driver ad_dpot_spi_driver = { | |||
131 | .owner = THIS_MODULE, | 131 | .owner = THIS_MODULE, |
132 | }, | 132 | }, |
133 | .probe = ad_dpot_spi_probe, | 133 | .probe = ad_dpot_spi_probe, |
134 | .remove = __devexit_p(ad_dpot_spi_remove), | 134 | .remove = ad_dpot_spi_remove, |
135 | .id_table = ad_dpot_spi_id, | 135 | .id_table = ad_dpot_spi_id, |
136 | }; | 136 | }; |
137 | 137 | ||
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 6938f1be664..8f99e8e3f0a 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c | |||
@@ -641,7 +641,7 @@ static const struct attribute_group ad525x_group_commands = { | |||
641 | .attrs = ad525x_attributes_commands, | 641 | .attrs = ad525x_attributes_commands, |
642 | }; | 642 | }; |
643 | 643 | ||
644 | __devinit int ad_dpot_add_files(struct device *dev, | 644 | int ad_dpot_add_files(struct device *dev, |
645 | unsigned features, unsigned rdac) | 645 | unsigned features, unsigned rdac) |
646 | { | 646 | { |
647 | int err = sysfs_create_file(&dev->kobj, | 647 | int err = sysfs_create_file(&dev->kobj, |
@@ -685,7 +685,7 @@ inline void ad_dpot_remove_files(struct device *dev, | |||
685 | } | 685 | } |
686 | } | 686 | } |
687 | 687 | ||
688 | int __devinit ad_dpot_probe(struct device *dev, | 688 | int ad_dpot_probe(struct device *dev, |
689 | struct ad_dpot_bus_data *bdata, unsigned long devid, | 689 | struct ad_dpot_bus_data *bdata, unsigned long devid, |
690 | const char *name) | 690 | const char *name) |
691 | { | 691 | { |
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c index 0314773f6db..d648b089302 100644 --- a/drivers/misc/apds9802als.c +++ b/drivers/misc/apds9802als.c | |||
@@ -68,7 +68,7 @@ static int als_wait_for_data_ready(struct device *dev) | |||
68 | ret = i2c_smbus_read_byte_data(client, 0x86); | 68 | ret = i2c_smbus_read_byte_data(client, 0x86); |
69 | } while (!(ret & 0x80) && retry--); | 69 | } while (!(ret & 0x80) && retry--); |
70 | 70 | ||
71 | if (!retry) { | 71 | if (retry < 0) { |
72 | dev_warn(dev, "timeout waiting for data ready\n"); | 72 | dev_warn(dev, "timeout waiting for data ready\n"); |
73 | return -ETIMEDOUT; | 73 | return -ETIMEDOUT; |
74 | } | 74 | } |
@@ -254,7 +254,7 @@ als_error1: | |||
254 | return res; | 254 | return res; |
255 | } | 255 | } |
256 | 256 | ||
257 | static int __devexit apds9802als_remove(struct i2c_client *client) | 257 | static int apds9802als_remove(struct i2c_client *client) |
258 | { | 258 | { |
259 | struct als_data *data = i2c_get_clientdata(client); | 259 | struct als_data *data = i2c_get_clientdata(client); |
260 | 260 | ||
@@ -326,7 +326,7 @@ static struct i2c_driver apds9802als_driver = { | |||
326 | .pm = APDS9802ALS_PM_OPS, | 326 | .pm = APDS9802ALS_PM_OPS, |
327 | }, | 327 | }, |
328 | .probe = apds9802als_probe, | 328 | .probe = apds9802als_probe, |
329 | .remove = __devexit_p(apds9802als_remove), | 329 | .remove = apds9802als_remove, |
330 | .suspend = apds9802als_suspend, | 330 | .suspend = apds9802als_suspend, |
331 | .resume = apds9802als_resume, | 331 | .resume = apds9802als_resume, |
332 | .id_table = apds9802als_id, | 332 | .id_table = apds9802als_id, |
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index ee74244aa03..0e67f8263cd 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c | |||
@@ -1047,7 +1047,7 @@ static struct attribute_group apds990x_attribute_group[] = { | |||
1047 | {.attrs = sysfs_attrs_ctrl }, | 1047 | {.attrs = sysfs_attrs_ctrl }, |
1048 | }; | 1048 | }; |
1049 | 1049 | ||
1050 | static int __devinit apds990x_probe(struct i2c_client *client, | 1050 | static int apds990x_probe(struct i2c_client *client, |
1051 | const struct i2c_device_id *id) | 1051 | const struct i2c_device_id *id) |
1052 | { | 1052 | { |
1053 | struct apds990x_chip *chip; | 1053 | struct apds990x_chip *chip; |
@@ -1181,7 +1181,7 @@ fail1: | |||
1181 | return err; | 1181 | return err; |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | static int __devexit apds990x_remove(struct i2c_client *client) | 1184 | static int apds990x_remove(struct i2c_client *client) |
1185 | { | 1185 | { |
1186 | struct apds990x_chip *chip = i2c_get_clientdata(client); | 1186 | struct apds990x_chip *chip = i2c_get_clientdata(client); |
1187 | 1187 | ||
@@ -1275,7 +1275,7 @@ static struct i2c_driver apds990x_driver = { | |||
1275 | .pm = &apds990x_pm_ops, | 1275 | .pm = &apds990x_pm_ops, |
1276 | }, | 1276 | }, |
1277 | .probe = apds990x_probe, | 1277 | .probe = apds990x_probe, |
1278 | .remove = __devexit_p(apds990x_remove), | 1278 | .remove = apds990x_remove, |
1279 | .id_table = apds990x_id, | 1279 | .id_table = apds990x_id, |
1280 | }; | 1280 | }; |
1281 | 1281 | ||
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 5bb18778107..c58f9abcb35 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c | |||
@@ -137,7 +137,7 @@ out: | |||
137 | return retval; | 137 | return retval; |
138 | } | 138 | } |
139 | 139 | ||
140 | static int __devexit ssc_remove(struct platform_device *pdev) | 140 | static int ssc_remove(struct platform_device *pdev) |
141 | { | 141 | { |
142 | struct ssc_device *ssc = platform_get_drvdata(pdev); | 142 | struct ssc_device *ssc = platform_get_drvdata(pdev); |
143 | 143 | ||
@@ -152,7 +152,7 @@ static int __devexit ssc_remove(struct platform_device *pdev) | |||
152 | } | 152 | } |
153 | 153 | ||
154 | static struct platform_driver ssc_driver = { | 154 | static struct platform_driver ssc_driver = { |
155 | .remove = __devexit_p(ssc_remove), | 155 | .remove = ssc_remove, |
156 | .driver = { | 156 | .driver = { |
157 | .name = "ssc", | 157 | .name = "ssc", |
158 | .owner = THIS_MODULE, | 158 | .owner = THIS_MODULE, |
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index 3d56ae7ef8d..2ed8fc3be7e 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c | |||
@@ -1162,7 +1162,7 @@ static struct attribute_group bh1770_attribute_group = { | |||
1162 | .attrs = sysfs_attrs | 1162 | .attrs = sysfs_attrs |
1163 | }; | 1163 | }; |
1164 | 1164 | ||
1165 | static int __devinit bh1770_probe(struct i2c_client *client, | 1165 | static int bh1770_probe(struct i2c_client *client, |
1166 | const struct i2c_device_id *id) | 1166 | const struct i2c_device_id *id) |
1167 | { | 1167 | { |
1168 | struct bh1770_chip *chip; | 1168 | struct bh1770_chip *chip; |
@@ -1285,7 +1285,7 @@ fail1: | |||
1285 | return err; | 1285 | return err; |
1286 | } | 1286 | } |
1287 | 1287 | ||
1288 | static int __devexit bh1770_remove(struct i2c_client *client) | 1288 | static int bh1770_remove(struct i2c_client *client) |
1289 | { | 1289 | { |
1290 | struct bh1770_chip *chip = i2c_get_clientdata(client); | 1290 | struct bh1770_chip *chip = i2c_get_clientdata(client); |
1291 | 1291 | ||
@@ -1395,7 +1395,7 @@ static struct i2c_driver bh1770_driver = { | |||
1395 | .pm = &bh1770_pm_ops, | 1395 | .pm = &bh1770_pm_ops, |
1396 | }, | 1396 | }, |
1397 | .probe = bh1770_probe, | 1397 | .probe = bh1770_probe, |
1398 | .remove = __devexit_p(bh1770_remove), | 1398 | .remove = bh1770_remove, |
1399 | .id_table = bh1770_id, | 1399 | .id_table = bh1770_id, |
1400 | }; | 1400 | }; |
1401 | 1401 | ||
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index f1f9877f3fd..cf03d0abf33 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c | |||
@@ -144,7 +144,7 @@ static const struct attribute_group bh1780_attr_group = { | |||
144 | .attrs = bh1780_attributes, | 144 | .attrs = bh1780_attributes, |
145 | }; | 145 | }; |
146 | 146 | ||
147 | static int __devinit bh1780_probe(struct i2c_client *client, | 147 | static int bh1780_probe(struct i2c_client *client, |
148 | const struct i2c_device_id *id) | 148 | const struct i2c_device_id *id) |
149 | { | 149 | { |
150 | int ret; | 150 | int ret; |
@@ -185,7 +185,7 @@ err_op_failed: | |||
185 | return ret; | 185 | return ret; |
186 | } | 186 | } |
187 | 187 | ||
188 | static int __devexit bh1780_remove(struct i2c_client *client) | 188 | static int bh1780_remove(struct i2c_client *client) |
189 | { | 189 | { |
190 | struct bh1780_data *ddata; | 190 | struct bh1780_data *ddata; |
191 | 191 | ||
@@ -248,7 +248,7 @@ static const struct i2c_device_id bh1780_id[] = { | |||
248 | 248 | ||
249 | static struct i2c_driver bh1780_driver = { | 249 | static struct i2c_driver bh1780_driver = { |
250 | .probe = bh1780_probe, | 250 | .probe = bh1780_probe, |
251 | .remove = __devexit_p(bh1780_remove), | 251 | .remove = bh1780_remove, |
252 | .id_table = bh1780_id, | 252 | .id_table = bh1780_id, |
253 | .driver = { | 253 | .driver = { |
254 | .name = "bh1780", | 254 | .name = "bh1780", |
diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c index a4f33c995ea..3abfcecf842 100644 --- a/drivers/misc/bmp085-i2c.c +++ b/drivers/misc/bmp085-i2c.c | |||
@@ -36,7 +36,7 @@ static int bmp085_i2c_detect(struct i2c_client *client, | |||
36 | return bmp085_detect(&client->dev); | 36 | return bmp085_detect(&client->dev); |
37 | } | 37 | } |
38 | 38 | ||
39 | static int __devinit bmp085_i2c_probe(struct i2c_client *client, | 39 | static int bmp085_i2c_probe(struct i2c_client *client, |
40 | const struct i2c_device_id *id) | 40 | const struct i2c_device_id *id) |
41 | { | 41 | { |
42 | int err; | 42 | int err; |
@@ -71,7 +71,7 @@ static struct i2c_driver bmp085_i2c_driver = { | |||
71 | }, | 71 | }, |
72 | .id_table = bmp085_id, | 72 | .id_table = bmp085_id, |
73 | .probe = bmp085_i2c_probe, | 73 | .probe = bmp085_i2c_probe, |
74 | .remove = __devexit_p(bmp085_i2c_remove), | 74 | .remove = bmp085_i2c_remove, |
75 | 75 | ||
76 | .detect = bmp085_i2c_detect, | 76 | .detect = bmp085_i2c_detect, |
77 | .address_list = normal_i2c | 77 | .address_list = normal_i2c |
diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c index 5e982af9973..d6a52659cf2 100644 --- a/drivers/misc/bmp085-spi.c +++ b/drivers/misc/bmp085-spi.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/err.h> | 22 | #include <linux/err.h> |
23 | #include "bmp085.h" | 23 | #include "bmp085.h" |
24 | 24 | ||
25 | static int __devinit bmp085_spi_probe(struct spi_device *client) | 25 | static int bmp085_spi_probe(struct spi_device *client) |
26 | { | 26 | { |
27 | int err; | 27 | int err; |
28 | struct regmap *regmap; | 28 | struct regmap *regmap; |
@@ -70,7 +70,7 @@ static struct spi_driver bmp085_spi_driver = { | |||
70 | }, | 70 | }, |
71 | .id_table = bmp085_id, | 71 | .id_table = bmp085_id, |
72 | .probe = bmp085_spi_probe, | 72 | .probe = bmp085_spi_probe, |
73 | .remove = __devexit_p(bmp085_spi_remove) | 73 | .remove = bmp085_spi_remove |
74 | }; | 74 | }; |
75 | 75 | ||
76 | module_spi_driver(bmp085_spi_driver); | 76 | module_spi_driver(bmp085_spi_driver); |
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c index 62e418293b7..849e2fed4da 100644 --- a/drivers/misc/bmp085.c +++ b/drivers/misc/bmp085.c | |||
@@ -420,7 +420,7 @@ struct regmap_config bmp085_regmap_config = { | |||
420 | }; | 420 | }; |
421 | EXPORT_SYMBOL_GPL(bmp085_regmap_config); | 421 | EXPORT_SYMBOL_GPL(bmp085_regmap_config); |
422 | 422 | ||
423 | __devinit int bmp085_probe(struct device *dev, struct regmap *regmap) | 423 | int bmp085_probe(struct device *dev, struct regmap *regmap) |
424 | { | 424 | { |
425 | struct bmp085_data *data; | 425 | struct bmp085_data *data; |
426 | int err = 0; | 426 | int err = 0; |
diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index 9d5eed75466..2e50f811ff5 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c | |||
@@ -30,7 +30,7 @@ void cb710_pci_update_config_reg(struct pci_dev *pdev, | |||
30 | EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg); | 30 | EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg); |
31 | 31 | ||
32 | /* Some magic writes based on Windows driver init code */ | 32 | /* Some magic writes based on Windows driver init code */ |
33 | static int __devinit cb710_pci_configure(struct pci_dev *pdev) | 33 | static int cb710_pci_configure(struct pci_dev *pdev) |
34 | { | 34 | { |
35 | unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); | 35 | unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); |
36 | struct pci_dev *pdev0; | 36 | struct pci_dev *pdev0; |
@@ -96,7 +96,7 @@ static void cb710_release_slot(struct device *dev) | |||
96 | #endif | 96 | #endif |
97 | } | 97 | } |
98 | 98 | ||
99 | static int __devinit cb710_register_slot(struct cb710_chip *chip, | 99 | static int cb710_register_slot(struct cb710_chip *chip, |
100 | unsigned slot_mask, unsigned io_offset, const char *name) | 100 | unsigned slot_mask, unsigned io_offset, const char *name) |
101 | { | 101 | { |
102 | int nr = chip->slots; | 102 | int nr = chip->slots; |
@@ -201,7 +201,7 @@ static int cb710_resume(struct pci_dev *pdev) | |||
201 | 201 | ||
202 | #endif /* CONFIG_PM */ | 202 | #endif /* CONFIG_PM */ |
203 | 203 | ||
204 | static int __devinit cb710_probe(struct pci_dev *pdev, | 204 | static int cb710_probe(struct pci_dev *pdev, |
205 | const struct pci_device_id *ent) | 205 | const struct pci_device_id *ent) |
206 | { | 206 | { |
207 | struct cb710_chip *chip; | 207 | struct cb710_chip *chip; |
@@ -305,7 +305,7 @@ unreg_mmc: | |||
305 | return err; | 305 | return err; |
306 | } | 306 | } |
307 | 307 | ||
308 | static void __devexit cb710_remove_one(struct pci_dev *pdev) | 308 | static void cb710_remove_one(struct pci_dev *pdev) |
309 | { | 309 | { |
310 | struct cb710_chip *chip = pci_get_drvdata(pdev); | 310 | struct cb710_chip *chip = pci_get_drvdata(pdev); |
311 | unsigned long flags; | 311 | unsigned long flags; |
@@ -332,7 +332,7 @@ static struct pci_driver cb710_driver = { | |||
332 | .name = KBUILD_MODNAME, | 332 | .name = KBUILD_MODNAME, |
333 | .id_table = cb710_pci_tbl, | 333 | .id_table = cb710_pci_tbl, |
334 | .probe = cb710_probe, | 334 | .probe = cb710_probe, |
335 | .remove = __devexit_p(cb710_remove_one), | 335 | .remove = cb710_remove_one, |
336 | #ifdef CONFIG_PM | 336 | #ifdef CONFIG_PM |
337 | .suspend = cb710_suspend, | 337 | .suspend = cb710_suspend, |
338 | .resume = cb710_resume, | 338 | .resume = cb710_resume, |
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index f505a40a8f4..9858f36dad8 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c | |||
@@ -246,7 +246,7 @@ EXPORT_SYMBOL_GPL(cs5535_mfgpt_write); | |||
246 | * Jordan tells me that he and Mitch once played w/ it, but it's unclear | 246 | * Jordan tells me that he and Mitch once played w/ it, but it's unclear |
247 | * what the results of that were (and they experienced some instability). | 247 | * what the results of that were (and they experienced some instability). |
248 | */ | 248 | */ |
249 | static void __devinit reset_all_timers(void) | 249 | static void reset_all_timers(void) |
250 | { | 250 | { |
251 | uint32_t val, dummy; | 251 | uint32_t val, dummy; |
252 | 252 | ||
@@ -262,7 +262,7 @@ static void __devinit reset_all_timers(void) | |||
262 | * In other cases (such as with VSAless OpenFirmware), the system firmware | 262 | * In other cases (such as with VSAless OpenFirmware), the system firmware |
263 | * leaves timers available for us to use. | 263 | * leaves timers available for us to use. |
264 | */ | 264 | */ |
265 | static int __devinit scan_timers(struct cs5535_mfgpt_chip *mfgpt) | 265 | static int scan_timers(struct cs5535_mfgpt_chip *mfgpt) |
266 | { | 266 | { |
267 | struct cs5535_mfgpt_timer timer = { .chip = mfgpt }; | 267 | struct cs5535_mfgpt_timer timer = { .chip = mfgpt }; |
268 | unsigned long flags; | 268 | unsigned long flags; |
@@ -289,7 +289,7 @@ static int __devinit scan_timers(struct cs5535_mfgpt_chip *mfgpt) | |||
289 | return timers; | 289 | return timers; |
290 | } | 290 | } |
291 | 291 | ||
292 | static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev) | 292 | static int cs5535_mfgpt_probe(struct platform_device *pdev) |
293 | { | 293 | { |
294 | struct resource *res; | 294 | struct resource *res; |
295 | int err = -EIO, t; | 295 | int err = -EIO, t; |
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index ab1ad41786d..2baeec56edf 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c | |||
@@ -656,7 +656,7 @@ err_out: | |||
656 | return err; | 656 | return err; |
657 | } | 657 | } |
658 | 658 | ||
659 | static int __devexit at24_remove(struct i2c_client *client) | 659 | static int at24_remove(struct i2c_client *client) |
660 | { | 660 | { |
661 | struct at24_data *at24; | 661 | struct at24_data *at24; |
662 | int i; | 662 | int i; |
@@ -680,7 +680,7 @@ static struct i2c_driver at24_driver = { | |||
680 | .owner = THIS_MODULE, | 680 | .owner = THIS_MODULE, |
681 | }, | 681 | }, |
682 | .probe = at24_probe, | 682 | .probe = at24_probe, |
683 | .remove = __devexit_p(at24_remove), | 683 | .remove = at24_remove, |
684 | .id_table = at24_ids, | 684 | .id_table = at24_ids, |
685 | }; | 685 | }; |
686 | 686 | ||
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 4ed93dd5411..b08cf8a0878 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c | |||
@@ -459,7 +459,7 @@ fail: | |||
459 | return err; | 459 | return err; |
460 | } | 460 | } |
461 | 461 | ||
462 | static int __devexit at25_remove(struct spi_device *spi) | 462 | static int at25_remove(struct spi_device *spi) |
463 | { | 463 | { |
464 | struct at25_data *at25; | 464 | struct at25_data *at25; |
465 | 465 | ||
@@ -477,7 +477,7 @@ static struct spi_driver at25_driver = { | |||
477 | .owner = THIS_MODULE, | 477 | .owner = THIS_MODULE, |
478 | }, | 478 | }, |
479 | .probe = at25_probe, | 479 | .probe = at25_probe, |
480 | .remove = __devexit_p(at25_remove), | 480 | .remove = at25_remove, |
481 | }; | 481 | }; |
482 | 482 | ||
483 | module_spi_driver(at25_driver); | 483 | module_spi_driver(at25_driver); |
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index ce3fe3633dd..a6b5d5e7348 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c | |||
@@ -309,7 +309,7 @@ static ssize_t eeprom_93xx46_store_erase(struct device *dev, | |||
309 | } | 309 | } |
310 | static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); | 310 | static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); |
311 | 311 | ||
312 | static int __devinit eeprom_93xx46_probe(struct spi_device *spi) | 312 | static int eeprom_93xx46_probe(struct spi_device *spi) |
313 | { | 313 | { |
314 | struct eeprom_93xx46_platform_data *pd; | 314 | struct eeprom_93xx46_platform_data *pd; |
315 | struct eeprom_93xx46_dev *edev; | 315 | struct eeprom_93xx46_dev *edev; |
@@ -370,7 +370,7 @@ fail: | |||
370 | return err; | 370 | return err; |
371 | } | 371 | } |
372 | 372 | ||
373 | static int __devexit eeprom_93xx46_remove(struct spi_device *spi) | 373 | static int eeprom_93xx46_remove(struct spi_device *spi) |
374 | { | 374 | { |
375 | struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev); | 375 | struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev); |
376 | 376 | ||
@@ -389,7 +389,7 @@ static struct spi_driver eeprom_93xx46_driver = { | |||
389 | .owner = THIS_MODULE, | 389 | .owner = THIS_MODULE, |
390 | }, | 390 | }, |
391 | .probe = eeprom_93xx46_probe, | 391 | .probe = eeprom_93xx46_probe, |
392 | .remove = __devexit_p(eeprom_93xx46_remove), | 392 | .remove = eeprom_93xx46_remove, |
393 | }; | 393 | }; |
394 | 394 | ||
395 | module_spi_driver(eeprom_93xx46_driver); | 395 | module_spi_driver(eeprom_93xx46_driver); |
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c index ac96c3a4034..e8cbb1c59f4 100644 --- a/drivers/misc/fsa9480.c +++ b/drivers/misc/fsa9480.c | |||
@@ -407,7 +407,7 @@ static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw) | |||
407 | return 0; | 407 | return 0; |
408 | } | 408 | } |
409 | 409 | ||
410 | static int __devinit fsa9480_probe(struct i2c_client *client, | 410 | static int fsa9480_probe(struct i2c_client *client, |
411 | const struct i2c_device_id *id) | 411 | const struct i2c_device_id *id) |
412 | { | 412 | { |
413 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 413 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
@@ -462,7 +462,7 @@ fail1: | |||
462 | return ret; | 462 | return ret; |
463 | } | 463 | } |
464 | 464 | ||
465 | static int __devexit fsa9480_remove(struct i2c_client *client) | 465 | static int fsa9480_remove(struct i2c_client *client) |
466 | { | 466 | { |
467 | struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); | 467 | struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); |
468 | if (client->irq) | 468 | if (client->irq) |
@@ -533,7 +533,7 @@ static struct i2c_driver fsa9480_i2c_driver = { | |||
533 | .name = "fsa9480", | 533 | .name = "fsa9480", |
534 | }, | 534 | }, |
535 | .probe = fsa9480_probe, | 535 | .probe = fsa9480_probe, |
536 | .remove = __devexit_p(fsa9480_remove), | 536 | .remove = fsa9480_remove, |
537 | .resume = fsa9480_resume, | 537 | .resume = fsa9480_resume, |
538 | .suspend = fsa9480_suspend, | 538 | .suspend = fsa9480_suspend, |
539 | .id_table = fsa9480_id, | 539 | .id_table = fsa9480_id, |
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 12ccdf94e4f..621c7a37339 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c | |||
@@ -30,7 +30,7 @@ | |||
30 | 30 | ||
31 | static struct class *ilo_class; | 31 | static struct class *ilo_class; |
32 | static unsigned int ilo_major; | 32 | static unsigned int ilo_major; |
33 | static unsigned int max_ccb = MIN_CCB; | 33 | static unsigned int max_ccb = 16; |
34 | static char ilo_hwdev[MAX_ILO_DEV]; | 34 | static char ilo_hwdev[MAX_ILO_DEV]; |
35 | 35 | ||
36 | static inline int get_entry_id(int entry) | 36 | static inline int get_entry_id(int entry) |
@@ -686,7 +686,7 @@ static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) | |||
686 | pci_iounmap(pdev, hw->mmio_vaddr); | 686 | pci_iounmap(pdev, hw->mmio_vaddr); |
687 | } | 687 | } |
688 | 688 | ||
689 | static int __devinit ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) | 689 | static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) |
690 | { | 690 | { |
691 | int error = -ENOMEM; | 691 | int error = -ENOMEM; |
692 | 692 | ||
@@ -725,6 +725,9 @@ static void ilo_remove(struct pci_dev *pdev) | |||
725 | int i, minor; | 725 | int i, minor; |
726 | struct ilo_hwinfo *ilo_hw = pci_get_drvdata(pdev); | 726 | struct ilo_hwinfo *ilo_hw = pci_get_drvdata(pdev); |
727 | 727 | ||
728 | if (!ilo_hw) | ||
729 | return; | ||
730 | |||
728 | clear_device(ilo_hw); | 731 | clear_device(ilo_hw); |
729 | 732 | ||
730 | minor = MINOR(ilo_hw->cdev.dev); | 733 | minor = MINOR(ilo_hw->cdev.dev); |
@@ -748,12 +751,16 @@ static void ilo_remove(struct pci_dev *pdev) | |||
748 | ilo_hwdev[(minor / max_ccb)] = 0; | 751 | ilo_hwdev[(minor / max_ccb)] = 0; |
749 | } | 752 | } |
750 | 753 | ||
751 | static int __devinit ilo_probe(struct pci_dev *pdev, | 754 | static int ilo_probe(struct pci_dev *pdev, |
752 | const struct pci_device_id *ent) | 755 | const struct pci_device_id *ent) |
753 | { | 756 | { |
754 | int devnum, minor, start, error; | 757 | int devnum, minor, start, error = 0; |
755 | struct ilo_hwinfo *ilo_hw; | 758 | struct ilo_hwinfo *ilo_hw; |
756 | 759 | ||
760 | /* Ignore subsystem_device = 0x1979 (set by BIOS) */ | ||
761 | if (pdev->subsystem_device == 0x1979) | ||
762 | goto out; | ||
763 | |||
757 | if (max_ccb > MAX_CCB) | 764 | if (max_ccb > MAX_CCB) |
758 | max_ccb = MAX_CCB; | 765 | max_ccb = MAX_CCB; |
759 | else if (max_ccb < MIN_CCB) | 766 | else if (max_ccb < MIN_CCB) |
@@ -852,7 +859,7 @@ static struct pci_driver ilo_driver = { | |||
852 | .name = ILO_NAME, | 859 | .name = ILO_NAME, |
853 | .id_table = ilo_devices, | 860 | .id_table = ilo_devices, |
854 | .probe = ilo_probe, | 861 | .probe = ilo_probe, |
855 | .remove = __devexit_p(ilo_remove), | 862 | .remove = ilo_remove, |
856 | }; | 863 | }; |
857 | 864 | ||
858 | static int __init ilo_init(void) | 865 | static int __init ilo_init(void) |
@@ -892,14 +899,14 @@ static void __exit ilo_exit(void) | |||
892 | class_destroy(ilo_class); | 899 | class_destroy(ilo_class); |
893 | } | 900 | } |
894 | 901 | ||
895 | MODULE_VERSION("1.3"); | 902 | MODULE_VERSION("1.4"); |
896 | MODULE_ALIAS(ILO_NAME); | 903 | MODULE_ALIAS(ILO_NAME); |
897 | MODULE_DESCRIPTION(ILO_NAME); | 904 | MODULE_DESCRIPTION(ILO_NAME); |
898 | MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>"); | 905 | MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>"); |
899 | MODULE_LICENSE("GPL v2"); | 906 | MODULE_LICENSE("GPL v2"); |
900 | 907 | ||
901 | module_param(max_ccb, uint, 0444); | 908 | module_param(max_ccb, uint, 0444); |
902 | MODULE_PARM_DESC(max_ccb, "Maximum number of HP iLO channels to attach (8)"); | 909 | MODULE_PARM_DESC(max_ccb, "Maximum number of HP iLO channels to attach (16)"); |
903 | 910 | ||
904 | module_init(ilo_init); | 911 | module_init(ilo_init); |
905 | module_exit(ilo_exit); | 912 | module_exit(ilo_exit); |
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 168d8008f46..0346d87c5fe 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c | |||
@@ -62,7 +62,7 @@ module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR); | |||
62 | MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off"); | 62 | MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off"); |
63 | 63 | ||
64 | 64 | ||
65 | static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | 65 | static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) |
66 | { | 66 | { |
67 | int result; | 67 | int result; |
68 | struct service_processor *sp; | 68 | struct service_processor *sp; |
@@ -163,7 +163,7 @@ error_resources: | |||
163 | return result; | 163 | return result; |
164 | } | 164 | } |
165 | 165 | ||
166 | static void __devexit ibmasm_remove_one(struct pci_dev *pdev) | 166 | static void ibmasm_remove_one(struct pci_dev *pdev) |
167 | { | 167 | { |
168 | struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev); | 168 | struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev); |
169 | 169 | ||
@@ -198,7 +198,7 @@ static struct pci_driver ibmasm_driver = { | |||
198 | .name = DRIVER_NAME, | 198 | .name = DRIVER_NAME, |
199 | .id_table = ibmasm_pci_table, | 199 | .id_table = ibmasm_pci_table, |
200 | .probe = ibmasm_init_one, | 200 | .probe = ibmasm_init_one, |
201 | .remove = __devexit_p(ibmasm_remove_one), | 201 | .remove = ibmasm_remove_one, |
202 | }; | 202 | }; |
203 | 203 | ||
204 | static void __exit ibmasm_exit (void) | 204 | static void __exit ibmasm_exit (void) |
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 6a7710603a9..06f6ad29cef 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c | |||
@@ -139,7 +139,7 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) | |||
139 | * even though the following code utilizes external interrupt registers | 139 | * even though the following code utilizes external interrupt registers |
140 | * to perform the speed calculation. | 140 | * to perform the speed calculation. |
141 | */ | 141 | */ |
142 | static void __devinit | 142 | static void |
143 | ioc4_clock_calibrate(struct ioc4_driver_data *idd) | 143 | ioc4_clock_calibrate(struct ioc4_driver_data *idd) |
144 | { | 144 | { |
145 | union ioc4_int_out int_out; | 145 | union ioc4_int_out int_out; |
@@ -231,7 +231,7 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) | |||
231 | * on the same PCI bus at slot number 3 to differentiate IO9 from IO10. | 231 | * on the same PCI bus at slot number 3 to differentiate IO9 from IO10. |
232 | * If neither is present, it's a PCI-RT. | 232 | * If neither is present, it's a PCI-RT. |
233 | */ | 233 | */ |
234 | static unsigned int __devinit | 234 | static unsigned int |
235 | ioc4_variant(struct ioc4_driver_data *idd) | 235 | ioc4_variant(struct ioc4_driver_data *idd) |
236 | { | 236 | { |
237 | struct pci_dev *pdev = NULL; | 237 | struct pci_dev *pdev = NULL; |
@@ -279,7 +279,7 @@ ioc4_load_modules(struct work_struct *work) | |||
279 | static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules); | 279 | static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules); |
280 | 280 | ||
281 | /* Adds a new instance of an IOC4 card */ | 281 | /* Adds a new instance of an IOC4 card */ |
282 | static int __devinit | 282 | static int |
283 | ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) | 283 | ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) |
284 | { | 284 | { |
285 | struct ioc4_driver_data *idd; | 285 | struct ioc4_driver_data *idd; |
@@ -415,7 +415,7 @@ out: | |||
415 | } | 415 | } |
416 | 416 | ||
417 | /* Removes a particular instance of an IOC4 card. */ | 417 | /* Removes a particular instance of an IOC4 card. */ |
418 | static void __devexit | 418 | static void |
419 | ioc4_remove(struct pci_dev *pdev) | 419 | ioc4_remove(struct pci_dev *pdev) |
420 | { | 420 | { |
421 | struct ioc4_submodule *is; | 421 | struct ioc4_submodule *is; |
@@ -466,7 +466,7 @@ static struct pci_driver ioc4_driver = { | |||
466 | .name = "IOC4", | 466 | .name = "IOC4", |
467 | .id_table = ioc4_id_table, | 467 | .id_table = ioc4_id_table, |
468 | .probe = ioc4_probe, | 468 | .probe = ioc4_probe, |
469 | .remove = __devexit_p(ioc4_remove), | 469 | .remove = ioc4_remove, |
470 | }; | 470 | }; |
471 | 471 | ||
472 | MODULE_DEVICE_TABLE(pci, ioc4_id_table); | 472 | MODULE_DEVICE_TABLE(pci, ioc4_id_table); |
diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c index eb5de2e210d..29b306c6bdb 100644 --- a/drivers/misc/isl29003.c +++ b/drivers/misc/isl29003.c | |||
@@ -365,7 +365,7 @@ static int isl29003_init_client(struct i2c_client *client) | |||
365 | * I2C layer | 365 | * I2C layer |
366 | */ | 366 | */ |
367 | 367 | ||
368 | static int __devinit isl29003_probe(struct i2c_client *client, | 368 | static int isl29003_probe(struct i2c_client *client, |
369 | const struct i2c_device_id *id) | 369 | const struct i2c_device_id *id) |
370 | { | 370 | { |
371 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 371 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
@@ -401,7 +401,7 @@ exit_kfree: | |||
401 | return err; | 401 | return err; |
402 | } | 402 | } |
403 | 403 | ||
404 | static int __devexit isl29003_remove(struct i2c_client *client) | 404 | static int isl29003_remove(struct i2c_client *client) |
405 | { | 405 | { |
406 | sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group); | 406 | sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group); |
407 | isl29003_set_power_state(client, 0); | 407 | isl29003_set_power_state(client, 0); |
@@ -451,7 +451,7 @@ static struct i2c_driver isl29003_driver = { | |||
451 | .suspend = isl29003_suspend, | 451 | .suspend = isl29003_suspend, |
452 | .resume = isl29003_resume, | 452 | .resume = isl29003_resume, |
453 | .probe = isl29003_probe, | 453 | .probe = isl29003_probe, |
454 | .remove = __devexit_p(isl29003_remove), | 454 | .remove = isl29003_remove, |
455 | .id_table = isl29003_id, | 455 | .id_table = isl29003_id, |
456 | }; | 456 | }; |
457 | 457 | ||
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index 60ec8689d6e..7c97550240f 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c | |||
@@ -114,7 +114,7 @@ static struct of_device_id lis3lv02d_i2c_dt_ids[] = { | |||
114 | MODULE_DEVICE_TABLE(of, lis3lv02d_i2c_dt_ids); | 114 | MODULE_DEVICE_TABLE(of, lis3lv02d_i2c_dt_ids); |
115 | #endif | 115 | #endif |
116 | 116 | ||
117 | static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, | 117 | static int lis3lv02d_i2c_probe(struct i2c_client *client, |
118 | const struct i2c_device_id *id) | 118 | const struct i2c_device_id *id) |
119 | { | 119 | { |
120 | int ret = 0; | 120 | int ret = 0; |
@@ -191,7 +191,7 @@ fail: | |||
191 | return ret; | 191 | return ret; |
192 | } | 192 | } |
193 | 193 | ||
194 | static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) | 194 | static int lis3lv02d_i2c_remove(struct i2c_client *client) |
195 | { | 195 | { |
196 | struct lis3lv02d *lis3 = i2c_get_clientdata(client); | 196 | struct lis3lv02d *lis3 = i2c_get_clientdata(client); |
197 | struct lis3lv02d_platform_data *pdata = client->dev.platform_data; | 197 | struct lis3lv02d_platform_data *pdata = client->dev.platform_data; |
@@ -280,7 +280,7 @@ static struct i2c_driver lis3lv02d_i2c_driver = { | |||
280 | .of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids), | 280 | .of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids), |
281 | }, | 281 | }, |
282 | .probe = lis3lv02d_i2c_probe, | 282 | .probe = lis3lv02d_i2c_probe, |
283 | .remove = __devexit_p(lis3lv02d_i2c_remove), | 283 | .remove = lis3lv02d_i2c_remove, |
284 | .id_table = lis3lv02d_id, | 284 | .id_table = lis3lv02d_id, |
285 | }; | 285 | }; |
286 | 286 | ||
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c index ccb6475fa05..9aa2bd2a71a 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c | |||
@@ -69,7 +69,7 @@ static struct of_device_id lis302dl_spi_dt_ids[] = { | |||
69 | MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids); | 69 | MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids); |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | static int __devinit lis302dl_spi_probe(struct spi_device *spi) | 72 | static int lis302dl_spi_probe(struct spi_device *spi) |
73 | { | 73 | { |
74 | int ret; | 74 | int ret; |
75 | 75 | ||
@@ -100,7 +100,7 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi) | |||
100 | return lis3lv02d_init_device(&lis3_dev); | 100 | return lis3lv02d_init_device(&lis3_dev); |
101 | } | 101 | } |
102 | 102 | ||
103 | static int __devexit lis302dl_spi_remove(struct spi_device *spi) | 103 | static int lis302dl_spi_remove(struct spi_device *spi) |
104 | { | 104 | { |
105 | struct lis3lv02d *lis3 = spi_get_drvdata(spi); | 105 | struct lis3lv02d *lis3 = spi_get_drvdata(spi); |
106 | lis3lv02d_joystick_disable(lis3); | 106 | lis3lv02d_joystick_disable(lis3); |
@@ -144,7 +144,7 @@ static struct spi_driver lis302dl_spi_driver = { | |||
144 | .of_match_table = of_match_ptr(lis302dl_spi_dt_ids), | 144 | .of_match_table = of_match_ptr(lis302dl_spi_dt_ids), |
145 | }, | 145 | }, |
146 | .probe = lis302dl_spi_probe, | 146 | .probe = lis302dl_spi_probe, |
147 | .remove = __devexit_p(lis302dl_spi_remove), | 147 | .remove = lis302dl_spi_remove, |
148 | }; | 148 | }; |
149 | 149 | ||
150 | module_spi_driver(lis302dl_spi_driver); | 150 | module_spi_driver(lis302dl_spi_driver); |
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index 57168db6c7e..0017842e166 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile | |||
@@ -8,4 +8,5 @@ mei-objs += interrupt.o | |||
8 | mei-objs += interface.o | 8 | mei-objs += interface.o |
9 | mei-objs += iorw.o | 9 | mei-objs += iorw.o |
10 | mei-objs += main.o | 10 | mei-objs += main.o |
11 | mei-objs += amthif.o | ||
11 | mei-objs += wd.o | 12 | mei-objs += wd.o |
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c new file mode 100644 index 00000000000..18794aea606 --- /dev/null +++ b/drivers/misc/mei/amthif.c | |||
@@ -0,0 +1,722 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Intel Management Engine Interface (Intel MEI) Linux driver | ||
4 | * Copyright (c) 2003-2012, Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/fcntl.h> | ||
22 | #include <linux/aio.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/ioctl.h> | ||
26 | #include <linux/cdev.h> | ||
27 | #include <linux/list.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/uuid.h> | ||
31 | #include <linux/jiffies.h> | ||
32 | #include <linux/uaccess.h> | ||
33 | |||
34 | |||
35 | #include "mei_dev.h" | ||
36 | #include "hw.h" | ||
37 | #include <linux/mei.h> | ||
38 | #include "interface.h" | ||
39 | |||
40 | const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, | ||
41 | 0xa8, 0x46, 0xe0, 0xff, 0x65, | ||
42 | 0x81, 0x4c); | ||
43 | |||
44 | /** | ||
45 | * mei_amthif_reset_params - initializes mei device iamthif | ||
46 | * | ||
47 | * @dev: the device structure | ||
48 | */ | ||
49 | void mei_amthif_reset_params(struct mei_device *dev) | ||
50 | { | ||
51 | /* reset iamthif parameters. */ | ||
52 | dev->iamthif_current_cb = NULL; | ||
53 | dev->iamthif_msg_buf_size = 0; | ||
54 | dev->iamthif_msg_buf_index = 0; | ||
55 | dev->iamthif_canceled = false; | ||
56 | dev->iamthif_ioctl = false; | ||
57 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
58 | dev->iamthif_timer = 0; | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * mei_amthif_host_init_ - mei initialization amthif client. | ||
63 | * | ||
64 | * @dev: the device structure | ||
65 | * | ||
66 | */ | ||
67 | void mei_amthif_host_init(struct mei_device *dev) | ||
68 | { | ||
69 | int i; | ||
70 | unsigned char *msg_buf; | ||
71 | |||
72 | mei_cl_init(&dev->iamthif_cl, dev); | ||
73 | dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; | ||
74 | |||
75 | /* find ME amthi client */ | ||
76 | i = mei_me_cl_link(dev, &dev->iamthif_cl, | ||
77 | &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); | ||
78 | if (i < 0) { | ||
79 | dev_info(&dev->pdev->dev, "failed to find iamthif client.\n"); | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | /* Assign iamthif_mtu to the value received from ME */ | ||
84 | |||
85 | dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; | ||
86 | dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", | ||
87 | dev->me_clients[i].props.max_msg_length); | ||
88 | |||
89 | kfree(dev->iamthif_msg_buf); | ||
90 | dev->iamthif_msg_buf = NULL; | ||
91 | |||
92 | /* allocate storage for ME message buffer */ | ||
93 | msg_buf = kcalloc(dev->iamthif_mtu, | ||
94 | sizeof(unsigned char), GFP_KERNEL); | ||
95 | if (!msg_buf) { | ||
96 | dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | dev->iamthif_msg_buf = msg_buf; | ||
101 | |||
102 | if (mei_connect(dev, &dev->iamthif_cl)) { | ||
103 | dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); | ||
104 | dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; | ||
105 | dev->iamthif_cl.host_client_id = 0; | ||
106 | } else { | ||
107 | dev->iamthif_cl.timer_count = MEI_CONNECT_TIMEOUT; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * mei_amthif_find_read_list_entry - finds a amthilist entry for current file | ||
113 | * | ||
114 | * @dev: the device structure | ||
115 | * @file: pointer to file object | ||
116 | * | ||
117 | * returns returned a list entry on success, NULL on failure. | ||
118 | */ | ||
119 | struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, | ||
120 | struct file *file) | ||
121 | { | ||
122 | struct mei_cl_cb *pos = NULL; | ||
123 | struct mei_cl_cb *next = NULL; | ||
124 | |||
125 | list_for_each_entry_safe(pos, next, | ||
126 | &dev->amthif_rd_complete_list.list, list) { | ||
127 | if (pos->cl && pos->cl == &dev->iamthif_cl && | ||
128 | pos->file_object == file) | ||
129 | return pos; | ||
130 | } | ||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | |||
135 | /** | ||
136 | * mei_amthif_read - read data from AMTHIF client | ||
137 | * | ||
138 | * @dev: the device structure | ||
139 | * @if_num: minor number | ||
140 | * @file: pointer to file object | ||
141 | * @*ubuf: pointer to user data in user space | ||
142 | * @length: data length to read | ||
143 | * @offset: data read offset | ||
144 | * | ||
145 | * Locking: called under "dev->device_lock" lock | ||
146 | * | ||
147 | * returns | ||
148 | * returned data length on success, | ||
149 | * zero if no data to read, | ||
150 | * negative on failure. | ||
151 | */ | ||
152 | int mei_amthif_read(struct mei_device *dev, struct file *file, | ||
153 | char __user *ubuf, size_t length, loff_t *offset) | ||
154 | { | ||
155 | int rets; | ||
156 | int wait_ret; | ||
157 | struct mei_cl_cb *cb = NULL; | ||
158 | struct mei_cl *cl = file->private_data; | ||
159 | unsigned long timeout; | ||
160 | int i; | ||
161 | |||
162 | /* Only Posible if we are in timeout */ | ||
163 | if (!cl || cl != &dev->iamthif_cl) { | ||
164 | dev_dbg(&dev->pdev->dev, "bad file ext.\n"); | ||
165 | return -ETIMEDOUT; | ||
166 | } | ||
167 | |||
168 | i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); | ||
169 | |||
170 | if (i < 0) { | ||
171 | dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); | ||
172 | return -ENODEV; | ||
173 | } | ||
174 | dev_dbg(&dev->pdev->dev, "checking amthi data\n"); | ||
175 | cb = mei_amthif_find_read_list_entry(dev, file); | ||
176 | |||
177 | /* Check for if we can block or not*/ | ||
178 | if (cb == NULL && file->f_flags & O_NONBLOCK) | ||
179 | return -EAGAIN; | ||
180 | |||
181 | |||
182 | dev_dbg(&dev->pdev->dev, "waiting for amthi data\n"); | ||
183 | while (cb == NULL) { | ||
184 | /* unlock the Mutex */ | ||
185 | mutex_unlock(&dev->device_lock); | ||
186 | |||
187 | wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, | ||
188 | (cb = mei_amthif_find_read_list_entry(dev, file))); | ||
189 | |||
190 | if (wait_ret) | ||
191 | return -ERESTARTSYS; | ||
192 | |||
193 | dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); | ||
194 | |||
195 | /* Locking again the Mutex */ | ||
196 | mutex_lock(&dev->device_lock); | ||
197 | } | ||
198 | |||
199 | |||
200 | dev_dbg(&dev->pdev->dev, "Got amthi data\n"); | ||
201 | dev->iamthif_timer = 0; | ||
202 | |||
203 | if (cb) { | ||
204 | timeout = cb->read_time + | ||
205 | mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); | ||
206 | dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", | ||
207 | timeout); | ||
208 | |||
209 | if (time_after(jiffies, timeout)) { | ||
210 | dev_dbg(&dev->pdev->dev, "amthi Time out\n"); | ||
211 | /* 15 sec for the message has expired */ | ||
212 | list_del(&cb->list); | ||
213 | rets = -ETIMEDOUT; | ||
214 | goto free; | ||
215 | } | ||
216 | } | ||
217 | /* if the whole message will fit remove it from the list */ | ||
218 | if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) | ||
219 | list_del(&cb->list); | ||
220 | else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) { | ||
221 | /* end of the message has been reached */ | ||
222 | list_del(&cb->list); | ||
223 | rets = 0; | ||
224 | goto free; | ||
225 | } | ||
226 | /* else means that not full buffer will be read and do not | ||
227 | * remove message from deletion list | ||
228 | */ | ||
229 | |||
230 | dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", | ||
231 | cb->response_buffer.size); | ||
232 | dev_dbg(&dev->pdev->dev, "amthi cb->buf_idx - %lu\n", cb->buf_idx); | ||
233 | |||
234 | /* length is being turncated to PAGE_SIZE, however, | ||
235 | * the buf_idx may point beyond */ | ||
236 | length = min_t(size_t, length, (cb->buf_idx - *offset)); | ||
237 | |||
238 | if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) | ||
239 | rets = -EFAULT; | ||
240 | else { | ||
241 | rets = length; | ||
242 | if ((*offset + length) < cb->buf_idx) { | ||
243 | *offset += length; | ||
244 | goto out; | ||
245 | } | ||
246 | } | ||
247 | free: | ||
248 | dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); | ||
249 | *offset = 0; | ||
250 | mei_io_cb_free(cb); | ||
251 | out: | ||
252 | return rets; | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * mei_amthif_send_cmd - send amthif command to the ME | ||
257 | * | ||
258 | * @dev: the device structure | ||
259 | * @cb: mei call back struct | ||
260 | * | ||
261 | * returns 0 on success, <0 on failure. | ||
262 | * | ||
263 | */ | ||
264 | static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) | ||
265 | { | ||
266 | struct mei_msg_hdr mei_hdr; | ||
267 | int ret; | ||
268 | |||
269 | if (!dev || !cb) | ||
270 | return -ENODEV; | ||
271 | |||
272 | dev_dbg(&dev->pdev->dev, "write data to amthi client.\n"); | ||
273 | |||
274 | dev->iamthif_state = MEI_IAMTHIF_WRITING; | ||
275 | dev->iamthif_current_cb = cb; | ||
276 | dev->iamthif_file_object = cb->file_object; | ||
277 | dev->iamthif_canceled = false; | ||
278 | dev->iamthif_ioctl = true; | ||
279 | dev->iamthif_msg_buf_size = cb->request_buffer.size; | ||
280 | memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, | ||
281 | cb->request_buffer.size); | ||
282 | |||
283 | ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); | ||
284 | if (ret < 0) | ||
285 | return ret; | ||
286 | |||
287 | if (ret && dev->mei_host_buffer_is_empty) { | ||
288 | ret = 0; | ||
289 | dev->mei_host_buffer_is_empty = false; | ||
290 | if (cb->request_buffer.size > mei_hbuf_max_data(dev)) { | ||
291 | mei_hdr.length = mei_hbuf_max_data(dev); | ||
292 | mei_hdr.msg_complete = 0; | ||
293 | } else { | ||
294 | mei_hdr.length = cb->request_buffer.size; | ||
295 | mei_hdr.msg_complete = 1; | ||
296 | } | ||
297 | |||
298 | mei_hdr.host_addr = dev->iamthif_cl.host_client_id; | ||
299 | mei_hdr.me_addr = dev->iamthif_cl.me_client_id; | ||
300 | mei_hdr.reserved = 0; | ||
301 | dev->iamthif_msg_buf_index += mei_hdr.length; | ||
302 | if (mei_write_message(dev, &mei_hdr, | ||
303 | (unsigned char *)(dev->iamthif_msg_buf), | ||
304 | mei_hdr.length)) | ||
305 | return -ENODEV; | ||
306 | |||
307 | if (mei_hdr.msg_complete) { | ||
308 | if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl)) | ||
309 | return -ENODEV; | ||
310 | dev->iamthif_flow_control_pending = true; | ||
311 | dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; | ||
312 | dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); | ||
313 | dev->iamthif_current_cb = cb; | ||
314 | dev->iamthif_file_object = cb->file_object; | ||
315 | list_add_tail(&cb->list, &dev->write_waiting_list.list); | ||
316 | } else { | ||
317 | dev_dbg(&dev->pdev->dev, "message does not complete, so add amthi cb to write list.\n"); | ||
318 | list_add_tail(&cb->list, &dev->write_list.list); | ||
319 | } | ||
320 | } else { | ||
321 | if (!(dev->mei_host_buffer_is_empty)) | ||
322 | dev_dbg(&dev->pdev->dev, "host buffer is not empty"); | ||
323 | |||
324 | dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n"); | ||
325 | list_add_tail(&cb->list, &dev->write_list.list); | ||
326 | } | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | /** | ||
331 | * mei_amthif_write - write amthif data to amthif client | ||
332 | * | ||
333 | * @dev: the device structure | ||
334 | * @cb: mei call back struct | ||
335 | * | ||
336 | * returns 0 on success, <0 on failure. | ||
337 | * | ||
338 | */ | ||
339 | int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) | ||
340 | { | ||
341 | int ret; | ||
342 | |||
343 | if (!dev || !cb) | ||
344 | return -ENODEV; | ||
345 | |||
346 | ret = mei_io_cb_alloc_resp_buf(cb, dev->iamthif_mtu); | ||
347 | if (ret) | ||
348 | return ret; | ||
349 | |||
350 | cb->fop_type = MEI_FOP_IOCTL; | ||
351 | |||
352 | if (!list_empty(&dev->amthif_cmd_list.list) || | ||
353 | dev->iamthif_state != MEI_IAMTHIF_IDLE) { | ||
354 | dev_dbg(&dev->pdev->dev, | ||
355 | "amthif state = %d\n", dev->iamthif_state); | ||
356 | dev_dbg(&dev->pdev->dev, "AMTHIF: add cb to the wait list\n"); | ||
357 | list_add_tail(&cb->list, &dev->amthif_cmd_list.list); | ||
358 | return 0; | ||
359 | } | ||
360 | return mei_amthif_send_cmd(dev, cb); | ||
361 | } | ||
362 | /** | ||
363 | * mei_amthif_run_next_cmd | ||
364 | * | ||
365 | * @dev: the device structure | ||
366 | * | ||
367 | * returns 0 on success, <0 on failure. | ||
368 | */ | ||
369 | void mei_amthif_run_next_cmd(struct mei_device *dev) | ||
370 | { | ||
371 | struct mei_cl_cb *pos = NULL; | ||
372 | struct mei_cl_cb *next = NULL; | ||
373 | int status; | ||
374 | |||
375 | if (!dev) | ||
376 | return; | ||
377 | |||
378 | dev->iamthif_msg_buf_size = 0; | ||
379 | dev->iamthif_msg_buf_index = 0; | ||
380 | dev->iamthif_canceled = false; | ||
381 | dev->iamthif_ioctl = true; | ||
382 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
383 | dev->iamthif_timer = 0; | ||
384 | dev->iamthif_file_object = NULL; | ||
385 | |||
386 | dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); | ||
387 | |||
388 | list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) { | ||
389 | list_del(&pos->list); | ||
390 | |||
391 | if (pos->cl && pos->cl == &dev->iamthif_cl) { | ||
392 | status = mei_amthif_send_cmd(dev, pos); | ||
393 | if (status) { | ||
394 | dev_dbg(&dev->pdev->dev, | ||
395 | "amthi write failed status = %d\n", | ||
396 | status); | ||
397 | return; | ||
398 | } | ||
399 | break; | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | |||
404 | |||
405 | unsigned int mei_amthif_poll(struct mei_device *dev, | ||
406 | struct file *file, poll_table *wait) | ||
407 | { | ||
408 | unsigned int mask = 0; | ||
409 | mutex_unlock(&dev->device_lock); | ||
410 | poll_wait(file, &dev->iamthif_cl.wait, wait); | ||
411 | mutex_lock(&dev->device_lock); | ||
412 | if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && | ||
413 | dev->iamthif_file_object == file) { | ||
414 | mask |= (POLLIN | POLLRDNORM); | ||
415 | dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); | ||
416 | mei_amthif_run_next_cmd(dev); | ||
417 | } | ||
418 | return mask; | ||
419 | } | ||
420 | |||
421 | |||
422 | |||
423 | /** | ||
424 | * mei_amthif_irq_process_completed - processes completed iamthif operation. | ||
425 | * | ||
426 | * @dev: the device structure. | ||
427 | * @slots: free slots. | ||
428 | * @cb_pos: callback block. | ||
429 | * @cl: private data of the file object. | ||
430 | * @cmpl_list: complete list. | ||
431 | * | ||
432 | * returns 0, OK; otherwise, error. | ||
433 | */ | ||
434 | int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, | ||
435 | struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) | ||
436 | { | ||
437 | struct mei_msg_hdr *mei_hdr; | ||
438 | struct mei_cl *cl = cb->cl; | ||
439 | size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index; | ||
440 | size_t msg_slots = mei_data2slots(len); | ||
441 | |||
442 | mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; | ||
443 | mei_hdr->host_addr = cl->host_client_id; | ||
444 | mei_hdr->me_addr = cl->me_client_id; | ||
445 | mei_hdr->reserved = 0; | ||
446 | |||
447 | if (*slots >= msg_slots) { | ||
448 | mei_hdr->length = len; | ||
449 | mei_hdr->msg_complete = 1; | ||
450 | /* Split the message only if we can write the whole host buffer */ | ||
451 | } else if (*slots == dev->hbuf_depth) { | ||
452 | msg_slots = *slots; | ||
453 | len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); | ||
454 | mei_hdr->length = len; | ||
455 | mei_hdr->msg_complete = 0; | ||
456 | } else { | ||
457 | /* wait for next time the host buffer is empty */ | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n", | ||
462 | mei_hdr->length, mei_hdr->msg_complete); | ||
463 | |||
464 | *slots -= msg_slots; | ||
465 | if (mei_write_message(dev, mei_hdr, | ||
466 | dev->iamthif_msg_buf + dev->iamthif_msg_buf_index, | ||
467 | mei_hdr->length)) { | ||
468 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
469 | cl->status = -ENODEV; | ||
470 | list_del(&cb->list); | ||
471 | return -ENODEV; | ||
472 | } | ||
473 | |||
474 | if (mei_flow_ctrl_reduce(dev, cl)) | ||
475 | return -ENODEV; | ||
476 | |||
477 | dev->iamthif_msg_buf_index += mei_hdr->length; | ||
478 | cl->status = 0; | ||
479 | |||
480 | if (mei_hdr->msg_complete) { | ||
481 | dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; | ||
482 | dev->iamthif_flow_control_pending = true; | ||
483 | |||
484 | /* save iamthif cb sent to amthi client */ | ||
485 | cb->buf_idx = dev->iamthif_msg_buf_index; | ||
486 | dev->iamthif_current_cb = cb; | ||
487 | |||
488 | list_move_tail(&cb->list, &dev->write_waiting_list.list); | ||
489 | } | ||
490 | |||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * mei_amthif_irq_read_message - read routine after ISR to | ||
497 | * handle the read amthi message | ||
498 | * | ||
499 | * @complete_list: An instance of our list structure | ||
500 | * @dev: the device structure | ||
501 | * @mei_hdr: header of amthi message | ||
502 | * | ||
503 | * returns 0 on success, <0 on failure. | ||
504 | */ | ||
505 | int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, | ||
506 | struct mei_device *dev, struct mei_msg_hdr *mei_hdr) | ||
507 | { | ||
508 | struct mei_cl_cb *cb; | ||
509 | unsigned char *buffer; | ||
510 | |||
511 | BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); | ||
512 | BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); | ||
513 | |||
514 | buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; | ||
515 | BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); | ||
516 | |||
517 | mei_read_slots(dev, buffer, mei_hdr->length); | ||
518 | |||
519 | dev->iamthif_msg_buf_index += mei_hdr->length; | ||
520 | |||
521 | if (!mei_hdr->msg_complete) | ||
522 | return 0; | ||
523 | |||
524 | dev_dbg(&dev->pdev->dev, | ||
525 | "amthi_message_buffer_index =%d\n", | ||
526 | mei_hdr->length); | ||
527 | |||
528 | dev_dbg(&dev->pdev->dev, "completed amthi read.\n "); | ||
529 | if (!dev->iamthif_current_cb) | ||
530 | return -ENODEV; | ||
531 | |||
532 | cb = dev->iamthif_current_cb; | ||
533 | dev->iamthif_current_cb = NULL; | ||
534 | |||
535 | if (!cb->cl) | ||
536 | return -ENODEV; | ||
537 | |||
538 | dev->iamthif_stall_timer = 0; | ||
539 | cb->buf_idx = dev->iamthif_msg_buf_index; | ||
540 | cb->read_time = jiffies; | ||
541 | if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) { | ||
542 | /* found the iamthif cb */ | ||
543 | dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); | ||
544 | dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); | ||
545 | list_add_tail(&cb->list, &complete_list->list); | ||
546 | } | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | /** | ||
551 | * mei_amthif_irq_read - prepares to read amthif data. | ||
552 | * | ||
553 | * @dev: the device structure. | ||
554 | * @slots: free slots. | ||
555 | * | ||
556 | * returns 0, OK; otherwise, error. | ||
557 | */ | ||
558 | int mei_amthif_irq_read(struct mei_device *dev, s32 *slots) | ||
559 | { | ||
560 | |||
561 | if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr) | ||
562 | + sizeof(struct hbm_flow_control))) { | ||
563 | return -EMSGSIZE; | ||
564 | } | ||
565 | *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); | ||
566 | if (mei_send_flow_control(dev, &dev->iamthif_cl)) { | ||
567 | dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); | ||
568 | return -EIO; | ||
569 | } | ||
570 | |||
571 | dev_dbg(&dev->pdev->dev, "iamthif flow control success\n"); | ||
572 | dev->iamthif_state = MEI_IAMTHIF_READING; | ||
573 | dev->iamthif_flow_control_pending = false; | ||
574 | dev->iamthif_msg_buf_index = 0; | ||
575 | dev->iamthif_msg_buf_size = 0; | ||
576 | dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; | ||
577 | dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | /** | ||
582 | * mei_amthif_complete - complete amthif callback. | ||
583 | * | ||
584 | * @dev: the device structure. | ||
585 | * @cb_pos: callback block. | ||
586 | */ | ||
587 | void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) | ||
588 | { | ||
589 | if (dev->iamthif_canceled != 1) { | ||
590 | dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; | ||
591 | dev->iamthif_stall_timer = 0; | ||
592 | memcpy(cb->response_buffer.data, | ||
593 | dev->iamthif_msg_buf, | ||
594 | dev->iamthif_msg_buf_index); | ||
595 | list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); | ||
596 | dev_dbg(&dev->pdev->dev, "amthi read completed\n"); | ||
597 | dev->iamthif_timer = jiffies; | ||
598 | dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", | ||
599 | dev->iamthif_timer); | ||
600 | } else { | ||
601 | mei_amthif_run_next_cmd(dev); | ||
602 | } | ||
603 | |||
604 | dev_dbg(&dev->pdev->dev, "completing amthi call back.\n"); | ||
605 | wake_up_interruptible(&dev->iamthif_cl.wait); | ||
606 | } | ||
607 | |||
608 | /** | ||
609 | * mei_clear_list - removes all callbacks associated with file | ||
610 | * from mei_cb_list | ||
611 | * | ||
612 | * @dev: device structure. | ||
613 | * @file: file structure | ||
614 | * @mei_cb_list: callbacks list | ||
615 | * | ||
616 | * mei_clear_list is called to clear resources associated with file | ||
617 | * when application calls close function or Ctrl-C was pressed | ||
618 | * | ||
619 | * returns true if callback removed from the list, false otherwise | ||
620 | */ | ||
621 | static bool mei_clear_list(struct mei_device *dev, | ||
622 | const struct file *file, struct list_head *mei_cb_list) | ||
623 | { | ||
624 | struct mei_cl_cb *cb_pos = NULL; | ||
625 | struct mei_cl_cb *cb_next = NULL; | ||
626 | bool removed = false; | ||
627 | |||
628 | /* list all list member */ | ||
629 | list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) { | ||
630 | /* check if list member associated with a file */ | ||
631 | if (file == cb_pos->file_object) { | ||
632 | /* remove member from the list */ | ||
633 | list_del(&cb_pos->list); | ||
634 | /* check if cb equal to current iamthif cb */ | ||
635 | if (dev->iamthif_current_cb == cb_pos) { | ||
636 | dev->iamthif_current_cb = NULL; | ||
637 | /* send flow control to iamthif client */ | ||
638 | mei_send_flow_control(dev, &dev->iamthif_cl); | ||
639 | } | ||
640 | /* free all allocated buffers */ | ||
641 | mei_io_cb_free(cb_pos); | ||
642 | cb_pos = NULL; | ||
643 | removed = true; | ||
644 | } | ||
645 | } | ||
646 | return removed; | ||
647 | } | ||
648 | |||
649 | /** | ||
650 | * mei_clear_lists - removes all callbacks associated with file | ||
651 | * | ||
652 | * @dev: device structure | ||
653 | * @file: file structure | ||
654 | * | ||
655 | * mei_clear_lists is called to clear resources associated with file | ||
656 | * when application calls close function or Ctrl-C was pressed | ||
657 | * | ||
658 | * returns true if callback removed from the list, false otherwise | ||
659 | */ | ||
660 | static bool mei_clear_lists(struct mei_device *dev, struct file *file) | ||
661 | { | ||
662 | bool removed = false; | ||
663 | |||
664 | /* remove callbacks associated with a file */ | ||
665 | mei_clear_list(dev, file, &dev->amthif_cmd_list.list); | ||
666 | if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list)) | ||
667 | removed = true; | ||
668 | |||
669 | mei_clear_list(dev, file, &dev->ctrl_rd_list.list); | ||
670 | |||
671 | if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list)) | ||
672 | removed = true; | ||
673 | |||
674 | if (mei_clear_list(dev, file, &dev->write_waiting_list.list)) | ||
675 | removed = true; | ||
676 | |||
677 | if (mei_clear_list(dev, file, &dev->write_list.list)) | ||
678 | removed = true; | ||
679 | |||
680 | /* check if iamthif_current_cb not NULL */ | ||
681 | if (dev->iamthif_current_cb && !removed) { | ||
682 | /* check file and iamthif current cb association */ | ||
683 | if (dev->iamthif_current_cb->file_object == file) { | ||
684 | /* remove cb */ | ||
685 | mei_io_cb_free(dev->iamthif_current_cb); | ||
686 | dev->iamthif_current_cb = NULL; | ||
687 | removed = true; | ||
688 | } | ||
689 | } | ||
690 | return removed; | ||
691 | } | ||
692 | |||
693 | /** | ||
694 | * mei_amthif_release - the release function | ||
695 | * | ||
696 | * @inode: pointer to inode structure | ||
697 | * @file: pointer to file structure | ||
698 | * | ||
699 | * returns 0 on success, <0 on error | ||
700 | */ | ||
701 | int mei_amthif_release(struct mei_device *dev, struct file *file) | ||
702 | { | ||
703 | if (dev->open_handle_count > 0) | ||
704 | dev->open_handle_count--; | ||
705 | |||
706 | if (dev->iamthif_file_object == file && | ||
707 | dev->iamthif_state != MEI_IAMTHIF_IDLE) { | ||
708 | |||
709 | dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", | ||
710 | dev->iamthif_state); | ||
711 | dev->iamthif_canceled = true; | ||
712 | if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { | ||
713 | dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); | ||
714 | mei_amthif_run_next_cmd(dev); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | if (mei_clear_lists(dev, file)) | ||
719 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
720 | |||
721 | return 0; | ||
722 | } | ||
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 9700532f02f..be8ca6b333c 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h | |||
@@ -20,16 +20,16 @@ | |||
20 | #include <linux/uuid.h> | 20 | #include <linux/uuid.h> |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * Timeouts | 23 | * Timeouts in Seconds |
24 | */ | 24 | */ |
25 | #define MEI_INTEROP_TIMEOUT (HZ * 7) | 25 | #define MEI_INTEROP_TIMEOUT 7 /* Timeout on ready message */ |
26 | #define MEI_CONNECT_TIMEOUT 3 /* at least 2 seconds */ | 26 | #define MEI_CONNECT_TIMEOUT 3 /* HPS: at least 2 seconds */ |
27 | 27 | ||
28 | #define CONNECT_TIMEOUT 15 /* HPS definition */ | 28 | #define MEI_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */ |
29 | #define INIT_CLIENTS_TIMEOUT 15 /* HPS definition */ | 29 | #define MEI_CLIENTS_INIT_TIMEOUT 15 /* HPS: Clients Enumeration Timeout */ |
30 | 30 | ||
31 | #define IAMTHIF_STALL_TIMER 12 /* seconds */ | 31 | #define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ |
32 | #define IAMTHIF_READ_TIMER 10000 /* ms */ | 32 | #define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * Internal Clients Number | 35 | * Internal Clients Number |
@@ -293,6 +293,14 @@ struct hbm_props_response { | |||
293 | struct mei_client_properties client_properties; | 293 | struct mei_client_properties client_properties; |
294 | } __packed; | 294 | } __packed; |
295 | 295 | ||
296 | /** | ||
297 | * struct hbm_client_connect_request - connect/disconnect request | ||
298 | * | ||
299 | * @hbm_cmd - bus message command header | ||
300 | * @me_addr - address of the client in ME | ||
301 | * @host_addr - address of the client in the driver | ||
302 | * @reserved | ||
303 | */ | ||
296 | struct hbm_client_connect_request { | 304 | struct hbm_client_connect_request { |
297 | u8 hbm_cmd; | 305 | u8 hbm_cmd; |
298 | u8 me_addr; | 306 | u8 me_addr; |
@@ -300,6 +308,14 @@ struct hbm_client_connect_request { | |||
300 | u8 reserved; | 308 | u8 reserved; |
301 | } __packed; | 309 | } __packed; |
302 | 310 | ||
311 | /** | ||
312 | * struct hbm_client_connect_response - connect/disconnect response | ||
313 | * | ||
314 | * @hbm_cmd - bus message command header | ||
315 | * @me_addr - address of the client in ME | ||
316 | * @host_addr - address of the client in the driver | ||
317 | * @status - status of the request | ||
318 | */ | ||
303 | struct hbm_client_connect_response { | 319 | struct hbm_client_connect_response { |
304 | u8 hbm_cmd; | 320 | u8 hbm_cmd; |
305 | u8 me_addr; | 321 | u8 me_addr; |
@@ -307,12 +323,6 @@ struct hbm_client_connect_response { | |||
307 | u8 status; | 323 | u8 status; |
308 | } __packed; | 324 | } __packed; |
309 | 325 | ||
310 | struct hbm_client_disconnect_request { | ||
311 | u8 hbm_cmd; | ||
312 | u8 me_addr; | ||
313 | u8 host_addr; | ||
314 | u8 reserved[1]; | ||
315 | } __packed; | ||
316 | 326 | ||
317 | #define MEI_FC_MESSAGE_RESERVED_LENGTH 5 | 327 | #define MEI_FC_MESSAGE_RESERVED_LENGTH 5 |
318 | 328 | ||
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 98f1430e3e1..a54cd5567ca 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
@@ -43,21 +43,6 @@ const char *mei_dev_state_str(int state) | |||
43 | } | 43 | } |
44 | 44 | ||
45 | 45 | ||
46 | const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, | ||
47 | 0xa8, 0x46, 0xe0, 0xff, 0x65, | ||
48 | 0x81, 0x4c); | ||
49 | |||
50 | /** | ||
51 | * mei_io_list_init - Sets up a queue list. | ||
52 | * | ||
53 | * @list: An instance io list structure | ||
54 | * @dev: the device structure | ||
55 | */ | ||
56 | void mei_io_list_init(struct mei_io_list *list) | ||
57 | { | ||
58 | /* initialize our queue list */ | ||
59 | INIT_LIST_HEAD(&list->mei_cb.cb_list); | ||
60 | } | ||
61 | 46 | ||
62 | /** | 47 | /** |
63 | * mei_io_list_flush - removes list entry belonging to cl. | 48 | * mei_io_list_flush - removes list entry belonging to cl. |
@@ -65,17 +50,15 @@ void mei_io_list_init(struct mei_io_list *list) | |||
65 | * @list: An instance of our list structure | 50 | * @list: An instance of our list structure |
66 | * @cl: private data of the file object | 51 | * @cl: private data of the file object |
67 | */ | 52 | */ |
68 | void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl) | 53 | void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) |
69 | { | 54 | { |
70 | struct mei_cl_cb *pos; | 55 | struct mei_cl_cb *pos; |
71 | struct mei_cl_cb *next; | 56 | struct mei_cl_cb *next; |
72 | 57 | ||
73 | list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { | 58 | list_for_each_entry_safe(pos, next, &list->list, list) { |
74 | if (pos->file_private) { | 59 | if (pos->cl) { |
75 | struct mei_cl *cl_tmp; | 60 | if (mei_cl_cmp_id(cl, pos->cl)) |
76 | cl_tmp = (struct mei_cl *)pos->file_private; | 61 | list_del(&pos->list); |
77 | if (mei_cl_cmp_id(cl, cl_tmp)) | ||
78 | list_del(&pos->cb_list); | ||
79 | } | 62 | } |
80 | } | 63 | } |
81 | } | 64 | } |
@@ -96,31 +79,14 @@ int mei_cl_flush_queues(struct mei_cl *cl) | |||
96 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); | 79 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); |
97 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); | 80 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); |
98 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); | 81 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); |
99 | mei_io_list_flush(&cl->dev->amthi_cmd_list, cl); | 82 | mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); |
100 | mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl); | 83 | mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); |
101 | return 0; | 84 | return 0; |
102 | } | 85 | } |
103 | 86 | ||
104 | 87 | ||
105 | 88 | ||
106 | /** | 89 | /** |
107 | * mei_reset_iamthif_params - initializes mei device iamthif | ||
108 | * | ||
109 | * @dev: the device structure | ||
110 | */ | ||
111 | static void mei_reset_iamthif_params(struct mei_device *dev) | ||
112 | { | ||
113 | /* reset iamthif parameters. */ | ||
114 | dev->iamthif_current_cb = NULL; | ||
115 | dev->iamthif_msg_buf_size = 0; | ||
116 | dev->iamthif_msg_buf_index = 0; | ||
117 | dev->iamthif_canceled = false; | ||
118 | dev->iamthif_ioctl = false; | ||
119 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
120 | dev->iamthif_timer = 0; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * init_mei_device - allocates and initializes the mei device structure | 90 | * init_mei_device - allocates and initializes the mei device structure |
125 | * | 91 | * |
126 | * @pdev: The pci device structure | 92 | * @pdev: The pci device structure |
@@ -144,16 +110,14 @@ struct mei_device *mei_device_init(struct pci_dev *pdev) | |||
144 | init_waitqueue_head(&dev->wait_stop_wd); | 110 | init_waitqueue_head(&dev->wait_stop_wd); |
145 | dev->dev_state = MEI_DEV_INITIALIZING; | 111 | dev->dev_state = MEI_DEV_INITIALIZING; |
146 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 112 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
147 | dev->wd_interface_reg = false; | ||
148 | |||
149 | 113 | ||
150 | mei_io_list_init(&dev->read_list); | 114 | mei_io_list_init(&dev->read_list); |
151 | mei_io_list_init(&dev->write_list); | 115 | mei_io_list_init(&dev->write_list); |
152 | mei_io_list_init(&dev->write_waiting_list); | 116 | mei_io_list_init(&dev->write_waiting_list); |
153 | mei_io_list_init(&dev->ctrl_wr_list); | 117 | mei_io_list_init(&dev->ctrl_wr_list); |
154 | mei_io_list_init(&dev->ctrl_rd_list); | 118 | mei_io_list_init(&dev->ctrl_rd_list); |
155 | mei_io_list_init(&dev->amthi_cmd_list); | 119 | mei_io_list_init(&dev->amthif_cmd_list); |
156 | mei_io_list_init(&dev->amthi_read_complete_list); | 120 | mei_io_list_init(&dev->amthif_rd_complete_list); |
157 | dev->pdev = pdev; | 121 | dev->pdev = pdev; |
158 | return dev; | 122 | return dev; |
159 | } | 123 | } |
@@ -196,7 +160,8 @@ int mei_hw_init(struct mei_device *dev) | |||
196 | if (!dev->recvd_msg) { | 160 | if (!dev->recvd_msg) { |
197 | mutex_unlock(&dev->device_lock); | 161 | mutex_unlock(&dev->device_lock); |
198 | err = wait_event_interruptible_timeout(dev->wait_recvd_msg, | 162 | err = wait_event_interruptible_timeout(dev->wait_recvd_msg, |
199 | dev->recvd_msg, MEI_INTEROP_TIMEOUT); | 163 | dev->recvd_msg, |
164 | mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); | ||
200 | mutex_lock(&dev->device_lock); | 165 | mutex_lock(&dev->device_lock); |
201 | } | 166 | } |
202 | 167 | ||
@@ -317,15 +282,13 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
317 | cl_pos->timer_count = 0; | 282 | cl_pos->timer_count = 0; |
318 | } | 283 | } |
319 | /* remove entry if already in list */ | 284 | /* remove entry if already in list */ |
320 | dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n"); | 285 | dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); |
321 | mei_remove_client_from_file_list(dev, | 286 | mei_me_cl_unlink(dev, &dev->wd_cl); |
322 | dev->wd_cl.host_client_id); | ||
323 | 287 | ||
324 | mei_remove_client_from_file_list(dev, | 288 | mei_me_cl_unlink(dev, &dev->iamthif_cl); |
325 | dev->iamthif_cl.host_client_id); | ||
326 | 289 | ||
327 | mei_reset_iamthif_params(dev); | 290 | mei_amthif_reset_params(dev); |
328 | dev->extra_write_index = 0; | 291 | memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); |
329 | } | 292 | } |
330 | 293 | ||
331 | dev->me_clients_num = 0; | 294 | dev->me_clients_num = 0; |
@@ -351,10 +314,9 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
351 | } | 314 | } |
352 | } | 315 | } |
353 | /* remove all waiting requests */ | 316 | /* remove all waiting requests */ |
354 | list_for_each_entry_safe(cb_pos, cb_next, | 317 | list_for_each_entry_safe(cb_pos, cb_next, &dev->write_list.list, list) { |
355 | &dev->write_list.mei_cb.cb_list, cb_list) { | 318 | list_del(&cb_pos->list); |
356 | list_del(&cb_pos->cb_list); | 319 | mei_io_cb_free(cb_pos); |
357 | mei_free_cb_private(cb_pos); | ||
358 | } | 320 | } |
359 | } | 321 | } |
360 | 322 | ||
@@ -370,31 +332,26 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
370 | void mei_host_start_message(struct mei_device *dev) | 332 | void mei_host_start_message(struct mei_device *dev) |
371 | { | 333 | { |
372 | struct mei_msg_hdr *mei_hdr; | 334 | struct mei_msg_hdr *mei_hdr; |
373 | struct hbm_host_version_request *host_start_req; | 335 | struct hbm_host_version_request *start_req; |
336 | const size_t len = sizeof(struct hbm_host_version_request); | ||
337 | |||
338 | mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); | ||
374 | 339 | ||
375 | /* host start message */ | 340 | /* host start message */ |
376 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | 341 | start_req = (struct hbm_host_version_request *)&dev->wr_msg_buf[1]; |
377 | mei_hdr->host_addr = 0; | 342 | memset(start_req, 0, len); |
378 | mei_hdr->me_addr = 0; | 343 | start_req->hbm_cmd = HOST_START_REQ_CMD; |
379 | mei_hdr->length = sizeof(struct hbm_host_version_request); | 344 | start_req->host_version.major_version = HBM_MAJOR_VERSION; |
380 | mei_hdr->msg_complete = 1; | 345 | start_req->host_version.minor_version = HBM_MINOR_VERSION; |
381 | mei_hdr->reserved = 0; | 346 | |
382 | |||
383 | host_start_req = | ||
384 | (struct hbm_host_version_request *) &dev->wr_msg_buf[1]; | ||
385 | memset(host_start_req, 0, sizeof(struct hbm_host_version_request)); | ||
386 | host_start_req->hbm_cmd = HOST_START_REQ_CMD; | ||
387 | host_start_req->host_version.major_version = HBM_MAJOR_VERSION; | ||
388 | host_start_req->host_version.minor_version = HBM_MINOR_VERSION; | ||
389 | dev->recvd_msg = false; | 347 | dev->recvd_msg = false; |
390 | if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req, | 348 | if (mei_write_message(dev, mei_hdr, (unsigned char *)start_req, len)) { |
391 | mei_hdr->length)) { | ||
392 | dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); | 349 | dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); |
393 | dev->dev_state = MEI_DEV_RESETING; | 350 | dev->dev_state = MEI_DEV_RESETING; |
394 | mei_reset(dev, 1); | 351 | mei_reset(dev, 1); |
395 | } | 352 | } |
396 | dev->init_clients_state = MEI_START_MESSAGE; | 353 | dev->init_clients_state = MEI_START_MESSAGE; |
397 | dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; | 354 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
398 | return ; | 355 | return ; |
399 | } | 356 | } |
400 | 357 | ||
@@ -408,26 +365,22 @@ void mei_host_start_message(struct mei_device *dev) | |||
408 | void mei_host_enum_clients_message(struct mei_device *dev) | 365 | void mei_host_enum_clients_message(struct mei_device *dev) |
409 | { | 366 | { |
410 | struct mei_msg_hdr *mei_hdr; | 367 | struct mei_msg_hdr *mei_hdr; |
411 | struct hbm_host_enum_request *host_enum_req; | 368 | struct hbm_host_enum_request *enum_req; |
412 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | 369 | const size_t len = sizeof(struct hbm_host_enum_request); |
413 | /* enumerate clients */ | 370 | /* enumerate clients */ |
414 | mei_hdr->host_addr = 0; | 371 | mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); |
415 | mei_hdr->me_addr = 0; | 372 | |
416 | mei_hdr->length = sizeof(struct hbm_host_enum_request); | 373 | enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; |
417 | mei_hdr->msg_complete = 1; | 374 | memset(enum_req, 0, sizeof(struct hbm_host_enum_request)); |
418 | mei_hdr->reserved = 0; | 375 | enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; |
419 | 376 | ||
420 | host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; | 377 | if (mei_write_message(dev, mei_hdr, (unsigned char *)enum_req, len)) { |
421 | memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); | ||
422 | host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; | ||
423 | if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req, | ||
424 | mei_hdr->length)) { | ||
425 | dev->dev_state = MEI_DEV_RESETING; | 378 | dev->dev_state = MEI_DEV_RESETING; |
426 | dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); | 379 | dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); |
427 | mei_reset(dev, 1); | 380 | mei_reset(dev, 1); |
428 | } | 381 | } |
429 | dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; | 382 | dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; |
430 | dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; | 383 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
431 | return; | 384 | return; |
432 | } | 385 | } |
433 | 386 | ||
@@ -470,56 +423,87 @@ void mei_allocate_me_clients_storage(struct mei_device *dev) | |||
470 | dev->me_clients = clients; | 423 | dev->me_clients = clients; |
471 | return ; | 424 | return ; |
472 | } | 425 | } |
473 | /** | 426 | |
474 | * host_client_properties - reads properties for client | 427 | void mei_host_client_init(struct work_struct *work) |
475 | * | ||
476 | * @dev: the device structure | ||
477 | * | ||
478 | * returns: | ||
479 | * < 0 - Error. | ||
480 | * = 0 - no more clients. | ||
481 | * = 1 - still have clients to send properties request. | ||
482 | */ | ||
483 | int mei_host_client_properties(struct mei_device *dev) | ||
484 | { | 428 | { |
485 | struct mei_msg_hdr *mei_header; | 429 | struct mei_device *dev = container_of(work, |
486 | struct hbm_props_request *host_cli_req; | 430 | struct mei_device, init_work); |
487 | int b; | 431 | struct mei_client_properties *client_props; |
488 | u8 client_num = dev->me_client_presentation_num; | 432 | int i; |
489 | 433 | ||
490 | b = dev->me_client_index; | 434 | mutex_lock(&dev->device_lock); |
491 | b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b); | 435 | |
492 | if (b < MEI_CLIENTS_MAX) { | 436 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); |
493 | dev->me_clients[client_num].client_id = b; | 437 | dev->open_handle_count = 0; |
494 | dev->me_clients[client_num].mei_flow_ctrl_creds = 0; | 438 | |
495 | mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; | 439 | /* |
496 | mei_header->host_addr = 0; | 440 | * Reserving the first three client IDs |
497 | mei_header->me_addr = 0; | 441 | * 0: Reserved for MEI Bus Message communications |
498 | mei_header->length = sizeof(struct hbm_props_request); | 442 | * 1: Reserved for Watchdog |
499 | mei_header->msg_complete = 1; | 443 | * 2: Reserved for AMTHI |
500 | mei_header->reserved = 0; | 444 | */ |
501 | 445 | bitmap_set(dev->host_clients_map, 0, 3); | |
502 | host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; | 446 | |
503 | 447 | for (i = 0; i < dev->me_clients_num; i++) { | |
504 | memset(host_cli_req, 0, sizeof(struct hbm_props_request)); | 448 | client_props = &dev->me_clients[i].props; |
505 | 449 | ||
506 | host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; | 450 | if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) |
507 | host_cli_req->address = b; | 451 | mei_amthif_host_init(dev); |
508 | 452 | else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) | |
509 | if (mei_write_message(dev, mei_header, | 453 | mei_wd_host_init(dev); |
510 | (unsigned char *)host_cli_req, | 454 | } |
511 | mei_header->length)) { | 455 | |
512 | dev->dev_state = MEI_DEV_RESETING; | 456 | dev->dev_state = MEI_DEV_ENABLED; |
513 | dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); | ||
514 | mei_reset(dev, 1); | ||
515 | return -EIO; | ||
516 | } | ||
517 | 457 | ||
518 | dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; | 458 | mutex_unlock(&dev->device_lock); |
519 | dev->me_client_index = b; | 459 | } |
520 | return 1; | 460 | |
461 | int mei_host_client_enumerate(struct mei_device *dev) | ||
462 | { | ||
463 | |||
464 | struct mei_msg_hdr *mei_hdr; | ||
465 | struct hbm_props_request *prop_req; | ||
466 | const size_t len = sizeof(struct hbm_props_request); | ||
467 | unsigned long next_client_index; | ||
468 | u8 client_num; | ||
469 | |||
470 | |||
471 | client_num = dev->me_client_presentation_num; | ||
472 | |||
473 | next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, | ||
474 | dev->me_client_index); | ||
475 | |||
476 | /* We got all client properties */ | ||
477 | if (next_client_index == MEI_CLIENTS_MAX) { | ||
478 | schedule_work(&dev->init_work); | ||
479 | |||
480 | return 0; | ||
521 | } | 481 | } |
522 | 482 | ||
483 | dev->me_clients[client_num].client_id = next_client_index; | ||
484 | dev->me_clients[client_num].mei_flow_ctrl_creds = 0; | ||
485 | |||
486 | mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); | ||
487 | prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; | ||
488 | |||
489 | memset(prop_req, 0, sizeof(struct hbm_props_request)); | ||
490 | |||
491 | |||
492 | prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; | ||
493 | prop_req->address = next_client_index; | ||
494 | |||
495 | if (mei_write_message(dev, mei_hdr, (unsigned char *) prop_req, | ||
496 | mei_hdr->length)) { | ||
497 | dev->dev_state = MEI_DEV_RESETING; | ||
498 | dev_err(&dev->pdev->dev, "Properties request command failed\n"); | ||
499 | mei_reset(dev, 1); | ||
500 | |||
501 | return -EIO; | ||
502 | } | ||
503 | |||
504 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | ||
505 | dev->me_client_index = next_client_index; | ||
506 | |||
523 | return 0; | 507 | return 0; |
524 | } | 508 | } |
525 | 509 | ||
@@ -557,17 +541,20 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid) | |||
557 | 541 | ||
558 | 542 | ||
559 | /** | 543 | /** |
560 | * mei_me_cl_update_filext - searches for ME client guid | 544 | * mei_me_cl_link - create link between host and me clinet and add |
561 | * sets client_id in mei_file_private if found | 545 | * me_cl to the list |
546 | * | ||
562 | * @dev: the device structure | 547 | * @dev: the device structure |
563 | * @cl: private file structure to set client_id in | 548 | * @cl: link between me and host client assocated with opened file descriptor |
564 | * @cuuid: searched uuid of ME client | 549 | * @cuuid: uuid of ME client |
565 | * @client_id: id of host client to be set in file private structure | 550 | * @client_id: id of the host client |
566 | * | 551 | * |
567 | * returns ME client index | 552 | * returns ME client index if ME client |
553 | * -EINVAL on incorrect values | ||
554 | * -ENONET if client not found | ||
568 | */ | 555 | */ |
569 | int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, | 556 | int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, |
570 | const uuid_le *cuuid, u8 host_cl_id) | 557 | const uuid_le *cuuid, u8 host_cl_id) |
571 | { | 558 | { |
572 | int i; | 559 | int i; |
573 | 560 | ||
@@ -587,54 +574,22 @@ int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, | |||
587 | 574 | ||
588 | return -ENOENT; | 575 | return -ENOENT; |
589 | } | 576 | } |
590 | |||
591 | /** | 577 | /** |
592 | * host_init_iamthif - mei initialization iamthif client. | 578 | * mei_me_cl_unlink - remove me_cl from the list |
593 | * | 579 | * |
594 | * @dev: the device structure | 580 | * @dev: the device structure |
595 | * | 581 | * @host_client_id: host client id to be removed |
596 | */ | 582 | */ |
597 | void mei_host_init_iamthif(struct mei_device *dev) | 583 | void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl) |
598 | { | 584 | { |
599 | int i; | 585 | struct mei_cl *pos, *next; |
600 | unsigned char *msg_buf; | 586 | list_for_each_entry_safe(pos, next, &dev->file_list, link) { |
601 | 587 | if (cl->host_client_id == pos->host_client_id) { | |
602 | mei_cl_init(&dev->iamthif_cl, dev); | 588 | dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", |
603 | dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; | 589 | pos->host_client_id, pos->me_client_id); |
604 | 590 | list_del_init(&pos->link); | |
605 | /* find ME amthi client */ | 591 | break; |
606 | i = mei_me_cl_update_filext(dev, &dev->iamthif_cl, | 592 | } |
607 | &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); | ||
608 | if (i < 0) { | ||
609 | dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); | ||
610 | return; | ||
611 | } | ||
612 | |||
613 | /* Assign iamthif_mtu to the value received from ME */ | ||
614 | |||
615 | dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; | ||
616 | dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", | ||
617 | dev->me_clients[i].props.max_msg_length); | ||
618 | |||
619 | kfree(dev->iamthif_msg_buf); | ||
620 | dev->iamthif_msg_buf = NULL; | ||
621 | |||
622 | /* allocate storage for ME message buffer */ | ||
623 | msg_buf = kcalloc(dev->iamthif_mtu, | ||
624 | sizeof(unsigned char), GFP_KERNEL); | ||
625 | if (!msg_buf) { | ||
626 | dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); | ||
627 | return; | ||
628 | } | ||
629 | |||
630 | dev->iamthif_msg_buf = msg_buf; | ||
631 | |||
632 | if (mei_connect(dev, &dev->iamthif_cl)) { | ||
633 | dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); | ||
634 | dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; | ||
635 | dev->iamthif_cl.host_client_id = 0; | ||
636 | } else { | ||
637 | dev->iamthif_cl.timer_count = CONNECT_TIMEOUT; | ||
638 | } | 593 | } |
639 | } | 594 | } |
640 | 595 | ||
@@ -671,9 +626,8 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev) | |||
671 | */ | 626 | */ |
672 | int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | 627 | int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) |
673 | { | 628 | { |
674 | int rets, err; | ||
675 | long timeout = 15; /* 15 seconds */ | ||
676 | struct mei_cl_cb *cb; | 629 | struct mei_cl_cb *cb; |
630 | int rets, err; | ||
677 | 631 | ||
678 | if (!dev || !cl) | 632 | if (!dev || !cl) |
679 | return -ENODEV; | 633 | return -ENODEV; |
@@ -681,13 +635,11 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | |||
681 | if (cl->state != MEI_FILE_DISCONNECTING) | 635 | if (cl->state != MEI_FILE_DISCONNECTING) |
682 | return 0; | 636 | return 0; |
683 | 637 | ||
684 | cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); | 638 | cb = mei_io_cb_init(cl, NULL); |
685 | if (!cb) | 639 | if (!cb) |
686 | return -ENOMEM; | 640 | return -ENOMEM; |
687 | 641 | ||
688 | INIT_LIST_HEAD(&cb->cb_list); | 642 | cb->fop_type = MEI_FOP_CLOSE; |
689 | cb->file_private = cl; | ||
690 | cb->major_file_operations = MEI_CLOSE; | ||
691 | if (dev->mei_host_buffer_is_empty) { | 643 | if (dev->mei_host_buffer_is_empty) { |
692 | dev->mei_host_buffer_is_empty = false; | 644 | dev->mei_host_buffer_is_empty = false; |
693 | if (mei_disconnect(dev, cl)) { | 645 | if (mei_disconnect(dev, cl)) { |
@@ -696,17 +648,17 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | |||
696 | goto free; | 648 | goto free; |
697 | } | 649 | } |
698 | mdelay(10); /* Wait for hardware disconnection ready */ | 650 | mdelay(10); /* Wait for hardware disconnection ready */ |
699 | list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list); | 651 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); |
700 | } else { | 652 | } else { |
701 | dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); | 653 | dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); |
702 | list_add_tail(&cb->cb_list, | 654 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
703 | &dev->ctrl_wr_list.mei_cb.cb_list); | 655 | |
704 | } | 656 | } |
705 | mutex_unlock(&dev->device_lock); | 657 | mutex_unlock(&dev->device_lock); |
706 | 658 | ||
707 | err = wait_event_timeout(dev->wait_recvd_msg, | 659 | err = wait_event_timeout(dev->wait_recvd_msg, |
708 | (MEI_FILE_DISCONNECTED == cl->state), | 660 | MEI_FILE_DISCONNECTED == cl->state, |
709 | timeout * HZ); | 661 | mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); |
710 | 662 | ||
711 | mutex_lock(&dev->device_lock); | 663 | mutex_lock(&dev->device_lock); |
712 | if (MEI_FILE_DISCONNECTED == cl->state) { | 664 | if (MEI_FILE_DISCONNECTED == cl->state) { |
@@ -728,29 +680,7 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | |||
728 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 680 | mei_io_list_flush(&dev->ctrl_rd_list, cl); |
729 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | 681 | mei_io_list_flush(&dev->ctrl_wr_list, cl); |
730 | free: | 682 | free: |
731 | mei_free_cb_private(cb); | 683 | mei_io_cb_free(cb); |
732 | return rets; | 684 | return rets; |
733 | } | 685 | } |
734 | 686 | ||
735 | /** | ||
736 | * mei_remove_client_from_file_list - | ||
737 | * removes file private data from device file list | ||
738 | * | ||
739 | * @dev: the device structure | ||
740 | * @host_client_id: host client id to be removed | ||
741 | */ | ||
742 | void mei_remove_client_from_file_list(struct mei_device *dev, | ||
743 | u8 host_client_id) | ||
744 | { | ||
745 | struct mei_cl *cl_pos = NULL; | ||
746 | struct mei_cl *cl_next = NULL; | ||
747 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { | ||
748 | if (host_client_id == cl_pos->host_client_id) { | ||
749 | dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", | ||
750 | cl_pos->host_client_id, | ||
751 | cl_pos->me_client_id); | ||
752 | list_del_init(&cl_pos->link); | ||
753 | break; | ||
754 | } | ||
755 | } | ||
756 | } | ||
diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c index 509c3957ff4..8de85478596 100644 --- a/drivers/misc/mei/interface.c +++ b/drivers/misc/mei/interface.c | |||
@@ -292,28 +292,23 @@ int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl) | |||
292 | int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl) | 292 | int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl) |
293 | { | 293 | { |
294 | struct mei_msg_hdr *mei_hdr; | 294 | struct mei_msg_hdr *mei_hdr; |
295 | struct hbm_flow_control *mei_flow_control; | 295 | struct hbm_flow_control *flow_ctrl; |
296 | 296 | const size_t len = sizeof(struct hbm_flow_control); | |
297 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | 297 | |
298 | mei_hdr->host_addr = 0; | 298 | mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); |
299 | mei_hdr->me_addr = 0; | 299 | |
300 | mei_hdr->length = sizeof(struct hbm_flow_control); | 300 | flow_ctrl = (struct hbm_flow_control *)&dev->wr_msg_buf[1]; |
301 | mei_hdr->msg_complete = 1; | 301 | memset(flow_ctrl, 0, len); |
302 | mei_hdr->reserved = 0; | 302 | flow_ctrl->hbm_cmd = MEI_FLOW_CONTROL_CMD; |
303 | 303 | flow_ctrl->host_addr = cl->host_client_id; | |
304 | mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1]; | 304 | flow_ctrl->me_addr = cl->me_client_id; |
305 | memset(mei_flow_control, 0, sizeof(*mei_flow_control)); | 305 | /* FIXME: reserved !? */ |
306 | mei_flow_control->host_addr = cl->host_client_id; | 306 | memset(flow_ctrl->reserved, 0, sizeof(flow_ctrl->reserved)); |
307 | mei_flow_control->me_addr = cl->me_client_id; | ||
308 | mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD; | ||
309 | memset(mei_flow_control->reserved, 0, | ||
310 | sizeof(mei_flow_control->reserved)); | ||
311 | dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n", | 307 | dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n", |
312 | cl->host_client_id, cl->me_client_id); | 308 | cl->host_client_id, cl->me_client_id); |
313 | 309 | ||
314 | return mei_write_message(dev, mei_hdr, | 310 | return mei_write_message(dev, mei_hdr, |
315 | (unsigned char *) mei_flow_control, | 311 | (unsigned char *) flow_ctrl, len); |
316 | sizeof(struct hbm_flow_control)); | ||
317 | } | 312 | } |
318 | 313 | ||
319 | /** | 314 | /** |
@@ -352,26 +347,19 @@ int mei_other_client_is_connecting(struct mei_device *dev, | |||
352 | int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) | 347 | int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) |
353 | { | 348 | { |
354 | struct mei_msg_hdr *mei_hdr; | 349 | struct mei_msg_hdr *mei_hdr; |
355 | struct hbm_client_disconnect_request *mei_cli_disconnect; | 350 | struct hbm_client_connect_request *req; |
356 | 351 | const size_t len = sizeof(struct hbm_client_connect_request); | |
357 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | ||
358 | mei_hdr->host_addr = 0; | ||
359 | mei_hdr->me_addr = 0; | ||
360 | mei_hdr->length = sizeof(struct hbm_client_disconnect_request); | ||
361 | mei_hdr->msg_complete = 1; | ||
362 | mei_hdr->reserved = 0; | ||
363 | |||
364 | mei_cli_disconnect = | ||
365 | (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1]; | ||
366 | memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect)); | ||
367 | mei_cli_disconnect->host_addr = cl->host_client_id; | ||
368 | mei_cli_disconnect->me_addr = cl->me_client_id; | ||
369 | mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; | ||
370 | mei_cli_disconnect->reserved[0] = 0; | ||
371 | 352 | ||
372 | return mei_write_message(dev, mei_hdr, | 353 | mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); |
373 | (unsigned char *) mei_cli_disconnect, | 354 | |
374 | sizeof(struct hbm_client_disconnect_request)); | 355 | req = (struct hbm_client_connect_request *)&dev->wr_msg_buf[1]; |
356 | memset(req, 0, len); | ||
357 | req->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; | ||
358 | req->host_addr = cl->host_client_id; | ||
359 | req->me_addr = cl->me_client_id; | ||
360 | req->reserved = 0; | ||
361 | |||
362 | return mei_write_message(dev, mei_hdr, (unsigned char *)req, len); | ||
375 | } | 363 | } |
376 | 364 | ||
377 | /** | 365 | /** |
@@ -385,23 +373,16 @@ int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) | |||
385 | int mei_connect(struct mei_device *dev, struct mei_cl *cl) | 373 | int mei_connect(struct mei_device *dev, struct mei_cl *cl) |
386 | { | 374 | { |
387 | struct mei_msg_hdr *mei_hdr; | 375 | struct mei_msg_hdr *mei_hdr; |
388 | struct hbm_client_connect_request *mei_cli_connect; | 376 | struct hbm_client_connect_request *req; |
389 | 377 | const size_t len = sizeof(struct hbm_client_connect_request); | |
390 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | ||
391 | mei_hdr->host_addr = 0; | ||
392 | mei_hdr->me_addr = 0; | ||
393 | mei_hdr->length = sizeof(struct hbm_client_connect_request); | ||
394 | mei_hdr->msg_complete = 1; | ||
395 | mei_hdr->reserved = 0; | ||
396 | |||
397 | mei_cli_connect = | ||
398 | (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; | ||
399 | mei_cli_connect->host_addr = cl->host_client_id; | ||
400 | mei_cli_connect->me_addr = cl->me_client_id; | ||
401 | mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD; | ||
402 | mei_cli_connect->reserved = 0; | ||
403 | 378 | ||
404 | return mei_write_message(dev, mei_hdr, | 379 | mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); |
405 | (unsigned char *) mei_cli_connect, | 380 | |
406 | sizeof(struct hbm_client_connect_request)); | 381 | req = (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; |
382 | req->hbm_cmd = CLIENT_CONNECT_REQ_CMD; | ||
383 | req->host_addr = cl->host_client_id; | ||
384 | req->me_addr = cl->me_client_id; | ||
385 | req->reserved = 0; | ||
386 | |||
387 | return mei_write_message(dev, mei_hdr, (unsigned char *) req, len); | ||
407 | } | 388 | } |
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 3533edde04a..04fa2134615 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -57,14 +57,14 @@ irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id) | |||
57 | */ | 57 | */ |
58 | static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) | 58 | static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) |
59 | { | 59 | { |
60 | if (cb_pos->major_file_operations == MEI_WRITE) { | 60 | if (cb_pos->fop_type == MEI_FOP_WRITE) { |
61 | mei_free_cb_private(cb_pos); | 61 | mei_io_cb_free(cb_pos); |
62 | cb_pos = NULL; | 62 | cb_pos = NULL; |
63 | cl->writing_state = MEI_WRITE_COMPLETE; | 63 | cl->writing_state = MEI_WRITE_COMPLETE; |
64 | if (waitqueue_active(&cl->tx_wait)) | 64 | if (waitqueue_active(&cl->tx_wait)) |
65 | wake_up_interruptible(&cl->tx_wait); | 65 | wake_up_interruptible(&cl->tx_wait); |
66 | 66 | ||
67 | } else if (cb_pos->major_file_operations == MEI_READ && | 67 | } else if (cb_pos->fop_type == MEI_FOP_READ && |
68 | MEI_READING == cl->reading_state) { | 68 | MEI_READING == cl->reading_state) { |
69 | cl->reading_state = MEI_READ_COMPLETE; | 69 | cl->reading_state = MEI_READ_COMPLETE; |
70 | if (waitqueue_active(&cl->rx_wait)) | 70 | if (waitqueue_active(&cl->rx_wait)) |
@@ -74,94 +74,6 @@ static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) | |||
74 | } | 74 | } |
75 | 75 | ||
76 | /** | 76 | /** |
77 | * _mei_cmpl_iamthif - processes completed iamthif operation. | ||
78 | * | ||
79 | * @dev: the device structure. | ||
80 | * @cb_pos: callback block. | ||
81 | */ | ||
82 | static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos) | ||
83 | { | ||
84 | if (dev->iamthif_canceled != 1) { | ||
85 | dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; | ||
86 | dev->iamthif_stall_timer = 0; | ||
87 | memcpy(cb_pos->response_buffer.data, | ||
88 | dev->iamthif_msg_buf, | ||
89 | dev->iamthif_msg_buf_index); | ||
90 | list_add_tail(&cb_pos->cb_list, | ||
91 | &dev->amthi_read_complete_list.mei_cb.cb_list); | ||
92 | dev_dbg(&dev->pdev->dev, "amthi read completed.\n"); | ||
93 | dev->iamthif_timer = jiffies; | ||
94 | dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", | ||
95 | dev->iamthif_timer); | ||
96 | } else { | ||
97 | mei_run_next_iamthif_cmd(dev); | ||
98 | } | ||
99 | |||
100 | dev_dbg(&dev->pdev->dev, "completing amthi call back.\n"); | ||
101 | wake_up_interruptible(&dev->iamthif_cl.wait); | ||
102 | } | ||
103 | |||
104 | |||
105 | /** | ||
106 | * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to | ||
107 | * handle the read amthi message data processing. | ||
108 | * | ||
109 | * @complete_list: An instance of our list structure | ||
110 | * @dev: the device structure | ||
111 | * @mei_hdr: header of amthi message | ||
112 | * | ||
113 | * returns 0 on success, <0 on failure. | ||
114 | */ | ||
115 | static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list, | ||
116 | struct mei_device *dev, | ||
117 | struct mei_msg_hdr *mei_hdr) | ||
118 | { | ||
119 | struct mei_cl *cl; | ||
120 | struct mei_cl_cb *cb; | ||
121 | unsigned char *buffer; | ||
122 | |||
123 | BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); | ||
124 | BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); | ||
125 | |||
126 | buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; | ||
127 | BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); | ||
128 | |||
129 | mei_read_slots(dev, buffer, mei_hdr->length); | ||
130 | |||
131 | dev->iamthif_msg_buf_index += mei_hdr->length; | ||
132 | |||
133 | if (!mei_hdr->msg_complete) | ||
134 | return 0; | ||
135 | |||
136 | dev_dbg(&dev->pdev->dev, | ||
137 | "amthi_message_buffer_index =%d\n", | ||
138 | mei_hdr->length); | ||
139 | |||
140 | dev_dbg(&dev->pdev->dev, "completed amthi read.\n "); | ||
141 | if (!dev->iamthif_current_cb) | ||
142 | return -ENODEV; | ||
143 | |||
144 | cb = dev->iamthif_current_cb; | ||
145 | dev->iamthif_current_cb = NULL; | ||
146 | |||
147 | cl = (struct mei_cl *)cb->file_private; | ||
148 | if (!cl) | ||
149 | return -ENODEV; | ||
150 | |||
151 | dev->iamthif_stall_timer = 0; | ||
152 | cb->information = dev->iamthif_msg_buf_index; | ||
153 | cb->read_time = jiffies; | ||
154 | if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) { | ||
155 | /* found the iamthif cb */ | ||
156 | dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); | ||
157 | dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); | ||
158 | list_add_tail(&cb->cb_list, | ||
159 | &complete_list->mei_cb.cb_list); | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * _mei_irq_thread_state_ok - checks if mei header matches file private data | 77 | * _mei_irq_thread_state_ok - checks if mei header matches file private data |
166 | * | 78 | * |
167 | * @cl: private data of the file object | 79 | * @cl: private data of the file object |
@@ -188,7 +100,7 @@ static int _mei_irq_thread_state_ok(struct mei_cl *cl, | |||
188 | * | 100 | * |
189 | * returns 0 on success, <0 on failure. | 101 | * returns 0 on success, <0 on failure. |
190 | */ | 102 | */ |
191 | static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, | 103 | static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list, |
192 | struct mei_device *dev, | 104 | struct mei_device *dev, |
193 | struct mei_msg_hdr *mei_hdr) | 105 | struct mei_msg_hdr *mei_hdr) |
194 | { | 106 | { |
@@ -197,36 +109,36 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, | |||
197 | unsigned char *buffer = NULL; | 109 | unsigned char *buffer = NULL; |
198 | 110 | ||
199 | dev_dbg(&dev->pdev->dev, "start client msg\n"); | 111 | dev_dbg(&dev->pdev->dev, "start client msg\n"); |
200 | if (list_empty(&dev->read_list.mei_cb.cb_list)) | 112 | if (list_empty(&dev->read_list.list)) |
201 | goto quit; | 113 | goto quit; |
202 | 114 | ||
203 | list_for_each_entry_safe(cb_pos, cb_next, | 115 | list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) { |
204 | &dev->read_list.mei_cb.cb_list, cb_list) { | 116 | cl = cb_pos->cl; |
205 | cl = (struct mei_cl *)cb_pos->file_private; | ||
206 | if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) { | 117 | if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) { |
207 | cl->reading_state = MEI_READING; | 118 | cl->reading_state = MEI_READING; |
208 | buffer = cb_pos->response_buffer.data + cb_pos->information; | 119 | buffer = cb_pos->response_buffer.data + cb_pos->buf_idx; |
209 | 120 | ||
210 | if (cb_pos->response_buffer.size < | 121 | if (cb_pos->response_buffer.size < |
211 | mei_hdr->length + cb_pos->information) { | 122 | mei_hdr->length + cb_pos->buf_idx) { |
212 | dev_dbg(&dev->pdev->dev, "message overflow.\n"); | 123 | dev_dbg(&dev->pdev->dev, "message overflow.\n"); |
213 | list_del(&cb_pos->cb_list); | 124 | list_del(&cb_pos->list); |
214 | return -ENOMEM; | 125 | return -ENOMEM; |
215 | } | 126 | } |
216 | if (buffer) | 127 | if (buffer) |
217 | mei_read_slots(dev, buffer, mei_hdr->length); | 128 | mei_read_slots(dev, buffer, mei_hdr->length); |
218 | 129 | ||
219 | cb_pos->information += mei_hdr->length; | 130 | cb_pos->buf_idx += mei_hdr->length; |
220 | if (mei_hdr->msg_complete) { | 131 | if (mei_hdr->msg_complete) { |
221 | cl->status = 0; | 132 | cl->status = 0; |
222 | list_del(&cb_pos->cb_list); | 133 | list_del(&cb_pos->list); |
223 | dev_dbg(&dev->pdev->dev, | 134 | dev_dbg(&dev->pdev->dev, |
224 | "completed read H cl = %d, ME cl = %d, length = %lu\n", | 135 | "completed read H cl = %d, ME cl = %d, length = %lu\n", |
225 | cl->host_client_id, | 136 | cl->host_client_id, |
226 | cl->me_client_id, | 137 | cl->me_client_id, |
227 | cb_pos->information); | 138 | cb_pos->buf_idx); |
228 | list_add_tail(&cb_pos->cb_list, | 139 | |
229 | &complete_list->mei_cb.cb_list); | 140 | list_add_tail(&cb_pos->list, |
141 | &complete_list->list); | ||
230 | } | 142 | } |
231 | 143 | ||
232 | break; | 144 | break; |
@@ -246,37 +158,6 @@ quit: | |||
246 | } | 158 | } |
247 | 159 | ||
248 | /** | 160 | /** |
249 | * _mei_irq_thread_iamthif_read - prepares to read iamthif data. | ||
250 | * | ||
251 | * @dev: the device structure. | ||
252 | * @slots: free slots. | ||
253 | * | ||
254 | * returns 0, OK; otherwise, error. | ||
255 | */ | ||
256 | static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) | ||
257 | { | ||
258 | |||
259 | if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr) | ||
260 | + sizeof(struct hbm_flow_control))) { | ||
261 | return -EMSGSIZE; | ||
262 | } | ||
263 | *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); | ||
264 | if (mei_send_flow_control(dev, &dev->iamthif_cl)) { | ||
265 | dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); | ||
266 | return -EIO; | ||
267 | } | ||
268 | |||
269 | dev_dbg(&dev->pdev->dev, "iamthif flow control success\n"); | ||
270 | dev->iamthif_state = MEI_IAMTHIF_READING; | ||
271 | dev->iamthif_flow_control_pending = false; | ||
272 | dev->iamthif_msg_buf_index = 0; | ||
273 | dev->iamthif_msg_buf_size = 0; | ||
274 | dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER; | ||
275 | dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * _mei_irq_thread_close - processes close related operation. | 161 | * _mei_irq_thread_close - processes close related operation. |
281 | * | 162 | * |
282 | * @dev: the device structure. | 163 | * @dev: the device structure. |
@@ -290,26 +171,24 @@ static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) | |||
290 | static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, | 171 | static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, |
291 | struct mei_cl_cb *cb_pos, | 172 | struct mei_cl_cb *cb_pos, |
292 | struct mei_cl *cl, | 173 | struct mei_cl *cl, |
293 | struct mei_io_list *cmpl_list) | 174 | struct mei_cl_cb *cmpl_list) |
294 | { | 175 | { |
295 | if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + | 176 | if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + |
296 | sizeof(struct hbm_client_disconnect_request))) | 177 | sizeof(struct hbm_client_connect_request))) |
297 | return -EBADMSG; | 178 | return -EBADMSG; |
298 | 179 | ||
299 | *slots -= mei_data2slots(sizeof(struct hbm_client_disconnect_request)); | 180 | *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); |
300 | 181 | ||
301 | if (mei_disconnect(dev, cl)) { | 182 | if (mei_disconnect(dev, cl)) { |
302 | cl->status = 0; | 183 | cl->status = 0; |
303 | cb_pos->information = 0; | 184 | cb_pos->buf_idx = 0; |
304 | list_move_tail(&cb_pos->cb_list, | 185 | list_move_tail(&cb_pos->list, &cmpl_list->list); |
305 | &cmpl_list->mei_cb.cb_list); | ||
306 | return -EMSGSIZE; | 186 | return -EMSGSIZE; |
307 | } else { | 187 | } else { |
308 | cl->state = MEI_FILE_DISCONNECTING; | 188 | cl->state = MEI_FILE_DISCONNECTING; |
309 | cl->status = 0; | 189 | cl->status = 0; |
310 | cb_pos->information = 0; | 190 | cb_pos->buf_idx = 0; |
311 | list_move_tail(&cb_pos->cb_list, | 191 | list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); |
312 | &dev->ctrl_rd_list.mei_cb.cb_list); | ||
313 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 192 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
314 | } | 193 | } |
315 | 194 | ||
@@ -356,7 +235,7 @@ static void mei_client_connect_response(struct mei_device *dev, | |||
356 | { | 235 | { |
357 | 236 | ||
358 | struct mei_cl *cl; | 237 | struct mei_cl *cl; |
359 | struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; | 238 | struct mei_cl_cb *pos = NULL, *next = NULL; |
360 | 239 | ||
361 | dev_dbg(&dev->pdev->dev, | 240 | dev_dbg(&dev->pdev->dev, |
362 | "connect_response:\n" | 241 | "connect_response:\n" |
@@ -373,8 +252,6 @@ static void mei_client_connect_response(struct mei_device *dev, | |||
373 | dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n"); | 252 | dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n"); |
374 | mei_watchdog_register(dev); | 253 | mei_watchdog_register(dev); |
375 | 254 | ||
376 | /* next step in the state maching */ | ||
377 | mei_host_init_iamthif(dev); | ||
378 | return; | 255 | return; |
379 | } | 256 | } |
380 | 257 | ||
@@ -382,17 +259,16 @@ static void mei_client_connect_response(struct mei_device *dev, | |||
382 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 259 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
383 | return; | 260 | return; |
384 | } | 261 | } |
385 | list_for_each_entry_safe(cb_pos, cb_next, | 262 | list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { |
386 | &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { | ||
387 | 263 | ||
388 | cl = (struct mei_cl *)cb_pos->file_private; | 264 | cl = pos->cl; |
389 | if (!cl) { | 265 | if (!cl) { |
390 | list_del(&cb_pos->cb_list); | 266 | list_del(&pos->list); |
391 | return; | 267 | return; |
392 | } | 268 | } |
393 | if (MEI_IOCTL == cb_pos->major_file_operations) { | 269 | if (pos->fop_type == MEI_FOP_IOCTL) { |
394 | if (is_treat_specially_client(cl, rs)) { | 270 | if (is_treat_specially_client(cl, rs)) { |
395 | list_del(&cb_pos->cb_list); | 271 | list_del(&pos->list); |
396 | cl->status = 0; | 272 | cl->status = 0; |
397 | cl->timer_count = 0; | 273 | cl->timer_count = 0; |
398 | break; | 274 | break; |
@@ -411,7 +287,7 @@ static void mei_client_disconnect_response(struct mei_device *dev, | |||
411 | struct hbm_client_connect_response *rs) | 287 | struct hbm_client_connect_response *rs) |
412 | { | 288 | { |
413 | struct mei_cl *cl; | 289 | struct mei_cl *cl; |
414 | struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; | 290 | struct mei_cl_cb *pos = NULL, *next = NULL; |
415 | 291 | ||
416 | dev_dbg(&dev->pdev->dev, | 292 | dev_dbg(&dev->pdev->dev, |
417 | "disconnect_response:\n" | 293 | "disconnect_response:\n" |
@@ -422,12 +298,11 @@ static void mei_client_disconnect_response(struct mei_device *dev, | |||
422 | rs->host_addr, | 298 | rs->host_addr, |
423 | rs->status); | 299 | rs->status); |
424 | 300 | ||
425 | list_for_each_entry_safe(cb_pos, cb_next, | 301 | list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { |
426 | &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { | 302 | cl = pos->cl; |
427 | cl = (struct mei_cl *)cb_pos->file_private; | ||
428 | 303 | ||
429 | if (!cl) { | 304 | if (!cl) { |
430 | list_del(&cb_pos->cb_list); | 305 | list_del(&pos->list); |
431 | return; | 306 | return; |
432 | } | 307 | } |
433 | 308 | ||
@@ -435,7 +310,7 @@ static void mei_client_disconnect_response(struct mei_device *dev, | |||
435 | if (cl->host_client_id == rs->host_addr && | 310 | if (cl->host_client_id == rs->host_addr && |
436 | cl->me_client_id == rs->me_addr) { | 311 | cl->me_client_id == rs->me_addr) { |
437 | 312 | ||
438 | list_del(&cb_pos->cb_list); | 313 | list_del(&pos->list); |
439 | if (!rs->status) | 314 | if (!rs->status) |
440 | cl->state = MEI_FILE_DISCONNECTED; | 315 | cl->state = MEI_FILE_DISCONNECTED; |
441 | 316 | ||
@@ -537,10 +412,10 @@ static void mei_client_flow_control_response(struct mei_device *dev, | |||
537 | * returns !=0, same; 0,not. | 412 | * returns !=0, same; 0,not. |
538 | */ | 413 | */ |
539 | static int same_disconn_addr(struct mei_cl *cl, | 414 | static int same_disconn_addr(struct mei_cl *cl, |
540 | struct hbm_client_disconnect_request *disconn) | 415 | struct hbm_client_connect_request *req) |
541 | { | 416 | { |
542 | return (cl->host_client_id == disconn->host_addr && | 417 | return (cl->host_client_id == req->host_addr && |
543 | cl->me_client_id == disconn->me_addr); | 418 | cl->me_client_id == req->me_addr); |
544 | } | 419 | } |
545 | 420 | ||
546 | /** | 421 | /** |
@@ -550,49 +425,38 @@ static int same_disconn_addr(struct mei_cl *cl, | |||
550 | * @disconnect_req: disconnect request bus message. | 425 | * @disconnect_req: disconnect request bus message. |
551 | */ | 426 | */ |
552 | static void mei_client_disconnect_request(struct mei_device *dev, | 427 | static void mei_client_disconnect_request(struct mei_device *dev, |
553 | struct hbm_client_disconnect_request *disconnect_req) | 428 | struct hbm_client_connect_request *disconnect_req) |
554 | { | 429 | { |
555 | struct mei_msg_hdr *mei_hdr; | ||
556 | struct hbm_client_connect_response *disconnect_res; | 430 | struct hbm_client_connect_response *disconnect_res; |
557 | struct mei_cl *cl_pos = NULL; | 431 | struct mei_cl *pos, *next; |
558 | struct mei_cl *cl_next = NULL; | 432 | const size_t len = sizeof(struct hbm_client_connect_response); |
559 | 433 | ||
560 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { | 434 | list_for_each_entry_safe(pos, next, &dev->file_list, link) { |
561 | if (same_disconn_addr(cl_pos, disconnect_req)) { | 435 | if (same_disconn_addr(pos, disconnect_req)) { |
562 | dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n", | 436 | dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n", |
563 | disconnect_req->host_addr, | 437 | disconnect_req->host_addr, |
564 | disconnect_req->me_addr); | 438 | disconnect_req->me_addr); |
565 | cl_pos->state = MEI_FILE_DISCONNECTED; | 439 | pos->state = MEI_FILE_DISCONNECTED; |
566 | cl_pos->timer_count = 0; | 440 | pos->timer_count = 0; |
567 | if (cl_pos == &dev->wd_cl) | 441 | if (pos == &dev->wd_cl) |
568 | dev->wd_pending = false; | 442 | dev->wd_pending = false; |
569 | else if (cl_pos == &dev->iamthif_cl) | 443 | else if (pos == &dev->iamthif_cl) |
570 | dev->iamthif_timer = 0; | 444 | dev->iamthif_timer = 0; |
571 | 445 | ||
572 | /* prepare disconnect response */ | 446 | /* prepare disconnect response */ |
573 | mei_hdr = | 447 | (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); |
574 | (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; | ||
575 | mei_hdr->host_addr = 0; | ||
576 | mei_hdr->me_addr = 0; | ||
577 | mei_hdr->length = | ||
578 | sizeof(struct hbm_client_connect_response); | ||
579 | mei_hdr->msg_complete = 1; | ||
580 | mei_hdr->reserved = 0; | ||
581 | |||
582 | disconnect_res = | 448 | disconnect_res = |
583 | (struct hbm_client_connect_response *) | 449 | (struct hbm_client_connect_response *) |
584 | &dev->ext_msg_buf[1]; | 450 | &dev->wr_ext_msg.data; |
585 | disconnect_res->host_addr = cl_pos->host_client_id; | ||
586 | disconnect_res->me_addr = cl_pos->me_client_id; | ||
587 | disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD; | 451 | disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD; |
452 | disconnect_res->host_addr = pos->host_client_id; | ||
453 | disconnect_res->me_addr = pos->me_client_id; | ||
588 | disconnect_res->status = 0; | 454 | disconnect_res->status = 0; |
589 | dev->extra_write_index = 2; | ||
590 | break; | 455 | break; |
591 | } | 456 | } |
592 | } | 457 | } |
593 | } | 458 | } |
594 | 459 | ||
595 | |||
596 | /** | 460 | /** |
597 | * mei_irq_thread_read_bus_message - bottom half read routine after ISR to | 461 | * mei_irq_thread_read_bus_message - bottom half read routine after ISR to |
598 | * handle the read bus message cmd processing. | 462 | * handle the read bus message cmd processing. |
@@ -604,16 +468,15 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, | |||
604 | struct mei_msg_hdr *mei_hdr) | 468 | struct mei_msg_hdr *mei_hdr) |
605 | { | 469 | { |
606 | struct mei_bus_message *mei_msg; | 470 | struct mei_bus_message *mei_msg; |
471 | struct mei_me_client *me_client; | ||
607 | struct hbm_host_version_response *version_res; | 472 | struct hbm_host_version_response *version_res; |
608 | struct hbm_client_connect_response *connect_res; | 473 | struct hbm_client_connect_response *connect_res; |
609 | struct hbm_client_connect_response *disconnect_res; | 474 | struct hbm_client_connect_response *disconnect_res; |
475 | struct hbm_client_connect_request *disconnect_req; | ||
610 | struct hbm_flow_control *flow_control; | 476 | struct hbm_flow_control *flow_control; |
611 | struct hbm_props_response *props_res; | 477 | struct hbm_props_response *props_res; |
612 | struct hbm_host_enum_response *enum_res; | 478 | struct hbm_host_enum_response *enum_res; |
613 | struct hbm_client_disconnect_request *disconnect_req; | 479 | struct hbm_host_stop_request *stop_req; |
614 | struct hbm_host_stop_request *host_stop_req; | ||
615 | int res; | ||
616 | |||
617 | 480 | ||
618 | /* read the message to our buffer */ | 481 | /* read the message to our buffer */ |
619 | BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf)); | 482 | BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf)); |
@@ -637,26 +500,20 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, | |||
637 | return; | 500 | return; |
638 | } | 501 | } |
639 | } else { | 502 | } else { |
503 | u32 *buf = dev->wr_msg_buf; | ||
504 | const size_t len = sizeof(struct hbm_host_stop_request); | ||
505 | |||
640 | dev->version = version_res->me_max_version; | 506 | dev->version = version_res->me_max_version; |
507 | |||
641 | /* send stop message */ | 508 | /* send stop message */ |
642 | mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; | 509 | mei_hdr = mei_hbm_hdr(&buf[0], len); |
643 | mei_hdr->host_addr = 0; | 510 | stop_req = (struct hbm_host_stop_request *)&buf[1]; |
644 | mei_hdr->me_addr = 0; | 511 | memset(stop_req, 0, len); |
645 | mei_hdr->length = sizeof(struct hbm_host_stop_request); | 512 | stop_req->hbm_cmd = HOST_STOP_REQ_CMD; |
646 | mei_hdr->msg_complete = 1; | 513 | stop_req->reason = DRIVER_STOP_REQUEST; |
647 | mei_hdr->reserved = 0; | 514 | |
648 | |||
649 | host_stop_req = (struct hbm_host_stop_request *) | ||
650 | &dev->wr_msg_buf[1]; | ||
651 | |||
652 | memset(host_stop_req, | ||
653 | 0, | ||
654 | sizeof(struct hbm_host_stop_request)); | ||
655 | host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD; | ||
656 | host_stop_req->reason = DRIVER_STOP_REQUEST; | ||
657 | mei_write_message(dev, mei_hdr, | 515 | mei_write_message(dev, mei_hdr, |
658 | (unsigned char *) (host_stop_req), | 516 | (unsigned char *)stop_req, len); |
659 | mei_hdr->length); | ||
660 | dev_dbg(&dev->pdev->dev, "version mismatch.\n"); | 517 | dev_dbg(&dev->pdev->dev, "version mismatch.\n"); |
661 | return; | 518 | return; |
662 | } | 519 | } |
@@ -666,16 +523,14 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, | |||
666 | break; | 523 | break; |
667 | 524 | ||
668 | case CLIENT_CONNECT_RES_CMD: | 525 | case CLIENT_CONNECT_RES_CMD: |
669 | connect_res = | 526 | connect_res = (struct hbm_client_connect_response *) mei_msg; |
670 | (struct hbm_client_connect_response *) mei_msg; | ||
671 | mei_client_connect_response(dev, connect_res); | 527 | mei_client_connect_response(dev, connect_res); |
672 | dev_dbg(&dev->pdev->dev, "client connect response message received.\n"); | 528 | dev_dbg(&dev->pdev->dev, "client connect response message received.\n"); |
673 | wake_up(&dev->wait_recvd_msg); | 529 | wake_up(&dev->wait_recvd_msg); |
674 | break; | 530 | break; |
675 | 531 | ||
676 | case CLIENT_DISCONNECT_RES_CMD: | 532 | case CLIENT_DISCONNECT_RES_CMD: |
677 | disconnect_res = | 533 | disconnect_res = (struct hbm_client_connect_response *) mei_msg; |
678 | (struct hbm_client_connect_response *) mei_msg; | ||
679 | mei_client_disconnect_response(dev, disconnect_res); | 534 | mei_client_disconnect_response(dev, disconnect_res); |
680 | dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); | 535 | dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); |
681 | wake_up(&dev->wait_recvd_msg); | 536 | wake_up(&dev->wait_recvd_msg); |
@@ -689,64 +544,37 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, | |||
689 | 544 | ||
690 | case HOST_CLIENT_PROPERTIES_RES_CMD: | 545 | case HOST_CLIENT_PROPERTIES_RES_CMD: |
691 | props_res = (struct hbm_props_response *)mei_msg; | 546 | props_res = (struct hbm_props_response *)mei_msg; |
547 | me_client = &dev->me_clients[dev->me_client_presentation_num]; | ||
548 | |||
692 | if (props_res->status || !dev->me_clients) { | 549 | if (props_res->status || !dev->me_clients) { |
693 | dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n"); | 550 | dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n"); |
694 | mei_reset(dev, 1); | 551 | mei_reset(dev, 1); |
695 | return; | 552 | return; |
696 | } | 553 | } |
697 | if (dev->me_clients[dev->me_client_presentation_num] | ||
698 | .client_id == props_res->address) { | ||
699 | 554 | ||
700 | dev->me_clients[dev->me_client_presentation_num].props | 555 | if (me_client->client_id != props_res->address) { |
701 | = props_res->client_properties; | 556 | dev_err(&dev->pdev->dev, |
557 | "Host client properties reply mismatch\n"); | ||
558 | mei_reset(dev, 1); | ||
702 | 559 | ||
703 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && | 560 | return; |
704 | dev->init_clients_state == | 561 | } |
705 | MEI_CLIENT_PROPERTIES_MESSAGE) { | ||
706 | dev->me_client_index++; | ||
707 | dev->me_client_presentation_num++; | ||
708 | |||
709 | /** Send Client Properties request **/ | ||
710 | res = mei_host_client_properties(dev); | ||
711 | if (res < 0) { | ||
712 | dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed"); | ||
713 | return; | ||
714 | } else if (!res) { | ||
715 | /* | ||
716 | * No more clients to send to. | ||
717 | * Clear Map for indicating now ME clients | ||
718 | * with associated host client | ||
719 | */ | ||
720 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | ||
721 | dev->open_handle_count = 0; | ||
722 | |||
723 | /* | ||
724 | * Reserving the first three client IDs | ||
725 | * Client Id 0 - Reserved for MEI Bus Message communications | ||
726 | * Client Id 1 - Reserved for Watchdog | ||
727 | * Client ID 2 - Reserved for AMTHI | ||
728 | */ | ||
729 | bitmap_set(dev->host_clients_map, 0, 3); | ||
730 | dev->dev_state = MEI_DEV_ENABLED; | ||
731 | |||
732 | /* if wd initialization fails, initialization the AMTHI client, | ||
733 | * otherwise the AMTHI client will be initialized after the WD client connect response | ||
734 | * will be received | ||
735 | */ | ||
736 | if (mei_wd_host_init(dev)) | ||
737 | mei_host_init_iamthif(dev); | ||
738 | } | ||
739 | 562 | ||
740 | } else { | 563 | if (dev->dev_state != MEI_DEV_INIT_CLIENTS || |
741 | dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message"); | 564 | dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) { |
742 | mei_reset(dev, 1); | 565 | dev_err(&dev->pdev->dev, |
743 | return; | 566 | "Unexpected client properties reply\n"); |
744 | } | ||
745 | } else { | ||
746 | dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n"); | ||
747 | mei_reset(dev, 1); | 567 | mei_reset(dev, 1); |
568 | |||
748 | return; | 569 | return; |
749 | } | 570 | } |
571 | |||
572 | me_client->props = props_res->client_properties; | ||
573 | dev->me_client_index++; | ||
574 | dev->me_client_presentation_num++; | ||
575 | |||
576 | mei_host_client_enumerate(dev); | ||
577 | |||
750 | break; | 578 | break; |
751 | 579 | ||
752 | case HOST_ENUM_RES_CMD: | 580 | case HOST_ENUM_RES_CMD: |
@@ -760,7 +588,8 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, | |||
760 | mei_allocate_me_clients_storage(dev); | 588 | mei_allocate_me_clients_storage(dev); |
761 | dev->init_clients_state = | 589 | dev->init_clients_state = |
762 | MEI_CLIENT_PROPERTIES_MESSAGE; | 590 | MEI_CLIENT_PROPERTIES_MESSAGE; |
763 | mei_host_client_properties(dev); | 591 | |
592 | mei_host_client_enumerate(dev); | ||
764 | } else { | 593 | } else { |
765 | dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n"); | 594 | dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n"); |
766 | mei_reset(dev, 1); | 595 | mei_reset(dev, 1); |
@@ -776,29 +605,23 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, | |||
776 | 605 | ||
777 | case CLIENT_DISCONNECT_REQ_CMD: | 606 | case CLIENT_DISCONNECT_REQ_CMD: |
778 | /* search for client */ | 607 | /* search for client */ |
779 | disconnect_req = | 608 | disconnect_req = (struct hbm_client_connect_request *)mei_msg; |
780 | (struct hbm_client_disconnect_request *) mei_msg; | ||
781 | mei_client_disconnect_request(dev, disconnect_req); | 609 | mei_client_disconnect_request(dev, disconnect_req); |
782 | break; | 610 | break; |
783 | 611 | ||
784 | case ME_STOP_REQ_CMD: | 612 | case ME_STOP_REQ_CMD: |
785 | /* prepare stop request */ | 613 | { |
786 | mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; | 614 | /* prepare stop request: sent in next interrupt event */ |
787 | mei_hdr->host_addr = 0; | 615 | |
788 | mei_hdr->me_addr = 0; | 616 | const size_t len = sizeof(struct hbm_host_stop_request); |
789 | mei_hdr->length = sizeof(struct hbm_host_stop_request); | ||
790 | mei_hdr->msg_complete = 1; | ||
791 | mei_hdr->reserved = 0; | ||
792 | host_stop_req = | ||
793 | (struct hbm_host_stop_request *) &dev->ext_msg_buf[1]; | ||
794 | memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request)); | ||
795 | host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD; | ||
796 | host_stop_req->reason = DRIVER_STOP_REQUEST; | ||
797 | host_stop_req->reserved[0] = 0; | ||
798 | host_stop_req->reserved[1] = 0; | ||
799 | dev->extra_write_index = 2; | ||
800 | break; | ||
801 | 617 | ||
618 | mei_hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); | ||
619 | stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data; | ||
620 | memset(stop_req, 0, len); | ||
621 | stop_req->hbm_cmd = HOST_STOP_REQ_CMD; | ||
622 | stop_req->reason = DRIVER_STOP_REQUEST; | ||
623 | break; | ||
624 | } | ||
802 | default: | 625 | default: |
803 | BUG(); | 626 | BUG(); |
804 | break; | 627 | break; |
@@ -821,12 +644,12 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, | |||
821 | static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, | 644 | static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, |
822 | struct mei_cl_cb *cb_pos, | 645 | struct mei_cl_cb *cb_pos, |
823 | struct mei_cl *cl, | 646 | struct mei_cl *cl, |
824 | struct mei_io_list *cmpl_list) | 647 | struct mei_cl_cb *cmpl_list) |
825 | { | 648 | { |
826 | if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + | 649 | if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + |
827 | sizeof(struct hbm_flow_control))) { | 650 | sizeof(struct hbm_flow_control))) { |
828 | /* return the cancel routine */ | 651 | /* return the cancel routine */ |
829 | list_del(&cb_pos->cb_list); | 652 | list_del(&cb_pos->list); |
830 | return -EBADMSG; | 653 | return -EBADMSG; |
831 | } | 654 | } |
832 | 655 | ||
@@ -834,11 +657,11 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, | |||
834 | 657 | ||
835 | if (mei_send_flow_control(dev, cl)) { | 658 | if (mei_send_flow_control(dev, cl)) { |
836 | cl->status = -ENODEV; | 659 | cl->status = -ENODEV; |
837 | cb_pos->information = 0; | 660 | cb_pos->buf_idx = 0; |
838 | list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list); | 661 | list_move_tail(&cb_pos->list, &cmpl_list->list); |
839 | return -ENODEV; | 662 | return -ENODEV; |
840 | } | 663 | } |
841 | list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list); | 664 | list_move_tail(&cb_pos->list, &dev->read_list.list); |
842 | 665 | ||
843 | return 0; | 666 | return 0; |
844 | } | 667 | } |
@@ -858,12 +681,12 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, | |||
858 | static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, | 681 | static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, |
859 | struct mei_cl_cb *cb_pos, | 682 | struct mei_cl_cb *cb_pos, |
860 | struct mei_cl *cl, | 683 | struct mei_cl *cl, |
861 | struct mei_io_list *cmpl_list) | 684 | struct mei_cl_cb *cmpl_list) |
862 | { | 685 | { |
863 | if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + | 686 | if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + |
864 | sizeof(struct hbm_client_connect_request))) { | 687 | sizeof(struct hbm_client_connect_request))) { |
865 | /* return the cancel routine */ | 688 | /* return the cancel routine */ |
866 | list_del(&cb_pos->cb_list); | 689 | list_del(&cb_pos->list); |
867 | return -EBADMSG; | 690 | return -EBADMSG; |
868 | } | 691 | } |
869 | 692 | ||
@@ -871,188 +694,73 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, | |||
871 | *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); | 694 | *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); |
872 | if (mei_connect(dev, cl)) { | 695 | if (mei_connect(dev, cl)) { |
873 | cl->status = -ENODEV; | 696 | cl->status = -ENODEV; |
874 | cb_pos->information = 0; | 697 | cb_pos->buf_idx = 0; |
875 | list_del(&cb_pos->cb_list); | 698 | list_del(&cb_pos->list); |
876 | return -ENODEV; | 699 | return -ENODEV; |
877 | } else { | 700 | } else { |
878 | list_move_tail(&cb_pos->cb_list, | 701 | list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); |
879 | &dev->ctrl_rd_list.mei_cb.cb_list); | ||
880 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 702 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
881 | } | 703 | } |
882 | return 0; | 704 | return 0; |
883 | } | 705 | } |
884 | 706 | ||
885 | /** | 707 | /** |
886 | * _mei_irq_thread_cmpl - processes completed and no-iamthif operation. | 708 | * mei_irq_thread_write_complete - write messages to device. |
887 | * | 709 | * |
888 | * @dev: the device structure. | 710 | * @dev: the device structure. |
889 | * @slots: free slots. | 711 | * @slots: free slots. |
890 | * @cb_pos: callback block. | 712 | * @cb: callback block. |
891 | * @cl: private data of the file object. | ||
892 | * @cmpl_list: complete list. | 713 | * @cmpl_list: complete list. |
893 | * | 714 | * |
894 | * returns 0, OK; otherwise, error. | 715 | * returns 0, OK; otherwise, error. |
895 | */ | 716 | */ |
896 | static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, | 717 | static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots, |
897 | struct mei_cl_cb *cb_pos, | 718 | struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) |
898 | struct mei_cl *cl, | ||
899 | struct mei_io_list *cmpl_list) | ||
900 | { | 719 | { |
901 | struct mei_msg_hdr *mei_hdr; | 720 | struct mei_msg_hdr *mei_hdr; |
721 | struct mei_cl *cl = cb->cl; | ||
722 | size_t len = cb->request_buffer.size - cb->buf_idx; | ||
723 | size_t msg_slots = mei_data2slots(len); | ||
724 | |||
725 | mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; | ||
726 | mei_hdr->host_addr = cl->host_client_id; | ||
727 | mei_hdr->me_addr = cl->me_client_id; | ||
728 | mei_hdr->reserved = 0; | ||
902 | 729 | ||
903 | if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + | 730 | if (*slots >= msg_slots) { |
904 | (cb_pos->request_buffer.size - | 731 | mei_hdr->length = len; |
905 | cb_pos->information))) { | ||
906 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | ||
907 | mei_hdr->host_addr = cl->host_client_id; | ||
908 | mei_hdr->me_addr = cl->me_client_id; | ||
909 | mei_hdr->length = cb_pos->request_buffer.size - | ||
910 | cb_pos->information; | ||
911 | mei_hdr->msg_complete = 1; | 732 | mei_hdr->msg_complete = 1; |
912 | mei_hdr->reserved = 0; | 733 | /* Split the message only if we can write the whole host buffer */ |
913 | dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d" | ||
914 | "mei_hdr->msg_complete = %d\n", | ||
915 | cb_pos->request_buffer.size, | ||
916 | mei_hdr->msg_complete); | ||
917 | dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", | ||
918 | cb_pos->information); | ||
919 | dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", | ||
920 | mei_hdr->length); | ||
921 | *slots -= mei_data2slots(mei_hdr->length); | ||
922 | if (mei_write_message(dev, mei_hdr, | ||
923 | (unsigned char *) | ||
924 | (cb_pos->request_buffer.data + | ||
925 | cb_pos->information), | ||
926 | mei_hdr->length)) { | ||
927 | cl->status = -ENODEV; | ||
928 | list_move_tail(&cb_pos->cb_list, | ||
929 | &cmpl_list->mei_cb.cb_list); | ||
930 | return -ENODEV; | ||
931 | } else { | ||
932 | if (mei_flow_ctrl_reduce(dev, cl)) | ||
933 | return -ENODEV; | ||
934 | cl->status = 0; | ||
935 | cb_pos->information += mei_hdr->length; | ||
936 | list_move_tail(&cb_pos->cb_list, | ||
937 | &dev->write_waiting_list.mei_cb.cb_list); | ||
938 | } | ||
939 | } else if (*slots == dev->hbuf_depth) { | 734 | } else if (*slots == dev->hbuf_depth) { |
940 | /* buffer is still empty */ | 735 | msg_slots = *slots; |
941 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | 736 | len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); |
942 | mei_hdr->host_addr = cl->host_client_id; | 737 | mei_hdr->length = len; |
943 | mei_hdr->me_addr = cl->me_client_id; | ||
944 | mei_hdr->length = | ||
945 | (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); | ||
946 | mei_hdr->msg_complete = 0; | 738 | mei_hdr->msg_complete = 0; |
947 | mei_hdr->reserved = 0; | ||
948 | *slots -= mei_data2slots(mei_hdr->length); | ||
949 | if (mei_write_message(dev, mei_hdr, | ||
950 | (unsigned char *) | ||
951 | (cb_pos->request_buffer.data + | ||
952 | cb_pos->information), | ||
953 | mei_hdr->length)) { | ||
954 | cl->status = -ENODEV; | ||
955 | list_move_tail(&cb_pos->cb_list, | ||
956 | &cmpl_list->mei_cb.cb_list); | ||
957 | return -ENODEV; | ||
958 | } else { | ||
959 | cb_pos->information += mei_hdr->length; | ||
960 | dev_dbg(&dev->pdev->dev, | ||
961 | "cb_pos->request_buffer.size =%d" | ||
962 | " mei_hdr->msg_complete = %d\n", | ||
963 | cb_pos->request_buffer.size, | ||
964 | mei_hdr->msg_complete); | ||
965 | dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", | ||
966 | cb_pos->information); | ||
967 | dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", | ||
968 | mei_hdr->length); | ||
969 | } | ||
970 | return -EMSGSIZE; | ||
971 | } else { | 739 | } else { |
972 | return -EBADMSG; | 740 | /* wait for next time the host buffer is empty */ |
741 | return 0; | ||
973 | } | 742 | } |
974 | 743 | ||
975 | return 0; | 744 | dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", |
976 | } | 745 | cb->request_buffer.size, cb->buf_idx); |
977 | 746 | dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n", | |
978 | /** | 747 | mei_hdr->length, mei_hdr->msg_complete); |
979 | * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation. | ||
980 | * | ||
981 | * @dev: the device structure. | ||
982 | * @slots: free slots. | ||
983 | * @cb_pos: callback block. | ||
984 | * @cl: private data of the file object. | ||
985 | * @cmpl_list: complete list. | ||
986 | * | ||
987 | * returns 0, OK; otherwise, error. | ||
988 | */ | ||
989 | static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, | ||
990 | struct mei_cl_cb *cb_pos, | ||
991 | struct mei_cl *cl, | ||
992 | struct mei_io_list *cmpl_list) | ||
993 | { | ||
994 | struct mei_msg_hdr *mei_hdr; | ||
995 | |||
996 | if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + | ||
997 | dev->iamthif_msg_buf_size - | ||
998 | dev->iamthif_msg_buf_index)) { | ||
999 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | ||
1000 | mei_hdr->host_addr = cl->host_client_id; | ||
1001 | mei_hdr->me_addr = cl->me_client_id; | ||
1002 | mei_hdr->length = dev->iamthif_msg_buf_size - | ||
1003 | dev->iamthif_msg_buf_index; | ||
1004 | mei_hdr->msg_complete = 1; | ||
1005 | mei_hdr->reserved = 0; | ||
1006 | |||
1007 | *slots -= mei_data2slots(mei_hdr->length); | ||
1008 | |||
1009 | if (mei_write_message(dev, mei_hdr, | ||
1010 | (dev->iamthif_msg_buf + | ||
1011 | dev->iamthif_msg_buf_index), | ||
1012 | mei_hdr->length)) { | ||
1013 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
1014 | cl->status = -ENODEV; | ||
1015 | list_del(&cb_pos->cb_list); | ||
1016 | return -ENODEV; | ||
1017 | } else { | ||
1018 | if (mei_flow_ctrl_reduce(dev, cl)) | ||
1019 | return -ENODEV; | ||
1020 | dev->iamthif_msg_buf_index += mei_hdr->length; | ||
1021 | cb_pos->information = dev->iamthif_msg_buf_index; | ||
1022 | cl->status = 0; | ||
1023 | dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; | ||
1024 | dev->iamthif_flow_control_pending = true; | ||
1025 | /* save iamthif cb sent to amthi client */ | ||
1026 | dev->iamthif_current_cb = cb_pos; | ||
1027 | list_move_tail(&cb_pos->cb_list, | ||
1028 | &dev->write_waiting_list.mei_cb.cb_list); | ||
1029 | 748 | ||
1030 | } | 749 | *slots -= msg_slots; |
1031 | } else if (*slots == dev->hbuf_depth) { | 750 | if (mei_write_message(dev, mei_hdr, |
1032 | /* buffer is still empty */ | 751 | cb->request_buffer.data + cb->buf_idx, len)) { |
1033 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | 752 | cl->status = -ENODEV; |
1034 | mei_hdr->host_addr = cl->host_client_id; | 753 | list_move_tail(&cb->list, &cmpl_list->list); |
1035 | mei_hdr->me_addr = cl->me_client_id; | 754 | return -ENODEV; |
1036 | mei_hdr->length = | 755 | } |
1037 | (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); | ||
1038 | mei_hdr->msg_complete = 0; | ||
1039 | mei_hdr->reserved = 0; | ||
1040 | 756 | ||
1041 | *slots -= mei_data2slots(mei_hdr->length); | 757 | if (mei_flow_ctrl_reduce(dev, cl)) |
758 | return -ENODEV; | ||
1042 | 759 | ||
1043 | if (mei_write_message(dev, mei_hdr, | 760 | cl->status = 0; |
1044 | (dev->iamthif_msg_buf + | 761 | cb->buf_idx += mei_hdr->length; |
1045 | dev->iamthif_msg_buf_index), | 762 | if (mei_hdr->msg_complete) |
1046 | mei_hdr->length)) { | 763 | list_move_tail(&cb->list, &dev->write_waiting_list.list); |
1047 | cl->status = -ENODEV; | ||
1048 | list_del(&cb_pos->cb_list); | ||
1049 | } else { | ||
1050 | dev->iamthif_msg_buf_index += mei_hdr->length; | ||
1051 | } | ||
1052 | return -EMSGSIZE; | ||
1053 | } else { | ||
1054 | return -EBADMSG; | ||
1055 | } | ||
1056 | 764 | ||
1057 | return 0; | 765 | return 0; |
1058 | } | 766 | } |
@@ -1067,7 +775,7 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, | |||
1067 | * | 775 | * |
1068 | * returns 0 on success, <0 on failure. | 776 | * returns 0 on success, <0 on failure. |
1069 | */ | 777 | */ |
1070 | static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list, | 778 | static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list, |
1071 | struct mei_device *dev, | 779 | struct mei_device *dev, |
1072 | s32 *slots) | 780 | s32 *slots) |
1073 | { | 781 | { |
@@ -1130,8 +838,8 @@ static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list, | |||
1130 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n"); | 838 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n"); |
1131 | dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", | 839 | dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", |
1132 | mei_hdr->length); | 840 | mei_hdr->length); |
1133 | ret = mei_irq_thread_read_amthi_message(cmpl_list, | 841 | |
1134 | dev, mei_hdr); | 842 | ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr); |
1135 | if (ret) | 843 | if (ret) |
1136 | goto end; | 844 | goto end; |
1137 | 845 | ||
@@ -1164,53 +872,51 @@ end: | |||
1164 | * mei_irq_thread_write_handler - bottom half write routine after | 872 | * mei_irq_thread_write_handler - bottom half write routine after |
1165 | * ISR to handle the write processing. | 873 | * ISR to handle the write processing. |
1166 | * | 874 | * |
1167 | * @cmpl_list: An instance of our list structure | ||
1168 | * @dev: the device structure | 875 | * @dev: the device structure |
1169 | * @slots: slots to write. | 876 | * @cmpl_list: An instance of our list structure |
1170 | * | 877 | * |
1171 | * returns 0 on success, <0 on failure. | 878 | * returns 0 on success, <0 on failure. |
1172 | */ | 879 | */ |
1173 | static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, | 880 | static int mei_irq_thread_write_handler(struct mei_device *dev, |
1174 | struct mei_device *dev, | 881 | struct mei_cl_cb *cmpl_list) |
1175 | s32 *slots) | ||
1176 | { | 882 | { |
1177 | 883 | ||
1178 | struct mei_cl *cl; | 884 | struct mei_cl *cl; |
1179 | struct mei_cl_cb *pos = NULL, *next = NULL; | 885 | struct mei_cl_cb *pos = NULL, *next = NULL; |
1180 | struct mei_io_list *list; | 886 | struct mei_cl_cb *list; |
887 | s32 slots; | ||
1181 | int ret; | 888 | int ret; |
1182 | 889 | ||
1183 | if (!mei_hbuf_is_empty(dev)) { | 890 | if (!mei_hbuf_is_empty(dev)) { |
1184 | dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n"); | 891 | dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n"); |
1185 | return 0; | 892 | return 0; |
1186 | } | 893 | } |
1187 | *slots = mei_hbuf_empty_slots(dev); | 894 | slots = mei_hbuf_empty_slots(dev); |
1188 | if (*slots <= 0) | 895 | if (slots <= 0) |
1189 | return -EMSGSIZE; | 896 | return -EMSGSIZE; |
1190 | 897 | ||
1191 | /* complete all waiting for write CB */ | 898 | /* complete all waiting for write CB */ |
1192 | dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n"); | 899 | dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n"); |
1193 | 900 | ||
1194 | list = &dev->write_waiting_list; | 901 | list = &dev->write_waiting_list; |
1195 | list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { | 902 | list_for_each_entry_safe(pos, next, &list->list, list) { |
1196 | cl = (struct mei_cl *)pos->file_private; | 903 | cl = pos->cl; |
1197 | if (cl == NULL) | 904 | if (cl == NULL) |
1198 | continue; | 905 | continue; |
1199 | 906 | ||
1200 | cl->status = 0; | 907 | cl->status = 0; |
1201 | list_del(&pos->cb_list); | 908 | list_del(&pos->list); |
1202 | if (MEI_WRITING == cl->writing_state && | 909 | if (MEI_WRITING == cl->writing_state && |
1203 | (pos->major_file_operations == MEI_WRITE) && | 910 | pos->fop_type == MEI_FOP_WRITE && |
1204 | (cl != &dev->iamthif_cl)) { | 911 | cl != &dev->iamthif_cl) { |
1205 | dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n"); | 912 | dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n"); |
1206 | cl->writing_state = MEI_WRITE_COMPLETE; | 913 | cl->writing_state = MEI_WRITE_COMPLETE; |
1207 | list_add_tail(&pos->cb_list, | 914 | list_add_tail(&pos->list, &cmpl_list->list); |
1208 | &cmpl_list->mei_cb.cb_list); | ||
1209 | } | 915 | } |
1210 | if (cl == &dev->iamthif_cl) { | 916 | if (cl == &dev->iamthif_cl) { |
1211 | dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); | 917 | dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); |
1212 | if (dev->iamthif_flow_control_pending) { | 918 | if (dev->iamthif_flow_control_pending) { |
1213 | ret = _mei_irq_thread_iamthif_read(dev, slots); | 919 | ret = mei_amthif_irq_read(dev, &slots); |
1214 | if (ret) | 920 | if (ret) |
1215 | return ret; | 921 | return ret; |
1216 | } | 922 | } |
@@ -1222,15 +928,11 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, | |||
1222 | wake_up_interruptible(&dev->wait_stop_wd); | 928 | wake_up_interruptible(&dev->wait_stop_wd); |
1223 | } | 929 | } |
1224 | 930 | ||
1225 | if (dev->extra_write_index) { | 931 | if (dev->wr_ext_msg.hdr.length) { |
1226 | dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n", | 932 | mei_write_message(dev, &dev->wr_ext_msg.hdr, |
1227 | dev->extra_write_index); | 933 | dev->wr_ext_msg.data, dev->wr_ext_msg.hdr.length); |
1228 | mei_write_message(dev, | 934 | slots -= mei_data2slots(dev->wr_ext_msg.hdr.length); |
1229 | (struct mei_msg_hdr *) &dev->ext_msg_buf[0], | 935 | dev->wr_ext_msg.hdr.length = 0; |
1230 | (unsigned char *) &dev->ext_msg_buf[1], | ||
1231 | (dev->extra_write_index - 1) * sizeof(u32)); | ||
1232 | *slots -= dev->extra_write_index; | ||
1233 | dev->extra_write_index = 0; | ||
1234 | } | 936 | } |
1235 | if (dev->dev_state == MEI_DEV_ENABLED) { | 937 | if (dev->dev_state == MEI_DEV_ENABLED) { |
1236 | if (dev->wd_pending && | 938 | if (dev->wd_pending && |
@@ -1243,41 +945,43 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, | |||
1243 | dev->wd_pending = false; | 945 | dev->wd_pending = false; |
1244 | 946 | ||
1245 | if (dev->wd_state == MEI_WD_RUNNING) | 947 | if (dev->wd_state == MEI_WD_RUNNING) |
1246 | *slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); | 948 | slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); |
1247 | else | 949 | else |
1248 | *slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); | 950 | slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); |
1249 | } | 951 | } |
1250 | } | 952 | } |
1251 | 953 | ||
1252 | /* complete control write list CB */ | 954 | /* complete control write list CB */ |
1253 | dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); | 955 | dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); |
1254 | list_for_each_entry_safe(pos, next, | 956 | list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.list, list) { |
1255 | &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) { | 957 | cl = pos->cl; |
1256 | cl = (struct mei_cl *) pos->file_private; | ||
1257 | if (!cl) { | 958 | if (!cl) { |
1258 | list_del(&pos->cb_list); | 959 | list_del(&pos->list); |
1259 | return -ENODEV; | 960 | return -ENODEV; |
1260 | } | 961 | } |
1261 | switch (pos->major_file_operations) { | 962 | switch (pos->fop_type) { |
1262 | case MEI_CLOSE: | 963 | case MEI_FOP_CLOSE: |
1263 | /* send disconnect message */ | 964 | /* send disconnect message */ |
1264 | ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list); | 965 | ret = _mei_irq_thread_close(dev, &slots, pos, |
966 | cl, cmpl_list); | ||
1265 | if (ret) | 967 | if (ret) |
1266 | return ret; | 968 | return ret; |
1267 | 969 | ||
1268 | break; | 970 | break; |
1269 | case MEI_READ: | 971 | case MEI_FOP_READ: |
1270 | /* send flow control message */ | 972 | /* send flow control message */ |
1271 | ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list); | 973 | ret = _mei_irq_thread_read(dev, &slots, pos, |
974 | cl, cmpl_list); | ||
1272 | if (ret) | 975 | if (ret) |
1273 | return ret; | 976 | return ret; |
1274 | 977 | ||
1275 | break; | 978 | break; |
1276 | case MEI_IOCTL: | 979 | case MEI_FOP_IOCTL: |
1277 | /* connect message */ | 980 | /* connect message */ |
1278 | if (mei_other_client_is_connecting(dev, cl)) | 981 | if (mei_other_client_is_connecting(dev, cl)) |
1279 | continue; | 982 | continue; |
1280 | ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list); | 983 | ret = _mei_irq_thread_ioctl(dev, &slots, pos, |
984 | cl, cmpl_list); | ||
1281 | if (ret) | 985 | if (ret) |
1282 | return ret; | 986 | return ret; |
1283 | 987 | ||
@@ -1290,40 +994,26 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, | |||
1290 | } | 994 | } |
1291 | /* complete write list CB */ | 995 | /* complete write list CB */ |
1292 | dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); | 996 | dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); |
1293 | list_for_each_entry_safe(pos, next, | 997 | list_for_each_entry_safe(pos, next, &dev->write_list.list, list) { |
1294 | &dev->write_list.mei_cb.cb_list, cb_list) { | 998 | cl = pos->cl; |
1295 | cl = (struct mei_cl *)pos->file_private; | ||
1296 | if (cl == NULL) | 999 | if (cl == NULL) |
1297 | continue; | 1000 | continue; |
1298 | 1001 | if (mei_flow_ctrl_creds(dev, cl) <= 0) { | |
1299 | if (cl != &dev->iamthif_cl) { | 1002 | dev_dbg(&dev->pdev->dev, |
1300 | if (mei_flow_ctrl_creds(dev, cl) <= 0) { | 1003 | "No flow control credentials for client %d, not sending.\n", |
1301 | dev_dbg(&dev->pdev->dev, | 1004 | cl->host_client_id); |
1302 | "No flow control credentials for client %d, not sending.\n", | 1005 | continue; |
1303 | cl->host_client_id); | ||
1304 | continue; | ||
1305 | } | ||
1306 | ret = _mei_irq_thread_cmpl(dev, slots, pos, | ||
1307 | cl, cmpl_list); | ||
1308 | if (ret) | ||
1309 | return ret; | ||
1310 | |||
1311 | } else if (cl == &dev->iamthif_cl) { | ||
1312 | /* IAMTHIF IOCTL */ | ||
1313 | dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n"); | ||
1314 | if (mei_flow_ctrl_creds(dev, cl) <= 0) { | ||
1315 | dev_dbg(&dev->pdev->dev, | ||
1316 | "No flow control credentials for amthi client %d.\n", | ||
1317 | cl->host_client_id); | ||
1318 | continue; | ||
1319 | } | ||
1320 | ret = _mei_irq_thread_cmpl_iamthif(dev, slots, pos, | ||
1321 | cl, cmpl_list); | ||
1322 | if (ret) | ||
1323 | return ret; | ||
1324 | |||
1325 | } | 1006 | } |
1326 | 1007 | ||
1008 | if (cl == &dev->iamthif_cl) | ||
1009 | ret = mei_amthif_irq_write_complete(dev, &slots, | ||
1010 | pos, cmpl_list); | ||
1011 | else | ||
1012 | ret = mei_irq_thread_write_complete(dev, &slots, pos, | ||
1013 | cmpl_list); | ||
1014 | if (ret) | ||
1015 | return ret; | ||
1016 | |||
1327 | } | 1017 | } |
1328 | return 0; | 1018 | return 0; |
1329 | } | 1019 | } |
@@ -1342,7 +1032,6 @@ void mei_timer(struct work_struct *work) | |||
1342 | unsigned long timeout; | 1032 | unsigned long timeout; |
1343 | struct mei_cl *cl_pos = NULL; | 1033 | struct mei_cl *cl_pos = NULL; |
1344 | struct mei_cl *cl_next = NULL; | 1034 | struct mei_cl *cl_next = NULL; |
1345 | struct list_head *amthi_complete_list = NULL; | ||
1346 | struct mei_cl_cb *cb_pos = NULL; | 1035 | struct mei_cl_cb *cb_pos = NULL; |
1347 | struct mei_cl_cb *cb_next = NULL; | 1036 | struct mei_cl_cb *cb_next = NULL; |
1348 | 1037 | ||
@@ -1385,19 +1074,18 @@ void mei_timer(struct work_struct *work) | |||
1385 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 1074 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
1386 | dev->iamthif_timer = 0; | 1075 | dev->iamthif_timer = 0; |
1387 | 1076 | ||
1388 | if (dev->iamthif_current_cb) | 1077 | mei_io_cb_free(dev->iamthif_current_cb); |
1389 | mei_free_cb_private(dev->iamthif_current_cb); | 1078 | dev->iamthif_current_cb = NULL; |
1390 | 1079 | ||
1391 | dev->iamthif_file_object = NULL; | 1080 | dev->iamthif_file_object = NULL; |
1392 | dev->iamthif_current_cb = NULL; | 1081 | mei_amthif_run_next_cmd(dev); |
1393 | mei_run_next_iamthif_cmd(dev); | ||
1394 | } | 1082 | } |
1395 | } | 1083 | } |
1396 | 1084 | ||
1397 | if (dev->iamthif_timer) { | 1085 | if (dev->iamthif_timer) { |
1398 | 1086 | ||
1399 | timeout = dev->iamthif_timer + | 1087 | timeout = dev->iamthif_timer + |
1400 | msecs_to_jiffies(IAMTHIF_READ_TIMER); | 1088 | mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); |
1401 | 1089 | ||
1402 | dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", | 1090 | dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", |
1403 | dev->iamthif_timer); | 1091 | dev->iamthif_timer); |
@@ -1411,25 +1099,22 @@ void mei_timer(struct work_struct *work) | |||
1411 | 1099 | ||
1412 | dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n"); | 1100 | dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n"); |
1413 | 1101 | ||
1414 | amthi_complete_list = &dev->amthi_read_complete_list. | 1102 | list_for_each_entry_safe(cb_pos, cb_next, |
1415 | mei_cb.cb_list; | 1103 | &dev->amthif_rd_complete_list.list, list) { |
1416 | |||
1417 | list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) { | ||
1418 | 1104 | ||
1419 | cl_pos = cb_pos->file_object->private_data; | 1105 | cl_pos = cb_pos->file_object->private_data; |
1420 | 1106 | ||
1421 | /* Finding the AMTHI entry. */ | 1107 | /* Finding the AMTHI entry. */ |
1422 | if (cl_pos == &dev->iamthif_cl) | 1108 | if (cl_pos == &dev->iamthif_cl) |
1423 | list_del(&cb_pos->cb_list); | 1109 | list_del(&cb_pos->list); |
1424 | } | 1110 | } |
1425 | if (dev->iamthif_current_cb) | 1111 | mei_io_cb_free(dev->iamthif_current_cb); |
1426 | mei_free_cb_private(dev->iamthif_current_cb); | 1112 | dev->iamthif_current_cb = NULL; |
1427 | 1113 | ||
1428 | dev->iamthif_file_object->private_data = NULL; | 1114 | dev->iamthif_file_object->private_data = NULL; |
1429 | dev->iamthif_file_object = NULL; | 1115 | dev->iamthif_file_object = NULL; |
1430 | dev->iamthif_current_cb = NULL; | ||
1431 | dev->iamthif_timer = 0; | 1116 | dev->iamthif_timer = 0; |
1432 | mei_run_next_iamthif_cmd(dev); | 1117 | mei_amthif_run_next_cmd(dev); |
1433 | 1118 | ||
1434 | } | 1119 | } |
1435 | } | 1120 | } |
@@ -1451,7 +1136,7 @@ out: | |||
1451 | irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) | 1136 | irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) |
1452 | { | 1137 | { |
1453 | struct mei_device *dev = (struct mei_device *) dev_id; | 1138 | struct mei_device *dev = (struct mei_device *) dev_id; |
1454 | struct mei_io_list complete_list; | 1139 | struct mei_cl_cb complete_list; |
1455 | struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; | 1140 | struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; |
1456 | struct mei_cl *cl; | 1141 | struct mei_cl *cl; |
1457 | s32 slots; | 1142 | s32 slots; |
@@ -1504,17 +1189,17 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) | |||
1504 | } | 1189 | } |
1505 | /* check slots available for reading */ | 1190 | /* check slots available for reading */ |
1506 | slots = mei_count_full_read_slots(dev); | 1191 | slots = mei_count_full_read_slots(dev); |
1507 | dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", | 1192 | while (slots > 0) { |
1508 | slots, dev->extra_write_index); | 1193 | /* we have urgent data to send so break the read */ |
1509 | while (slots > 0 && !dev->extra_write_index) { | 1194 | if (dev->wr_ext_msg.hdr.length) |
1510 | dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", | 1195 | break; |
1511 | slots, dev->extra_write_index); | 1196 | dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots); |
1512 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n"); | 1197 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n"); |
1513 | rets = mei_irq_thread_read_handler(&complete_list, dev, &slots); | 1198 | rets = mei_irq_thread_read_handler(&complete_list, dev, &slots); |
1514 | if (rets) | 1199 | if (rets) |
1515 | goto end; | 1200 | goto end; |
1516 | } | 1201 | } |
1517 | rets = mei_irq_thread_write_handler(&complete_list, dev, &slots); | 1202 | rets = mei_irq_thread_write_handler(dev, &complete_list); |
1518 | end: | 1203 | end: |
1519 | dev_dbg(&dev->pdev->dev, "end of bottom half function.\n"); | 1204 | dev_dbg(&dev->pdev->dev, "end of bottom half function.\n"); |
1520 | dev->host_hw_state = mei_hcsr_read(dev); | 1205 | dev->host_hw_state = mei_hcsr_read(dev); |
@@ -1531,21 +1216,20 @@ end: | |||
1531 | wake_up_interruptible(&dev->wait_recvd_msg); | 1216 | wake_up_interruptible(&dev->wait_recvd_msg); |
1532 | bus_message_received = false; | 1217 | bus_message_received = false; |
1533 | } | 1218 | } |
1534 | if (list_empty(&complete_list.mei_cb.cb_list)) | 1219 | if (list_empty(&complete_list.list)) |
1535 | return IRQ_HANDLED; | 1220 | return IRQ_HANDLED; |
1536 | 1221 | ||
1537 | 1222 | ||
1538 | list_for_each_entry_safe(cb_pos, cb_next, | 1223 | list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) { |
1539 | &complete_list.mei_cb.cb_list, cb_list) { | 1224 | cl = cb_pos->cl; |
1540 | cl = (struct mei_cl *)cb_pos->file_private; | 1225 | list_del(&cb_pos->list); |
1541 | list_del(&cb_pos->cb_list); | ||
1542 | if (cl) { | 1226 | if (cl) { |
1543 | if (cl != &dev->iamthif_cl) { | 1227 | if (cl != &dev->iamthif_cl) { |
1544 | dev_dbg(&dev->pdev->dev, "completing call back.\n"); | 1228 | dev_dbg(&dev->pdev->dev, "completing call back.\n"); |
1545 | _mei_cmpl(cl, cb_pos); | 1229 | _mei_cmpl(cl, cb_pos); |
1546 | cb_pos = NULL; | 1230 | cb_pos = NULL; |
1547 | } else if (cl == &dev->iamthif_cl) { | 1231 | } else if (cl == &dev->iamthif_cl) { |
1548 | _mei_cmpl_iamthif(dev, cb_pos); | 1232 | mei_amthif_complete(dev, cb_pos); |
1549 | } | 1233 | } |
1550 | } | 1234 | } |
1551 | } | 1235 | } |
diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index fcba98eb892..eb93a1b53b9 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c | |||
@@ -39,6 +39,95 @@ | |||
39 | #include "interface.h" | 39 | #include "interface.h" |
40 | 40 | ||
41 | /** | 41 | /** |
42 | * mei_io_cb_free - free mei_cb_private related memory | ||
43 | * | ||
44 | * @cb: mei callback struct | ||
45 | */ | ||
46 | void mei_io_cb_free(struct mei_cl_cb *cb) | ||
47 | { | ||
48 | if (cb == NULL) | ||
49 | return; | ||
50 | |||
51 | kfree(cb->request_buffer.data); | ||
52 | kfree(cb->response_buffer.data); | ||
53 | kfree(cb); | ||
54 | } | ||
55 | /** | ||
56 | * mei_io_cb_init - allocate and initialize io callback | ||
57 | * | ||
58 | * @cl - mei client | ||
59 | * @file: pointer to file structure | ||
60 | * | ||
61 | * returns mei_cl_cb pointer or NULL; | ||
62 | */ | ||
63 | struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) | ||
64 | { | ||
65 | struct mei_cl_cb *cb; | ||
66 | |||
67 | cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); | ||
68 | if (!cb) | ||
69 | return NULL; | ||
70 | |||
71 | mei_io_list_init(cb); | ||
72 | |||
73 | cb->file_object = fp; | ||
74 | cb->cl = cl; | ||
75 | cb->buf_idx = 0; | ||
76 | return cb; | ||
77 | } | ||
78 | |||
79 | |||
80 | /** | ||
81 | * mei_io_cb_alloc_req_buf - allocate request buffer | ||
82 | * | ||
83 | * @cb - io callback structure | ||
84 | * @size: size of the buffer | ||
85 | * | ||
86 | * returns 0 on success | ||
87 | * -EINVAL if cb is NULL | ||
88 | * -ENOMEM if allocation failed | ||
89 | */ | ||
90 | int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) | ||
91 | { | ||
92 | if (!cb) | ||
93 | return -EINVAL; | ||
94 | |||
95 | if (length == 0) | ||
96 | return 0; | ||
97 | |||
98 | cb->request_buffer.data = kmalloc(length, GFP_KERNEL); | ||
99 | if (!cb->request_buffer.data) | ||
100 | return -ENOMEM; | ||
101 | cb->request_buffer.size = length; | ||
102 | return 0; | ||
103 | } | ||
104 | /** | ||
105 | * mei_io_cb_alloc_req_buf - allocate respose buffer | ||
106 | * | ||
107 | * @cb - io callback structure | ||
108 | * @size: size of the buffer | ||
109 | * | ||
110 | * returns 0 on success | ||
111 | * -EINVAL if cb is NULL | ||
112 | * -ENOMEM if allocation failed | ||
113 | */ | ||
114 | int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) | ||
115 | { | ||
116 | if (!cb) | ||
117 | return -EINVAL; | ||
118 | |||
119 | if (length == 0) | ||
120 | return 0; | ||
121 | |||
122 | cb->response_buffer.data = kmalloc(length, GFP_KERNEL); | ||
123 | if (!cb->response_buffer.data) | ||
124 | return -ENOMEM; | ||
125 | cb->response_buffer.size = length; | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | |||
130 | /** | ||
42 | * mei_me_cl_by_id return index to me_clients for client_id | 131 | * mei_me_cl_by_id return index to me_clients for client_id |
43 | * | 132 | * |
44 | * @dev: the device structure | 133 | * @dev: the device structure |
@@ -82,9 +171,7 @@ int mei_ioctl_connect_client(struct file *file, | |||
82 | struct mei_cl_cb *cb; | 171 | struct mei_cl_cb *cb; |
83 | struct mei_client *client; | 172 | struct mei_client *client; |
84 | struct mei_cl *cl; | 173 | struct mei_cl *cl; |
85 | struct mei_cl *cl_pos = NULL; | 174 | long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); |
86 | struct mei_cl *cl_next = NULL; | ||
87 | long timeout = CONNECT_TIMEOUT; | ||
88 | int i; | 175 | int i; |
89 | int err; | 176 | int err; |
90 | int rets; | 177 | int rets; |
@@ -97,16 +184,14 @@ int mei_ioctl_connect_client(struct file *file, | |||
97 | 184 | ||
98 | dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); | 185 | dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); |
99 | 186 | ||
100 | |||
101 | /* buffered ioctl cb */ | 187 | /* buffered ioctl cb */ |
102 | cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); | 188 | cb = mei_io_cb_init(cl, file); |
103 | if (!cb) { | 189 | if (!cb) { |
104 | rets = -ENOMEM; | 190 | rets = -ENOMEM; |
105 | goto end; | 191 | goto end; |
106 | } | 192 | } |
107 | INIT_LIST_HEAD(&cb->cb_list); | ||
108 | 193 | ||
109 | cb->major_file_operations = MEI_IOCTL; | 194 | cb->fop_type = MEI_FOP_IOCTL; |
110 | 195 | ||
111 | if (dev->dev_state != MEI_DEV_ENABLED) { | 196 | if (dev->dev_state != MEI_DEV_ENABLED) { |
112 | rets = -ENODEV; | 197 | rets = -ENODEV; |
@@ -142,21 +227,9 @@ int mei_ioctl_connect_client(struct file *file, | |||
142 | goto end; | 227 | goto end; |
143 | } | 228 | } |
144 | clear_bit(cl->host_client_id, dev->host_clients_map); | 229 | clear_bit(cl->host_client_id, dev->host_clients_map); |
145 | list_for_each_entry_safe(cl_pos, cl_next, | 230 | mei_me_cl_unlink(dev, cl); |
146 | &dev->file_list, link) { | ||
147 | if (mei_cl_cmp_id(cl, cl_pos)) { | ||
148 | dev_dbg(&dev->pdev->dev, | ||
149 | "remove file private data node host" | ||
150 | " client = %d, ME client = %d.\n", | ||
151 | cl_pos->host_client_id, | ||
152 | cl_pos->me_client_id); | ||
153 | list_del(&cl_pos->link); | ||
154 | } | ||
155 | 231 | ||
156 | } | ||
157 | dev_dbg(&dev->pdev->dev, "free file private data memory.\n"); | ||
158 | kfree(cl); | 232 | kfree(cl); |
159 | |||
160 | cl = NULL; | 233 | cl = NULL; |
161 | file->private_data = &dev->iamthif_cl; | 234 | file->private_data = &dev->iamthif_cl; |
162 | 235 | ||
@@ -192,25 +265,19 @@ int mei_ioctl_connect_client(struct file *file, | |||
192 | } else { | 265 | } else { |
193 | dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); | 266 | dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); |
194 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 267 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
195 | cb->file_private = cl; | 268 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); |
196 | list_add_tail(&cb->cb_list, | ||
197 | &dev->ctrl_rd_list.mei_cb. | ||
198 | cb_list); | ||
199 | } | 269 | } |
200 | 270 | ||
201 | 271 | ||
202 | } else { | 272 | } else { |
203 | dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); | 273 | dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); |
204 | cb->file_private = cl; | ||
205 | dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); | 274 | dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); |
206 | list_add_tail(&cb->cb_list, | 275 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
207 | &dev->ctrl_wr_list.mei_cb.cb_list); | ||
208 | } | 276 | } |
209 | mutex_unlock(&dev->device_lock); | 277 | mutex_unlock(&dev->device_lock); |
210 | err = wait_event_timeout(dev->wait_recvd_msg, | 278 | err = wait_event_timeout(dev->wait_recvd_msg, |
211 | (MEI_FILE_CONNECTED == cl->state || | 279 | (MEI_FILE_CONNECTED == cl->state || |
212 | MEI_FILE_DISCONNECTED == cl->state), | 280 | MEI_FILE_DISCONNECTED == cl->state), timeout); |
213 | timeout * HZ); | ||
214 | 281 | ||
215 | mutex_lock(&dev->device_lock); | 282 | mutex_lock(&dev->device_lock); |
216 | if (MEI_FILE_CONNECTED == cl->state) { | 283 | if (MEI_FILE_CONNECTED == cl->state) { |
@@ -234,153 +301,7 @@ int mei_ioctl_connect_client(struct file *file, | |||
234 | rets = 0; | 301 | rets = 0; |
235 | end: | 302 | end: |
236 | dev_dbg(&dev->pdev->dev, "free connect cb memory."); | 303 | dev_dbg(&dev->pdev->dev, "free connect cb memory."); |
237 | kfree(cb); | 304 | mei_io_cb_free(cb); |
238 | return rets; | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * find_amthi_read_list_entry - finds a amthilist entry for current file | ||
243 | * | ||
244 | * @dev: the device structure | ||
245 | * @file: pointer to file object | ||
246 | * | ||
247 | * returns returned a list entry on success, NULL on failure. | ||
248 | */ | ||
249 | struct mei_cl_cb *find_amthi_read_list_entry( | ||
250 | struct mei_device *dev, | ||
251 | struct file *file) | ||
252 | { | ||
253 | struct mei_cl *cl_temp; | ||
254 | struct mei_cl_cb *pos = NULL; | ||
255 | struct mei_cl_cb *next = NULL; | ||
256 | |||
257 | list_for_each_entry_safe(pos, next, | ||
258 | &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) { | ||
259 | cl_temp = (struct mei_cl *)pos->file_private; | ||
260 | if (cl_temp && cl_temp == &dev->iamthif_cl && | ||
261 | pos->file_object == file) | ||
262 | return pos; | ||
263 | } | ||
264 | return NULL; | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * amthi_read - read data from AMTHI client | ||
269 | * | ||
270 | * @dev: the device structure | ||
271 | * @if_num: minor number | ||
272 | * @file: pointer to file object | ||
273 | * @*ubuf: pointer to user data in user space | ||
274 | * @length: data length to read | ||
275 | * @offset: data read offset | ||
276 | * | ||
277 | * Locking: called under "dev->device_lock" lock | ||
278 | * | ||
279 | * returns | ||
280 | * returned data length on success, | ||
281 | * zero if no data to read, | ||
282 | * negative on failure. | ||
283 | */ | ||
284 | int amthi_read(struct mei_device *dev, struct file *file, | ||
285 | char __user *ubuf, size_t length, loff_t *offset) | ||
286 | { | ||
287 | int rets; | ||
288 | int wait_ret; | ||
289 | struct mei_cl_cb *cb = NULL; | ||
290 | struct mei_cl *cl = file->private_data; | ||
291 | unsigned long timeout; | ||
292 | int i; | ||
293 | |||
294 | /* Only Posible if we are in timeout */ | ||
295 | if (!cl || cl != &dev->iamthif_cl) { | ||
296 | dev_dbg(&dev->pdev->dev, "bad file ext.\n"); | ||
297 | return -ETIMEDOUT; | ||
298 | } | ||
299 | |||
300 | i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); | ||
301 | |||
302 | if (i < 0) { | ||
303 | dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); | ||
304 | return -ENODEV; | ||
305 | } | ||
306 | dev_dbg(&dev->pdev->dev, "checking amthi data\n"); | ||
307 | cb = find_amthi_read_list_entry(dev, file); | ||
308 | |||
309 | /* Check for if we can block or not*/ | ||
310 | if (cb == NULL && file->f_flags & O_NONBLOCK) | ||
311 | return -EAGAIN; | ||
312 | |||
313 | |||
314 | dev_dbg(&dev->pdev->dev, "waiting for amthi data\n"); | ||
315 | while (cb == NULL) { | ||
316 | /* unlock the Mutex */ | ||
317 | mutex_unlock(&dev->device_lock); | ||
318 | |||
319 | wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, | ||
320 | (cb = find_amthi_read_list_entry(dev, file))); | ||
321 | |||
322 | if (wait_ret) | ||
323 | return -ERESTARTSYS; | ||
324 | |||
325 | dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); | ||
326 | |||
327 | /* Locking again the Mutex */ | ||
328 | mutex_lock(&dev->device_lock); | ||
329 | } | ||
330 | |||
331 | |||
332 | dev_dbg(&dev->pdev->dev, "Got amthi data\n"); | ||
333 | dev->iamthif_timer = 0; | ||
334 | |||
335 | if (cb) { | ||
336 | timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER); | ||
337 | dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", | ||
338 | timeout); | ||
339 | |||
340 | if (time_after(jiffies, timeout)) { | ||
341 | dev_dbg(&dev->pdev->dev, "amthi Time out\n"); | ||
342 | /* 15 sec for the message has expired */ | ||
343 | list_del(&cb->cb_list); | ||
344 | rets = -ETIMEDOUT; | ||
345 | goto free; | ||
346 | } | ||
347 | } | ||
348 | /* if the whole message will fit remove it from the list */ | ||
349 | if (cb->information >= *offset && length >= (cb->information - *offset)) | ||
350 | list_del(&cb->cb_list); | ||
351 | else if (cb->information > 0 && cb->information <= *offset) { | ||
352 | /* end of the message has been reached */ | ||
353 | list_del(&cb->cb_list); | ||
354 | rets = 0; | ||
355 | goto free; | ||
356 | } | ||
357 | /* else means that not full buffer will be read and do not | ||
358 | * remove message from deletion list | ||
359 | */ | ||
360 | |||
361 | dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", | ||
362 | cb->response_buffer.size); | ||
363 | dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n", | ||
364 | cb->information); | ||
365 | |||
366 | /* length is being turncated to PAGE_SIZE, however, | ||
367 | * the information may be longer */ | ||
368 | length = min_t(size_t, length, (cb->information - *offset)); | ||
369 | |||
370 | if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) | ||
371 | rets = -EFAULT; | ||
372 | else { | ||
373 | rets = length; | ||
374 | if ((*offset + length) < cb->information) { | ||
375 | *offset += length; | ||
376 | goto out; | ||
377 | } | ||
378 | } | ||
379 | free: | ||
380 | dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); | ||
381 | *offset = 0; | ||
382 | mei_free_cb_private(cb); | ||
383 | out: | ||
384 | return rets; | 305 | return rets; |
385 | } | 306 | } |
386 | 307 | ||
@@ -396,7 +317,7 @@ out: | |||
396 | int mei_start_read(struct mei_device *dev, struct mei_cl *cl) | 317 | int mei_start_read(struct mei_device *dev, struct mei_cl *cl) |
397 | { | 318 | { |
398 | struct mei_cl_cb *cb; | 319 | struct mei_cl_cb *cb; |
399 | int rets = 0; | 320 | int rets; |
400 | int i; | 321 | int i; |
401 | 322 | ||
402 | if (cl->state != MEI_FILE_CONNECTED) | 323 | if (cl->state != MEI_FILE_CONNECTED) |
@@ -405,187 +326,41 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) | |||
405 | if (dev->dev_state != MEI_DEV_ENABLED) | 326 | if (dev->dev_state != MEI_DEV_ENABLED) |
406 | return -ENODEV; | 327 | return -ENODEV; |
407 | 328 | ||
408 | dev_dbg(&dev->pdev->dev, "check if read is pending.\n"); | ||
409 | if (cl->read_pending || cl->read_cb) { | 329 | if (cl->read_pending || cl->read_cb) { |
410 | dev_dbg(&dev->pdev->dev, "read is pending.\n"); | 330 | dev_dbg(&dev->pdev->dev, "read is pending.\n"); |
411 | return -EBUSY; | 331 | return -EBUSY; |
412 | } | 332 | } |
333 | i = mei_me_cl_by_id(dev, cl->me_client_id); | ||
334 | if (i < 0) { | ||
335 | dev_err(&dev->pdev->dev, "no such me client %d\n", | ||
336 | cl->me_client_id); | ||
337 | return -ENODEV; | ||
338 | } | ||
413 | 339 | ||
414 | cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); | 340 | cb = mei_io_cb_init(cl, NULL); |
415 | if (!cb) | 341 | if (!cb) |
416 | return -ENOMEM; | 342 | return -ENOMEM; |
417 | 343 | ||
418 | dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n", | 344 | rets = mei_io_cb_alloc_resp_buf(cb, |
419 | cl->host_client_id, cl->me_client_id); | 345 | dev->me_clients[i].props.max_msg_length); |
420 | i = mei_me_cl_by_id(dev, cl->me_client_id); | 346 | if (rets) |
421 | if (i < 0) { | 347 | goto err; |
422 | rets = -ENODEV; | ||
423 | goto unlock; | ||
424 | } | ||
425 | 348 | ||
426 | cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; | 349 | cb->fop_type = MEI_FOP_READ; |
427 | cb->response_buffer.data = | ||
428 | kmalloc(cb->response_buffer.size, GFP_KERNEL); | ||
429 | if (!cb->response_buffer.data) { | ||
430 | rets = -ENOMEM; | ||
431 | goto unlock; | ||
432 | } | ||
433 | dev_dbg(&dev->pdev->dev, "allocation call back data success.\n"); | ||
434 | cb->major_file_operations = MEI_READ; | ||
435 | /* make sure information is zero before we start */ | ||
436 | cb->information = 0; | ||
437 | cb->file_private = (void *) cl; | ||
438 | cl->read_cb = cb; | 350 | cl->read_cb = cb; |
439 | if (dev->mei_host_buffer_is_empty) { | 351 | if (dev->mei_host_buffer_is_empty) { |
440 | dev->mei_host_buffer_is_empty = false; | 352 | dev->mei_host_buffer_is_empty = false; |
441 | if (mei_send_flow_control(dev, cl)) { | 353 | if (mei_send_flow_control(dev, cl)) { |
442 | rets = -ENODEV; | 354 | rets = -ENODEV; |
443 | goto unlock; | 355 | goto err; |
444 | } | 356 | } |
445 | list_add_tail(&cb->cb_list, &dev->read_list.mei_cb.cb_list); | 357 | list_add_tail(&cb->list, &dev->read_list.list); |
446 | } else { | 358 | } else { |
447 | list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list); | 359 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
448 | } | 360 | } |
449 | return rets; | 361 | return rets; |
450 | unlock: | 362 | err: |
451 | mei_free_cb_private(cb); | 363 | mei_io_cb_free(cb); |
452 | return rets; | 364 | return rets; |
453 | } | 365 | } |
454 | 366 | ||
455 | /** | ||
456 | * amthi_write - write iamthif data to amthi client | ||
457 | * | ||
458 | * @dev: the device structure | ||
459 | * @cb: mei call back struct | ||
460 | * | ||
461 | * returns 0 on success, <0 on failure. | ||
462 | */ | ||
463 | int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) | ||
464 | { | ||
465 | struct mei_msg_hdr mei_hdr; | ||
466 | int ret; | ||
467 | |||
468 | if (!dev || !cb) | ||
469 | return -ENODEV; | ||
470 | |||
471 | dev_dbg(&dev->pdev->dev, "write data to amthi client.\n"); | ||
472 | |||
473 | dev->iamthif_state = MEI_IAMTHIF_WRITING; | ||
474 | dev->iamthif_current_cb = cb; | ||
475 | dev->iamthif_file_object = cb->file_object; | ||
476 | dev->iamthif_canceled = false; | ||
477 | dev->iamthif_ioctl = true; | ||
478 | dev->iamthif_msg_buf_size = cb->request_buffer.size; | ||
479 | memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, | ||
480 | cb->request_buffer.size); | ||
481 | |||
482 | ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); | ||
483 | if (ret < 0) | ||
484 | return ret; | ||
485 | |||
486 | if (ret && dev->mei_host_buffer_is_empty) { | ||
487 | ret = 0; | ||
488 | dev->mei_host_buffer_is_empty = false; | ||
489 | if (cb->request_buffer.size > mei_hbuf_max_data(dev)) { | ||
490 | mei_hdr.length = mei_hbuf_max_data(dev); | ||
491 | mei_hdr.msg_complete = 0; | ||
492 | } else { | ||
493 | mei_hdr.length = cb->request_buffer.size; | ||
494 | mei_hdr.msg_complete = 1; | ||
495 | } | ||
496 | |||
497 | mei_hdr.host_addr = dev->iamthif_cl.host_client_id; | ||
498 | mei_hdr.me_addr = dev->iamthif_cl.me_client_id; | ||
499 | mei_hdr.reserved = 0; | ||
500 | dev->iamthif_msg_buf_index += mei_hdr.length; | ||
501 | if (mei_write_message(dev, &mei_hdr, | ||
502 | (unsigned char *)(dev->iamthif_msg_buf), | ||
503 | mei_hdr.length)) | ||
504 | return -ENODEV; | ||
505 | |||
506 | if (mei_hdr.msg_complete) { | ||
507 | if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl)) | ||
508 | return -ENODEV; | ||
509 | dev->iamthif_flow_control_pending = true; | ||
510 | dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; | ||
511 | dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); | ||
512 | dev->iamthif_current_cb = cb; | ||
513 | dev->iamthif_file_object = cb->file_object; | ||
514 | list_add_tail(&cb->cb_list, | ||
515 | &dev->write_waiting_list.mei_cb.cb_list); | ||
516 | } else { | ||
517 | dev_dbg(&dev->pdev->dev, "message does not complete, " | ||
518 | "so add amthi cb to write list.\n"); | ||
519 | list_add_tail(&cb->cb_list, | ||
520 | &dev->write_list.mei_cb.cb_list); | ||
521 | } | ||
522 | } else { | ||
523 | if (!(dev->mei_host_buffer_is_empty)) | ||
524 | dev_dbg(&dev->pdev->dev, "host buffer is not empty"); | ||
525 | |||
526 | dev_dbg(&dev->pdev->dev, "No flow control credentials, " | ||
527 | "so add iamthif cb to write list.\n"); | ||
528 | list_add_tail(&cb->cb_list, &dev->write_list.mei_cb.cb_list); | ||
529 | } | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | /** | ||
534 | * iamthif_ioctl_send_msg - send cmd data to amthi client | ||
535 | * | ||
536 | * @dev: the device structure | ||
537 | * | ||
538 | * returns 0 on success, <0 on failure. | ||
539 | */ | ||
540 | void mei_run_next_iamthif_cmd(struct mei_device *dev) | ||
541 | { | ||
542 | struct mei_cl *cl_tmp; | ||
543 | struct mei_cl_cb *pos = NULL; | ||
544 | struct mei_cl_cb *next = NULL; | ||
545 | int status; | ||
546 | |||
547 | if (!dev) | ||
548 | return; | ||
549 | |||
550 | dev->iamthif_msg_buf_size = 0; | ||
551 | dev->iamthif_msg_buf_index = 0; | ||
552 | dev->iamthif_canceled = false; | ||
553 | dev->iamthif_ioctl = true; | ||
554 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
555 | dev->iamthif_timer = 0; | ||
556 | dev->iamthif_file_object = NULL; | ||
557 | |||
558 | dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); | ||
559 | |||
560 | list_for_each_entry_safe(pos, next, | ||
561 | &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) { | ||
562 | list_del(&pos->cb_list); | ||
563 | cl_tmp = (struct mei_cl *)pos->file_private; | ||
564 | |||
565 | if (cl_tmp && cl_tmp == &dev->iamthif_cl) { | ||
566 | status = amthi_write(dev, pos); | ||
567 | if (status) { | ||
568 | dev_dbg(&dev->pdev->dev, | ||
569 | "amthi write failed status = %d\n", | ||
570 | status); | ||
571 | return; | ||
572 | } | ||
573 | break; | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | |||
578 | /** | ||
579 | * mei_free_cb_private - free mei_cb_private related memory | ||
580 | * | ||
581 | * @cb: mei callback struct | ||
582 | */ | ||
583 | void mei_free_cb_private(struct mei_cl_cb *cb) | ||
584 | { | ||
585 | if (cb == NULL) | ||
586 | return; | ||
587 | |||
588 | kfree(cb->request_buffer.data); | ||
589 | kfree(cb->response_buffer.data); | ||
590 | kfree(cb); | ||
591 | } | ||
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index e8b0858132c..43fb52ff98a 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -90,93 +90,6 @@ static DEFINE_MUTEX(mei_mutex); | |||
90 | 90 | ||
91 | 91 | ||
92 | /** | 92 | /** |
93 | * mei_clear_list - removes all callbacks associated with file | ||
94 | * from mei_cb_list | ||
95 | * | ||
96 | * @dev: device structure. | ||
97 | * @file: file structure | ||
98 | * @mei_cb_list: callbacks list | ||
99 | * | ||
100 | * mei_clear_list is called to clear resources associated with file | ||
101 | * when application calls close function or Ctrl-C was pressed | ||
102 | * | ||
103 | * returns true if callback removed from the list, false otherwise | ||
104 | */ | ||
105 | static bool mei_clear_list(struct mei_device *dev, | ||
106 | struct file *file, struct list_head *mei_cb_list) | ||
107 | { | ||
108 | struct mei_cl_cb *cb_pos = NULL; | ||
109 | struct mei_cl_cb *cb_next = NULL; | ||
110 | struct file *file_temp; | ||
111 | bool removed = false; | ||
112 | |||
113 | /* list all list member */ | ||
114 | list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) { | ||
115 | file_temp = (struct file *)cb_pos->file_object; | ||
116 | /* check if list member associated with a file */ | ||
117 | if (file_temp == file) { | ||
118 | /* remove member from the list */ | ||
119 | list_del(&cb_pos->cb_list); | ||
120 | /* check if cb equal to current iamthif cb */ | ||
121 | if (dev->iamthif_current_cb == cb_pos) { | ||
122 | dev->iamthif_current_cb = NULL; | ||
123 | /* send flow control to iamthif client */ | ||
124 | mei_send_flow_control(dev, &dev->iamthif_cl); | ||
125 | } | ||
126 | /* free all allocated buffers */ | ||
127 | mei_free_cb_private(cb_pos); | ||
128 | cb_pos = NULL; | ||
129 | removed = true; | ||
130 | } | ||
131 | } | ||
132 | return removed; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * mei_clear_lists - removes all callbacks associated with file | ||
137 | * | ||
138 | * @dev: device structure | ||
139 | * @file: file structure | ||
140 | * | ||
141 | * mei_clear_lists is called to clear resources associated with file | ||
142 | * when application calls close function or Ctrl-C was pressed | ||
143 | * | ||
144 | * returns true if callback removed from the list, false otherwise | ||
145 | */ | ||
146 | static bool mei_clear_lists(struct mei_device *dev, struct file *file) | ||
147 | { | ||
148 | bool removed = false; | ||
149 | |||
150 | /* remove callbacks associated with a file */ | ||
151 | mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list); | ||
152 | if (mei_clear_list(dev, file, | ||
153 | &dev->amthi_read_complete_list.mei_cb.cb_list)) | ||
154 | removed = true; | ||
155 | |||
156 | mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list); | ||
157 | |||
158 | if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list)) | ||
159 | removed = true; | ||
160 | |||
161 | if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list)) | ||
162 | removed = true; | ||
163 | |||
164 | if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list)) | ||
165 | removed = true; | ||
166 | |||
167 | /* check if iamthif_current_cb not NULL */ | ||
168 | if (dev->iamthif_current_cb && !removed) { | ||
169 | /* check file and iamthif current cb association */ | ||
170 | if (dev->iamthif_current_cb->file_object == file) { | ||
171 | /* remove cb */ | ||
172 | mei_free_cb_private(dev->iamthif_current_cb); | ||
173 | dev->iamthif_current_cb = NULL; | ||
174 | removed = true; | ||
175 | } | ||
176 | } | ||
177 | return removed; | ||
178 | } | ||
179 | /** | ||
180 | * find_read_list_entry - find read list entry | 93 | * find_read_list_entry - find read list entry |
181 | * | 94 | * |
182 | * @dev: device structure | 95 | * @dev: device structure |
@@ -192,14 +105,9 @@ static struct mei_cl_cb *find_read_list_entry( | |||
192 | struct mei_cl_cb *next = NULL; | 105 | struct mei_cl_cb *next = NULL; |
193 | 106 | ||
194 | dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); | 107 | dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); |
195 | list_for_each_entry_safe(pos, next, | 108 | list_for_each_entry_safe(pos, next, &dev->read_list.list, list) |
196 | &dev->read_list.mei_cb.cb_list, cb_list) { | 109 | if (mei_cl_cmp_id(cl, pos->cl)) |
197 | struct mei_cl *cl_temp; | ||
198 | cl_temp = (struct mei_cl *)pos->file_private; | ||
199 | |||
200 | if (mei_cl_cmp_id(cl, cl_temp)) | ||
201 | return pos; | 110 | return pos; |
202 | } | ||
203 | return NULL; | 111 | return NULL; |
204 | } | 112 | } |
205 | 113 | ||
@@ -297,67 +205,51 @@ static int mei_release(struct inode *inode, struct file *file) | |||
297 | dev = cl->dev; | 205 | dev = cl->dev; |
298 | 206 | ||
299 | mutex_lock(&dev->device_lock); | 207 | mutex_lock(&dev->device_lock); |
300 | if (cl != &dev->iamthif_cl) { | 208 | if (cl == &dev->iamthif_cl) { |
301 | if (cl->state == MEI_FILE_CONNECTED) { | 209 | rets = mei_amthif_release(dev, file); |
302 | cl->state = MEI_FILE_DISCONNECTING; | 210 | goto out; |
303 | dev_dbg(&dev->pdev->dev, | 211 | } |
304 | "disconnecting client host client = %d, " | 212 | if (cl->state == MEI_FILE_CONNECTED) { |
305 | "ME client = %d\n", | 213 | cl->state = MEI_FILE_DISCONNECTING; |
306 | cl->host_client_id, | 214 | dev_dbg(&dev->pdev->dev, |
307 | cl->me_client_id); | 215 | "disconnecting client host client = %d, " |
308 | rets = mei_disconnect_host_client(dev, cl); | 216 | "ME client = %d\n", |
309 | } | ||
310 | mei_cl_flush_queues(cl); | ||
311 | dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", | ||
312 | cl->host_client_id, | 217 | cl->host_client_id, |
313 | cl->me_client_id); | 218 | cl->me_client_id); |
219 | rets = mei_disconnect_host_client(dev, cl); | ||
220 | } | ||
221 | mei_cl_flush_queues(cl); | ||
222 | dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", | ||
223 | cl->host_client_id, | ||
224 | cl->me_client_id); | ||
225 | |||
226 | if (dev->open_handle_count > 0) { | ||
227 | clear_bit(cl->host_client_id, dev->host_clients_map); | ||
228 | dev->open_handle_count--; | ||
229 | } | ||
230 | mei_me_cl_unlink(dev, cl); | ||
314 | 231 | ||
315 | if (dev->open_handle_count > 0) { | 232 | /* free read cb */ |
316 | clear_bit(cl->host_client_id, dev->host_clients_map); | 233 | cb = NULL; |
317 | dev->open_handle_count--; | 234 | if (cl->read_cb) { |
318 | } | 235 | cb = find_read_list_entry(dev, cl); |
319 | mei_remove_client_from_file_list(dev, cl->host_client_id); | 236 | /* Remove entry from read list */ |
320 | 237 | if (cb) | |
321 | /* free read cb */ | 238 | list_del(&cb->list); |
322 | cb = NULL; | ||
323 | if (cl->read_cb) { | ||
324 | cb = find_read_list_entry(dev, cl); | ||
325 | /* Remove entry from read list */ | ||
326 | if (cb) | ||
327 | list_del(&cb->cb_list); | ||
328 | |||
329 | cb = cl->read_cb; | ||
330 | cl->read_cb = NULL; | ||
331 | } | ||
332 | |||
333 | file->private_data = NULL; | ||
334 | |||
335 | if (cb) { | ||
336 | mei_free_cb_private(cb); | ||
337 | cb = NULL; | ||
338 | } | ||
339 | 239 | ||
340 | kfree(cl); | 240 | cb = cl->read_cb; |
341 | } else { | 241 | cl->read_cb = NULL; |
342 | if (dev->open_handle_count > 0) | 242 | } |
343 | dev->open_handle_count--; | ||
344 | |||
345 | if (dev->iamthif_file_object == file && | ||
346 | dev->iamthif_state != MEI_IAMTHIF_IDLE) { | ||
347 | |||
348 | dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", | ||
349 | dev->iamthif_state); | ||
350 | dev->iamthif_canceled = true; | ||
351 | if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { | ||
352 | dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); | ||
353 | mei_run_next_iamthif_cmd(dev); | ||
354 | } | ||
355 | } | ||
356 | 243 | ||
357 | if (mei_clear_lists(dev, file)) | 244 | file->private_data = NULL; |
358 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
359 | 245 | ||
246 | if (cb) { | ||
247 | mei_io_cb_free(cb); | ||
248 | cb = NULL; | ||
360 | } | 249 | } |
250 | |||
251 | kfree(cl); | ||
252 | out: | ||
361 | mutex_unlock(&dev->device_lock); | 253 | mutex_unlock(&dev->device_lock); |
362 | return rets; | 254 | return rets; |
363 | } | 255 | } |
@@ -411,20 +303,19 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
411 | } | 303 | } |
412 | 304 | ||
413 | if (cl == &dev->iamthif_cl) { | 305 | if (cl == &dev->iamthif_cl) { |
414 | rets = amthi_read(dev, file, ubuf, length, offset); | 306 | rets = mei_amthif_read(dev, file, ubuf, length, offset); |
415 | goto out; | 307 | goto out; |
416 | } | 308 | } |
417 | 309 | ||
418 | if (cl->read_cb && cl->read_cb->information > *offset) { | 310 | if (cl->read_cb && cl->read_cb->buf_idx > *offset) { |
419 | cb = cl->read_cb; | 311 | cb = cl->read_cb; |
420 | goto copy_buffer; | 312 | goto copy_buffer; |
421 | } else if (cl->read_cb && cl->read_cb->information > 0 && | 313 | } else if (cl->read_cb && cl->read_cb->buf_idx > 0 && |
422 | cl->read_cb->information <= *offset) { | 314 | cl->read_cb->buf_idx <= *offset) { |
423 | cb = cl->read_cb; | 315 | cb = cl->read_cb; |
424 | rets = 0; | 316 | rets = 0; |
425 | goto free; | 317 | goto free; |
426 | } else if ((!cl->read_cb || !cl->read_cb->information) && | 318 | } else if ((!cl->read_cb || !cl->read_cb->buf_idx) && *offset > 0) { |
427 | *offset > 0) { | ||
428 | /*Offset needs to be cleaned for contiguous reads*/ | 319 | /*Offset needs to be cleaned for contiguous reads*/ |
429 | *offset = 0; | 320 | *offset = 0; |
430 | rets = 0; | 321 | rets = 0; |
@@ -481,16 +372,15 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
481 | copy_buffer: | 372 | copy_buffer: |
482 | dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n", | 373 | dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n", |
483 | cb->response_buffer.size); | 374 | cb->response_buffer.size); |
484 | dev_dbg(&dev->pdev->dev, "cb->information - %lu\n", | 375 | dev_dbg(&dev->pdev->dev, "cb->buf_idx - %lu\n", cb->buf_idx); |
485 | cb->information); | 376 | if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { |
486 | if (length == 0 || ubuf == NULL || *offset > cb->information) { | ||
487 | rets = -EMSGSIZE; | 377 | rets = -EMSGSIZE; |
488 | goto free; | 378 | goto free; |
489 | } | 379 | } |
490 | 380 | ||
491 | /* length is being truncated to PAGE_SIZE, however, */ | 381 | /* length is being truncated to PAGE_SIZE, |
492 | /* information size may be longer */ | 382 | * however buf_idx may point beyond that */ |
493 | length = min_t(size_t, length, (cb->information - *offset)); | 383 | length = min_t(size_t, length, cb->buf_idx - *offset); |
494 | 384 | ||
495 | if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) { | 385 | if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) { |
496 | rets = -EFAULT; | 386 | rets = -EFAULT; |
@@ -499,15 +389,15 @@ copy_buffer: | |||
499 | 389 | ||
500 | rets = length; | 390 | rets = length; |
501 | *offset += length; | 391 | *offset += length; |
502 | if ((unsigned long)*offset < cb->information) | 392 | if ((unsigned long)*offset < cb->buf_idx) |
503 | goto out; | 393 | goto out; |
504 | 394 | ||
505 | free: | 395 | free: |
506 | cb_pos = find_read_list_entry(dev, cl); | 396 | cb_pos = find_read_list_entry(dev, cl); |
507 | /* Remove entry from read list */ | 397 | /* Remove entry from read list */ |
508 | if (cb_pos) | 398 | if (cb_pos) |
509 | list_del(&cb_pos->cb_list); | 399 | list_del(&cb_pos->list); |
510 | mei_free_cb_private(cb); | 400 | mei_io_cb_free(cb); |
511 | cl->reading_state = MEI_IDLE; | 401 | cl->reading_state = MEI_IDLE; |
512 | cl->read_cb = NULL; | 402 | cl->read_cb = NULL; |
513 | cl->read_pending = 0; | 403 | cl->read_pending = 0; |
@@ -516,7 +406,6 @@ out: | |||
516 | mutex_unlock(&dev->device_lock); | 406 | mutex_unlock(&dev->device_lock); |
517 | return rets; | 407 | return rets; |
518 | } | 408 | } |
519 | |||
520 | /** | 409 | /** |
521 | * mei_write - the write function. | 410 | * mei_write - the write function. |
522 | * | 411 | * |
@@ -546,23 +435,39 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
546 | mutex_lock(&dev->device_lock); | 435 | mutex_lock(&dev->device_lock); |
547 | 436 | ||
548 | if (dev->dev_state != MEI_DEV_ENABLED) { | 437 | if (dev->dev_state != MEI_DEV_ENABLED) { |
549 | mutex_unlock(&dev->device_lock); | 438 | rets = -ENODEV; |
550 | return -ENODEV; | 439 | goto err; |
551 | } | 440 | } |
552 | 441 | ||
442 | i = mei_me_cl_by_id(dev, cl->me_client_id); | ||
443 | if (i < 0) { | ||
444 | rets = -ENODEV; | ||
445 | goto err; | ||
446 | } | ||
447 | if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { | ||
448 | rets = -EMSGSIZE; | ||
449 | goto err; | ||
450 | } | ||
451 | |||
452 | if (cl->state != MEI_FILE_CONNECTED) { | ||
453 | rets = -ENODEV; | ||
454 | dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", | ||
455 | cl->host_client_id, cl->me_client_id); | ||
456 | goto err; | ||
457 | } | ||
553 | if (cl == &dev->iamthif_cl) { | 458 | if (cl == &dev->iamthif_cl) { |
554 | write_cb = find_amthi_read_list_entry(dev, file); | 459 | write_cb = mei_amthif_find_read_list_entry(dev, file); |
555 | 460 | ||
556 | if (write_cb) { | 461 | if (write_cb) { |
557 | timeout = write_cb->read_time + | 462 | timeout = write_cb->read_time + |
558 | msecs_to_jiffies(IAMTHIF_READ_TIMER); | 463 | mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); |
559 | 464 | ||
560 | if (time_after(jiffies, timeout) || | 465 | if (time_after(jiffies, timeout) || |
561 | cl->reading_state == MEI_READ_COMPLETE) { | 466 | cl->reading_state == MEI_READ_COMPLETE) { |
562 | *offset = 0; | 467 | *offset = 0; |
563 | list_del(&write_cb->cb_list); | 468 | list_del(&write_cb->list); |
564 | mei_free_cb_private(write_cb); | 469 | mei_io_cb_free(write_cb); |
565 | write_cb = NULL; | 470 | write_cb = NULL; |
566 | } | 471 | } |
567 | } | 472 | } |
568 | } | 473 | } |
@@ -572,8 +477,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
572 | *offset = 0; | 477 | *offset = 0; |
573 | write_cb = find_read_list_entry(dev, cl); | 478 | write_cb = find_read_list_entry(dev, cl); |
574 | if (write_cb) { | 479 | if (write_cb) { |
575 | list_del(&write_cb->cb_list); | 480 | list_del(&write_cb->list); |
576 | mei_free_cb_private(write_cb); | 481 | mei_io_cb_free(write_cb); |
577 | write_cb = NULL; | 482 | write_cb = NULL; |
578 | cl->reading_state = MEI_IDLE; | 483 | cl->reading_state = MEI_IDLE; |
579 | cl->read_cb = NULL; | 484 | cl->read_cb = NULL; |
@@ -583,24 +488,21 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
583 | *offset = 0; | 488 | *offset = 0; |
584 | 489 | ||
585 | 490 | ||
586 | write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); | 491 | write_cb = mei_io_cb_init(cl, file); |
587 | if (!write_cb) { | 492 | if (!write_cb) { |
588 | mutex_unlock(&dev->device_lock); | 493 | dev_err(&dev->pdev->dev, "write cb allocation failed\n"); |
589 | return -ENOMEM; | 494 | rets = -ENOMEM; |
495 | goto err; | ||
590 | } | 496 | } |
497 | rets = mei_io_cb_alloc_req_buf(write_cb, length); | ||
498 | if (rets) | ||
499 | goto err; | ||
591 | 500 | ||
592 | write_cb->file_object = file; | 501 | dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length); |
593 | write_cb->file_private = cl; | ||
594 | write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL); | ||
595 | rets = -ENOMEM; | ||
596 | if (!write_cb->request_buffer.data) | ||
597 | goto unlock_dev; | ||
598 | |||
599 | dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length); | ||
600 | 502 | ||
601 | rets = -EFAULT; | 503 | rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); |
602 | if (copy_from_user(write_cb->request_buffer.data, ubuf, length)) | 504 | if (rets) |
603 | goto unlock_dev; | 505 | goto err; |
604 | 506 | ||
605 | cl->sm_state = 0; | 507 | cl->sm_state = 0; |
606 | if (length == 4 && | 508 | if (length == 4 && |
@@ -612,139 +514,71 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
612 | write_cb->request_buffer.data, 4) == 0))) | 514 | write_cb->request_buffer.data, 4) == 0))) |
613 | cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT; | 515 | cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT; |
614 | 516 | ||
615 | INIT_LIST_HEAD(&write_cb->cb_list); | ||
616 | if (cl == &dev->iamthif_cl) { | 517 | if (cl == &dev->iamthif_cl) { |
617 | write_cb->response_buffer.data = | 518 | rets = mei_amthif_write(dev, write_cb); |
618 | kmalloc(dev->iamthif_mtu, GFP_KERNEL); | ||
619 | if (!write_cb->response_buffer.data) { | ||
620 | rets = -ENOMEM; | ||
621 | goto unlock_dev; | ||
622 | } | ||
623 | if (dev->dev_state != MEI_DEV_ENABLED) { | ||
624 | rets = -ENODEV; | ||
625 | goto unlock_dev; | ||
626 | } | ||
627 | i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); | ||
628 | if (i < 0) { | ||
629 | rets = -ENODEV; | ||
630 | goto unlock_dev; | ||
631 | } | ||
632 | if (length > dev->me_clients[i].props.max_msg_length || | ||
633 | length <= 0) { | ||
634 | rets = -EMSGSIZE; | ||
635 | goto unlock_dev; | ||
636 | } | ||
637 | 519 | ||
638 | write_cb->response_buffer.size = dev->iamthif_mtu; | 520 | if (rets) { |
639 | write_cb->major_file_operations = MEI_IOCTL; | 521 | dev_err(&dev->pdev->dev, |
640 | write_cb->information = 0; | 522 | "amthi write failed with status = %d\n", rets); |
641 | write_cb->request_buffer.size = length; | 523 | goto err; |
642 | if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { | ||
643 | rets = -ENODEV; | ||
644 | goto unlock_dev; | ||
645 | } | ||
646 | |||
647 | if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) || | ||
648 | dev->iamthif_state != MEI_IAMTHIF_IDLE) { | ||
649 | dev_dbg(&dev->pdev->dev, "amthi_state = %d\n", | ||
650 | (int) dev->iamthif_state); | ||
651 | dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n"); | ||
652 | list_add_tail(&write_cb->cb_list, | ||
653 | &dev->amthi_cmd_list.mei_cb.cb_list); | ||
654 | rets = length; | ||
655 | } else { | ||
656 | dev_dbg(&dev->pdev->dev, "call amthi write\n"); | ||
657 | rets = amthi_write(dev, write_cb); | ||
658 | |||
659 | if (rets) { | ||
660 | dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n", | ||
661 | rets); | ||
662 | goto unlock_dev; | ||
663 | } | ||
664 | rets = length; | ||
665 | } | 524 | } |
666 | mutex_unlock(&dev->device_lock); | 525 | mutex_unlock(&dev->device_lock); |
667 | return rets; | 526 | return length; |
668 | } | 527 | } |
669 | 528 | ||
670 | write_cb->major_file_operations = MEI_WRITE; | 529 | write_cb->fop_type = MEI_FOP_WRITE; |
671 | /* make sure information is zero before we start */ | ||
672 | |||
673 | write_cb->information = 0; | ||
674 | write_cb->request_buffer.size = length; | ||
675 | 530 | ||
676 | dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", | 531 | dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", |
677 | cl->host_client_id, cl->me_client_id); | 532 | cl->host_client_id, cl->me_client_id); |
678 | if (cl->state != MEI_FILE_CONNECTED) { | ||
679 | rets = -ENODEV; | ||
680 | dev_dbg(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", | ||
681 | cl->host_client_id, | ||
682 | cl->me_client_id); | ||
683 | goto unlock_dev; | ||
684 | } | ||
685 | i = mei_me_cl_by_id(dev, cl->me_client_id); | ||
686 | if (i < 0) { | ||
687 | rets = -ENODEV; | ||
688 | goto unlock_dev; | ||
689 | } | ||
690 | if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { | ||
691 | rets = -EINVAL; | ||
692 | goto unlock_dev; | ||
693 | } | ||
694 | write_cb->file_private = cl; | ||
695 | |||
696 | rets = mei_flow_ctrl_creds(dev, cl); | 533 | rets = mei_flow_ctrl_creds(dev, cl); |
697 | if (rets < 0) | 534 | if (rets < 0) |
698 | goto unlock_dev; | 535 | goto err; |
699 | 536 | ||
700 | if (rets && dev->mei_host_buffer_is_empty) { | 537 | if (rets == 0 || dev->mei_host_buffer_is_empty == false) { |
701 | rets = 0; | 538 | write_cb->buf_idx = 0; |
702 | dev->mei_host_buffer_is_empty = false; | 539 | mei_hdr.msg_complete = 0; |
703 | if (length > mei_hbuf_max_data(dev)) { | ||
704 | mei_hdr.length = mei_hbuf_max_data(dev); | ||
705 | mei_hdr.msg_complete = 0; | ||
706 | } else { | ||
707 | mei_hdr.length = length; | ||
708 | mei_hdr.msg_complete = 1; | ||
709 | } | ||
710 | mei_hdr.host_addr = cl->host_client_id; | ||
711 | mei_hdr.me_addr = cl->me_client_id; | ||
712 | mei_hdr.reserved = 0; | ||
713 | dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", | ||
714 | *((u32 *) &mei_hdr)); | ||
715 | if (mei_write_message(dev, &mei_hdr, | ||
716 | (unsigned char *) (write_cb->request_buffer.data), | ||
717 | mei_hdr.length)) { | ||
718 | rets = -ENODEV; | ||
719 | goto unlock_dev; | ||
720 | } | ||
721 | cl->writing_state = MEI_WRITING; | 540 | cl->writing_state = MEI_WRITING; |
722 | write_cb->information = mei_hdr.length; | 541 | goto out; |
723 | if (mei_hdr.msg_complete) { | 542 | } |
724 | if (mei_flow_ctrl_reduce(dev, cl)) { | ||
725 | rets = -ENODEV; | ||
726 | goto unlock_dev; | ||
727 | } | ||
728 | list_add_tail(&write_cb->cb_list, | ||
729 | &dev->write_waiting_list.mei_cb.cb_list); | ||
730 | } else { | ||
731 | list_add_tail(&write_cb->cb_list, | ||
732 | &dev->write_list.mei_cb.cb_list); | ||
733 | } | ||
734 | 543 | ||
544 | dev->mei_host_buffer_is_empty = false; | ||
545 | if (length > mei_hbuf_max_data(dev)) { | ||
546 | mei_hdr.length = mei_hbuf_max_data(dev); | ||
547 | mei_hdr.msg_complete = 0; | ||
735 | } else { | 548 | } else { |
549 | mei_hdr.length = length; | ||
550 | mei_hdr.msg_complete = 1; | ||
551 | } | ||
552 | mei_hdr.host_addr = cl->host_client_id; | ||
553 | mei_hdr.me_addr = cl->me_client_id; | ||
554 | mei_hdr.reserved = 0; | ||
555 | dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", | ||
556 | *((u32 *) &mei_hdr)); | ||
557 | if (mei_write_message(dev, &mei_hdr, | ||
558 | write_cb->request_buffer.data, mei_hdr.length)) { | ||
559 | rets = -ENODEV; | ||
560 | goto err; | ||
561 | } | ||
562 | cl->writing_state = MEI_WRITING; | ||
563 | write_cb->buf_idx = mei_hdr.length; | ||
736 | 564 | ||
737 | write_cb->information = 0; | 565 | out: |
738 | cl->writing_state = MEI_WRITING; | 566 | if (mei_hdr.msg_complete) { |
739 | list_add_tail(&write_cb->cb_list, | 567 | if (mei_flow_ctrl_reduce(dev, cl)) { |
740 | &dev->write_list.mei_cb.cb_list); | 568 | rets = -ENODEV; |
569 | goto err; | ||
570 | } | ||
571 | list_add_tail(&write_cb->list, &dev->write_waiting_list.list); | ||
572 | } else { | ||
573 | list_add_tail(&write_cb->list, &dev->write_list.list); | ||
741 | } | 574 | } |
575 | |||
742 | mutex_unlock(&dev->device_lock); | 576 | mutex_unlock(&dev->device_lock); |
743 | return length; | 577 | return length; |
744 | 578 | ||
745 | unlock_dev: | 579 | err: |
746 | mutex_unlock(&dev->device_lock); | 580 | mutex_unlock(&dev->device_lock); |
747 | mei_free_cb_private(write_cb); | 581 | mei_io_cb_free(write_cb); |
748 | return rets; | 582 | return rets; |
749 | } | 583 | } |
750 | 584 | ||
@@ -860,15 +694,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) | |||
860 | 694 | ||
861 | 695 | ||
862 | if (cl == &dev->iamthif_cl) { | 696 | if (cl == &dev->iamthif_cl) { |
863 | mutex_unlock(&dev->device_lock); | 697 | mask = mei_amthif_poll(dev, file, wait); |
864 | poll_wait(file, &dev->iamthif_cl.wait, wait); | ||
865 | mutex_lock(&dev->device_lock); | ||
866 | if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && | ||
867 | dev->iamthif_file_object == file) { | ||
868 | mask |= (POLLIN | POLLRDNORM); | ||
869 | dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); | ||
870 | mei_run_next_iamthif_cmd(dev); | ||
871 | } | ||
872 | goto out; | 698 | goto out; |
873 | } | 699 | } |
874 | 700 | ||
@@ -917,7 +743,7 @@ static struct miscdevice mei_misc_device = { | |||
917 | * | 743 | * |
918 | * returns true if ME Interface is valid, false otherwise | 744 | * returns true if ME Interface is valid, false otherwise |
919 | */ | 745 | */ |
920 | static bool __devinit mei_quirk_probe(struct pci_dev *pdev, | 746 | static bool mei_quirk_probe(struct pci_dev *pdev, |
921 | const struct pci_device_id *ent) | 747 | const struct pci_device_id *ent) |
922 | { | 748 | { |
923 | u32 reg; | 749 | u32 reg; |
@@ -939,7 +765,7 @@ static bool __devinit mei_quirk_probe(struct pci_dev *pdev, | |||
939 | * | 765 | * |
940 | * returns 0 on success, <0 on failure. | 766 | * returns 0 on success, <0 on failure. |
941 | */ | 767 | */ |
942 | static int __devinit mei_probe(struct pci_dev *pdev, | 768 | static int mei_probe(struct pci_dev *pdev, |
943 | const struct pci_device_id *ent) | 769 | const struct pci_device_id *ent) |
944 | { | 770 | { |
945 | struct mei_device *dev; | 771 | struct mei_device *dev; |
@@ -1003,6 +829,8 @@ static int __devinit mei_probe(struct pci_dev *pdev, | |||
1003 | goto disable_msi; | 829 | goto disable_msi; |
1004 | } | 830 | } |
1005 | INIT_DELAYED_WORK(&dev->timer_work, mei_timer); | 831 | INIT_DELAYED_WORK(&dev->timer_work, mei_timer); |
832 | INIT_WORK(&dev->init_work, mei_host_client_init); | ||
833 | |||
1006 | if (mei_hw_init(dev)) { | 834 | if (mei_hw_init(dev)) { |
1007 | dev_err(&pdev->dev, "init hw failure.\n"); | 835 | dev_err(&pdev->dev, "init hw failure.\n"); |
1008 | err = -ENODEV; | 836 | err = -ENODEV; |
@@ -1054,7 +882,7 @@ end: | |||
1054 | * mei_remove is called by the PCI subsystem to alert the driver | 882 | * mei_remove is called by the PCI subsystem to alert the driver |
1055 | * that it should release a PCI device. | 883 | * that it should release a PCI device. |
1056 | */ | 884 | */ |
1057 | static void __devexit mei_remove(struct pci_dev *pdev) | 885 | static void mei_remove(struct pci_dev *pdev) |
1058 | { | 886 | { |
1059 | struct mei_device *dev; | 887 | struct mei_device *dev; |
1060 | 888 | ||
@@ -1087,8 +915,8 @@ static void __devexit mei_remove(struct pci_dev *pdev) | |||
1087 | 915 | ||
1088 | /* remove entry if already in list */ | 916 | /* remove entry if already in list */ |
1089 | dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); | 917 | dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); |
1090 | mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id); | 918 | mei_me_cl_unlink(dev, &dev->wd_cl); |
1091 | mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id); | 919 | mei_me_cl_unlink(dev, &dev->iamthif_cl); |
1092 | 920 | ||
1093 | dev->iamthif_current_cb = NULL; | 921 | dev->iamthif_current_cb = NULL; |
1094 | dev->me_clients_num = 0; | 922 | dev->me_clients_num = 0; |
@@ -1195,8 +1023,8 @@ static struct pci_driver mei_driver = { | |||
1195 | .name = KBUILD_MODNAME, | 1023 | .name = KBUILD_MODNAME, |
1196 | .id_table = mei_pci_tbl, | 1024 | .id_table = mei_pci_tbl, |
1197 | .probe = mei_probe, | 1025 | .probe = mei_probe, |
1198 | .remove = __devexit_p(mei_remove), | 1026 | .remove = mei_remove, |
1199 | .shutdown = __devexit_p(mei_remove), | 1027 | .shutdown = mei_remove, |
1200 | .driver.pm = MEI_PM_OPS, | 1028 | .driver.pm = MEI_PM_OPS, |
1201 | }; | 1029 | }; |
1202 | 1030 | ||
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index adb35fb9281..25da04549d0 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/watchdog.h> | 21 | #include <linux/watchdog.h> |
22 | #include <linux/poll.h> | ||
22 | #include <linux/mei.h> | 23 | #include <linux/mei.h> |
23 | #include "hw.h" | 24 | #include "hw.h" |
24 | 25 | ||
@@ -125,13 +126,20 @@ enum mei_wd_states { | |||
125 | MEI_WD_STOPPING, | 126 | MEI_WD_STOPPING, |
126 | }; | 127 | }; |
127 | 128 | ||
128 | /* MEI CB */ | 129 | /** |
129 | enum mei_cb_major_types { | 130 | * enum mei_cb_file_ops - file operation associated with the callback |
130 | MEI_READ = 0, | 131 | * @MEI_FOP_READ - read |
131 | MEI_WRITE, | 132 | * @MEI_FOP_WRITE - write |
132 | MEI_IOCTL, | 133 | * @MEI_FOP_IOCTL - ioctl |
133 | MEI_OPEN, | 134 | * @MEI_FOP_OPEN - open |
134 | MEI_CLOSE | 135 | * @MEI_FOP_CLOSE - close |
136 | */ | ||
137 | enum mei_cb_file_ops { | ||
138 | MEI_FOP_READ = 0, | ||
139 | MEI_FOP_WRITE, | ||
140 | MEI_FOP_IOCTL, | ||
141 | MEI_FOP_OPEN, | ||
142 | MEI_FOP_CLOSE | ||
135 | }; | 143 | }; |
136 | 144 | ||
137 | /* | 145 | /* |
@@ -143,13 +151,21 @@ struct mei_message_data { | |||
143 | }; | 151 | }; |
144 | 152 | ||
145 | 153 | ||
154 | struct mei_cl; | ||
155 | |||
156 | /** | ||
157 | * struct mei_cl_cb - file operation callback structure | ||
158 | * | ||
159 | * @cl - file client who is running this operation | ||
160 | * @fop_type - file operation type | ||
161 | */ | ||
146 | struct mei_cl_cb { | 162 | struct mei_cl_cb { |
147 | struct list_head cb_list; | 163 | struct list_head list; |
148 | enum mei_cb_major_types major_file_operations; | 164 | struct mei_cl *cl; |
149 | void *file_private; | 165 | enum mei_cb_file_ops fop_type; |
150 | struct mei_message_data request_buffer; | 166 | struct mei_message_data request_buffer; |
151 | struct mei_message_data response_buffer; | 167 | struct mei_message_data response_buffer; |
152 | unsigned long information; | 168 | unsigned long buf_idx; |
153 | unsigned long read_time; | 169 | unsigned long read_time; |
154 | struct file *file_object; | 170 | struct file *file_object; |
155 | }; | 171 | }; |
@@ -175,29 +191,23 @@ struct mei_cl { | |||
175 | struct mei_cl_cb *read_cb; | 191 | struct mei_cl_cb *read_cb; |
176 | }; | 192 | }; |
177 | 193 | ||
178 | struct mei_io_list { | ||
179 | struct mei_cl_cb mei_cb; | ||
180 | }; | ||
181 | |||
182 | /** | 194 | /** |
183 | * struct mei_deive - MEI private device struct | 195 | * struct mei_device - MEI private device struct |
184 | * @hbuf_depth - depth of host(write) buffer | 196 | * @hbuf_depth - depth of host(write) buffer |
197 | * @wr_ext_msg - buffer for hbm control responses (set in read cycle) | ||
185 | */ | 198 | */ |
186 | struct mei_device { | 199 | struct mei_device { |
187 | struct pci_dev *pdev; /* pointer to pci device struct */ | 200 | struct pci_dev *pdev; /* pointer to pci device struct */ |
188 | /* | 201 | /* |
189 | * lists of queues | 202 | * lists of queues |
190 | */ | 203 | */ |
191 | /* array of pointers to aio lists */ | 204 | /* array of pointers to aio lists */ |
192 | struct mei_io_list read_list; /* driver read queue */ | 205 | struct mei_cl_cb read_list; /* driver read queue */ |
193 | struct mei_io_list write_list; /* driver write queue */ | 206 | struct mei_cl_cb write_list; /* driver write queue */ |
194 | struct mei_io_list write_waiting_list; /* write waiting queue */ | 207 | struct mei_cl_cb write_waiting_list; /* write waiting queue */ |
195 | struct mei_io_list ctrl_wr_list; /* managed write IOCTL list */ | 208 | struct mei_cl_cb ctrl_wr_list; /* managed write IOCTL list */ |
196 | struct mei_io_list ctrl_rd_list; /* managed read IOCTL list */ | 209 | struct mei_cl_cb ctrl_rd_list; /* managed read IOCTL list */ |
197 | struct mei_io_list amthi_cmd_list; /* amthi list for cmd waiting */ | 210 | |
198 | |||
199 | /* driver managed amthi list for reading completed amthi cmd data */ | ||
200 | struct mei_io_list amthi_read_complete_list; | ||
201 | /* | 211 | /* |
202 | * list of files | 212 | * list of files |
203 | */ | 213 | */ |
@@ -235,11 +245,13 @@ struct mei_device { | |||
235 | u16 init_clients_timer; | 245 | u16 init_clients_timer; |
236 | bool need_reset; | 246 | bool need_reset; |
237 | 247 | ||
238 | u32 extra_write_index; | ||
239 | unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ | 248 | unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ |
240 | u32 wr_msg_buf[128]; /* used for control messages */ | ||
241 | u32 ext_msg_buf[8]; /* for control responses */ | ||
242 | u32 rd_msg_hdr; | 249 | u32 rd_msg_hdr; |
250 | u32 wr_msg_buf[128]; /* used for control messages */ | ||
251 | struct { | ||
252 | struct mei_msg_hdr hdr; | ||
253 | unsigned char data[4]; /* All HBM messages are 4 bytes */ | ||
254 | } wr_ext_msg; /* for control responses */ | ||
243 | 255 | ||
244 | struct hbm_version version; | 256 | struct hbm_version version; |
245 | 257 | ||
@@ -253,12 +265,15 @@ struct mei_device { | |||
253 | 265 | ||
254 | struct mei_cl wd_cl; | 266 | struct mei_cl wd_cl; |
255 | enum mei_wd_states wd_state; | 267 | enum mei_wd_states wd_state; |
256 | bool wd_interface_reg; | ||
257 | bool wd_pending; | 268 | bool wd_pending; |
258 | u16 wd_timeout; | 269 | u16 wd_timeout; |
259 | unsigned char wd_data[MEI_WD_START_MSG_SIZE]; | 270 | unsigned char wd_data[MEI_WD_START_MSG_SIZE]; |
260 | 271 | ||
261 | 272 | ||
273 | /* amthif list for cmd waiting */ | ||
274 | struct mei_cl_cb amthif_cmd_list; | ||
275 | /* driver managed amthif list for reading completed amthif cmd data */ | ||
276 | struct mei_cl_cb amthif_rd_complete_list; | ||
262 | struct file *iamthif_file_object; | 277 | struct file *iamthif_file_object; |
263 | struct mei_cl iamthif_cl; | 278 | struct mei_cl iamthif_cl; |
264 | struct mei_cl_cb *iamthif_current_cb; | 279 | struct mei_cl_cb *iamthif_current_cb; |
@@ -272,8 +287,15 @@ struct mei_device { | |||
272 | bool iamthif_flow_control_pending; | 287 | bool iamthif_flow_control_pending; |
273 | bool iamthif_ioctl; | 288 | bool iamthif_ioctl; |
274 | bool iamthif_canceled; | 289 | bool iamthif_canceled; |
290 | |||
291 | struct work_struct init_work; | ||
275 | }; | 292 | }; |
276 | 293 | ||
294 | static inline unsigned long mei_secs_to_jiffies(unsigned long sec) | ||
295 | { | ||
296 | return msecs_to_jiffies(sec * MSEC_PER_SEC); | ||
297 | } | ||
298 | |||
277 | 299 | ||
278 | /* | 300 | /* |
279 | * mei init function prototypes | 301 | * mei init function prototypes |
@@ -284,21 +306,34 @@ int mei_hw_init(struct mei_device *dev); | |||
284 | int mei_task_initialize_clients(void *data); | 306 | int mei_task_initialize_clients(void *data); |
285 | int mei_initialize_clients(struct mei_device *dev); | 307 | int mei_initialize_clients(struct mei_device *dev); |
286 | int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl); | 308 | int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl); |
287 | void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id); | ||
288 | void mei_host_init_iamthif(struct mei_device *dev); | ||
289 | void mei_allocate_me_clients_storage(struct mei_device *dev); | 309 | void mei_allocate_me_clients_storage(struct mei_device *dev); |
290 | 310 | ||
291 | 311 | ||
292 | int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, | 312 | int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, |
293 | const uuid_le *cguid, u8 host_client_id); | 313 | const uuid_le *cguid, u8 host_client_id); |
314 | void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl); | ||
294 | int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid); | 315 | int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid); |
295 | int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); | 316 | int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); |
296 | 317 | ||
297 | /* | 318 | /* |
298 | * MEI IO List Functions | 319 | * MEI IO Functions |
320 | */ | ||
321 | struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp); | ||
322 | void mei_io_cb_free(struct mei_cl_cb *priv_cb); | ||
323 | int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length); | ||
324 | int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length); | ||
325 | |||
326 | |||
327 | /** | ||
328 | * mei_io_list_init - Sets up a queue list. | ||
329 | * | ||
330 | * @list: An instance cl callback structure | ||
299 | */ | 331 | */ |
300 | void mei_io_list_init(struct mei_io_list *list); | 332 | static inline void mei_io_list_init(struct mei_cl_cb *list) |
301 | void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl); | 333 | { |
334 | INIT_LIST_HEAD(&list->list); | ||
335 | } | ||
336 | void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl); | ||
302 | 337 | ||
303 | /* | 338 | /* |
304 | * MEI ME Client Functions | 339 | * MEI ME Client Functions |
@@ -330,7 +365,8 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1, | |||
330 | */ | 365 | */ |
331 | void mei_host_start_message(struct mei_device *dev); | 366 | void mei_host_start_message(struct mei_device *dev); |
332 | void mei_host_enum_clients_message(struct mei_device *dev); | 367 | void mei_host_enum_clients_message(struct mei_device *dev); |
333 | int mei_host_client_properties(struct mei_device *dev); | 368 | int mei_host_client_enumerate(struct mei_device *dev); |
369 | void mei_host_client_init(struct work_struct *work); | ||
334 | 370 | ||
335 | /* | 371 | /* |
336 | * MEI interrupt functions prototype | 372 | * MEI interrupt functions prototype |
@@ -347,18 +383,40 @@ int mei_ioctl_connect_client(struct file *file, | |||
347 | 383 | ||
348 | int mei_start_read(struct mei_device *dev, struct mei_cl *cl); | 384 | int mei_start_read(struct mei_device *dev, struct mei_cl *cl); |
349 | 385 | ||
350 | int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); | ||
351 | 386 | ||
352 | int amthi_read(struct mei_device *dev, struct file *file, | 387 | /* |
353 | char __user *ubuf, size_t length, loff_t *offset); | 388 | * AMTHIF - AMT Host Interface Functions |
389 | */ | ||
390 | void mei_amthif_reset_params(struct mei_device *dev); | ||
391 | |||
392 | void mei_amthif_host_init(struct mei_device *dev); | ||
393 | |||
394 | int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); | ||
354 | 395 | ||
355 | struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev, | 396 | int mei_amthif_read(struct mei_device *dev, struct file *file, |
397 | char __user *ubuf, size_t length, loff_t *offset); | ||
398 | |||
399 | unsigned int mei_amthif_poll(struct mei_device *dev, | ||
400 | struct file *file, poll_table *wait); | ||
401 | |||
402 | int mei_amthif_release(struct mei_device *dev, struct file *file); | ||
403 | |||
404 | struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, | ||
356 | struct file *file); | 405 | struct file *file); |
357 | 406 | ||
358 | void mei_run_next_iamthif_cmd(struct mei_device *dev); | 407 | void mei_amthif_run_next_cmd(struct mei_device *dev); |
408 | |||
359 | 409 | ||
360 | void mei_free_cb_private(struct mei_cl_cb *priv_cb); | 410 | int mei_amthif_read_message(struct mei_cl_cb *complete_list, |
411 | struct mei_device *dev, struct mei_msg_hdr *mei_hdr); | ||
361 | 412 | ||
413 | int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, | ||
414 | struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); | ||
415 | |||
416 | void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb); | ||
417 | int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, | ||
418 | struct mei_device *dev, struct mei_msg_hdr *mei_hdr); | ||
419 | int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); | ||
362 | 420 | ||
363 | /* | 421 | /* |
364 | * Register Access Function | 422 | * Register Access Function |
@@ -437,4 +495,15 @@ void mei_csr_clear_his(struct mei_device *dev); | |||
437 | void mei_enable_interrupts(struct mei_device *dev); | 495 | void mei_enable_interrupts(struct mei_device *dev); |
438 | void mei_disable_interrupts(struct mei_device *dev); | 496 | void mei_disable_interrupts(struct mei_device *dev); |
439 | 497 | ||
498 | static inline struct mei_msg_hdr *mei_hbm_hdr(u32 *buf, size_t length) | ||
499 | { | ||
500 | struct mei_msg_hdr *hdr = (struct mei_msg_hdr *)buf; | ||
501 | hdr->host_addr = 0; | ||
502 | hdr->me_addr = 0; | ||
503 | hdr->length = length; | ||
504 | hdr->msg_complete = 1; | ||
505 | hdr->reserved = 0; | ||
506 | return hdr; | ||
507 | } | ||
508 | |||
440 | #endif | 509 | #endif |
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index d96c537f046..636409f9667 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c | |||
@@ -62,6 +62,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout) | |||
62 | */ | 62 | */ |
63 | int mei_wd_host_init(struct mei_device *dev) | 63 | int mei_wd_host_init(struct mei_device *dev) |
64 | { | 64 | { |
65 | int id; | ||
65 | mei_cl_init(&dev->wd_cl, dev); | 66 | mei_cl_init(&dev->wd_cl, dev); |
66 | 67 | ||
67 | /* look for WD client and connect to it */ | 68 | /* look for WD client and connect to it */ |
@@ -69,12 +70,11 @@ int mei_wd_host_init(struct mei_device *dev) | |||
69 | dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT; | 70 | dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT; |
70 | dev->wd_state = MEI_WD_IDLE; | 71 | dev->wd_state = MEI_WD_IDLE; |
71 | 72 | ||
72 | /* find ME WD client */ | 73 | /* Connect WD ME client to the host client */ |
73 | mei_me_cl_update_filext(dev, &dev->wd_cl, | 74 | id = mei_me_cl_link(dev, &dev->wd_cl, |
74 | &mei_wd_guid, MEI_WD_HOST_CLIENT_ID); | 75 | &mei_wd_guid, MEI_WD_HOST_CLIENT_ID); |
75 | 76 | ||
76 | dev_dbg(&dev->pdev->dev, "wd: check client\n"); | 77 | if (id < 0) { |
77 | if (MEI_FILE_CONNECTING != dev->wd_cl.state) { | ||
78 | dev_info(&dev->pdev->dev, "wd: failed to find the client\n"); | 78 | dev_info(&dev->pdev->dev, "wd: failed to find the client\n"); |
79 | return -ENOENT; | 79 | return -ENOENT; |
80 | } | 80 | } |
@@ -85,7 +85,7 @@ int mei_wd_host_init(struct mei_device *dev) | |||
85 | dev->wd_cl.host_client_id = 0; | 85 | dev->wd_cl.host_client_id = 0; |
86 | return -EIO; | 86 | return -EIO; |
87 | } | 87 | } |
88 | dev->wd_cl.timer_count = CONNECT_TIMEOUT; | 88 | dev->wd_cl.timer_count = MEI_CONNECT_TIMEOUT; |
89 | 89 | ||
90 | return 0; | 90 | return 0; |
91 | } | 91 | } |
@@ -360,23 +360,20 @@ void mei_watchdog_register(struct mei_device *dev) | |||
360 | if (watchdog_register_device(&amt_wd_dev)) { | 360 | if (watchdog_register_device(&amt_wd_dev)) { |
361 | dev_err(&dev->pdev->dev, | 361 | dev_err(&dev->pdev->dev, |
362 | "wd: unable to register watchdog device.\n"); | 362 | "wd: unable to register watchdog device.\n"); |
363 | dev->wd_interface_reg = false; | ||
364 | return; | 363 | return; |
365 | } | 364 | } |
366 | 365 | ||
367 | dev_dbg(&dev->pdev->dev, | 366 | dev_dbg(&dev->pdev->dev, |
368 | "wd: successfully register watchdog interface.\n"); | 367 | "wd: successfully register watchdog interface.\n"); |
369 | dev->wd_interface_reg = true; | ||
370 | watchdog_set_drvdata(&amt_wd_dev, dev); | 368 | watchdog_set_drvdata(&amt_wd_dev, dev); |
371 | } | 369 | } |
372 | 370 | ||
373 | void mei_watchdog_unregister(struct mei_device *dev) | 371 | void mei_watchdog_unregister(struct mei_device *dev) |
374 | { | 372 | { |
375 | if (!dev->wd_interface_reg) | 373 | if (test_bit(WDOG_UNREGISTERED, &amt_wd_dev.status)) |
376 | return; | 374 | return; |
377 | 375 | ||
378 | watchdog_set_drvdata(&amt_wd_dev, NULL); | 376 | watchdog_set_drvdata(&amt_wd_dev, NULL); |
379 | watchdog_unregister_device(&amt_wd_dev); | 377 | watchdog_unregister_device(&amt_wd_dev); |
380 | dev->wd_interface_reg = false; | ||
381 | } | 378 | } |
382 | 379 | ||
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index c9f20dae185..931e635aa49 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c | |||
@@ -666,7 +666,7 @@ static struct bin_attribute pch_bin_attr = { | |||
666 | .write = pch_phub_bin_write, | 666 | .write = pch_phub_bin_write, |
667 | }; | 667 | }; |
668 | 668 | ||
669 | static int __devinit pch_phub_probe(struct pci_dev *pdev, | 669 | static int pch_phub_probe(struct pci_dev *pdev, |
670 | const struct pci_device_id *id) | 670 | const struct pci_device_id *id) |
671 | { | 671 | { |
672 | int retval; | 672 | int retval; |
@@ -819,7 +819,7 @@ err_pci_enable_dev: | |||
819 | return ret; | 819 | return ret; |
820 | } | 820 | } |
821 | 821 | ||
822 | static void __devexit pch_phub_remove(struct pci_dev *pdev) | 822 | static void pch_phub_remove(struct pci_dev *pdev) |
823 | { | 823 | { |
824 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | 824 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); |
825 | 825 | ||
@@ -888,7 +888,7 @@ static struct pci_driver pch_phub_driver = { | |||
888 | .name = "pch_phub", | 888 | .name = "pch_phub", |
889 | .id_table = pch_phub_pcidev_id, | 889 | .id_table = pch_phub_pcidev_id, |
890 | .probe = pch_phub_probe, | 890 | .probe = pch_phub_probe, |
891 | .remove = __devexit_p(pch_phub_remove), | 891 | .remove = pch_phub_remove, |
892 | .suspend = pch_phub_suspend, | 892 | .suspend = pch_phub_suspend, |
893 | .resume = pch_phub_resume | 893 | .resume = pch_phub_resume |
894 | }; | 894 | }; |
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 21b28fc6d91..68b7c773d2c 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c | |||
@@ -324,7 +324,7 @@ static irqreturn_t phantom_isr(int irq, void *data) | |||
324 | * Init and deinit driver | 324 | * Init and deinit driver |
325 | */ | 325 | */ |
326 | 326 | ||
327 | static unsigned int __devinit phantom_get_free(void) | 327 | static unsigned int phantom_get_free(void) |
328 | { | 328 | { |
329 | unsigned int i; | 329 | unsigned int i; |
330 | 330 | ||
@@ -335,7 +335,7 @@ static unsigned int __devinit phantom_get_free(void) | |||
335 | return i; | 335 | return i; |
336 | } | 336 | } |
337 | 337 | ||
338 | static int __devinit phantom_probe(struct pci_dev *pdev, | 338 | static int phantom_probe(struct pci_dev *pdev, |
339 | const struct pci_device_id *pci_id) | 339 | const struct pci_device_id *pci_id) |
340 | { | 340 | { |
341 | struct phantom_device *pht; | 341 | struct phantom_device *pht; |
@@ -435,7 +435,7 @@ err: | |||
435 | return retval; | 435 | return retval; |
436 | } | 436 | } |
437 | 437 | ||
438 | static void __devexit phantom_remove(struct pci_dev *pdev) | 438 | static void phantom_remove(struct pci_dev *pdev) |
439 | { | 439 | { |
440 | struct phantom_device *pht = pci_get_drvdata(pdev); | 440 | struct phantom_device *pht = pci_get_drvdata(pdev); |
441 | unsigned int minor = MINOR(pht->cdev.dev); | 441 | unsigned int minor = MINOR(pht->cdev.dev); |
@@ -487,7 +487,7 @@ static int phantom_resume(struct pci_dev *pdev) | |||
487 | #define phantom_resume NULL | 487 | #define phantom_resume NULL |
488 | #endif | 488 | #endif |
489 | 489 | ||
490 | static struct pci_device_id phantom_pci_tbl[] __devinitdata = { | 490 | static struct pci_device_id phantom_pci_tbl[] = { |
491 | { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, | 491 | { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, |
492 | .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050, | 492 | .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050, |
493 | .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 }, | 493 | .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 }, |
@@ -499,7 +499,7 @@ static struct pci_driver phantom_pci_driver = { | |||
499 | .name = "phantom", | 499 | .name = "phantom", |
500 | .id_table = phantom_pci_tbl, | 500 | .id_table = phantom_pci_tbl, |
501 | .probe = phantom_probe, | 501 | .probe = phantom_probe, |
502 | .remove = __devexit_p(phantom_remove), | 502 | .remove = phantom_remove, |
503 | .suspend = phantom_suspend, | 503 | .suspend = phantom_suspend, |
504 | .resume = phantom_resume | 504 | .resume = phantom_resume |
505 | }; | 505 | }; |
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 4999b34b7a6..7003031c918 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c | |||
@@ -76,7 +76,7 @@ struct pti_dev { | |||
76 | */ | 76 | */ |
77 | static DEFINE_MUTEX(alloclock); | 77 | static DEFINE_MUTEX(alloclock); |
78 | 78 | ||
79 | static const struct pci_device_id pci_ids[] __devinitconst = { | 79 | static const struct pci_device_id pci_ids[] = { |
80 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)}, | 80 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)}, |
81 | {0} | 81 | {0} |
82 | }; | 82 | }; |
@@ -796,7 +796,7 @@ static const struct tty_port_operations tty_port_ops = { | |||
796 | * 0 for success | 796 | * 0 for success |
797 | * otherwise, error | 797 | * otherwise, error |
798 | */ | 798 | */ |
799 | static int __devinit pti_pci_probe(struct pci_dev *pdev, | 799 | static int pti_pci_probe(struct pci_dev *pdev, |
800 | const struct pci_device_id *ent) | 800 | const struct pci_device_id *ent) |
801 | { | 801 | { |
802 | unsigned int a; | 802 | unsigned int a; |
@@ -879,7 +879,7 @@ err: | |||
879 | * PCI bus. | 879 | * PCI bus. |
880 | * @pdev: variable containing pci info of PTI. | 880 | * @pdev: variable containing pci info of PTI. |
881 | */ | 881 | */ |
882 | static void __devexit pti_pci_remove(struct pci_dev *pdev) | 882 | static void pti_pci_remove(struct pci_dev *pdev) |
883 | { | 883 | { |
884 | struct pti_dev *drv_data = pci_get_drvdata(pdev); | 884 | struct pti_dev *drv_data = pci_get_drvdata(pdev); |
885 | 885 | ||
@@ -901,7 +901,7 @@ static struct pci_driver pti_pci_driver = { | |||
901 | .name = PCINAME, | 901 | .name = PCINAME, |
902 | .id_table = pci_ids, | 902 | .id_table = pci_ids, |
903 | .probe = pti_pci_probe, | 903 | .probe = pti_pci_probe, |
904 | .remove = __devexit_p(pti_pci_remove), | 904 | .remove = pti_pci_remove, |
905 | }; | 905 | }; |
906 | 906 | ||
907 | /** | 907 | /** |
diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index 123ed98eec3..7deb25dc86a 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c | |||
@@ -711,7 +711,7 @@ static void spear13xx_pcie_device_init(struct spear_pcie_gadget_config *config) | |||
711 | spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); | 711 | spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); |
712 | } | 712 | } |
713 | 713 | ||
714 | static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev) | 714 | static int spear_pcie_gadget_probe(struct platform_device *pdev) |
715 | { | 715 | { |
716 | struct resource *res0, *res1; | 716 | struct resource *res0, *res1; |
717 | unsigned int status = 0; | 717 | unsigned int status = 0; |
@@ -853,7 +853,7 @@ err_rel_res0: | |||
853 | return status; | 853 | return status; |
854 | } | 854 | } |
855 | 855 | ||
856 | static int __devexit spear_pcie_gadget_remove(struct platform_device *pdev) | 856 | static int spear_pcie_gadget_remove(struct platform_device *pdev) |
857 | { | 857 | { |
858 | struct resource *res0, *res1; | 858 | struct resource *res0, *res1; |
859 | static struct pcie_gadget_target *target; | 859 | static struct pcie_gadget_target *target; |
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 46937b10726..b90a2241d79 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c | |||
@@ -511,7 +511,6 @@ long st_register(struct st_proto_s *new_proto) | |||
511 | unsigned long flags = 0; | 511 | unsigned long flags = 0; |
512 | 512 | ||
513 | st_kim_ref(&st_gdata, 0); | 513 | st_kim_ref(&st_gdata, 0); |
514 | pr_info("%s(%d) ", __func__, new_proto->chnl_id); | ||
515 | if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL | 514 | if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL |
516 | || new_proto->reg_complete_cb == NULL) { | 515 | || new_proto->reg_complete_cb == NULL) { |
517 | pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); | 516 | pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); |
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 04a819944f6..9ff942a346e 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c | |||
@@ -705,9 +705,9 @@ static const struct file_operations list_debugfs_fops = { | |||
705 | static struct dentry *kim_debugfs_dir; | 705 | static struct dentry *kim_debugfs_dir; |
706 | static int kim_probe(struct platform_device *pdev) | 706 | static int kim_probe(struct platform_device *pdev) |
707 | { | 707 | { |
708 | long status; | ||
709 | struct kim_data_s *kim_gdata; | 708 | struct kim_data_s *kim_gdata; |
710 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; | 709 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; |
710 | int err; | ||
711 | 711 | ||
712 | if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { | 712 | if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { |
713 | /* multiple devices could exist */ | 713 | /* multiple devices could exist */ |
@@ -724,10 +724,11 @@ static int kim_probe(struct platform_device *pdev) | |||
724 | } | 724 | } |
725 | dev_set_drvdata(&pdev->dev, kim_gdata); | 725 | dev_set_drvdata(&pdev->dev, kim_gdata); |
726 | 726 | ||
727 | status = st_core_init(&kim_gdata->core_data); | 727 | err = st_core_init(&kim_gdata->core_data); |
728 | if (status != 0) { | 728 | if (err != 0) { |
729 | pr_err(" ST core init failed"); | 729 | pr_err(" ST core init failed"); |
730 | return -EIO; | 730 | err = -EIO; |
731 | goto err_core_init; | ||
731 | } | 732 | } |
732 | /* refer to itself */ | 733 | /* refer to itself */ |
733 | kim_gdata->core_data->kim_data = kim_gdata; | 734 | kim_gdata->core_data->kim_data = kim_gdata; |
@@ -738,10 +739,10 @@ static int kim_probe(struct platform_device *pdev) | |||
738 | init_completion(&kim_gdata->kim_rcvd); | 739 | init_completion(&kim_gdata->kim_rcvd); |
739 | init_completion(&kim_gdata->ldisc_installed); | 740 | init_completion(&kim_gdata->ldisc_installed); |
740 | 741 | ||
741 | status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); | 742 | err = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); |
742 | if (status) { | 743 | if (err) { |
743 | pr_err("failed to create sysfs entries"); | 744 | pr_err("failed to create sysfs entries"); |
744 | return status; | 745 | goto err_sysfs_group; |
745 | } | 746 | } |
746 | 747 | ||
747 | /* copying platform data */ | 748 | /* copying platform data */ |
@@ -753,8 +754,8 @@ static int kim_probe(struct platform_device *pdev) | |||
753 | kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); | 754 | kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); |
754 | if (IS_ERR(kim_debugfs_dir)) { | 755 | if (IS_ERR(kim_debugfs_dir)) { |
755 | pr_err(" debugfs entries creation failed "); | 756 | pr_err(" debugfs entries creation failed "); |
756 | kim_debugfs_dir = NULL; | 757 | err = -EIO; |
757 | return -EIO; | 758 | goto err_debugfs_dir; |
758 | } | 759 | } |
759 | 760 | ||
760 | debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, | 761 | debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, |
@@ -763,6 +764,17 @@ static int kim_probe(struct platform_device *pdev) | |||
763 | kim_gdata, &list_debugfs_fops); | 764 | kim_gdata, &list_debugfs_fops); |
764 | pr_info(" debugfs entries created "); | 765 | pr_info(" debugfs entries created "); |
765 | return 0; | 766 | return 0; |
767 | |||
768 | err_debugfs_dir: | ||
769 | sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); | ||
770 | |||
771 | err_sysfs_group: | ||
772 | st_core_exit(kim_gdata->core_data); | ||
773 | |||
774 | err_core_init: | ||
775 | kfree(kim_gdata); | ||
776 | |||
777 | return err; | ||
766 | } | 778 | } |
767 | 779 | ||
768 | static int kim_remove(struct platform_device *pdev) | 780 | static int kim_remove(struct platform_device *pdev) |
diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c index 5acbba120de..1d86407189e 100644 --- a/drivers/misc/ti_dac7512.c +++ b/drivers/misc/ti_dac7512.c | |||
@@ -54,7 +54,7 @@ static const struct attribute_group dac7512_attr_group = { | |||
54 | .attrs = dac7512_attributes, | 54 | .attrs = dac7512_attributes, |
55 | }; | 55 | }; |
56 | 56 | ||
57 | static int __devinit dac7512_probe(struct spi_device *spi) | 57 | static int dac7512_probe(struct spi_device *spi) |
58 | { | 58 | { |
59 | int ret; | 59 | int ret; |
60 | 60 | ||
@@ -67,7 +67,7 @@ static int __devinit dac7512_probe(struct spi_device *spi) | |||
67 | return sysfs_create_group(&spi->dev.kobj, &dac7512_attr_group); | 67 | return sysfs_create_group(&spi->dev.kobj, &dac7512_attr_group); |
68 | } | 68 | } |
69 | 69 | ||
70 | static int __devexit dac7512_remove(struct spi_device *spi) | 70 | static int dac7512_remove(struct spi_device *spi) |
71 | { | 71 | { |
72 | sysfs_remove_group(&spi->dev.kobj, &dac7512_attr_group); | 72 | sysfs_remove_group(&spi->dev.kobj, &dac7512_attr_group); |
73 | return 0; | 73 | return 0; |
@@ -79,7 +79,7 @@ static struct spi_driver dac7512_driver = { | |||
79 | .owner = THIS_MODULE, | 79 | .owner = THIS_MODULE, |
80 | }, | 80 | }, |
81 | .probe = dac7512_probe, | 81 | .probe = dac7512_probe, |
82 | .remove = __devexit_p(dac7512_remove), | 82 | .remove = dac7512_remove, |
83 | }; | 83 | }; |
84 | 84 | ||
85 | module_spi_driver(dac7512_driver); | 85 | module_spi_driver(dac7512_driver); |
diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index 0beb298a17d..1e7bc0eb081 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c | |||
@@ -347,7 +347,7 @@ static int tsl2550_init_client(struct i2c_client *client) | |||
347 | */ | 347 | */ |
348 | 348 | ||
349 | static struct i2c_driver tsl2550_driver; | 349 | static struct i2c_driver tsl2550_driver; |
350 | static int __devinit tsl2550_probe(struct i2c_client *client, | 350 | static int tsl2550_probe(struct i2c_client *client, |
351 | const struct i2c_device_id *id) | 351 | const struct i2c_device_id *id) |
352 | { | 352 | { |
353 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 353 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
@@ -405,7 +405,7 @@ exit: | |||
405 | return err; | 405 | return err; |
406 | } | 406 | } |
407 | 407 | ||
408 | static int __devexit tsl2550_remove(struct i2c_client *client) | 408 | static int tsl2550_remove(struct i2c_client *client) |
409 | { | 409 | { |
410 | sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group); | 410 | sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group); |
411 | 411 | ||
@@ -450,7 +450,7 @@ static struct i2c_driver tsl2550_driver = { | |||
450 | .suspend = tsl2550_suspend, | 450 | .suspend = tsl2550_suspend, |
451 | .resume = tsl2550_resume, | 451 | .resume = tsl2550_resume, |
452 | .probe = tsl2550_probe, | 452 | .probe = tsl2550_probe, |
453 | .remove = __devexit_p(tsl2550_remove), | 453 | .remove = tsl2550_remove, |
454 | .id_table = tsl2550_id, | 454 | .id_table = tsl2550_id, |
455 | }; | 455 | }; |
456 | 456 | ||
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index bebbe167fd8..737e4edc241 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig | |||
@@ -624,3 +624,10 @@ config MMC_WMT | |||
624 | 624 | ||
625 | To compile this driver as a module, choose M here: the | 625 | To compile this driver as a module, choose M here: the |
626 | module will be called wmt-sdmmc. | 626 | module will be called wmt-sdmmc. |
627 | |||
628 | config MMC_REALTEK_PCI | ||
629 | tristate "Realtek PCI-E SD/MMC Card Interface Driver" | ||
630 | depends on MFD_RTSX_PCI | ||
631 | help | ||
632 | Say Y here to include driver code to support SD/MMC card interface | ||
633 | of Realtek PCI-E card reader | ||
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index c5eddc1b483..b648058d718 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile | |||
@@ -47,6 +47,8 @@ obj-$(CONFIG_MMC_VUB300) += vub300.o | |||
47 | obj-$(CONFIG_MMC_USHC) += ushc.o | 47 | obj-$(CONFIG_MMC_USHC) += ushc.o |
48 | obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o | 48 | obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o |
49 | 49 | ||
50 | obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o | ||
51 | |||
50 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o | 52 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o |
51 | obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o | 53 | obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o |
52 | obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o | 54 | obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o |
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c new file mode 100644 index 00000000000..12eff6f8cab --- /dev/null +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c | |||
@@ -0,0 +1,1348 @@ | |||
1 | /* Realtek PCI-Express SD/MMC Card Interface driver | ||
2 | * | ||
3 | * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/highmem.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/mmc/host.h> | ||
28 | #include <linux/mmc/mmc.h> | ||
29 | #include <linux/mmc/sd.h> | ||
30 | #include <linux/mmc/card.h> | ||
31 | #include <linux/mfd/rtsx_pci.h> | ||
32 | #include <asm/unaligned.h> | ||
33 | |||
34 | /* SD Tuning Data Structure | ||
35 | * Record continuous timing phase path | ||
36 | */ | ||
37 | struct timing_phase_path { | ||
38 | int start; | ||
39 | int end; | ||
40 | int mid; | ||
41 | int len; | ||
42 | }; | ||
43 | |||
44 | struct realtek_pci_sdmmc { | ||
45 | struct platform_device *pdev; | ||
46 | struct rtsx_pcr *pcr; | ||
47 | struct mmc_host *mmc; | ||
48 | struct mmc_request *mrq; | ||
49 | |||
50 | struct mutex host_mutex; | ||
51 | |||
52 | u8 ssc_depth; | ||
53 | unsigned int clock; | ||
54 | bool vpclk; | ||
55 | bool double_clk; | ||
56 | bool eject; | ||
57 | bool initial_mode; | ||
58 | bool ddr_mode; | ||
59 | }; | ||
60 | |||
61 | static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) | ||
62 | { | ||
63 | return &(host->pdev->dev); | ||
64 | } | ||
65 | |||
66 | static inline void sd_clear_error(struct realtek_pci_sdmmc *host) | ||
67 | { | ||
68 | rtsx_pci_write_register(host->pcr, CARD_STOP, | ||
69 | SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); | ||
70 | } | ||
71 | |||
72 | #ifdef DEBUG | ||
73 | static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) | ||
74 | { | ||
75 | struct rtsx_pcr *pcr = host->pcr; | ||
76 | u16 i; | ||
77 | u8 *ptr; | ||
78 | |||
79 | /* Print SD host internal registers */ | ||
80 | rtsx_pci_init_cmd(pcr); | ||
81 | for (i = 0xFDA0; i <= 0xFDAE; i++) | ||
82 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); | ||
83 | for (i = 0xFD52; i <= 0xFD69; i++) | ||
84 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); | ||
85 | rtsx_pci_send_cmd(pcr, 100); | ||
86 | |||
87 | ptr = rtsx_pci_get_cmd_data(pcr); | ||
88 | for (i = 0xFDA0; i <= 0xFDAE; i++) | ||
89 | dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); | ||
90 | for (i = 0xFD52; i <= 0xFD69; i++) | ||
91 | dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); | ||
92 | } | ||
93 | #else | ||
94 | #define sd_print_debug_regs(host) | ||
95 | #endif /* DEBUG */ | ||
96 | |||
97 | static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, | ||
98 | u8 *buf, int buf_len, int timeout) | ||
99 | { | ||
100 | struct rtsx_pcr *pcr = host->pcr; | ||
101 | int err, i; | ||
102 | u8 trans_mode; | ||
103 | |||
104 | dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__, cmd[0] - 0x40); | ||
105 | |||
106 | if (!buf) | ||
107 | buf_len = 0; | ||
108 | |||
109 | if ((cmd[0] & 0x3F) == MMC_SEND_TUNING_BLOCK) | ||
110 | trans_mode = SD_TM_AUTO_TUNING; | ||
111 | else | ||
112 | trans_mode = SD_TM_NORMAL_READ; | ||
113 | |||
114 | rtsx_pci_init_cmd(pcr); | ||
115 | |||
116 | for (i = 0; i < 5; i++) | ||
117 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0 + i, 0xFF, cmd[i]); | ||
118 | |||
119 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); | ||
120 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, | ||
121 | 0xFF, (u8)(byte_cnt >> 8)); | ||
122 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); | ||
123 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); | ||
124 | |||
125 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, | ||
126 | SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | | ||
127 | SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); | ||
128 | if (trans_mode != SD_TM_AUTO_TUNING) | ||
129 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
130 | CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); | ||
131 | |||
132 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, | ||
133 | 0xFF, trans_mode | SD_TRANSFER_START); | ||
134 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, | ||
135 | SD_TRANSFER_END, SD_TRANSFER_END); | ||
136 | |||
137 | err = rtsx_pci_send_cmd(pcr, timeout); | ||
138 | if (err < 0) { | ||
139 | sd_print_debug_regs(host); | ||
140 | dev_dbg(sdmmc_dev(host), | ||
141 | "rtsx_pci_send_cmd fail (err = %d)\n", err); | ||
142 | return err; | ||
143 | } | ||
144 | |||
145 | if (buf && buf_len) { | ||
146 | err = rtsx_pci_read_ppbuf(pcr, buf, buf_len); | ||
147 | if (err < 0) { | ||
148 | dev_dbg(sdmmc_dev(host), | ||
149 | "rtsx_pci_read_ppbuf fail (err = %d)\n", err); | ||
150 | return err; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, | ||
158 | u8 *buf, int buf_len, int timeout) | ||
159 | { | ||
160 | struct rtsx_pcr *pcr = host->pcr; | ||
161 | int err, i; | ||
162 | u8 trans_mode; | ||
163 | |||
164 | if (!buf) | ||
165 | buf_len = 0; | ||
166 | |||
167 | if (buf && buf_len) { | ||
168 | err = rtsx_pci_write_ppbuf(pcr, buf, buf_len); | ||
169 | if (err < 0) { | ||
170 | dev_dbg(sdmmc_dev(host), | ||
171 | "rtsx_pci_write_ppbuf fail (err = %d)\n", err); | ||
172 | return err; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | trans_mode = cmd ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3; | ||
177 | rtsx_pci_init_cmd(pcr); | ||
178 | |||
179 | if (cmd) { | ||
180 | dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d\n", __func__, | ||
181 | cmd[0] - 0x40); | ||
182 | |||
183 | for (i = 0; i < 5; i++) | ||
184 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
185 | SD_CMD0 + i, 0xFF, cmd[i]); | ||
186 | } | ||
187 | |||
188 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); | ||
189 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, | ||
190 | 0xFF, (u8)(byte_cnt >> 8)); | ||
191 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); | ||
192 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); | ||
193 | |||
194 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, | ||
195 | SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | | ||
196 | SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); | ||
197 | |||
198 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, | ||
199 | trans_mode | SD_TRANSFER_START); | ||
200 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, | ||
201 | SD_TRANSFER_END, SD_TRANSFER_END); | ||
202 | |||
203 | err = rtsx_pci_send_cmd(pcr, timeout); | ||
204 | if (err < 0) { | ||
205 | sd_print_debug_regs(host); | ||
206 | dev_dbg(sdmmc_dev(host), | ||
207 | "rtsx_pci_send_cmd fail (err = %d)\n", err); | ||
208 | return err; | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, | ||
215 | struct mmc_command *cmd) | ||
216 | { | ||
217 | struct rtsx_pcr *pcr = host->pcr; | ||
218 | u8 cmd_idx = (u8)cmd->opcode; | ||
219 | u32 arg = cmd->arg; | ||
220 | int err = 0; | ||
221 | int timeout = 100; | ||
222 | int i; | ||
223 | u8 *ptr; | ||
224 | int stat_idx = 0; | ||
225 | u8 rsp_type; | ||
226 | int rsp_len = 5; | ||
227 | |||
228 | dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", | ||
229 | __func__, cmd_idx, arg); | ||
230 | |||
231 | /* Response type: | ||
232 | * R0 | ||
233 | * R1, R5, R6, R7 | ||
234 | * R1b | ||
235 | * R2 | ||
236 | * R3, R4 | ||
237 | */ | ||
238 | switch (mmc_resp_type(cmd)) { | ||
239 | case MMC_RSP_NONE: | ||
240 | rsp_type = SD_RSP_TYPE_R0; | ||
241 | rsp_len = 0; | ||
242 | break; | ||
243 | case MMC_RSP_R1: | ||
244 | rsp_type = SD_RSP_TYPE_R1; | ||
245 | break; | ||
246 | case MMC_RSP_R1B: | ||
247 | rsp_type = SD_RSP_TYPE_R1b; | ||
248 | break; | ||
249 | case MMC_RSP_R2: | ||
250 | rsp_type = SD_RSP_TYPE_R2; | ||
251 | rsp_len = 16; | ||
252 | break; | ||
253 | case MMC_RSP_R3: | ||
254 | rsp_type = SD_RSP_TYPE_R3; | ||
255 | break; | ||
256 | default: | ||
257 | dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n"); | ||
258 | err = -EINVAL; | ||
259 | goto out; | ||
260 | } | ||
261 | |||
262 | if (rsp_type == SD_RSP_TYPE_R1b) | ||
263 | timeout = 3000; | ||
264 | |||
265 | if (cmd->opcode == SD_SWITCH_VOLTAGE) { | ||
266 | err = rtsx_pci_write_register(pcr, SD_BUS_STAT, | ||
267 | 0xFF, SD_CLK_TOGGLE_EN); | ||
268 | if (err < 0) | ||
269 | goto out; | ||
270 | } | ||
271 | |||
272 | rtsx_pci_init_cmd(pcr); | ||
273 | |||
274 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); | ||
275 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); | ||
276 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); | ||
277 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); | ||
278 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); | ||
279 | |||
280 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); | ||
281 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, | ||
282 | 0x01, PINGPONG_BUFFER); | ||
283 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, | ||
284 | 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); | ||
285 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, | ||
286 | SD_TRANSFER_END | SD_STAT_IDLE, | ||
287 | SD_TRANSFER_END | SD_STAT_IDLE); | ||
288 | |||
289 | if (rsp_type == SD_RSP_TYPE_R2) { | ||
290 | /* Read data from ping-pong buffer */ | ||
291 | for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) | ||
292 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); | ||
293 | stat_idx = 16; | ||
294 | } else if (rsp_type != SD_RSP_TYPE_R0) { | ||
295 | /* Read data from SD_CMDx registers */ | ||
296 | for (i = SD_CMD0; i <= SD_CMD4; i++) | ||
297 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); | ||
298 | stat_idx = 5; | ||
299 | } | ||
300 | |||
301 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0); | ||
302 | |||
303 | err = rtsx_pci_send_cmd(pcr, timeout); | ||
304 | if (err < 0) { | ||
305 | sd_print_debug_regs(host); | ||
306 | sd_clear_error(host); | ||
307 | dev_dbg(sdmmc_dev(host), | ||
308 | "rtsx_pci_send_cmd error (err = %d)\n", err); | ||
309 | goto out; | ||
310 | } | ||
311 | |||
312 | if (rsp_type == SD_RSP_TYPE_R0) { | ||
313 | err = 0; | ||
314 | goto out; | ||
315 | } | ||
316 | |||
317 | /* Eliminate returned value of CHECK_REG_CMD */ | ||
318 | ptr = rtsx_pci_get_cmd_data(pcr) + 1; | ||
319 | |||
320 | /* Check (Start,Transmission) bit of Response */ | ||
321 | if ((ptr[0] & 0xC0) != 0) { | ||
322 | err = -EILSEQ; | ||
323 | dev_dbg(sdmmc_dev(host), "Invalid response bit\n"); | ||
324 | goto out; | ||
325 | } | ||
326 | |||
327 | /* Check CRC7 */ | ||
328 | if (!(rsp_type & SD_NO_CHECK_CRC7)) { | ||
329 | if (ptr[stat_idx] & SD_CRC7_ERR) { | ||
330 | err = -EILSEQ; | ||
331 | dev_dbg(sdmmc_dev(host), "CRC7 error\n"); | ||
332 | goto out; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | if (rsp_type == SD_RSP_TYPE_R2) { | ||
337 | for (i = 0; i < 4; i++) { | ||
338 | cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4); | ||
339 | dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n", | ||
340 | i, cmd->resp[i]); | ||
341 | } | ||
342 | } else { | ||
343 | cmd->resp[0] = get_unaligned_be32(ptr + 1); | ||
344 | dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", | ||
345 | cmd->resp[0]); | ||
346 | } | ||
347 | |||
348 | out: | ||
349 | cmd->error = err; | ||
350 | } | ||
351 | |||
352 | static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) | ||
353 | { | ||
354 | struct rtsx_pcr *pcr = host->pcr; | ||
355 | struct mmc_host *mmc = host->mmc; | ||
356 | struct mmc_card *card = mmc->card; | ||
357 | struct mmc_data *data = mrq->data; | ||
358 | int uhs = mmc_sd_card_uhs(card); | ||
359 | int read = (data->flags & MMC_DATA_READ) ? 1 : 0; | ||
360 | u8 cfg2, trans_mode; | ||
361 | int err; | ||
362 | size_t data_len = data->blksz * data->blocks; | ||
363 | |||
364 | if (read) { | ||
365 | cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | | ||
366 | SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0; | ||
367 | trans_mode = SD_TM_AUTO_READ_3; | ||
368 | } else { | ||
369 | cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | | ||
370 | SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; | ||
371 | trans_mode = SD_TM_AUTO_WRITE_3; | ||
372 | } | ||
373 | |||
374 | if (!uhs) | ||
375 | cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; | ||
376 | |||
377 | rtsx_pci_init_cmd(pcr); | ||
378 | |||
379 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00); | ||
380 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02); | ||
381 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, | ||
382 | 0xFF, (u8)data->blocks); | ||
383 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, | ||
384 | 0xFF, (u8)(data->blocks >> 8)); | ||
385 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
386 | CARD_DATA_SOURCE, 0x01, RING_BUFFER); | ||
387 | |||
388 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, | ||
389 | DMA_DONE_INT, DMA_DONE_INT); | ||
390 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, | ||
391 | 0xFF, (u8)(data_len >> 24)); | ||
392 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, | ||
393 | 0xFF, (u8)(data_len >> 16)); | ||
394 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, | ||
395 | 0xFF, (u8)(data_len >> 8)); | ||
396 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)data_len); | ||
397 | if (read) { | ||
398 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, | ||
399 | 0x03 | DMA_PACK_SIZE_MASK, | ||
400 | DMA_DIR_FROM_CARD | DMA_EN | DMA_512); | ||
401 | } else { | ||
402 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, | ||
403 | 0x03 | DMA_PACK_SIZE_MASK, | ||
404 | DMA_DIR_TO_CARD | DMA_EN | DMA_512); | ||
405 | } | ||
406 | |||
407 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, | ||
408 | 0x01, RING_BUFFER); | ||
409 | |||
410 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, | ||
411 | trans_mode | SD_TRANSFER_START); | ||
412 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, | ||
413 | SD_TRANSFER_END, SD_TRANSFER_END); | ||
414 | |||
415 | rtsx_pci_send_cmd_no_wait(pcr); | ||
416 | |||
417 | err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000); | ||
418 | if (err < 0) { | ||
419 | sd_clear_error(host); | ||
420 | return err; | ||
421 | } | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host) | ||
427 | { | ||
428 | rtsx_pci_write_register(host->pcr, SD_CFG1, | ||
429 | SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128); | ||
430 | } | ||
431 | |||
432 | static inline void sd_disable_initial_mode(struct realtek_pci_sdmmc *host) | ||
433 | { | ||
434 | rtsx_pci_write_register(host->pcr, SD_CFG1, | ||
435 | SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0); | ||
436 | } | ||
437 | |||
438 | static void sd_normal_rw(struct realtek_pci_sdmmc *host, | ||
439 | struct mmc_request *mrq) | ||
440 | { | ||
441 | struct mmc_command *cmd = mrq->cmd; | ||
442 | struct mmc_data *data = mrq->data; | ||
443 | u8 _cmd[5], *buf; | ||
444 | |||
445 | _cmd[0] = 0x40 | (u8)cmd->opcode; | ||
446 | put_unaligned_be32(cmd->arg, (u32 *)(&_cmd[1])); | ||
447 | |||
448 | buf = kzalloc(data->blksz, GFP_NOIO); | ||
449 | if (!buf) { | ||
450 | cmd->error = -ENOMEM; | ||
451 | return; | ||
452 | } | ||
453 | |||
454 | if (data->flags & MMC_DATA_READ) { | ||
455 | if (host->initial_mode) | ||
456 | sd_disable_initial_mode(host); | ||
457 | |||
458 | cmd->error = sd_read_data(host, _cmd, (u16)data->blksz, buf, | ||
459 | data->blksz, 200); | ||
460 | |||
461 | if (host->initial_mode) | ||
462 | sd_enable_initial_mode(host); | ||
463 | |||
464 | sg_copy_from_buffer(data->sg, data->sg_len, buf, data->blksz); | ||
465 | } else { | ||
466 | sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz); | ||
467 | |||
468 | cmd->error = sd_write_data(host, _cmd, (u16)data->blksz, buf, | ||
469 | data->blksz, 200); | ||
470 | } | ||
471 | |||
472 | kfree(buf); | ||
473 | } | ||
474 | |||
475 | static int sd_change_phase(struct realtek_pci_sdmmc *host, u8 sample_point) | ||
476 | { | ||
477 | struct rtsx_pcr *pcr = host->pcr; | ||
478 | int err; | ||
479 | |||
480 | dev_dbg(sdmmc_dev(host), "%s: sample_point = %d\n", | ||
481 | __func__, sample_point); | ||
482 | |||
483 | rtsx_pci_init_cmd(pcr); | ||
484 | |||
485 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, CHANGE_CLK); | ||
486 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPRX_CTL, 0x1F, sample_point); | ||
487 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); | ||
488 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, | ||
489 | PHASE_NOT_RESET, PHASE_NOT_RESET); | ||
490 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, 0); | ||
491 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0); | ||
492 | |||
493 | err = rtsx_pci_send_cmd(pcr, 100); | ||
494 | if (err < 0) | ||
495 | return err; | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map) | ||
501 | { | ||
502 | struct timing_phase_path path[MAX_PHASE + 1]; | ||
503 | int i, j, cont_path_cnt; | ||
504 | int new_block, max_len, final_path_idx; | ||
505 | u8 final_phase = 0xFF; | ||
506 | |||
507 | /* Parse phase_map, take it as a bit-ring */ | ||
508 | cont_path_cnt = 0; | ||
509 | new_block = 1; | ||
510 | j = 0; | ||
511 | for (i = 0; i < MAX_PHASE + 1; i++) { | ||
512 | if (phase_map & (1 << i)) { | ||
513 | if (new_block) { | ||
514 | new_block = 0; | ||
515 | j = cont_path_cnt++; | ||
516 | path[j].start = i; | ||
517 | path[j].end = i; | ||
518 | } else { | ||
519 | path[j].end = i; | ||
520 | } | ||
521 | } else { | ||
522 | new_block = 1; | ||
523 | if (cont_path_cnt) { | ||
524 | /* Calculate path length and middle point */ | ||
525 | int idx = cont_path_cnt - 1; | ||
526 | path[idx].len = | ||
527 | path[idx].end - path[idx].start + 1; | ||
528 | path[idx].mid = | ||
529 | path[idx].start + path[idx].len / 2; | ||
530 | } | ||
531 | } | ||
532 | } | ||
533 | |||
534 | if (cont_path_cnt == 0) { | ||
535 | dev_dbg(sdmmc_dev(host), "No continuous phase path\n"); | ||
536 | goto finish; | ||
537 | } else { | ||
538 | /* Calculate last continuous path length and middle point */ | ||
539 | int idx = cont_path_cnt - 1; | ||
540 | path[idx].len = path[idx].end - path[idx].start + 1; | ||
541 | path[idx].mid = path[idx].start + path[idx].len / 2; | ||
542 | } | ||
543 | |||
544 | /* Connect the first and last continuous paths if they are adjacent */ | ||
545 | if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) { | ||
546 | /* Using negative index */ | ||
547 | path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; | ||
548 | path[0].len += path[cont_path_cnt - 1].len; | ||
549 | path[0].mid = path[0].start + path[0].len / 2; | ||
550 | /* Convert negative middle point index to positive one */ | ||
551 | if (path[0].mid < 0) | ||
552 | path[0].mid += MAX_PHASE + 1; | ||
553 | cont_path_cnt--; | ||
554 | } | ||
555 | |||
556 | /* Choose the longest continuous phase path */ | ||
557 | max_len = 0; | ||
558 | final_phase = 0; | ||
559 | final_path_idx = 0; | ||
560 | for (i = 0; i < cont_path_cnt; i++) { | ||
561 | if (path[i].len > max_len) { | ||
562 | max_len = path[i].len; | ||
563 | final_phase = (u8)path[i].mid; | ||
564 | final_path_idx = i; | ||
565 | } | ||
566 | |||
567 | dev_dbg(sdmmc_dev(host), "path[%d].start = %d\n", | ||
568 | i, path[i].start); | ||
569 | dev_dbg(sdmmc_dev(host), "path[%d].end = %d\n", | ||
570 | i, path[i].end); | ||
571 | dev_dbg(sdmmc_dev(host), "path[%d].len = %d\n", | ||
572 | i, path[i].len); | ||
573 | dev_dbg(sdmmc_dev(host), "path[%d].mid = %d\n", | ||
574 | i, path[i].mid); | ||
575 | } | ||
576 | |||
577 | finish: | ||
578 | dev_dbg(sdmmc_dev(host), "Final chosen phase: %d\n", final_phase); | ||
579 | return final_phase; | ||
580 | } | ||
581 | |||
582 | static void sd_wait_data_idle(struct realtek_pci_sdmmc *host) | ||
583 | { | ||
584 | int err, i; | ||
585 | u8 val = 0; | ||
586 | |||
587 | for (i = 0; i < 100; i++) { | ||
588 | err = rtsx_pci_read_register(host->pcr, SD_DATA_STATE, &val); | ||
589 | if (val & SD_DATA_IDLE) | ||
590 | return; | ||
591 | |||
592 | udelay(100); | ||
593 | } | ||
594 | } | ||
595 | |||
596 | static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, | ||
597 | u8 opcode, u8 sample_point) | ||
598 | { | ||
599 | int err; | ||
600 | u8 cmd[5] = {0}; | ||
601 | |||
602 | err = sd_change_phase(host, sample_point); | ||
603 | if (err < 0) | ||
604 | return err; | ||
605 | |||
606 | cmd[0] = 0x40 | opcode; | ||
607 | err = sd_read_data(host, cmd, 0x40, NULL, 0, 100); | ||
608 | if (err < 0) { | ||
609 | /* Wait till SD DATA IDLE */ | ||
610 | sd_wait_data_idle(host); | ||
611 | sd_clear_error(host); | ||
612 | return err; | ||
613 | } | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static int sd_tuning_phase(struct realtek_pci_sdmmc *host, | ||
619 | u8 opcode, u32 *phase_map) | ||
620 | { | ||
621 | int err, i; | ||
622 | u32 raw_phase_map = 0; | ||
623 | |||
624 | for (i = MAX_PHASE; i >= 0; i--) { | ||
625 | err = sd_tuning_rx_cmd(host, opcode, (u8)i); | ||
626 | if (err == 0) | ||
627 | raw_phase_map |= 1 << i; | ||
628 | } | ||
629 | |||
630 | if (phase_map) | ||
631 | *phase_map = raw_phase_map; | ||
632 | |||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) | ||
637 | { | ||
638 | int err, i; | ||
639 | u32 raw_phase_map[RX_TUNING_CNT] = {0}, phase_map; | ||
640 | u8 final_phase; | ||
641 | |||
642 | for (i = 0; i < RX_TUNING_CNT; i++) { | ||
643 | err = sd_tuning_phase(host, opcode, &(raw_phase_map[i])); | ||
644 | if (err < 0) | ||
645 | return err; | ||
646 | |||
647 | if (raw_phase_map[i] == 0) | ||
648 | break; | ||
649 | } | ||
650 | |||
651 | phase_map = 0xFFFFFFFF; | ||
652 | for (i = 0; i < RX_TUNING_CNT; i++) { | ||
653 | dev_dbg(sdmmc_dev(host), "RX raw_phase_map[%d] = 0x%08x\n", | ||
654 | i, raw_phase_map[i]); | ||
655 | phase_map &= raw_phase_map[i]; | ||
656 | } | ||
657 | dev_dbg(sdmmc_dev(host), "RX phase_map = 0x%08x\n", phase_map); | ||
658 | |||
659 | if (phase_map) { | ||
660 | final_phase = sd_search_final_phase(host, phase_map); | ||
661 | if (final_phase == 0xFF) | ||
662 | return -EINVAL; | ||
663 | |||
664 | err = sd_change_phase(host, final_phase); | ||
665 | if (err < 0) | ||
666 | return err; | ||
667 | } else { | ||
668 | return -EINVAL; | ||
669 | } | ||
670 | |||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | ||
675 | { | ||
676 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
677 | struct rtsx_pcr *pcr = host->pcr; | ||
678 | struct mmc_command *cmd = mrq->cmd; | ||
679 | struct mmc_data *data = mrq->data; | ||
680 | unsigned int data_size = 0; | ||
681 | |||
682 | if (host->eject) { | ||
683 | cmd->error = -ENOMEDIUM; | ||
684 | goto finish; | ||
685 | } | ||
686 | |||
687 | mutex_lock(&pcr->pcr_mutex); | ||
688 | |||
689 | rtsx_pci_start_run(pcr); | ||
690 | |||
691 | rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth, | ||
692 | host->initial_mode, host->double_clk, host->vpclk); | ||
693 | rtsx_pci_write_register(pcr, CARD_SELECT, 0x07, SD_MOD_SEL); | ||
694 | rtsx_pci_write_register(pcr, CARD_SHARE_MODE, | ||
695 | CARD_SHARE_MASK, CARD_SHARE_48_SD); | ||
696 | |||
697 | mutex_lock(&host->host_mutex); | ||
698 | host->mrq = mrq; | ||
699 | mutex_unlock(&host->host_mutex); | ||
700 | |||
701 | if (mrq->data) | ||
702 | data_size = data->blocks * data->blksz; | ||
703 | |||
704 | if (!data_size || mmc_op_multi(cmd->opcode) || | ||
705 | (cmd->opcode == MMC_READ_SINGLE_BLOCK) || | ||
706 | (cmd->opcode == MMC_WRITE_BLOCK)) { | ||
707 | sd_send_cmd_get_rsp(host, cmd); | ||
708 | |||
709 | if (!cmd->error && data_size) { | ||
710 | sd_rw_multi(host, mrq); | ||
711 | |||
712 | if (mmc_op_multi(cmd->opcode) && mrq->stop) | ||
713 | sd_send_cmd_get_rsp(host, mrq->stop); | ||
714 | } | ||
715 | } else { | ||
716 | sd_normal_rw(host, mrq); | ||
717 | } | ||
718 | |||
719 | if (mrq->data) { | ||
720 | if (cmd->error || data->error) | ||
721 | data->bytes_xfered = 0; | ||
722 | else | ||
723 | data->bytes_xfered = data->blocks * data->blksz; | ||
724 | } | ||
725 | |||
726 | mutex_unlock(&pcr->pcr_mutex); | ||
727 | |||
728 | finish: | ||
729 | if (cmd->error) | ||
730 | dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); | ||
731 | |||
732 | mutex_lock(&host->host_mutex); | ||
733 | host->mrq = NULL; | ||
734 | mutex_unlock(&host->host_mutex); | ||
735 | |||
736 | mmc_request_done(mmc, mrq); | ||
737 | } | ||
738 | |||
739 | static int sd_set_bus_width(struct realtek_pci_sdmmc *host, | ||
740 | unsigned char bus_width) | ||
741 | { | ||
742 | int err = 0; | ||
743 | u8 width[] = { | ||
744 | [MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT, | ||
745 | [MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT, | ||
746 | [MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT, | ||
747 | }; | ||
748 | |||
749 | if (bus_width <= MMC_BUS_WIDTH_8) | ||
750 | err = rtsx_pci_write_register(host->pcr, SD_CFG1, | ||
751 | 0x03, width[bus_width]); | ||
752 | |||
753 | return err; | ||
754 | } | ||
755 | |||
756 | static int sd_power_on(struct realtek_pci_sdmmc *host) | ||
757 | { | ||
758 | struct rtsx_pcr *pcr = host->pcr; | ||
759 | int err; | ||
760 | |||
761 | rtsx_pci_init_cmd(pcr); | ||
762 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); | ||
763 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, | ||
764 | CARD_SHARE_MASK, CARD_SHARE_48_SD); | ||
765 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, | ||
766 | SD_CLK_EN, SD_CLK_EN); | ||
767 | err = rtsx_pci_send_cmd(pcr, 100); | ||
768 | if (err < 0) | ||
769 | return err; | ||
770 | |||
771 | err = rtsx_pci_card_pull_ctl_enable(pcr, RTSX_SD_CARD); | ||
772 | if (err < 0) | ||
773 | return err; | ||
774 | |||
775 | err = rtsx_pci_card_power_on(pcr, RTSX_SD_CARD); | ||
776 | if (err < 0) | ||
777 | return err; | ||
778 | |||
779 | err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); | ||
780 | if (err < 0) | ||
781 | return err; | ||
782 | |||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | static int sd_power_off(struct realtek_pci_sdmmc *host) | ||
787 | { | ||
788 | struct rtsx_pcr *pcr = host->pcr; | ||
789 | int err; | ||
790 | |||
791 | rtsx_pci_init_cmd(pcr); | ||
792 | |||
793 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); | ||
794 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0); | ||
795 | |||
796 | err = rtsx_pci_send_cmd(pcr, 100); | ||
797 | if (err < 0) | ||
798 | return err; | ||
799 | |||
800 | err = rtsx_pci_card_power_off(pcr, RTSX_SD_CARD); | ||
801 | if (err < 0) | ||
802 | return err; | ||
803 | |||
804 | return rtsx_pci_card_pull_ctl_disable(pcr, RTSX_SD_CARD); | ||
805 | } | ||
806 | |||
807 | static int sd_set_power_mode(struct realtek_pci_sdmmc *host, | ||
808 | unsigned char power_mode) | ||
809 | { | ||
810 | int err; | ||
811 | |||
812 | if (power_mode == MMC_POWER_OFF) | ||
813 | err = sd_power_off(host); | ||
814 | else | ||
815 | err = sd_power_on(host); | ||
816 | |||
817 | return err; | ||
818 | } | ||
819 | |||
820 | static int sd_set_timing(struct realtek_pci_sdmmc *host, | ||
821 | unsigned char timing, bool *ddr_mode) | ||
822 | { | ||
823 | struct rtsx_pcr *pcr = host->pcr; | ||
824 | int err = 0; | ||
825 | |||
826 | *ddr_mode = false; | ||
827 | |||
828 | rtsx_pci_init_cmd(pcr); | ||
829 | |||
830 | switch (timing) { | ||
831 | case MMC_TIMING_UHS_SDR104: | ||
832 | case MMC_TIMING_UHS_SDR50: | ||
833 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, | ||
834 | 0x0C | SD_ASYNC_FIFO_NOT_RST, | ||
835 | SD_30_MODE | SD_ASYNC_FIFO_NOT_RST); | ||
836 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, | ||
837 | CLK_LOW_FREQ, CLK_LOW_FREQ); | ||
838 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, | ||
839 | CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); | ||
840 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); | ||
841 | break; | ||
842 | |||
843 | case MMC_TIMING_UHS_DDR50: | ||
844 | *ddr_mode = true; | ||
845 | |||
846 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, | ||
847 | 0x0C | SD_ASYNC_FIFO_NOT_RST, | ||
848 | SD_DDR_MODE | SD_ASYNC_FIFO_NOT_RST); | ||
849 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, | ||
850 | CLK_LOW_FREQ, CLK_LOW_FREQ); | ||
851 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, | ||
852 | CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); | ||
853 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); | ||
854 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, | ||
855 | DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT); | ||
856 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, | ||
857 | DDR_VAR_RX_DAT | DDR_VAR_RX_CMD, | ||
858 | DDR_VAR_RX_DAT | DDR_VAR_RX_CMD); | ||
859 | break; | ||
860 | |||
861 | case MMC_TIMING_MMC_HS: | ||
862 | case MMC_TIMING_SD_HS: | ||
863 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, | ||
864 | 0x0C, SD_20_MODE); | ||
865 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, | ||
866 | CLK_LOW_FREQ, CLK_LOW_FREQ); | ||
867 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, | ||
868 | CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); | ||
869 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); | ||
870 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, | ||
871 | SD20_TX_SEL_MASK, SD20_TX_14_AHEAD); | ||
872 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, | ||
873 | SD20_RX_SEL_MASK, SD20_RX_14_DELAY); | ||
874 | break; | ||
875 | |||
876 | default: | ||
877 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
878 | SD_CFG1, 0x0C, SD_20_MODE); | ||
879 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, | ||
880 | CLK_LOW_FREQ, CLK_LOW_FREQ); | ||
881 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, | ||
882 | CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); | ||
883 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); | ||
884 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
885 | SD_PUSH_POINT_CTL, 0xFF, 0); | ||
886 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, | ||
887 | SD20_RX_SEL_MASK, SD20_RX_POS_EDGE); | ||
888 | break; | ||
889 | } | ||
890 | |||
891 | err = rtsx_pci_send_cmd(pcr, 100); | ||
892 | |||
893 | return err; | ||
894 | } | ||
895 | |||
896 | static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | ||
897 | { | ||
898 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
899 | struct rtsx_pcr *pcr = host->pcr; | ||
900 | |||
901 | if (host->eject) | ||
902 | return; | ||
903 | |||
904 | mutex_lock(&pcr->pcr_mutex); | ||
905 | |||
906 | rtsx_pci_start_run(pcr); | ||
907 | |||
908 | sd_set_bus_width(host, ios->bus_width); | ||
909 | sd_set_power_mode(host, ios->power_mode); | ||
910 | sd_set_timing(host, ios->timing, &host->ddr_mode); | ||
911 | |||
912 | host->vpclk = false; | ||
913 | host->double_clk = true; | ||
914 | |||
915 | switch (ios->timing) { | ||
916 | case MMC_TIMING_UHS_SDR104: | ||
917 | case MMC_TIMING_UHS_SDR50: | ||
918 | host->ssc_depth = RTSX_SSC_DEPTH_2M; | ||
919 | host->vpclk = true; | ||
920 | host->double_clk = false; | ||
921 | break; | ||
922 | case MMC_TIMING_UHS_DDR50: | ||
923 | case MMC_TIMING_UHS_SDR25: | ||
924 | host->ssc_depth = RTSX_SSC_DEPTH_1M; | ||
925 | break; | ||
926 | default: | ||
927 | host->ssc_depth = RTSX_SSC_DEPTH_500K; | ||
928 | break; | ||
929 | } | ||
930 | |||
931 | host->initial_mode = (ios->clock <= 1000000) ? true : false; | ||
932 | |||
933 | host->clock = ios->clock; | ||
934 | rtsx_pci_switch_clock(pcr, ios->clock, host->ssc_depth, | ||
935 | host->initial_mode, host->double_clk, host->vpclk); | ||
936 | |||
937 | mutex_unlock(&pcr->pcr_mutex); | ||
938 | } | ||
939 | |||
940 | static int sdmmc_get_ro(struct mmc_host *mmc) | ||
941 | { | ||
942 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
943 | struct rtsx_pcr *pcr = host->pcr; | ||
944 | int ro = 0; | ||
945 | u32 val; | ||
946 | |||
947 | if (host->eject) | ||
948 | return -ENOMEDIUM; | ||
949 | |||
950 | mutex_lock(&pcr->pcr_mutex); | ||
951 | |||
952 | rtsx_pci_start_run(pcr); | ||
953 | |||
954 | /* Check SD mechanical write-protect switch */ | ||
955 | val = rtsx_pci_readl(pcr, RTSX_BIPR); | ||
956 | dev_dbg(sdmmc_dev(host), "%s: RTSX_BIPR = 0x%08x\n", __func__, val); | ||
957 | if (val & SD_WRITE_PROTECT) | ||
958 | ro = 1; | ||
959 | |||
960 | mutex_unlock(&pcr->pcr_mutex); | ||
961 | |||
962 | return ro; | ||
963 | } | ||
964 | |||
965 | static int sdmmc_get_cd(struct mmc_host *mmc) | ||
966 | { | ||
967 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
968 | struct rtsx_pcr *pcr = host->pcr; | ||
969 | int cd = 0; | ||
970 | u32 val; | ||
971 | |||
972 | if (host->eject) | ||
973 | return -ENOMEDIUM; | ||
974 | |||
975 | mutex_lock(&pcr->pcr_mutex); | ||
976 | |||
977 | rtsx_pci_start_run(pcr); | ||
978 | |||
979 | /* Check SD card detect */ | ||
980 | val = rtsx_pci_card_exist(pcr); | ||
981 | dev_dbg(sdmmc_dev(host), "%s: RTSX_BIPR = 0x%08x\n", __func__, val); | ||
982 | if (val & SD_EXIST) | ||
983 | cd = 1; | ||
984 | |||
985 | mutex_unlock(&pcr->pcr_mutex); | ||
986 | |||
987 | return cd; | ||
988 | } | ||
989 | |||
990 | static int sd_wait_voltage_stable_1(struct realtek_pci_sdmmc *host) | ||
991 | { | ||
992 | struct rtsx_pcr *pcr = host->pcr; | ||
993 | int err; | ||
994 | u8 stat; | ||
995 | |||
996 | /* Reference to Signal Voltage Switch Sequence in SD spec. | ||
997 | * Wait for a period of time so that the card can drive SD_CMD and | ||
998 | * SD_DAT[3:0] to low after sending back CMD11 response. | ||
999 | */ | ||
1000 | mdelay(1); | ||
1001 | |||
1002 | /* SD_CMD, SD_DAT[3:0] should be driven to low by card; | ||
1003 | * If either one of SD_CMD,SD_DAT[3:0] is not low, | ||
1004 | * abort the voltage switch sequence; | ||
1005 | */ | ||
1006 | err = rtsx_pci_read_register(pcr, SD_BUS_STAT, &stat); | ||
1007 | if (err < 0) | ||
1008 | return err; | ||
1009 | |||
1010 | if (stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | | ||
1011 | SD_DAT1_STATUS | SD_DAT0_STATUS)) | ||
1012 | return -EINVAL; | ||
1013 | |||
1014 | /* Stop toggle SD clock */ | ||
1015 | err = rtsx_pci_write_register(pcr, SD_BUS_STAT, | ||
1016 | 0xFF, SD_CLK_FORCE_STOP); | ||
1017 | if (err < 0) | ||
1018 | return err; | ||
1019 | |||
1020 | return 0; | ||
1021 | } | ||
1022 | |||
1023 | static int sd_wait_voltage_stable_2(struct realtek_pci_sdmmc *host) | ||
1024 | { | ||
1025 | struct rtsx_pcr *pcr = host->pcr; | ||
1026 | int err; | ||
1027 | u8 stat, mask, val; | ||
1028 | |||
1029 | /* Wait 1.8V output of voltage regulator in card stable */ | ||
1030 | msleep(50); | ||
1031 | |||
1032 | /* Toggle SD clock again */ | ||
1033 | err = rtsx_pci_write_register(pcr, SD_BUS_STAT, 0xFF, SD_CLK_TOGGLE_EN); | ||
1034 | if (err < 0) | ||
1035 | return err; | ||
1036 | |||
1037 | /* Wait for a period of time so that the card can drive | ||
1038 | * SD_DAT[3:0] to high at 1.8V | ||
1039 | */ | ||
1040 | msleep(20); | ||
1041 | |||
1042 | /* SD_CMD, SD_DAT[3:0] should be pulled high by host */ | ||
1043 | err = rtsx_pci_read_register(pcr, SD_BUS_STAT, &stat); | ||
1044 | if (err < 0) | ||
1045 | return err; | ||
1046 | |||
1047 | mask = SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | | ||
1048 | SD_DAT1_STATUS | SD_DAT0_STATUS; | ||
1049 | val = SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | | ||
1050 | SD_DAT1_STATUS | SD_DAT0_STATUS; | ||
1051 | if ((stat & mask) != val) { | ||
1052 | dev_dbg(sdmmc_dev(host), | ||
1053 | "%s: SD_BUS_STAT = 0x%x\n", __func__, stat); | ||
1054 | rtsx_pci_write_register(pcr, SD_BUS_STAT, | ||
1055 | SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); | ||
1056 | rtsx_pci_write_register(pcr, CARD_CLK_EN, 0xFF, 0); | ||
1057 | return -EINVAL; | ||
1058 | } | ||
1059 | |||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | static int sd_change_bank_voltage(struct realtek_pci_sdmmc *host, u8 voltage) | ||
1064 | { | ||
1065 | struct rtsx_pcr *pcr = host->pcr; | ||
1066 | int err; | ||
1067 | |||
1068 | if (voltage == SD_IO_3V3) { | ||
1069 | err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); | ||
1070 | if (err < 0) | ||
1071 | return err; | ||
1072 | } else if (voltage == SD_IO_1V8) { | ||
1073 | err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); | ||
1074 | if (err < 0) | ||
1075 | return err; | ||
1076 | } else { | ||
1077 | return -EINVAL; | ||
1078 | } | ||
1079 | |||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) | ||
1084 | { | ||
1085 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
1086 | struct rtsx_pcr *pcr = host->pcr; | ||
1087 | int err = 0; | ||
1088 | u8 voltage; | ||
1089 | |||
1090 | dev_dbg(sdmmc_dev(host), "%s: signal_voltage = %d\n", | ||
1091 | __func__, ios->signal_voltage); | ||
1092 | |||
1093 | if (host->eject) | ||
1094 | return -ENOMEDIUM; | ||
1095 | |||
1096 | mutex_lock(&pcr->pcr_mutex); | ||
1097 | |||
1098 | rtsx_pci_start_run(pcr); | ||
1099 | |||
1100 | if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) | ||
1101 | voltage = SD_IO_3V3; | ||
1102 | else | ||
1103 | voltage = SD_IO_1V8; | ||
1104 | |||
1105 | if (voltage == SD_IO_1V8) { | ||
1106 | err = rtsx_pci_write_register(pcr, | ||
1107 | SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); | ||
1108 | if (err < 0) | ||
1109 | goto out; | ||
1110 | |||
1111 | err = sd_wait_voltage_stable_1(host); | ||
1112 | if (err < 0) | ||
1113 | goto out; | ||
1114 | } | ||
1115 | |||
1116 | err = sd_change_bank_voltage(host, voltage); | ||
1117 | if (err < 0) | ||
1118 | goto out; | ||
1119 | |||
1120 | if (voltage == SD_IO_1V8) { | ||
1121 | err = sd_wait_voltage_stable_2(host); | ||
1122 | if (err < 0) | ||
1123 | goto out; | ||
1124 | } | ||
1125 | |||
1126 | /* Stop toggle SD clock in idle */ | ||
1127 | err = rtsx_pci_write_register(pcr, SD_BUS_STAT, | ||
1128 | SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); | ||
1129 | |||
1130 | out: | ||
1131 | mutex_unlock(&pcr->pcr_mutex); | ||
1132 | |||
1133 | return err; | ||
1134 | } | ||
1135 | |||
1136 | static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) | ||
1137 | { | ||
1138 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
1139 | struct rtsx_pcr *pcr = host->pcr; | ||
1140 | int err = 0; | ||
1141 | |||
1142 | if (host->eject) | ||
1143 | return -ENOMEDIUM; | ||
1144 | |||
1145 | mutex_lock(&pcr->pcr_mutex); | ||
1146 | |||
1147 | rtsx_pci_start_run(pcr); | ||
1148 | |||
1149 | if (!host->ddr_mode) | ||
1150 | err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK); | ||
1151 | |||
1152 | mutex_unlock(&pcr->pcr_mutex); | ||
1153 | |||
1154 | return err; | ||
1155 | } | ||
1156 | |||
1157 | static const struct mmc_host_ops realtek_pci_sdmmc_ops = { | ||
1158 | .request = sdmmc_request, | ||
1159 | .set_ios = sdmmc_set_ios, | ||
1160 | .get_ro = sdmmc_get_ro, | ||
1161 | .get_cd = sdmmc_get_cd, | ||
1162 | .start_signal_voltage_switch = sdmmc_switch_voltage, | ||
1163 | .execute_tuning = sdmmc_execute_tuning, | ||
1164 | }; | ||
1165 | |||
1166 | #ifdef CONFIG_PM | ||
1167 | static int rtsx_pci_sdmmc_suspend(struct platform_device *pdev, | ||
1168 | pm_message_t state) | ||
1169 | { | ||
1170 | struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); | ||
1171 | struct mmc_host *mmc = host->mmc; | ||
1172 | int err; | ||
1173 | |||
1174 | dev_dbg(sdmmc_dev(host), "--> %s\n", __func__); | ||
1175 | |||
1176 | err = mmc_suspend_host(mmc); | ||
1177 | if (err) | ||
1178 | return err; | ||
1179 | |||
1180 | return 0; | ||
1181 | } | ||
1182 | |||
1183 | static int rtsx_pci_sdmmc_resume(struct platform_device *pdev) | ||
1184 | { | ||
1185 | struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); | ||
1186 | struct mmc_host *mmc = host->mmc; | ||
1187 | |||
1188 | dev_dbg(sdmmc_dev(host), "--> %s\n", __func__); | ||
1189 | |||
1190 | return mmc_resume_host(mmc); | ||
1191 | } | ||
1192 | #else /* CONFIG_PM */ | ||
1193 | #define rtsx_pci_sdmmc_suspend NULL | ||
1194 | #define rtsx_pci_sdmmc_resume NULL | ||
1195 | #endif /* CONFIG_PM */ | ||
1196 | |||
1197 | static void init_extra_caps(struct realtek_pci_sdmmc *host) | ||
1198 | { | ||
1199 | struct mmc_host *mmc = host->mmc; | ||
1200 | struct rtsx_pcr *pcr = host->pcr; | ||
1201 | |||
1202 | dev_dbg(sdmmc_dev(host), "pcr->extra_caps = 0x%x\n", pcr->extra_caps); | ||
1203 | |||
1204 | if (pcr->extra_caps & EXTRA_CAPS_SD_SDR50) | ||
1205 | mmc->caps |= MMC_CAP_UHS_SDR50; | ||
1206 | if (pcr->extra_caps & EXTRA_CAPS_SD_SDR104) | ||
1207 | mmc->caps |= MMC_CAP_UHS_SDR104; | ||
1208 | if (pcr->extra_caps & EXTRA_CAPS_SD_DDR50) | ||
1209 | mmc->caps |= MMC_CAP_UHS_DDR50; | ||
1210 | if (pcr->extra_caps & EXTRA_CAPS_MMC_HSDDR) | ||
1211 | mmc->caps |= MMC_CAP_1_8V_DDR; | ||
1212 | if (pcr->extra_caps & EXTRA_CAPS_MMC_8BIT) | ||
1213 | mmc->caps |= MMC_CAP_8_BIT_DATA; | ||
1214 | } | ||
1215 | |||
1216 | static void realtek_init_host(struct realtek_pci_sdmmc *host) | ||
1217 | { | ||
1218 | struct mmc_host *mmc = host->mmc; | ||
1219 | |||
1220 | mmc->f_min = 250000; | ||
1221 | mmc->f_max = 208000000; | ||
1222 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; | ||
1223 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | | ||
1224 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | | ||
1225 | MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; | ||
1226 | mmc->max_current_330 = 400; | ||
1227 | mmc->max_current_180 = 800; | ||
1228 | mmc->ops = &realtek_pci_sdmmc_ops; | ||
1229 | |||
1230 | init_extra_caps(host); | ||
1231 | |||
1232 | mmc->max_segs = 256; | ||
1233 | mmc->max_seg_size = 65536; | ||
1234 | mmc->max_blk_size = 512; | ||
1235 | mmc->max_blk_count = 65535; | ||
1236 | mmc->max_req_size = 524288; | ||
1237 | } | ||
1238 | |||
1239 | static void rtsx_pci_sdmmc_card_event(struct platform_device *pdev) | ||
1240 | { | ||
1241 | struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); | ||
1242 | |||
1243 | mmc_detect_change(host->mmc, 0); | ||
1244 | } | ||
1245 | |||
1246 | static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) | ||
1247 | { | ||
1248 | struct mmc_host *mmc; | ||
1249 | struct realtek_pci_sdmmc *host; | ||
1250 | struct rtsx_pcr *pcr; | ||
1251 | struct pcr_handle *handle = pdev->dev.platform_data; | ||
1252 | |||
1253 | if (!handle) | ||
1254 | return -ENXIO; | ||
1255 | |||
1256 | pcr = handle->pcr; | ||
1257 | if (!pcr) | ||
1258 | return -ENXIO; | ||
1259 | |||
1260 | dev_dbg(&(pdev->dev), ": Realtek PCI-E SDMMC controller found\n"); | ||
1261 | |||
1262 | mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); | ||
1263 | if (!mmc) | ||
1264 | return -ENOMEM; | ||
1265 | |||
1266 | host = mmc_priv(mmc); | ||
1267 | host->pcr = pcr; | ||
1268 | host->mmc = mmc; | ||
1269 | host->pdev = pdev; | ||
1270 | platform_set_drvdata(pdev, host); | ||
1271 | pcr->slots[RTSX_SD_CARD].p_dev = pdev; | ||
1272 | pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; | ||
1273 | |||
1274 | mutex_init(&host->host_mutex); | ||
1275 | |||
1276 | realtek_init_host(host); | ||
1277 | |||
1278 | mmc_add_host(mmc); | ||
1279 | |||
1280 | return 0; | ||
1281 | } | ||
1282 | |||
1283 | static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) | ||
1284 | { | ||
1285 | struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); | ||
1286 | struct rtsx_pcr *pcr; | ||
1287 | struct mmc_host *mmc; | ||
1288 | |||
1289 | if (!host) | ||
1290 | return 0; | ||
1291 | |||
1292 | pcr = host->pcr; | ||
1293 | pcr->slots[RTSX_SD_CARD].p_dev = NULL; | ||
1294 | pcr->slots[RTSX_SD_CARD].card_event = NULL; | ||
1295 | mmc = host->mmc; | ||
1296 | host->eject = true; | ||
1297 | |||
1298 | mutex_lock(&host->host_mutex); | ||
1299 | if (host->mrq) { | ||
1300 | dev_dbg(&(pdev->dev), | ||
1301 | "%s: Controller removed during transfer\n", | ||
1302 | mmc_hostname(mmc)); | ||
1303 | |||
1304 | rtsx_pci_complete_unfinished_transfer(pcr); | ||
1305 | |||
1306 | host->mrq->cmd->error = -ENOMEDIUM; | ||
1307 | if (host->mrq->stop) | ||
1308 | host->mrq->stop->error = -ENOMEDIUM; | ||
1309 | mmc_request_done(mmc, host->mrq); | ||
1310 | } | ||
1311 | mutex_unlock(&host->host_mutex); | ||
1312 | |||
1313 | mmc_remove_host(mmc); | ||
1314 | mmc_free_host(mmc); | ||
1315 | |||
1316 | platform_set_drvdata(pdev, NULL); | ||
1317 | |||
1318 | dev_dbg(&(pdev->dev), | ||
1319 | ": Realtek PCI-E SDMMC controller has been removed\n"); | ||
1320 | |||
1321 | return 0; | ||
1322 | } | ||
1323 | |||
1324 | static struct platform_device_id rtsx_pci_sdmmc_ids[] = { | ||
1325 | { | ||
1326 | .name = DRV_NAME_RTSX_PCI_SDMMC, | ||
1327 | }, { | ||
1328 | /* sentinel */ | ||
1329 | } | ||
1330 | }; | ||
1331 | MODULE_DEVICE_TABLE(platform, rtsx_pci_sdmmc_ids); | ||
1332 | |||
1333 | static struct platform_driver rtsx_pci_sdmmc_driver = { | ||
1334 | .probe = rtsx_pci_sdmmc_drv_probe, | ||
1335 | .remove = rtsx_pci_sdmmc_drv_remove, | ||
1336 | .id_table = rtsx_pci_sdmmc_ids, | ||
1337 | .suspend = rtsx_pci_sdmmc_suspend, | ||
1338 | .resume = rtsx_pci_sdmmc_resume, | ||
1339 | .driver = { | ||
1340 | .owner = THIS_MODULE, | ||
1341 | .name = DRV_NAME_RTSX_PCI_SDMMC, | ||
1342 | }, | ||
1343 | }; | ||
1344 | module_platform_driver(rtsx_pci_sdmmc_driver); | ||
1345 | |||
1346 | MODULE_LICENSE("GPL"); | ||
1347 | MODULE_AUTHOR("Wei WANG <wei_wang@realsil.com.cn>"); | ||
1348 | MODULE_DESCRIPTION("Realtek PCI-E SD/MMC Card Host Driver"); | ||
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 4b6e4e7aca8..0e60438ebe3 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig | |||
@@ -57,8 +57,8 @@ config PARPORT_SERIAL | |||
57 | will be called parport_serial. | 57 | will be called parport_serial. |
58 | 58 | ||
59 | config PARPORT_PC_FIFO | 59 | config PARPORT_PC_FIFO |
60 | bool "Use FIFO/DMA if available (EXPERIMENTAL)" | 60 | bool "Use FIFO/DMA if available" |
61 | depends on PARPORT_PC && EXPERIMENTAL | 61 | depends on PARPORT_PC |
62 | help | 62 | help |
63 | Many parallel port chipsets provide hardware that can speed up | 63 | Many parallel port chipsets provide hardware that can speed up |
64 | printing. Say Y here if you want to take advantage of that. | 64 | printing. Say Y here if you want to take advantage of that. |
@@ -70,8 +70,8 @@ config PARPORT_PC_FIFO | |||
70 | specify which IRQ/DMA to use. | 70 | specify which IRQ/DMA to use. |
71 | 71 | ||
72 | config PARPORT_PC_SUPERIO | 72 | config PARPORT_PC_SUPERIO |
73 | bool "SuperIO chipset support (EXPERIMENTAL)" | 73 | bool "SuperIO chipset support" |
74 | depends on PARPORT_PC && EXPERIMENTAL | 74 | depends on PARPORT_PC |
75 | help | 75 | help |
76 | Saying Y here enables some probes for Super-IO chipsets in order to | 76 | Saying Y here enables some probes for Super-IO chipsets in order to |
77 | find out things like base addresses, IRQ lines and DMA channels. It | 77 | find out things like base addresses, IRQ lines and DMA channels. It |
@@ -85,8 +85,8 @@ config PARPORT_PC_PCMCIA | |||
85 | ports. If unsure, say N. | 85 | ports. If unsure, say N. |
86 | 86 | ||
87 | config PARPORT_IP32 | 87 | config PARPORT_IP32 |
88 | tristate "SGI IP32 builtin port (EXPERIMENTAL)" | 88 | tristate "SGI IP32 builtin port" |
89 | depends on SGI_IP32 && EXPERIMENTAL | 89 | depends on SGI_IP32 |
90 | select PARPORT_NOT_PC | 90 | select PARPORT_NOT_PC |
91 | help | 91 | help |
92 | Say Y here if you need support for the parallel port on | 92 | Say Y here if you need support for the parallel port on |
@@ -126,8 +126,8 @@ config PARPORT_GSC | |||
126 | select PARPORT_NOT_PC | 126 | select PARPORT_NOT_PC |
127 | 127 | ||
128 | config PARPORT_SUNBPP | 128 | config PARPORT_SUNBPP |
129 | tristate "Sparc hardware (EXPERIMENTAL)" | 129 | tristate "Sparc hardware" |
130 | depends on SBUS && EXPERIMENTAL | 130 | depends on SBUS |
131 | select PARPORT_NOT_PC | 131 | select PARPORT_NOT_PC |
132 | help | 132 | help |
133 | This driver provides support for the bidirectional parallel port | 133 | This driver provides support for the bidirectional parallel port |
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 6f3ea9bbc81..82e2b89d448 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig | |||
@@ -44,6 +44,22 @@ config UIO_PDRV_GENIRQ | |||
44 | 44 | ||
45 | If you don't know what to do here, say N. | 45 | If you don't know what to do here, say N. |
46 | 46 | ||
47 | config UIO_DMEM_GENIRQ | ||
48 | tristate "Userspace platform driver with generic irq and dynamic memory" | ||
49 | help | ||
50 | Platform driver for Userspace I/O devices, including generic | ||
51 | interrupt handling code. Shared interrupts are not supported. | ||
52 | |||
53 | Memory regions can be specified with the same platform device | ||
54 | resources as the UIO_PDRV drivers, but dynamic regions can also | ||
55 | be specified. | ||
56 | The number and size of these regions is static, | ||
57 | but the memory allocation is not performed until | ||
58 | the associated device file is opened. The | ||
59 | memory is freed once the uio device is closed. | ||
60 | |||
61 | If you don't know what to do here, say N. | ||
62 | |||
47 | config UIO_AEC | 63 | config UIO_AEC |
48 | tristate "AEC video timestamp device" | 64 | tristate "AEC video timestamp device" |
49 | depends on PCI | 65 | depends on PCI |
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index d4dd9a5552f..b354c539507 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile | |||
@@ -2,6 +2,7 @@ obj-$(CONFIG_UIO) += uio.o | |||
2 | obj-$(CONFIG_UIO_CIF) += uio_cif.o | 2 | obj-$(CONFIG_UIO_CIF) += uio_cif.o |
3 | obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o | 3 | obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o |
4 | obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o | 4 | obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o |
5 | obj-$(CONFIG_UIO_DMEM_GENIRQ) += uio_dmem_genirq.o | ||
5 | obj-$(CONFIG_UIO_AEC) += uio_aec.o | 6 | obj-$(CONFIG_UIO_AEC) += uio_aec.o |
6 | obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o | 7 | obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o |
7 | obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o | 8 | obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o |
diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c index 72b22d44e8b..1548982db58 100644 --- a/drivers/uio/uio_aec.c +++ b/drivers/uio/uio_aec.c | |||
@@ -78,7 +78,7 @@ static void print_board_data(struct pci_dev *pdev, struct uio_info *i) | |||
78 | ioread8(i->priv + 0x07)); | 78 | ioread8(i->priv + 0x07)); |
79 | } | 79 | } |
80 | 80 | ||
81 | static int __devinit probe(struct pci_dev *pdev, const struct pci_device_id *id) | 81 | static int probe(struct pci_dev *pdev, const struct pci_device_id *id) |
82 | { | 82 | { |
83 | struct uio_info *info; | 83 | struct uio_info *info; |
84 | int ret; | 84 | int ret; |
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index a84a451159e..7dd6fc60539 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c | |||
@@ -40,7 +40,7 @@ static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info) | |||
40 | return IRQ_HANDLED; | 40 | return IRQ_HANDLED; |
41 | } | 41 | } |
42 | 42 | ||
43 | static int __devinit hilscher_pci_probe(struct pci_dev *dev, | 43 | static int hilscher_pci_probe(struct pci_dev *dev, |
44 | const struct pci_device_id *id) | 44 | const struct pci_device_id *id) |
45 | { | 45 | { |
46 | struct uio_info *info; | 46 | struct uio_info *info; |
@@ -112,7 +112,7 @@ static void hilscher_pci_remove(struct pci_dev *dev) | |||
112 | kfree (info); | 112 | kfree (info); |
113 | } | 113 | } |
114 | 114 | ||
115 | static struct pci_device_id hilscher_pci_ids[] __devinitdata = { | 115 | static struct pci_device_id hilscher_pci_ids[] = { |
116 | { | 116 | { |
117 | .vendor = PCI_VENDOR_ID_PLX, | 117 | .vendor = PCI_VENDOR_ID_PLX, |
118 | .device = PCI_DEVICE_ID_PLX_9030, | 118 | .device = PCI_DEVICE_ID_PLX_9030, |
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c new file mode 100644 index 00000000000..252434c9ea9 --- /dev/null +++ b/drivers/uio/uio_dmem_genirq.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /* | ||
2 | * drivers/uio/uio_dmem_genirq.c | ||
3 | * | ||
4 | * Userspace I/O platform driver with generic IRQ handling code. | ||
5 | * | ||
6 | * Copyright (C) 2012 Damian Hobson-Garcia | ||
7 | * | ||
8 | * Based on uio_pdrv_genirq.c by Magnus Damm | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/uio_driver.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/bitops.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/platform_data/uio_dmem_genirq.h> | ||
22 | #include <linux/stringify.h> | ||
23 | #include <linux/pm_runtime.h> | ||
24 | #include <linux/dma-mapping.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include <linux/of.h> | ||
28 | #include <linux/of_platform.h> | ||
29 | #include <linux/of_address.h> | ||
30 | |||
31 | #define DRIVER_NAME "uio_dmem_genirq" | ||
32 | #define DMEM_MAP_ERROR (~0) | ||
33 | |||
34 | struct uio_dmem_genirq_platdata { | ||
35 | struct uio_info *uioinfo; | ||
36 | spinlock_t lock; | ||
37 | unsigned long flags; | ||
38 | struct platform_device *pdev; | ||
39 | unsigned int dmem_region_start; | ||
40 | unsigned int num_dmem_regions; | ||
41 | void *dmem_region_vaddr[MAX_UIO_MAPS]; | ||
42 | struct mutex alloc_lock; | ||
43 | unsigned int refcnt; | ||
44 | }; | ||
45 | |||
46 | static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode) | ||
47 | { | ||
48 | struct uio_dmem_genirq_platdata *priv = info->priv; | ||
49 | struct uio_mem *uiomem; | ||
50 | int ret = 0; | ||
51 | int dmem_region = priv->dmem_region_start; | ||
52 | |||
53 | uiomem = &priv->uioinfo->mem[priv->dmem_region_start]; | ||
54 | |||
55 | mutex_lock(&priv->alloc_lock); | ||
56 | while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) { | ||
57 | void *addr; | ||
58 | if (!uiomem->size) | ||
59 | break; | ||
60 | |||
61 | addr = dma_alloc_coherent(&priv->pdev->dev, uiomem->size, | ||
62 | (dma_addr_t *)&uiomem->addr, GFP_KERNEL); | ||
63 | if (!addr) { | ||
64 | uiomem->addr = DMEM_MAP_ERROR; | ||
65 | } | ||
66 | priv->dmem_region_vaddr[dmem_region++] = addr; | ||
67 | ++uiomem; | ||
68 | } | ||
69 | priv->refcnt++; | ||
70 | |||
71 | mutex_unlock(&priv->alloc_lock); | ||
72 | /* Wait until the Runtime PM code has woken up the device */ | ||
73 | pm_runtime_get_sync(&priv->pdev->dev); | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode) | ||
78 | { | ||
79 | struct uio_dmem_genirq_platdata *priv = info->priv; | ||
80 | struct uio_mem *uiomem; | ||
81 | int dmem_region = priv->dmem_region_start; | ||
82 | |||
83 | /* Tell the Runtime PM code that the device has become idle */ | ||
84 | pm_runtime_put_sync(&priv->pdev->dev); | ||
85 | |||
86 | uiomem = &priv->uioinfo->mem[priv->dmem_region_start]; | ||
87 | |||
88 | mutex_lock(&priv->alloc_lock); | ||
89 | |||
90 | priv->refcnt--; | ||
91 | while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) { | ||
92 | if (!uiomem->size) | ||
93 | break; | ||
94 | if (priv->dmem_region_vaddr[dmem_region]) { | ||
95 | dma_free_coherent(&priv->pdev->dev, uiomem->size, | ||
96 | priv->dmem_region_vaddr[dmem_region], | ||
97 | uiomem->addr); | ||
98 | } | ||
99 | uiomem->addr = DMEM_MAP_ERROR; | ||
100 | ++dmem_region; | ||
101 | ++uiomem; | ||
102 | } | ||
103 | |||
104 | mutex_unlock(&priv->alloc_lock); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static irqreturn_t uio_dmem_genirq_handler(int irq, struct uio_info *dev_info) | ||
109 | { | ||
110 | struct uio_dmem_genirq_platdata *priv = dev_info->priv; | ||
111 | |||
112 | /* Just disable the interrupt in the interrupt controller, and | ||
113 | * remember the state so we can allow user space to enable it later. | ||
114 | */ | ||
115 | |||
116 | if (!test_and_set_bit(0, &priv->flags)) | ||
117 | disable_irq_nosync(irq); | ||
118 | |||
119 | return IRQ_HANDLED; | ||
120 | } | ||
121 | |||
122 | static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) | ||
123 | { | ||
124 | struct uio_dmem_genirq_platdata *priv = dev_info->priv; | ||
125 | unsigned long flags; | ||
126 | |||
127 | /* Allow user space to enable and disable the interrupt | ||
128 | * in the interrupt controller, but keep track of the | ||
129 | * state to prevent per-irq depth damage. | ||
130 | * | ||
131 | * Serialize this operation to support multiple tasks. | ||
132 | */ | ||
133 | |||
134 | spin_lock_irqsave(&priv->lock, flags); | ||
135 | if (irq_on) { | ||
136 | if (test_and_clear_bit(0, &priv->flags)) | ||
137 | enable_irq(dev_info->irq); | ||
138 | } else { | ||
139 | if (!test_and_set_bit(0, &priv->flags)) | ||
140 | disable_irq(dev_info->irq); | ||
141 | } | ||
142 | spin_unlock_irqrestore(&priv->lock, flags); | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static int uio_dmem_genirq_probe(struct platform_device *pdev) | ||
148 | { | ||
149 | struct uio_dmem_genirq_pdata *pdata = pdev->dev.platform_data; | ||
150 | struct uio_info *uioinfo = &pdata->uioinfo; | ||
151 | struct uio_dmem_genirq_platdata *priv; | ||
152 | struct uio_mem *uiomem; | ||
153 | int ret = -EINVAL; | ||
154 | int i; | ||
155 | |||
156 | if (pdev->dev.of_node) { | ||
157 | int irq; | ||
158 | |||
159 | /* alloc uioinfo for one device */ | ||
160 | uioinfo = kzalloc(sizeof(*uioinfo), GFP_KERNEL); | ||
161 | if (!uioinfo) { | ||
162 | ret = -ENOMEM; | ||
163 | dev_err(&pdev->dev, "unable to kmalloc\n"); | ||
164 | goto bad2; | ||
165 | } | ||
166 | uioinfo->name = pdev->dev.of_node->name; | ||
167 | uioinfo->version = "devicetree"; | ||
168 | |||
169 | /* Multiple IRQs are not supported */ | ||
170 | irq = platform_get_irq(pdev, 0); | ||
171 | if (irq == -ENXIO) | ||
172 | uioinfo->irq = UIO_IRQ_NONE; | ||
173 | else | ||
174 | uioinfo->irq = irq; | ||
175 | } | ||
176 | |||
177 | if (!uioinfo || !uioinfo->name || !uioinfo->version) { | ||
178 | dev_err(&pdev->dev, "missing platform_data\n"); | ||
179 | goto bad0; | ||
180 | } | ||
181 | |||
182 | if (uioinfo->handler || uioinfo->irqcontrol || | ||
183 | uioinfo->irq_flags & IRQF_SHARED) { | ||
184 | dev_err(&pdev->dev, "interrupt configuration error\n"); | ||
185 | goto bad0; | ||
186 | } | ||
187 | |||
188 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
189 | if (!priv) { | ||
190 | ret = -ENOMEM; | ||
191 | dev_err(&pdev->dev, "unable to kmalloc\n"); | ||
192 | goto bad0; | ||
193 | } | ||
194 | |||
195 | dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); | ||
196 | |||
197 | priv->uioinfo = uioinfo; | ||
198 | spin_lock_init(&priv->lock); | ||
199 | priv->flags = 0; /* interrupt is enabled to begin with */ | ||
200 | priv->pdev = pdev; | ||
201 | mutex_init(&priv->alloc_lock); | ||
202 | |||
203 | if (!uioinfo->irq) { | ||
204 | ret = platform_get_irq(pdev, 0); | ||
205 | if (ret < 0) { | ||
206 | dev_err(&pdev->dev, "failed to get IRQ\n"); | ||
207 | goto bad0; | ||
208 | } | ||
209 | uioinfo->irq = ret; | ||
210 | } | ||
211 | uiomem = &uioinfo->mem[0]; | ||
212 | |||
213 | for (i = 0; i < pdev->num_resources; ++i) { | ||
214 | struct resource *r = &pdev->resource[i]; | ||
215 | |||
216 | if (r->flags != IORESOURCE_MEM) | ||
217 | continue; | ||
218 | |||
219 | if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { | ||
220 | dev_warn(&pdev->dev, "device has more than " | ||
221 | __stringify(MAX_UIO_MAPS) | ||
222 | " I/O memory resources.\n"); | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | uiomem->memtype = UIO_MEM_PHYS; | ||
227 | uiomem->addr = r->start; | ||
228 | uiomem->size = resource_size(r); | ||
229 | ++uiomem; | ||
230 | } | ||
231 | |||
232 | priv->dmem_region_start = i; | ||
233 | priv->num_dmem_regions = pdata->num_dynamic_regions; | ||
234 | |||
235 | for (i = 0; i < pdata->num_dynamic_regions; ++i) { | ||
236 | if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { | ||
237 | dev_warn(&pdev->dev, "device has more than " | ||
238 | __stringify(MAX_UIO_MAPS) | ||
239 | " dynamic and fixed memory regions.\n"); | ||
240 | break; | ||
241 | } | ||
242 | uiomem->memtype = UIO_MEM_PHYS; | ||
243 | uiomem->addr = DMEM_MAP_ERROR; | ||
244 | uiomem->size = pdata->dynamic_region_sizes[i]; | ||
245 | ++uiomem; | ||
246 | } | ||
247 | |||
248 | while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) { | ||
249 | uiomem->size = 0; | ||
250 | ++uiomem; | ||
251 | } | ||
252 | |||
253 | /* This driver requires no hardware specific kernel code to handle | ||
254 | * interrupts. Instead, the interrupt handler simply disables the | ||
255 | * interrupt in the interrupt controller. User space is responsible | ||
256 | * for performing hardware specific acknowledge and re-enabling of | ||
257 | * the interrupt in the interrupt controller. | ||
258 | * | ||
259 | * Interrupt sharing is not supported. | ||
260 | */ | ||
261 | |||
262 | uioinfo->handler = uio_dmem_genirq_handler; | ||
263 | uioinfo->irqcontrol = uio_dmem_genirq_irqcontrol; | ||
264 | uioinfo->open = uio_dmem_genirq_open; | ||
265 | uioinfo->release = uio_dmem_genirq_release; | ||
266 | uioinfo->priv = priv; | ||
267 | |||
268 | /* Enable Runtime PM for this device: | ||
269 | * The device starts in suspended state to allow the hardware to be | ||
270 | * turned off by default. The Runtime PM bus code should power on the | ||
271 | * hardware and enable clocks at open(). | ||
272 | */ | ||
273 | pm_runtime_enable(&pdev->dev); | ||
274 | |||
275 | ret = uio_register_device(&pdev->dev, priv->uioinfo); | ||
276 | if (ret) { | ||
277 | dev_err(&pdev->dev, "unable to register uio device\n"); | ||
278 | goto bad1; | ||
279 | } | ||
280 | |||
281 | platform_set_drvdata(pdev, priv); | ||
282 | return 0; | ||
283 | bad1: | ||
284 | kfree(priv); | ||
285 | pm_runtime_disable(&pdev->dev); | ||
286 | bad0: | ||
287 | /* kfree uioinfo for OF */ | ||
288 | if (pdev->dev.of_node) | ||
289 | kfree(uioinfo); | ||
290 | bad2: | ||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | static int uio_dmem_genirq_remove(struct platform_device *pdev) | ||
295 | { | ||
296 | struct uio_dmem_genirq_platdata *priv = platform_get_drvdata(pdev); | ||
297 | |||
298 | uio_unregister_device(priv->uioinfo); | ||
299 | pm_runtime_disable(&pdev->dev); | ||
300 | |||
301 | priv->uioinfo->handler = NULL; | ||
302 | priv->uioinfo->irqcontrol = NULL; | ||
303 | |||
304 | /* kfree uioinfo for OF */ | ||
305 | if (pdev->dev.of_node) | ||
306 | kfree(priv->uioinfo); | ||
307 | |||
308 | kfree(priv); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int uio_dmem_genirq_runtime_nop(struct device *dev) | ||
313 | { | ||
314 | /* Runtime PM callback shared between ->runtime_suspend() | ||
315 | * and ->runtime_resume(). Simply returns success. | ||
316 | * | ||
317 | * In this driver pm_runtime_get_sync() and pm_runtime_put_sync() | ||
318 | * are used at open() and release() time. This allows the | ||
319 | * Runtime PM code to turn off power to the device while the | ||
320 | * device is unused, ie before open() and after release(). | ||
321 | * | ||
322 | * This Runtime PM callback does not need to save or restore | ||
323 | * any registers since user space is responsbile for hardware | ||
324 | * register reinitialization after open(). | ||
325 | */ | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static const struct dev_pm_ops uio_dmem_genirq_dev_pm_ops = { | ||
330 | .runtime_suspend = uio_dmem_genirq_runtime_nop, | ||
331 | .runtime_resume = uio_dmem_genirq_runtime_nop, | ||
332 | }; | ||
333 | |||
334 | #ifdef CONFIG_OF | ||
335 | static const struct of_device_id uio_of_genirq_match[] = { | ||
336 | { /* empty for now */ }, | ||
337 | }; | ||
338 | MODULE_DEVICE_TABLE(of, uio_of_genirq_match); | ||
339 | #else | ||
340 | # define uio_of_genirq_match NULL | ||
341 | #endif | ||
342 | |||
343 | static struct platform_driver uio_dmem_genirq = { | ||
344 | .probe = uio_dmem_genirq_probe, | ||
345 | .remove = uio_dmem_genirq_remove, | ||
346 | .driver = { | ||
347 | .name = DRIVER_NAME, | ||
348 | .owner = THIS_MODULE, | ||
349 | .pm = &uio_dmem_genirq_dev_pm_ops, | ||
350 | .of_match_table = uio_of_genirq_match, | ||
351 | }, | ||
352 | }; | ||
353 | |||
354 | module_platform_driver(uio_dmem_genirq); | ||
355 | |||
356 | MODULE_AUTHOR("Damian Hobson-Garcia"); | ||
357 | MODULE_DESCRIPTION("Userspace I/O platform driver with dynamic memory."); | ||
358 | MODULE_LICENSE("GPL v2"); | ||
359 | MODULE_ALIAS("platform:" DRIVER_NAME); | ||
diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index a879fd5741f..6a4ba5e83e3 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c | |||
@@ -48,7 +48,7 @@ static irqreturn_t netx_handler(int irq, struct uio_info *dev_info) | |||
48 | return IRQ_HANDLED; | 48 | return IRQ_HANDLED; |
49 | } | 49 | } |
50 | 50 | ||
51 | static int __devinit netx_pci_probe(struct pci_dev *dev, | 51 | static int netx_pci_probe(struct pci_dev *dev, |
52 | const struct pci_device_id *id) | 52 | const struct pci_device_id *id) |
53 | { | 53 | { |
54 | struct uio_info *info; | 54 | struct uio_info *info; |
diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index 0bd08ef2b39..14aa10c1f6d 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c | |||
@@ -53,7 +53,7 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info) | |||
53 | return IRQ_HANDLED; | 53 | return IRQ_HANDLED; |
54 | } | 54 | } |
55 | 55 | ||
56 | static int __devinit probe(struct pci_dev *pdev, | 56 | static int probe(struct pci_dev *pdev, |
57 | const struct pci_device_id *id) | 57 | const struct pci_device_id *id) |
58 | { | 58 | { |
59 | struct uio_pci_generic_dev *gdev; | 59 | struct uio_pci_generic_dev *gdev; |
diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c index 72d3646c736..39be9e06170 100644 --- a/drivers/uio/uio_pdrv.c +++ b/drivers/uio/uio_pdrv.c | |||
@@ -60,6 +60,7 @@ static int uio_pdrv_probe(struct platform_device *pdev) | |||
60 | uiomem->memtype = UIO_MEM_PHYS; | 60 | uiomem->memtype = UIO_MEM_PHYS; |
61 | uiomem->addr = r->start; | 61 | uiomem->addr = r->start; |
62 | uiomem->size = resource_size(r); | 62 | uiomem->size = resource_size(r); |
63 | uiomem->name = r->name; | ||
63 | ++uiomem; | 64 | ++uiomem; |
64 | } | 65 | } |
65 | 66 | ||
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 42202cd8315..c122bca669b 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c | |||
@@ -102,7 +102,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) | |||
102 | int ret = -EINVAL; | 102 | int ret = -EINVAL; |
103 | int i; | 103 | int i; |
104 | 104 | ||
105 | if (!uioinfo) { | 105 | if (pdev->dev.of_node) { |
106 | int irq; | 106 | int irq; |
107 | 107 | ||
108 | /* alloc uioinfo for one device */ | 108 | /* alloc uioinfo for one device */ |
@@ -172,6 +172,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) | |||
172 | uiomem->memtype = UIO_MEM_PHYS; | 172 | uiomem->memtype = UIO_MEM_PHYS; |
173 | uiomem->addr = r->start; | 173 | uiomem->addr = r->start; |
174 | uiomem->size = resource_size(r); | 174 | uiomem->size = resource_size(r); |
175 | uiomem->name = r->name; | ||
175 | ++uiomem; | 176 | ++uiomem; |
176 | } | 177 | } |
177 | 178 | ||
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index 33a7a273b45..cce0f78341c 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c | |||
@@ -112,7 +112,7 @@ static void pruss_cleanup(struct platform_device *dev, | |||
112 | kfree(gdev); | 112 | kfree(gdev); |
113 | } | 113 | } |
114 | 114 | ||
115 | static int __devinit pruss_probe(struct platform_device *dev) | 115 | static int pruss_probe(struct platform_device *dev) |
116 | { | 116 | { |
117 | struct uio_info *p; | 117 | struct uio_info *p; |
118 | struct uio_pruss_dev *gdev; | 118 | struct uio_pruss_dev *gdev; |
@@ -209,7 +209,7 @@ out_free: | |||
209 | return ret; | 209 | return ret; |
210 | } | 210 | } |
211 | 211 | ||
212 | static int __devexit pruss_remove(struct platform_device *dev) | 212 | static int pruss_remove(struct platform_device *dev) |
213 | { | 213 | { |
214 | struct uio_pruss_dev *gdev = platform_get_drvdata(dev); | 214 | struct uio_pruss_dev *gdev = platform_get_drvdata(dev); |
215 | 215 | ||
@@ -220,7 +220,7 @@ static int __devexit pruss_remove(struct platform_device *dev) | |||
220 | 220 | ||
221 | static struct platform_driver pruss_driver = { | 221 | static struct platform_driver pruss_driver = { |
222 | .probe = pruss_probe, | 222 | .probe = pruss_probe, |
223 | .remove = __devexit_p(pruss_remove), | 223 | .remove = pruss_remove, |
224 | .driver = { | 224 | .driver = { |
225 | .name = DRV_NAME, | 225 | .name = DRV_NAME, |
226 | .owner = THIS_MODULE, | 226 | .owner = THIS_MODULE, |
diff --git a/drivers/uio/uio_sercos3.c b/drivers/uio/uio_sercos3.c index a187fa14c5c..81a10a56312 100644 --- a/drivers/uio/uio_sercos3.c +++ b/drivers/uio/uio_sercos3.c | |||
@@ -116,7 +116,7 @@ static int sercos3_setup_iomem(struct pci_dev *dev, struct uio_info *info, | |||
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
118 | 118 | ||
119 | static int __devinit sercos3_pci_probe(struct pci_dev *dev, | 119 | static int sercos3_pci_probe(struct pci_dev *dev, |
120 | const struct pci_device_id *id) | 120 | const struct pci_device_id *id) |
121 | { | 121 | { |
122 | struct uio_info *info; | 122 | struct uio_info *info; |
@@ -197,7 +197,7 @@ static void sercos3_pci_remove(struct pci_dev *dev) | |||
197 | kfree(info); | 197 | kfree(info); |
198 | } | 198 | } |
199 | 199 | ||
200 | static struct pci_device_id sercos3_pci_ids[] __devinitdata = { | 200 | static struct pci_device_id sercos3_pci_ids[] = { |
201 | { | 201 | { |
202 | .vendor = PCI_VENDOR_ID_PLX, | 202 | .vendor = PCI_VENDOR_ID_PLX, |
203 | .device = PCI_DEVICE_ID_PLX_9030, | 203 | .device = PCI_DEVICE_ID_PLX_9030, |
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 7e984034a11..c433a746e3f 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig | |||
@@ -26,7 +26,7 @@ config W1_MASTER_DS2490 | |||
26 | 26 | ||
27 | config W1_MASTER_DS2482 | 27 | config W1_MASTER_DS2482 |
28 | tristate "Maxim DS2482 I2C to 1-Wire bridge" | 28 | tristate "Maxim DS2482 I2C to 1-Wire bridge" |
29 | depends on I2C && EXPERIMENTAL | 29 | depends on I2C |
30 | help | 30 | help |
31 | If you say yes here you get support for the Maxim DS2482 | 31 | If you say yes here you get support for the Maxim DS2482 |
32 | I2C to 1-Wire bridge. | 32 | I2C to 1-Wire bridge. |
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index e5f74416d4b..6429b9e9fb8 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c | |||
@@ -505,19 +505,8 @@ static int ds2482_remove(struct i2c_client *client) | |||
505 | return 0; | 505 | return 0; |
506 | } | 506 | } |
507 | 507 | ||
508 | static int __init sensors_ds2482_init(void) | 508 | module_i2c_driver(ds2482_driver); |
509 | { | ||
510 | return i2c_add_driver(&ds2482_driver); | ||
511 | } | ||
512 | |||
513 | static void __exit sensors_ds2482_exit(void) | ||
514 | { | ||
515 | i2c_del_driver(&ds2482_driver); | ||
516 | } | ||
517 | 509 | ||
518 | MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); | 510 | MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); |
519 | MODULE_DESCRIPTION("DS2482 driver"); | 511 | MODULE_DESCRIPTION("DS2482 driver"); |
520 | MODULE_LICENSE("GPL"); | 512 | MODULE_LICENSE("GPL"); |
521 | |||
522 | module_init(sensors_ds2482_init); | ||
523 | module_exit(sensors_ds2482_exit); | ||
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index f667c26b219..d8667b0212d 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c | |||
@@ -48,14 +48,14 @@ static struct pci_device_id matrox_w1_tbl[] = { | |||
48 | }; | 48 | }; |
49 | MODULE_DEVICE_TABLE(pci, matrox_w1_tbl); | 49 | MODULE_DEVICE_TABLE(pci, matrox_w1_tbl); |
50 | 50 | ||
51 | static int __devinit matrox_w1_probe(struct pci_dev *, const struct pci_device_id *); | 51 | static int matrox_w1_probe(struct pci_dev *, const struct pci_device_id *); |
52 | static void __devexit matrox_w1_remove(struct pci_dev *); | 52 | static void matrox_w1_remove(struct pci_dev *); |
53 | 53 | ||
54 | static struct pci_driver matrox_w1_pci_driver = { | 54 | static struct pci_driver matrox_w1_pci_driver = { |
55 | .name = "matrox_w1", | 55 | .name = "matrox_w1", |
56 | .id_table = matrox_w1_tbl, | 56 | .id_table = matrox_w1_tbl, |
57 | .probe = matrox_w1_probe, | 57 | .probe = matrox_w1_probe, |
58 | .remove = __devexit_p(matrox_w1_remove), | 58 | .remove = matrox_w1_remove, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | /* | 61 | /* |
@@ -152,7 +152,7 @@ static void matrox_w1_hw_init(struct matrox_device *dev) | |||
152 | matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00); | 152 | matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00); |
153 | } | 153 | } |
154 | 154 | ||
155 | static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 155 | static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
156 | { | 156 | { |
157 | struct matrox_device *dev; | 157 | struct matrox_device *dev; |
158 | int err; | 158 | int err; |
@@ -220,7 +220,7 @@ err_out_free_device: | |||
220 | return err; | 220 | return err; |
221 | } | 221 | } |
222 | 222 | ||
223 | static void __devexit matrox_w1_remove(struct pci_dev *pdev) | 223 | static void matrox_w1_remove(struct pci_dev *pdev) |
224 | { | 224 | { |
225 | struct matrox_device *dev = pci_get_drvdata(pdev); | 225 | struct matrox_device *dev = pci_get_drvdata(pdev); |
226 | 226 | ||
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 1cc61a700fa..d338b56ea2f 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c | |||
@@ -103,7 +103,7 @@ static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit) | |||
103 | return ((__raw_readb(ctrl_addr)) >> 3) & 0x1; | 103 | return ((__raw_readb(ctrl_addr)) >> 3) & 0x1; |
104 | } | 104 | } |
105 | 105 | ||
106 | static int __devinit mxc_w1_probe(struct platform_device *pdev) | 106 | static int mxc_w1_probe(struct platform_device *pdev) |
107 | { | 107 | { |
108 | struct mxc_w1_device *mdev; | 108 | struct mxc_w1_device *mdev; |
109 | struct resource *res; | 109 | struct resource *res; |
@@ -117,9 +117,9 @@ static int __devinit mxc_w1_probe(struct platform_device *pdev) | |||
117 | if (!mdev) | 117 | if (!mdev) |
118 | return -ENOMEM; | 118 | return -ENOMEM; |
119 | 119 | ||
120 | mdev->clk = clk_get(&pdev->dev, "owire"); | 120 | mdev->clk = clk_get(&pdev->dev, NULL); |
121 | if (!mdev->clk) { | 121 | if (IS_ERR(mdev->clk)) { |
122 | err = -ENODEV; | 122 | err = PTR_ERR(mdev->clk); |
123 | goto failed_clk; | 123 | goto failed_clk; |
124 | } | 124 | } |
125 | 125 | ||
@@ -134,7 +134,7 @@ static int __devinit mxc_w1_probe(struct platform_device *pdev) | |||
134 | 134 | ||
135 | mdev->regs = ioremap(res->start, resource_size(res)); | 135 | mdev->regs = ioremap(res->start, resource_size(res)); |
136 | if (!mdev->regs) { | 136 | if (!mdev->regs) { |
137 | printk(KERN_ERR "Cannot map frame buffer registers\n"); | 137 | dev_err(&pdev->dev, "Cannot map mxc_w1 registers\n"); |
138 | goto failed_ioremap; | 138 | goto failed_ioremap; |
139 | } | 139 | } |
140 | 140 | ||
@@ -167,7 +167,7 @@ failed_clk: | |||
167 | /* | 167 | /* |
168 | * disassociate the w1 device from the driver | 168 | * disassociate the w1 device from the driver |
169 | */ | 169 | */ |
170 | static int __devexit mxc_w1_remove(struct platform_device *pdev) | 170 | static int mxc_w1_remove(struct platform_device *pdev) |
171 | { | 171 | { |
172 | struct mxc_w1_device *mdev = platform_get_drvdata(pdev); | 172 | struct mxc_w1_device *mdev = platform_get_drvdata(pdev); |
173 | struct resource *res; | 173 | struct resource *res; |
@@ -191,21 +191,9 @@ static struct platform_driver mxc_w1_driver = { | |||
191 | .name = "mxc_w1", | 191 | .name = "mxc_w1", |
192 | }, | 192 | }, |
193 | .probe = mxc_w1_probe, | 193 | .probe = mxc_w1_probe, |
194 | .remove = mxc_w1_remove, | 194 | .remove = __devexit_p(mxc_w1_remove), |
195 | }; | 195 | }; |
196 | 196 | module_platform_driver(mxc_w1_driver); | |
197 | static int __init mxc_w1_init(void) | ||
198 | { | ||
199 | return platform_driver_register(&mxc_w1_driver); | ||
200 | } | ||
201 | |||
202 | static void mxc_w1_exit(void) | ||
203 | { | ||
204 | platform_driver_unregister(&mxc_w1_driver); | ||
205 | } | ||
206 | |||
207 | module_init(mxc_w1_init); | ||
208 | module_exit(mxc_w1_exit); | ||
209 | 197 | ||
210 | MODULE_LICENSE("GPL"); | 198 | MODULE_LICENSE("GPL"); |
211 | MODULE_AUTHOR("Freescale Semiconductors Inc"); | 199 | MODULE_AUTHOR("Freescale Semiconductors Inc"); |
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index ca8e60bb2f9..184dbce4abd 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c | |||
@@ -69,12 +69,12 @@ struct hdq_data { | |||
69 | int init_trans; | 69 | int init_trans; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static int __devinit omap_hdq_probe(struct platform_device *pdev); | 72 | static int omap_hdq_probe(struct platform_device *pdev); |
73 | static int __devexit omap_hdq_remove(struct platform_device *pdev); | 73 | static int omap_hdq_remove(struct platform_device *pdev); |
74 | 74 | ||
75 | static struct platform_driver omap_hdq_driver = { | 75 | static struct platform_driver omap_hdq_driver = { |
76 | .probe = omap_hdq_probe, | 76 | .probe = omap_hdq_probe, |
77 | .remove = __devexit_p(omap_hdq_remove), | 77 | .remove = omap_hdq_remove, |
78 | .driver = { | 78 | .driver = { |
79 | .name = "omap_hdq", | 79 | .name = "omap_hdq", |
80 | }, | 80 | }, |
@@ -537,7 +537,7 @@ static void omap_w1_write_byte(void *_hdq, u8 byte) | |||
537 | } | 537 | } |
538 | } | 538 | } |
539 | 539 | ||
540 | static int __devinit omap_hdq_probe(struct platform_device *pdev) | 540 | static int omap_hdq_probe(struct platform_device *pdev) |
541 | { | 541 | { |
542 | struct device *dev = &pdev->dev; | 542 | struct device *dev = &pdev->dev; |
543 | struct hdq_data *hdq_data; | 543 | struct hdq_data *hdq_data; |
@@ -613,7 +613,7 @@ err_w1: | |||
613 | return ret; | 613 | return ret; |
614 | } | 614 | } |
615 | 615 | ||
616 | static int __devexit omap_hdq_remove(struct platform_device *pdev) | 616 | static int omap_hdq_remove(struct platform_device *pdev) |
617 | { | 617 | { |
618 | struct hdq_data *hdq_data = platform_get_drvdata(pdev); | 618 | struct hdq_data *hdq_data = platform_get_drvdata(pdev); |
619 | 619 | ||
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index 6012c4ea320..85b363a5bd0 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c | |||
@@ -16,6 +16,9 @@ | |||
16 | #include <linux/gpio.h> | 16 | #include <linux/gpio.h> |
17 | #include <linux/of_platform.h> | 17 | #include <linux/of_platform.h> |
18 | #include <linux/of_gpio.h> | 18 | #include <linux/of_gpio.h> |
19 | #include <linux/pinctrl/consumer.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/of.h> | ||
19 | 22 | ||
20 | #include "../w1.h" | 23 | #include "../w1.h" |
21 | #include "../w1_int.h" | 24 | #include "../w1_int.h" |
@@ -44,7 +47,6 @@ static u8 w1_gpio_read_bit(void *data) | |||
44 | return gpio_get_value(pdata->pin) ? 1 : 0; | 47 | return gpio_get_value(pdata->pin) ? 1 : 0; |
45 | } | 48 | } |
46 | 49 | ||
47 | #ifdef CONFIG_OF | ||
48 | static struct of_device_id w1_gpio_dt_ids[] = { | 50 | static struct of_device_id w1_gpio_dt_ids[] = { |
49 | { .compatible = "w1-gpio" }, | 51 | { .compatible = "w1-gpio" }, |
50 | {} | 52 | {} |
@@ -55,11 +57,6 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) | |||
55 | { | 57 | { |
56 | struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; | 58 | struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; |
57 | struct device_node *np = pdev->dev.of_node; | 59 | struct device_node *np = pdev->dev.of_node; |
58 | const struct of_device_id *of_id = | ||
59 | of_match_device(w1_gpio_dt_ids, &pdev->dev); | ||
60 | |||
61 | if (!of_id) | ||
62 | return 0; | ||
63 | 60 | ||
64 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | 61 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
65 | if (!pdata) | 62 | if (!pdata) |
@@ -74,41 +71,53 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) | |||
74 | 71 | ||
75 | return 0; | 72 | return 0; |
76 | } | 73 | } |
77 | #else | ||
78 | static int w1_gpio_probe_dt(struct platform_device *pdev) | ||
79 | { | ||
80 | return 0; | ||
81 | } | ||
82 | #endif | ||
83 | 74 | ||
84 | static int __init w1_gpio_probe(struct platform_device *pdev) | 75 | static int __init w1_gpio_probe(struct platform_device *pdev) |
85 | { | 76 | { |
86 | struct w1_bus_master *master; | 77 | struct w1_bus_master *master; |
87 | struct w1_gpio_platform_data *pdata; | 78 | struct w1_gpio_platform_data *pdata; |
79 | struct pinctrl *pinctrl; | ||
88 | int err; | 80 | int err; |
89 | 81 | ||
90 | err = w1_gpio_probe_dt(pdev); | 82 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); |
91 | if (err < 0) | 83 | if (IS_ERR(pinctrl)) |
92 | return err; | 84 | dev_warn(&pdev->dev, "unable to select pin group\n"); |
85 | |||
86 | if (of_have_populated_dt()) { | ||
87 | err = w1_gpio_probe_dt(pdev); | ||
88 | if (err < 0) { | ||
89 | dev_err(&pdev->dev, "Failed to parse DT\n"); | ||
90 | return err; | ||
91 | } | ||
92 | } | ||
93 | 93 | ||
94 | pdata = pdev->dev.platform_data; | 94 | pdata = pdev->dev.platform_data; |
95 | 95 | ||
96 | if (!pdata) | 96 | if (!pdata) { |
97 | dev_err(&pdev->dev, "No configuration data\n"); | ||
97 | return -ENXIO; | 98 | return -ENXIO; |
99 | } | ||
98 | 100 | ||
99 | master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL); | 101 | master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL); |
100 | if (!master) | 102 | if (!master) { |
103 | dev_err(&pdev->dev, "Out of memory\n"); | ||
101 | return -ENOMEM; | 104 | return -ENOMEM; |
105 | } | ||
102 | 106 | ||
103 | err = gpio_request(pdata->pin, "w1"); | 107 | err = gpio_request(pdata->pin, "w1"); |
104 | if (err) | 108 | if (err) { |
109 | dev_err(&pdev->dev, "gpio_request (pin) failed\n"); | ||
105 | goto free_master; | 110 | goto free_master; |
111 | } | ||
106 | 112 | ||
107 | if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { | 113 | if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { |
108 | err = gpio_request_one(pdata->ext_pullup_enable_pin, | 114 | err = gpio_request_one(pdata->ext_pullup_enable_pin, |
109 | GPIOF_INIT_LOW, "w1 pullup"); | 115 | GPIOF_INIT_LOW, "w1 pullup"); |
110 | if (err < 0) | 116 | if (err < 0) { |
117 | dev_err(&pdev->dev, "gpio_request_one " | ||
118 | "(ext_pullup_enable_pin) failed\n"); | ||
111 | goto free_gpio; | 119 | goto free_gpio; |
120 | } | ||
112 | } | 121 | } |
113 | 122 | ||
114 | master->data = pdata; | 123 | master->data = pdata; |
@@ -123,8 +132,10 @@ static int __init w1_gpio_probe(struct platform_device *pdev) | |||
123 | } | 132 | } |
124 | 133 | ||
125 | err = w1_add_master_device(master); | 134 | err = w1_add_master_device(master); |
126 | if (err) | 135 | if (err) { |
136 | dev_err(&pdev->dev, "w1_add_master device failed\n"); | ||
127 | goto free_gpio_ext_pu; | 137 | goto free_gpio_ext_pu; |
138 | } | ||
128 | 139 | ||
129 | if (pdata->enable_external_pullup) | 140 | if (pdata->enable_external_pullup) |
130 | pdata->enable_external_pullup(1); | 141 | pdata->enable_external_pullup(1); |
@@ -198,23 +209,13 @@ static struct platform_driver w1_gpio_driver = { | |||
198 | .owner = THIS_MODULE, | 209 | .owner = THIS_MODULE, |
199 | .of_match_table = of_match_ptr(w1_gpio_dt_ids), | 210 | .of_match_table = of_match_ptr(w1_gpio_dt_ids), |
200 | }, | 211 | }, |
212 | .probe = w1_gpio_probe, | ||
201 | .remove = __exit_p(w1_gpio_remove), | 213 | .remove = __exit_p(w1_gpio_remove), |
202 | .suspend = w1_gpio_suspend, | 214 | .suspend = w1_gpio_suspend, |
203 | .resume = w1_gpio_resume, | 215 | .resume = w1_gpio_resume, |
204 | }; | 216 | }; |
205 | 217 | ||
206 | static int __init w1_gpio_init(void) | 218 | module_platform_driver(w1_gpio_driver); |
207 | { | ||
208 | return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe); | ||
209 | } | ||
210 | |||
211 | static void __exit w1_gpio_exit(void) | ||
212 | { | ||
213 | platform_driver_unregister(&w1_gpio_driver); | ||
214 | } | ||
215 | |||
216 | module_init(w1_gpio_init); | ||
217 | module_exit(w1_gpio_exit); | ||
218 | 219 | ||
219 | MODULE_DESCRIPTION("GPIO w1 bus master driver"); | 220 | MODULE_DESCRIPTION("GPIO w1 bus master driver"); |
220 | MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); | 221 | MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); |
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 1a574370d2c..7994d933f04 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -551,7 +551,6 @@ void w1_destroy_master_attributes(struct w1_master *master) | |||
551 | sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); | 551 | sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); |
552 | } | 552 | } |
553 | 553 | ||
554 | #ifdef CONFIG_HOTPLUG | ||
555 | static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) | 554 | static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) |
556 | { | 555 | { |
557 | struct w1_master *md = NULL; | 556 | struct w1_master *md = NULL; |
@@ -587,12 +586,6 @@ static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
587 | end: | 586 | end: |
588 | return err; | 587 | return err; |
589 | } | 588 | } |
590 | #else | ||
591 | static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
592 | { | ||
593 | return 0; | ||
594 | } | ||
595 | #endif | ||
596 | 589 | ||
597 | static int __w1_attach_slave_device(struct w1_slave *sl) | 590 | static int __w1_attach_slave_device(struct w1_slave *sl) |
598 | { | 591 | { |
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c index 7d041cb6da2..2552d3e0a70 100644 --- a/drivers/xen/xen-selfballoon.c +++ b/drivers/xen/xen-selfballoon.c | |||
@@ -222,7 +222,7 @@ static void selfballoon_process(struct work_struct *work) | |||
222 | if (xen_selfballooning_enabled) { | 222 | if (xen_selfballooning_enabled) { |
223 | cur_pages = totalram_pages; | 223 | cur_pages = totalram_pages; |
224 | tgt_pages = cur_pages; /* default is no change */ | 224 | tgt_pages = cur_pages; /* default is no change */ |
225 | goal_pages = percpu_counter_read_positive(&vm_committed_as) + | 225 | goal_pages = vm_memory_committed() + |
226 | totalreserve_pages + | 226 | totalreserve_pages + |
227 | MB2PAGES(selfballoon_reserved_mb); | 227 | MB2PAGES(selfballoon_reserved_mb); |
228 | #ifdef CONFIG_FRONTSWAP | 228 | #ifdef CONFIG_FRONTSWAP |
diff --git a/include/linux/mfd/rtsx_common.h b/include/linux/mfd/rtsx_common.h new file mode 100644 index 00000000000..a8d393e3066 --- /dev/null +++ b/include/linux/mfd/rtsx_common.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* Driver for Realtek driver-based card reader | ||
2 | * | ||
3 | * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #ifndef __RTSX_COMMON_H | ||
24 | #define __RTSX_COMMON_H | ||
25 | |||
26 | #define DRV_NAME_RTSX_PCI "rtsx_pci" | ||
27 | #define DRV_NAME_RTSX_PCI_SDMMC "rtsx_pci_sdmmc" | ||
28 | #define DRV_NAME_RTSX_PCI_MS "rtsx_pci_ms" | ||
29 | |||
30 | #define RTSX_REG_PAIR(addr, val) (((u32)(addr) << 16) | (u8)(val)) | ||
31 | |||
32 | #define RTSX_SSC_DEPTH_4M 0x01 | ||
33 | #define RTSX_SSC_DEPTH_2M 0x02 | ||
34 | #define RTSX_SSC_DEPTH_1M 0x03 | ||
35 | #define RTSX_SSC_DEPTH_500K 0x04 | ||
36 | #define RTSX_SSC_DEPTH_250K 0x05 | ||
37 | |||
38 | #define RTSX_SD_CARD 0 | ||
39 | #define RTSX_MS_CARD 1 | ||
40 | |||
41 | struct platform_device; | ||
42 | |||
43 | struct rtsx_slot { | ||
44 | struct platform_device *p_dev; | ||
45 | void (*card_event)(struct platform_device *p_dev); | ||
46 | }; | ||
47 | |||
48 | #endif | ||
diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h new file mode 100644 index 00000000000..060b721fcbf --- /dev/null +++ b/include/linux/mfd/rtsx_pci.h | |||
@@ -0,0 +1,794 @@ | |||
1 | /* Driver for Realtek PCI-Express card reader | ||
2 | * | ||
3 | * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #ifndef __RTSX_PCI_H | ||
24 | #define __RTSX_PCI_H | ||
25 | |||
26 | #include <linux/sched.h> | ||
27 | #include <linux/pci.h> | ||
28 | |||
29 | #include "rtsx_common.h" | ||
30 | |||
31 | #define MAX_RW_REG_CNT 1024 | ||
32 | |||
33 | /* PCI Operation Register Address */ | ||
34 | #define RTSX_HCBAR 0x00 | ||
35 | #define RTSX_HCBCTLR 0x04 | ||
36 | #define RTSX_HDBAR 0x08 | ||
37 | #define RTSX_HDBCTLR 0x0C | ||
38 | #define RTSX_HAIMR 0x10 | ||
39 | #define RTSX_BIPR 0x14 | ||
40 | #define RTSX_BIER 0x18 | ||
41 | |||
42 | /* Host command buffer control register */ | ||
43 | #define STOP_CMD (0x01 << 28) | ||
44 | |||
45 | /* Host data buffer control register */ | ||
46 | #define SDMA_MODE 0x00 | ||
47 | #define ADMA_MODE (0x02 << 26) | ||
48 | #define STOP_DMA (0x01 << 28) | ||
49 | #define TRIG_DMA (0x01 << 31) | ||
50 | |||
51 | /* Host access internal memory register */ | ||
52 | #define HAIMR_TRANS_START (0x01 << 31) | ||
53 | #define HAIMR_READ 0x00 | ||
54 | #define HAIMR_WRITE (0x01 << 30) | ||
55 | #define HAIMR_READ_START (HAIMR_TRANS_START | HAIMR_READ) | ||
56 | #define HAIMR_WRITE_START (HAIMR_TRANS_START | HAIMR_WRITE) | ||
57 | #define HAIMR_TRANS_END (HAIMR_TRANS_START) | ||
58 | |||
59 | /* Bus interrupt pending register */ | ||
60 | #define CMD_DONE_INT (1 << 31) | ||
61 | #define DATA_DONE_INT (1 << 30) | ||
62 | #define TRANS_OK_INT (1 << 29) | ||
63 | #define TRANS_FAIL_INT (1 << 28) | ||
64 | #define XD_INT (1 << 27) | ||
65 | #define MS_INT (1 << 26) | ||
66 | #define SD_INT (1 << 25) | ||
67 | #define GPIO0_INT (1 << 24) | ||
68 | #define OC_INT (1 << 23) | ||
69 | #define SD_WRITE_PROTECT (1 << 19) | ||
70 | #define XD_EXIST (1 << 18) | ||
71 | #define MS_EXIST (1 << 17) | ||
72 | #define SD_EXIST (1 << 16) | ||
73 | #define DELINK_INT GPIO0_INT | ||
74 | #define MS_OC_INT (1 << 23) | ||
75 | #define SD_OC_INT (1 << 22) | ||
76 | |||
77 | #define CARD_INT (XD_INT | MS_INT | SD_INT) | ||
78 | #define NEED_COMPLETE_INT (DATA_DONE_INT | TRANS_OK_INT | TRANS_FAIL_INT) | ||
79 | #define RTSX_INT (CMD_DONE_INT | NEED_COMPLETE_INT | \ | ||
80 | CARD_INT | GPIO0_INT | OC_INT) | ||
81 | |||
82 | #define CARD_EXIST (XD_EXIST | MS_EXIST | SD_EXIST) | ||
83 | |||
84 | /* Bus interrupt enable register */ | ||
85 | #define CMD_DONE_INT_EN (1 << 31) | ||
86 | #define DATA_DONE_INT_EN (1 << 30) | ||
87 | #define TRANS_OK_INT_EN (1 << 29) | ||
88 | #define TRANS_FAIL_INT_EN (1 << 28) | ||
89 | #define XD_INT_EN (1 << 27) | ||
90 | #define MS_INT_EN (1 << 26) | ||
91 | #define SD_INT_EN (1 << 25) | ||
92 | #define GPIO0_INT_EN (1 << 24) | ||
93 | #define OC_INT_EN (1 << 23) | ||
94 | #define DELINK_INT_EN GPIO0_INT_EN | ||
95 | #define MS_OC_INT_EN (1 << 23) | ||
96 | #define SD_OC_INT_EN (1 << 22) | ||
97 | |||
98 | #define READ_REG_CMD 0 | ||
99 | #define WRITE_REG_CMD 1 | ||
100 | #define CHECK_REG_CMD 2 | ||
101 | |||
102 | /* | ||
103 | * macros for easy use | ||
104 | */ | ||
105 | #define rtsx_pci_writel(pcr, reg, value) \ | ||
106 | iowrite32(value, (pcr)->remap_addr + reg) | ||
107 | #define rtsx_pci_readl(pcr, reg) \ | ||
108 | ioread32((pcr)->remap_addr + reg) | ||
109 | #define rtsx_pci_writew(pcr, reg, value) \ | ||
110 | iowrite16(value, (pcr)->remap_addr + reg) | ||
111 | #define rtsx_pci_readw(pcr, reg) \ | ||
112 | ioread16((pcr)->remap_addr + reg) | ||
113 | #define rtsx_pci_writeb(pcr, reg, value) \ | ||
114 | iowrite8(value, (pcr)->remap_addr + reg) | ||
115 | #define rtsx_pci_readb(pcr, reg) \ | ||
116 | ioread8((pcr)->remap_addr + reg) | ||
117 | |||
118 | #define rtsx_pci_read_config_byte(pcr, where, val) \ | ||
119 | pci_read_config_byte((pcr)->pci, where, val) | ||
120 | |||
121 | #define rtsx_pci_write_config_byte(pcr, where, val) \ | ||
122 | pci_write_config_byte((pcr)->pci, where, val) | ||
123 | |||
124 | #define rtsx_pci_read_config_dword(pcr, where, val) \ | ||
125 | pci_read_config_dword((pcr)->pci, where, val) | ||
126 | |||
127 | #define rtsx_pci_write_config_dword(pcr, where, val) \ | ||
128 | pci_write_config_dword((pcr)->pci, where, val) | ||
129 | |||
130 | #define STATE_TRANS_NONE 0 | ||
131 | #define STATE_TRANS_CMD 1 | ||
132 | #define STATE_TRANS_BUF 2 | ||
133 | #define STATE_TRANS_SG 3 | ||
134 | |||
135 | #define TRANS_NOT_READY 0 | ||
136 | #define TRANS_RESULT_OK 1 | ||
137 | #define TRANS_RESULT_FAIL 2 | ||
138 | #define TRANS_NO_DEVICE 3 | ||
139 | |||
140 | #define RTSX_RESV_BUF_LEN 4096 | ||
141 | #define HOST_CMDS_BUF_LEN 1024 | ||
142 | #define HOST_SG_TBL_BUF_LEN (RTSX_RESV_BUF_LEN - HOST_CMDS_BUF_LEN) | ||
143 | #define HOST_SG_TBL_ITEMS (HOST_SG_TBL_BUF_LEN / 8) | ||
144 | #define MAX_SG_ITEM_LEN 0x80000 | ||
145 | |||
146 | #define HOST_TO_DEVICE 0 | ||
147 | #define DEVICE_TO_HOST 1 | ||
148 | |||
149 | #define MAX_PHASE 31 | ||
150 | #define RX_TUNING_CNT 3 | ||
151 | |||
152 | /* SG descriptor */ | ||
153 | #define SG_INT 0x04 | ||
154 | #define SG_END 0x02 | ||
155 | #define SG_VALID 0x01 | ||
156 | |||
157 | #define SG_NO_OP 0x00 | ||
158 | #define SG_TRANS_DATA (0x02 << 4) | ||
159 | #define SG_LINK_DESC (0x03 << 4) | ||
160 | |||
161 | /* SD bank voltage */ | ||
162 | #define SD_IO_3V3 0 | ||
163 | #define SD_IO_1V8 1 | ||
164 | |||
165 | |||
166 | /* Card Clock Enable Register */ | ||
167 | #define SD_CLK_EN 0x04 | ||
168 | #define MS_CLK_EN 0x08 | ||
169 | |||
170 | /* Card Select Register */ | ||
171 | #define SD_MOD_SEL 2 | ||
172 | #define MS_MOD_SEL 3 | ||
173 | |||
174 | /* Card Output Enable Register */ | ||
175 | #define SD_OUTPUT_EN 0x04 | ||
176 | #define MS_OUTPUT_EN 0x08 | ||
177 | |||
178 | /* CARD_SHARE_MODE */ | ||
179 | #define CARD_SHARE_MASK 0x0F | ||
180 | #define CARD_SHARE_MULTI_LUN 0x00 | ||
181 | #define CARD_SHARE_NORMAL 0x00 | ||
182 | #define CARD_SHARE_48_SD 0x04 | ||
183 | #define CARD_SHARE_48_MS 0x08 | ||
184 | /* CARD_SHARE_MODE for barossa */ | ||
185 | #define CARD_SHARE_BAROSSA_SD 0x01 | ||
186 | #define CARD_SHARE_BAROSSA_MS 0x02 | ||
187 | |||
188 | /* SD30_DRIVE_SEL */ | ||
189 | #define DRIVER_TYPE_A 0x05 | ||
190 | #define DRIVER_TYPE_B 0x03 | ||
191 | #define DRIVER_TYPE_C 0x02 | ||
192 | #define DRIVER_TYPE_D 0x01 | ||
193 | |||
194 | /* FPDCTL */ | ||
195 | #define SSC_POWER_DOWN 0x01 | ||
196 | #define SD_OC_POWER_DOWN 0x02 | ||
197 | #define ALL_POWER_DOWN 0x07 | ||
198 | #define OC_POWER_DOWN 0x06 | ||
199 | |||
200 | /* CLK_CTL */ | ||
201 | #define CHANGE_CLK 0x01 | ||
202 | |||
203 | /* LDO_CTL */ | ||
204 | #define BPP_LDO_POWB 0x03 | ||
205 | #define BPP_LDO_ON 0x00 | ||
206 | #define BPP_LDO_SUSPEND 0x02 | ||
207 | #define BPP_LDO_OFF 0x03 | ||
208 | |||
209 | /* CD_PAD_CTL */ | ||
210 | #define CD_DISABLE_MASK 0x07 | ||
211 | #define MS_CD_DISABLE 0x04 | ||
212 | #define SD_CD_DISABLE 0x02 | ||
213 | #define XD_CD_DISABLE 0x01 | ||
214 | #define CD_DISABLE 0x07 | ||
215 | #define CD_ENABLE 0x00 | ||
216 | #define MS_CD_EN_ONLY 0x03 | ||
217 | #define SD_CD_EN_ONLY 0x05 | ||
218 | #define XD_CD_EN_ONLY 0x06 | ||
219 | #define FORCE_CD_LOW_MASK 0x38 | ||
220 | #define FORCE_CD_XD_LOW 0x08 | ||
221 | #define FORCE_CD_SD_LOW 0x10 | ||
222 | #define FORCE_CD_MS_LOW 0x20 | ||
223 | #define CD_AUTO_DISABLE 0x40 | ||
224 | |||
225 | /* SD_STAT1 */ | ||
226 | #define SD_CRC7_ERR 0x80 | ||
227 | #define SD_CRC16_ERR 0x40 | ||
228 | #define SD_CRC_WRITE_ERR 0x20 | ||
229 | #define SD_CRC_WRITE_ERR_MASK 0x1C | ||
230 | #define GET_CRC_TIME_OUT 0x02 | ||
231 | #define SD_TUNING_COMPARE_ERR 0x01 | ||
232 | |||
233 | /* SD_STAT2 */ | ||
234 | #define SD_RSP_80CLK_TIMEOUT 0x01 | ||
235 | |||
236 | /* SD_BUS_STAT */ | ||
237 | #define SD_CLK_TOGGLE_EN 0x80 | ||
238 | #define SD_CLK_FORCE_STOP 0x40 | ||
239 | #define SD_DAT3_STATUS 0x10 | ||
240 | #define SD_DAT2_STATUS 0x08 | ||
241 | #define SD_DAT1_STATUS 0x04 | ||
242 | #define SD_DAT0_STATUS 0x02 | ||
243 | #define SD_CMD_STATUS 0x01 | ||
244 | |||
245 | /* SD_PAD_CTL */ | ||
246 | #define SD_IO_USING_1V8 0x80 | ||
247 | #define SD_IO_USING_3V3 0x7F | ||
248 | #define TYPE_A_DRIVING 0x00 | ||
249 | #define TYPE_B_DRIVING 0x01 | ||
250 | #define TYPE_C_DRIVING 0x02 | ||
251 | #define TYPE_D_DRIVING 0x03 | ||
252 | |||
253 | /* SD_SAMPLE_POINT_CTL */ | ||
254 | #define DDR_FIX_RX_DAT 0x00 | ||
255 | #define DDR_VAR_RX_DAT 0x80 | ||
256 | #define DDR_FIX_RX_DAT_EDGE 0x00 | ||
257 | #define DDR_FIX_RX_DAT_14_DELAY 0x40 | ||
258 | #define DDR_FIX_RX_CMD 0x00 | ||
259 | #define DDR_VAR_RX_CMD 0x20 | ||
260 | #define DDR_FIX_RX_CMD_POS_EDGE 0x00 | ||
261 | #define DDR_FIX_RX_CMD_14_DELAY 0x10 | ||
262 | #define SD20_RX_POS_EDGE 0x00 | ||
263 | #define SD20_RX_14_DELAY 0x08 | ||
264 | #define SD20_RX_SEL_MASK 0x08 | ||
265 | |||
266 | /* SD_PUSH_POINT_CTL */ | ||
267 | #define DDR_FIX_TX_CMD_DAT 0x00 | ||
268 | #define DDR_VAR_TX_CMD_DAT 0x80 | ||
269 | #define DDR_FIX_TX_DAT_14_TSU 0x00 | ||
270 | #define DDR_FIX_TX_DAT_12_TSU 0x40 | ||
271 | #define DDR_FIX_TX_CMD_NEG_EDGE 0x00 | ||
272 | #define DDR_FIX_TX_CMD_14_AHEAD 0x20 | ||
273 | #define SD20_TX_NEG_EDGE 0x00 | ||
274 | #define SD20_TX_14_AHEAD 0x10 | ||
275 | #define SD20_TX_SEL_MASK 0x10 | ||
276 | #define DDR_VAR_SDCLK_POL_SWAP 0x01 | ||
277 | |||
278 | /* SD_TRANSFER */ | ||
279 | #define SD_TRANSFER_START 0x80 | ||
280 | #define SD_TRANSFER_END 0x40 | ||
281 | #define SD_STAT_IDLE 0x20 | ||
282 | #define SD_TRANSFER_ERR 0x10 | ||
283 | /* SD Transfer Mode definition */ | ||
284 | #define SD_TM_NORMAL_WRITE 0x00 | ||
285 | #define SD_TM_AUTO_WRITE_3 0x01 | ||
286 | #define SD_TM_AUTO_WRITE_4 0x02 | ||
287 | #define SD_TM_AUTO_READ_3 0x05 | ||
288 | #define SD_TM_AUTO_READ_4 0x06 | ||
289 | #define SD_TM_CMD_RSP 0x08 | ||
290 | #define SD_TM_AUTO_WRITE_1 0x09 | ||
291 | #define SD_TM_AUTO_WRITE_2 0x0A | ||
292 | #define SD_TM_NORMAL_READ 0x0C | ||
293 | #define SD_TM_AUTO_READ_1 0x0D | ||
294 | #define SD_TM_AUTO_READ_2 0x0E | ||
295 | #define SD_TM_AUTO_TUNING 0x0F | ||
296 | |||
297 | /* SD_VPTX_CTL / SD_VPRX_CTL */ | ||
298 | #define PHASE_CHANGE 0x80 | ||
299 | #define PHASE_NOT_RESET 0x40 | ||
300 | |||
301 | /* SD_DCMPS_TX_CTL / SD_DCMPS_RX_CTL */ | ||
302 | #define DCMPS_CHANGE 0x80 | ||
303 | #define DCMPS_CHANGE_DONE 0x40 | ||
304 | #define DCMPS_ERROR 0x20 | ||
305 | #define DCMPS_CURRENT_PHASE 0x1F | ||
306 | |||
307 | /* SD Configure 1 Register */ | ||
308 | #define SD_CLK_DIVIDE_0 0x00 | ||
309 | #define SD_CLK_DIVIDE_256 0xC0 | ||
310 | #define SD_CLK_DIVIDE_128 0x80 | ||
311 | #define SD_BUS_WIDTH_1BIT 0x00 | ||
312 | #define SD_BUS_WIDTH_4BIT 0x01 | ||
313 | #define SD_BUS_WIDTH_8BIT 0x02 | ||
314 | #define SD_ASYNC_FIFO_NOT_RST 0x10 | ||
315 | #define SD_20_MODE 0x00 | ||
316 | #define SD_DDR_MODE 0x04 | ||
317 | #define SD_30_MODE 0x08 | ||
318 | |||
319 | #define SD_CLK_DIVIDE_MASK 0xC0 | ||
320 | |||
321 | /* SD_CMD_STATE */ | ||
322 | #define SD_CMD_IDLE 0x80 | ||
323 | |||
324 | /* SD_DATA_STATE */ | ||
325 | #define SD_DATA_IDLE 0x80 | ||
326 | |||
327 | /* DCM_DRP_CTL */ | ||
328 | #define DCM_RESET 0x08 | ||
329 | #define DCM_LOCKED 0x04 | ||
330 | #define DCM_208M 0x00 | ||
331 | #define DCM_TX 0x01 | ||
332 | #define DCM_RX 0x02 | ||
333 | |||
334 | /* DCM_DRP_TRIG */ | ||
335 | #define DRP_START 0x80 | ||
336 | #define DRP_DONE 0x40 | ||
337 | |||
338 | /* DCM_DRP_CFG */ | ||
339 | #define DRP_WRITE 0x80 | ||
340 | #define DRP_READ 0x00 | ||
341 | #define DCM_WRITE_ADDRESS_50 0x50 | ||
342 | #define DCM_WRITE_ADDRESS_51 0x51 | ||
343 | #define DCM_READ_ADDRESS_00 0x00 | ||
344 | #define DCM_READ_ADDRESS_51 0x51 | ||
345 | |||
346 | /* IRQSTAT0 */ | ||
347 | #define DMA_DONE_INT 0x80 | ||
348 | #define SUSPEND_INT 0x40 | ||
349 | #define LINK_RDY_INT 0x20 | ||
350 | #define LINK_DOWN_INT 0x10 | ||
351 | |||
352 | /* DMACTL */ | ||
353 | #define DMA_RST 0x80 | ||
354 | #define DMA_BUSY 0x04 | ||
355 | #define DMA_DIR_TO_CARD 0x00 | ||
356 | #define DMA_DIR_FROM_CARD 0x02 | ||
357 | #define DMA_EN 0x01 | ||
358 | #define DMA_128 (0 << 4) | ||
359 | #define DMA_256 (1 << 4) | ||
360 | #define DMA_512 (2 << 4) | ||
361 | #define DMA_1024 (3 << 4) | ||
362 | #define DMA_PACK_SIZE_MASK 0x30 | ||
363 | |||
364 | /* SSC_CTL1 */ | ||
365 | #define SSC_RSTB 0x80 | ||
366 | #define SSC_8X_EN 0x40 | ||
367 | #define SSC_FIX_FRAC 0x20 | ||
368 | #define SSC_SEL_1M 0x00 | ||
369 | #define SSC_SEL_2M 0x08 | ||
370 | #define SSC_SEL_4M 0x10 | ||
371 | #define SSC_SEL_8M 0x18 | ||
372 | |||
373 | /* SSC_CTL2 */ | ||
374 | #define SSC_DEPTH_MASK 0x07 | ||
375 | #define SSC_DEPTH_DISALBE 0x00 | ||
376 | #define SSC_DEPTH_4M 0x01 | ||
377 | #define SSC_DEPTH_2M 0x02 | ||
378 | #define SSC_DEPTH_1M 0x03 | ||
379 | #define SSC_DEPTH_500K 0x04 | ||
380 | #define SSC_DEPTH_250K 0x05 | ||
381 | |||
382 | /* System Clock Control Register */ | ||
383 | #define CLK_LOW_FREQ 0x01 | ||
384 | |||
385 | /* System Clock Divider Register */ | ||
386 | #define CLK_DIV_1 0x01 | ||
387 | #define CLK_DIV_2 0x02 | ||
388 | #define CLK_DIV_4 0x03 | ||
389 | #define CLK_DIV_8 0x04 | ||
390 | |||
391 | /* MS_CFG */ | ||
392 | #define SAMPLE_TIME_RISING 0x00 | ||
393 | #define SAMPLE_TIME_FALLING 0x80 | ||
394 | #define PUSH_TIME_DEFAULT 0x00 | ||
395 | #define PUSH_TIME_ODD 0x40 | ||
396 | #define NO_EXTEND_TOGGLE 0x00 | ||
397 | #define EXTEND_TOGGLE_CHK 0x20 | ||
398 | #define MS_BUS_WIDTH_1 0x00 | ||
399 | #define MS_BUS_WIDTH_4 0x10 | ||
400 | #define MS_BUS_WIDTH_8 0x18 | ||
401 | #define MS_2K_SECTOR_MODE 0x04 | ||
402 | #define MS_512_SECTOR_MODE 0x00 | ||
403 | #define MS_TOGGLE_TIMEOUT_EN 0x00 | ||
404 | #define MS_TOGGLE_TIMEOUT_DISEN 0x01 | ||
405 | #define MS_NO_CHECK_INT 0x02 | ||
406 | |||
407 | /* MS_TRANS_CFG */ | ||
408 | #define WAIT_INT 0x80 | ||
409 | #define NO_WAIT_INT 0x00 | ||
410 | #define NO_AUTO_READ_INT_REG 0x00 | ||
411 | #define AUTO_READ_INT_REG 0x40 | ||
412 | #define MS_CRC16_ERR 0x20 | ||
413 | #define MS_RDY_TIMEOUT 0x10 | ||
414 | #define MS_INT_CMDNK 0x08 | ||
415 | #define MS_INT_BREQ 0x04 | ||
416 | #define MS_INT_ERR 0x02 | ||
417 | #define MS_INT_CED 0x01 | ||
418 | |||
419 | /* MS_TRANSFER */ | ||
420 | #define MS_TRANSFER_START 0x80 | ||
421 | #define MS_TRANSFER_END 0x40 | ||
422 | #define MS_TRANSFER_ERR 0x20 | ||
423 | #define MS_BS_STATE 0x10 | ||
424 | #define MS_TM_READ_BYTES 0x00 | ||
425 | #define MS_TM_NORMAL_READ 0x01 | ||
426 | #define MS_TM_WRITE_BYTES 0x04 | ||
427 | #define MS_TM_NORMAL_WRITE 0x05 | ||
428 | #define MS_TM_AUTO_READ 0x08 | ||
429 | #define MS_TM_AUTO_WRITE 0x0C | ||
430 | |||
431 | /* SD Configure 2 Register */ | ||
432 | #define SD_CALCULATE_CRC7 0x00 | ||
433 | #define SD_NO_CALCULATE_CRC7 0x80 | ||
434 | #define SD_CHECK_CRC16 0x00 | ||
435 | #define SD_NO_CHECK_CRC16 0x40 | ||
436 | #define SD_NO_CHECK_WAIT_CRC_TO 0x20 | ||
437 | #define SD_WAIT_BUSY_END 0x08 | ||
438 | #define SD_NO_WAIT_BUSY_END 0x00 | ||
439 | #define SD_CHECK_CRC7 0x00 | ||
440 | #define SD_NO_CHECK_CRC7 0x04 | ||
441 | #define SD_RSP_LEN_0 0x00 | ||
442 | #define SD_RSP_LEN_6 0x01 | ||
443 | #define SD_RSP_LEN_17 0x02 | ||
444 | /* SD/MMC Response Type Definition */ | ||
445 | #define SD_RSP_TYPE_R0 0x04 | ||
446 | #define SD_RSP_TYPE_R1 0x01 | ||
447 | #define SD_RSP_TYPE_R1b 0x09 | ||
448 | #define SD_RSP_TYPE_R2 0x02 | ||
449 | #define SD_RSP_TYPE_R3 0x05 | ||
450 | #define SD_RSP_TYPE_R4 0x05 | ||
451 | #define SD_RSP_TYPE_R5 0x01 | ||
452 | #define SD_RSP_TYPE_R6 0x01 | ||
453 | #define SD_RSP_TYPE_R7 0x01 | ||
454 | |||
455 | /* SD_CONFIURE3 */ | ||
456 | #define SD_RSP_80CLK_TIMEOUT_EN 0x01 | ||
457 | |||
458 | /* Card Transfer Reset Register */ | ||
459 | #define SPI_STOP 0x01 | ||
460 | #define XD_STOP 0x02 | ||
461 | #define SD_STOP 0x04 | ||
462 | #define MS_STOP 0x08 | ||
463 | #define SPI_CLR_ERR 0x10 | ||
464 | #define XD_CLR_ERR 0x20 | ||
465 | #define SD_CLR_ERR 0x40 | ||
466 | #define MS_CLR_ERR 0x80 | ||
467 | |||
468 | /* Card Data Source Register */ | ||
469 | #define PINGPONG_BUFFER 0x01 | ||
470 | #define RING_BUFFER 0x00 | ||
471 | |||
472 | /* Card Power Control Register */ | ||
473 | #define PMOS_STRG_MASK 0x10 | ||
474 | #define PMOS_STRG_800mA 0x10 | ||
475 | #define PMOS_STRG_400mA 0x00 | ||
476 | #define SD_POWER_OFF 0x03 | ||
477 | #define SD_PARTIAL_POWER_ON 0x01 | ||
478 | #define SD_POWER_ON 0x00 | ||
479 | #define SD_POWER_MASK 0x03 | ||
480 | #define MS_POWER_OFF 0x0C | ||
481 | #define MS_PARTIAL_POWER_ON 0x04 | ||
482 | #define MS_POWER_ON 0x00 | ||
483 | #define MS_POWER_MASK 0x0C | ||
484 | #define BPP_POWER_OFF 0x0F | ||
485 | #define BPP_POWER_5_PERCENT_ON 0x0E | ||
486 | #define BPP_POWER_10_PERCENT_ON 0x0C | ||
487 | #define BPP_POWER_15_PERCENT_ON 0x08 | ||
488 | #define BPP_POWER_ON 0x00 | ||
489 | #define BPP_POWER_MASK 0x0F | ||
490 | |||
491 | /* PWR_GATE_CTRL */ | ||
492 | #define PWR_GATE_EN 0x01 | ||
493 | #define LDO3318_PWR_MASK 0x06 | ||
494 | #define LDO_ON 0x00 | ||
495 | #define LDO_SUSPEND 0x04 | ||
496 | #define LDO_OFF 0x06 | ||
497 | |||
498 | /* CARD_CLK_SOURCE */ | ||
499 | #define CRC_FIX_CLK (0x00 << 0) | ||
500 | #define CRC_VAR_CLK0 (0x01 << 0) | ||
501 | #define CRC_VAR_CLK1 (0x02 << 0) | ||
502 | #define SD30_FIX_CLK (0x00 << 2) | ||
503 | #define SD30_VAR_CLK0 (0x01 << 2) | ||
504 | #define SD30_VAR_CLK1 (0x02 << 2) | ||
505 | #define SAMPLE_FIX_CLK (0x00 << 4) | ||
506 | #define SAMPLE_VAR_CLK0 (0x01 << 4) | ||
507 | #define SAMPLE_VAR_CLK1 (0x02 << 4) | ||
508 | |||
509 | #define MS_CFG 0xFD40 | ||
510 | #define MS_TPC 0xFD41 | ||
511 | #define MS_TRANS_CFG 0xFD42 | ||
512 | #define MS_TRANSFER 0xFD43 | ||
513 | #define MS_INT_REG 0xFD44 | ||
514 | #define MS_BYTE_CNT 0xFD45 | ||
515 | #define MS_SECTOR_CNT_L 0xFD46 | ||
516 | #define MS_SECTOR_CNT_H 0xFD47 | ||
517 | #define MS_DBUS_H 0xFD48 | ||
518 | |||
519 | #define SD_CFG1 0xFDA0 | ||
520 | #define SD_CFG2 0xFDA1 | ||
521 | #define SD_CFG3 0xFDA2 | ||
522 | #define SD_STAT1 0xFDA3 | ||
523 | #define SD_STAT2 0xFDA4 | ||
524 | #define SD_BUS_STAT 0xFDA5 | ||
525 | #define SD_PAD_CTL 0xFDA6 | ||
526 | #define SD_SAMPLE_POINT_CTL 0xFDA7 | ||
527 | #define SD_PUSH_POINT_CTL 0xFDA8 | ||
528 | #define SD_CMD0 0xFDA9 | ||
529 | #define SD_CMD1 0xFDAA | ||
530 | #define SD_CMD2 0xFDAB | ||
531 | #define SD_CMD3 0xFDAC | ||
532 | #define SD_CMD4 0xFDAD | ||
533 | #define SD_CMD5 0xFDAE | ||
534 | #define SD_BYTE_CNT_L 0xFDAF | ||
535 | #define SD_BYTE_CNT_H 0xFDB0 | ||
536 | #define SD_BLOCK_CNT_L 0xFDB1 | ||
537 | #define SD_BLOCK_CNT_H 0xFDB2 | ||
538 | #define SD_TRANSFER 0xFDB3 | ||
539 | #define SD_CMD_STATE 0xFDB5 | ||
540 | #define SD_DATA_STATE 0xFDB6 | ||
541 | |||
542 | #define SRCTL 0xFC13 | ||
543 | |||
544 | #define DCM_DRP_CTL 0xFC23 | ||
545 | #define DCM_DRP_TRIG 0xFC24 | ||
546 | #define DCM_DRP_CFG 0xFC25 | ||
547 | #define DCM_DRP_WR_DATA_L 0xFC26 | ||
548 | #define DCM_DRP_WR_DATA_H 0xFC27 | ||
549 | #define DCM_DRP_RD_DATA_L 0xFC28 | ||
550 | #define DCM_DRP_RD_DATA_H 0xFC29 | ||
551 | #define SD_VPCLK0_CTL 0xFC2A | ||
552 | #define SD_VPCLK1_CTL 0xFC2B | ||
553 | #define SD_DCMPS0_CTL 0xFC2C | ||
554 | #define SD_DCMPS1_CTL 0xFC2D | ||
555 | #define SD_VPTX_CTL SD_VPCLK0_CTL | ||
556 | #define SD_VPRX_CTL SD_VPCLK1_CTL | ||
557 | #define SD_DCMPS_TX_CTL SD_DCMPS0_CTL | ||
558 | #define SD_DCMPS_RX_CTL SD_DCMPS1_CTL | ||
559 | #define CARD_CLK_SOURCE 0xFC2E | ||
560 | |||
561 | #define CARD_PWR_CTL 0xFD50 | ||
562 | #define CARD_CLK_SWITCH 0xFD51 | ||
563 | #define CARD_SHARE_MODE 0xFD52 | ||
564 | #define CARD_DRIVE_SEL 0xFD53 | ||
565 | #define CARD_STOP 0xFD54 | ||
566 | #define CARD_OE 0xFD55 | ||
567 | #define CARD_AUTO_BLINK 0xFD56 | ||
568 | #define CARD_GPIO_DIR 0xFD57 | ||
569 | #define CARD_GPIO 0xFD58 | ||
570 | #define CARD_DATA_SOURCE 0xFD5B | ||
571 | #define CARD_SELECT 0xFD5C | ||
572 | #define SD30_DRIVE_SEL 0xFD5E | ||
573 | #define CARD_CLK_EN 0xFD69 | ||
574 | #define SDIO_CTRL 0xFD6B | ||
575 | #define CD_PAD_CTL 0xFD73 | ||
576 | |||
577 | #define FPDCTL 0xFC00 | ||
578 | #define PDINFO 0xFC01 | ||
579 | |||
580 | #define CLK_CTL 0xFC02 | ||
581 | #define CLK_DIV 0xFC03 | ||
582 | #define CLK_SEL 0xFC04 | ||
583 | |||
584 | #define SSC_DIV_N_0 0xFC0F | ||
585 | #define SSC_DIV_N_1 0xFC10 | ||
586 | #define SSC_CTL1 0xFC11 | ||
587 | #define SSC_CTL2 0xFC12 | ||
588 | |||
589 | #define RCCTL 0xFC14 | ||
590 | |||
591 | #define FPGA_PULL_CTL 0xFC1D | ||
592 | #define OLT_LED_CTL 0xFC1E | ||
593 | #define GPIO_CTL 0xFC1F | ||
594 | |||
595 | #define LDO_CTL 0xFC1E | ||
596 | #define SYS_VER 0xFC32 | ||
597 | |||
598 | #define CARD_PULL_CTL1 0xFD60 | ||
599 | #define CARD_PULL_CTL2 0xFD61 | ||
600 | #define CARD_PULL_CTL3 0xFD62 | ||
601 | #define CARD_PULL_CTL4 0xFD63 | ||
602 | #define CARD_PULL_CTL5 0xFD64 | ||
603 | #define CARD_PULL_CTL6 0xFD65 | ||
604 | |||
605 | /* PCI Express Related Registers */ | ||
606 | #define IRQEN0 0xFE20 | ||
607 | #define IRQSTAT0 0xFE21 | ||
608 | #define IRQEN1 0xFE22 | ||
609 | #define IRQSTAT1 0xFE23 | ||
610 | #define TLPRIEN 0xFE24 | ||
611 | #define TLPRISTAT 0xFE25 | ||
612 | #define TLPTIEN 0xFE26 | ||
613 | #define TLPTISTAT 0xFE27 | ||
614 | #define DMATC0 0xFE28 | ||
615 | #define DMATC1 0xFE29 | ||
616 | #define DMATC2 0xFE2A | ||
617 | #define DMATC3 0xFE2B | ||
618 | #define DMACTL 0xFE2C | ||
619 | #define BCTL 0xFE2D | ||
620 | #define RBBC0 0xFE2E | ||
621 | #define RBBC1 0xFE2F | ||
622 | #define RBDAT 0xFE30 | ||
623 | #define RBCTL 0xFE34 | ||
624 | #define CFGADDR0 0xFE35 | ||
625 | #define CFGADDR1 0xFE36 | ||
626 | #define CFGDATA0 0xFE37 | ||
627 | #define CFGDATA1 0xFE38 | ||
628 | #define CFGDATA2 0xFE39 | ||
629 | #define CFGDATA3 0xFE3A | ||
630 | #define CFGRWCTL 0xFE3B | ||
631 | #define PHYRWCTL 0xFE3C | ||
632 | #define PHYDATA0 0xFE3D | ||
633 | #define PHYDATA1 0xFE3E | ||
634 | #define PHYADDR 0xFE3F | ||
635 | #define MSGRXDATA0 0xFE40 | ||
636 | #define MSGRXDATA1 0xFE41 | ||
637 | #define MSGRXDATA2 0xFE42 | ||
638 | #define MSGRXDATA3 0xFE43 | ||
639 | #define MSGTXDATA0 0xFE44 | ||
640 | #define MSGTXDATA1 0xFE45 | ||
641 | #define MSGTXDATA2 0xFE46 | ||
642 | #define MSGTXDATA3 0xFE47 | ||
643 | #define MSGTXCTL 0xFE48 | ||
644 | #define PETXCFG 0xFE49 | ||
645 | |||
646 | #define CDRESUMECTL 0xFE52 | ||
647 | #define WAKE_SEL_CTL 0xFE54 | ||
648 | #define PME_FORCE_CTL 0xFE56 | ||
649 | #define ASPM_FORCE_CTL 0xFE57 | ||
650 | #define PM_CLK_FORCE_CTL 0xFE58 | ||
651 | #define PERST_GLITCH_WIDTH 0xFE5C | ||
652 | #define CHANGE_LINK_STATE 0xFE5B | ||
653 | #define RESET_LOAD_REG 0xFE5E | ||
654 | #define EFUSE_CONTENT 0xFE5F | ||
655 | #define HOST_SLEEP_STATE 0xFE60 | ||
656 | #define SDIO_CFG 0xFE70 | ||
657 | |||
658 | #define NFTS_TX_CTRL 0xFE72 | ||
659 | |||
660 | #define PWR_GATE_CTRL 0xFE75 | ||
661 | #define PWD_SUSPEND_EN 0xFE76 | ||
662 | #define LDO_PWR_SEL 0xFE78 | ||
663 | |||
664 | #define DUMMY_REG_RESET_0 0xFE90 | ||
665 | |||
666 | /* Memory mapping */ | ||
667 | #define SRAM_BASE 0xE600 | ||
668 | #define RBUF_BASE 0xF400 | ||
669 | #define PPBUF_BASE1 0xF800 | ||
670 | #define PPBUF_BASE2 0xFA00 | ||
671 | #define IMAGE_FLAG_ADDR0 0xCE80 | ||
672 | #define IMAGE_FLAG_ADDR1 0xCE81 | ||
673 | |||
674 | #define rtsx_pci_init_cmd(pcr) ((pcr)->ci = 0) | ||
675 | |||
676 | struct rtsx_pcr; | ||
677 | |||
678 | struct pcr_handle { | ||
679 | struct rtsx_pcr *pcr; | ||
680 | }; | ||
681 | |||
682 | struct pcr_ops { | ||
683 | int (*extra_init_hw)(struct rtsx_pcr *pcr); | ||
684 | int (*optimize_phy)(struct rtsx_pcr *pcr); | ||
685 | int (*turn_on_led)(struct rtsx_pcr *pcr); | ||
686 | int (*turn_off_led)(struct rtsx_pcr *pcr); | ||
687 | int (*enable_auto_blink)(struct rtsx_pcr *pcr); | ||
688 | int (*disable_auto_blink)(struct rtsx_pcr *pcr); | ||
689 | int (*card_power_on)(struct rtsx_pcr *pcr, int card); | ||
690 | int (*card_power_off)(struct rtsx_pcr *pcr, int card); | ||
691 | unsigned int (*cd_deglitch)(struct rtsx_pcr *pcr); | ||
692 | }; | ||
693 | |||
694 | enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN}; | ||
695 | |||
696 | struct rtsx_pcr { | ||
697 | struct pci_dev *pci; | ||
698 | unsigned int id; | ||
699 | |||
700 | /* pci resources */ | ||
701 | unsigned long addr; | ||
702 | void __iomem *remap_addr; | ||
703 | int irq; | ||
704 | |||
705 | /* host reserved buffer */ | ||
706 | void *rtsx_resv_buf; | ||
707 | dma_addr_t rtsx_resv_buf_addr; | ||
708 | |||
709 | void *host_cmds_ptr; | ||
710 | dma_addr_t host_cmds_addr; | ||
711 | int ci; | ||
712 | |||
713 | void *host_sg_tbl_ptr; | ||
714 | dma_addr_t host_sg_tbl_addr; | ||
715 | int sgi; | ||
716 | |||
717 | u32 bier; | ||
718 | char trans_result; | ||
719 | |||
720 | unsigned int card_inserted; | ||
721 | unsigned int card_removed; | ||
722 | |||
723 | struct delayed_work carddet_work; | ||
724 | struct delayed_work idle_work; | ||
725 | |||
726 | spinlock_t lock; | ||
727 | struct mutex pcr_mutex; | ||
728 | struct completion *done; | ||
729 | struct completion *finish_me; | ||
730 | |||
731 | unsigned int cur_clock; | ||
732 | bool ms_pmos; | ||
733 | bool remove_pci; | ||
734 | bool msi_en; | ||
735 | |||
736 | #define EXTRA_CAPS_SD_SDR50 (1 << 0) | ||
737 | #define EXTRA_CAPS_SD_SDR104 (1 << 1) | ||
738 | #define EXTRA_CAPS_SD_DDR50 (1 << 2) | ||
739 | #define EXTRA_CAPS_MMC_HSDDR (1 << 3) | ||
740 | #define EXTRA_CAPS_MMC_HS200 (1 << 4) | ||
741 | #define EXTRA_CAPS_MMC_8BIT (1 << 5) | ||
742 | u32 extra_caps; | ||
743 | |||
744 | #define IC_VER_A 0 | ||
745 | #define IC_VER_B 1 | ||
746 | #define IC_VER_C 2 | ||
747 | #define IC_VER_D 3 | ||
748 | u8 ic_version; | ||
749 | |||
750 | const u32 *sd_pull_ctl_enable_tbl; | ||
751 | const u32 *sd_pull_ctl_disable_tbl; | ||
752 | const u32 *ms_pull_ctl_enable_tbl; | ||
753 | const u32 *ms_pull_ctl_disable_tbl; | ||
754 | |||
755 | const struct pcr_ops *ops; | ||
756 | enum PDEV_STAT state; | ||
757 | |||
758 | int num_slots; | ||
759 | struct rtsx_slot *slots; | ||
760 | }; | ||
761 | |||
762 | #define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid)) | ||
763 | #define PCI_VID(pcr) ((pcr)->pci->vendor) | ||
764 | #define PCI_PID(pcr) ((pcr)->pci->device) | ||
765 | |||
766 | void rtsx_pci_start_run(struct rtsx_pcr *pcr); | ||
767 | int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data); | ||
768 | int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data); | ||
769 | int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val); | ||
770 | int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val); | ||
771 | void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr); | ||
772 | void rtsx_pci_add_cmd(struct rtsx_pcr *pcr, | ||
773 | u8 cmd_type, u16 reg_addr, u8 mask, u8 data); | ||
774 | void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr); | ||
775 | int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout); | ||
776 | int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, | ||
777 | int num_sg, bool read, int timeout); | ||
778 | int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len); | ||
779 | int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len); | ||
780 | int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card); | ||
781 | int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card); | ||
782 | int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, | ||
783 | u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk); | ||
784 | int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card); | ||
785 | int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card); | ||
786 | unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr); | ||
787 | void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr); | ||
788 | |||
789 | static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr) | ||
790 | { | ||
791 | return (u8 *)(pcr->host_cmds_ptr); | ||
792 | } | ||
793 | |||
794 | #endif | ||
diff --git a/include/linux/mman.h b/include/linux/mman.h index d09dde1e57f..9aa863da287 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h | |||
@@ -11,6 +11,8 @@ extern int sysctl_overcommit_memory; | |||
11 | extern int sysctl_overcommit_ratio; | 11 | extern int sysctl_overcommit_ratio; |
12 | extern struct percpu_counter vm_committed_as; | 12 | extern struct percpu_counter vm_committed_as; |
13 | 13 | ||
14 | unsigned long vm_memory_committed(void); | ||
15 | |||
14 | static inline void vm_acct_memory(long pages) | 16 | static inline void vm_acct_memory(long pages) |
15 | { | 17 | { |
16 | percpu_counter_add(&vm_committed_as, pages); | 18 | percpu_counter_add(&vm_committed_as, pages); |
diff --git a/include/linux/platform_data/uio_dmem_genirq.h b/include/linux/platform_data/uio_dmem_genirq.h new file mode 100644 index 00000000000..973c1bb3216 --- /dev/null +++ b/include/linux/platform_data/uio_dmem_genirq.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * include/linux/platform_data/uio_dmem_genirq.h | ||
3 | * | ||
4 | * Copyright (C) 2012 Damian Hobson-Garcia | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef _UIO_DMEM_GENIRQ_H | ||
17 | #define _UIO_DMEM_GENIRQ_H | ||
18 | |||
19 | #include <linux/uio_driver.h> | ||
20 | |||
21 | struct uio_dmem_genirq_pdata { | ||
22 | struct uio_info uioinfo; | ||
23 | unsigned int *dynamic_region_sizes; | ||
24 | unsigned int num_dynamic_regions; | ||
25 | }; | ||
26 | #endif /* _UIO_DMEM_GENIRQ_H */ | ||
@@ -89,6 +89,20 @@ int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; | |||
89 | struct percpu_counter vm_committed_as ____cacheline_aligned_in_smp; | 89 | struct percpu_counter vm_committed_as ____cacheline_aligned_in_smp; |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * The global memory commitment made in the system can be a metric | ||
93 | * that can be used to drive ballooning decisions when Linux is hosted | ||
94 | * as a guest. On Hyper-V, the host implements a policy engine for dynamically | ||
95 | * balancing memory across competing virtual machines that are hosted. | ||
96 | * Several metrics drive this policy engine including the guest reported | ||
97 | * memory commitment. | ||
98 | */ | ||
99 | unsigned long vm_memory_committed(void) | ||
100 | { | ||
101 | return percpu_counter_read_positive(&vm_committed_as); | ||
102 | } | ||
103 | EXPORT_SYMBOL_GPL(vm_memory_committed); | ||
104 | |||
105 | /* | ||
92 | * Check that a process has enough memory to allocate a new virtual | 106 | * Check that a process has enough memory to allocate a new virtual |
93 | * mapping. 0 means there is enough memory for the allocation to | 107 | * mapping. 0 means there is enough memory for the allocation to |
94 | * succeed and -ENOMEM implies there is not. | 108 | * succeed and -ENOMEM implies there is not. |
diff --git a/mm/nommu.c b/mm/nommu.c index 45131b41bcd..79c3cac87af 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -66,6 +66,21 @@ int heap_stack_gap = 0; | |||
66 | 66 | ||
67 | atomic_long_t mmap_pages_allocated; | 67 | atomic_long_t mmap_pages_allocated; |
68 | 68 | ||
69 | /* | ||
70 | * The global memory commitment made in the system can be a metric | ||
71 | * that can be used to drive ballooning decisions when Linux is hosted | ||
72 | * as a guest. On Hyper-V, the host implements a policy engine for dynamically | ||
73 | * balancing memory across competing virtual machines that are hosted. | ||
74 | * Several metrics drive this policy engine including the guest reported | ||
75 | * memory commitment. | ||
76 | */ | ||
77 | unsigned long vm_memory_committed(void) | ||
78 | { | ||
79 | return percpu_counter_read_positive(&vm_committed_as); | ||
80 | } | ||
81 | |||
82 | EXPORT_SYMBOL_GPL(vm_memory_committed); | ||
83 | |||
69 | EXPORT_SYMBOL(mem_map); | 84 | EXPORT_SYMBOL(mem_map); |
70 | EXPORT_SYMBOL(num_physpages); | 85 | EXPORT_SYMBOL(num_physpages); |
71 | 86 | ||
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 5959affd882..d25a46925e6 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <sys/stat.h> | 43 | #include <sys/stat.h> |
44 | #include <fcntl.h> | 44 | #include <fcntl.h> |
45 | #include <dirent.h> | 45 | #include <dirent.h> |
46 | #include <net/if.h> | ||
46 | 47 | ||
47 | /* | 48 | /* |
48 | * KVP protocol: The user mode component first registers with the | 49 | * KVP protocol: The user mode component first registers with the |
@@ -88,6 +89,7 @@ static char *os_major = ""; | |||
88 | static char *os_minor = ""; | 89 | static char *os_minor = ""; |
89 | static char *processor_arch; | 90 | static char *processor_arch; |
90 | static char *os_build; | 91 | static char *os_build; |
92 | static char *os_version; | ||
91 | static char *lic_version = "Unknown version"; | 93 | static char *lic_version = "Unknown version"; |
92 | static struct utsname uts_buf; | 94 | static struct utsname uts_buf; |
93 | 95 | ||
@@ -297,7 +299,7 @@ static int kvp_file_init(void) | |||
297 | return 0; | 299 | return 0; |
298 | } | 300 | } |
299 | 301 | ||
300 | static int kvp_key_delete(int pool, __u8 *key, int key_size) | 302 | static int kvp_key_delete(int pool, const char *key, int key_size) |
301 | { | 303 | { |
302 | int i; | 304 | int i; |
303 | int j, k; | 305 | int j, k; |
@@ -340,7 +342,7 @@ static int kvp_key_delete(int pool, __u8 *key, int key_size) | |||
340 | return 1; | 342 | return 1; |
341 | } | 343 | } |
342 | 344 | ||
343 | static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value, | 345 | static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value, |
344 | int value_size) | 346 | int value_size) |
345 | { | 347 | { |
346 | int i; | 348 | int i; |
@@ -394,7 +396,7 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value, | |||
394 | return 0; | 396 | return 0; |
395 | } | 397 | } |
396 | 398 | ||
397 | static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, | 399 | static int kvp_get_value(int pool, const char *key, int key_size, char *value, |
398 | int value_size) | 400 | int value_size) |
399 | { | 401 | { |
400 | int i; | 402 | int i; |
@@ -426,8 +428,8 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, | |||
426 | return 1; | 428 | return 1; |
427 | } | 429 | } |
428 | 430 | ||
429 | static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, | 431 | static int kvp_pool_enumerate(int pool, int index, char *key, int key_size, |
430 | __u8 *value, int value_size) | 432 | char *value, int value_size) |
431 | { | 433 | { |
432 | struct kvp_record *record; | 434 | struct kvp_record *record; |
433 | 435 | ||
@@ -453,7 +455,9 @@ void kvp_get_os_info(void) | |||
453 | char *p, buf[512]; | 455 | char *p, buf[512]; |
454 | 456 | ||
455 | uname(&uts_buf); | 457 | uname(&uts_buf); |
456 | os_build = uts_buf.release; | 458 | os_version = uts_buf.release; |
459 | os_build = strdup(uts_buf.release); | ||
460 | |||
457 | os_name = uts_buf.sysname; | 461 | os_name = uts_buf.sysname; |
458 | processor_arch = uts_buf.machine; | 462 | processor_arch = uts_buf.machine; |
459 | 463 | ||
@@ -462,7 +466,7 @@ void kvp_get_os_info(void) | |||
462 | * string to be of the form: x.y.z | 466 | * string to be of the form: x.y.z |
463 | * Strip additional information we may have. | 467 | * Strip additional information we may have. |
464 | */ | 468 | */ |
465 | p = strchr(os_build, '-'); | 469 | p = strchr(os_version, '-'); |
466 | if (p) | 470 | if (p) |
467 | *p = '\0'; | 471 | *p = '\0'; |
468 | 472 | ||
@@ -879,7 +883,7 @@ static int kvp_process_ip_address(void *addrp, | |||
879 | addr_length = INET6_ADDRSTRLEN; | 883 | addr_length = INET6_ADDRSTRLEN; |
880 | } | 884 | } |
881 | 885 | ||
882 | if ((length - *offset) < addr_length + 1) | 886 | if ((length - *offset) < addr_length + 2) |
883 | return HV_E_FAIL; | 887 | return HV_E_FAIL; |
884 | if (str == NULL) { | 888 | if (str == NULL) { |
885 | strcpy(buffer, "inet_ntop failed\n"); | 889 | strcpy(buffer, "inet_ntop failed\n"); |
@@ -887,11 +891,13 @@ static int kvp_process_ip_address(void *addrp, | |||
887 | } | 891 | } |
888 | if (*offset == 0) | 892 | if (*offset == 0) |
889 | strcpy(buffer, tmp); | 893 | strcpy(buffer, tmp); |
890 | else | 894 | else { |
895 | strcat(buffer, ";"); | ||
891 | strcat(buffer, tmp); | 896 | strcat(buffer, tmp); |
892 | strcat(buffer, ";"); | 897 | } |
893 | 898 | ||
894 | *offset += strlen(str) + 1; | 899 | *offset += strlen(str) + 1; |
900 | |||
895 | return 0; | 901 | return 0; |
896 | } | 902 | } |
897 | 903 | ||
@@ -953,7 +959,9 @@ kvp_get_ip_info(int family, char *if_name, int op, | |||
953 | * supported address families; if not we gather info on | 959 | * supported address families; if not we gather info on |
954 | * the specified address family. | 960 | * the specified address family. |
955 | */ | 961 | */ |
956 | if ((family != 0) && (curp->ifa_addr->sa_family != family)) { | 962 | if ((((family != 0) && |
963 | (curp->ifa_addr->sa_family != family))) || | ||
964 | (curp->ifa_flags & IFF_LOOPBACK)) { | ||
957 | curp = curp->ifa_next; | 965 | curp = curp->ifa_next; |
958 | continue; | 966 | continue; |
959 | } | 967 | } |
@@ -1478,13 +1486,19 @@ int main(void) | |||
1478 | len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0, | 1486 | len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0, |
1479 | addr_p, &addr_l); | 1487 | addr_p, &addr_l); |
1480 | 1488 | ||
1481 | if (len < 0 || addr.nl_pid) { | 1489 | if (len < 0) { |
1482 | syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", | 1490 | syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", |
1483 | addr.nl_pid, errno, strerror(errno)); | 1491 | addr.nl_pid, errno, strerror(errno)); |
1484 | close(fd); | 1492 | close(fd); |
1485 | return -1; | 1493 | return -1; |
1486 | } | 1494 | } |
1487 | 1495 | ||
1496 | if (addr.nl_pid) { | ||
1497 | syslog(LOG_WARNING, "Received packet from untrusted pid:%u", | ||
1498 | addr.nl_pid); | ||
1499 | continue; | ||
1500 | } | ||
1501 | |||
1488 | incoming_msg = (struct nlmsghdr *)kvp_recv_buffer; | 1502 | incoming_msg = (struct nlmsghdr *)kvp_recv_buffer; |
1489 | incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); | 1503 | incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); |
1490 | hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; | 1504 | hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; |
@@ -1649,7 +1663,7 @@ int main(void) | |||
1649 | strcpy(key_name, "OSMinorVersion"); | 1663 | strcpy(key_name, "OSMinorVersion"); |
1650 | break; | 1664 | break; |
1651 | case OSVersion: | 1665 | case OSVersion: |
1652 | strcpy(key_value, os_build); | 1666 | strcpy(key_value, os_version); |
1653 | strcpy(key_name, "OSVersion"); | 1667 | strcpy(key_name, "OSVersion"); |
1654 | break; | 1668 | break; |
1655 | case ProcessorArchitecture: | 1669 | case ProcessorArchitecture: |