aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/quirks.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/quirks.c')
-rw-r--r--drivers/pci/quirks.c74
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
2638fs_initcall_sync(pci_apply_final_quirks); 2638fs_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 */
2645static 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
2667static 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
2687static 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
2695int 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
2640void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} 2711void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {}
2712int pci_dev_specific_reset(struct pci_dev *dev, int probe) { return -ENOTTY; }
2641#endif 2713#endif
2642EXPORT_SYMBOL(pci_fixup_device); 2714EXPORT_SYMBOL(pci_fixup_device);