diff options
Diffstat (limited to 'drivers/pci/access.c')
-rw-r--r-- | drivers/pci/access.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index ba91a7e17519..3af0478c057b 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c | |||
@@ -469,3 +469,205 @@ void pci_cfg_access_unlock(struct pci_dev *dev) | |||
469 | raw_spin_unlock_irqrestore(&pci_lock, flags); | 469 | raw_spin_unlock_irqrestore(&pci_lock, flags); |
470 | } | 470 | } |
471 | EXPORT_SYMBOL_GPL(pci_cfg_access_unlock); | 471 | EXPORT_SYMBOL_GPL(pci_cfg_access_unlock); |
472 | |||
473 | static inline int pcie_cap_version(const struct pci_dev *dev) | ||
474 | { | ||
475 | return dev->pcie_flags_reg & PCI_EXP_FLAGS_VERS; | ||
476 | } | ||
477 | |||
478 | static inline bool pcie_cap_has_devctl(const struct pci_dev *dev) | ||
479 | { | ||
480 | return true; | ||
481 | } | ||
482 | |||
483 | static inline bool pcie_cap_has_lnkctl(const struct pci_dev *dev) | ||
484 | { | ||
485 | int type = pci_pcie_type(dev); | ||
486 | |||
487 | return pcie_cap_version(dev) > 1 || | ||
488 | type == PCI_EXP_TYPE_ROOT_PORT || | ||
489 | type == PCI_EXP_TYPE_ENDPOINT || | ||
490 | type == PCI_EXP_TYPE_LEG_END; | ||
491 | } | ||
492 | |||
493 | static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev) | ||
494 | { | ||
495 | int type = pci_pcie_type(dev); | ||
496 | |||
497 | return pcie_cap_version(dev) > 1 || | ||
498 | type == PCI_EXP_TYPE_ROOT_PORT || | ||
499 | (type == PCI_EXP_TYPE_DOWNSTREAM && | ||
500 | dev->pcie_flags_reg & PCI_EXP_FLAGS_SLOT); | ||
501 | } | ||
502 | |||
503 | static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev) | ||
504 | { | ||
505 | int type = pci_pcie_type(dev); | ||
506 | |||
507 | return pcie_cap_version(dev) > 1 || | ||
508 | type == PCI_EXP_TYPE_ROOT_PORT || | ||
509 | type == PCI_EXP_TYPE_RC_EC; | ||
510 | } | ||
511 | |||
512 | static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos) | ||
513 | { | ||
514 | if (!pci_is_pcie(dev)) | ||
515 | return false; | ||
516 | |||
517 | switch (pos) { | ||
518 | case PCI_EXP_FLAGS_TYPE: | ||
519 | return true; | ||
520 | case PCI_EXP_DEVCAP: | ||
521 | case PCI_EXP_DEVCTL: | ||
522 | case PCI_EXP_DEVSTA: | ||
523 | return pcie_cap_has_devctl(dev); | ||
524 | case PCI_EXP_LNKCAP: | ||
525 | case PCI_EXP_LNKCTL: | ||
526 | case PCI_EXP_LNKSTA: | ||
527 | return pcie_cap_has_lnkctl(dev); | ||
528 | case PCI_EXP_SLTCAP: | ||
529 | case PCI_EXP_SLTCTL: | ||
530 | case PCI_EXP_SLTSTA: | ||
531 | return pcie_cap_has_sltctl(dev); | ||
532 | case PCI_EXP_RTCTL: | ||
533 | case PCI_EXP_RTCAP: | ||
534 | case PCI_EXP_RTSTA: | ||
535 | return pcie_cap_has_rtctl(dev); | ||
536 | case PCI_EXP_DEVCAP2: | ||
537 | case PCI_EXP_DEVCTL2: | ||
538 | case PCI_EXP_LNKCAP2: | ||
539 | case PCI_EXP_LNKCTL2: | ||
540 | case PCI_EXP_LNKSTA2: | ||
541 | return pcie_cap_version(dev) > 1; | ||
542 | default: | ||
543 | return false; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Note that these accessor functions are only for the "PCI Express | ||
549 | * Capability" (see PCIe spec r3.0, sec 7.8). They do not apply to the | ||
550 | * other "PCI Express Extended Capabilities" (AER, VC, ACS, MFVC, etc.) | ||
551 | */ | ||
552 | int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val) | ||
553 | { | ||
554 | int ret; | ||
555 | |||
556 | *val = 0; | ||
557 | if (pos & 1) | ||
558 | return -EINVAL; | ||
559 | |||
560 | if (pcie_capability_reg_implemented(dev, pos)) { | ||
561 | ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val); | ||
562 | /* | ||
563 | * Reset *val to 0 if pci_read_config_word() fails, it may | ||
564 | * have been written as 0xFFFF if hardware error happens | ||
565 | * during pci_read_config_word(). | ||
566 | */ | ||
567 | if (ret) | ||
568 | *val = 0; | ||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | /* | ||
573 | * For Functions that do not implement the Slot Capabilities, | ||
574 | * Slot Status, and Slot Control registers, these spaces must | ||
575 | * be hardwired to 0b, with the exception of the Presence Detect | ||
576 | * State bit in the Slot Status register of Downstream Ports, | ||
577 | * which must be hardwired to 1b. (PCIe Base Spec 3.0, sec 7.8) | ||
578 | */ | ||
579 | if (pci_is_pcie(dev) && pos == PCI_EXP_SLTSTA && | ||
580 | pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) { | ||
581 | *val = PCI_EXP_SLTSTA_PDS; | ||
582 | } | ||
583 | |||
584 | return 0; | ||
585 | } | ||
586 | EXPORT_SYMBOL(pcie_capability_read_word); | ||
587 | |||
588 | int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val) | ||
589 | { | ||
590 | int ret; | ||
591 | |||
592 | *val = 0; | ||
593 | if (pos & 3) | ||
594 | return -EINVAL; | ||
595 | |||
596 | if (pcie_capability_reg_implemented(dev, pos)) { | ||
597 | ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val); | ||
598 | /* | ||
599 | * Reset *val to 0 if pci_read_config_dword() fails, it may | ||
600 | * have been written as 0xFFFFFFFF if hardware error happens | ||
601 | * during pci_read_config_dword(). | ||
602 | */ | ||
603 | if (ret) | ||
604 | *val = 0; | ||
605 | return ret; | ||
606 | } | ||
607 | |||
608 | if (pci_is_pcie(dev) && pos == PCI_EXP_SLTCTL && | ||
609 | pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) { | ||
610 | *val = PCI_EXP_SLTSTA_PDS; | ||
611 | } | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | EXPORT_SYMBOL(pcie_capability_read_dword); | ||
616 | |||
617 | int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val) | ||
618 | { | ||
619 | if (pos & 1) | ||
620 | return -EINVAL; | ||
621 | |||
622 | if (!pcie_capability_reg_implemented(dev, pos)) | ||
623 | return 0; | ||
624 | |||
625 | return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val); | ||
626 | } | ||
627 | EXPORT_SYMBOL(pcie_capability_write_word); | ||
628 | |||
629 | int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val) | ||
630 | { | ||
631 | if (pos & 3) | ||
632 | return -EINVAL; | ||
633 | |||
634 | if (!pcie_capability_reg_implemented(dev, pos)) | ||
635 | return 0; | ||
636 | |||
637 | return pci_write_config_dword(dev, pci_pcie_cap(dev) + pos, val); | ||
638 | } | ||
639 | EXPORT_SYMBOL(pcie_capability_write_dword); | ||
640 | |||
641 | int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, | ||
642 | u16 clear, u16 set) | ||
643 | { | ||
644 | int ret; | ||
645 | u16 val; | ||
646 | |||
647 | ret = pcie_capability_read_word(dev, pos, &val); | ||
648 | if (!ret) { | ||
649 | val &= ~clear; | ||
650 | val |= set; | ||
651 | ret = pcie_capability_write_word(dev, pos, val); | ||
652 | } | ||
653 | |||
654 | return ret; | ||
655 | } | ||
656 | EXPORT_SYMBOL(pcie_capability_clear_and_set_word); | ||
657 | |||
658 | int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos, | ||
659 | u32 clear, u32 set) | ||
660 | { | ||
661 | int ret; | ||
662 | u32 val; | ||
663 | |||
664 | ret = pcie_capability_read_dword(dev, pos, &val); | ||
665 | if (!ret) { | ||
666 | val &= ~clear; | ||
667 | val |= set; | ||
668 | ret = pcie_capability_write_dword(dev, pos, val); | ||
669 | } | ||
670 | |||
671 | return ret; | ||
672 | } | ||
673 | EXPORT_SYMBOL(pcie_capability_clear_and_set_dword); | ||