diff options
Diffstat (limited to 'drivers/pci/quirks.c')
| -rw-r--r-- | drivers/pci/quirks.c | 74 |
1 files changed, 73 insertions, 1 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7cfa7c38d318..c74694345b6e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
| @@ -2629,14 +2629,86 @@ static int __init pci_apply_final_quirks(void) | |||
| 2629 | if (!pci_cache_line_size) { | 2629 | if (!pci_cache_line_size) { |
| 2630 | printk(KERN_DEBUG "PCI: CLS %u bytes, default %u\n", | 2630 | printk(KERN_DEBUG "PCI: CLS %u bytes, default %u\n", |
| 2631 | cls << 2, pci_dfl_cache_line_size << 2); | 2631 | cls << 2, pci_dfl_cache_line_size << 2); |
| 2632 | pci_cache_line_size = cls; | 2632 | pci_cache_line_size = cls ? cls : pci_dfl_cache_line_size; |
| 2633 | } | 2633 | } |
| 2634 | 2634 | ||
| 2635 | return 0; | 2635 | return 0; |
| 2636 | } | 2636 | } |
| 2637 | 2637 | ||
| 2638 | fs_initcall_sync(pci_apply_final_quirks); | 2638 | fs_initcall_sync(pci_apply_final_quirks); |
| 2639 | |||
| 2640 | /* | ||
| 2641 | * Followings are device-specific reset methods which can be used to | ||
| 2642 | * reset a single function if other methods (e.g. FLR, PM D0->D3) are | ||
| 2643 | * not available. | ||
| 2644 | */ | ||
| 2645 | static int reset_intel_generic_dev(struct pci_dev *dev, int probe) | ||
| 2646 | { | ||
| 2647 | int pos; | ||
| 2648 | |||
| 2649 | /* only implement PCI_CLASS_SERIAL_USB at present */ | ||
| 2650 | if (dev->class == PCI_CLASS_SERIAL_USB) { | ||
| 2651 | pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); | ||
| 2652 | if (!pos) | ||
| 2653 | return -ENOTTY; | ||
| 2654 | |||
| 2655 | if (probe) | ||
| 2656 | return 0; | ||
| 2657 | |||
| 2658 | pci_write_config_byte(dev, pos + 0x4, 1); | ||
| 2659 | msleep(100); | ||
| 2660 | |||
| 2661 | return 0; | ||
| 2662 | } else { | ||
| 2663 | return -ENOTTY; | ||
| 2664 | } | ||
| 2665 | } | ||
| 2666 | |||
| 2667 | static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe) | ||
| 2668 | { | ||
| 2669 | int pos; | ||
| 2670 | |||
| 2671 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | ||
| 2672 | if (!pos) | ||
| 2673 | return -ENOTTY; | ||
| 2674 | |||
| 2675 | if (probe) | ||
| 2676 | return 0; | ||
| 2677 | |||
| 2678 | pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, | ||
| 2679 | PCI_EXP_DEVCTL_BCR_FLR); | ||
| 2680 | msleep(100); | ||
| 2681 | |||
| 2682 | return 0; | ||
| 2683 | } | ||
| 2684 | |||
| 2685 | #define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed | ||
| 2686 | |||
| 2687 | static const struct pci_dev_reset_methods pci_dev_reset_methods[] = { | ||
| 2688 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF, | ||
| 2689 | reset_intel_82599_sfp_virtfn }, | ||
| 2690 | { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, | ||
| 2691 | reset_intel_generic_dev }, | ||
| 2692 | { 0 } | ||
| 2693 | }; | ||
| 2694 | |||
| 2695 | int pci_dev_specific_reset(struct pci_dev *dev, int probe) | ||
| 2696 | { | ||
| 2697 | const struct pci_dev_reset_methods *i; | ||
| 2698 | |||
| 2699 | for (i = pci_dev_reset_methods; i->reset; i++) { | ||
| 2700 | if ((i->vendor == dev->vendor || | ||
| 2701 | i->vendor == (u16)PCI_ANY_ID) && | ||
| 2702 | (i->device == dev->device || | ||
| 2703 | i->device == (u16)PCI_ANY_ID)) | ||
| 2704 | return i->reset(dev, probe); | ||
| 2705 | } | ||
| 2706 | |||
| 2707 | return -ENOTTY; | ||
| 2708 | } | ||
| 2709 | |||
| 2639 | #else | 2710 | #else |
| 2640 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} | 2711 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} |
| 2712 | int pci_dev_specific_reset(struct pci_dev *dev, int probe) { return -ENOTTY; } | ||
| 2641 | #endif | 2713 | #endif |
| 2642 | EXPORT_SYMBOL(pci_fixup_device); | 2714 | EXPORT_SYMBOL(pci_fixup_device); |
