diff options
Diffstat (limited to 'drivers/pci/quirks.c')
-rw-r--r-- | drivers/pci/quirks.c | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7cfa7c38d318..d58b94030ef3 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -338,6 +338,23 @@ static void __devinit quirk_s3_64M(struct pci_dev *dev) | |||
338 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M); | 338 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M); |
339 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M); | 339 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M); |
340 | 340 | ||
341 | /* | ||
342 | * Some CS5536 BIOSes (for example, the Soekris NET5501 board w/ comBIOS | ||
343 | * ver. 1.33 20070103) don't set the correct ISA PCI region header info. | ||
344 | * BAR0 should be 8 bytes; instead, it may be set to something like 8k | ||
345 | * (which conflicts w/ BAR1's memory range). | ||
346 | */ | ||
347 | static void __devinit quirk_cs5536_vsa(struct pci_dev *dev) | ||
348 | { | ||
349 | if (pci_resource_len(dev, 0) != 8) { | ||
350 | struct resource *res = &dev->resource[0]; | ||
351 | res->end = res->start + 8 - 1; | ||
352 | dev_info(&dev->dev, "CS5536 ISA bridge bug detected " | ||
353 | "(incorrect header); workaround applied.\n"); | ||
354 | } | ||
355 | } | ||
356 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa); | ||
357 | |||
341 | static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, | 358 | static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, |
342 | unsigned size, int nr, const char *name) | 359 | unsigned size, int nr, const char *name) |
343 | { | 360 | { |
@@ -2629,14 +2646,86 @@ static int __init pci_apply_final_quirks(void) | |||
2629 | if (!pci_cache_line_size) { | 2646 | if (!pci_cache_line_size) { |
2630 | printk(KERN_DEBUG "PCI: CLS %u bytes, default %u\n", | 2647 | printk(KERN_DEBUG "PCI: CLS %u bytes, default %u\n", |
2631 | cls << 2, pci_dfl_cache_line_size << 2); | 2648 | cls << 2, pci_dfl_cache_line_size << 2); |
2632 | pci_cache_line_size = cls; | 2649 | pci_cache_line_size = cls ? cls : pci_dfl_cache_line_size; |
2633 | } | 2650 | } |
2634 | 2651 | ||
2635 | return 0; | 2652 | return 0; |
2636 | } | 2653 | } |
2637 | 2654 | ||
2638 | fs_initcall_sync(pci_apply_final_quirks); | 2655 | fs_initcall_sync(pci_apply_final_quirks); |
2656 | |||
2657 | /* | ||
2658 | * Followings are device-specific reset methods which can be used to | ||
2659 | * reset a single function if other methods (e.g. FLR, PM D0->D3) are | ||
2660 | * not available. | ||
2661 | */ | ||
2662 | static int reset_intel_generic_dev(struct pci_dev *dev, int probe) | ||
2663 | { | ||
2664 | int pos; | ||
2665 | |||
2666 | /* only implement PCI_CLASS_SERIAL_USB at present */ | ||
2667 | if (dev->class == PCI_CLASS_SERIAL_USB) { | ||
2668 | pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); | ||
2669 | if (!pos) | ||
2670 | return -ENOTTY; | ||
2671 | |||
2672 | if (probe) | ||
2673 | return 0; | ||
2674 | |||
2675 | pci_write_config_byte(dev, pos + 0x4, 1); | ||
2676 | msleep(100); | ||
2677 | |||
2678 | return 0; | ||
2679 | } else { | ||
2680 | return -ENOTTY; | ||
2681 | } | ||
2682 | } | ||
2683 | |||
2684 | static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe) | ||
2685 | { | ||
2686 | int pos; | ||
2687 | |||
2688 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | ||
2689 | if (!pos) | ||
2690 | return -ENOTTY; | ||
2691 | |||
2692 | if (probe) | ||
2693 | return 0; | ||
2694 | |||
2695 | pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, | ||
2696 | PCI_EXP_DEVCTL_BCR_FLR); | ||
2697 | msleep(100); | ||
2698 | |||
2699 | return 0; | ||
2700 | } | ||
2701 | |||
2702 | #define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed | ||
2703 | |||
2704 | static const struct pci_dev_reset_methods pci_dev_reset_methods[] = { | ||
2705 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF, | ||
2706 | reset_intel_82599_sfp_virtfn }, | ||
2707 | { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, | ||
2708 | reset_intel_generic_dev }, | ||
2709 | { 0 } | ||
2710 | }; | ||
2711 | |||
2712 | int pci_dev_specific_reset(struct pci_dev *dev, int probe) | ||
2713 | { | ||
2714 | const struct pci_dev_reset_methods *i; | ||
2715 | |||
2716 | for (i = pci_dev_reset_methods; i->reset; i++) { | ||
2717 | if ((i->vendor == dev->vendor || | ||
2718 | i->vendor == (u16)PCI_ANY_ID) && | ||
2719 | (i->device == dev->device || | ||
2720 | i->device == (u16)PCI_ANY_ID)) | ||
2721 | return i->reset(dev, probe); | ||
2722 | } | ||
2723 | |||
2724 | return -ENOTTY; | ||
2725 | } | ||
2726 | |||
2639 | #else | 2727 | #else |
2640 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} | 2728 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} |
2729 | int pci_dev_specific_reset(struct pci_dev *dev, int probe) { return -ENOTTY; } | ||
2641 | #endif | 2730 | #endif |
2642 | EXPORT_SYMBOL(pci_fixup_device); | 2731 | EXPORT_SYMBOL(pci_fixup_device); |